tomcat7-7.0.52/0000755000175100017510000000000012301126373013141 5ustar locutuslocutustomcat7-7.0.52/res/0000755000175100017510000000000012301126372013731 5ustar locutuslocutustomcat7-7.0.52/res/META-INF/0000755000175100017510000000000012301126372015071 5ustar locutuslocutustomcat7-7.0.52/res/META-INF/default.manifest0000644000175100017510000000052512271302242020245 0ustar locutuslocutusManifest-Version: 1.0 Specification-Title: Apache Tomcat Specification-Version: @VERSION_MAJOR_MINOR@ Specification-Vendor: Apache Software Foundation Implementation-Title: Apache Tomcat Implementation-Version: @VERSION@ Implementation-Vendor: Apache Software Foundation X-Compile-Source-JDK: @source.jdk@ X-Compile-Target-JDK: @target.jdk@ tomcat7-7.0.52/res/META-INF/websocket-api.jar.manifest0000644000175100017510000000052712204665332022143 0ustar locutuslocutusManifest-version: 1.0 X-Compile-Source-JDK: @source.jdk@ X-Compile-Target-JDK: @target.jdk@ Name: javax/el/ Specification-Title: WebSocket Specification-Version: 1.0 Specification-Vendor: Oracle, Inc. Implementation-Title: javax.net.websocket Implementation-Version: 1.0.@websocket.revision@ Implementation-Vendor: Apache Software Foundation tomcat7-7.0.52/res/META-INF/default/0000755000175100017510000000000012301126372016515 5ustar locutuslocutustomcat7-7.0.52/res/META-INF/default/.gitignore0000644000175100017510000000225512057500552020515 0ustar locutuslocutus# ----------------------------------------------------------------------------- # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Git ignores empty directories and the unit tests require this directory to # be present for the welcome file tests to pass. The presence of this file # doesn't break the unit tests. # # Ignore everything in this directory * # Except this file !.gitignoretomcat7-7.0.52/res/META-INF/servlet-api.jar.notice0000644000175100017510000000103112271302242021273 0ustar locutuslocutusApache Tomcat Copyright 1999-@YEAR@ The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). The original XML Schemas for Java EE Deployment Descriptors: - javaee_5.xsd - javaee_web_services_1_2.xsd - javaee_web_services_client_1_2.xsd - javaee_6.xsd - javaee_web_services_1_3.xsd - javaee_web_services_client_1_3.xsd - jsp_2_2.xsd - web-app_3_0.xsd - web-common_3_0.xsd - web-fragment_3_0.xsd may be obtained from http://java.sun.com/xml/ns/javaee/ tomcat7-7.0.52/res/META-INF/default.license0000644000175100017510000002613611252504723020075 0ustar locutuslocutus 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. tomcat7-7.0.52/res/META-INF/tomcat7-websocket.jar/0000755000175100017510000000000012301126372021206 5ustar locutuslocutustomcat7-7.0.52/res/META-INF/tomcat7-websocket.jar/web-fragment.xml0000644000175100017510000000225712233712073024317 0ustar locutuslocutus org_apache_tomcat_websocket tomcat7-7.0.52/res/META-INF/tomcat7-websocket.jar/services/0000755000175100017510000000000012301126372023031 5ustar locutuslocutustomcat7-7.0.52/res/META-INF/tomcat7-websocket.jar/services/javax.websocket.ContainerProvider0000644000175100017510000000005712166436036031522 0ustar locutuslocutusorg.apache.tomcat.websocket.WsContainerProvidertomcat7-7.0.52/res/META-INF/tomcat7-websocket.jar/services/javax.servlet.ServletContainerInitializer0000644000175100017510000000005012231340004033225 0ustar locutuslocutusorg.apache.tomcat.websocket.server.WsSci././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootroottomcat7-7.0.52/res/META-INF/tomcat7-websocket.jar/services/javax.websocket.server.ServerEndpointConfig$Configuratortomcat7-7.0.52/res/META-INF/tomcat7-websocket.jar/services/javax.websocket.server.ServerEndpointConf0000644000175100017510000000010412236014551033130 0ustar locutuslocutusorg.apache.tomcat.websocket.server.DefaultServerEndpointConfiguratortomcat7-7.0.52/res/META-INF/el-api.jar.manifest0000644000175100017510000000053112271302242020540 0ustar locutuslocutusManifest-version: 1.0 X-Compile-Source-JDK: @source.jdk@ X-Compile-Target-JDK: @target.jdk@ Name: javax/el/ Specification-Title: Expression Language Specification-Version: 2.2 Specification-Vendor: Sun Microsystems, Inc. Implementation-Title: javax.el Implementation-Version: 2.2.@el.revision@ Implementation-Vendor: Apache Software Foundation tomcat7-7.0.52/res/META-INF/bootstrap.jar.manifest0000644000175100017510000000067112271302242021413 0ustar locutuslocutusManifest-Version: 1.0 Main-Class: org.apache.catalina.startup.Bootstrap Class-Path: commons-daemon.jar Specification-Title: Apache Tomcat Bootstrap Specification-Version: @VERSION_MAJOR_MINOR@ Specification-Vendor: Apache Software Foundation Implementation-Title: Apache Tomcat Bootstrap Implementation-Version: @VERSION@ Implementation-Vendor: Apache Software Foundation X-Compile-Source-JDK: @source.jdk@ X-Compile-Target-JDK: @target.jdk@tomcat7-7.0.52/res/META-INF/jsp-api.jar.notice0000644000175100017510000000045612271302242020415 0ustar locutuslocutusApache Tomcat Copyright 1999-@YEAR@ The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). The original XML Schemas for Java EE Deployment Descriptors: - jsp_2_2.xsd may be obtained from http://java.sun.com/xml/ns/javaee/ tomcat7-7.0.52/res/META-INF/jsp-api.jar.license0000644000175100017510000007301612271302242020560 0ustar locutuslocutus 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. APACHE TOMCAT SUBCOMPONENTS: Apache Tomcat includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the following licenses. For the following XML Schemas for Java EE Deployment Descriptors: - jsp_2_2.xsd COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. Definitions. 1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications. 1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. Executable. means the Covered Software in any form other than Source Code. 1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License. 1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. License. means this document. 1.8. 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 the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. 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.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. 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. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (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 Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party 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 Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and 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 Software 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 distributes or otherwise makes the Modifications available to a third party. (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) 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 (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. 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 that 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.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of 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 form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form 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 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.6. Larger Works. You may create a Larger Work by combining Covered Software 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 Software. 4. Versions of the License. 4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE 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 SOFTWARE 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 SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE 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 SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.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. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. 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 SOFTWARE, 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 LOST PROFITS, 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. 8. U.S. GOVERNMENT END USERS. The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. ? 252.227-7014(a)(1)) 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 Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. 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 the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction's conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, 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. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. 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. NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California. tomcat7-7.0.52/res/META-INF/servlet-api.jar.license0000644000175100017510000007337112271302242021454 0ustar locutuslocutus 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. APACHE TOMCAT SUBCOMPONENTS: Apache Tomcat includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the following licenses. For the following XML Schemas for Java EE Deployment Descriptors: - javaee_5.xsd - javaee_web_services_1_2.xsd - javaee_web_services_client_1_2.xsd - javaee_6.xsd - javaee_web_services_1_3.xsd - javaee_web_services_client_1_3.xsd - jsp_2_2.xsd - web-app_3_0.xsd - web-common_3_0.xsd - web-fragment_3_0.xsd COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. Definitions. 1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications. 1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. Executable. means the Covered Software in any form other than Source Code. 1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License. 1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. License. means this document. 1.8. 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 the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. 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.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. 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. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (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 Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party 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 Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and 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 Software 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 distributes or otherwise makes the Modifications available to a third party. (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) 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 (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. 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 that 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.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of 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 form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form 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 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.6. Larger Works. You may create a Larger Work by combining Covered Software 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 Software. 4. Versions of the License. 4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE 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 SOFTWARE 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 SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE 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 SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.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. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. 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 SOFTWARE, 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 LOST PROFITS, 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. 8. U.S. GOVERNMENT END USERS. The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. ? 252.227-7014(a)(1)) 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 Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. 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 the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction's conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, 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. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. 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. NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California. tomcat7-7.0.52/res/META-INF/annotations-api.jar.manifest0000644000175100017510000000057012271302242022500 0ustar locutuslocutusManifest-version: 1.0 X-Compile-Source-JDK: @source.jdk@ X-Compile-Target-JDK: @target.jdk@ Name: javax/servlet/ Specification-Title: Java API for Servlets (Annotations) Specification-Version: 3.0 Specification-Vendor: Sun Microsystems, Inc. Implementation-Title: javax.servlet Implementation-Version: 3.0.@servlet.revision@ Implementation-Vendor: Apache Software Foundation tomcat7-7.0.52/res/META-INF/servlet-api.jar.manifest0000644000175100017510000000055212271302242021627 0ustar locutuslocutusManifest-version: 1.0 X-Compile-Source-JDK: @source.jdk@ X-Compile-Target-JDK: @target.jdk@ Name: javax/servlet/ Specification-Title: Java API for Servlets Specification-Version: 3.0 Specification-Vendor: Sun Microsystems, Inc. Implementation-Title: javax.servlet Implementation-Version: 3.0.@servlet.revision@ Implementation-Vendor: Apache Software Foundation tomcat7-7.0.52/res/META-INF/jsp-api.jar.manifest0000644000175100017510000000056612271302242020744 0ustar locutuslocutusManifest-version: 1.0 X-Compile-Source-JDK: @source.jdk@ X-Compile-Target-JDK: @target.jdk@ Name: javax/servlet/jsp/ Specification-Title: Java API for JavaServer Pages Specification-Version: 2.2 Specification-Vendor: Sun Microsystems, Inc. Implementation-Title: javax.servlet.jsp Implementation-Version: 2.2.@jsp.revision@ Implementation-Vendor: Apache Software Foundation tomcat7-7.0.52/res/META-INF/default.notice0000644000175100017510000000025112230121034017705 0ustar locutuslocutusApache Tomcat Copyright 1999-@YEAR@ The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). tomcat7-7.0.52/res/ide-support/0000755000175100017510000000000012301126372016204 5ustar locutuslocutustomcat7-7.0.52/res/ide-support/eclipse/0000755000175100017510000000000012301126372017630 5ustar locutuslocutustomcat7-7.0.52/res/ide-support/eclipse/start-tomcat.launch0000644000175100017510000000320411450351552023451 0ustar locutuslocutus tomcat7-7.0.52/res/ide-support/eclipse/stop-tomcat.launch0000644000175100017510000000320311450351552023300 0ustar locutuslocutus tomcat7-7.0.52/res/ide-support/eclipse/eclipse.project0000644000175100017510000000231312271302242022641 0ustar locutuslocutus tomcat-7.0.x org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature tomcat7-7.0.52/res/ide-support/eclipse/eclipse.classpath0000644000175100017510000000355312271302242023164 0ustar locutuslocutus tomcat7-7.0.52/res/ide-support/eclipse/java-compiler-errors-warnings.txt0000644000175100017510000000576712200762652026306 0ustar locutuslocutus================================================================================ Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. ================================================================================ # Java -> Compiler -> Errors/Warnings The following settings are for Indigo Release W = Warning I = Ignore E = Error Code style - Non-static access to static member - W - Indirect access to static member - I - Unqualified access to instance field - I - Undocumented empty block - I - Access to a non-accessible member... - I - Method with a constructor name - W - Parameter assignment - I - Non-externalized strings - I - Method can be static - I (Eclipse 3.7+) - Method can potentially be static - I (Eclipse 3.7+) Potential programming errors - All - W Name shadowing and conflicts - Field declaration hides another... - I - Local variable declaration hides.. - I - Type parameter hides another type - W - Method does not override... - W - Interface method conflicts... - W Deprecated and restricted API - Deprecated API - W (no additional check boxes) - Forbidden references - E - Discouraged reference - W Unnecessary code - Unnecessary else - I - The rest - W (all additional check boxes) Generic types - All - W [ ] Ignore unavoidable generic type problems Annotations - All - W (all additional check boxes) Note: The list of codes supported in @SuppressWarnings annotation in Eclipse IDE is documented here: 3.6: http://help.eclipse.org/helios/topic/org.eclipse.jdt.doc.isv/guide/jdt_api_compile.htm 3.7: http://help.eclipse.org/indigo/topic/org.eclipse.jdt.doc.user/tasks/task-suppress_warnings.htm # Java -> Code Style -> Organize Imports The following configuration of Organize Imports can be recommended for a quick setup. The order is enforced by checkstyle, so for the authorative definition look at in res/checkstyle/checkstyle.xml - java - javax - async - jsp2 - [static] org.junit - org.junit - [static] org - org - com - util tomcat7-7.0.52/res/header.bmp0000644000175100017510000002301610457676032015700 0ustar locutuslocutusBM&6(9! N N#)$).*&+3(0O8I)<_0V4(Qk/p#e5)rQMx RQ*Nf0SKmq qM.nk5k,JU4Eg%Tb9YgMlNjQk{myqMmIKTIYMrVVi[b]h¸ĺ[Ayfq_b㰚WWѭK6a.~kRR\2XR§6RZz^JJ7ave!m, BB/6j+9:#c˵umBn:}ZUX||!ʱɶ˷cɳhI6K04@65 3 CCCC CC  GGGG{?5GGGccɾ˱c#ҰK#:I..II /FDD. DDL|CCD CCCC#ɳʵʳcAR¥9l 0E5{N/]5GGH 1G '%%% CGG%%CC%%DD"a##avvƶvtP\JI<9]E]-5?GGHGG1C%%%DDCC%%"#cQgQvdc#T\78J95p5E?G5GG/HCDFGC&&CDF%% ..Qdɳ˵5i,5-IG-GGG`GGGECGHG"&&`HC&&  CC5l˷d׿fl:L/GGGGG`GGGHDCF&& ?:DCGGɲdybni]GGGpDHD`DDDDDD"&& G| %%%%+ GG| jRzǵ˷§qNEGGGGpGHGHE &&DD CCG"%%%%%%&`5J\#̶짥l7EGYGGGDDDD"&&D('%%DC1G %%%%DC il3Xs6+HD`D&"&&&&&&FDD'%%DCCG-|E%%% CCG-Y\¿ Ks,&&(&&&"&&&&(&&&DCCDDDCCG'`CGGG] %5 G luzI>3s/H&&"&&&(&&&&"%HCGGDFDCCGGGG DC "G?qDD }=J.sYHH&&(&&&"&&DDDGG?DCCCGGGGG|5CGGL~DCCG§E0J5pY&&"&&%%CCGD-OCGG` G|8GGELCGG/fUbJI?pGGG&&&%%DCGGDCC] GG?r |E3[G|59lR[]EE EGGED&"%%%&%FGGDCG|YGG?Y|5B6lo¼$)G/CGD`"%%(%%DD G?GCG AYBlMM) *CD"%%%%(CCCDDCG G-E6Y24lmBP$ *"%%%%%%%"GGGCCG5E-\XMk* ** $%%"DDG??1GE|0N6j kw$$  %%'DD"CCCE|I-|,PM %"%%%(DDD`DDCCCGG`?5730]ww)%"%%%DDGGGGGGGG?150 kZ%""DDDCCCY1GO?||.\M~Ib *)DCCGC GHY|,L|.6BSz*)$DCCGGG`?E5 =Bb$DD`CCGG? GE5 ]=0* CCGYGGGE5E]05)$)CGH | 0=z$*?/[**z;8)$Ԝ tomcat7-7.0.52/res/maven/0000755000175100017510000000000012301126372015037 5ustar locutuslocutustomcat7-7.0.52/res/maven/tomcat-i18n-ja.pom0000644000175100017510000000243312271302242020210 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-i18n-ja @MAVEN.DEPLOY.VERSION@ Japanese translations http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-extras-juli-adapters.pom0000644000175100017510000000346411757770042023135 0ustar locutuslocutus 4.0.0 org.apache.tomcat.extras tomcat-extras-juli-adapters @MAVEN.DEPLOY.VERSION@ Adapters to plug in other logging frameworks in Tomcat http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat.extras tomcat-extras-juli @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ compile true tomcat7-7.0.52/res/maven/tomcat-i18n-fr.pom0000644000175100017510000000243112271302242020223 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-i18n-fr @MAVEN.DEPLOY.VERSION@ French translations http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-extras-juli.pom0000644000175100017510000000247411757770042021334 0ustar locutuslocutus 4.0.0 org.apache.tomcat.extras tomcat-extras-juli @MAVEN.DEPLOY.VERSION@ Replacement for Tomcat Core Logging Package http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/mvn.properties.default0000644000175100017510000000377712276372100021421 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # To create custom properties, simply create # the file mvn.properties # in this directory # no need to change this file # # Authentication # Note: You will be prompted for your GPG passphrase and LDAP password when # running this script asf.ldap.username= gpg.exec=C:/software/GNU/GnuPG/gpg.exe # ASF Snapshot Repository (hosted on Nexus) maven.snapshot.repo.url=https://repository.apache.org/content/repositories/snapshots maven.snapshot.repo.repositoryId=apache.snapshots # ASF Release Repository (hosted on Nexus) # Note: Also used for staging releases prior to voting maven.asf.release.repo.url=https://repository.apache.org/service/local/staging/deploy/maven2 maven.asf.release.repo.repositoryId=apache.releases # Release version info maven.asf.release.deploy.version=7.0.52 #Where do we load the libraries from tomcat.lib.path=../../output/build/lib tomcat.bin.path=../../output/build/bin tomcat.release.path=../../output/release tomcat.src.path=../../output/src-jars tomcat.embed.path=../../output/embed tomcat.embed.src.path=../../output/embed-src-jars tomcat.extras.path=../../output/extras tomcat.extras.src.path=../../output/extras-src-jars #Where do we find the POM files tomcat.pom.path=../../res/maven tomcat7-7.0.52/res/maven/tomcat-embed-logging-log4j.pom0000644000175100017510000000251012271302242022552 0ustar locutuslocutus 4.0.0 org.apache.tomcat.embed tomcat-embed-logging-log4j @MAVEN.DEPLOY.VERSION@ log4j logging implementation for embedded Tomcat http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/README.txt0000644000175100017510000000366112271302242016541 0ustar locutuslocutus================================================================================ Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. ================================================================================ General preparations before any publishing: 1 - Download Maven Ant Tasks (version 2.1.0 is known to work) and place it in this directory 2 - Generate a standard Tomcat release (ant release) 3 - Copy mvn.properties.default to mvn.properties and adjust it as necessary. You will need to set asf.ldap.username and you'll probably need to set gpg.exec The other properties should be OK. Note: you will be prompted for your GPG pass-phrase and LDAP password when the script runs. To publish a snapshot do the following: 1 - ant -f mvn-pub.xml deploy-snapshot This populates https://repository.apache.org/content/repositories/snapshots/org/apache/tomcat/ To release do the following: 1 - ant -f mvn-pub.xml deploy-release that step creates a staging area in https://repository.apache.org/index.html#stagingRepositories 2 - check the upload and then close the repository 3 - include the repository in the VOTE thread 4 - in https://repository.apache.org/index.html#stagingRepositories release it tomcat7-7.0.52/res/maven/tomcat-annotations-api.pom0000644000175100017510000000244211757770042022164 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-annotations-api @MAVEN.DEPLOY.VERSION@ Annotations Package http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-catalina-ws.pom0000644000175100017510000000303312271302242021241 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-catalina-ws @MAVEN.DEPLOY.VERSION@ Tomcat JNDI Factory for Web Services http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-catalina @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-tribes.pom0000644000175100017510000000302011757770042020341 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-tribes @MAVEN.DEPLOY.VERSION@ Tomcat Group Communication Package http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat7-embed-websocket.pom0000644000175100017510000000304312270465432022200 0ustar locutuslocutus 4.0.0 org.apache.tomcat.embed tomcat-embed-websocket @MAVEN.DEPLOY.VERSION@ Core Tomcat implementation http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat.embed tomcat-embed-core @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-servlet-api.pom0000644000175100017510000000352511760430027021304 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ javax.servlet package http://tomcat.apache.org/ Apache License, Version 2.0 and Common Development And Distribution License (CDDL) Version 1.0 http://www.apache.org/licenses/LICENSE-2.0.txt and http://www.opensource.org/licenses/cddl1.txt repo The Apache License, version 2.0 applies to all files apart from javaee_5.xsd, javaee_web_services_1_2.xsd, javaee_web_services_client_1_2.xsd, javaee_6.xsd, javaee_web_services_1_3.xsd, javaee_web_services_client_1_3.xsd, web-app_3_0.xsd, web-common_3_0.xsd, web-fragment_3_0.xsd to which the CDDL version 1.0 applies. tomcat7-7.0.52/res/maven/tomcat-embed-core.pom0000644000175100017510000000350112271302242021040 0ustar locutuslocutus 4.0.0 org.apache.tomcat.embed tomcat-embed-core @MAVEN.DEPLOY.VERSION@ Core Tomcat implementation http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat.embed tomcat-embed-logging-juli @MAVEN.DEPLOY.VERSION@ compile true org.apache.tomcat.embed tomcat-embed-logging-log4j @MAVEN.DEPLOY.VERSION@ compile true tomcat7-7.0.52/res/maven/mvn-pub.xml0000644000175100017510000003652112270465432017164 0ustar locutuslocutus tomcat7-7.0.52/res/maven/tomcat-i18n-es.pom0000644000175100017510000000243212271302242020224 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-i18n-es @MAVEN.DEPLOY.VERSION@ Spanish translations http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-catalina-ha.pom0000644000175100017510000000500711757770042021222 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-catalina-ha @MAVEN.DEPLOY.VERSION@ Tomcat High Availability Implementation http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-coyote @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-tribes @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-catalina @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-util @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-util.pom0000644000175100017510000000333212271302242020015 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-util @MAVEN.DEPLOY.VERSION@ Common code shared by Catalina and Jasper http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-api @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-catalina.pom0000644000175100017510000000453011757770042020634 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-catalina @MAVEN.DEPLOY.VERSION@ Tomcat Servlet Engine Core Classes and Standard implementations http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-annotations-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-util @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-embed-jasper.pom0000644000175100017510000000361412271302242021401 0ustar locutuslocutus 4.0.0 org.apache.tomcat.embed tomcat-embed-jasper @MAVEN.DEPLOY.VERSION@ Core Tomcat implementation http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat.embed tomcat-embed-core @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat.embed tomcat-embed-el @MAVEN.DEPLOY.VERSION@ compile org.eclipse.jdt.core.compiler ecj 4.3.1 tomcat7-7.0.52/res/maven/tomcat-jdbc.pom0000644000175100017510000000300411757770042017755 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-jdbc @MAVEN.DEPLOY.VERSION@ Tomcat JDBC Pool Package http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-jasper.pom0000644000175100017510000000552012250670537020341 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-jasper @MAVEN.DEPLOY.VERSION@ Tomcats JSP Parser http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-jsp-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-el-api @MAVEN.DEPLOY.VERSION@ compile org.eclipse.jdt.core.compiler ecj 4.3.1 org.apache.tomcat tomcat-jasper-el @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-util @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-dbcp.pom0000644000175100017510000000245511757770042017774 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-dbcp @MAVEN.DEPLOY.VERSION@ Tomcat Database Connection Pooling package http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-el-api.pom0000644000175100017510000000244011757770042020225 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-el-api @MAVEN.DEPLOY.VERSION@ Expression language package http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-catalina-jmx-remote.pom0000644000175100017510000000364712271302242022712 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-catalina-jmx-remote @MAVEN.DEPLOY.VERSION@ Tomcat Remote JMX listener http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-coyote @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-catalina @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-juli.pom0000644000175100017510000000243611757770042020026 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ Tomcat Core Logging Package http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-websocket-api.pom0000644000175100017510000000244212204665332021606 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-websocket-api @MAVEN.DEPLOY.VERSION@ WebSocket (JSR356) API http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-catalina-ant.pom0000644000175100017510000000334612271302242021401 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-catalina-ant @MAVEN.DEPLOY.VERSION@ Tomcat Ant tasks for remote management http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-coyote @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-catalina @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-jsp-api.pom0000644000175100017510000000402311760430027020406 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-jsp-api @MAVEN.DEPLOY.VERSION@ JSP package http://tomcat.apache.org/ Apache License, Version 2.0 and Common Development And Distribution License (CDDL) Version 1.0 http://www.apache.org/licenses/LICENSE-2.0.txt and http://www.opensource.org/licenses/cddl1.txt repo The Apache License, version 2.0 applies to all files apart from jsp_2_2.xsd to which the CDDL version 1.0 applies. org.apache.tomcat tomcat-el-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-api.pom0000644000175100017510000000305012271302242017606 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-api @MAVEN.DEPLOY.VERSION@ Definition of interfaces shared by Catalina and Jasper http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-embed-logging-juli.pom0000644000175100017510000000250612271302242022503 0ustar locutuslocutus 4.0.0 org.apache.tomcat.embed tomcat-embed-logging-juli @MAVEN.DEPLOY.VERSION@ JULI logging implementation for embedded Tomcat http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat-coyote.pom0000644000175100017510000000364212203402076020347 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-coyote @MAVEN.DEPLOY.VERSION@ Tomcat Connectors and HTTP parser http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-servlet-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-util @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat7-websocket.pom0000644000175100017510000000450112220371272021117 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat7-websocket @MAVEN.DEPLOY.VERSION@ Tomcat WebSocket (JSR356) implementation http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-websocket-api @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-catalina @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-coyote @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-juli @MAVEN.DEPLOY.VERSION@ compile org.apache.tomcat tomcat-util @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-jasper-el.pom0000644000175100017510000000302311757770042020736 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat-jasper-el @MAVEN.DEPLOY.VERSION@ Jasper Expression Language Impl http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo org.apache.tomcat tomcat-el-api @MAVEN.DEPLOY.VERSION@ compile tomcat7-7.0.52/res/maven/tomcat-embed-el.pom0000644000175100017510000000244712270454227020532 0ustar locutuslocutus 4.0.0 org.apache.tomcat.embed tomcat-embed-el @MAVEN.DEPLOY.VERSION@ Core Tomcat implementation http://tomcat.apache.org/ Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/maven/tomcat.pom0000644000175100017510000000247712072573234017065 0ustar locutuslocutus 4.0.0 org.apache.tomcat tomcat @MAVEN.DEPLOY.VERSION@ Binary distribution of Apache Tomcat http://tomcat.apache.org/ pom Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo tomcat7-7.0.52/res/side_left.bmp0000644000175100017510000124222611471741316016410 0ustar locutuslocutusBMD6(`D  wqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcwqfxpcwqftpeypfvpewqfwqfwqfvpeypfypfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpexoevpexoevpewqfxoevpevpewqfvpewqfwndxoewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewqfwqfvpewqfypfwqfwqfvpevpewqfvpevpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewqfvpewqfwqfwqdxoevpevpevpexrgvpewqfvpevpeypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdvofwqdvpevpeyqdwpgupgvqhwpgvpevpevpewqfwqfxoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewpgwqfvofwqfvpe֫wqfxoewqfwqfvpexoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewpgxpcwqfvofwqfvofypfxoewqfvpexoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcvofyqdwqfwqfvpevofxoexoewqfvpexoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxofuohypcxpcwpgypfvpewqfwqfvpevpexoeypfxpcvpevofwqfxoewqfwqfxrgypbtofvpexpcwqfwpgyoevpewqfxpcyqdvpewqfxpcvpevpeyqdxpcwqfvpeyqdtofwqftpewqfypcwpgyqdypfsnezpfvpcxqhvofwqfvofyqdtofypfvpeyqdxpcuodwqfxpcwpgyqdypfypfvpcwpgyqdxoeyqdupgzqdypfwqfvofxofypftpewqfwqfwqfwqfwqfwqfwqfwqfwqfxoewqfxoexoeypfvofvofxoexoewqfvpeypfvpewqfvpeyqdxoeyqdxoeypfxoewqfvpexpcwqfvpewqfwqfxpctofxpcwqfvpexpcwqfxpcypfwpgxoevpexoevpewqfypcwpgwpgwqfxoeypfvpcvpevpcxpcypfvpctofupgxofvpcvpewpgtpexoevpeypfvpexpcwqfxoezqdvpevpewqfyqdtofwpgxoeypfwqfwqfwqfvpewqdvpcxoeypfvpewqfypfypfwqftpewqfypfxoetofvpexoevpeypfyqdupgtngzqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfzre~wnupgvpewpgvofxrgvpexof~xmwqf¿ŖwqfvpexpcwqftofvofΨtofxobuqfwndyqdwohx¿vpewqfvpeypfwpgvpexxwqfuneyqdwpgvof{yozqdwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfvpexvpewqfwqfvpevpewqfypfwqfy׻xvpezqgxoevpevpevpewqfwqfvpewqfvpeypfxoewqfvpewqftofػypczqcwqfyÿ¿ywwvrgvpcyqdtofŗvpexpcyqdypfypfwqfvpewqfxoexoevpewqfvpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpeyqdtofvpewpgywqfvpewqfxpcxoexxoeupgvpewqfwqftofzqdwqfzqg|wnyqdxpcvpeuodxoevpezqgvofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewpgxqhvpewqfypfxpcwqfwpgºvofypfxpcvofwpguodwpgwqfuodwqfvpewqfypfwqfyxoewqfyqdypfÿupgwqdyqdypfwqfvpevofvpezrevpcvpeyqdtpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypfvofypfzreypfxoevofwqfwpgypfuqfupgvpewqfypgypftofupgxoeypfypfxpcypfxpcwqfwqfwqfwqfwqfwqfwqfwqfxoexoeypfvofvpewqfwqfypfxpcwpgvofyqdvofxoezrexoeuodzrexpcvpevpexoe}xoypfvpeypfwpίvpevpevpewqfvpewqfvpewqfxpcvpeuohypcvofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypfvpeypfxoexpcy꼶yxoevpcvpeuqf|wnxrgvpeupgzuqfypgupgwpg㻷wqfyqdxoevpexoeyqdypfyqdxqbxqhtofuqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoexpcwqfvpeyqdvpevpewqf}wpxnvpe~xq~xqyqdwqfwqfyqdyqdwqfxpcxpcxrgvpewqfwqfxovofwqdvpcsnexoeypfupgwqfvpewqfwqfwqfvpewqfypfvpcvpewqfypfvpex~wnypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcwqfwqfwpgxoevofvpcxpcxpcvpe¿wqf|vowpgyqdxoewqftpeypfvpcvpewqfxovxpcxrgwqfwqfvpewqfxouohwqfvpewpgxpczsdtofypfwqfwqfwqfwqfwqfwqfwqfwqfwpgwqfxoewpgypfxpcwqfvpewqfvpevofwpgxpcypfwqfxpcwqfwpgvpewqfvpexpcwqfxoxpctofwnezsdvylwqd¿xoeypbypfypfxpcvpevpcyqdwqfvofwqfvpcvpeyqdvpcwqfwpgypfyqdxpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpeypfwqfwqfwqfxoewpgwqfwpgxoeypfvpeynxpcwqftofxoeyqdyqdvpeupgxpcxpcxpcwqfvpevpeuqfĻywqfwqfwqfwqfwqfwqfwqfwqfwpgwqfypfvofwqfyqdwqfwqfvpeypfwqfxpcwqfypfwqfwqfwqfvpewqfxrgvofypfvpeypfxpcwqfyqdvpcvpewqftofͼvpeyqdwqfwqfxpcwqfwqfvpeypfwqfvpeyqdwqfvpeypfxpcypfwp|wnwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwpgyoexoeypfwqfxpcyn얓xoypfvpewqfwqfxpcyqdvpewqfypfypftpewpgxofxpcwpgvofvpcwpgtofypfvpeypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoexpcvpewqfvpcwqfvpexpcvpevpeyqdvofypfvpevpeuneypfxoevpewqfypfwqfvpewpgypfyqdupgwqfxpcypfypfwpgxoexoexoeypfvpewqfwqfxoeuqfwqfxoevpexrgvpcwqfvofxpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpexoeypfwqfwqftofxwqfvxoewpgvpezqdwqfyqdwqfwqfxoewqfwqfwupgwpgwpgxoexoevpevofxoeypfwqfypgxpcvpevpeyĺwqfwqfvpevpewqfwqfvpewqfvofwqfypfvofxoeypfupgyqdvpevofyqdvpetofwqfvofwqfvpeypfxpcyqdwqfvpevofxqypcvpeypgwndwpgwqdvpeyqdvpewqftpeyqdvpexpcyqdwqfvpewqdyqdwqfwqfwqfwqfwqfwqfwqfwqfvpeyqdxvpevpewqfwqfvpewqfxpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfxoevpevpeupgxoeyqduqfwqfxpcypfyqdxoxpcypfyzxntpewqfzqdwndupgtpeyqd~wnyqdvpe}xoĽwpgvpeُvof|voyqdypfvpeyqdvpe~wnwqfvpewqfvpevpewqfvpevpewqfvpcyqdvpewqfwqfupgyqdwpgwvpexpcwpgwvpexpcێyqdx~wnwpgypfwpgtpeyqdvpeyxrgxoewqfxoexpcypfvofwqfvpevofwpgvpevpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpeyqdvpewqfypfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpevpewqfwqfvpevofvpeupgyqdvpewqfwqfupgxpcxof׻¿wqfyqdvoftofwqftofyqdxpcκxrgwqfwqfwqfvpewqfvpevpewqfwqfypfxpcwqfwndyqdvpexpcupgwpgڻvpexpcxoexpcwqfzuobwqfŹynxoe֪wpgvpevpewpgwqfwqfwqfwqfwqfwqfwqfwqfvpewqfzqdyqdwqfwqfwndypfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfvpevpewqfvpevofypfvpewpgvpevofxoexqh}wpypfvpewqf}wpvpeypfupgxrgxoexqhzvpewqfwqfvpevpewqfvpewqfvpexoeypfxoexoeypfxpczrexpcvpevpexozvqypfwqfwpgwpgxoewqfvpeyqdypfyqdvofvofypfxoevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcxvpexpcvpewqfxoevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpewqfwndypfypfwndyqdvpevpeڨᡛvpcvpcvpcvpe׻|wnypfypcwpgypfzqdxoe⼷xvpewqfy뻷vofwqfvpewqfxoewqfÿ~ypvpeyqdwqfvpewqfwqfvpewqfwqfwqfwqfvpevpewpgupgwpgwqfvofvpewqfxpcwpgتvpewpgxoewpgtofרy㠝uodwqf~ypvpcwqfyqdvpcwqf|wnשxnwqdtof̘vofxpcvofשvpexpcypfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfypcyqdvpevofyqdvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfvpevpewqfwqfxpcwqfvpexoewqfxpcwqfyqdtofuqfzqdxoexrgwqfvpeypfxoeypfyqdwqfvofwqfypfwqdwqftpevpeypfypfyqdyqdvpcwqfvpevofwqfvpewqfupgvofxoezqdvpewqfxoexpcwqfuohxpczqdvoftofwqfypfvofvpeyqdvpewqfwqfxoewqfwqdvpevpexoeyqdxpcwqfvofvpevpewqfvpevpevpevpexźvpewqfypfvpexrgvpevpewqfvpewqfupgyqdxoeypgvofwqfvpewpgxofwqfvpewqfuodzrexpcvpewqfvpewqfyqdypcypcyqdvpevpewqfxoewqfypfypfvpevpetpeypbvpewqfvofxpcupgzqgyoeypfxoexoezqgxoeypfypfxoevpeyqdwqfuodtofupgwqfwqdyqdvpevpewqfwqfwqfwqfwqfwqfwqfwqfxpcvpevpeyqdynvpevpewpgxoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpcwqfwqfvpewqfwqfvpexoevpewqfyqdwqfvpcxrgyqdvpevpewqfvpevpeypfwqfvpewqdwqfvofypgxoeypfypfypfwqdvpewqfuodwqfvpeuqfupgwqfxoeyqdxpcyqdyqdyqdxpcyqdxpcypfyqduodwpgtofvofwqfyqdxpcxoewpgvpeyqdwqfxoevpeypfxoevpcwqdvpexrgwqfvpewqfwqfwqfwqfvpevpewqfvpewpgypfvpewqfypfxoeypfypfwndypfxoexoevpeypfypfxoewqfyqdxpcyqdvpevpeypfzqdvpeupgwqfzqdzqdvpewqfyqdyqdtofwpgypcvpexrgvpexoeypfxpcyqdvpcyqdwpgypfwqfzretofvpewqfxpcxpcypfvpewqfvpevpeypfwpgxpcwqfyqdwqfxpcxpcwqfuodwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoexrgvpewqfxpcwqfxoevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqdvpevpewqfvpewqfvpexxvpewqftofypfvofwqfxoexoevofwqfyqdyqdypfwqfvpewqdwqfxoexoeyqdwqdvpewqfwqfxpcwqfvofwpgxoeyqdxpcypfvpewqfvpewqfypfvpewqftpetpetoftofypfyqdypfwqfvpevpewqdwqdvofxoewqfxoetpeypfyqdxoetofypfxpcyqdxoewpgwpgwqfyrcvpewqfvpewqfvpevpevofzqdwqfwqfvofvpewqfvpewqfwqfvpewqftofvpexoeypfvpeypfwqfvpevpeypfxoewpgvpexpcxpcwqftofwqfxoeypfvpevpewqfwqfypfvpeypfvpevpeypfvpeypgvpewpgypgwpgxpcwqfypfwqfwqfwqfwqfvpewqfypfypfxoevpezqduqfvpevofxoewqfvpewpgvpeyqdwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfxnypcupgvpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpctpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvofvofvpevpewqfsphupgwqfvpewqfvpexoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpewqfvpewqfwtofvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoeypfwqfvpeyqdyqdxoevpewqfvpewqfvpevpewqfyqdxofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpcvpewqfvofwpgwpgwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoeypfxoeypfvpeyvpeypfxoewqfwqfxoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpewpgvpevpevpcxpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpexoexrgvpevofvofwqfvpewqfvpeypfypftng}wpvpewpgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypfxoexpcxreuobxpcypfypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdxoeypfxoeypfypfvpewqfvofvpeyqdxpcypfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpewqfvpevpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfxpcyqdypfxoeypfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoevpevpezrewndwqfxoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvofvpexrgvpcwqdwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfxpcxpcypfyqdxpcxoevpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpevpevpevpevpewqfvpevpevpevpevpevpevpevpewqfvpexoeypfwqfwqfwpgvofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdwpgwqfxpcwqfvpeyqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpexrgwqfvpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvofvpevpewqfvpewqfvpewqfwqfwqfvpewqfvpewqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfvpewqfvpevpexoexoexoexoexoexoexoexoevpeuobwqdwqdvpcvpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdvpevpezrevofwqfxpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfvpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypfxoevpcvpcwqdvpexrgvpewqfvpewpgvpewqfxoexoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfvpevpewqfwqfypfypfypfypfypfypfypfypfvpexrgvpevpeypfyqdyqdxpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewqfvpeypftofupgvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypfvpewqfuodwqfwqfvpeypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewqfvpcvpcvpewqfvpewqfxoevpewqfvpeypfxoexoevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpevpewqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfuodwqfxoeypfxoexoexoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwpgwqfvpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfvpevpewqfvpcyqdypfvpexrgxpcyqdypfvofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpcwqdvpevpevpewqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvofwqfxoewqfvpexpcxoevofxofxoexoeypfwqfxpcyqdvpevpexoeypfwqfvofwqdyqdwndwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfvpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpewqfwqfvpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfvpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfvpewqfwqfwqfwqfxrgxrgwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgyshyshxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgwqfwqfxrgxrgxrgxrgyshyshxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshxrgxrgxrgxrgyshyshyshyshyshyshyshyshxrgxrgyshyshyshyshyshyshyshyshyshyshyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfxrgxrgwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshyshxrgxrgxrgyshyshyshyshyshyshyshyshxrgxrgxrgxrgyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfwqfvpewqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgwqfwqfwqfxrgxrgxrgxrgxrgyshyshyshyshyshxrgxrgxrgxrgxrgxrgyshyshyshyshyshyshyshyshyshztiyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshztiztiztiztiztiztiyshyshyshyshyshxrgxrgxrgyshyshyshyshyshyshxrgxrgxrgxrgyshyshyshxrgxrgwqfxrgxrgwqfwqfxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfvpevpewqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfvpevpewqfvpevpewqfwqfwqfwqfvpewqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgyshyshxrgxrgyshyshxrgxrgxrgxrgxrgxrgyshyshyshyshztiztjyshyshztizujzujzukztiztiztjztlztmyslztjztjzukzvlzvkzti{ukxuq~{v|w{wmxshzujytjysiyshyshztiysjytjysiztjztkztlysmyrkzsjztizujztiyshyshyshyshyshysiysiyshyshyshyshxrgxrgxrgxrgysh|vlysjxrgwqfwqfwqfwqfwqfxrgwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgyshxrgxrgxrgxrgyshxrgxrgxrgyshyshyshyshztizuj}xm~|t|}szuj{ulv{}|ru|wpzzxzonkiqir_iWj_~urpy{zpstyyhwZuOdMSnektq|vwyzsp{vu{{nnhukflsj}{orbwau]q_tqr{}}vwonkcysn~wytnutlzu|pyslgyuk~yozwnwthyti}wu{q}qynxqtysjyshxshxrhxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgyshyshyshxrgyshyshyshxrgyshyshyshztiztjzujytiyti}wnvpoxnZT,IYRtzv{nUYK$NG ? BE]z|sU{LJOYTgGSALQ_[rVpL^H@S/Q? ?E#Q0P"DA> B2Uzkm_}NKJ&R&V'QNV;_Zepsv_oy^NW3I;@Gun|z|~|wzzzxtsqk{yr}|uxvo|wnytiwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfwqfxrgxrgxrgxrgyshyshyshyshyshyshxrgxrgyshyshyshztiyshyshyshzukzys|~|z~z{~{yyzfG`; DEF9`ulJOE OLB O_rՇuRhF"R2R?F6D3SD[QQNF=CDFGCCLN JGKF]qmWGABH OK F DF;HaThk_I^BE FI KG&B>Mlhi_|^wbqrstvyuqxsqxqrwplwqgxrgxrgvqfvpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfxrgxrgxrgxrgyshxrgxrgxrgxrgyshyshztiztiztizujyshzti|wm~ypywqsrrj[bpyiLFGT M G.axwwiJAEQSHPZqڂpQ]FO SCAPSH@EQ UI@ITTLG3Pleo^HCEKR SKD"DCQo`jleYpF1F OQLH+JMWva_}RpMnRuYgdbTvGJB/X&HJVdZh[`[VQQE@BL UPHB$J@WSZMRCHGLXVn`dZvNOD!FL K B=A=JhUcqqg~ncrfeajfqojy{vz{zxrxrhwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshyshzti{vlzxr{wo{uk|ztzndaypkTsToa}\pJVS`^pbuWqE;MWXUI+Ta[fX]XbKNHTYVF"PiabcO]HNQOBJSKAMZXE?QYUH@ K3WARXOCDK T#PFA!G>VUY_S_IGH!P WZWMI6Pc_ilh^Kg:$6AE,EMX|mmjowz{wjwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfvpevpevpewqfvpevpevpewqfxrgwqfwqfxrgxrgxrgxrgxrgxrgyshxrgxrgyshyshyshyshzti|wlru|v{kc\UyrڇaoJ4U9U@MRNNOF>HY]OBDNSMD@IS&O+I.J+R^d c#\L"E7PZ]u`r^l\uSnE?HSRF<]dcab^SPvrtz}vrwnqtmkvpfvpexrgxrhxrhvqfvpevpevpewqfwqgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfxrgxrgwqfyshyshyshxrgxrgxrgyshyshyshyshyshyshyshzulx~xzk]dT}Sqa`XpntǖO.H PG@KPMGJ\] [^SFNMLDK^\\LG"O"OL"APZYUHTWLH[ ]VHO^]VGIROCEV]_RBDPSPSSE?L]_OEIPVPECNUJCRd!m"k(k'e%NC L-R3Q2R9REHED.O]UD%FCYb_i]iWjReMSI?E/@ BV,`B`Rlktw{yz}~}~tthroixt~zxqrtr}xqjwqfwrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfwqfxrgxrgwqfwqfxrgyshxrgxrgxrgyshyshyshyshyshyshztizti{uk~yoi]uUt^gWsLcXp`wS]WStߓk[HL M@EQSMFYc#a!b"`"NIQPLGY"f"`!Y!FIPNEK^^ ^RO]XM X b!^ QL^ d!\!LJUXNIX!`!a W FLXWUZZJCR!a `QJPX^XJIT]NE\%r+v+s+t*l)P#GNQNOJBL ^g!Z#GF P&S%N,G7F5G'IM S XOAA)JQUt`fdZOaM?WB[FR>M;M>pl}zq{xwtm{um{vlwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfxrgxrgxrgyshyshxrgxrgxrgyshyshyshyshyshyshyshztizti{uj|lZR|FdTmbwXdGMMMXRR?J0cCÍ_`a#D9">>#D9#?. 3) *.!,0!,+ +* .-!3, /()$$'&, *. ,+*$%% ** 0&)#$"#*&5!06!4.!,& &$*-51 <5!>5"<1"19%/A$5;"5>#6@%8A$9E&9C%BI%XO&_I%RL$\P'gI&VQ&An,Ix.Zm,PN(BH'\b)i)\(|V(Vw/Q4o2p3q1ok+pc)t){+q*d'h)~~.20,u.fNh|zoy~hbx~em~ohovmckmp{~zwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfxrgxrgwqfwqfxrgxrgyshyshyshyshysh|wo}t~u~Ѿzzti|ry|vk{tnpcSKGITRDGXUJO]\XT!m-75y15r5v1o4v763rx/c5v76~894t|0i8:92j4t96z~0jq,bx.jj+`[)TM&EO(GA%>5"2/!-* *+ +( )"#!"    !""" ""() -* -&'' 2 &2!+3",9$18"13 :]Skl[VfsulZb{x`iqmywej|odgytkwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfxrgwqfwqfwqfyshyshxrgxrgyshyshyshyshysh{vm{йʽ||ʺ}wl~worMMJNZTGO^XN X c!c#`#\%v084t1y4t4u|2k4v771p|.h698872n0k7z1nn.]P(EN'EP(C>$8.!.)'* '$#"! "  ! "! ! # !#$% "!      %!#&!#  $%*1).7*.6%(/"$*+7>3FO4HR2BO3$5>"5H%;T'CR'CF&:U)KY)RK&D@#=L%?g+Lk,Sh+P\)GF%;R'Dj,Qk-Ql,Va*SH%KO'a[)oU'hO&eO&cQ%iM$l?$A^*G_(K\(H^)J`*GE$HA!sK#yM%yA"n;#?L'7P'BP'BT)=>$<6d< k< e,C2j6o1`0f-_'!E-?@5NO9M\3;N/7D6LY4JV3AQ17D)-71@M7M[7HZ6@V.7F3BO4BP3@P7M\1CM8J[Ih>Se0=IDbtVHl|>XeN|`ipwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfxrgxrgxrgxrgyshxrgyshyshyshyshyshztiztiztizti{uj{rˬ{ɶ|r}wl{i>UR!X"f$b#R"`%p(j([&i)u+x+o-h,}2722t97~0k{/i{1ji-]M(G<$98#6/ .%'" !"! "!# #!!  #()1!09$:C$DA$?D$:R&CW'DT(>M&GW(hd*b)a)k|/X4h2kt-[s-]2u3}2|z/io-e13/m,o|.\5m6q4k2ez0[3d6w43z.yd*vq*-{+y+w*v+Y&r,S5n5n5m5l1c\&d%l&d$W%|/Z7j5n6j2[S"[ c"b!` \T d*q0.z.r+U%DQWSQIMQg~y^^t|ze_pvsbcxzxn\iymcr}tk_uywowqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfxrgxrgxrgxrgyshyshxrgxrgyshztiyshyshztizti{uj{uj{uj{uj{uj{pxr{o^ʶw~xmxqRZZ$a&o)i,X'i+{/y-g+v.154s/p1}3o.l])S[)NK&C9#60!/$&!!! !! ""$ ##$%3"-=$6I&?E%A6#4L&?q-Sl-Te+`w.y00y.}0a7h5j3b{/ju,.{,g)s-h3p3/rn+f/201p-wi+p01|-]*nj-Q5f6n5l3gq/\y.m000p-](j(p(m'l'l'e%Q&e2Z6o4j4k5e{.aR"_!g$V ^'x5Z6l4i5bo*kP[]ZYVMe),v)s(m'Q$@NWSQHF&[zii}h`vxapۀ~|qbmzqcbme`wrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgyshxrgxrgztiztiztiyshztiztizti{uj{uj{uj{uj|vk|vk|vk|xn~DZwm_nd[vqz|zo|qm`b#g){,z-j+/42s.s1z4{0n`*UF&A=%>3!5$% !!!"#!#" !"$&$%##2 /=#6H&;L&>E&;Z*Is.Vv-Wh,Pu.`1r3z2i,ex/[5m3bw.s01/s,r,e2h6u4oy.md'm(r)d(c*0v2/f*nl,|0/.~-f*~_)tv+-q,V'rq-Q6e4s2{0wd*ir-~/-{-d)W%e'j%f%e%g$S"`)W5c4m4i5j4bj*lK^]Kk+`7^4m3q2lS$JVUSTNGY#o(k%h%g%S!@FPP#Q"ME(Mbk|kfwl^oނr]k|uhfnrlVp{{vlwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgyshyshyshyshyshztiztiztizti{uj{uj|vk|vk|vk|vk}wl}wl}wl}xn~zq~jveodYygpwf{i{~xmq1o v255t.qt.iw0n`,YF%>5"10!,&&"# " #!$ ""():#45"2F$;`*Lq,U}.]^)Ku/X3g4j2o/b2f7q6o}/[t-m112o,~g+W3g4io-dp,z-x+o+d*w/r12w/x\'g&o&f$Z%l,1/o*_)ws,},y+z,v+]'X'~o)y*i'T&st.W3w10u.](rm+z,u+q*[%S"_"c#`#a#]!J!t/P5g4j4j5i3]Z$|I[TO~0^5w02r.yGJSOOOHDU"e"b!`!_ QBF1RHUSXUWQPLK[_vkcvp]kρwablv}zmh\i~~|{vnwrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgyshztiyshyshyshzti{uj{uj{uj{uj{uj{uj|vk|vk}wl}wl}wl}wmzq{unymvgte{klym]_XPb[Sxm^sfZvqj|qy~Xpii+]e-\P)I9$40 +'% !  !"!" $- +4"/=#7O&A_)Js.W1a4jv/Yf-Q5n7s6r0]p.Z3w3|2}/vw/]5g5l0[f*cw.~//{.Y'`/o3zu/ga)r*s)o(['p-s0/|/_(\#g#e#Y!]'u-}-u+])_)r*s)q)t)l(R%U%k(q'_$P%qq.i20/m+X'wh)q(p(k(T"P [![ [ ] PN"u2U6j4i4j6f1[Q KUFR!2s1./e*BJQONO%L-C0K'Y]ZWQE"GFWh]r\s^s[kOdYqocnԂt_gƀpgjeez}vxrvqgvpewqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfxrgwqfxrgxrgxrgyshxrgyshyshyshztiztiztizti{uj{uj{uj{uj{uj|vk|vk}wl}wl|vk|vk}wl{vl}yqxzzoyqfqj`sld|}wpPKJd_^ojfNJKc^[okfKDG*$ #"#!!/!-?#6F%;J%>c*Nz/Z2a0^y/\5k7s5n4l6r3h])K2b5k4j2bg,W.01}/q-h2f4u2ni*bi*z,u+y,^'j*o2/Y&h%m'j&^%X(p0}.{,d(R"^!`"ZS!g)u+u*f)P%`'o'l&k'n'f&N#S#g%j$V!M&un-}},x+y,^&N%|c'l'i%c$M!MXXUWGY%k4Y5j4h5j7du.cFJMD_$.{.w+x+]&B#I3TBSGSKVRUYHOC0KUVTNDGFWsdggdYzYlsfdr{hclz|qrzztyukwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfxrgxrgxrgxrgyshyshyshyshyshyshztiztiztizti{uj{uj{uj|vk|vk}wl}wl|vk|vk|vk}wl}wl}wl~xm~xm~xm~xm~xmynynynwVTV&#*.+0'#' "! !"#!$!$&&8"2G%;K'?r.W5p4k/^2h6q7q4l~/\1`5j4i4g5j5je*Nt/X5l4l4im+[l*~0.{.i*~y.o21s-q\(p)s)p)g'Y&t//b)Y"j$e$_$P#j*},r*l(R!S]YOP"j(o'o%\$L"a%j%f&c$h$^"H!S"c"b MK"{j*s*q(q(S&J#^"b!c X BKUTTRAd'e4^4l3o2w2rf'vCN$O(H,c)v&q(p(o([%F0KQXk]s]tbybUwGPCG LOP)I9FNRmbmoog]dssiirvpc]w}{rxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpewqfwqfxrgxrgxrgxrgyshyshyshyshyshztiztiztizti{uj{uj{uj{uj|vk|vk|vk|vk}wl}wl|vk}wl}vm~xm~xm~xmwmwmwmyoxoxoqjdkfd^[Z;9<"#! ""#!! !+!*E$:Y)FT(B]*I0^3g3iz/]1_7s3iw-Y1b5k4m3q}/d/^3g4j3h5k4rr-Ye,T2u2x2|v.i^)vz,x+u*g)i+x01|/Y'xa&m'j'g&V$i*~.m+R#_!b#[ M P&yu)o(l'\%KUZQCT$i%f$g$S!I \!c"_!\ `!W G S`[FJ#zf)n'l%g$N#H X [^P?GQOPJ@n+d2m201.Z+H?VTRWI?^!m i'g&f"^K'JFTi]`chdXHNI4SEY[^hZiNeMj\hq||kaosknjqzwpysiyshyshyshxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfxrgyshyshyshxrgyshyshyshyshztiztiztizti{uj{uj|vk|vk|vk|vk}wl}wl|vk|vk}wl~xm~wn~wn~xm~xmwmvm~wozur^Y[DCB-+.    "$" #" $"#1 /N'@U)Cp-U3k7t1b}0\5m6n7o0\g,O4f4hx/[0j2w1y1{/wv/b4i3q1u1v3x.n[)Z}.|01}0~Z)qi(u)q(h(_(w--~-f)U$d$f$c#Y!W$t*t)Y&N^[NA!]'q'i%c%OHSTE>X d#`"^!ME V]XXZSFL[V@J#d&h%f$_#IFSYXK;FO%Q+S0M6I;j/o(-|-.v)R6N`^yXuMNV aa \ \!\RJ$J7JJ\quvotyzx}}~w}xskplnnv~}z~wytlvxpu~y|ztlztjztiztiztiztiyshyshxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfxrgxrgxrgyshyshyshyshyshyshyshztiztiztizti{uj{uj{uj|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl~xm~xm~xm{ukvqhqmg`\X<99#$"# %!&JHFfg`nacr4Ww*Y3h2a2e6q6oz/\q,T4i4k3p0ei+R1d5n|/`z.s000{.k,r0w10020X)bn,0./\(u[%n(m&h%X%e)w+x+s*W$V"_"`![O b&q'd&I O[TCE!{c#i#d"[!FFSP>@V[ZXLEOWVWWKAKXO?G[ `!a!ZEBNSRH@%G=RLXYZ`UaKQ^0}w"y"s&w&i!O9UsfaSaQ*UTRTRJJ \<=1+0A;Bspp{wo|q8l|(Z4e2c0\4g6k1]l+U2r2w1~0}k,_y.g3}z/mo,y//-}-g*q,/..~/0\(pc)y,z+|,h*N$d$g$f$X"U%m)q)r(_&M!WZZMO"g%i%T!@SVN=F_a_ SAG-VATKA=@RXWUJDIQRPQG?HSPB"@#QZ]WB>HPU,QBHMLWTg\paz_SqUEb(g i!n `O1UqiiWME[1\(SU(_?oaxvzozozozoynzoynynynynyn~xm~xm~xm~xm~xm}wl}wl}wl}wl}wl}wl|vk|vk{uj{uj{ujztiztiztiztiztiyshyshyshyshyshxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfxrgxrgyshxrgxrgxrgyshyshztiztiztizti{uj{uj{uj{uj|vk|vk}wl}wl}wl|vk|vk|vk}wl~xm~wn~xmyo{wpfeb1/1"#!#*'*@>@SPNd`\zte]Vphd}s|rp|.cw)V1d2fy/\3m4t0ig+^/200j+sk+m1x.}d*xv,{-u+y+g(c*w-},y+v+|+g(W&}s+t)q)p*M#{S b"a"^ P!\&k'j&h&P!LWXSGW c"`!KCPSI;!EX[ZNB-KQ]q]wIUB"J P STKCBFMRT#K)B(I.U>VHJFD5GMURE<B(RF\aXgQhRnTsX~ag\RmUH\6j?k>`7eXizrpt|r}~oufyr|vzq{p{p{pzozozozoynxnxnxn~xm~xm~xm~xm~xm~xm~xm~wn}wl}wl|vk|vk|vk|vk|vk{uj{uj{uj{ujztiztiyshyshztiyshyshyshyshxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfwqfwqfvpevpewqfwqfwqfxrgyshyshxrgxrgyshyshztiztiztiztiztizti{uj{uj{uj|vk}wl}wl|vk}wl}wl}wl}wl}wl~xm~xm~yo}yseb`.,/!!,*,B?A]ZZyupyumzp|q}twl\vg{n|szuc|-hx+]y/k0ut.g0{1}.ze+hs.1~/.j)b(u/}/_)wi(v*m)p'k'Z&j)v*r)q*q)o(Q$}g'n'l(n'Z&E Z[\QL b#d#e#\"INTSIEW_ZFC#R7WBOEC=F!QVWMD$KJ]xcU{KEJJLML#I-G/G.I4PAWQPTCIKPYd^mXlM[H=H IO$N?BC>ALW_va\\`zhuu|tsrk}uu}s}{sw{t|s~xy}r|q}r|q|q|q{p{p{p{pzozozozozozozoynxnxnxn~xm~xm~xm~xm~xm~xm}wl}wl|vk|vk~ukvlvl{uj{uj{ujzti{ujztiztiztiztiyshyshyshyshyshxrgxrgxrgwqfvpevpewqfwqfvpewqfvpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfxrgxrgxrgyshxrgyshyshyshztiztiztizti{uj{uj{uj{uj|vk|vk|vk|vk|vk}wl}wl}wl~xm~xm~xmytkurl][X-,/$ (,(-JGHgc_plfytmzp|q|q|qvzr]|i{p`|tc}t|x^(zs)km-r}/p-u{.0}.e*tg*~-y,w+j(]'t+}-^'}V%l'm(h&k&Z$[%m(n'l(k'l'U%V$j%f&f$c$H!IYVTGP` ^ ` RBMQNE!ETZSDH?Ue`t\tM]D0HL M G@C0P`YXTpOKI9LFQ WRFE?PcYy\UO`I7N+\;[;S7RC^\hurtty~y|ekinwnrihoxz|hlwiprtns~~v~v{x~uvvuuuuutttt~s~s~s~s~s~s}r}r}r|s|s}r}r}r}r|q|q|q|q{p{p{pzozozozozozoynynynynyn~xm~xm~xm~xm}wl}wl|vk|vk|vk}wl|vk|vk{uj{ujzti{ujztiztiyshyshyshyshyshxrgyshxrgxrgwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfxrgxrgxrgyshxrgxrgyshztiztiztizti{uj{uj{uj{uj|vk|vk}wl}wl|vk|vk}wl~xm~xm~xm~xookfQNN)')  "$:8;ZXVkgbzun|wm~xn{p{p|q|q|qwztkpicz©wwv|l~s~W|"o)b)}t*j*f*w+z+k)X&e&p'k&i%]%\'q(m'M$L!b!c#^#`!R P"a$d#_"a"_"N S `![ \ ] KBOPOG?LTUSEE;Ub]nYnJQD JME =A2X`~rr|vqyz~yyyxxxz{{yy|yvwwwww|wuwvvvuuvvuuuuuttttt~s~s~s~s~s~s}t|s|s}r}r}r}r|q}r|q|q|q{p{p{pzozozozozoynxnxnxnwmwmwm~xm~xm~xm}wl|vk|vk}wl}wl|vk|vk{uj{uj{uj{ujztiztiztiztiyshyshxrgyshyshxrgxrgxrgwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgyshyshxrgyshyshyshztiztiztiztizti{uj{uj|vk|vk}wl|vk|vk|vk}wl}wl~xm~xm~xnnjeSQQ !   ##=9;QMNe_^ytn|s{p{p{p{p|q|q|q|q}r{sqkdl˵}pa|zq~s}zMx"p)W&{n(m(Z%i)s(n'[&Z$h%g%f#\"U#d%m%\$E!}N]ZZWIP ]] [\RHWZVXUEC#P3W=WEMGA0DMQG @A7QfcaOnFDV@mZl^jczy}}|zyyyyyyyxxxxyyxxxxxxxxxxwwvvwwwwvvvvvvuvvuuuuutttttt~s~s}t}t|s}r}r}r}r}r|q|q|q|q|q|q{p{p{p{pzozozoxnxnxnxnxnxnyn~xm~xm~xm~xm}wl}wl}wl}wl|vk|vk{uj{uj{uj{ujztiztiztiyshyshyshxrgyshyshxrgxrgxrgwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfxrgxrgxrgyshyshyshyshyshztiztiztizti{uj{uj{uj|vk|vk|vk|vk|vk}wl}wl}wl~xm~xmxb]] =:KNLPL)D)FMI EH?:P*V1N,Y?fWqku~{{{zzzz{{{{{{{{{{zzzzz{zzz{{zzzzzzzzzzzyyyyyyyyxxxxxwwwxxxwvvvvvvuuuuuutt~s~s~s~s~s}t~s~s}r}r|q|q}r|q{q{q{q{p{p{pzozozozozoynynxnwmwm~xm~xm~xm~xm}wl|vk}wl|vi}wl|vk|vk|vk{uj{ujztiztiztiyshztiztiyshxrgyshyshxrgxrgwqfwqfwqfvpewqfxrgxrgxrgxrgyshxrgztiztiztiztiztizti{uj{uj}tj~uk~uk}wl}wl}wl}wl}vm}wl~xm~xm~xmzqztmtnhyphzozozozozozo{p{p{r|q|q|q|q|q}r}r|s}r}r~sxʺyvʾvvukDU YAH_QHX ^YMDNTRLBGLN QD=C%L8VGZQTYKLB+V2Y9T7XE`Yupw~z{{{|{{||||||||||||||{{{{{{yy{{{{{zzz{{{zzzzzzzzzzyyyyyxxxxxxxwwwwwvvvvvuuuuuuuuutt~s}s~s~s~s}r}r}r}r}r}r}r}r|q|q{p{p{p{p{pzozozoynynynxnxn~xm~xm~xm}wl}wl}wl}wl}wl|vk|vk{uj{uj{uj{ujztiztiyshztiyshyshxrgyshyshwqfwqfwqfwqfwqfwqfxrgyshyshxrgxrgyshztiztiztiztiztizti{uj{uj~uk~uk}wl}wl}wl}wl}wl~xm~xm~xm~xm~xmzo~ynynynzozozo{p{p{p{p|q|q|q|q}r}r}r|s|s}r~s~s~sxu|ûyzvvveA](Y5O+UVC@RYTFCKONC:Q3dA[1W4eV|~{dg]feqgvtu|{y}z|||||||||||||||||||||||||||||||||{{{{{|||{{{zzzz{{zzzzzzzyyyyxxxxxxxwwwwwwvvuvvuuvuuuttt~s~s~s~s~s~s}r}r}r}r}r}r|q|q|q{p{p{p{pzozozozoynynxnxn~xm~xm~xm~xm}wl}wl}wl}wl}wl|vk|vk|vk{uj{uj{ujztiztiyshztiyshyshxrgyshyshxrgxrgwqfwqfxrgxrgyshyshyshyshyshyshztizti{uj{uj{uj|vk}wlvl}wl}wl}wl}wl}wl~xmynynynynynynynzozozozo{p{p|q|q|q|q|q}r|q}r}r|s}t|s~s~s~stv}u|~w{{vvvx{|{syzfJPS)`MaBQS\8ld}|w|whcOfWsk~}|{{~~|z{{|}|||||||}}}}|}}}}}}}}||||||||}}}}}}}}||||||||{{{{{{{{{{{{{zzzzzyyyyyyxxxxxwwwxxxvvuvvuuuuuuuuttt~s~s~s}r}r}r}r}r}r|q}r|q|q{p{p{pzozozozozozoynynynyn~xm~xm~xm}wl}wl}wl}wl}wl|vk|vk{uj{uj{ujztiztiztiyshyshyshxrgyshxrgxrgxrgxrgxrgyshyshyshztiztiztiztizti{uj{uj{uj{uj|vk}wl|vk}wl}wl}wl~xm~xm~xmynwmxnxnynzozozozo{p{p|q|q|q|q|q}r|q}r}r}r|s|s~s~s~stttuzvu~vvy|wxxxwxxy}}x~}{~tk[obzyz{~}{{{z{{{{||||||||||}}}}}}|||}}}}}~~~}}}}}}}}~~}}}}||}}||||||||||||{{||{{{{{zzzzzzyyyyyxxyxxwyxxxxxvvvvvvuuuutttt~s~s~s~s|s}r}r}r}r}r|q}r|q|q{p{p{pzozozozozoynxnxnyn~xm~xm~xm}wl}wl}wl|vk|vk|vk|vk{uj{uj{uj{ujztiztiyshyshxrgyshxrgyshyshxrgxrgxrgyshyshyshztizti{uj{uj{uj{uj|vk|vk|vk|vk|vk}wl~xm~xm~xm~xm~xmynxnxnxnzozozozo{p{p|q|q|q|q|q|q|q}r}r|s|s~s~s~s~stttuuuuvz{vvwwwwxyxwwxyyyyyz{zz{zz{{{{{{{{||||}}}}}||||~~~}}}}~}}}}}}}}}}}}}}}}}}}}}}}}~~}}}}}}}}|||||}|||{{{{{{{{zzzzzzyyyyyyxxxyyxwwxvvuvvvuuuuttt~s~s~s~s}r~s}r}r}r|q}r|q|q|q{p{p{pzozozozoynxnxnyn~xm~xm~xm~xm}wl}wl|vk|vk|vk}wl|vk{uj{uj{uj{ujztiztiyshyshztixrgyshxrgyshyshyshyshyshztizti{ujzti{uj|vk|vk}wl}wl|vk|vk}wl}wl~xm~xm~xm~xmynxnynynzozozo{p{p{p|q|q|q|q|q|q}r}r|s|s|s~s~s~stttuuuuuvvx}vwwwwxxwxyyyyzzzzzz{{zz{{||||||||}}}}||}}}}}}}}}}}~~~~~~~~~~~~~~~~~~~~~~~}}}}}~~~~~}}}}|||||||||{{{{{{{zzzzzzyyyyyxxxxyxxxwvvvvuuuuuutttt~s~s~s~s}r}r}r}r}r}r|q|q{p{p{pzozozozoynynynyn~xm~xm~xm~xm}wl}wl|vk|vk}wl|vk|vk|vk{uj{uj{ujztiztiyshztiyshyshxrgyshztiztiyshyshzti{uj{uj{uj|vk|vk}wl}wl}wl}wl}wl~xm~xm~xm~xm~xmynxnxnzozozozo{p{p|q|q|q|q}r}r}r}r}r}r}t}t~s~sttttuuuuuuvvvvwwwxxxxxyyyyyzzz{{{{{{|{{||||}|}}}}}}}}}}}}~~~~~~~~~~~}~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}||||||||||{{{{{zzzzzzzyyyyxxwyxxwwvvvvuuuuuuttt~s~s~s~s~s|s|s}r}r|q|q|q|q{p{p{p{pzozozozoxnxn~xm~xm~xm~xm~xm}wl}wl}wl|vk}wl}wl|vk{uj{uj{ujztiyshyshyshyshyshztiyshztiztiztizti{uj|vk|vk|vk}wl}wl}wl}wl~xm~xm~wn~xmynynynxnxnxnzozozo{p{p{q{q{q|q}r}r}r}r}r~s~s~s~s~stttuvuvvvvvvwwwwwwxxxxyyyyz{{zzz{{{|||||||}}|}}}}}}}}~~~~~~~~~~~~~~~~~~~~~}}}}~}}}}}||||||||{{{{{z{{zzzzyyxxxxyyxwwwvvwwvuuuuuttt~s~s}t|s}t}r}r|q|q|q|q|q|q{p{p{pzozozoxnxnyn~xm~xm~xm~xm~xm}wl}vm}wl}wl|vk|vk|vk{uj{ujzti{ujztiyshztiyshyshyshzti{uj{uj{uj{uj|vkvlvl|vk|vk}wl~xm~xm~xm~xmynynynynzozozo{p{p{p{p{p|q|q}r{r|s}r}r~s~s}s}s}s~tttuuuuvwwwwxwxxxxxxyyyyzyzz{{{{{{{|||}}|||}}}~}}~~~~~~~~~~~~~~~~~}}}}}}}}|||||{{{{{zzzzzzyyyyxxxxwxxxwwwwvuvuuuuut~s~s~s~s}t}r}r}r|q}r|q|q|q|q{p{pzozozozoxnxnxn~xm~xm~xm~xm~xm}vm|vk|vk|vk}wl~uk}tj}tj{uj{ujztiyshyshztiztizti{uj{uj{uj|vk}wlvl~uk}wl}wl}wl~xm~xm~xmynynynynzozozozo{p{p{p|q|q|q}r}r}r}r}r}r~s~s~s~ttttuuuvvwwwxwxxxxxxxyyyzzzzzz{{{{{|||||}|}}~~~~~~~~~~~~~~~~~~~~~~}}}}}|||||{{{{{{zzzzyyyyxxxxwxxxxvvvvuuuuuttt~s~s~s}r}r}r}r}r|q|q|q|q|q{p{pzozozozoynynynynyn~xm~xm~xm}wl}wl|vk|vk}wl~uk}tj{uj{ujztiztiztiztiztizti{uj{uj|vk|vk}wl|vk|vk}wl~xm~xm~xmwmwmynynynzozozo{p{p{p{p|q|q}r}r}r}r}r~s}r~st~stttuuuuvvvvwvwwxxxxxyyyzzzzzz{{{{{||||}}}}}}}~~~~~~~~~~~~~~~~}}}}}}}}||{{{{{{zzzzzyyyxyxxxxwwwvvvvuuuuttttt~s~s~s}r}r}r}r}r}r|q|q{p{pzozozozoynynynynyn~xm~xm~xm~xm}wl|vk|vk|vk~uk|vk{uj{ujztiztizti{uj{uj|vk|vk|vk|vk|vk}wl}wl}wl~xm~xmynxnxnynynzozozo{p{p{p|q|q|q}r}r}r}r|s~s~s~s~sttttuuuvvvvvwwwxxxxxyyyyzz{{{{{{{||||}}}}}}~~~~~~~~~~~}}}}}}}}|||||{{{{zzzzzyyyxxxxxwwwwvvvuvuuuttt~s~s~s~s~s}r}r}r}r}r|q|q{p{p{pzozozozoynxnxnxn~xm~xm~xm~xm}wl|vk|vk}wl|vk|vk{uj{ujztizti{uj|vk|vk|vk}wl}wl|vk}wl~xm~xm~xmynxnxnxnzozozo{p{p{p|q|q|q|q|q|q}r}r|s}t~st~stttuuuvuvvvwvwwwxxyyyyyzzz{{{{{||||}}}}}}~~~~~~~~~~~~~~}~}}}}}}||||{{{{zzzzyyyyxxxxxwwvvvvvuuuuutt~s~s~s~s~s}r}r}r}r|q|q|q{p{p{pzozozozoxnxnxnyn~xm~xm~xm~xm}wl|vk|vk}wl|vk|vk{uj{uj{uj|vk}wl|vk|vk|vk}wl}wl~xm~xm~xmynxnynynzozozo{p{p{p|q|q|q|q|q}r}r}r}r~s}t~stttuuuuuvvvvwwwwxxxxyyyzzzz{{{{||||}}}}}}}}~~~~~~~~~~}}}}}}||||{{{{zzzzyyyyyxxwwwxvvvvuuuuuttt~s~s~s}r}r}r}r}r|q|q|q|q{p{pzozozozoynynxnyn~xm~xm~xm~xm}wl|vk|vk}wl|vk|vk{uj|vk|vk}wl|vk|vk}wl~xm~xm~xm~xmxnxnxnynzozozozo{p{p|q|q}r}r}r}r}r|s~s~s~s~s~tttuuuvvvvvwwwxxxxxyyzzzzz{{{|||||}}}}~~}~~~~~~~~}}}}}}||||{{{{z{zzyyyyyxxxxwwwvvvuuuuttt~s~s~s~s}r}r}r}r|q|q|q|q{p{p{pzozozoynxnxnyn~xm~xm~xm~xm}wl|vk}wl}wl|vk|vk}wl}wl}wl|vk}wl~xm~wn~wn~xm~xmxnxnxnzozozozo{p{p{p|q|q}r}r}r|s|s}t}tttt~tuuuvvvvvvvwwxxxxyyyzzz{{{{{|||}}|}}~}~~~~~~~~~}}}}}}}||||{{{{zzzzzyyxyyxxwwwvvuuvuuuttt~s~s~s~s}r}r}r}r}r{q{qzp{p{pzozozoyoxnwm~xmynyn~xm~wn}wl}wl|vk|vk|vk}wl|vk|vk}wl}wl~xm~xm~xm~xmynynzozozozozo{p|q|q|q|q|q}r}r|s~s~s~s~sttuuuuuvwwwwxwxxxyyyzyzzz{z|||||}||}}}~~~~~~~~~~~~~}}||||{{{{zzzzyyxxxwwwwvvvuuuuuutt}s}s~s~s}r}r}r|q}r}r|qzqzq{pzozozoynynynynyn~xm~xm~xm}wl}wl}wl}wl|vk}wl}wl}wl~xm~xm~xm~xmynynynzozozo{p{p{p|q|q|q|q}r}r}r}r~s~s~stttuuvvvvvwxxyxxxxyyyzzz{{{{{||}}}}}}}}~~~~~~~}}}}}|||{{{{zzzyyyxxxxwwwwvvvuuuuut~tt~s~s}r}r}r}r}r}r|q{rzq{p{pzozozoynynynyn~xm~xm~xm}wl}wl}wl}wl|vk}wl}wl~xm~xm~xmynynynynzozozo{p{p{p|q|q}r}r}r}r~s~s~s~stttuuuuvvvvvvxwxxxyyzzzzz{{{|||||}}~~~~~~~~}}~}}}||||{|{zzzzzyyxxxxwwwwvvvuuuuttt~s~s~s}r}r}r}r}r|q|q|q{p{p{pzozozozoynynyn~xm~xm~xm}wl}wl}wl}wl~xm~xm~xmynynynzozozozo{p{p|q|q}r}r}r}r|s~s~s~s~stttuuuuvvvwwwxxxyyzzzzzz{{{||}|}}}}}~~~~~~~~}}}}}||||{{{zzzzzyyyxxxwwwvvvvuuuutt~s~s~s~s}r}r}r}r|q|q|q|q{p{pzozozozoynynwmyn~xm}wl}wl}wl~xm~xm~xmynynynzozozozo{p{p|q|q|q}r}r}r}r}r~s~s~s~stuuuuuvuvvwwwxxxyyzzzzz{{{|||}}}}}~~~~~~~~~}}}}}|||{{zzzzyyyxxxwxwwvvvvuuuttt~s~s~s}r}r}r}r|q|q|q|q{p{p{pzozozoynynxn~xm~xm~xm~xm~xm~xm~xmynynynzozo{p{p{p{p|q|q|q}r}r}r}r~s~s~s~sttuuuuuvvxwwwxxxyyzzzzz{|{|||}}}}}}~~~~~~~}}}}|||{{{zzzzyyyyxxwwwvvvvuuuutt~s~s~s}r}r}r}r|q|q}r|q{p{p{pzozoynynxnxn~xm~xm~xm~xm~xmynynynzozozo{p{p{p|q|q}r}r}r|s|s~s~s~s~sttuuuuvvvwxxxxxxyyyzzz{{|||||}}}~~~~~~~~~}}~}|||||{{zzzzyyyxxxwwxwwvvuuutt}s~s~s~s}t|s}r}r}r|q|q{p{p{pzozoynzoynxnxnxn~xm~xmynynzozozozo{p{p|q|q}r}r}r}r|s|s~sttttuuvvvvvvxxyyxyyzzzz{{{{||}}}}~~~~~~~~~~~}}}|||{{{{zzzzyyxxxyxwwvvvvuu~t~tt~s~s}t}t}r}r}r}r|q|q{p{p{pzozozozoxnxnxnynynzozozozozo{p{p|q|q}r|q|q|s|s}r~s~sttuuvuvvwwvwxxxzxyzzzyx||y|z|}}}~~~~~~~}}}}}||{{{{zzzyyyyxxwxxxwwuuuut~t~t~s~s~s~s}r|s}r}r}r|q{p{pzozozozoynynynynynzozozo{p{p{p|q|q}r|q}r}r}r|s~s~stttuuvvv~|}}}}}}}~~~~~~}}}}|||{{{{zzyyyyxxxxwwvvvuuuu~t~s~s~s~s~s}r}r}r}r|q|q{p{pzozozozoynynynzozozo{p{p|q|q|q}r}r}r}r~s~s~s~sttuuuvvvw|}}|~~~~~~~~}}}}||||{{{zzyyyxxxxwwvvvvvuutt~s~s~s~s}r}r}r}r|q|q{p{p{pzozozozozozozo{p{p{p|q}r}r}r}r}r~s~s~s~sttuuuuvvvx}||z~~~~~~}}}}||||{{zzzzzyxxxxwwvvvvuuu~tt~s~s~s|s}r}r}r}r|q|q{p{p{pzozozozozozo{p{p|q|q}r}r}r}r~s~s~s~sttuuuvvvvww{~~~~~~~}}}}}|||{{{zzyyyyxxxwwvvvuuuutt~s~s}t~s}r}r}r}r|q|q|q{pzozozozo{p{p{p{p|q|q}r|q}r~s~s~s~stttuuvvvvvwx¾Ŀ½½½½½þ½ÿ{~~~~~}~~}}}|||{{{zzzyyxxxxwwvwvvuuutttt~s~s}r}r}r}r}r|q{p{p{pzo{p{p|q|q|q|q}r}r|s~s~s~s~stttuuvvvvwwxyxyyzz|{}~|}~~}~~~~~}}}||||{{zzzzyyxxxwxxvvvuuutttt~s~s}r}r}r}r|q|q{p{pzo{p{p|q|q|q}r}r}r}t}t~stttuuuvvvvwwxywyyz{z|}z}|{|{~}~~~}}}||||{{zzzzyyxxyxwxvvvvvu~trtt}t|s}r}r}r|q|q{p{p{p|q|q|q|q|q|q|s}t~s~sttttuuuvvvwwxxvyyz{z{}}}}~}~}~~~}}||||{{{{zzyyyxxwxxvvvvuu~ttt~s~s~s}r|s|q}r|q|q|q|q|q|q|q|q}r}r}t~s~stttuuuvvvwwxxxyyz{{{z޷~~}}}}||||{zzzzyyxxxxxvvvvuuutt~s~s~s~s}r|q|q|q|q|q|q}r}r}r}r~s~s~stttuuuvvvvwwxxxyz{{x{z|~~~~}}}}|{{zzzyyyxxxwwvvvvvvutt~s~s~s~s}r}r|q|q|q|q}r}r}r}r~s~s~sttuuuuvvvwwxxxyyzz{x{|y~~~~~~}}||{{{zzzyyxxwwxwvvvvuutt~s~s~s}t}r}r}r}r}r|q}r}r~s~s~stttuuuvvvwwxxxyyzz{{|{{z~~~~}}}|||{{zzzyyxxwxxvvvvuuu~tt~s~s}t|s}r}r}r}r}r}r~s~s~stttuuuvvvxwxxxyyzzy{{z}}{|}üþĿĿĿĿ~}}}}}|||{{{zzzyxxwwwvvvvuuut~s~s~s~s}r}r}r|s}r~s~s~s~stuuuvvvvxxxxxyyzzzz{}}||}}~~~~~~}}|||{{zzzyyxxwwxxvvvuuu~t~t~s~s~s|s|s|s}t~s~s~stuuuuvvvxxxxxyyzzz{||}z{~}~~}}}}||{{{zzzyyxxxxxxvvuuuu~ttt~s|s|s~s~s~s~stuuuuuuvwwxxyyyzzz{|y}}}|}}ޑ~~~~}}||{{{zzzzyxxxwwxwvvvut~t~s~s~s~s~s~s~sttuuvuvvwwwxxyyzzz{{|~}{γ~~~}}|||{{{zzzyyxxxxxvvvvuutt~s~s~s~s~sttuuvvuvwwxxxyyzzz{{||}z|}~~~}}}||{{{zzzyyxxywwvvvuuut~s~s~s~sttuuuvvvvwxxxyyyz{{{|||z|}~~~}}}||{{{{zzyyyxxwwvvvuuutt~s~stuuuuvvvwwxxxyzzz{{{||}~~~~~~}}}||{{{zzyyyxxxwwvvuvutttttuuuvvvwwxxxyyz{z{{||}~|}~~ߏ~~~}}||||{{zzzyyxxxwwvwvuuuttuuuuvvxwxxxyyzz{{{||}}~|}ߐ~~~}}}|||{{zzzyyxxxwwwvvuuuuuvvvvwxxxxyzzzz{{||}}~~|ޓ~~~}}}|||{zzzzyxxxxwxvvuuutuuvvxxyxxyz{zz{{|}}}}~~}•~~~~}}||{{z{zzyyxxxxwvvuuuuvvwwyyxxyzzz{||||}}~~~~~~}}}||{{{zzyyxxxxwvvuuuuvwwwxyxyzzz{|||||}~~~}ޑ~~}~}}|||{zzzyyxxwxvvvvvvwwwxxyyzzzz{||}}}~~~ʜ~~~}}}}|{{zzyzyxxxwwvvvvwwxxxyzzzz{{||}}~~~~Ж~~}}}}||{{zzzyyxxwvvvwwwwxxyyzzz{{||}}~~~~~~}~~}|||{{zzyyyxwwwwxxwxxyyzzz{{||}}}~~~~~}}|||{{zzyyyxxxxxxyxxyzz{{{|||}}}~~ߔ~~~}|||{{zzyyyxxxxxwxxyyzzz{|||}}}~~ߔ~~~}}|||{{{zyyxxxwxxxyyyzz{|||}}~}~~~}}}|||{{zzzyxxwxxyyzzz{{||}}}~~~~~}}|||{{zzyyxxxyyyzz{{|||}~}~~~}}}|||{zzyyyxxyyzzz{{|||}~}~Ũ~~}}}||{{{zyyxyyzzz{{|}}}}~~~~~}}||{{{zzyyyyzz{{||}}}~~~~~~}}||{{zzyyzzz{{|||}~~~~~~}}}|{|{zzyyzz{{|}}}~~~⳰~}}}}||{{zzzzz{{||}}~~~~𕒊~~}}}||{{zzzz{{||}}~~~~~}}}||{{zz{{||}}~~~~~}}||{{{{{||}}}~~龻ÿ~~}}}||{{{{||}}}~~~}}||{{||}}}~~~~}}}||||||}}}~~姣~~}}||||}~}~½~}}|||||}~}~~~~}}}}}~~~~~~}}}}}~~~~~}}}}}~~~~}}~~~~~~}~~~~~~~~}}~~~~~~~~~~~~~~~~~~~~}}~~~~~~~~~~~~~~~~~~~~}}|~}~~~~}}}JJJ        ~~~}IHJ ~~omm\ZZVXXXXXXWYVVVUUUSUVQSSRQSNOSNOSONRNMQLNOKMN{}~|}IHJ *JW.]r+\r-\r0\s/[r+]q-\q0\t-\r0\t+]q~/20~GII   +]qEKHLLJKKKLJK:| (*+111"$%KKK  .]rDKLKKLKLKIKJL? rojkmn&DOAB@?B?B>@+*,JJJ  .]rFJKKKKKKLNKKLI:| IGF¿̤ ILKLLLJKL *)+IKK -\qFKKKKLKLKJLJKND(Sd @?;弻YXZ*\sLGNKMKLK *)-IKL  0]rELKLJNKKLHNILA5q#GW SQPت FKLKKLIH (-,{xz?CD  -\rEKLHKIJLLK!>L   ,,,~|{¿ţooo"  -[sGKJKMLJLKKN0i ###][Z޺/11=KKLKLI%GW ZY[QQQPPPPPPPPPQQQQQQQQQQQQRRRSSSSSSxxxjlm133 ,^rEKLJKLIKLMMH6h 245MLNOOOaaaytuΩ#INHLJK4tabf|{}#"$UUUY\`###&-8sEKJKHKMLLKKKK0h """PRS(ReHLKJNG467ccc hhhJLM (07rGKLJLLKIKKLKKM;| " ڳ>MMIJL'2???vuw;:< 1@;{LJJMMKJLKMNIIKK@ #!!IIKKH8tSOT{z|! "ddd\^_)(* %FZCKMJKJKJKJJIJJKJK>  wvxNRS(ReKLKKK aaa kkk{z|DCE$-,\tFJMJJJKKJJLJJIJJJJ>  uxv@>>>;;;ooorrrrrrrrr~`^]*** 3?4qIGJKJKKNLIMLILLPJLJD/7 wvxɳ ILJMH"stx"""mln=;; "(Sh@KHIJOJJMJKIK&Tf?M.j?JHNIF.:ghfPRS,;\^_'''2fHKLK(Sf$#^]_)))}|~TSU','ReCILKKJKJKLLKJLIHHINK< %\^_뭮 BMJHL&/!!EEEZY[vuwDCE%GW;{JKHONJKJJJIJLKHIJKLKGHKH4Ba\]ڸlpq !IKMLI%,"""<;=gfh::: ;L8tEKIIJLKLMKKLKKKKLIJHJLHIJGKD#*>;=ͧEHF;LKKIIL&-|{} 111tsuUTV)(* =K5rCKKKJLKMHJKJMLIJKLJLGJIGIHJJIJ#FT>:?£&&&-\qJLNLG&/SOT! LIKnmqSRT413 #FZ=|CNKJKKJJKLLKJJKLKKKJKJIGJ$Qf;L5xIKKE/aw 9:>ٲ:zKEKJM&GZ YYYvqs kjltsw]\`CBF')) (1.\n?KKLKNLIHKJKLLKJJJLLKJJKKIKJII $%11mH4`w 9:>Ƥqqq BNILIL9| BFGwyzuss  yuzrqsnkmLJJ9;<((( #%GW;{FKLKKNKLIKKLJJLLKJJJJKKJIIJIHJJIH;  ! 彼QRV$0GKNIKJH.\t MJLIHL999()'   2<(Sd;|GKKLKKLKJJMJIJNLKLLKKJJLLKJIIJIHHIIIJH%Nd~٨422 =LJKJKLKJF2]r$   49'Sd3fBKNHKKLKKKLKJKLKKMJLKLLKKJJLKKJIJJIJIIJFIJLD â&HXLKKKKKIKL;s (02<'Sd+\rA@GKLLIJKLHKLNLNHKKLKIJJKKKIKKJJLKJKKKJIJJIIHIGHJ:| 3oKLIKKLKG$0%Pc=+]s(Sd1=3=3=3=3=3=3=3=3=3=-[s#A?IIIKMHKNHMIHHMLKLKLJLKNKLKKLKJKJLMKJJLKKJJJJIJIJIHJGCG;|  {z~ KJKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJKKJINIKJGD+4;odefeehijdiI +-.柞hff.:GNLKMJKKLKKKKKKKKLL'Sd @LKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJKJIKHIFJC+4%UdeicffgfgfgiW'(/2栟 04ELJLKIKLKJKLLKKKLL7q5qLJKKKKKKKKKKKKKKKKLJKKKKLKJLJJJHKIFLFIA(HSacegfdgffghijjld"?H*>C222PPP-;DKJKKKLKLIGNKHNIJD$EXLJKKKKKKKKKKKKKKKKKKKKKKLKKKMKLJKJLGJA 6cqcigfefdfghighhhhhj/[h(>Díqqq%&$ =LJKJKNLLKLKLLKNI('..^vJLKKKKKKKKKKKKKKKKKKKKKLKKOKHIMKHJHJCEdechgbihghihhhhhjifk0Yh,+-権 %$ 0fOJKJKIK<(FLIKLLILJLLKKKKKKKKKKKKKKKKKKKJKKKKLJLLGKHIJA FddggeeihehihhhiiigligiB*,-\\\;;;GGG *ReMMILJ*`y %JJLLJILKKIKKKKKKKKKKKKKKKKKKKKJLKJKJKJKMHJHF&-Fefadghfgghghiiiijjikkjjh=uBDDܥ`\[:HBKA,3%TjKKKMJKKJOKMKKKKKKKKKKKKKKKKKKKJKKJJKMLGIKKG)5Egdcdgcigfeighiiijjjjjjkjoh.ZgWVXɺ_]]GEEtoq "Mb H***333&()/>;|B?N>PILOKIJKK9'_xJJKJA@>B@?>?=>$*TRbedddgffi1[h#>H^ilfmjX">I)PXemijjjkdVXWR ```~~~~~~|||Ǥ'''b_[  ELOKKLNG J]ALLLN*\p ScdegjgfhfD  Djji?x#%NjmijjiliY UUUۺQQQ@=?+`uLJLJLK8 &KKLKN0_u       Sfefchhgkhi[#@G">IM095hxeijgiijkljY      XXXjhhqqq}| FLKJLFK\)_vKLKLLILJJOJMI4>"%ehbcfdegigdjgihjjC"?F[iijjjlijkjigjjjhlX`^^^_[&13sJI7~ CLJLKIMLJIMIK;OddfdffegffkhkhjgkV$' @F`ihiijliiijjjgimhij/\gFJK===MHI&-@P &NHKOKK=-\r.]r*[q,[p.Zq+Zo(/8o|w?wAuvihmijii_?v;v;v;v>w:v;vw=u;u@w>vu=u>v>v=v5@6hzejiijjjjliilj`^^^fab =L;{IKLJKMHCGdegefeehhigd7kwjljgljikhliih!>Evxyvtsiggzvu<:: %HV5qFLMK/e|dcggdededhehgvvvv;v>v=u4^j ejiiiljjikhig`,R^EDF===gcb/<0[p;#/Wccehegedfdghhec Pljijkjjjjjjjjji/[h?tmjijmiiiijeI"?F  ⾿QOO Zafcdegigeghhilumhilkjjmjkjjmjhki.YhtvvХ^[]ccdebedefcidhjiijlbhjiljjjjjjjj=u5ivijjkikflhijljikjhMKMM533?==|}|}{|z{}xy}xy7321XffdcffceeggfXUWWUTY"8> ;n~YUYWVVVVVVVVH #8@VXXUVVUXkgnigjjhhK'%%igfe`a4/0 0..NIJvqr Jgdfdfddffhgjhjjg=p"=G   trrsqpHCD JQWbdcfcfehc'AH">E!=H#>H#?F"?H#>H"?H"?H#?J#@I!@I#@I"?H"?H"?H"?H"?H#@I#@I#?F#)#@G"?F"?F!?J!@I"?H&CJjgjijc;w"&ϥUSSTRR(&&IDE]^\   )AM]eehiehehgihjiaigkiijjjjjjiW djjiljjlhhnhggjF%?E WWWJHH533{z*%&605:DSddefehhigghihkj"=GXgiihhhiiiiijk"Gggfiiihhhhhjeihh>t#)/Vd:v9tWhhgeihih ;E|||`^^JHH533533533533533USS_]]~~jhhLGH`^]&BIhddddgcfee]!'#)hegcfffhL&JTigggggghfggkejdhg].Xe"l}+++gdfdaea`ab\]_][\`^]^a_aaec`/R_Ndddfdfcfeeaedadab_aa^\]\`1XfA|r@@@FFFNda*=JWWWʠ젟 Uga ( )AMaa$@Gtttםࠟ梠333DydKVVVxxx[d!ttt̠FIGBzf*KT000PPP9gxc ^^^*DPg ###FFF&)`  6A@>&%$SSS^^^nlkMMM&&%'&% '&%'&%\[X][Xhhh~|{򠟛봳䝛㝚Ϝ¾䞝埜~}~~}~~}~~}~}~~~}~}}~ɛ~~}~}}~Ν~}~}}}}~~횖~}}}}}~~~ә~~}}}|}}}~ś~~~}}|||}}~~ƚ⚗~~~}}||||}}~~ژ֙Ԝ~~}}}|||||}}}~~ճ~~}}}||{||}}}~~~~~}}||{{|||}}~~~~}}}||{{z{||}}}~~~~~}}}||{{zz{||}}~~~Ɯ~~~}}||{{zzz{||||~}~~~~~}}}||{zzz{{||}}~}~~~~}}}|||{{zzyzz{{||}}}}~~~}}}||{{zyyyzzz{|||}}}}~~~}}}|||{{zzzyzzz{||||}~}~~~}}}}||{{zzyyxyyzz{{||}}}~~~~}}}|||{zzzyyxxyyzz{{{|}}~~~⭩~~}}}|||{{{zzyyxyyzzz{|{||}~~~旔~~}}}||{zz{yyxxxxzz{zzz|||}}~~~~ߕ~~~}}||{{z{zyxxxxxyxyzz{z{|}}}~~~~璏~~~}}||{{zzzzyxxxxxxyyyzzz{|||}}~~~~~~}}}||{{zzyyxxwwxxwxyyyzz{{|||}}~~~~}}~}}||{{{zzyyxxxxxxwwxyyzzz{{|||}~~~~~~~}}||{zzzzyxyxxxxwwwxxyyyzzz{{|}}}~~~~ɖ~~~~}||{{zzzyyxxxxwwvvwwxxxyzzzz{{|}}}}~~~ӯ~~~}}|||{{zzyyyxxxwvvvvwxxxxxyzzzz{{|||}~~~~}~~~}}|||{{zzzyxxxxxwvvvvvvwxyyxyzzzz{||||}}}~}~~~}}}}|{{{zzyyxxxxwvvvuvvvvwyyxyyzzz{{|||}}}~~~~Ѯ~~}}}}||{{z{zyyxxwxxwuvuuuuvvvwxxxyyyzz{{||}}}~~~ާ~}}}}}||{zzz{yyxxxwwwvuvuuuuvvvvwxxxyyzzz{{||}}}}}~~}}}}}|{{zzzyyxxxwwvvvuuuuuuvvvvwwwxxyyzzz{{|||}}~~ה~~~}}}}|{{{zzzyyxxwwvvvuuuuttuuvvvwwwxxxyyzzz{{|||}}~~}~~~}}}||{{zzzzyyxxxxwvvuuuut~stuuuvvvvwwxxxyyzz{{{||}}}}~~Ŀ瑍~~~}}}||{{{zzzyxxxwxxvvuuuttt~stuuuuuuvvwwwxxyzzz{{{|}||~~Αْᕏ~}~~}}|||{{{{{yxxxxwxwvuuuutt~s}r~sttuuuvvvwwxyyyyyzzz{{|}||~}|~~~~}||||{zzzyyxxxwvvvvvvutt~s~s~s~s~sttuuuuvvwwwyyyyyzz{{{||}}~{~~~~~}}|||{{zzzyyxxxwwvvvvuutt~s~s~s}t~s~s~stuuuuuvvvwwyxxyyzz{{|{}}}{~~~~}}}|||{{zzzyyxxxwwvvvuuuut~s~s}t}t|s}r~s~s~stuuuuvvvvwxxxxyyzzzz{|}|}}~~~~}}}||{{{zzzyyxxxwwvvvvuutt~s~s~s|s|s}r}r~s~s~stttuuuvvvwwwxxyyyzz{{{~}|}~ߒ~~~}}}||{{{zzzyyxxxwwvvvvuuutt~s~s~s|s|s}r}r}r~s~stt~suuuuvvvwxxxxxyyzz{{{{}|||}~~~~~~~}||}|{{{{zzyyxxxwwvvvvuuutt~s~s}r}r}r}r|q|q}r}r~s~s~s~sttuuuuvvxxxxxxyyzyz{{{{}}~}~}}~~~~}}|||{{zzzzyyxxxwwvvvvuuutt~s~s|s}r}r}r}r|q|q}r}r}r~s~stttuuuuuvwxxwxxyyy{zx{{{{|zþ}~~~}}}}}||{{{{zyyyyxxwwvvvuuuttt~s~s}r|s|s}r|q|q|q|q}r}r}r}r~s~s~sttuuuuvvvwwxyyyyw{z{{y||½֓~~~}}}}}||||{zzzzyyxxxxxvvvuuuttt~s~s|s|s}r}r}r|q|q{p|q}r}r}r}r}r~s~s~sttuuuuuvvwwwyyxz{zzz{}捈~~~~}}}||||{zzzyyyxxxxxvvvvuuutt~s~s~s}r|s}r}r|q|q|q{p{p|q|q|q|q}r}r|s~s~sttuuuuuvvvwwyxyzzzzzþ~~~~}}}}}|||{{{zzzyyxxxwwxvvvuuuttt~s~s~s~s}r|q}r|q|q|q{pzo{p|q|q|q|q}r}r|s|s~s~sttuuuuvvvvwxywzxzzyŪ쎇~~~~~~~}}|||{{zzz{zyxxxxwwvvvuuuttt~s~s~s~s}r}r|q|q|q|q{p{pzo{p{p|q|q|q|q|q|s|s~s~s~sttuuuuvvvwwyywyzzz}{||~~~~~~~}}}}|||{{zzzzzyxxxxwwvvvuuuuttt~s~s~s}r}r|q}r|q|q{p{pzozozo{p{p|q|q|q|q}r}r}r~s~s~sttuuuuvvvwxwxxyyx剄{xyzy}}~~~~}}|||||{{zzzzyyxxxwwwvuvvuuuttt~s~s~s}r}r}r}r|q{p{p{p{pzozozozo{p{p|q|q|q|q}r}r|s|s~s~stttuuuuvvwvwxyyy܊yy{{|z~}~~~~~~~~}}||||{{zzzzyxxxxwwvvvuuuuttt~s~s}t~s}r}r}r}r|q|q{p{pzozozoynynzozo{p{p|q|q|q|q}r|s|s|s~s~sttuuuuuvvwwwyxv쉃|zz{{|}}~}~~~~~}}}}||{{z{zzzyxxxxwwvvuuuuutttt~s~s}t|s|q}r}r|q|q{pzo{pzozozoxnxnzoyp{p{p{p|q|q|q|q|q}r}r~s~st~s~stuuuvvwwvxxx{xwz{{}}}~~~~~~~~~~~}}}|||{{{zzzzyyyyyyxxvvvvvuuutt~s~s}t}t}r}r}r}r}r|q{p{pzozozozoynxnxnzozozo{p{p{p|q|q|q|q}r}r}r~s~s~sttuuuuuwvvxxy䇁z{z{֍||}}}}}~~~~~~}}}}}}||{{{zzzzyyxxxyxwvvvvvuuutt~s~s~s}r|s}r}r|q|q|q|q{pzozozoynynyn~xmynynzozozo{p{p{p|q|q|q|q|q}r}r~s~stttuuuuwvvvwwxv{zy|{{|}}}}}~~~~~}~}}}||||{{zzzyyyyxxxwwxvvvuuuuut~s~s~s~s~s}r|q}r|q|q|q{p{p{pzozozoynynyn~xm~xmynxnxnzozo{p{p{p|q|q|q|q}r}r}r~s~s~s~sttuvuuuutuvwxxxyxyz{{|x||y}|}}}}}~~~~~~~}}}}}}|||{{{zzzzyyxxxxwwwvvuuuuutt~s~s~s~s}r}r|q|q|q|q{p{p{p{pzozozoynynynyn~xm~xmynxnxnzozoypzo{p{p|q|q|q}r}r}r}r~s~s~s~sttrrvwvwwxwwxwxyxyzz{x{{z||||}}}}}~~~~~~~~~~~}}|||{{{{zzzyyyxxxwwwwvvvuuuutt~s~s~s~s}r}r}r|q|q|q|q{p{p{pzozozoynyn~xmyn~xm~xm~xm~xmynynynzozozozo{p{p|q|q}r}r}r}r}r~s~s~s~stvv{{zy{{|||||}}~}}}~~~~~~~}}|}||{{{zzzzyyyxxywwwwvvuvuuutt~s~s~s~s}r}r}r}r|q|q|q|q{pzozozozozoynyn~xm~xm~xm}vm~xm~xm~xm~xmynxnxnynzozo{p{p{p|q|q|q|q}r}r}r~s~s~s~q~qzzy{zz{|||||}}}}}}~~~~~~~~}}}||||{{{zzzzyyyyxxwxxwvvuuuuuttt~s~s~s}t}r}r|q}r}r|q|q{p{p{pzozozoynynynyn~xm~xm~xm}vm}vm~xm~xm~xm~xmxnxnynzozozozo{p{p|q|q|q}r}r|s}t~s}rt~tyy{yzzz{{||||}}~~~}}}~~~~~~~}}}}||||{{zzzyzyyxxxxxxxwvvuututt~s~s~s~s~s|s|s}r}r|q|q|q|q{p{pzozozoynynynyn~xm~xm~xm}wl|vk}wl~wn~wn~wn~xmynynxnyozozo{p{p{p{p|q}r}r}r}r}r}r}t~s~qވzyyyzzz{{{{{|||}}}}}~~~~~~~~}}}}}}||||{{{zzzzzyxxxxxxxwwvvuuuuutt~s~s~s|s|s|s}r}r}r|q|q{p{p{pzozozoypxnxnyn~xm~wn~xm}wl}wl}wl}wl}wl}wl~wn~wn~xm~xm~xmxnxnzozozozo{p{p|q|q|q|q}r}r}r}r}t~t|s}tt~sq~vwvwtwvzuxxzzyzzzz{{{||||}}}}}}~~~~~~~~~}}|}||||{{{{{zzzyyyxxxxwxxwvvvuuuuutt~s~s}r}r|s|s}r}r|q|q{p{p{pzozozozoxnxnxn~xm~xm~xm~xm}wl|vk|vk}wl}wl|vk}wl~xm~xm~xm~xmynynynynzozozo{p{p{p|q|q|q|q}r}r}t|s|u|s~u~srvtuvwuxwxxyxxyyyzzzzz{{{||||}}}}~~~~~~~~~~~~}}}}|||||{{{{zzzzyyxxxxxwwvvvuuuuutttt~s~s~s}r}r}r|q|q|q|q|q{p{p{pzozozoynynxn~xm~xm~xm~xm~xm}wl|vk|vk|vk}wl}wl|vk|vk}wl}wl~xm~wn~xmynynxnxnynzozo{pzo{p|q|q|q}r|q|o|s|s}s}tt~s}vuvuwwvtywxwxxxxyyyzzzz{{{||||}}}}}~~~~~~~~~~~~~~}}}}||||{{{{zzzzzyyxxxxxwwwvvvuuuuutt~s~s~s~s}r}r}r}r|q|q|q|q{p{p{pzozozoxnxnxn~xm~xm~xm~wn~wn}wl}wl|vk}wl}wl|vk|vk|vk|vk|vk}wl}wl}vm~xm~xmynxnxnynzozo{pzo{p{p{p|q}r|q}p}r|s|o~s|r}s•vvuvvv~wwxvyyxxyyyyyzz{{{{{{||||}}}}}~~~~~~~~~~~~}}}}}|||||{{{zzzzyyyxxxxxwwwvvvvvuuuu~tt~s~s~s|s}r}r}r}r|q|q|q|q{p{p{pzozozoynxnxnyn~xm~xm~xm}vm}vm|vk}wl|vk|vk|vk{uj{uj|vk}wl}wl|vk}wl}wl~xm~xm~xmynynynynzozozozo{p{p{p|q|q{r|s{r~s{r}t}t~wwxvwxxxxxyyyzzz{z{{{{||||}}}}}}}~~~~~~~~~~~~}}}}}}}|||||{{{{zzzzyyxxxxxwwwvvvvvuvuuttt~s~s~s}r}r}r}r}r|q|q|q|q{p{pzozozozoynynwmwm~xm~xm~xm}wl}wl}wl}wl}wl|vk{uj{uj{uj{uj{uj|vk|vk|vk|vk}wl}wl~xm~xm~xm~xmynxnxnynzozozo{p{p{p|q{q}p|r|q|q|s|swuwxwxxxxxxxyyzzzzzz{{{{|||}}|}}}}~~~}~~~~~~~}}}}}}}}|||||{{{{{zzzyyyyxxxxwwwvwvvvuvuuut~t~tt~s~s~s}r}r}r}r}r|q|q|q{p{p{pzozozozoynynyn~xm~xm~xm~xm}wl}wlvl~ukvl~uk}tj}tj}tj{uj{uj{uj{uj|vk}wl}wl}wl}wl}wl~xm~xm~xm~xmxnxnxozozozozozo{p{p{r{n|q|q}r}r|rsswxvwxxwwxxxxyyzyzz{z{{{{|||||}}}}}}}}~~~~~~~~~~~~~~}}}}}||||||{{{zzzz{zyyxyxxxxwwwvvvvuuuuttt~t}s~s~s~s}r}r|s}r}r}r|q|q{pzozozozozoynynynyn~xm~xm~xm}wl}vm}wl|vk~uk~uk~uk~uk}tj}tj}tjztiztizti{uj{uj|vk|vk|vk|vk}wl}wl~wn~wn~xm~xm~xmxnxnynzozozo{p{pzq{p{q{q}r|q}r|r{څwsvvwvvvwwxyyxxxyy{{{zzz{{{||||||||}}}}}}~~~~~~~~}~~~}~}}}}|}||||||{{z{zzzzzzyyyyxxwxxxwvvvuuvuuttt~s~st~s~s}r}r}r}r}r}r|q|q|q{p{p{pzozozoynxnwm~xm~xmyn~xm~xm~xm}wl}wl}wl|vk|vk|vk{ujztiztiztiztiztizti{uj{uj{uj|vk|vk}wl}wl}wl}wl}wl~xm~xm~xmxnynynynzozozozo{p{pzp{q{p}r}r|s{r|u|qt}t|sr}r}t~uvtutvuvvvvwwxxxxxxxyyzzzzz{{{{{||||||}}}}}}}}}}~~~~~~~~~~~~~~}}}}}}}|||||{{{zz{zzzyzyyyxxxxxwxvvvvvuuuuutttt~s~s~s}r}r}r}r}r}r|q|q|q|q{p{pzozozozozoynyn~xm~xm~xm~xm~xm}wl}wl}wl}wl|vk|vk{uj{uj{ujztiyshyshyshyshyshzti{uj{uj{uj|vk}wl|vk|vk}wl}wl}wl~xm~xm~xm~xmynynynzozozozozmyo|q{p}r{q|s|o}p}r{r}s~s~s}srr~qtvuuuvvvvvvwxwwxxxxxxyyzzzzzz{{{{{||||||||}}}}}}}}}~~~~~~~~~~~~~~~~~~~~}}}}}}}}||||||{{{{zzzyzzzyxxyxxxxwxwxvvvvuuuuuttt~s~s~s}r}r}r}r}r}r}r|q|q{p{p{p{pzozozoynynynynynyn~xm~xm}wl}wl|vk|vk}wl}wl|vk{uj{uj{ujztiztiyshyshyshyshyshztizti{uj{uj{uj|vk|vk|vk|vk|vk}wl}wl}wl~xm~xm~xmxnxnxnynzozo{p{pzq{p|q{q{r|q}pԵ{rr~s}tutuuuuuvvvvxxxwwxxxxyyyyzzzzzz{{{{{||||||||}}}}}}~~}}~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}||||||||{{{{{zzzzzzyyyyyxwxwxxxxwwvvuuuuuutt~s~s~s~s}r}r}r}r}r}r|q|q|q{p{p{pzozozoynynynxnyn~xm~xm~xm~xm}wlvl|vk|vk|vk|vk|vk{uj{uj{ujztiztiyshztiztiyshyshyshyshztizti{uj{uj{uj|vk|vk|vk|vk|vk}wl}wl~xm~xm~xmwmxnxnynynyoynzozq{p{n}r{pz헔}rtt~svtuuuuvvvvwwxwwwxxxxxyyyyzzzzzz{{{{{||||||||||}}}}}}}}~~~~~~~~~~~~}}}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}|}}}}|||||{{{{{{zzzzzyyyxxyxxwxxxxxxwwvvvvuuuttttt~s~s~s~s}r}r}r}r}r|q|q|q{pzo{pzozozozoynynynwmyn~xm~xm~xm}wl}wl~uk|vk}wl|vk|vk{uj{uj{uj{ujztiztiztiyshyshyshyshyshyshztiztiztizti{uj{uj{uj|vk|vk}wl|vk|vk}wl}wl~xm~xm~xmynynynxnzoypypyo|oynzq}|rrr~q~tttuuuuuuvvvwwwwwxxxxxxyyyyyzzzzz{{{{{{|||||||}}|}}}}}}~~}}}}}}}}~~~~~~~~~~~~~~~~~~~~~}}}}}}}~~~~}}}|}}}|||||||||{{{{zzzzzzzyyyyxyxxwxxwwxxwvvvuuuuuuttt~s~s~s~s~s}r}r}r}r}r|q|q|q{p{p{pzozozozozoynynynyn~xm~xm~xm~xm}wl}wl|vk|vk}wl|vk|vk{uj{uj{ujztiztiztiyshyshyshyshxrgxrgxrgyshyshyshztiztiztizti{uj{uj|vk|vk|vk|vkvl}wl}wl~xm~xm~xmynynxn~xmxoypyozm~yp˄}t~q~qt}sttttuuuuvvvvvvwwwwwwxxxxxyyyyyyzzzz{{{{{|{{||||||||}}}}}}}}}}~~~~~}}}}~~}}}}}}}}~~}}}}}}~~}}}}||}}}}}}||{|||{{{z{z{zzzzzzzyyyxxxwwxwwvwwwvvvuuuuutttt~s~s~s~s~s}r}r}r}r|q|q}r|q|q{p{p{pzozozozoynynynynyn~xm~xm~xm}wl}wl}wl}wl|vk|vk|vk|vk{uj{uj{ujztiztiyshztiyshxrgyshyshxrgxrgxrgxrgyshyshyshyshztizti{uj{uj{uj|vk}wl}wlvlvl}wl}wl~xm~xm~xm~xmwm~xmyn~xmyoyn~ypz{t{q~s}t}t}s~stttuuuuuuvvwwwvvwwwxxxxxyyyyyyzzzzzzz{zzz{{|||||||||||}}}}}|||}}}|}}}~}}}}}}}}}}}}}}}}|||||||||||||||{{{{zzz{{{zzzzzzyyyxxxxxxxwwwwvvvvvuuuutt~ttt~s~s~s~s~s|s}r}r}r}r|q|q|q|q{p{p{pzozozozoynynynynyn~xm~xm~xm~wn~wn}wlvlvl|vk|vk|vk{uj{ujzti{uj{ujztiyshyshxrgyshyshxrgxrgxrgxrgxrgxrgyshyshyshyshztiztiztizti{uj{uj{uj|vk}wl}wl|vk|vk}wl~xm~xm~xmxn~xmxnxnxoxnyoɁ{p|o{r|r}p}r~s~s~s~s~sttttuuuuvvvvvvvwwwwxxxxxxxyyyyyzz{{zzzzzzzzz{{|||||{||||||||||||||||}}}}}}}}}}|||||||||||||||||{{{{{{zz{zzzzzzyyyxxxyxxxxxwwxxxwvvvuvuuuutttttt~s~s}t|s|s}r}r}r}r|q|q|q|qzp{p{pzoypzozoyoxnxnxn~xmyn~xm~xm~wn}wl|vk|vk|vk|vk|vk|vk{uj{uj{uj{ujztiyshyshyshyshxrgyshxrgxrgxrgwqfxrgxrgxrgxrgyshyshxrgyshyshztiztizti{uj{uj{uj|vk}wl}wl|vk|vk}wl}wl~xmvlyn~xmxnxoxnxnzo{pzq}r}r}t|s~s~s~s~s~s~s~s~sttuuuuvvvvvvvwwwwwwxxxxxxxxyyzzzzzzzzzzzzzzzz{{||||||||||||||||||||||||||||||||||||{{{{{zz{{zz{{zzzzzzzzyyyyyxxxxxxwwwwwwwvvvvuuuuutttt~s~s~s~s~s}r}r}r}r}r}r|q|q|q|q{p{p{p{pzozozozoynynxnxn~xm~xm~xm~xm}wl}wl}wl|vk|vk|vk|vk|vk{uj{uj{ujztiztiyshztiyshyshyshxrgxrgxrgwqfwqfvpewqfwqfxrgxrgxrgxrgxrgxrgyshztiztiztizti{uj{uj{uj|vk}wl}wl|vk|vk}wl}wl~xm~xm}wlxn~wn~xmyoف{pzmzq|s}r{r|r}r}r}r~s~s~s~s~sttttuuuuuuuvvvvvwwwwwwwxxxxxyyyyyzzzzzzzzzzzz{{{zzzzz{{{{{{{{{{{{{{{{{{{|||{{{{{zzzzz{{{{zzzzzzzyzzyyyyxyyxxwwyywwwvwwvvvvvuuuuuuuutt~s~s~s~s~s}r}r}r}r}r}r|q|q|q|q{p{p{p{pzozozozoynynynynxn~xm~xm~xm~xm}wl}wl|vk}wl}wl|vk|vk|vk{uj{ujztiztiztiyshyshyshyshxrgyshxrgxrgwqfwqfwqfvpevpewqfwqfxrgxrgxrgxrgxrgyshyshztiztiztizti{uj{uj{uj|vk|vk|vk|vk|vk|vk}wl~xm~xmwmxoyn~xm{pyp{r{r|q|n}r}r}r}r}r}t}t}t~s~s~stttuuuuuuuuvvvvvvwwwwyyxwxxxyxxxyyyzz{{{{{{{{zzzzzz{{{{{{{{{{zzzzzzzzzz{{{{{{zzzzzzzzzzzzzzyyyyyxxyyxxxxxyxxwvvvvvvvvuuuuuuuuttt~s~s~s~s~s|s}r}r}r}r|q|q|q|q|q|q{p{p{pzozoypypynxnxnynyn~xm~xm~xm~xm}wl}wl}wl}wl}wl}wl|vk|vk{uj{uj{ujztiztiyshztiyshyshyshyshxrgxrgxrgwqfwqfvpevpewqfwqfwqfwqfwqfwqfxrgxrgyshxrgyshyshyshztiztizti{uj{uj{uj{uj|vk|vk}wl}wl}wl|vk}vmvl~xm}wlzoxnyo|q{r{r{r|q|q|q}r}r}r|s}t}t~s~s~s~sttttuuuuuuuuvvvvvvwwxxxwwxxxxxxxxxyyzzzz{{{{zzzzzz{{zzzzzzzz{{{{{{{{zzzzzzzzzzzzzzzzyyyyyyyxxyxxxxxxxxwwwxxxvvvvvvuuuuuuutttt~s~s~s~s~s~s~s}r}r}r}r}r|q|q|q{p{p{p{p{pzozozoypxoynxnxnyn~xm~xm~xm~xm}wl}wl}wl}wl}wl}wl|vk{uj{uj{ujztiztiztiyshyshyshyshxrgyshyshxrgxrgwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfxrgxrgxrgyshyshyshyshyshztiztiztiztizti{uj{uj|vk|vk}wl}wl~vi|wnvlvl~xm}wlxxoxzozp{p{p|q|q|q|q}r}r}r}r}r~s~s~s~s~s~s~s~sttttuuuuuuvvvvvvvvwwwwwwxxxxxxxxxxxxxxxxyy{{{{{{zzzzzzzzzzzzzzzz{{{{{{{{zzyyyyyxyyyxxxxxxxxxxwwwwwwwwvwwvvuuuuuuuuutttt~s~s~s~s~s~s}r}r}r|q}r}r|q|q|q|q{p{p{p{pzozozozozoynynynyn~xm~xm~xm~xm~xm}wl|vk|vk}wl}wl|vk~uk{uj{ujztiztiztiztiztiyshyshyshxrgyshyshxrgxrgwqfwqfvpevpewqfwqfvpevpevpevpewqfwqfwqfxrgwqfxrgyshxrgxrgyshyshyshyshztizti{uj{uj{uj{uj|vkvlwjzul~ukvl|vkwm~wnwÿwp{pyp{n{nzp|q|q|q|q|q|q|q|q}r}r}r}r~s~s~s~st~s~sttuutuuuuvvvvuuvvvwwwwwwwwxxxxxxxxxyyyyyyyyyyzzzzzzzzyyyyyyyyyyyyyyyxyyyyyyyyxxxxxxxxxxxxxxxxwvvvvvvvvvuuuuuttttt~s~s~s~s~s~s~s}r}r}r}r|q|q|q|q|q|q{p{p{pzozozozozoynynynynyn~xm~xm~xm~xm}wl}wl}wl}wl|vk|vk|vk|vk~uk}tj{uj{ujztiztiztiztiztiyshyshyshxrgxrgxrgwqfwqfwqfvpewqfwqfvpevpevpevpevpevpewqfwqfwqfwqfwqfwqfxrgxrgyshxrgyshyshztiztiztiztiztizti{uj|vk}tj~vi{vmvl~vi|vkvlwmyj~xm}vmxn}xoynynynzoxqzqyo~yp{p{p{p|q|q|q|q|q|q|q}r}r}r~s~s~s~s~s~stttttuuuuuuvvuuvvvwwwwwwwwwwwxxyyyyyyxxxxxxxyyyyyyyyyyyyyyyyyyyyyyxxxyyyyyyyyxxxxwwwwxxxxxwwwvvvvvuuuuuuuuttt}s~s~s~s~s~s~s~s|s}r}r}r}r|q}r|q|q|q|q{p{p{p{p{pzozozozoynynyn~xmwm~xm~xm~xm~wn}wl}wlvl|vk|vk}wl|vk|vk}tj}tj}tj{ujztiztiyshyshyshyshyshyshxrgxrgxrgxrgwqfwqfvpewqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgyshyshyshyshyshyshyshzti{uj{uj{uj{uj{uj|vk|vk}wl}wl|vk|vk~ul~xmxo}wlynyn~xkwmxoylypzo~ypypzo{pzozo{p{p{p|q|q|q}r}r}r}r}r}r}r}r~s~s~s~s~s~sttttttuuuuuuvuuvvvvvvvvvvwxxxxxxxxwwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwvvvvvvvvuuuuuuuuuutttt~s~s~s~s~s~s}r~s}r|q}r}r|q|q|q|q|q|qzpzpzp{p{pzozozozozoynynynynynyn~xm~xm~xm~xm}wl|vk|vk}wl}wl|vk|vk|vk{uj{uj{uj{ujztiyshztiyshyshyshxrgxrgxrgxrgwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgyshyshztiztiztiztizti{uj{uj{uj|vk|vk|vk|vk|vk~uk}wl|ul~xmyn}wlyl|voynyl}xoylynxnzoypzozozo{p{p{p|q|q|q|q}r}r}r}r}r}r}r}r}r~s~s~s~s~s~sttttttuuuuuuvuuvvvvvvvvwwwxxxxxwwwwwwwwxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwvvvvvvvvvvuuuuuuuuttttttt~s~s~s~s~s}r~s}r}r}r}r}r|q}r}r|q|q{p{p|q{p{p{pzozozozozoynynynynynyn~xm~xm~xm~xm}wl}wl}wl|vk|vk|vk|vk|vk{uj{uj{uj{ujztiztiztiyshyshyshxrgyshxrgxrgxrgxrgwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgyshyshyshyshyshztiztizti{uj{uj|vk|vk|vk|vkvl|vk}wl}wl}vmwm~xmxnxnyozoypzozozozo{p{p{p{p{p|q|q|q|q|q}r}r}r}r}r}r}r~s~s~s~s~s~s~s~stttutttuuuuuuuuvvvvvvvvuvvvvvwwwwwwxxxxxxxxwwwwwwwwwwwwwwwwwwwvvuuvvvvvvvvvvvvuuuuutttttttt~s~s~s~s~s~s~s~s~s}r}r}r}r}r|q}r}r|q|q|q|q|q{p{pzozozozozozoynynynynyn~xm~xm~xm~xm~xm}wl}wl}wl|vk|vk|vk|vk|vk{uj{uj{uj{ujztiztiztiyshyshyshyshxrgxrgxrgxrgxrgwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgyshyshyshyshztiztizti{uj{uj{uj|vk|vk~uk}wl|vkvl}vmvl~xmxoxnxn~xmxoynynzozozozo{p{p{p{p{p|q|q|q|q|q|q}r}r}r}r}r}r}r}t|s}t~s~s~st~stttttttuuuuuuuvvuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuvuuuuuttttttt~s~s~s~s~s~s~s}r}r}r}r}r}r}r|q|q}r|q|q|q|q|q|q{pzozo{pzozozozoynxnxnxnynyn~xm~xm~xm}wl}wl}wl}wl}wl|vk}wl}wl|vk{uj{uj{uj{uj{ujztiztiyshyshyshxrgyshyshyshxrgxrgxrgwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfxrgxrgyshxrgxrgyshyshyshztiztiztiztizti{uj{uj{uj~uk|vk~ukvl|ulvl|vk~wnylwmxoxoynynynzozozozozozo{p{p{p{p{p|q|q|q|q}r}r}r}r}r}r|s|s}t~s~s~s~s~s~s~s~stttttuuuuuuuuvvvvvvuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuvvvvuuuuuuuuuuuuttttttt~s~s~s~s~s~s~s}r}r}r}r}r}r}r|q|q|q|q|q|q|q|q{p{p{p{p{pzoynzozozoynynxnxnxn~xm~xm~xm~xm~xm}wl}wl|vk}wl}wl|vk|vk|vk|vk{ujzti{ujztiztiztiztiyshyshyshxrgxrgxrgyshxrgwqfwqfwqfvpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfxrgxrgxrgxrgyshxrgyshyshyshyshyshyshztiztizti{uj|si|vk|vk~uk}wl~uk}wl|wn~xmwm~xmwnynynynynynzozozozozozozozo{p{p|q|q|q|q|q|q|q|q|q|s}r}r}r}r}r}r}r~s~s~s~s~s~s~st~sttttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvuuuuuuvuuuuuuuuuuuuuuutttttt~s~s~s~s~s~s~s~s~s~s}r}r}r}r}r}r}r}r|q|q|q|q|q|q|q{p{p{p{pzozoynynzoynynynynynyn~xm~xm~xm~xm~xm}wl}wl}wl|vk|vk}wl|vk|vk|vk{uj{uj{ujztiztiztiztiztiyshyshyshyshyshxrgxrgxrgwqfwqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgyshyshyshyshztiztiztizti|si{uj{uj}tj{uj}wl}wl|ul~wnwm}wlyn~xm~xmynynynynynynzozozozozozo{p{p{p{p{p|q|q|q|q|q|q}r}r}r}r}r}r}r}r}r~s~s~s~s~s~stttttttttttuutttttuuuuuuuuuuuuuuuuuuuuuuvvvuuuuuuuuuuuttuuttttttt~s~s~s~s~s~s~s~s~s~s}r}r}r}r}r}r}r}r}r}r}r}r}r|q|q{p{p{p{p{pzo{pzozozozozoynynynynyn~xm~xm~xm~xm~xm~xm}wl}wl}wl|vk|vk|vk|vk|vk|vk{uj{uj{uj{ujztiztiztiztiztiyshyshxrgxrgyshxrgxrgwqfwqfwqfwqfvpewqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfvpevpevpewqfwqfwqfwqfxrgxrgyshxrgxrgyshyshyshztiztizti}tkztizsj}tj~uk{tk}wl|ul|vk~vi}wl|vi}vmvl~xm~wn~xm~xm~xm~xmynynynynynzozozozozozozozo{p{p{p|q|q|q|q|q}r}r|q}r}r|q}r}r}r}r}r}r}r~s}r~s~s~s~s~s~s~st~s~s~s~s~sttttttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuut~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s}r}r}r}r}r}r}r}r}r}r|q|q|q|q|q|q|q|q{p{p{pzozozozozozozoynynynynxnwmwm~xm~xm~xm~xm}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk{ujztizti{uj{ujztiztiztiyshyshyshyshyshxrgxrgwqfwqfxrgwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfxrgxrgyshxrgyshzqgzqgztiyri|si|sizti{ujzti{uj{uj|vk{ujvl~vi~uk|ul|vk}wl|vk~xm~wn~xm~xm~xm~xm~xmynynxnxnxnyoyozozozozozozozo{p{p{p{p|q|q|q|q|q|q|q|q}r}r}r}r}r}r}r}r}r}r~s~s~s~s}r}r~s~s~s~s~sttt~s~stttttt~s~s~stttuuuuuuuuuutttttttttt~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s}r}r}r}r}r}r}r}r}r|q|q|q|q|q|q|q{p{p{p{p{p{p{pzozozozozoyoyoxnxnwmwmwmwm~xm~xm~xm~xm~xm}wl}wl|vk}wl}wl|vk|vk|vk|vk{uj{uj{uj{ujztiztiztiyshyshyshyshyshyshyshxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfxrgwqfyshysh{rhzqgxrgzti|siztiztiûǫ|u|vk|vk}vm|vk|vk}vm|vk}wl}wl}wl~xm~xm~xmynynxnxnxnxnxnynzozozozozozo{p{pzozo{p{p{p|q|q|q|q|q}r}r}r}r}r}r}r}r}r}r}r}r}r}r~s~s~s~s~s~s~s~s~s~s~s~s~s~s~sttt~s~s~s~stttttttttttttttttttt~s~s~s~s~s~s~s~s~s~s~s~s~s~s}r}r}r}r}r}r}r}r}r}r}r}r}r|q|q|q|q|q|q|q{p{p{p{p{p{pzozozozoynynynynynynynynynyn~xm~xm~xm~xm~xm}wl}wl|vk|vk|vk|vk|vk|vk|vk{uj{uj{uj{uj{ujztiztiztiztiztiyshxrgyshyshyshxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfzqgwqfwqfzqgyshxrgxrgysh{r󑎆|ulzti}wj|vk}vm}wl|vk|vk}wl}wl}wl~xm~xm~xm~xm~xm~xmynynxnxnxnzozoynynzozozozozo{p{p{p{p{p{p|q|q|q|q|q|q}r}r}r|q|q}r}r}r}r}r}r}r}r}r}r}r}r}r}r}t}t}t}t}t}t|s|s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s}r~s~s~s~s~s~s~s}t}t}t}t}t}t}t}t}r}r}r|q|q|q}r}r}r}r}r|q|q|q|q|q|q|q|q|q|q|q|q|q{p{p{p{p{pzozozozozozozoynynyn~xmyn~xm~xm~xmyn~xm~wn~wn~xm}wl}wl|vk}wl|vk}wl|vk|vk|vk{uj{uj{uj{uj{ujztiztiztiyshyshyshyshyshxrgyshxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfxoexrgxrg{rhwqf|sizqgwri{uj~vi|vk|vkvl}wl}wl}wl}wl}wl}wl}wl~xm~xm~xm~xm~xm~xmwmxnxnxnxnxnxnyoyoyoyozozozozozo{p{p{p|q|q|q|q|q|q|q|q}r}r}r|q|q|q|q|q}r}r}r}r}r}r}r}r{r|s|s|s|s|s|s|s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s~s|s|s|s|s|s|s{r{r}r}r}r}r}r}r|q|q}r|q|q|q|q}r|q|q|q|q|q{p{p{p{p{p{p{pzozozozozozoyoyoyoxnxnxnxnxnyn~xm~xm~xm~xm~xm}vm}vm}wl|vk|vk|vk}wl}wl|vk|vk|vk{uj{uj{uj{ujztiztiztiyshyshyshyshyshxrgyshyshxrgxrgxrgwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpeypfwqfypfypfxrgzqgzqg{uj}tj}tj|vk}tj|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl}wl~xm~xm~xmwmwmxnxnxnxnxnxnxnxnzozozozozozozozozo{p{p{p{p|q|q|q|q|q|q|q|q|q|q}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r|q}r}r}r}r}r|q|q|q}r|q|q|q|q|q|q{p{p{p{p{p{p{p{p{pzozozozozozozozoxnxnxnxnwmwmwmwm~wn~wn~xm}wl}wl}wl}wl|vk|vk|vk}wl|vk}wl|vk|vk{uj{uj{uj{uj{ujztiztiztiztiztiyshxrgxrgyshyshxrgxrgxrgwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpexoewpgyqdypfwpgypfzqgztiyshzxsj}tj|sizti}tj{uj|vk|vk}wl}wl}wl}wl|vk|vk}wl}wl~xm~xm~xm~xm~xmynyn~xm~xmynynynynynynynynzozozozozozozo{p{p{p{p{p{p|q|q|q|q|q{p{p|q|q|q|q|q}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r}r|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q{p{p{p{pzo{p{pzozozozozozozozozoynynynynyn~xm~xmynyn~xm~xm~xm~xm~wn}vm}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk{uj{ujzti{ujztiztiztiztiyshyshyshyshyshyshxrgyshxrgxrgwqfwqfwqfwqfwqfvpewqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfvofyqdyqdupgxoexrgxqh{sfzreyshzre}tf{rh}tjztizti{uj{uj{uj|vk|vk|vk|vk|vk|vk|vk|vk}wl}wl}wl}wl~xm~xm~xm~xm~xmynyn~xm~xmxnxnxnxnxnxnyoyozozozozozozozozozozozo{p{p{p|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q}r}r|q|q|q|q|q|q|q|q}r}r}r}r}r}r}r}r}r}r|q|q|q|q|q|q}r}r}r|q|q|q|q|q|q|q|q|q|q|q{p{p{p{p{p{pzozozozozozozozozozoynynxnxnxnxnxnxnxnxnynyn~xm~xm~xm~xm~xm~xm}wl}wl}wl|vk|vk|vk|vk|vkvl~uk}tj}tj}tj}tj|si|siztiztiztiyshyshyshyshxrgxrgyshxrgxrgxrgwqfwqfwqfwqfvpewqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwpgyqdyqdtofypfvpexqhzqgxrgxqhyrixqh|si|tgztg{tk{uj{uj{uj{uj{uj|vk|vk}wl|vk|vk|vk|vk|vk}wl}wl}wl~xm~xm~xm~xm~xm~xm~xm~xmxnxnxnxnxnxnxnxnzozozozozozozozozo{p{p{pzozozozo{p{p{p{p{p|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q|q{p{p{p{p{p{p{p{pzo{p{pzozozozozozozozozoynynynynxnxnxnwmwmwmwmwm~xm~xm~xm~xm}wl}wl}wl}wlvlvlvlvlvl~uk~uk}tj}tj}tj}tj|si}tj|si|si|siztiztiyshyshyshxrgxrgxrgyshxrgxrgwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypfyqdwqfvofyqdtofxqhzrexrgwrixrg{rh|tgztizti}tgztizti{uj{uj{uj{uj{uj|vk|vk|vk|vk|vk|vk}wl}wl|vk|vk|vk}wl~xm~xm~xm~wn~wn~wnynyn~xm~xmynynynxnxnxnxnxnyoyoyozozozozozozozozozozozozo{p{p{p{p{p{p{p{p{p{p{p{p|q|q|q|q|q|q|q|q{r{r{r{r{r{r{r{r|q|q|q|q|q|q|q|q{p{p{p{p{p{p{p{pzozozo{p{pzozozozozozozozozozozoxnxnxnxnxnxnxnwmyn~xmynyn~xm~xm~xm~wn~xm~xm}wl|vk}wl|vk|vk|vk|vk|vk}wl|vk|vk|vk{uj{uj{uj{uj{ujztiztiztiyshyshyshyshyshxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoeyqdvpevpeyqdvpezrezre|qvqh{sfztiysh|tgztiztiztizti{uj{uj{ujzti{uj{uj{uj|vk|vk|vk}wl}wl}wl}wl|vk|vk}wl}wl~xm~xm~xm~xm~xm~xm~xmynynynwmxnxnxnxnxnxnxnynynynzozozozozozozozozozozozo{p{p{p{pzozozozozo{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{p{pzozozozozozozozozozozozozozozoynynynynynynynynynynyn~xm~xmyn~xm~xm~xm~xm~xm}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk}wl|vk|vk{uj{uj{uj{uj{uj{ujztiztiztiztiztiyshyshyshyshyshyshxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpexoevpewqfxrgxpcwqfztizre{rhyshyshztiyshyshyshztiztiztizti{uj{uj{uj{uj|vk|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl|vk}wl}wl~xm}wl~xm~xm~xm~xmynynynynyn~xm~xm~xmynynynynynynzozozozozozozozozozozozozozozozo{p{pzozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozoypypypypypypxoxoynynynynynyn~xm~xmynyn~xm~xm~xm~xm~xm~xm~xm~xm}wl}wl}wl}wl}wl|vk|vk|vk}wl}wl}wl|vk|vk|vk{uj{uj{uj{uj{ujztizti{ujyshztiztiztiyshyshyshyshyshyshxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypfwqfwqfvpeyqdwqf}xo󑋄xrgzqgzqgyshxqhyshyshyshyshyshyshztiztiztiztizti{uj{uj{uj{uj{uj{uj|vk|vk|vk|vk}wl}wl|vk|vk|vk|vk}wl}wl}wl~xm~xm~xm~xm~xm~xm~xmynynynwmxnxnxnxnxnxnxnxnxnxnxnxnxnxnyozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozozoxnxnxnxnxnxnxnxn~xm~xm~xm~xmynynynyn~xm~xm~xm~xm~xm~xm~xm~xm}wl}wl}wl}wl|vk|vk|vk}wl}wl|vk|vk|vk|vk|vk|vk{uj{uj{ujztiztiztiztiyshztiyshyshyshyshyshxrgyshyshxrgxrgxrgxrgwqfwqfwqfvpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpexrgxpcxoewqf}wp󏉂zqgxrgwqfxrg{rhxrgxrgxrgyshyshyshyshyshyshztiztiztiztizti{uj{uj{uj{uj{uj{uj{uj|vk}wl}wl}wl|vk|vk|vk}wl}wl}wl}wl}wl}wl~xm~xm~xm~xm~xm~xm~xmwmwmwmxnxnxnxnxnxnxnxnxnxnxnxnxnynynynynynynynynzozozozozozozozoypypypypypypypypzozozozozozozozoynynynynynynynynxnxnxnxnxnxnxnxnynynyn~xm~xm~xm~xm~xm~xm~xm~xm}wl}wl}wl|vk|vk|vk}wl}wl}wl|vk|vk|vk|vk}wl|vk|vk{uj{uj{uj{uj{ujzti{ujztiztiztiztiyshyshyshyshyshxrgyshyshxrgxrgxrgxrgwqfwqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfvpevpewqfwqdyqdvpeĨ}xowqfxpcwqfwqfyshxoe{rhxrgxrgxrgxrgxrgyshyshztiyshztiztiztiztiztiztizti{uj{uj{uj{uj{uj|vk|vk|vk}wl|vk|vk}wl}wl|vk|vk|vk|vk|vk}wl}wl}wl}wl~xm~xm~xm~xm~xm~xm~xm~xm~xmynynynynynynynynyn~xmynynynynynynynynynynynynynynynynynynynynynynynynynynynynynynynynynynynyn~xm~xm~xm~xmynynynynynynyn~xm~xm~xm~xm~xm~xm~xm~xm}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk{uj{uj{uj{uj{uj{uj{ujztiyshztiztiyshztiztiyshyshxrgxrgyshyshxrgxrgxrgxrgxrgwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfxoeyqdwqfuneyqdvofwqfypfypfypfxoexoeypfvpewqfvpewqfvpewqfwqfypfwqfxrgxrgyshxrgxrgyshyshyshyshyshyshyshztiztizti{uj{ujzti{uj{uj{uj{uj{uj{uj{uj{uj|vk|vk|vk}wl}wl|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl}wl~xm~xm}wl}wl~xm~xm~xm~xm~xm~xm~xmyn~xm~xmynynynynynyn~xm~xm~xm~xm~xm~xm~xm~xmwmwmwmwmwmwmwmwm~xm~xm~xm~xm~xm~xm~xm~xmynynynynyn~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk~uk~uk~uk~uk~uk}tj}tj}tjzti{uj{uj{uj{ujztiztiztiyshyshztiyshyshyshyshxrgxrgxrgxrgxrgwqfwqfwqfxrgwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpeypfxpcvpewpgxpcvpeyqdyqdwqfwqftofwqfxpcwqfwqfwqfvpeyqdwqfwqfvpexrgxrgwqfxrgxrgyshyshxrgxrgxrgxrgyshyshyshyshztiztiyshztizti{ujztizti{uj{uj{uj{uj|vk|vk|vk|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xmynynynynynynynynxnxnxnxnxnxnxnxnynynynynynynynyn~xm~xm~xm~xm~xm~xm~xm~xm~wn~wn~wn~wn~wn~wn}vm}vm|vk|vk|vk|vk|vk|vk}wl}wlvlvl~uk~uk~uk~uk~uk~uk}tj~uk}tj}tj}tj|si|si}tj{uj{ujztiztiztiztiyshyshztiyshyshyshxrgxrgyshyshxrgxrgxrgxrgwqfwqfwqfvpevpewqfwqfwqfwqfwqfvpevpewqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpexoeyqdtpewqfxpcyqdvpewqftpeyqdwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshyshyshyshyshztiztiztizti{uj{uj{uj{uj{uj{uj{uj{uj|vk|vk|vk|vk}wl|vk|vk}wl|vk|vk|vk|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm}wl}wl~xm~xm~xm~xm}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk{uj{uj{uj{uj{uj{ujzti{uj{ujztiztiztiztiztiztiyshztiztiyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewpgxpcwqfvpewqfwpgxoexoewqfxpcvpewqfwqfwqfwqfxrgxrgxrgwqfxrgxrgxrgyshxrgxrgyshyshyshyshyshztiztiztiyshztiztizti{uj{uj{ujztizti{uj{uj{uj{uj{uj|vk|vk|vk}wl}wl}wl}wl|vk|vk|vk|vk}wl}wl}wl|vk|vk}wl}wl}wl|vk|vk|vk|vk}wl}wl}wl}wl~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm~xm}wl}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk|vk{uj|vk{uj{uj{uj{uj{uj{uj{uj{ujztiztiztiyshztiztiztiztiztiztiyshyshxrgyshyshxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvofyqdyqdypftofvpevpcypftpevpevpevpevpewqfwqfwqfwqfwqfxrgxrgwqfwqfxrgyshxrgxrgxrgyshyshxrgyshyshztiyshyshyshyshyshztizti{uj{ujzti{uj{uj{uj{uj{uj{uj{uj{uj{uj|vk|vk|vk|vk|vk|vk|vk|vk}wl}wl}wl}wl|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk{uj{uj{uj{uj{uj{uj{uj{uj{ujztiztiztiztiztiyshztiztiyshyshztiyshyshyshyshyshyshyshyshyshxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwpgxpcvpcxoewqfwpgvpexoevpexoevpevpevpevpevpevpevpevpevpewqfxrgxrgxrgwqfxrgxrgxrgyshyshxrgxrgyshyshxrgztiztiyshyshyshyshyshyshztizti{ujzti{uj{uj{ujzti{uj{uj{uj{uj{uj{uj{uj{uj|vk|vk|vk|vk|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk|vk}wl|vk|vk|vk|vk|vk}wl}wl|vk|vk|vk|vk|vk{uj{uj{uj|vk|vk{uj{ujztizti{uj{uj{uj{ujztiztiztiztiyshyshyshyshyshyshyshyshyshxrgxrgxrgxrgxrgyshyshxrgxrgxrgxrgwqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpeypfxpcwqfvpexpc㻷vpevpeypfypfxoewqfwqfwqfvpevpevpevpevpewqfwqfvpewqfxrgxrgwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshztiztiyshyshyshyshyshyshzti{ujzti{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj|vk|vk|vk|vk}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl}wl|vk|vk|vk|vk|vk|vk|vk{uj{uj|vk|vk{uj{uj{uj{uj{uj{uj{uj{ujztiztiztizti{uj{uj{uj{ujyshyshztiztiztiztiztiyshyshyshyshyshyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqdypfxpctpewqfyqdvoftpewqfwqfvpcvpezqdyrcvofyqdvpeyqdvpcwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfvpevpewqfxrgwqfxrgxrgwqfxrgxrgxrgxrgyshyshxrgyshyshyshyshyshztiztiztiyshyshyshyshyshztiztiztiztiztizti{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk|vk{uj{uj{uj{uj|vk|vk{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{uj{ujztiztiztiztiztiztiyshyshyshyshyshyshyshyshyshyshyshxrgyshxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwndyqdvpevpevpeypfxpcyqdyqdxoevofypfvngvpewqfzqdyqdxoewqfwqfwqfwqfwqfwqfwqfvpevpewqfvpevpewqfwqfvpevpewqfwqfwqfwqfxrgxrgxrgwqfxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshztiztiyshztiztiztiztiztiyshyshyshyshztiztiztiztiztiztiztizti{uj{uj{uj{uj{ujztiztizti}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj}tj|si|si|siztizti{uj{uj{uj{uj{uj{uj{uj{ujztiztiztiztiztiyshztiyshyshyshyshyshztiztiyshyshyshyshyshyshyshyshxrgyshxrgxrgxrgxrgwqfwqfxrgwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewpgxpcvpcypfuqfvpexpcvpevpevofwqfxpcwpgyqdvpeyqdvpcupgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfvpewqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshxrgyshyshxrgxrgyshyshztiztiztiztiztiztiztiztiyshyshyshztiztiztizti{uj{uj{uj{ujztiztiztizti}tj}tj}tj}tj}tj}tj}tj}tj|si|si|si|si|si|si|si|si|si|si|si|si|si|si}tj}tjztizti{uj{ujztiztiztiztiyshyshyshztiztiztiztiztiyshyshztiztiyshyshxrgxrgyshyshxrgxrgxrgxrgyshyshxrgxrgxrgwqfxrgwqfwqfxrgvpevpevpewqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpeyqdvpewpgxoevpevpexoewqfvpeuqfwqfypfxoeypfvpcxoevpexoewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgxrgyshyshxrgxrgyshyshyshyshyshztiztiztiztiztiztiyshyshyshyshyshyshyshyshyshyshyshyshyshztiztiztiztiztizti{uj{uj{uj{uj{uj{uj{uj{ujztiztiztiyshyshyshztiztiyshyshyshyshyshztiztiztiztiztiztiztiyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfxpcypfvofypfypfvypfypfvpeypfxoewqfxoevpewqftpexoewqfwpgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgyshyshxrgxrgyshyshyshyshyshyshxrgxrgyshyshyshyshyshztiyshyshyshyshyshyshyshyshztiztiztiztiztiztiztiyshyshyshyshyshyshyshyshyshztiztiztiztiztiztiztiyshztiztiztiztiztiztiztiztixrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfxrgxrgwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpeypfxpcvofvpexoewqfwqfvpeyyvpexpcxpcypfvpezrewqdypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfxrgxrgxrgxrgwqfwqfwqfwqfxrgxrgyshxrgxrgxrgyshyshyshyshyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgyshyshyshyshyshztiztiztiztiztiztiztiztiztiztiztiztiztiztiztiyshyshyshxrgyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewpgypfyqdwqfwpgypfxpc~wnxoypfwmypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfwqfwqfvpevpewqfwqfwqfwqfwqfxrgwqfwqfwqfwqfwqfwqfxrgxrgyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshyshxrgxrgyshyshyshyshyshyshyshyshxrgxrgxrgyshyshyshyshxrgxrgxrgxrgyshyshyshyshyshxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewpgxoexpcvpevofypfyn}wpyvofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgyshyshyshyshyshyshyshyshxrgxrgxrgxrgyshyshyshyshyshyshyshyshyshyshyshyshyshxrgxrgxrgxrgxrgyshyshyshyshyshyshxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfwqfwqfxrgwqfwqfwqfwqfwqfvpevpewqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoevpevpeyqdvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfvpewqfwqfwqfvpevpevpevpexrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfxrgxrgxrgxrgxrgyshxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfwqfwqfxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfwqfvpevpevpewqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcwqfvpewqfvpeyqdwpgxpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpewqfvpevpevpevpevpevpewqfwqfxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgxrgwqfwqfwqfwqfxrgxrgwqfwqfwqfwqfvpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdvpewqfwqfxrgypcwpgvpeyqdypfvpewqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfwqfwqfvpevpevpevpewqfwqfwqfwqfvpevpevpevpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpevpevpevpevpevpewqfwqfwqfvpevpevpewqfwqfwqfwqfwqfvpevpevpewqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcyqdwpgvpewqfypfvoftofzrexpcwqfvpexoeypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfuodwqfvpeypfxoewpgxoezqgvpewpgxupgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpcvpeyqdxoe򗔌ꘒvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfxpcwqfxoeypfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoexoeypfwqfvofwpgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoeypfypfypfvofwpguod󢜕ypgvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewqfypfwqfvpeyqdtofwpgvpeypfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvofwqfvpewqdwqfvpczqcupgypfxoeypfxoexoeypfypfxoewqfwpgypfyqdyqdvpewqfvpcwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpevpevpevpewqfwqfvpexoeypfxpcyqdypfvpevpevpewqfvpeyqdyqdvpevpetofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfvpevpewqfwqfwqfvpeypfvpewpgtofvofwqfyqdzqcxoexoeypfvpewqfvpezovpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwpgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxofwqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfypdwqewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxpcvpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdvpfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdtofwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvpevpewqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfvqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwpgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfxoewqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfyqdtofwpgvpcxqhvpcyqdvpevpexoeypfypfxoeypfvpewpgwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqfwqftomcat7-7.0.52/res/checkstyle/0000755000175100017510000000000012301126372016067 5ustar locutuslocutustomcat7-7.0.52/res/checkstyle/org-checkstyle.xml0000644000175100017510000000311511527521764021551 0ustar locutuslocutus tomcat7-7.0.52/res/checkstyle/javax-import-control.xml0000644000175100017510000000343112204665332022717 0ustar locutuslocutus tomcat7-7.0.52/res/checkstyle/checkstyle.xml0000644000175100017510000000622712123143653020761 0ustar locutuslocutus tomcat7-7.0.52/res/checkstyle/header-al2.txt0000644000175100017510000000170111513073566020545 0ustar locutuslocutus^<\?xml.*>$ ^@echo off$ ^#! ^\W*$ ^(rem)?\W*Licensed to the Apache Software Foundation \(ASF\) under one or more$ ^(rem)?\W*contributor license agreements\. See the NOTICE file distributed with$ ^(rem)?\W*this work for additional information regarding copyright ownership\.$ ^(rem)?\W*The ASF licenses this file to You under the Apache License, Version 2\.0$ ^(rem)?\W*\(the "License"\); you may not use this file except in compliance with$ ^(rem)?\W*the License\. You may obtain a copy of the License at$ ^(rem)?\W*$ ^(rem)?\W*http://www.apache.org/licenses/LICENSE-2\.0$ ^(rem)?\W*$ ^(rem)?\W*Unless required by applicable law or agreed to in writing, software$ ^(rem)?\W*distributed under the License is distributed on an "AS IS" BASIS,$ ^(rem)?\W*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.$ ^(rem)?\W*See the License for the specific language governing permissions and$ ^(rem)?\W*limitations under the License\.$ ^(rem)?\W*$tomcat7-7.0.52/res/checkstyle/javax-checkstyle.xml0000644000175100017510000000312111527521764022070 0ustar locutuslocutus tomcat7-7.0.52/res/checkstyle/org-import-control.xml0000644000175100017510000001307012247730524022400 0ustar locutuslocutus tomcat7-7.0.52/res/INSTALLLICENSE0000644000175100017510000015675612271302242016007 0ustar locutuslocutus 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. APACHE TOMCAT SUBCOMPONENTS: Apache Tomcat includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the following licenses. For the Eclipse JDT Java compiler: Eclipse Public License - v 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and b) in the case of each subsequent Contributor: i) changes to the Program, and ii) additions to the Program; where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. "Contributor" means any person or entity that distributes the Program. "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: a) it complies with the terms and conditions of this Agreement; and b) its license agreement: i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. When the Program is made available in source code form: a) it must be made available under this Agreement; and b) a copy of this Agreement must be included with each copy of the Program. Contributors may not remove or alter any copyright notices contained within the Program. Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. For the Windows Installer component: * All NSIS source code, plug-ins, documentation, examples, header files and graphics, with the exception of the compression modules and where otherwise noted, are licensed under the zlib/libpng license. * The zlib compression module for NSIS is licensed under the zlib/libpng license. * The bzip2 compression module for NSIS is licensed under the bzip2 license. * The lzma compression module for NSIS is licensed under the Common Public License version 1.0. zlib/libpng license 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. bzip2 license 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. 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. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 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. Julian Seward, Cambridge, UK. jseward@acm.org Common Public License version 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and b) in the case of each subsequent Contributor: i) changes to the Program, and ii) additions to the Program; where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. "Contributor" means any person or entity that distributes the Program. "Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: a) it complies with the terms and conditions of this Agreement; and b) its license agreement: i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. When the Program is made available in source code form: a) it must be made available under this Agreement; and b) a copy of this Agreement must be included with each copy of the Program. Contributors may not remove or alter any copyright notices contained within the Program. Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. Special exception for LZMA compression module Igor Pavlov and Amir Szekely, the authors of the LZMA compression module for NSIS, expressly permit you to statically or dynamically link your code (or bind by name) to the files from the LZMA compression module for NSIS without subjecting your linked code to the terms of the Common Public license version 1.0. Any modifications or additions to files from the LZMA compression module for NSIS, however, are subject to the terms of the Common Public License version 1.0. For the following XML Schemas for Java EE Deployment Descriptors: - javaee_5.xsd - javaee_web_services_1_2.xsd - javaee_web_services_client_1_2.xsd - javaee_6.xsd - javaee_web_services_1_3.xsd - javaee_web_services_client_1_3.xsd - jsp_2_2.xsd - web-app_3_0.xsd - web-common_3_0.xsd - web-fragment_3_0.xsd COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. Definitions. 1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications. 1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. Executable. means the Covered Software in any form other than Source Code. 1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License. 1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. License. means this document. 1.8. 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 the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. 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.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. 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. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (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 Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party 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 Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and 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 Software 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 distributes or otherwise makes the Modifications available to a third party. (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) 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 (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. 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 that 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.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of 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 form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form 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 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.6. Larger Works. You may create a Larger Work by combining Covered Software 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 Software. 4. Versions of the License. 4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE 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 SOFTWARE 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 SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE 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 SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.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. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. 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 SOFTWARE, 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 LOST PROFITS, 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. 8. U.S. GOVERNMENT END USERS. The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. ? 252.227-7014(a)(1)) 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 Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. 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 the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction's conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, 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. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. 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. NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California. tomcat7-7.0.52/res/findbugs/0000755000175100017510000000000012301126372015532 5ustar locutuslocutustomcat7-7.0.52/res/findbugs/filter-false-positives.xml0000644000175100017510000002737211730476774022712 0ustar locutuslocutus tomcat7-7.0.52/res/findbugs/filter-post-7.0.x-fixes.xml0000644000175100017510000000344111765627647022442 0ustar locutuslocutus tomcat7-7.0.52/res/welcome.main.html0000644000175100017510000001110112271302242017165 0ustar locutuslocutus Apache Tomcat @VERSION@

Apache Tomcat @VERSION@

Useful references:

NOTE: The tar files in this distribution use GNU tar extensions, and must be untarred with a GNU compatible version of tar. The version of tar on Solaris and Mac OS X will not work with these files.

Tomcat @VERSION_MAJOR_MINOR@ requires Java SE 6 or later. Read the RELEASE-NOTES and the RUNNING.txt file in the distribution for more details.

Packaging Details (or "What Should I Download?")

bin/
apache-tomcat-[version].zip or .tar.gz
Base distribution. These distributions do not include the Windows service wrapper nor the compiled APR/native library for Windows.
apache-tomcat-[version].exe
32-bit/64-bit Windows installer for Tomcat.   Please note that while this distribution includes the vast majority of the base distribution, some of the command-line scripts for launching Tomcat are not included. This distribution is intended for those users planning to launch Tomcat through the Windows shortcuts or services.
apache-tomcat-[version]-windows-x86.zip
32-bit Windows specific distribution that includes the Windows service wrapper and the compiled APR/native library for use with 32-bit JVMs on both 32 and 64 bit Windows platforms.
apache-tomcat-[version]-windows-x64.zip
64-bit Windows specific distribution that includes the Windows service wrapper and the compiled APR/native library for use with 64-bit JVMs on x64 Windows platforms.
apache-tomcat-[version]-windows-i64.zip
64-bit Windows specific distribution that includes the Windows service wrapper and the compiled APR/native library for use with 64-bit JVMs on Itanium 64-bit Windows platforms.
apache-tomcat-[version]-deployer.zip or .tar.gz
The standalone Tomcat Web Application Deployer.
apache-tomcat-[version]-fulldocs.tar.gz
The Tomcat documentation bundle, including complete javadocs.
bin/extras/
tomcat-juli-adapters.jar & tomcat-juli.jar
Full commons-logging implementation. See the logging documentation for more information.
catalina-ws.jar
Web Services support (JSR 109). See the extras documentation for more information.
catalina-jmx-remote.jar
JMX Remote Lifecycle Listener. See the listeners documentation for details.
src/
apache-tomcat-[version].zip or .tar.gz
The source code. See building instructions.

Thank you for using Tomcat!.

The Apache Tomcat Project
http://tomcat.apache.org/

tomcat7-7.0.52/res/welcome.bin.html0000644000175100017510000001110412271302242017014 0ustar locutuslocutus Apache Tomcat @VERSION@

Apache Tomcat @VERSION@

Useful references:

NOTE: The tar files in this distribution use GNU tar extensions, and must be untarred with a GNU compatible version of tar. The version of tar on Solaris and Mac OS X will not work with these files.

Tomcat @VERSION_MAJOR_MINOR@ requires Java SE 6 or later. Read the RELEASE-NOTES and the RUNNING.txt file in the distribution for more details.

Packaging Details (or "What Should I Download?")

bin/
apache-tomcat-[version].zip or .tar.gz
Base distribution. These distributions do not include the Windows service wrapper nor the compiled APR/native library for Windows.
apache-tomcat-[version].exe
32-bit/64-bit Windows installer for Tomcat.   Please note that while this distribution includes the vast majority of the base distribution, some of the command-line scripts for launching Tomcat are not included. This distribution is intended for those users planning to launch Tomcat through the Windows shortcuts or services.
apache-tomcat-[version]-windows-x86.zip
32-bit Windows specific distribution that includes the Windows service wrapper and the compiled APR/native library for use with 32-bit JVMs on both 32 and 64 bit Windows platforms.
apache-tomcat-[version]-windows-x64.zip
64-bit Windows specific distribution that includes the Windows service wrapper and the compiled APR/native library for use with 64-bit JVMs on x64 Windows platforms.
apache-tomcat-[version]-windows-i64.zip
64-bit Windows specific distribution that includes the Windows service wrapper and the compiled APR/native library for use with 64-bit JVMs on Itanium 64-bit Windows platforms.
apache-tomcat-[version]-deployer.zip or .tar.gz
The standalone Tomcat Web Application Deployer.
apache-tomcat-[version]-fulldocs.tar.gz
The Tomcat documentation bundle, including complete javadocs.
bin/extras/
tomcat-juli-adapters.jar & tomcat-juli.jar
Full commons-logging implementation. See the logging documentation for more information.
catalina-ws.jar
Web Services support (JSR 109). See the extras documentation for more information.
catalina-jmx-remote.jar
JMX Remote Lifecycle Listener. See the listeners documentation for details.
src/
apache-tomcat-[version].zip or .tar.gz
The source code. See building instructions.

Thank you for using Tomcat!.

The Apache Tomcat Project
http://tomcat.apache.org/

tomcat7-7.0.52/res/tomcat.nsi0000644000175100017510000011314312271302242015734 0ustar locutuslocutus; Licensed to the Apache Software Foundation (ASF) under one or more ; contributor license agreements. See the NOTICE file distributed with ; this work for additional information regarding copyright ownership. ; The ASF licenses this file to You 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. ; Tomcat script for Nullsoft Installer ;Compression options CRCCheck on SetCompressor /SOLID lzma Name "Apache Tomcat" ;Product information VIAddVersionKey ProductName "Apache Tomcat" VIAddVersionKey CompanyName "Apache Software Foundation" VIAddVersionKey LegalCopyright "Copyright (c) 1999-@YEAR@ The Apache Software Foundation" VIAddVersionKey FileDescription "Apache Tomcat Installer" VIAddVersionKey FileVersion "2.0" VIAddVersionKey ProductVersion "@VERSION@" VIAddVersionKey Comments "tomcat.apache.org" VIAddVersionKey InternalName "apache-tomcat-@VERSION@.exe" VIProductVersion @VERSION_NUMBER@ !include "MUI2.nsh" !include "nsDialogs.nsh" !include "StrFunc.nsh" !include "LogicLib.nsh" !include "FileFunc.nsh" ${StrRep} Var JavaHome Var JavaExe Var JvmDll Var Arch Var ResetInstDir Var TomcatPortShutdown Var TomcatPortHttp Var TomcatPortAjp Var TomcatMenuEntriesEnable Var TomcatShortcutAllUsers Var TomcatServiceName Var TomcatServiceDefaultName Var TomcatServiceFileName Var TomcatServiceManagerFileName Var TomcatAdminEnable Var TomcatAdminUsername Var TomcatAdminPassword Var TomcatAdminRoles ; Variables that store handles of dialog controls Var CtlJavaHome Var CtlTomcatPortShutdown Var CtlTomcatPortHttp Var CtlTomcatPortAjp Var CtlTomcatServiceName Var CtlTomcatShortcutAllUsers Var CtlTomcatAdminUsername Var CtlTomcatAdminPassword Var CtlTomcatAdminRoles ; Handle of the service-install.log file ; It is opened in "Core" section and closed in "-post" Var ServiceInstallLog ;-------------------------------- ;Configuration !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_RIGHT !define MUI_HEADERIMAGE_BITMAP header.bmp !define MUI_WELCOMEFINISHPAGE_BITMAP side_left.bmp !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\webapps\ROOT\RELEASE-NOTES.txt" !define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN_FUNCTION "startService" !define MUI_FINISHPAGE_NOREBOOTSUPPORT !define MUI_ABORTWARNING !define MUI_ICON tomcat.ico !define MUI_UNICON tomcat.ico ;General OutFile tomcat-installer.exe ;Install Options pages LangString TEXT_JVM_TITLE ${LANG_ENGLISH} "Java Virtual Machine" LangString TEXT_JVM_SUBTITLE ${LANG_ENGLISH} "Java Virtual Machine path selection." LangString TEXT_JVM_PAGETITLE ${LANG_ENGLISH} ": Java Virtual Machine path selection" LangString TEXT_INSTDIR_NOT_EMPTY ${LANG_ENGLISH} "The specified installation directory is not empty. Do you wish to continue?" LangString TEXT_CONF_TITLE ${LANG_ENGLISH} "Configuration" LangString TEXT_CONF_SUBTITLE ${LANG_ENGLISH} "Tomcat basic configuration." LangString TEXT_CONF_PAGETITLE ${LANG_ENGLISH} ": Configuration Options" LangString TEXT_JVM_LABEL1 ${LANG_ENGLISH} "Please select the path of a Java SE 6.0 or later JRE installed on your system." LangString TEXT_CONF_LABEL_PORT_SHUTDOWN ${LANG_ENGLISH} "Server Shutdown Port" LangString TEXT_CONF_LABEL_PORT_HTTP ${LANG_ENGLISH} "HTTP/1.1 Connector Port" LangString TEXT_CONF_LABEL_PORT_AJP ${LANG_ENGLISH} "AJP/1.3 Connector Port" LangString TEXT_CONF_LABEL_SERVICE_NAME ${LANG_ENGLISH} "Windows Service Name" LangString TEXT_CONF_LABEL_SHORTCUT_ALL_USERS ${LANG_ENGLISH} "Create shortcuts for all users" LangString TEXT_CONF_LABEL_ADMIN ${LANG_ENGLISH} "Tomcat Administrator Login (optional)" LangString TEXT_CONF_LABEL_ADMINUSERNAME ${LANG_ENGLISH} "User Name" LangString TEXT_CONF_LABEL_ADMINPASSWORD ${LANG_ENGLISH} "Password" LangString TEXT_CONF_LABEL_ADMINROLES ${LANG_ENGLISH} "Roles" ;Install Page order !insertmacro MUI_PAGE_WELCOME ; Show file named "INSTALLLICENSE" !insertmacro MUI_PAGE_LICENSE INSTALLLICENSE ; Use custom onLeave function with COMPONENTS page !define MUI_PAGE_CUSTOMFUNCTION_LEAVE pageComponentsLeave !insertmacro MUI_PAGE_COMPONENTS Page custom pageConfiguration pageConfigurationLeave "$(TEXT_CONF_PAGETITLE)" Page custom pageChooseJVM pageChooseJVMLeave "$(TEXT_JVM_PAGETITLE)" !define MUI_PAGE_CUSTOMFUNCTION_LEAVE pageDirectoryLeave !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES Page custom CheckUserType !insertmacro MUI_PAGE_FINISH ;Uninstall Page order !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;Component-selection page ;Descriptions LangString DESC_SecTomcat ${LANG_ENGLISH} "Install the Tomcat Servlet container as a Windows service." LangString DESC_SecTomcatCore ${LANG_ENGLISH} "Install the Tomcat Servlet container core and create the Windows service." LangString DESC_SecTomcatService ${LANG_ENGLISH} "Automatically start the Tomcat service when the computer is started." LangString DESC_SecTomcatNative ${LANG_ENGLISH} "Install APR based Tomcat native .dll for better performance and scalability in production environments." LangString DESC_SecMenu ${LANG_ENGLISH} "Create a Start Menu program group for Tomcat." LangString DESC_SecDocs ${LANG_ENGLISH} "Install the Tomcat documentation bundle. This includes documentation on the servlet container and its configuration options, on the Jasper JSP page compiler, as well as on the native webserver connectors." LangString DESC_SecManager ${LANG_ENGLISH} "Install the Tomcat Manager administrative web application." LangString DESC_SecHostManager ${LANG_ENGLISH} "Install the Tomcat Host Manager administrative web application." LangString DESC_SecExamples ${LANG_ENGLISH} "Install the Servlet and JSP examples web application." ;Language !insertmacro MUI_LANGUAGE English ;Install types InstType Normal InstType Minimum InstType Full ReserveFile "${NSISDIR}\Plugins\System.dll" ReserveFile "${NSISDIR}\Plugins\nsDialogs.dll" ReserveFile confinstall\tomcat-users_1.xml ReserveFile confinstall\tomcat-users_2.xml ;-------------------------------- ;Installer Sections SubSection "Tomcat" SecTomcat Section "Core" SecTomcatCore SectionIn 1 2 3 RO ${If} ${Silent} Call checkJava ${EndIf} SetOutPath $INSTDIR File tomcat.ico File LICENSE File NOTICE SetOutPath $INSTDIR\lib File /r lib\*.* ; Note: just calling 'SetOutPath' will create the empty folders for us SetOutPath $INSTDIR\logs SetOutPath $INSTDIR\work SetOutPath $INSTDIR\temp SetOutPath $INSTDIR\bin File bin\bootstrap.jar File bin\tomcat-juli.jar SetOutPath $INSTDIR\conf File conf\*.* SetOutPath $INSTDIR\webapps\ROOT File /r webapps\ROOT\*.* Call configure DetailPrint "Using Jvm: $JavaHome" StrCpy $R0 $TomcatServiceName StrCpy $TomcatServiceFileName $R0.exe StrCpy $TomcatServiceManagerFileName $R0w.exe SetOutPath $INSTDIR\bin File /oname=$TomcatServiceManagerFileName bin\tomcat@VERSION_MAJOR@w.exe ; Get the current platform x86 / AMD64 / IA64 ${If} $Arch == "x86" File /oname=$TomcatServiceFileName bin\tomcat@VERSION_MAJOR@.exe ${ElseIf} $Arch == "x64" File /oname=$TomcatServiceFileName bin\x64\tomcat@VERSION_MAJOR@.exe ${ElseIf} $Arch == "i64" File /oname=$TomcatServiceFileName bin\i64\tomcat@VERSION_MAJOR@.exe ${EndIf} FileOpen $ServiceInstallLog "$INSTDIR\logs\service-install.log" a FileSeek $ServiceInstallLog 0 END InstallRetry: FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //IS//$TomcatServiceName --DisplayName "Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" --Description "Apache Tomcat @VERSION@ Server - http://tomcat.apache.org/" --LogPath "$INSTDIR\logs" --Install "$INSTDIR\bin\$TomcatServiceFileName" --Jvm "$JvmDll" --StartPath "$INSTDIR" --StopPath "$INSTDIR"' FileWrite $ServiceInstallLog "$\r$\n" ClearErrors DetailPrint "Installing $TomcatServiceName service" nsExec::ExecToStack '"$INSTDIR\bin\$TomcatServiceFileName" //IS//$TomcatServiceName --DisplayName "Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" --Description "Apache Tomcat @VERSION@ Server - http://tomcat.apache.org/" --LogPath "$INSTDIR\logs" --Install "$INSTDIR\bin\$TomcatServiceFileName" --Jvm "$JvmDll" --StartPath "$INSTDIR" --StopPath "$INSTDIR"' Pop $0 Pop $1 StrCmp $0 "0" InstallOk FileWrite $ServiceInstallLog "Install failed: $0 $1$\r$\n" MessageBox MB_ABORTRETRYIGNORE|MB_ICONSTOP \ "Failed to install $TomcatServiceName service.$\r$\nCheck your settings and permissions.$\r$\nIgnore and continue anyway (not recommended)?" \ /SD IDIGNORE IDIGNORE InstallOk IDRETRY InstallRetry Quit InstallOk: ClearErrors ; Will be closed in "-post" section ; FileClose $ServiceInstallLog SectionEnd Section "Service Startup" SecTomcatService SectionIn 3 ${If} $ServiceInstallLog != "" FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --Startup auto' FileWrite $ServiceInstallLog "$\r$\n" ${EndIf} DetailPrint "Configuring $TomcatServiceName service" nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --Startup auto' ClearErrors SectionEnd Section "Native" SecTomcatNative SectionIn 3 SetOutPath $INSTDIR\bin ${If} $Arch == "x86" File bin\tcnative-1.dll ${ElseIf} $Arch == "x64" File /oname=tcnative-1.dll bin\x64\tcnative-1.dll ${ElseIf} $Arch == "i64" File /oname=tcnative-1.dll bin\i64\tcnative-1.dll ${EndIf} ClearErrors SectionEnd SubSectionEnd Section "Start Menu Items" SecMenu SectionIn 1 2 3 SectionEnd Section "Documentation" SecDocs SectionIn 1 3 SetOutPath $INSTDIR\webapps\docs File /r webapps\docs\*.* SectionEnd Section "Manager" SecManager SectionIn 1 3 SetOverwrite on SetOutPath $INSTDIR\webapps\manager File /r webapps\manager\*.* SectionEnd Section "Host Manager" SecHostManager SectionIn 3 SetOverwrite on SetOutPath $INSTDIR\webapps\host-manager File /r webapps\host-manager\*.* SectionEnd Section "Examples" SecExamples SectionIn 3 SetOverwrite on SetOutPath $INSTDIR\webapps\examples File /r webapps\examples\*.* SectionEnd Section -post ${If} $ServiceInstallLog != "" FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --Classpath "$INSTDIR\bin\bootstrap.jar;$INSTDIR\bin\tomcat-juli.jar" --StartClass org.apache.catalina.startup.Bootstrap --StopClass org.apache.catalina.startup.Bootstrap --StartParams start --StopParams stop --StartMode jvm --StopMode jvm' FileWrite $ServiceInstallLog "$\r$\n" FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions "-Dcatalina.home=$INSTDIR#-Dcatalina.base=$INSTDIR#-Djava.endorsed.dirs=$INSTDIR\endorsed#-Djava.io.tmpdir=$INSTDIR\temp#-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager#-Djava.util.logging.config.file=$INSTDIR\conf\logging.properties"' FileWrite $ServiceInstallLog "$\r$\n" FileWrite $ServiceInstallLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --StdOutput auto --StdError auto' FileWrite $ServiceInstallLog "$\r$\n" FileClose $ServiceInstallLog ${EndIf} DetailPrint "Configuring $TomcatServiceName service" nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --Classpath "$INSTDIR\bin\bootstrap.jar;$INSTDIR\bin\tomcat-juli.jar" --StartClass org.apache.catalina.startup.Bootstrap --StopClass org.apache.catalina.startup.Bootstrap --StartParams start --StopParams stop --StartMode jvm --StopMode jvm' nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --JvmOptions "-Dcatalina.home=$INSTDIR#-Dcatalina.base=$INSTDIR#-Djava.endorsed.dirs=$INSTDIR\endorsed#-Djava.io.tmpdir=$INSTDIR\temp#-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager#-Djava.util.logging.config.file=$INSTDIR\conf\logging.properties"' nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //US//$TomcatServiceName --StdOutput auto --StdError auto' ${If} $TomcatShortcutAllUsers == "1" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor@VERSION_MAJOR_MINOR@_$TomcatServiceName" '"$INSTDIR\bin\$TomcatServiceManagerFileName" //MS//$TomcatServiceName' ${Else} WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor@VERSION_MAJOR_MINOR@_$TomcatServiceName" '"$INSTDIR\bin\$TomcatServiceManagerFileName" //MS//$TomcatServiceName' ${EndIf} ${If} $TomcatMenuEntriesEnable == "1" Call createShortcuts ${EndIf} WriteUninstaller "$INSTDIR\Uninstall.exe" WriteRegStr HKLM "SOFTWARE\Apache Software Foundation\Tomcat\@VERSION_MAJOR_MINOR@\$TomcatServiceName" "InstallPath" $INSTDIR WriteRegStr HKLM "SOFTWARE\Apache Software Foundation\Tomcat\@VERSION_MAJOR_MINOR@\$TomcatServiceName" "Version" @VERSION@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" \ "DisplayName" "Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName (remove only)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" \ "DisplayIcon" "$\"$INSTDIR\tomcat.ico$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" \ "UninstallString" "$\"$INSTDIR\Uninstall.exe$\" -ServiceName=$\"$TomcatServiceName$\"" SectionEnd Function .onInit ${GetParameters} $R0 ClearErrors ${GetOptions} "$R0" "/?" $R1 ${IfNot} ${Errors} MessageBox MB_OK|MB_ICONINFORMATION 'Available options:$\r$\n\ /S - Silent install.$\r$\n\ /D=INSTDIR - Specify installation directory.' Abort ${EndIf} ClearErrors StrCpy $ResetInstDir "$INSTDIR" ;Initialize default values StrCpy $JavaHome "" StrCpy $TomcatPortShutdown "8005" StrCpy $TomcatPortHttp "8080" StrCpy $TomcatPortAjp "8009" StrCpy $TomcatMenuEntriesEnable "0" StrCpy $TomcatShortcutAllUsers "0" StrCpy $TomcatServiceDefaultName "Tomcat@VERSION_MAJOR@" StrCpy $TomcatServiceName $TomcatServiceDefaultName StrCpy $TomcatServiceFileName "Tomcat@VERSION_MAJOR@.exe" StrCpy $TomcatServiceManagerFileName "Tomcat@VERSION_MAJOR@w.exe" StrCpy $TomcatAdminEnable "0" StrCpy $TomcatAdminUsername "" StrCpy $TomcatAdminPassword "" StrCpy $TomcatAdminRoles "" FunctionEnd Function pageChooseJVM !insertmacro MUI_HEADER_TEXT "$(TEXT_JVM_TITLE)" "$(TEXT_JVM_SUBTITLE)" ${If} $JavaHome == "" Call findJavaHome Pop $JavaHome ${EndIf} nsDialogs::Create 1018 Pop $R0 ${NSD_CreateLabel} 0 5u 100% 25u "$(TEXT_JVM_LABEL1)" Pop $R0 ${NSD_CreateDirRequest} 0 65u 280u 13u "$JavaHome" Pop $CtlJavaHome ${NSD_CreateBrowseButton} 282u 65u 15u 13u "..." Pop $R0 ${NSD_OnClick} $R0 pageChooseJVM_onDirBrowse ${NSD_SetFocus} $CtlJavaHome nsDialogs::Show FunctionEnd ; onClick function for button next to DirRequest control Function pageChooseJVM_onDirBrowse ; R0 is HWND of the button, it is on top of the stack Pop $R0 ${NSD_GetText} $CtlJavaHome $R1 nsDialogs::SelectFolderDialog "" "$R1" Pop $R1 ${If} $R1 != "error" ${NSD_SetText} $CtlJavaHome $R1 ${EndIf} FunctionEnd Function pageChooseJVMLeave ${NSD_GetText} $CtlJavaHome $JavaHome ${If} $JavaHome == "" Abort ${EndIf} Call checkJava FunctionEnd ; onLeave function for the COMPONENTS page ; It updates options based on what components were selected. ; Function pageComponentsLeave StrCpy $TomcatAdminEnable "0" StrCpy $TomcatAdminRoles "" StrCpy $TomcatMenuEntriesEnable "0" SectionGetFlags ${SecManager} $0 IntOp $0 $0 & ${SF_SELECTED} ${If} $0 <> 0 StrCpy $TomcatAdminEnable "1" StrCpy $TomcatAdminRoles "manager-gui" ${EndIf} SectionGetFlags ${SecHostManager} $0 IntOp $0 $0 & ${SF_SELECTED} ${If} $0 <> 0 StrCpy $TomcatAdminEnable "1" ${If} $TomcatAdminRoles != "" StrCpy $TomcatAdminRoles "admin-gui,$TomcatAdminRoles" ${Else} StrCpy $TomcatAdminRoles "admin-gui" ${EndIf} ${EndIf} SectionGetFlags ${SecMenu} $0 IntOp $0 $0 & ${SF_SELECTED} ${If} $0 <> 0 StrCpy $TomcatMenuEntriesEnable "1" ${EndIf} FunctionEnd Function pageDirectoryLeave ${DirState} "$INSTDIR" $0 ${If} $0 == 1 ;folder is full. (other values: 0: empty, -1: not found) ;query selection MessageBox MB_OKCANCEL|MB_ICONQUESTION "$(TEXT_INSTDIR_NOT_EMPTY)" /SD IDOK IDCANCEL notok Goto ok notok: Abort ok: ${EndIf} FunctionEnd Function pageConfiguration !insertmacro MUI_HEADER_TEXT "$(TEXT_CONF_TITLE)" "$(TEXT_CONF_SUBTITLE)" nsDialogs::Create 1018 Pop $R0 ${NSD_CreateLabel} 0 2u 100u 14u "$(TEXT_CONF_LABEL_PORT_SHUTDOWN)" Pop $R0 ${NSD_CreateText} 150u 0 50u 12u "$TomcatPortShutdown" Pop $CtlTomcatPortShutdown ${NSD_SetTextLimit} $CtlTomcatPortShutdown 5 ${NSD_CreateLabel} 0 19u 100u 14u "$(TEXT_CONF_LABEL_PORT_HTTP)" Pop $R0 ${NSD_CreateText} 150u 17u 50u 12u "$TomcatPortHttp" Pop $CtlTomcatPortHttp ${NSD_SetTextLimit} $CtlTomcatPortHttp 5 ${NSD_CreateLabel} 0 36u 100u 14u "$(TEXT_CONF_LABEL_PORT_AJP)" Pop $R0 ${NSD_CreateText} 150u 34u 50u 12u "$TomcatPortAjp" Pop $CtlTomcatPortAjp ${NSD_SetTextLimit} $CtlTomcatPortAjp 5 ${NSD_CreateLabel} 0 57u 140u 14u "$(TEXT_CONF_LABEL_SERVICE_NAME)" Pop $R0 ${NSD_CreateText} 150u 55u 140u 12u "$TomcatServiceName" Pop $CtlTomcatServiceName ${If} $TomcatMenuEntriesEnable == "1" ${NSD_CreateLabel} 0 75u 100u 14u "$(TEXT_CONF_LABEL_SHORTCUT_ALL_USERS)" Pop $R0 ${NSD_CreateCheckBox} 150u 74u 10u 10u "$TomcatShortcutAllUsers" Pop $CtlTomcatShortcutAllUsers ${EndIf} ${If} $TomcatAdminEnable == "1" ${NSD_CreateLabel} 0 93u 90u 28u "$(TEXT_CONF_LABEL_ADMIN)" Pop $R0 ${NSD_CreateLabel} 100u 93u 40u 14u "$(TEXT_CONF_LABEL_ADMINUSERNAME)" Pop $R0 ${NSD_CreateText} 150u 91u 110u 12u "$TomcatAdminUsername" Pop $CtlTomcatAdminUsername ${NSD_CreateLabel} 100u 110u 40u 12u "$(TEXT_CONF_LABEL_ADMINPASSWORD)" Pop $R0 ${NSD_CreatePassword} 150u 108u 110u 12u "$TomcatAdminPassword" Pop $CtlTomcatAdminPassword ${NSD_CreateLabel} 100u 127u 40u 14u "$(TEXT_CONF_LABEL_ADMINROLES)" Pop $R0 ${NSD_CreateText} 150u 125u 110u 12u "$TomcatAdminRoles" Pop $CtlTomcatAdminRoles ${EndIf} ${NSD_SetFocus} $CtlTomcatPortShutdown nsDialogs::Show FunctionEnd Function pageConfigurationLeave ${NSD_GetText} $CtlTomcatPortShutdown $TomcatPortShutdown ${NSD_GetText} $CtlTomcatPortHttp $TomcatPortHttp ${NSD_GetText} $CtlTomcatPortAjp $TomcatPortAjp ${NSD_GetText} $CtlTomcatServiceName $TomcatServiceName ${If} $TomcatMenuEntriesEnable == "1" ${NSD_GetState} $CtlTomcatShortcutAllUsers $TomcatShortcutAllUsers ${EndIf} ${If} $TomcatAdminEnable == "1" ${NSD_GetText} $CtlTomcatAdminUsername $TomcatAdminUsername ${NSD_GetText} $CtlTomcatAdminPassword $TomcatAdminPassword ${NSD_GetText} $CtlTomcatAdminRoles $TomcatAdminRoles ${EndIf} ${If} $TomcatPortShutdown == "" MessageBox MB_ICONEXCLAMATION|MB_OK 'The shutdown port may not be empty' Abort "Config not right" Goto exit ${EndIf} ${If} $TomcatPortHttp == "" MessageBox MB_ICONEXCLAMATION|MB_OK 'The HTTP port may not be empty' Abort "Config not right" Goto exit ${EndIf} ${If} $TomcatPortAjp == "" MessageBox MB_ICONEXCLAMATION|MB_OK 'The AJP port may not be empty' Abort "Config not right" Goto exit ${EndIf} ${If} $TomcatServiceName == "" MessageBox MB_ICONEXCLAMATION|MB_OK 'The Service Name may not be empty' Abort "Config not right" Goto exit ${EndIf} Push $TomcatServiceName Call validateServiceName Pop $0 IntCmp $0 1 exit MessageBox MB_ICONEXCLAMATION|MB_OK 'The Service Name may not contain a space or any of the following characters: <>:"/\:|?*' Abort "Config not right" exit: FunctionEnd ; Validates that a service name does not use any of the invalid ; characters: <>:"/\:|?* ; Note that space is also not permitted although it will be once ; Tomcat is using Daemon 1.0.6 or later ; ; Put the proposed service name on the stack ; If the name is valid, a 1 will be left on the stack ; If the name is invalid, a 0 will be left on the stack Function validateServiceName Pop $0 StrLen $1 $0 StrCpy $3 '<>:"/\:|?* ' StrLen $4 $3 loopInput: IntOp $1 $1 - 1 IntCmp $1 -1 valid loopTestChars: IntOp $4 $4 - 1 IntCmp $4 -1 loopTestCharsDone StrCpy $2 $0 1 $1 StrCpy $5 $3 1 $4 StrCmp $2 $5 invalid loopTestChars loopTestCharsDone: StrLen $4 $3 Goto loopInput invalid: Push 0 Goto exit valid: Push 1 exit: FunctionEnd ;-------------------------------- ;Descriptions !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcat} $(DESC_SecTomcat) !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcatCore} $(DESC_SecTomcatCore) !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcatService} $(DESC_SecTomcatService) !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcatNative} $(DESC_SecTomcatNative) !insertmacro MUI_DESCRIPTION_TEXT ${SecMenu} $(DESC_SecMenu) !insertmacro MUI_DESCRIPTION_TEXT ${SecDocs} $(DESC_SecDocs) !insertmacro MUI_DESCRIPTION_TEXT ${SecManager} $(DESC_SecManager) !insertmacro MUI_DESCRIPTION_TEXT ${SecHostManager} $(DESC_SecHostManager) !insertmacro MUI_DESCRIPTION_TEXT ${SecExamples} $(DESC_SecExamples) !insertmacro MUI_FUNCTION_DESCRIPTION_END ; ===================== ; CheckUserType Function ; ===================== ; ; Check the user type, and warn if it's not an administrator. ; Taken from Examples/UserInfo that ships with NSIS. Function CheckUserType ClearErrors UserInfo::GetName IfErrors Win9x Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +3 ; This is OK, do nothing Goto done MessageBox MB_OK|MB_ICONEXCLAMATION 'Note: the current user is not an administrator. \ To run Tomcat as a Windows service, you must be an administrator. \ You can still run Tomcat from the command-line as this type of user.' Goto done Win9x: # This one means you don't need to care about admin or # not admin because Windows 9x doesn't either MessageBox MB_OK "Error! This DLL can't run under Windows 9x!" done: FunctionEnd ; ================== ; checkJava Function ; ================== ; ; Checks that a valid JVM has been specified or a suitable default is available ; Sets $JavaHome, $JavaExe and $JvmDll accordingly ; Determines if the JVM is 32-bit or 64-bit and sets $Arch accordingly. For ; 64-bit JVMs, also determines if it is x64 or ia64 Function checkJava ${If} $JavaHome == "" ; E.g. if a silent install Call findJavaHome Pop $JavaHome ${EndIf} ${If} $JavaHome == "" ${OrIfNot} ${FileExists} "$JavaHome\bin\java.exe" IfSilent +2 MessageBox MB_OK|MB_ICONSTOP "No Java Virtual Machine found in folder:$\r$\n$JavaHome" DetailPrint "No Java Virtual Machine found in folder:$\r$\n$JavaHome" Quit ${EndIf} StrCpy "$JavaExe" "$JavaHome\bin\java.exe" ; Need path to jvm.dll to configure the service - uses $JavaHome Call findJVMPath Pop $5 ${If} $5 == "" IfSilent +2 MessageBox MB_OK|MB_ICONSTOP "No Java Virtual Machine found in folder:$\r$\n$5" DetailPrint "No Java Virtual Machine found in folder:$\r$\n$5" Quit ${EndIf} StrCpy "$JvmDll" $5 ; Read PE header of JvmDll to check for architecture ; 1. Jump to 0x3c and read offset of PE header ; 2. Jump to offset. Read PE header signature. It must be 'PE'\0\0 (50 45 00 00). ; 3. The next word gives the machine type. ; 0x014c: x86 ; 0x8664: x64 ; 0x0200: i64 ClearErrors FileOpen $R1 "$JvmDll" r IfErrors WrongPEHeader FileSeek $R1 0x3c SET FileReadByte $R1 $R2 FileReadByte $R1 $R3 IntOp $R3 $R3 << 8 IntOp $R2 $R2 + $R3 FileSeek $R1 $R2 SET FileReadByte $R1 $R2 IntCmp $R2 0x50 +1 WrongPEHeader WrongPEHeader FileReadByte $R1 $R2 IntCmp $R2 0x45 +1 WrongPEHeader WrongPEHeader FileReadByte $R1 $R2 IntCmp $R2 0 +1 WrongPEHeader WrongPEHeader FileReadByte $R1 $R2 IntCmp $R2 0 +1 WrongPEHeader WrongPEHeader FileReadByte $R1 $R2 FileReadByte $R1 $R3 IntOp $R3 $R3 << 8 IntOp $R2 $R2 + $R3 IntCmp $R2 0x014c +1 +3 +3 StrCpy "$Arch" "x86" Goto DonePEHeader IntCmp $R2 0x8664 +1 +3 +3 StrCpy "$Arch" "x64" Goto DonePEHeader IntCmp $R2 0x0200 +1 +3 +3 StrCpy "$Arch" "i64" Goto DonePEHeader WrongPEHeader: IfSilent +2 MessageBox MB_OK|MB_ICONEXCLAMATION 'Cannot read PE header from "$JvmDll"$\r$\nWill assume that the architecture is x86.' DetailPrint 'Cannot read PE header from "$JvmDll". Assuming the architecture is x86.' StrCpy "$Arch" "x86" DonePEHeader: FileClose $R1 DetailPrint 'Architecture: "$Arch"' StrCpy $INSTDIR "$ResetInstDir" ; The default varies depending on 32-bit or 64-bit ${If} "$INSTDIR" == "" ${If} $Arch == "x86" ${If} $TomcatServiceName == $TomcatServiceDefaultName StrCpy $INSTDIR "$PROGRAMFILES32\Apache Software Foundation\Tomcat @VERSION_MAJOR_MINOR@" ${Else} StrCpy $INSTDIR "$PROGRAMFILES32\Apache Software Foundation\Tomcat @VERSION_MAJOR_MINOR@_$TomcatServiceName" ${EndIf} ${Else} ${If} $TomcatServiceName == $TomcatServiceDefaultName StrCpy $INSTDIR "$PROGRAMFILES64\Apache Software Foundation\Tomcat @VERSION_MAJOR_MINOR@" ${Else} StrCpy $INSTDIR "$PROGRAMFILES64\Apache Software Foundation\Tomcat @VERSION_MAJOR_MINOR@_$TomcatServiceName" ${EndIf} ${EndIf} ${EndIf} FunctionEnd ; ===================== ; findJavaHome Function ; ===================== ; ; Find the JAVA_HOME used on the system, and put the result on the top of the ; stack ; Will return an empty string if the path cannot be determined ; Function findJavaHome ClearErrors StrCpy $1 "" ; Use the 64-bit registry first on 64-bit machines ExpandEnvStrings $0 "%PROGRAMW6432%" ${If} $0 != "%PROGRAMW6432%" SetRegView 64 ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" "CurrentVersion" ReadRegStr $1 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$2" "JavaHome" ReadRegStr $3 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$2" "RuntimeLib" IfErrors 0 +2 StrCpy $1 "" ClearErrors ${EndIf} ; If no 64-bit Java was found, look for 32-bit Java ${If} $1 == "" SetRegView 32 ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" "CurrentVersion" ReadRegStr $1 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$2" "JavaHome" ReadRegStr $3 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$2" "RuntimeLib" IfErrors 0 +2 StrCpy $1 "" ClearErrors ; If using 64-bit, go back to using 64-bit registry ${If} $0 != "%PROGRAMW6432%" SetRegView 64 ${EndIf} ${EndIf} ; Put the result in the stack Push $1 FunctionEnd ; ==================== ; FindJVMPath Function ; ==================== ; ; Find the full JVM path, and put the result on top of the stack ; Implicit argument: $JavaHome ; Will return an empty string if the path cannot be determined ; Function findJVMPath ClearErrors ;Step one: Is this a JRE path (Program Files\Java\XXX) StrCpy $1 "$JavaHome" StrCpy $2 "$1\bin\hotspot\jvm.dll" IfFileExists "$2" FoundJvmDll StrCpy $2 "$1\bin\server\jvm.dll" IfFileExists "$2" FoundJvmDll StrCpy $2 "$1\bin\client\jvm.dll" IfFileExists "$2" FoundJvmDll StrCpy $2 "$1\bin\classic\jvm.dll" IfFileExists "$2" FoundJvmDll ;Step two: Is this a JDK path (Program Files\XXX\jre) StrCpy $1 "$JavaHome\jre" StrCpy $2 "$1\bin\hotspot\jvm.dll" IfFileExists "$2" FoundJvmDll StrCpy $2 "$1\bin\server\jvm.dll" IfFileExists "$2" FoundJvmDll StrCpy $2 "$1\bin\client\jvm.dll" IfFileExists "$2" FoundJvmDll StrCpy $2 "$1\bin\classic\jvm.dll" IfFileExists "$2" FoundJvmDll ClearErrors ;Step tree: Read defaults from registry ReadRegStr $1 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" "CurrentVersion" ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$1" "RuntimeLib" IfErrors 0 FoundJvmDll StrCpy $2 "" FoundJvmDll: ClearErrors ; Put the result in the stack Push $2 FunctionEnd ; ================== ; Configure Function ; ================== ; ; Writes server.xml and tomcat-users.xml ; Function configure ; Build final server.xml DetailPrint "Creating server.xml.new" FileOpen $R1 "$INSTDIR\conf\server.xml" r FileOpen $R2 "$INSTDIR\conf\server.xml.new" w SERVER_XML_LOOP: FileRead $R1 $R3 IfErrors SERVER_XML_LEAVELOOP ${StrRep} $R4 $R3 "8005" "$TomcatPortShutdown" ${StrRep} $R3 $R4 "8080" "$TomcatPortHttp" ${StrRep} $R4 $R3 "8009" "$TomcatPortAjp" FileWrite $R2 $R4 Goto SERVER_XML_LOOP SERVER_XML_LEAVELOOP: FileClose $R1 FileClose $R2 ; Replace server.xml with server.xml.new Delete "$INSTDIR\conf\server.xml" FileOpen $R9 "$INSTDIR\conf\server.xml" w Push "$INSTDIR\conf\server.xml.new" Call copyFile FileClose $R9 Delete "$INSTDIR\conf\server.xml.new" DetailPrint 'Server shutdown listener configured on port "$TomcatPortShutdown"' DetailPrint 'HTTP/1.1 Connector configured on port "$TomcatPortHttp"' DetailPrint 'AJP/1.3 Connector configured on port "$TomcatPortAjp"' DetailPrint "server.xml written" StrCpy $R5 '' ${If} $TomcatAdminEnable == "1" ${AndIf} "$TomcatAdminUsername" != "" ${AndIf} "$TomcatAdminPassword" != "" ${AndIf} "$TomcatAdminRoles" != "" ; Escape XML Push $TomcatAdminUsername Call xmlEscape Pop $R1 Push $TomcatAdminPassword Call xmlEscape Pop $R2 Push $TomcatAdminRoles Call xmlEscape Pop $R3 StrCpy $R5 '$\r$\n' DetailPrint 'Admin user added: "$TomcatAdminUsername"' ${EndIf} ; Extract these fragments to $PLUGINSDIR. That is a temporary directory, ; that is automatically deleted when the installer exits. InitPluginsDir SetOutPath $PLUGINSDIR File confinstall\tomcat-users_1.xml File confinstall\tomcat-users_2.xml ; Build final tomcat-users.xml Delete "$INSTDIR\conf\tomcat-users.xml" DetailPrint "Writing tomcat-users.xml" FileOpen $R9 "$INSTDIR\conf\tomcat-users.xml" w ; File will be written using current windows codepage System::Call 'Kernel32::GetACP() i .r18' ${If} $R8 == "932" ; Special case where Java uses non-standard name for character set FileWrite $R9 "$\r$\n" ${Else} FileWrite $R9 "$\r$\n" ${EndIf} Push "$PLUGINSDIR\tomcat-users_1.xml" Call copyFile FileWrite $R9 $R5 Push "$PLUGINSDIR\tomcat-users_2.xml" Call copyFile FileClose $R9 DetailPrint "tomcat-users.xml written" Delete "$PLUGINSDIR\tomcat-users_1.xml" Delete "$PLUGINSDIR\tomcat-users_2.xml" FunctionEnd Function xmlEscape Pop $0 ${StrRep} $0 $0 "&" "&" ${StrRep} $0 $0 "$\"" """ ${StrRep} $0 $0 "<" "<" ${StrRep} $0 $0 ">" ">" Push $0 FunctionEnd ; ================= ; CopyFile Function ; ================= ; ; Copy specified file contents to $R9 ; Function copyFile ClearErrors Pop $0 FileOpen $1 $0 r NoError: FileRead $1 $2 IfErrors EOF 0 FileWrite $R9 $2 IfErrors 0 NoError EOF: FileClose $1 ClearErrors FunctionEnd ; ================= ; createShortcuts Function ; ================= Function createShortcuts ${If} $TomcatShortcutAllUsers == ${BST_CHECKED} SetShellVarContext all ${EndIf} SetOutPath "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Tomcat Home Page.lnk" \ "http://tomcat.apache.org/" CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Welcome.lnk" \ "http://127.0.0.1:$TomcatPortHttp/" ${If} ${SectionIsSelected} ${SecManager} CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Tomcat Manager.lnk" \ "http://127.0.0.1:$TomcatPortHttp/manager/html" ${EndIf} ${If} ${SectionIsSelected} ${SecHostManager} CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Tomcat Host Manager.lnk" \ "http://127.0.0.1:$TomcatPortHttp/host-manager/html" ${EndIf} ${If} ${SectionIsSelected} ${SecDocs} CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Tomcat Documentation.lnk" \ "$INSTDIR\webapps\docs\index.html" ${EndIf} CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Uninstall Tomcat @VERSION_MAJOR_MINOR@.lnk" \ "$INSTDIR\Uninstall.exe" '-ServiceName="$TomcatServiceName"' CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Tomcat @VERSION_MAJOR_MINOR@ Program Directory.lnk" \ "$INSTDIR" CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Monitor Tomcat.lnk" \ "$INSTDIR\bin\$TomcatServiceManagerFileName" \ '//MS//$TomcatServiceName' \ "$INSTDIR\tomcat.ico" 0 SW_SHOWNORMAL CreateShortCut "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName\Configure Tomcat.lnk" \ "$INSTDIR\bin\$TomcatServiceManagerFileName" \ '//ES//$TomcatServiceName' \ "$INSTDIR\tomcat.ico" 0 SW_SHOWNORMAL ${If} $TomcatShortcutAllUsers == ${BST_CHECKED} SetShellVarContext current ${EndIf} FunctionEnd ; ================= ; startService Function ; ; Using a function allows the service name to be varied ; ================= Function startService ExecShell "" "$INSTDIR\bin\$TomcatServiceManagerFileName" "//MR//$TomcatServiceName" FunctionEnd ;-------------------------------- ;Uninstaller Section Section Uninstall ${If} $TomcatServiceName == "" MessageBox MB_ICONSTOP|MB_OK \ "No service name specified to uninstall. This will be provided automatically if you uninstall via \ Add/Remove Programs or the shortcut on the Start menu. Alternatively, call the installer from \ the command line with -ServiceName=$\"$\"." Quit ${EndIf} Delete "$INSTDIR\Uninstall.exe" ; Stop Tomcat service monitor if running DetailPrint "Stopping $TomcatServiceName service monitor" nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceManagerFileName" //MQ//$TomcatServiceName' ; Delete Tomcat service DetailPrint "Uninstalling $TomcatServiceName service" nsExec::ExecToLog '"$INSTDIR\bin\$TomcatServiceFileName" //DS//$TomcatServiceName' ClearErrors ; Don't know if 32-bit or 64-bit registry was used so, for now, remove both SetRegView 32 DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" DeleteRegKey HKLM "SOFTWARE\Apache Software Foundation\Tomcat\@VERSION_MAJOR_MINOR@\$TomcatServiceName" DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor@VERSION_MAJOR_MINOR@_$TomcatServiceName" DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor@VERSION_MAJOR_MINOR@_$TomcatServiceName" SetRegView 64 DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" DeleteRegKey HKLM "SOFTWARE\Apache Software Foundation\Tomcat\@VERSION_MAJOR_MINOR@\$TomcatServiceName" DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor@VERSION_MAJOR_MINOR@_$TomcatServiceName" DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor@VERSION_MAJOR_MINOR@_$TomcatServiceName" ; Don't know if short-cuts were created for all users, one user or not at all so, for now, remove both SetShellVarContext all RMDir /r "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" SetShellVarContext current RMDir /r "$SMPROGRAMS\Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName" Delete "$INSTDIR\tomcat.ico" Delete "$INSTDIR\LICENSE" Delete "$INSTDIR\NOTICE" RMDir /r "$INSTDIR\bin" RMDir /r "$INSTDIR\lib" Delete "$INSTDIR\conf\*.dtd" RMDir "$INSTDIR\logs" RMDir /r "$INSTDIR\webapps\docs" RMDir /r "$INSTDIR\webapps\examples" RMDir /r "$INSTDIR\work" RMDir /r "$INSTDIR\temp" RMDir "$INSTDIR" IfSilent Removed 0 ; if $INSTDIR was removed, skip these next ones IfFileExists "$INSTDIR" 0 Removed MessageBox MB_YESNO|MB_ICONQUESTION \ "Remove all files in your Apache Tomcat @VERSION_MAJOR_MINOR@ $TomcatServiceName directory? (If you have anything \ you created that you want to keep, click No)" IDNO Removed ; these would be skipped if the user hits no RMDir /r "$INSTDIR\webapps" RMDir /r "$INSTDIR\logs" RMDir /r "$INSTDIR\conf" Delete "$INSTDIR\*.*" RMDir /r "$INSTDIR" Sleep 500 IfFileExists "$INSTDIR" 0 Removed MessageBox MB_OK|MB_ICONEXCLAMATION \ "Note: $INSTDIR could not be removed." Removed: SectionEnd ; ================= ; uninstall init function ; ; Read the command line paramater and set up the service name variables so the ; uninstaller knows which service it is working with ; ================= Function un.onInit ${GetParameters} $R0 ${GetOptions} $R0 "-ServiceName=" $R1 StrCpy $TomcatServiceName $R1 StrCpy $TomcatServiceFileName $R1.exe StrCpy $TomcatServiceManagerFileName $R1w.exe FunctionEnd ;eof tomcat7-7.0.52/res/tomcat.ico0000644000175100017510000005217610455227353015740 0ustar locutuslocutus (hh&  v 00h"00.)007( xxxwwwxwxxxwxx( @qelnfsnnypqnyunq|nkd]W]XCJNVO<5*,|}~uz}ft~\mwYYY "$BBBBBBBBBBBBBBBBBBBBB -BB ,/4BB(=A '2:1BB?7379;8.%BB(38820BB >65!$BB ,!#BB@  !BB&,*&+BB= <BBBBBBBBBBBBBBBBBBBBB( @嘥diӐWN~tz~ "$nD,X\mw8J?*7]yI44A]qe򂜧ft~OVspnn㓙ݹmlpqn݉YYYdnkfyuj|qnvy{|}~( @xxwpxwxwwxxwwxwwwwwwwwxxwwwwwwxwwxxxwxwwxxxwwwwwwxwxx( @pciacijkdZ]UT^kqrpqrmnnnqqonmnl{~jjkeheQJBKGKOXZS0:;367+'".s|oygxgwS}^z]vRzUvSs{||qy~sssku{mptgqwjnranxbmtiiiccc]t~[ozXksVlxRhtUdiMbnZ_dLZbYYYQY^PWYUUUHX_FSZMMMCCC>DF<<<59:048+./|||||||||||||||||||||||||||||||||||||||||  RBCp||l=D b@G@U ||B= nn ]AKJP||>ad|Z f>HHG]||b<t|q ]X=KKNDo||V>Q u||c SX>HLEENAV|| D=mTWYk>=GNLKHHKGTm||mGMMGTLENHHHHK=g5b|| ^;LKGXGHHHHHK?e#6|| TDGIHHNHNLGh9||  xGG>L=F=DFmXn]s}m_lUdi[[[㓓Z_dSr9Rhtt`mXksl^t~kckgqwꌌpx}ZN]uc]qqhona^kzzze^ln_wlm^t~obn҉VVVXXXhfdhqkaqofm~tttKKKy|~e`ooohbcpncs{ٚrzeXdnijnXUTdjtzq{flemqllnlgmw}{lhhhó{{{h{49:<<EKB<<<38:47:012.23./0*,.'))&')"Wofdf~{f[]je@EA<@Ab U>Lu ^pQ;?EGGD:p} t;Lyj X}p>;GE?AAG;=Df x@@[osWTcqfS8;GE?AAAAAGGg| rBHp[>OO>rR;@BGED?AAAAAAGE=Rb mhSEEEEK[>FGGAAAAAAAAAG@by`XBGAAAERREAAAAAAAAAAD@zV yjUfBDADD8aDAAAAAAAAADLr1t j r(G8@@>>IZaRl{Pgu/23___L^hK''4TxsssQkz'KXa󰰰OPQNblJ#6SrSkzS\a___KOfr~~~HHHOOO===󔔔./0RjyB*&9FNT?GM3QVVV׉EJKSpE#*-4L[dPeq3:CH⢢\]^IY`Q='1J>5NbluuuR?CGKљ_abGSZRzG0'/-*KGU_27;EHIA>9=@___؟fff678GT]QD.'043.FK*K]g:AF9;Qm}NSULLLnnnyz{]^aHOTJZaSpPB.'043333)-HWa38<AKQ0*ERZQoQS{R|R@LRTvE>4.'*0133333.'KQwNcoHX_GX`Sr''''QoP"..433333333,9Nco9>CRafccc-125,533'TvTv'3333333333*;7?Dat}k[p8<@___tttJ\f3-4-*QOfr-333333333-?AKQn[ad[lGMO___CNSA/Q99J433333333-?6<@oZaddd[iKU[qqq@DH?GMGWa0.&343..4.'&2IXbr[cgaadk]eWadKKKbbbAMS9'MSr4'=N-FSwR|J\f49:j_fa{nl]s}q]f\pzTTTSSSAFKM_iN!N38DHoXakmENQccc~~~*,/QRn~=*ESu.23O[bknaq^r|on[oyndkke012}}}HV`'*'F=DGg[al?EG^t~llg:@Bp[_]]s}琐022L^hN*QpFNQkaaaeiad[kl[_igqqqUUUikkIOS-12ogakqfmpopaynnl_jTXZZZZ'))nq_plfP]dnmn]q{Wiqmnan389HHHyyyNNN<<mime-type open($mimetypes_fh, '<', $opt_m) or die "Could not open file '$opt_m' for read - Aborting!"; while (<$mimetypes_fh>) { chomp($_); $line = $_; $line =~ s/#.*//; $line =~ s/^\s+//; if ($line ne '') { ($mimetype, @extensions) = split(/\s+/, $line); if (@extensions > 0) { for $extension (@extensions) { $httpd{$extension} = $mimetype; } } else { print STDERR "WARN mime.types line ignored: $_\n"; } } } close($mimetypes_fh); # Read and parse web.xml, build up hash extension->mime-type # and store the file parts form before and after mime mappings. open($webxml_fh, '<', $opt_i) or die "Could not open file '$opt_i' for read - Aborting!"; # Skip and record all lines before the first mime type definition. # Because of comment handling we need to read one line ahead. $line = ''; while (<$webxml_fh>) { if ($_ !~ //) { $tomcat_pre .= $line; } else { last; } $line = $_; } $commented = 0; # If the previous line was start of a comment # set marker, else add it to pre. if ($line =~ /^\s*\s*$/) { $comment = $1; $_ = <$webxml_fh>; chomp($_); } if ($_ =~ /^\s*([^<]*)<\/extension>\s*$/ ) { $extension = $1; $extension =~ s/^\s+//; $extension =~ s/\s+$//; } else { print STDERR "ERROR Parse error in Tomcat mime-mapping line $.\n"; print STDERR "ERROR Expected ...', got '$_' - Aborting!\n"; close($webxml_fh); exit 2; } $_ = <$webxml_fh>; chomp($_); if ($_ =~ /^\s*([^<]*)<\/mime-type>\s*$/ ) { $type = $1; $type =~ s/^\s+//; $type =~ s/\s+$//; if (exists($tomcat{$extension}) && $tomcat{$extension} ne $type) { print STDERR "WARN MIME mapping redefinition detected!\n"; print STDERR "WARN Kept '$extension' -> '$tomcat{$extension}'\n"; print STDERR "WARN Ignored '$extension' -> '$type'\n"; } else { $tomcat{$extension} = $type; if ($comment ne '') { $tomcat_comments{$extension} = $comment; } if ($commented) { $tomcat_commented{$extension} = 1; } push(@tomcat_extensions, $extension); } } else { print STDERR "ERROR Parse error in Tomcat mime-mapping line $.\n"; print STDERR "ERROR Expected ...', got '$_' - Aborting!\n"; close($webxml_fh); exit 3; } $_ = <$webxml_fh>; chomp($_); if ($_ !~ /^\s*<\/mime-mapping>\s*$/) { print STDERR "ERROR Parse error in Tomcat mime-mapping line $.\n"; print STDERR "ERROR Expected '', got '$_' - Aborting!\n"; close($webxml_fh); exit 4; } $_ = <$webxml_fh>; # Check for comment closure if ($commented && $_ =~ /^[^<]*-->\s*$/) { $commented = 0; $_ = <$webxml_fh>; } # Check for comment opening if ($_ =~ /^\s*\n"; } print $output_fh " $extension\n"; print $output_fh " $httpd{$extension}\n"; print $output_fh " \n"; if (exists($tomcat_commented{$extension})) { print $output_fh " -->\n"; } } print $output_fh $tomcat_post; close($output_fh); print "New file '$opt_o' has been written.\n"; tomcat7-7.0.52/res/deployer/0000755000175100017510000000000012301126372015554 5ustar locutuslocutustomcat7-7.0.52/res/deployer/build.xml0000644000175100017510000001010212271302242017365 0ustar locutuslocutus tomcat7-7.0.52/res/rat/0000755000175100017510000000000012301126372014517 5ustar locutuslocutustomcat7-7.0.52/res/rat/rat-excludes.txt0000644000175100017510000000534411762206102017666 0ustar locutuslocutus Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. This is excludes file for Apache RAT tool run by ASF Buildbot, http://incubator.apache.org/rat/ The following files are excluded: - *.html files in documentation are generated from XML sources - *.md5 files are generated and cannot contain license - *.manifest JAR manifest files cannot contain license - package-list files in API documentation (javadoc) are generated - bug52121-part1, bug52121-part2 files in tests are test data for a hard to reproduce testcase and should be used as is. - other trivial test files, such as textual files containing only "OK' string, are also excluded. output/build/webapps/docs/*.html output/build/webapps/docs/appdev/*.html output/build/webapps/docs/architecture/*.html output/build/webapps/docs/config/*.html output/build/webapps/docs/funcspecs/*.html output/build/webapps/docs/tribes/*.html output/deployer/deployer-howto.html output/dist/webapps/docs/*.html output/dist/webapps/docs/appdev/*.html output/dist/webapps/docs/architecture/*.html output/dist/webapps/docs/config/*.html output/dist/webapps/docs/funcspecs/*.html output/dist/webapps/docs/tribes/*.html output/embed/*.md5 output/extras/*.md5 modules/jdbc-pool/resources/MANIFEST.MF output/dist/src/modules/jdbc-pool/resources/MANIFEST.MF output/dist/src/res/META-INF/*.manifest output/jdbc-pool/resources/MANIFEST.MF output/manifests/*.manifest res/META-INF/*.manifest output/dist/webapps/docs/api/package-list output/dist/webapps/docs/elapi/package-list output/dist/webapps/docs/jspapi/package-list output/dist/webapps/docs/servletapi/package-list output/dist/src/test/org/apache/coyote/http11/filters/bug52121-part1 output/dist/src/test/org/apache/coyote/http11/filters/bug52121-part2 output/dist/src/test/webapp-3.0/bug53257/*.txt output/dist/src/test/webapp-3.0-fragments/WEB-INF/classes/*.txt test/org/apache/coyote/http11/filters/bug52121-part1 test/org/apache/coyote/http11/filters/bug52121-part2 test/webapp-3.0/bug53257/*.txt test/webapp-3.0-fragments/WEB-INF/classes/*.txt tomcat7-7.0.52/res/confinstall/0000755000175100017510000000000012301126372016245 5ustar locutuslocutustomcat7-7.0.52/res/confinstall/tomcat-users_2.xml0000644000175100017510000000126012271302242021633 0ustar locutuslocutus tomcat7-7.0.52/res/confinstall/tomcat-users_1.xml0000644000175100017510000000144312271302242021635 0ustar locutuslocutus tomcat7-7.0.52/LICENSE0000644000175100017510000015675412271005702014166 0ustar locutuslocutus 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. APACHE TOMCAT SUBCOMPONENTS: Apache Tomcat includes a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the following licenses. For the ecj-x.x.x.jar component: Eclipse Public License - v 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and b) in the case of each subsequent Contributor: i) changes to the Program, and ii) additions to the Program; where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. "Contributor" means any person or entity that distributes the Program. "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: a) it complies with the terms and conditions of this Agreement; and b) its license agreement: i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. When the Program is made available in source code form: a) it must be made available under this Agreement; and b) a copy of this Agreement must be included with each copy of the Program. Contributors may not remove or alter any copyright notices contained within the Program. Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. For the Windows Installer component: * All NSIS source code, plug-ins, documentation, examples, header files and graphics, with the exception of the compression modules and where otherwise noted, are licensed under the zlib/libpng license. * The zlib compression module for NSIS is licensed under the zlib/libpng license. * The bzip2 compression module for NSIS is licensed under the bzip2 license. * The lzma compression module for NSIS is licensed under the Common Public License version 1.0. zlib/libpng license 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. bzip2 license 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. 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. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 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. Julian Seward, Cambridge, UK. jseward@acm.org Common Public License version 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and b) in the case of each subsequent Contributor: i) changes to the Program, and ii) additions to the Program; where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. "Contributor" means any person or entity that distributes the Program. "Licensed Patents " mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: a) it complies with the terms and conditions of this Agreement; and b) its license agreement: i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. When the Program is made available in source code form: a) it must be made available under this Agreement; and b) a copy of this Agreement must be included with each copy of the Program. Contributors may not remove or alter any copyright notices contained within the Program. Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed. In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. Special exception for LZMA compression module Igor Pavlov and Amir Szekely, the authors of the LZMA compression module for NSIS, expressly permit you to statically or dynamically link your code (or bind by name) to the files from the LZMA compression module for NSIS without subjecting your linked code to the terms of the Common Public license version 1.0. Any modifications or additions to files from the LZMA compression module for NSIS, however, are subject to the terms of the Common Public License version 1.0. For the following XML Schemas for Java EE Deployment Descriptors: - javaee_5.xsd - javaee_web_services_1_2.xsd - javaee_web_services_client_1_2.xsd - javaee_6.xsd - javaee_web_services_1_3.xsd - javaee_web_services_client_1_3.xsd - jsp_2_2.xsd - web-app_3_0.xsd - web-common_3_0.xsd - web-fragment_3_0.xsd COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 1. Definitions. 1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications. 1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor. 1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof. 1.4. Executable. means the Covered Software in any form other than Source Code. 1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License. 1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License. 1.7. License. means this document. 1.8. 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 the Source Code and Executable form of any of the following: A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications; B. Any new file that contains any part of the Original Software or previous Modification; or C. Any new file that is contributed or otherwise made available under the terms of this License. 1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License. 1.11. 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.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code. 1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. 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. License Grants. 2.1. The Initial Developer Grant. Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license: (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 Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof). (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party 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 Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices. 2.2. Contributor Grant. Conditioned upon Your compliance with Section 3.1 below and 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 Software 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 distributes or otherwise makes the Modifications available to a third party. (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) 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 (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Availability of Source Code. Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange. 3.2. Modifications. The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License. 3.3. Required Notices. You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer. 3.4. Application of Additional Terms. You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. 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 that 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.5. Distribution of Executable Versions. You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of 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 form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form 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 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.6. Larger Works. You may create a Larger Work by combining Covered Software 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 Software. 4. Versions of the License. 4.1. New Versions. Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License. 4.2. Effect of New Versions. You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward. 4.3. Modified Versions. When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License. 5. DISCLAIMER OF WARRANTY. COVERED SOFTWARE 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 SOFTWARE 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 SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE 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 SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 6. TERMINATION. 6.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. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant. 6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination. 7. 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 SOFTWARE, 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 LOST PROFITS, 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. 8. U.S. GOVERNMENT END USERS. The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. ? 252.227-7014(a)(1)) 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 Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License. 9. 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 the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction's conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, 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. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software. 10. 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. NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California. tomcat7-7.0.52/bin/0000755000175100017510000000000012301126373013711 5ustar locutuslocutustomcat7-7.0.52/bin/digest.sh0000755000175100017510000000365512271014356015543 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Script to digest password using the algorithm specified # ----------------------------------------------------------------------------- # Better OS/400 detection: see Bugzilla 31132 os400=false case "`uname`" in OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0" while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done PRGDIR=`dirname "$PRG"` EXECUTABLE=tool-wrapper.sh # Check that target executable exists if $os400; then # -x will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups eval else if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "The file is absent or does not have execute permission" echo "This file is needed to run this program" exit 1 fi fi exec "$PRGDIR"/"$EXECUTABLE" -server org.apache.catalina.realm.RealmBase "$@" tomcat7-7.0.52/bin/version.sh0000755000175100017510000000356412271014356015750 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Version Script for the CATALINA Server # ----------------------------------------------------------------------------- # Better OS/400 detection: see Bugzilla 31132 os400=false case "`uname`" in OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0" while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done PRGDIR=`dirname "$PRG"` EXECUTABLE=catalina.sh # Check that target executable exists if $os400; then # -x will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups eval else if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "The file is absent or does not have execute permission" echo "This file is needed to run this program" exit 1 fi fi exec "$PRGDIR"/"$EXECUTABLE" version "$@" tomcat7-7.0.52/bin/shutdown.bat0000755000175100017510000000370312271014356016265 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Stop script for the CATALINA Server rem --------------------------------------------------------------------------- rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%CURRENT_DIR%" if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome cd .. set "CATALINA_HOME=%cd%" cd "%CURRENT_DIR%" :gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat" rem Check that target executable exists if exist "%EXECUTABLE%" goto okExec echo Cannot find "%EXECUTABLE%" echo This file is needed to run this program goto end :okExec rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs call "%EXECUTABLE%" stop %CMD_LINE_ARGS% :end tomcat7-7.0.52/bin/catalina.bat0000755000175100017510000003102412271014356016163 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Start/Stop Script for the CATALINA Server rem rem Environment Variable Prerequisites rem rem Do not set the variables in this script. Instead put them into a script rem setenv.bat in CATALINA_BASE/bin to keep your customizations separate. rem rem CATALINA_HOME May point at your Catalina "build" directory. rem rem CATALINA_BASE (Optional) Base directory for resolving dynamic portions rem of a Catalina installation. If not present, resolves to rem the same directory that CATALINA_HOME points to. rem rem CATALINA_OPTS (Optional) Java runtime options used when the "start", rem "run" or "debug" command is executed. rem Include here and not in JAVA_OPTS all options, that should rem only be used by Tomcat itself, not by the stop process, rem the version command etc. rem Examples are heap size, GC logging, JMX ports etc. rem rem CATALINA_TMPDIR (Optional) Directory path location of temporary directory rem the JVM should use (java.io.tmpdir). Defaults to rem %CATALINA_BASE%\temp. rem rem JAVA_HOME Must point at your Java Development Kit installation. rem Required to run the with the "debug" argument. rem rem JRE_HOME Must point at your Java Runtime installation. rem Defaults to JAVA_HOME if empty. If JRE_HOME and JAVA_HOME rem are both set, JRE_HOME is used. rem rem JAVA_OPTS (Optional) Java runtime options used when any command rem is executed. rem Include here and not in CATALINA_OPTS all options, that rem should be used by Tomcat and also by the stop process, rem the version command etc. rem Most options should go into CATALINA_OPTS. rem rem JAVA_ENDORSED_DIRS (Optional) Lists of of semi-colon separated directories rem containing some jars in order to allow replacement of APIs rem created outside of the JCP (i.e. DOM and SAX from W3C). rem It can also be used to update the XML parser implementation. rem Defaults to $CATALINA_HOME/endorsed. rem rem JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start" rem command is executed. The default is "dt_socket". rem rem JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start" rem command is executed. The default is 8000. rem rem JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start" rem command is executed. Specifies whether JVM should suspend rem execution immediately after startup. Default is "n". rem rem JPDA_OPTS (Optional) Java runtime options used when the "jpda start" rem command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS, rem and JPDA_SUSPEND are ignored. Thus, all required jpda rem options MUST be specified. The default is: rem rem -agentlib:jdwp=transport=%JPDA_TRANSPORT%, rem address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND% rem rem LOGGING_CONFIG (Optional) Override Tomcat's logging config file rem Example (all one line) rem set LOGGING_CONFIG="-Djava.util.logging.config.file=%CATALINA_BASE%\conf\logging.properties" rem rem LOGGING_MANAGER (Optional) Override Tomcat's logging manager rem Example (all one line) rem set LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" rem rem TITLE (Optional) Specify the title of Tomcat window. The default rem TITLE is Tomcat if it's not specified. rem Example (all one line) rem set TITLE=Tomcat.Cluster#1.Server#1 [%DATE% %TIME%] rem --------------------------------------------------------------------------- rem Suppress Terminate batch job on CTRL+C if not ""%1"" == ""run"" goto mainEntry if "%TEMP%" == "" goto mainEntry if exist "%TEMP%\%~nx0.run" goto mainEntry echo Y>"%TEMP%\%~nx0.run" if not exist "%TEMP%\%~nx0.run" goto mainEntry echo Y>"%TEMP%\%~nx0.Y" call "%~f0" %* <"%TEMP%\%~nx0.Y" rem Use provided errorlevel set RETVAL=%ERRORLEVEL% del /Q "%TEMP%\%~nx0.Y" >NUL 2>&1 exit /B %RETVAL% :mainEntry del /Q "%TEMP%\%~nx0.run" >NUL 2>&1 rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%CURRENT_DIR%" if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome cd .. set "CATALINA_HOME=%cd%" cd "%CURRENT_DIR%" :gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome rem Copy CATALINA_BASE from CATALINA_HOME if not defined if not "%CATALINA_BASE%" == "" goto gotBase set "CATALINA_BASE=%CATALINA_HOME%" :gotBase rem Ensure that any user defined CLASSPATH variables are not used on startup, rem but allow them to be specified in setenv.bat, in rare case when it is needed. set CLASSPATH= rem Get standard environment variables if not exist "%CATALINA_BASE%\bin\setenv.bat" goto checkSetenvHome call "%CATALINA_BASE%\bin\setenv.bat" goto setenvDone :checkSetenvHome if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat" :setenvDone rem Get standard Java environment variables if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath echo Cannot find "%CATALINA_HOME%\bin\setclasspath.bat" echo This file is needed to run this program goto end :okSetclasspath call "%CATALINA_HOME%\bin\setclasspath.bat" %1 if errorlevel 1 goto end rem Add on extra jar file to CLASSPATH rem Note that there are no quotes as we do not want to introduce random rem quotes into the CLASSPATH if "%CLASSPATH%" == "" goto emptyClasspath set "CLASSPATH=%CLASSPATH%;" :emptyClasspath set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar" if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir set "CATALINA_TMPDIR=%CATALINA_BASE%\temp" :gotTmpdir rem Add tomcat-juli.jar to classpath rem tomcat-juli.jar can be over-ridden per instance if not exist "%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathHome set "CLASSPATH=%CLASSPATH%;%CATALINA_BASE%\bin\tomcat-juli.jar" goto juliClasspathDone :juliClasspathHome set "CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\tomcat-juli.jar" :juliClasspathDone if not "%LOGGING_CONFIG%" == "" goto noJuliConfig set LOGGING_CONFIG=-Dnop if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuliConfig set LOGGING_CONFIG=-Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties" :noJuliConfig set JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG% if not "%LOGGING_MANAGER%" == "" goto noJuliManager set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager :noJuliManager set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER% rem ----- Execute The Requested Command --------------------------------------- echo Using CATALINA_BASE: "%CATALINA_BASE%" echo Using CATALINA_HOME: "%CATALINA_HOME%" echo Using CATALINA_TMPDIR: "%CATALINA_TMPDIR%" if ""%1"" == ""debug"" goto use_jdk echo Using JRE_HOME: "%JRE_HOME%" goto java_dir_displayed :use_jdk echo Using JAVA_HOME: "%JAVA_HOME%" :java_dir_displayed echo Using CLASSPATH: "%CLASSPATH%" set _EXECJAVA=%_RUNJAVA% set MAINCLASS=org.apache.catalina.startup.Bootstrap set ACTION=start set SECURITY_POLICY_FILE= set DEBUG_OPTS= set JPDA= if not ""%1"" == ""jpda"" goto noJpda set JPDA=jpda if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport set JPDA_TRANSPORT=dt_socket :gotJpdaTransport if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress set JPDA_ADDRESS=8000 :gotJpdaAddress if not "%JPDA_SUSPEND%" == "" goto gotJpdaSuspend set JPDA_SUSPEND=n :gotJpdaSuspend if not "%JPDA_OPTS%" == "" goto gotJpdaOpts set JPDA_OPTS=-agentlib:jdwp=transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=%JPDA_SUSPEND% :gotJpdaOpts shift :noJpda if ""%1"" == ""debug"" goto doDebug if ""%1"" == ""run"" goto doRun if ""%1"" == ""start"" goto doStart if ""%1"" == ""stop"" goto doStop if ""%1"" == ""configtest"" goto doConfigTest if ""%1"" == ""version"" goto doVersion echo Usage: catalina ( commands ... ) echo commands: echo debug Start Catalina in a debugger echo debug -security Debug Catalina with a security manager echo jpda start Start Catalina under JPDA debugger echo run Start Catalina in the current window echo run -security Start in the current window with security manager echo start Start Catalina in a separate window echo start -security Start in a separate window with security manager echo stop Stop Catalina echo configtest Run a basic syntax check on server.xml echo version What version of tomcat are you running? goto end :doDebug shift set _EXECJAVA=%_RUNJDB% set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\java" if not ""%1"" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd :doRun shift if not ""%1"" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd :doStart shift if not "%OS%" == "Windows_NT" goto noTitle if "%TITLE%" == "" set TITLE=Tomcat set _EXECJAVA=start "%TITLE%" %_RUNJAVA% goto gotTitle :noTitle set _EXECJAVA=start %_RUNJAVA% :gotTitle if not ""%1"" == ""-security"" goto execCmd shift echo Using Security Manager set "SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy" goto execCmd :doStop shift set ACTION=stop set CATALINA_OPTS= goto execCmd :doConfigTest shift set ACTION=configtest set CATALINA_OPTS= goto execCmd :doVersion %_EXECJAVA% -classpath "%CATALINA_HOME%\lib\catalina.jar" org.apache.catalina.util.ServerInfo goto end :execCmd rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs rem Execute Java with the applicable properties if not "%JPDA%" == "" goto doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurity %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doJpda if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :doSecurityJpda %_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %JPDA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% goto end :end tomcat7-7.0.52/bin/digest.bat0000755000175100017510000000401212271014356015663 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Script to digest password using the algorithm specified rem --------------------------------------------------------------------------- rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%CURRENT_DIR%" if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome cd .. set "CATALINA_HOME=%cd%" cd "%CURRENT_DIR%" :gotHome if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome set "EXECUTABLE=%CATALINA_HOME%\bin\tool-wrapper.bat" rem Check that target executable exists if exist "%EXECUTABLE%" goto okExec echo Cannot find "%EXECUTABLE%" echo This file is needed to run this program goto end :okExec rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs call "%EXECUTABLE%" -server org.apache.catalina.realm.RealmBase %CMD_LINE_ARGS% :end tomcat7-7.0.52/bin/version.bat0000755000175100017510000000371112271014356016076 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Version script for the CATALINA Server rem --------------------------------------------------------------------------- rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%CURRENT_DIR%" if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome cd .. set "CATALINA_HOME=%cd%" cd "%CURRENT_DIR%" :gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat" rem Check that target executable exists if exist "%EXECUTABLE%" goto okExec echo Cannot find "%EXECUTABLE%" echo This file is needed to run this program goto end :okExec rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs call "%EXECUTABLE%" version %CMD_LINE_ARGS% :end tomcat7-7.0.52/bin/configtest.bat0000755000175100017510000000372712271014356016565 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Configuration test script for the CATALINA Server rem --------------------------------------------------------------------------- rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%CURRENT_DIR%" if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome cd .. set "CATALINA_HOME=%cd%" cd "%CURRENT_DIR%" :gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat" rem Check that target executable exists if exist "%EXECUTABLE%" goto okExec echo Cannot find "%EXECUTABLE%" echo This file is needed to run this program goto end :okExec rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs call "%EXECUTABLE%" configtest %CMD_LINE_ARGS% :end tomcat7-7.0.52/bin/catalina-tasks.xml0000644000175100017510000000411112271014356017332 0ustar locutuslocutus Catalina Ant Manager, JMX and JSPC Tasks tomcat7-7.0.52/bin/setclasspath.sh0000755000175100017510000000660312271014356016756 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Set JAVA_HOME or JRE_HOME if not already set, ensure any provided settings # are valid and consistent with the selected start-up options and set up the # endorsed directory. # ----------------------------------------------------------------------------- # Make sure prerequisite environment variables are set if [ -z "$JAVA_HOME" -a -z "$JRE_HOME" ]; then if $darwin; then # Bugzilla 54390 if [ -x '/usr/libexec/java_home' ] ; then export JAVA_HOME=`/usr/libexec/java_home` # Bugzilla 37284 (reviewed). elif [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" ]; then export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" fi else JAVA_PATH=`which java 2>/dev/null` if [ "x$JAVA_PATH" != "x" ]; then JAVA_PATH=`dirname $JAVA_PATH 2>/dev/null` JRE_HOME=`dirname $JAVA_PATH 2>/dev/null` fi if [ "x$JRE_HOME" = "x" ]; then # XXX: Should we try other locations? if [ -x /usr/bin/java ]; then JRE_HOME=/usr fi fi fi if [ -z "$JAVA_HOME" -a -z "$JRE_HOME" ]; then echo "Neither the JAVA_HOME nor the JRE_HOME environment variable is defined" echo "At least one of these environment variable is needed to run this program" exit 1 fi fi if [ -z "$JAVA_HOME" -a "$1" = "debug" ]; then echo "JAVA_HOME should point to a JDK in order to run in debug mode." exit 1 fi if [ -z "$JRE_HOME" ]; then JRE_HOME="$JAVA_HOME" fi # If we're running under jdb, we need a full jdk. if [ "$1" = "debug" ] ; then if [ "$os400" = "true" ]; then if [ ! -x "$JAVA_HOME"/bin/java -o ! -x "$JAVA_HOME"/bin/javac ]; then echo "The JAVA_HOME environment variable is not defined correctly" echo "This environment variable is needed to run this program" echo "NB: JAVA_HOME should point to a JDK not a JRE" exit 1 fi else if [ ! -x "$JAVA_HOME"/bin/java -o ! -x "$JAVA_HOME"/bin/jdb -o ! -x "$JAVA_HOME"/bin/javac ]; then echo "The JAVA_HOME environment variable is not defined correctly" echo "This environment variable is needed to run this program" echo "NB: JAVA_HOME should point to a JDK not a JRE" exit 1 fi fi fi # Don't override the endorsed dir if the user has set it previously if [ -z "$JAVA_ENDORSED_DIRS" ]; then # Set the default -Djava.endorsed.dirs argument JAVA_ENDORSED_DIRS="$CATALINA_HOME"/endorsed fi # Set standard commands for invoking Java. _RUNJAVA="$JRE_HOME"/bin/java if [ "$os400" != "true" ]; then _RUNJDB="$JAVA_HOME"/bin/jdb fi tomcat7-7.0.52/bin/startup.sh0000755000175100017510000000356012271014356015761 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Start Script for the CATALINA Server # ----------------------------------------------------------------------------- # Better OS/400 detection: see Bugzilla 31132 os400=false case "`uname`" in OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0" while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done PRGDIR=`dirname "$PRG"` EXECUTABLE=catalina.sh # Check that target executable exists if $os400; then # -x will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups eval else if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "The file is absent or does not have execute permission" echo "This file is needed to run this program" exit 1 fi fi exec "$PRGDIR"/"$EXECUTABLE" start "$@" tomcat7-7.0.52/bin/shutdown.sh0000755000175100017510000000355612271014356016137 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Stop script for the CATALINA Server # ----------------------------------------------------------------------------- # Better OS/400 detection: see Bugzilla 31132 os400=false case "`uname`" in OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0" while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done PRGDIR=`dirname "$PRG"` EXECUTABLE=catalina.sh # Check that target executable exists if $os400; then # -x will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups eval else if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "The file is absent or does not have execute permission" echo "This file is needed to run this program" exit 1 fi fi exec "$PRGDIR"/"$EXECUTABLE" stop "$@" tomcat7-7.0.52/bin/service.bat0000755000175100017510000001371212276750205016060 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem NT Service Install/Uninstall script rem rem Options rem install Install the service using Tomcat@VERSION_MAJOR@ as service name. rem Service is installed using default settings. rem remove Remove the service from the System. rem rem name (optional) If the second argument is present it is considered rem to be new service name rem --------------------------------------------------------------------------- set "SELF=%~dp0%service.bat" rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%cd%" if exist "%CATALINA_HOME%\bin\tomcat@VERSION_MAJOR@.exe" goto okHome rem CD to the upper dir cd .. set "CATALINA_HOME=%cd%" :gotHome if exist "%CATALINA_HOME%\bin\tomcat@VERSION_MAJOR@.exe" goto okHome echo The tomcat@VERSION_MAJOR@.exe was not found... echo The CATALINA_HOME environment variable is not defined correctly. echo This environment variable is needed to run this program goto end :okHome rem Make sure prerequisite environment variables are set if not "%JAVA_HOME%" == "" goto gotJdkHome if not "%JRE_HOME%" == "" goto gotJreHome echo Neither the JAVA_HOME nor the JRE_HOME environment variable is defined echo Service will try to guess them from the registry. goto okJavaHome :gotJreHome if not exist "%JRE_HOME%\bin\java.exe" goto noJavaHome if not exist "%JRE_HOME%\bin\javaw.exe" goto noJavaHome goto okJavaHome :gotJdkHome if not exist "%JAVA_HOME%\jre\bin\java.exe" goto noJavaHome if not exist "%JAVA_HOME%\jre\bin\javaw.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\javac.exe" goto noJavaHome if not "%JRE_HOME%" == "" goto okJavaHome set "JRE_HOME=%JAVA_HOME%\jre" goto okJavaHome :noJavaHome echo The JAVA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program echo NB: JAVA_HOME should point to a JDK not a JRE goto end :okJavaHome if not "%CATALINA_BASE%" == "" goto gotBase set "CATALINA_BASE=%CATALINA_HOME%" :gotBase set "EXECUTABLE=%CATALINA_HOME%\bin\tomcat@VERSION_MAJOR@.exe" rem Set default Service name set SERVICE_NAME=Tomcat@VERSION_MAJOR@ set PR_DISPLAYNAME=Apache Tomcat @VERSION_MAJOR@ if "x%1x" == "xx" goto displayUsage set SERVICE_CMD=%1 shift if "x%1x" == "xx" goto checkServiceCmd :checkUser if "x%1x" == "x/userx" goto runAsUser if "x%1x" == "x--userx" goto runAsUser set SERVICE_NAME=%1 set PR_DISPLAYNAME=Apache Tomcat %1 shift if "x%1x" == "xx" goto checkServiceCmd goto checkUser :runAsUser shift if "x%1x" == "xx" goto displayUsage set SERVICE_USER=%1 shift runas /env /savecred /user:%SERVICE_USER% "%COMSPEC% /K \"%SELF%\" %SERVICE_CMD% %SERVICE_NAME%" goto end :checkServiceCmd if /i %SERVICE_CMD% == install goto doInstall if /i %SERVICE_CMD% == remove goto doRemove if /i %SERVICE_CMD% == uninstall goto doRemove echo Unknown parameter "%1" :displayUsage echo. echo Usage: service.bat install/remove [service_name] [/user username] goto end :doRemove rem Remove the service "%EXECUTABLE%" //DS//%SERVICE_NAME% if not errorlevel 1 goto removed echo Failed removing '%SERVICE_NAME%' service goto end :removed echo The service '%SERVICE_NAME%' has been removed goto end :doInstall rem Install the service echo Installing the service '%SERVICE_NAME%' ... echo Using CATALINA_HOME: "%CATALINA_HOME%" echo Using CATALINA_BASE: "%CATALINA_BASE%" echo Using JAVA_HOME: "%JAVA_HOME%" echo Using JRE_HOME: "%JRE_HOME%" rem Use the environment variables as an example rem Each command line option is prefixed with PR_ set PR_DESCRIPTION=Apache Tomcat @VERSION@ Server - http://tomcat.apache.org/ set "PR_INSTALL=%EXECUTABLE%" set "PR_LOGPATH=%CATALINA_BASE%\logs" set "PR_CLASSPATH=%CATALINA_HOME%\bin\bootstrap.jar;%CATALINA_BASE%\bin\tomcat-juli.jar;%CATALINA_HOME%\bin\tomcat-juli.jar" rem Set the server jvm from JAVA_HOME set "PR_JVM=%JRE_HOME%\bin\server\jvm.dll" if exist "%PR_JVM%" goto foundJvm rem Set the client jvm from JAVA_HOME set "PR_JVM=%JRE_HOME%\bin\client\jvm.dll" if exist "%PR_JVM%" goto foundJvm set PR_JVM=auto set PR_STDOUTPUT=auto set PR_STDERROR=auto :foundJvm echo Using JVM: "%PR_JVM%" "%EXECUTABLE%" //IS//%SERVICE_NAME% ^ --StartClass org.apache.catalina.startup.Bootstrap ^ --StopClass org.apache.catalina.startup.Bootstrap ^ --StartParams start ^ --StopParams stop ^ --JvmOptions "-Dcatalina.base=%CATALINA_BASE%;-Dcatalina.home=%CATALINA_HOME%;-Djava.endorsed.dirs=%CATALINA_HOME%\endorsed;-Djava.io.tmpdir=%CATALINA_BASE%\temp;-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager;-Djava.util.logging.config.file=%CATALINA_BASE%\conf\logging.properties" ^ --StartMode jvm ^ --StopMode jvm ^ --JvmMs 128 ^ --JvmMx 256 if not errorlevel 1 goto installed echo Failed installing '%SERVICE_NAME%' service goto end :installed rem Clear the environment variables. They are not needed any more. set PR_DISPLAYNAME= set PR_DESCRIPTION= set PR_INSTALL= set PR_LOGPATH= set PR_CLASSPATH= set PR_JVM= echo The service '%SERVICE_NAME%' has been installed. :end cd "%CURRENT_DIR%" tomcat7-7.0.52/bin/catalina.sh0000755000175100017510000005045312271014356016036 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Control Script for the CATALINA Server # # Environment Variable Prerequisites # # Do not set the variables in this script. Instead put them into a script # setenv.sh in CATALINA_BASE/bin to keep your customizations separate. # # CATALINA_HOME May point at your Catalina "build" directory. # # CATALINA_BASE (Optional) Base directory for resolving dynamic portions # of a Catalina installation. If not present, resolves to # the same directory that CATALINA_HOME points to. # # CATALINA_OUT (Optional) Full path to a file where stdout and stderr # will be redirected. # Default is $CATALINA_BASE/logs/catalina.out # # CATALINA_OPTS (Optional) Java runtime options used when the "start", # "run" or "debug" command is executed. # Include here and not in JAVA_OPTS all options, that should # only be used by Tomcat itself, not by the stop process, # the version command etc. # Examples are heap size, GC logging, JMX ports etc. # # CATALINA_TMPDIR (Optional) Directory path location of temporary directory # the JVM should use (java.io.tmpdir). Defaults to # $CATALINA_BASE/temp. # # JAVA_HOME Must point at your Java Development Kit installation. # Required to run the with the "debug" argument. # # JRE_HOME Must point at your Java Runtime installation. # Defaults to JAVA_HOME if empty. If JRE_HOME and JAVA_HOME # are both set, JRE_HOME is used. # # JAVA_OPTS (Optional) Java runtime options used when any command # is executed. # Include here and not in CATALINA_OPTS all options, that # should be used by Tomcat and also by the stop process, # the version command etc. # Most options should go into CATALINA_OPTS. # # JAVA_ENDORSED_DIRS (Optional) Lists of of colon separated directories # containing some jars in order to allow replacement of APIs # created outside of the JCP (i.e. DOM and SAX from W3C). # It can also be used to update the XML parser implementation. # Defaults to $CATALINA_HOME/endorsed. # # JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start" # command is executed. The default is "dt_socket". # # JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start" # command is executed. The default is 8000. # # JPDA_SUSPEND (Optional) Java runtime options used when the "jpda start" # command is executed. Specifies whether JVM should suspend # execution immediately after startup. Default is "n". # # JPDA_OPTS (Optional) Java runtime options used when the "jpda start" # command is executed. If used, JPDA_TRANSPORT, JPDA_ADDRESS, # and JPDA_SUSPEND are ignored. Thus, all required jpda # options MUST be specified. The default is: # # -agentlib:jdwp=transport=$JPDA_TRANSPORT, # address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND # # CATALINA_PID (Optional) Path of the file which should contains the pid # of the catalina startup java process, when start (fork) is # used # # LOGGING_CONFIG (Optional) Override Tomcat's logging config file # Example (all one line) # LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties" # # LOGGING_MANAGER (Optional) Override Tomcat's logging manager # Example (all one line) # LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" # ----------------------------------------------------------------------------- # OS specific support. $var _must_ be set to either true or false. cygwin=false darwin=false os400=false case "`uname`" in CYGWIN*) cygwin=true;; Darwin*) darwin=true;; OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0" while [ -h "$PRG" ]; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done # Get standard environment variables PRGDIR=`dirname "$PRG"` # Only set CATALINA_HOME if not already set [ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." >/dev/null; pwd` # Copy CATALINA_BASE from CATALINA_HOME if not already set [ -z "$CATALINA_BASE" ] && CATALINA_BASE="$CATALINA_HOME" # Ensure that any user defined CLASSPATH variables are not used on startup, # but allow them to be specified in setenv.sh, in rare case when it is needed. CLASSPATH= if [ -r "$CATALINA_BASE/bin/setenv.sh" ]; then . "$CATALINA_BASE/bin/setenv.sh" elif [ -r "$CATALINA_HOME/bin/setenv.sh" ]; then . "$CATALINA_HOME/bin/setenv.sh" fi # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin; then [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` [ -n "$JRE_HOME" ] && JRE_HOME=`cygpath --unix "$JRE_HOME"` [ -n "$CATALINA_HOME" ] && CATALINA_HOME=`cygpath --unix "$CATALINA_HOME"` [ -n "$CATALINA_BASE" ] && CATALINA_BASE=`cygpath --unix "$CATALINA_BASE"` [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` fi # For OS400 if $os400; then # Set job priority to standard for interactive (interactive - 6) by using # the interactive priority - 6, the helper threads that respond to requests # will be running at the same priority as interactive jobs. COMMAND='chgjob job('$JOBNAME') runpty(6)' system $COMMAND # Enable multi threading export QIBM_MULTI_THREADED=Y fi # Get standard Java environment variables if $os400; then # -r will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups . "$CATALINA_HOME"/bin/setclasspath.sh else if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then . "$CATALINA_HOME"/bin/setclasspath.sh else echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh" echo "This file is needed to run this program" exit 1 fi fi # Add on extra jar files to CLASSPATH if [ ! -z "$CLASSPATH" ] ; then CLASSPATH="$CLASSPATH": fi CLASSPATH="$CLASSPATH""$CATALINA_HOME"/bin/bootstrap.jar if [ -z "$CATALINA_OUT" ] ; then CATALINA_OUT="$CATALINA_BASE"/logs/catalina.out fi if [ -z "$CATALINA_TMPDIR" ] ; then # Define the java.io.tmpdir to use for Catalina CATALINA_TMPDIR="$CATALINA_BASE"/temp fi # Add tomcat-juli.jar to classpath # tomcat-juli.jar can be over-ridden per instance if [ -r "$CATALINA_BASE/bin/tomcat-juli.jar" ] ; then CLASSPATH=$CLASSPATH:$CATALINA_BASE/bin/tomcat-juli.jar else CLASSPATH=$CLASSPATH:$CATALINA_HOME/bin/tomcat-juli.jar fi # Bugzilla 37848: When no TTY is available, don't output to console have_tty=0 if [ "`tty`" != "not a tty" ]; then have_tty=1 fi # For Cygwin, switch paths to Windows format before running java if $cygwin; then JAVA_HOME=`cygpath --absolute --windows "$JAVA_HOME"` JRE_HOME=`cygpath --absolute --windows "$JRE_HOME"` CATALINA_HOME=`cygpath --absolute --windows "$CATALINA_HOME"` CATALINA_BASE=`cygpath --absolute --windows "$CATALINA_BASE"` CATALINA_TMPDIR=`cygpath --absolute --windows "$CATALINA_TMPDIR"` CLASSPATH=`cygpath --path --windows "$CLASSPATH"` JAVA_ENDORSED_DIRS=`cygpath --path --windows "$JAVA_ENDORSED_DIRS"` fi # Set juli LogManager config file if it is present and an override has not been issued if [ -z "$LOGGING_CONFIG" ]; then if [ -r "$CATALINA_BASE"/conf/logging.properties ]; then LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties" else # Bugzilla 45585 LOGGING_CONFIG="-Dnop" fi fi if [ -z "$LOGGING_MANAGER" ]; then LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" fi # Uncomment the following line to make the umask available when using the # org.apache.catalina.security.SecurityListener #JAVA_OPTS="$JAVA_OPTS -Dorg.apache.catalina.security.SecurityListener.UMASK=`umask`" # ----- Execute The Requested Command ----------------------------------------- # Bugzilla 37848: only output this if we have a TTY if [ $have_tty -eq 1 ]; then echo "Using CATALINA_BASE: $CATALINA_BASE" echo "Using CATALINA_HOME: $CATALINA_HOME" echo "Using CATALINA_TMPDIR: $CATALINA_TMPDIR" if [ "$1" = "debug" ] ; then echo "Using JAVA_HOME: $JAVA_HOME" else echo "Using JRE_HOME: $JRE_HOME" fi echo "Using CLASSPATH: $CLASSPATH" if [ ! -z "$CATALINA_PID" ]; then echo "Using CATALINA_PID: $CATALINA_PID" fi fi if [ "$1" = "jpda" ] ; then if [ -z "$JPDA_TRANSPORT" ]; then JPDA_TRANSPORT="dt_socket" fi if [ -z "$JPDA_ADDRESS" ]; then JPDA_ADDRESS="8000" fi if [ -z "$JPDA_SUSPEND" ]; then JPDA_SUSPEND="n" fi if [ -z "$JPDA_OPTS" ]; then JPDA_OPTS="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND" fi CATALINA_OPTS="$CATALINA_OPTS $JPDA_OPTS" shift fi if [ "$1" = "debug" ] ; then if $os400; then echo "Debug command not available on OS400" exit 1 else shift if [ "$1" = "-security" ] ; then if [ $have_tty -eq 1 ]; then echo "Using Security Manager" fi shift exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ -sourcepath "$CATALINA_HOME"/../../java \ -Djava.security.manager \ -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMPDIR" \ org.apache.catalina.startup.Bootstrap "$@" start else exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ -sourcepath "$CATALINA_HOME"/../../java \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMPDIR" \ org.apache.catalina.startup.Bootstrap "$@" start fi fi elif [ "$1" = "run" ]; then shift if [ "$1" = "-security" ] ; then if [ $have_tty -eq 1 ]; then echo "Using Security Manager" fi shift eval exec "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ -Djava.security.manager \ -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap "$@" start else eval exec "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap "$@" start fi elif [ "$1" = "start" ] ; then if [ ! -z "$CATALINA_PID" ]; then if [ -f "$CATALINA_PID" ]; then if [ -s "$CATALINA_PID" ]; then echo "Existing PID file found during start." if [ -r "$CATALINA_PID" ]; then PID=`cat "$CATALINA_PID"` ps -p $PID >/dev/null 2>&1 if [ $? -eq 0 ] ; then echo "Tomcat appears to still be running with PID $PID. Start aborted." exit 1 else echo "Removing/clearing stale PID file." rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then if [ -w "$CATALINA_PID" ]; then cat /dev/null > "$CATALINA_PID" else echo "Unable to remove or clear stale PID file. Start aborted." exit 1 fi fi fi else echo "Unable to read PID file. Start aborted." exit 1 fi else rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then if [ ! -w "$CATALINA_PID" ]; then echo "Unable to remove or write to empty PID file. Start aborted." exit 1 fi fi fi fi fi shift touch "$CATALINA_OUT" if [ "$1" = "-security" ] ; then if [ $have_tty -eq 1 ]; then echo "Using Security Manager" fi shift eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ -Djava.security.manager \ -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap "$@" start \ >> "$CATALINA_OUT" 2>&1 "&" else eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap "$@" start \ >> "$CATALINA_OUT" 2>&1 "&" fi if [ ! -z "$CATALINA_PID" ]; then echo $! > "$CATALINA_PID" fi echo "Tomcat started." elif [ "$1" = "stop" ] ; then shift SLEEP=5 if [ ! -z "$1" ]; then echo $1 | grep "[^0-9]" >/dev/null 2>&1 if [ $? -gt 0 ]; then SLEEP=$1 shift fi fi FORCE=0 if [ "$1" = "-force" ]; then shift FORCE=1 fi if [ ! -z "$CATALINA_PID" ]; then if [ -f "$CATALINA_PID" ]; then if [ -s "$CATALINA_PID" ]; then kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 if [ $? -gt 0 ]; then echo "PID file found but no matching process was found. Stop aborted." exit 1 fi else echo "PID file is empty and has been ignored." fi else echo "\$CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted." exit 1 fi fi eval "\"$_RUNJAVA\"" $LOGGING_MANAGER $JAVA_OPTS \ -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap "$@" stop # stop failed. Shutdown port disabled? Try a normal kill. if [ $? != 0 ]; then if [ ! -z "$CATALINA_PID" ]; then echo "The stop command failed. Attempting to signal the process to stop through OS signal." kill -15 `cat "$CATALINA_PID"` >/dev/null 2>&1 fi fi if [ ! -z "$CATALINA_PID" ]; then if [ -f "$CATALINA_PID" ]; then while [ $SLEEP -ge 0 ]; do kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 if [ $? -gt 0 ]; then rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then if [ -w "$CATALINA_PID" ]; then cat /dev/null > "$CATALINA_PID" # If Tomcat has stopped don't try and force a stop with an empty PID file FORCE=0 else echo "The PID file could not be removed or cleared." fi fi echo "Tomcat stopped." break fi if [ $SLEEP -gt 0 ]; then sleep 1 fi if [ $SLEEP -eq 0 ]; then if [ $FORCE -eq 0 ]; then echo "Tomcat did not stop in time. PID file was not removed. To aid diagnostics a thread dump has been written to standard out." kill -3 `cat "$CATALINA_PID"` fi fi SLEEP=`expr $SLEEP - 1 ` done fi fi KILL_SLEEP_INTERVAL=5 if [ $FORCE -eq 1 ]; then if [ -z "$CATALINA_PID" ]; then echo "Kill failed: \$CATALINA_PID not set" else if [ -f "$CATALINA_PID" ]; then PID=`cat "$CATALINA_PID"` echo "Killing Tomcat with the PID: $PID" kill -9 $PID while [ $KILL_SLEEP_INTERVAL -ge 0 ]; do kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 if [ $? -gt 0 ]; then rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then if [ -w "$CATALINA_PID" ]; then cat /dev/null > "$CATALINA_PID" else echo "The PID file could not be removed." fi fi # Set this to zero else a warning will be issued about the process still running KILL_SLEEP_INTERVAL=0 echo "The Tomcat process has been killed." break fi if [ $KILL_SLEEP_INTERVAL -gt 0 ]; then sleep 1 fi KILL_SLEEP_INTERVAL=`expr $KILL_SLEEP_INTERVAL - 1 ` done if [ $KILL_SLEEP_INTERVAL -gt 0 ]; then echo "Tomcat has not been killed completely yet. The process might be waiting on some system call or might be UNINTERRUPTIBLE." fi fi fi fi elif [ "$1" = "configtest" ] ; then eval "\"$_RUNJAVA\"" $LOGGING_MANAGER $JAVA_OPTS \ -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \ -Dcatalina.base="\"$CATALINA_BASE\"" \ -Dcatalina.home="\"$CATALINA_HOME\"" \ -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \ org.apache.catalina.startup.Bootstrap configtest result=$? if [ $result -ne 0 ]; then echo "Configuration error detected!" fi exit $result elif [ "$1" = "version" ] ; then "$_RUNJAVA" \ -classpath "$CATALINA_HOME/lib/catalina.jar" \ org.apache.catalina.util.ServerInfo else echo "Usage: catalina.sh ( commands ... )" echo "commands:" if $os400; then echo " debug Start Catalina in a debugger (not available on OS400)" echo " debug -security Debug Catalina with a security manager (not available on OS400)" else echo " debug Start Catalina in a debugger" echo " debug -security Debug Catalina with a security manager" fi echo " jpda start Start Catalina under JPDA debugger" echo " run Start Catalina in the current window" echo " run -security Start in the current window with security manager" echo " start Start Catalina in a separate window" echo " start -security Start in a separate window with security manager" echo " stop Stop Catalina, waiting up to 5 seconds for the process to end" echo " stop n Stop Catalina, waiting up to n seconds for the process to end" echo " stop -force Stop Catalina, wait up to 5 seconds and then use kill -KILL if still running" echo " stop n -force Stop Catalina, wait up to n seconds and then use kill -KILL if still running" echo " configtest Run a basic syntax check on server.xml - check exit code for result" echo " version What version of tomcat are you running?" echo "Note: Waiting for the process to end and use of the -force option require that \$CATALINA_PID is defined" exit 1 fi tomcat7-7.0.52/bin/configtest.sh0000755000175100017510000000360212271014356016421 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Configuration Test Script for the CATALINA Server # ----------------------------------------------------------------------------- # Better OS/400 detection: see Bugzilla 31132 os400=false case "`uname`" in OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0" while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done PRGDIR=`dirname "$PRG"` EXECUTABLE=catalina.sh # Check that target executable exists if $os400; then # -x will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups eval else if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then echo "Cannot find $PRGDIR/$EXECUTABLE" echo "The file is absent or does not have execute permission" echo "This file is needed to run this program" exit 1 fi fi exec "$PRGDIR"/"$EXECUTABLE" configtest "$@" tomcat7-7.0.52/bin/daemon.sh0000755000175100017510000001731412271014356015524 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # ----------------------------------------------------------------------------- # Commons Daemon wrapper script. # ----------------------------------------------------------------------------- # # resolve links - $0 may be a softlink ARG0="$0" while [ -h "$ARG0" ]; do ls=`ls -ld "$ARG0"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then ARG0="$link" else ARG0="`dirname $ARG0`/$link" fi done DIRNAME="`dirname $ARG0`" PROGRAM="`basename $ARG0`" while [ ".$1" != . ] do case "$1" in --java-home ) JAVA_HOME="$2" shift; shift; continue ;; --catalina-home ) CATALINA_HOME="$2" shift; shift; continue ;; --catalina-base ) CATALINA_BASE="$2" shift; shift; continue ;; --catalina-pid ) CATALINA_PID="$2" shift; shift; continue ;; --tomcat-user ) TOMCAT_USER="$2" shift; shift; continue ;; --service-start-wait-time ) SERVICE_START_WAIT_TIME="$2" shift; shift; continue ;; * ) break ;; esac done # OS specific support (must be 'true' or 'false'). cygwin=false; darwin=false; case "`uname`" in CYGWIN*) cygwin=true ;; Darwin*) darwin=true ;; esac # Use the maximum available, or set MAX_FD != -1 to use that test ".$MAX_FD" = . && MAX_FD="maximum" # Setup parameters for running the jsvc # test ".$TOMCAT_USER" = . && TOMCAT_USER=tomcat # Set JAVA_HOME to working JDK or JRE # JAVA_HOME=/opt/jdk-1.6.0.22 # If not set we'll try to guess the JAVA_HOME # from java binary if on the PATH # if [ -z "$JAVA_HOME" ]; then JAVA_BIN="`which java 2>/dev/null || type java 2>&1`" test -x "$JAVA_BIN" && JAVA_HOME="`dirname $JAVA_BIN`" test ".$JAVA_HOME" != . && JAVA_HOME=`cd "$JAVA_HOME/.." >/dev/null; pwd` else JAVA_BIN="$JAVA_HOME/bin/java" fi # Only set CATALINA_HOME if not already set test ".$CATALINA_HOME" = . && CATALINA_HOME=`cd "$DIRNAME/.." >/dev/null; pwd` test ".$CATALINA_BASE" = . && CATALINA_BASE="$CATALINA_HOME" test ".$CATALINA_MAIN" = . && CATALINA_MAIN=org.apache.catalina.startup.Bootstrap # If not explicitly set, look for jsvc in CATALINA_BASE first then CATALINA_HOME if [ -z $JSVC ]; then JSVC="$CATALINA_BASE/bin/jsvc" if [ ! -x $JSVC ]; then JSVC="$CATALINA_HOME/bin/jsvc" fi fi # Set the default service-start wait time if necessary test ".$SERVICE_START_WAIT_TIME" = . && SERVICE_START_WAIT_TIME=10 # Ensure that any user defined CLASSPATH variables are not used on startup, # but allow them to be specified in setenv.sh, in rare case when it is needed. CLASSPATH= JAVA_OPTS= if [ -r "$CATALINA_BASE/bin/setenv.sh" ]; then . "$CATALINA_BASE/bin/setenv.sh" elif [ -r "$CATALINA_HOME/bin/setenv.sh" ]; then . "$CATALINA_HOME/bin/setenv.sh" fi # Add on extra jar files to CLASSPATH test ".$CLASSPATH" != . && CLASSPATH="${CLASSPATH}:" CLASSPATH="$CLASSPATH$CATALINA_HOME/bin/bootstrap.jar:$CATALINA_HOME/bin/commons-daemon.jar" test ".$CATALINA_OUT" = . && CATALINA_OUT="$CATALINA_BASE/logs/catalina-daemon.out" test ".$CATALINA_TMP" = . && CATALINA_TMP="$CATALINA_BASE/temp" # Add tomcat-juli.jar to classpath # tomcat-juli.jar can be over-ridden per instance if [ -r "$CATALINA_BASE/bin/tomcat-juli.jar" ] ; then CLASSPATH="$CLASSPATH:$CATALINA_BASE/bin/tomcat-juli.jar" else CLASSPATH="$CLASSPATH:$CATALINA_HOME/bin/tomcat-juli.jar" fi # Set juli LogManager config file if it is present and an override has not been issued if [ -z "$LOGGING_CONFIG" ]; then if [ -r "$CATALINA_BASE/conf/logging.properties" ]; then LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties" else # Bugzilla 45585 LOGGING_CONFIG="-Dnop" fi fi test ".$LOGGING_MANAGER" = . && LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" JAVA_OPTS="$JAVA_OPTS $LOGGING_MANAGER" # Set -pidfile test ".$CATALINA_PID" = . && CATALINA_PID="$CATALINA_BASE/logs/catalina-daemon.pid" # Increase the maximum file descriptors if we can if [ "$cygwin" = "false" ]; then MAX_FD_LIMIT=`ulimit -H -n` if [ "$?" -eq 0 ]; then # Darwin does not allow RLIMIT_INFINITY on file soft limit if [ "$darwin" = "true" -a "$MAX_FD_LIMIT" = "unlimited" ]; then MAX_FD_LIMIT=`/usr/sbin/sysctl -n kern.maxfilesperproc` fi test ".$MAX_FD" = ".maximum" && MAX_FD="$MAX_FD_LIMIT" ulimit -n $MAX_FD if [ "$?" -ne 0 ]; then echo "$PROGRAM: Could not set maximum file descriptor limit: $MAX_FD" fi else echo "$PROGRAM: Could not query system maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # ----- Execute The Requested Command ----------------------------------------- case "$1" in run ) shift "$JSVC" $* \ $JSVC_OPTS \ -java-home "$JAVA_HOME" \ -pidfile "$CATALINA_PID" \ -wait "$SERVICE_START_WAIT_TIME" \ -nodetach \ -outfile "&1" \ -errfile "&2" \ -classpath "$CLASSPATH" \ "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMP" \ $CATALINA_MAIN exit $? ;; start ) "$JSVC" $JSVC_OPTS \ -java-home "$JAVA_HOME" \ -user $TOMCAT_USER \ -pidfile "$CATALINA_PID" \ -wait "$SERVICE_START_WAIT_TIME" \ -outfile "$CATALINA_OUT" \ -errfile "&1" \ -classpath "$CLASSPATH" \ "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMP" \ $CATALINA_MAIN exit $? ;; stop ) "$JSVC" $JSVC_OPTS \ -stop \ -pidfile "$CATALINA_PID" \ -classpath "$CLASSPATH" \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMP" \ $CATALINA_MAIN exit $? ;; version ) "$JSVC" \ -java-home "$JAVA_HOME" \ -pidfile "$CATALINA_PID" \ -classpath "$CLASSPATH" \ -errfile "&2" \ -version \ -check \ $CATALINA_MAIN if [ "$?" = 0 ]; then "$JAVA_BIN" \ -classpath "$CATALINA_HOME/lib/catalina.jar" \ org.apache.catalina.util.ServerInfo fi exit $? ;; * ) echo "Unknown command: \`$1'" echo "Usage: $PROGRAM ( commands ... )" echo "commands:" echo " run Start Tomcat without detaching from console" echo " start Start Tomcat" echo " stop Stop Tomcat" echo " version What version of commons daemon and Tomcat" echo " are you running?" exit 1 ;; esac tomcat7-7.0.52/bin/setclasspath.bat0000755000175100017510000000604512271014356017112 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. rem --------------------------------------------------------------------------- rem Set JAVA_HOME or JRE_HOME if not already set, ensure any provided settings rem are valid and consistent with the selected start-up options and set up the rem endorsed directory. rem --------------------------------------------------------------------------- rem Make sure prerequisite environment variables are set rem In debug mode we need a real JDK (JAVA_HOME) if ""%1"" == ""debug"" goto needJavaHome rem Otherwise either JRE or JDK are fine if not "%JRE_HOME%" == "" goto gotJreHome if not "%JAVA_HOME%" == "" goto gotJavaHome echo Neither the JAVA_HOME nor the JRE_HOME environment variable is defined echo At least one of these environment variable is needed to run this program goto exit :needJavaHome rem Check if we have a usable JDK if "%JAVA_HOME%" == "" goto noJavaHome if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\javaw.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\jdb.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\javac.exe" goto noJavaHome set "JRE_HOME=%JAVA_HOME%" goto okJava :noJavaHome echo The JAVA_HOME environment variable is not defined correctly. echo It is needed to run this program in debug mode. echo NB: JAVA_HOME should point to a JDK not a JRE. goto exit :gotJavaHome rem No JRE given, use JAVA_HOME as JRE_HOME set "JRE_HOME=%JAVA_HOME%" :gotJreHome rem Check if we have a usable JRE if not exist "%JRE_HOME%\bin\java.exe" goto noJreHome if not exist "%JRE_HOME%\bin\javaw.exe" goto noJreHome goto okJava :noJreHome rem Needed at least a JRE echo The JRE_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto exit :okJava rem Don't override the endorsed dir if the user has set it previously if not "%JAVA_ENDORSED_DIRS%" == "" goto gotEndorseddir rem Set the default -Djava.endorsed.dirs argument set "JAVA_ENDORSED_DIRS=%CATALINA_HOME%\endorsed" :gotEndorseddir rem Set standard command for invoking Java. rem Note that NT requires a window name argument when using start. rem Also note the quoting as JAVA_HOME may contain spaces. set _RUNJAVA="%JRE_HOME%\bin\java" set _RUNJDB="%JAVA_HOME%\bin\jdb" goto end :exit exit /b 1 :end exit /b 0 tomcat7-7.0.52/bin/cpappend.bat0000755000175100017510000000233512271014356016204 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. rem --------------------------------------------------------------------------- rem Append to CLASSPATH rem --------------------------------------------------------------------------- rem Process the first argument if ""%1"" == """" goto end set CLASSPATH=%CLASSPATH%;%1 shift rem Process the remaining arguments :setArgs if ""%1"" == """" goto doneSetArgs set CLASSPATH=%CLASSPATH% %1 shift goto setArgs :doneSetArgs :end tomcat7-7.0.52/bin/startup.bat0000755000175100017510000000370512271014356016116 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Start script for the CATALINA Server rem --------------------------------------------------------------------------- rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%CURRENT_DIR%" if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome cd .. set "CATALINA_HOME=%cd%" cd "%CURRENT_DIR%" :gotHome if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat" rem Check that target executable exists if exist "%EXECUTABLE%" goto okExec echo Cannot find "%EXECUTABLE%" echo This file is needed to run this program goto end :okExec rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs call "%EXECUTABLE%" start %CMD_LINE_ARGS% :end tomcat7-7.0.52/bin/tool-wrapper.bat0000755000175100017510000000755612271014356017057 0ustar locutuslocutus@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor license agreements. See the NOTICE file distributed with rem this work for additional information regarding copyright ownership. rem The ASF licenses this file to You under the Apache License, Version 2.0 rem (the "License"); you may not use this file except in compliance with rem the License. You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. if "%OS%" == "Windows_NT" setlocal rem --------------------------------------------------------------------------- rem Wrapper script for command line tools rem rem Environment Variable Prerequisites rem rem CATALINA_HOME May point at your Catalina "build" directory. rem rem TOOL_OPTS (Optional) Java runtime options. rem rem JAVA_HOME Must point at your Java Development Kit installation. rem Using JRE_HOME instead works as well. rem rem JRE_HOME Must point at your Java Runtime installation. rem Defaults to JAVA_HOME if empty. If JRE_HOME and JAVA_HOME rem are both set, JRE_HOME is used. rem rem JAVA_OPTS (Optional) Java runtime options. rem rem JAVA_ENDORSED_DIRS (Optional) Lists of of semi-colon separated directories rem containing some jars in order to allow replacement of APIs rem created outside of the JCP (i.e. DOM and SAX from W3C). rem It can also be used to update the XML parser implementation. rem Defaults to $CATALINA_HOME/endorsed. rem --------------------------------------------------------------------------- rem Guess CATALINA_HOME if not defined set "CURRENT_DIR=%cd%" if not "%CATALINA_HOME%" == "" goto gotHome set "CATALINA_HOME=%CURRENT_DIR%" if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome cd .. set "CATALINA_HOME=%cd%" cd "%CURRENT_DIR%" :gotHome if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome echo The CATALINA_HOME environment variable is not defined correctly echo This environment variable is needed to run this program goto end :okHome rem Ensure that any user defined CLASSPATH variables are not used on startup, rem but allow them to be specified in setenv.bat, in rare case when it is needed. set CLASSPATH= rem Get standard environment variables if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat" rem Get standard Java environment variables if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath echo Cannot find "%CATALINA_HOME%\bin\setclasspath.bat" echo This file is needed to run this program goto end :okSetclasspath call "%CATALINA_HOME%\bin\setclasspath.bat" %1 if errorlevel 1 goto end rem Add on extra jar files to CLASSPATH rem Note that there are no quotes as we do not want to introduce random rem quotes into the CLASSPATH if "%CLASSPATH%" == "" goto emptyClasspath set "CLASSPATH=%CLASSPATH%;" :emptyClasspath set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar;%CATALINA_HOME%\bin\tomcat-juli.jar;%CATALINA_HOME%\lib\servlet-api.jar" set JAVA_OPTS=%JAVA_OPTS% -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager rem Get remaining unshifted command line arguments and save them in the set CMD_LINE_ARGS= :setArgs if ""%1""=="""" goto doneSetArgs set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1 shift goto setArgs :doneSetArgs %_RUNJAVA% %JAVA_OPTS% %TOOL_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.home="%CATALINA_HOME%" org.apache.catalina.startup.Tool %CMD_LINE_ARGS% :end tomcat7-7.0.52/bin/tool-wrapper.sh0000755000175100017510000001164012271014356016710 0ustar locutuslocutus#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- # Wrapper script for command line tools # # Environment Variable Prerequisites # # CATALINA_HOME May point at your Catalina "build" directory. # # TOOL_OPTS (Optional) Java runtime options. # # JAVA_HOME Must point at your Java Development Kit installation. # Using JRE_HOME instead works as well. # # JRE_HOME Must point at your Java Runtime installation. # Defaults to JAVA_HOME if empty. If JRE_HOME and JAVA_HOME # are both set, JRE_HOME is used. # # JAVA_OPTS (Optional) Java runtime options. # # JAVA_ENDORSED_DIRS (Optional) Lists of of colon separated directories # containing some jars in order to allow replacement of APIs # created outside of the JCP (i.e. DOM and SAX from W3C). # It can also be used to update the XML parser implementation. # Defaults to $CATALINA_HOME/endorsed. # ----------------------------------------------------------------------------- # OS specific support. $var _must_ be set to either true or false. cygwin=false darwin=false os400=false case "`uname`" in CYGWIN*) cygwin=true;; Darwin*) darwin=true;; OS400*) os400=true;; esac # resolve links - $0 may be a softlink PRG="$0" while [ -h "$PRG" ]; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`/"$link" fi done # Get standard environment variables PRGDIR=`dirname "$PRG"` # Only set CATALINA_HOME if not already set [ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." >/dev/null; pwd` # Ensure that any user defined CLASSPATH variables are not used on startup, # but allow them to be specified in setenv.sh, in rare case when it is needed. CLASSPATH= if [ -r "$CATALINA_HOME/bin/setenv.sh" ]; then . "$CATALINA_HOME/bin/setenv.sh" fi # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin; then [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` [ -n "$JRE_HOME" ] && JRE_HOME=`cygpath --unix "$JRE_HOME"` [ -n "$CATALINA_HOME" ] && CATALINA_HOME=`cygpath --unix "$CATALINA_HOME"` [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` fi # For OS400 if $os400; then # Set job priority to standard for interactive (interactive - 6) by using # the interactive priority - 6, the helper threads that respond to requests # will be running at the same priority as interactive jobs. COMMAND='chgjob job('$JOBNAME') runpty(6)' system $COMMAND # Enable multi threading export QIBM_MULTI_THREADED=Y fi # Get standard Java environment variables if $os400; then # -r will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups . "$CATALINA_HOME"/bin/setclasspath.sh else if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then . "$CATALINA_HOME"/bin/setclasspath.sh else echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh" echo "This file is needed to run this program" exit 1 fi fi # Add on extra jar files to CLASSPATH if [ ! -z "$CLASSPATH" ] ; then CLASSPATH="$CLASSPATH": fi CLASSPATH="$CLASSPATH""$CATALINA_HOME"/bin/bootstrap.jar:"$CATALINA_HOME"/bin/tomcat-juli.jar:"$CATALINA_HOME"/lib/servlet-api.jar # For Cygwin, switch paths to Windows format before running java if $cygwin; then JAVA_HOME=`cygpath --absolute --windows "$JAVA_HOME"` JRE_HOME=`cygpath --absolute --windows "$JRE_HOME"` CATALINA_HOME=`cygpath --absolute --windows "$CATALINA_HOME"` CLASSPATH=`cygpath --path --windows "$CLASSPATH"` JAVA_ENDORSED_DIRS=`cygpath --path --windows "$JAVA_ENDORSED_DIRS"` fi JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" # ----- Execute The Requested Command ----------------------------------------- exec "$_RUNJAVA" $JAVA_OPTS $TOOL_OPTS \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ -Dcatalina.home="$CATALINA_HOME" \ org.apache.catalina.startup.Tool "$@" tomcat7-7.0.52/build.xml0000644000175100017510000035201012276740341014773 0ustar locutuslocutus Apache Tomcat ${version} native binaries for Win64 IA64 platform. Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform. Eclipse project files created. Read the Building page on the Apache Tomcat documentation site for details on how to configure your Eclipse workplace. tomcat7-7.0.52/RELEASE-NOTES0000644000175100017510000002150612271005702015034 0ustar locutuslocutus================================================================================ Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. ================================================================================ Apache Tomcat Version @VERSION@ Release Notes ========= CONTENTS: ========= * Dependency Changes * API Stability * JNI Based Applications * Bundled APIs * Web application reloading and static fields in shared libraries * Tomcat on Linux * Enabling SSI and CGI Support * Security manager URLs * Symlinking static resources * Viewing the Tomcat Change Log * Cryptographic software notice * When all else fails =================== Dependency Changes: =================== Tomcat @VERSION_MAJOR_MINOR@ is designed to run on Java SE 6 and later. In addition, Tomcat @VERSION_MAJOR_MINOR@ uses the Eclipse JDT Java compiler for compiling JSP pages. This means you no longer need to have the complete Java Development Kit (JDK) to run Tomcat, but a Java Runtime Environment (JRE) is sufficient. The Eclipse JDT Java compiler is bundled with the binary Tomcat distributions. Tomcat can also be configured to use the compiler from the JDK to compile JSPs, or any other Java compiler supported by Apache Ant. ============== API Stability: ============== The public interfaces for the following classes are fixed and will not be changed at all during the remaining lifetime of the 7.x series: - javax/**/* The public interfaces for the following classes may be added to in order to resolve bugs and/or add new features. No existing interface will be removed or changed although it may be deprecated. - org/apache/catalina/* - org/apache/catalina/comet/* Note: As Tomcat 7 matures, the above list will be added to. The list is not considered complete at this time. The remaining classes are considered part of the Tomcat internals and may change without notice between point releases. ======================= JNI Based Applications: ======================= Applications that require native libraries must ensure that the libraries have been loaded prior to use. Typically, this is done with a call like: static { System.loadLibrary("path-to-library-file"); } in some class. However, the application must also ensure that the library is not loaded more than once. If the above code were placed in a class inside the web application (i.e. under /WEB-INF/classes or /WEB-INF/lib), and the application were reloaded, the loadLibrary() call would be attempted a second time. To avoid this problem, place classes that load native libraries outside of the web application, and ensure that the loadLibrary() call is executed only once during the lifetime of a particular JVM. ============= Bundled APIs: ============= A standard installation of Tomcat @VERSION_MAJOR_MINOR@ makes all of the following APIs available for use by web applications (by placing them in "lib"): * annotations-api.jar (Annotations package) * catalina.jar (Tomcat Catalina implementation) * catalina-ant.jar (Tomcat Catalina Ant tasks) * catalina-ha.jar (High availability package) * catalina-tribes.jar (Group communication) * ecj-@JDT_VERSION@.jar (Eclipse JDT Java compiler) * el-api.jar (EL 2.2 API) * jasper.jar (Jasper 2 Compiler and Runtime) * jasper-el.jar (Jasper 2 EL implementation) * jsp-api.jar (JSP 2.2 API) * servlet-api.jar (Servlet 3.0 API) * tomcat7-websocket.jar (WebSocket 1.0 implementation) * tomcat-api.jar (Interfaces shared by Catalina and Jasper) * tomcat-coyote.jar (Tomcat connectors and utility classes) * tomcat-dbcp.jar (package renamed database connection pool based on Commons DBCP) * tomcat-jdbc.jar (Tomcat's database connection pooling solution) * tomcat-util.jar (Various utilities) * websocket-api.jar (WebSocket 1.0 API) You can make additional APIs available to all of your web applications by putting unpacked classes into a "classes" directory (not created by default), or by placing them in JAR files in the "lib" directory. To override the XML parser implementation or interfaces, use the endorsed mechanism of the JVM. The default configuration defines JARs located in "endorsed" as endorsed. ================================================================ Web application reloading and static fields in shared libraries: ================================================================ Some shared libraries (many are part of the JDK) keep references to objects instantiated by the web application. To avoid class loading related problems (ClassCastExceptions, messages indicating that the classloader is stopped, etc.), the shared libraries state should be reinitialized. Something which might help is to avoid putting classes which would be referenced by a shared static field in the web application classloader, and putting them in the shared classloader instead (JARs should be put in the "lib" folder, and classes should be put in the "classes" folder). ================ Tomcat on Linux: ================ GLIBC 2.2 / Linux 2.4 users should define an environment variable: export LD_ASSUME_KERNEL=2.2.5 Redhat Linux 9.0 users should use the following setting to avoid stability problems: export LD_ASSUME_KERNEL=2.4.1 There are some Linux bugs reported against the NIO sendfile behavior, make sure you have a JDK that is up to date, or disable sendfile behavior in the Connector.
6427312: (fc) FileChannel.transferTo() throws IOException "system call interrupted"
5103988: (fc) FileChannel.transferTo should return -1 for EAGAIN instead throws IOException
6253145: (fc) FileChannel.transferTo on Linux fails when going beyond 2GB boundary
6470086: (fc) FileChannel.transferTo(2147483647, 1, channel) cause "Value too large" exception
============================= Enabling SSI and CGI Support: ============================= Because of the security risks associated with CGI and SSI available to web applications, these features are disabled by default. To enable and configure CGI support, please see the cgi-howto.html page. To enable and configue SSI support, please see the ssi-howto.html page. ====================== Security manager URLs: ====================== In order to grant security permissions to JARs located inside the web application repository, use URLs of of the following format in your policy file: file:${catalina.base}/webapps/examples/WEB-INF/lib/driver.jar ============================ Symlinking static resources: ============================ By default, Unix symlinks will not work when used in a web application to link resources located outside the web application root directory. This behavior is optional, and the "allowLinking" flag may be used to disable the check. ============================== Viewing the Tomcat Change Log: ============================== See changelog.html in this directory. ============================= Cryptographic software notice ============================= This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See for more information. The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has classified this software as Export Commodity Control Number (ECCN) 5D002.C.1, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this Apache Software Foundation distribution makes it eligible for export under the License Exception ENC Technology Software Unrestricted (TSU) exception (see the BIS Export Administration Regulations, Section 740.13) for both object code and source code. The following provides more details on the included cryptographic software: - Tomcat includes code designed to work with JSSE - Tomcat includes code designed to work with OpenSSL ==================== When all else fails: ==================== See the FAQ http://tomcat.apache.org/faq/ tomcat7-7.0.52/BUILDING.txt0000644000175100017510000003443412271005702015105 0ustar locutuslocutus================================================================================ Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. ================================================================================ ==================================================== Building The Apache Tomcat @VERSION_MAJOR_MINOR@ Servlet/JSP Container ==================================================== This subproject contains the source code for Tomcat @VERSION_MAJOR_MINOR@, a container that implements the Servlet 3.0 and JSP 2.2 specifications from the Java Community Process . Note: If you just need to run Apache Tomcat, it is not necessary to build it. You may simply download a binary distribution. It is cross-platform. Read RUNNING.txt for the instruction on how to run it. In order to build a binary distribution version of Apache Tomcat from a source distribution, do the following: (1) Download and Install a Java 6 and Java 7 Development Kit 1. If the JDKs are already installed, skip to (2). 2. Download a version 6 of the Java Development Kit (JDK) release (use the latest update available for your chosen version) from http://www.oracle.com/technetwork/java/javase/downloads/index.html or from another JDK vendor. Note regarding later versions of Java: As documented elsewhere, one of the components in Apache Tomcat includes a private copy of the Apache Commons DBCP library. The source code for this library is downloaded, processed by the build script (renaming the packages) and compiled. Due to changes in JDBC interfaces implemented by the library between versions of Java SE specification, the library has to target specific version of Java and can be compiled only with the JDK version implementing this version of specification. Therefore, the build Tomcat build process must be executed with a Java 6 JDK. See Apache Commons DBCP project web site for more details on available versions of the library and its requirements, http://commons.apache.org/dbcp/ If you really want to use a later version of JDK to build Tomcat, several workarounds are possible. One of them is to skip building the component (tomcat-dbcp.jar). 3. Install the Java 6 JDK according to the instructions included with the release. 4. Set an environment variable JAVA_HOME to the pathname of the directory into which you installed the JDK release. 5. Download a version 7 of the Java Development Kit (JDK) release (use the latest update available for your chosen version) from http://www.oracle.com/technetwork/java/javase/downloads/index.html or from another JDK vendor. 6. Install the Java 7 JDK according to the instructions included with the release. * NOTE: The Java 7 JDK is only required if you wish to build Tomcat with JSR-356 (Java WebSocket 1.0) support. (2) Install Apache Ant 1.8.x on your computer 1. If Apache Ant 1.8.x is already installed on your computer, skip to (3). 2. Download a binary distribution of Ant 1.8.x from: http://ant.apache.org/bindownload.cgi 3. Unpack the binary distribution into a convenient location so that the Ant release resides in its own directory (conventionally named "apache-ant-[version]"). For the purposes of the remainder of this document, the symbolic name "${ant.home}" is used to refer to the full pathname of the release directory. 4. Create an ANT_HOME environment variable to point the directory ${ant.home}. 5. Modify the PATH environment variable to include the directory ${ant.home}/bin in its list. This makes the "ant" command line script available, which will be used to actually perform the build. (3) Building Tomcat @VERSION_MAJOR_MINOR@ (3.1) Checkout or obtain the source code for Tomcat @VERSION_MAJOR_MINOR@ Checkout the source using SVN, selecting a tag for released version or trunk for the current development code, or download and unpack a source package. * Tomcat SVN repository URL: http://svn.apache.org/repos/asf/tomcat/tc@VERSION_MAJOR_MINOR@.x/trunk/ * Source packages can be downloaded from: http://tomcat.apache.org/download-@VERSION_MAJOR@0.cgi The location where the source has been placed will be further referred as ${tomcat.source}. (3.2) Building 1. The build is controlled by creating a ${tomcat.source}/build.properties file. It is recommended to always create the file, because of unfortunate default value of base.path property. You may start with the following content for the file: # ----- Default Base Path for Dependent Packages ----- # Replace this path with the directory path where dependencies binaries # should be downloaded base.path=/home/me/some-place-to-download-to 2. Configure base.path property by adding it to the ${tomcat.source}/build.properties file. The base.path property specifies the place where Tomcat dependencies required by the build are downloaded. It is recommended to place this directory outside of the source tree, so that you do not waste your time re-downloading the libraries. * WARNING: The default value of base.path property makes the build script to download libraries required to build Tomcat to the /usr/share/java directory. On a typical Linux or MacOX system an ordinary user will not have access to write to this directory. Even if you do have access to that directory, it is likely not appropriate for you to write there. On Windows this usually corresponds to the "C:\usr\share\java" directory, unless Cygwin is used. * NOTE: Users accessing the Internet through a proxy must use the properties file to indicate to Ant the proxy configuration. The following properties should be added to the ${tomcat.source}/build.properties file. proxy.use=on proxy.host=proxy.domain proxy.port=8080 proxy.user=username proxy.password=password See Apache Ant documentation for the task for details. * NOTE: Users wishing to build Tomcat with JSR-356 (Java WebSocket 1.0) support must also set the java.7.home build property to the location of the Java 7 JDK installation. 3. Go to the sources directory and run Ant: cd ${tomcat.source} ant This will execute the "deploy" target in build.xml. Once the build has completed successfully, a usable Tomcat installation will have been produced in the ${tomcat.source}/output/build directory, and can be started and stopped with the usual scripts. Note that the build includes Tomcat documentation, which can be found in the output/build/webapps/docs directory. The path of the output directory can be controlled by specifying the "tomcat.output" property in the build.properties file. * NOTE: Do not run the build as the root user. Building and running Tomcat does not require root privileges. (4) Updating sources and rebuilding It is recommended that you regularly update the downloaded Tomcat @VERSION_MAJOR_MINOR@ sources using your SVN client. For a quick rebuild of only modified code you can use: cd ${tomcat.source} ant (5) Special builds There are several targets in Tomcat build files that are useful to be called separately. They build components that you may want to build quickly, or ones that are included in the full release and are not built during the default "deploy" build. (5.1) Building documentation The documentation web application is built during the default "deploy" build. It can be built quickly by using the following commands: cd ${tomcat.source} ant build-docs The output of this command will be found in the following directory: output/build/webapps/docs The API documentation (Javadoc) is built during a "release" build. It is easy to build it separately by using the following commands: cd ${tomcat.source} ant javadoc The output of this command will be found in the following directories: output/dist/webapps/docs/api output/dist/webapps/docs/elapi output/dist/webapps/docs/jspapi output/dist/webapps/docs/servletapi (5.2) Building the extras (commons-logging, webservices etc.) These components are documented on the "Additional Components" (extras.html) page of documentation. They are built during a "release" build. You can build them by using the following commands: cd ${tomcat.source} ant extras (5.3) Building the embedded packages These are built during a "release" build. You can build them by using the following commands: cd ${tomcat.source} ant embed (6) Building a full release (as provided via the ASF download pages) 1. Configure GPG, if needed If the released artifacts have to be cryptographically signed with a PGP signature, like the official ASF releases are, the following property can be added to the build.properties file: # Location of GPG executable (used only for releases) gpg.exec=/path/to/gpg You do not need it if you do not plan to sign the release. If "gpg.exec" property does not point to an existing file, it will be ignored and this feature will be disabled. You will be prompted for the GPG passphrase when the release build starts, unless "gpg.passphrase" property is set. 2. Build the release: cd ${tomcat.source} ant release (7) Tests (7.1) Running Tomcat tests Tomcat includes a number of junit tests. The tests are not run when a release is built. There is separate command to run them. To run the testsuite use the following command: cd ${tomcat.source} ant test It is advisable to redirect output of the above command to a file for later inspection. The JUnit reports generated by the tests will be written to the following directory: output/build/logs By default the testsuite is run three times to test 3 different implementations of Tomcat connectors: BIO, NIO and APR. (If you are not familiar with Tomcat connectors, see config/http.html in documentation for details). The 3 runs are enabled and disabled individually by the following properties, which all are "true" by default: execute.test.bio=true execute.test.nio=true execute.test.apr=true The APR connector can be tested only if Tomcat-Native library binaries are found by the testsuite. The "test.apr.loc" property specifies the directory where the library binaries are located. By default the "test.apr.loc" property specifies the following location: output/build/bin/native/ If you are on Windows and want to test the APR connector you can put the tcnative-1.dll file into ${tomcat.source}/bin/native/ and it will be copied into the above directory when the build runs. (7.2) Running a single test It is possible to run a single JUnit test class by adding the "test.entry" property to the build.properties file. The property specifies the name of the test class. For example: test.entry=org.apache.catalina.util.TestServerInfo (7.3) Other configuration options 1. It is possible to enable generation of access log file when the tests are run. This is off by default and can be enabled by the following property: test.accesslog=true The "access_log." file will be written to the same directory as JUnit reports, output/build/logs 2. The testsuite respects logging configuration as configured by ${tomcat.source}/conf/logging.properties The log files will be written to the temporary directory used by the tests, output/test-tmp/logs 3. It is possible to configure formatter used by JUnit reports. For example the following property disables generation of separate report files: junit.formatter.usefile=false 4. Optional support is provided for the Cobertura code coverage tool. It can be enabled using the following property: test.cobertura=true * NOTE: Cobertura is licensed under GPL v2 with parts of it being under Apache License v1.1. See http://cobertura.sf.net for details. Using it during Tomcat build is optional and is off by default. (8) Source code checks (8.1) Checkstyle * NOTE: Checkstyle is licensed under LGPL. Using Checkstyle during Tomcat build is optional and is off by default. Tomcat comes with a Checkstyle configuration that tests its source code for certain conventions, like presence of the license header. To enable Checkstyle, add the following property to build.properties file: execute.validate=true Once Checkstyle is enabled, the check will be performed automatically during the build. The check is run before compilation of the source code. To speed-up repeated runs of this check, a cache is configured. The cache is located in the following directory: output/res/checkstyle It is possible to run the check separately by invoking the "validate" target. The command is: cd ${tomcat.source} ant -Dexecute.validate=true validate (8.2) End-of-line conventions check You usually would not need to run this check. You can skip this section. Apache Tomcat project has convention that all of its textual source files, stored in Subversion repository, are marked with Subversion property "svn:eol-style" with value of "native". This convention makes the editing of source code on different platforms easier. This test is used by developers to check that the source code adheres to this convention. It verifies that the ends of lines in textual files are appropriate for the operating system where it is run. The idea is to run this check regularly on two different platforms and notify developers when an inconsistency is detected. The command to run this test is: cd ${tomcat.source} ant validate-eoln tomcat7-7.0.52/conf/0000755000175100017510000000000012301126372014065 5ustar locutuslocutustomcat7-7.0.52/conf/tomcat-users.xml0000644000175100017510000000277212271015321017242 0ustar locutuslocutus tomcat7-7.0.52/conf/catalina.properties0000644000175100017510000001414212271015321017756 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when # passed to checkPackageDefinition unless the # corresponding RuntimePermission ("defineClassInPackage."+package) has # been granted. # # by default, no packages are restricted for definition, and none of # the class loaders supplied with the JDK call checkPackageDefinition. # package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper. # # # List of comma-separated paths defining the contents of the "common" # classloader. Prefixes should be used to define what is the repository type. # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. # If left as blank,the JVM system loader will be used as Catalina's "common" # loader. # Examples: # "foo": Add this folder as a class repository # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar # # List of comma-separated paths defining the contents of the "server" # classloader. Prefixes should be used to define what is the repository type. # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. # If left as blank, the "common" loader will be used as Catalina's "server" # loader. # Examples: # "foo": Add this folder as a class repository # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository server.loader= # # List of comma-separated paths defining the contents of the "shared" # classloader. Prefixes should be used to define what is the repository type. # Path may be relative to the CATALINA_BASE path or absolute. If left as blank, # the "common" loader will be used as Catalina's "shared" loader. # Examples: # "foo": Add this folder as a class repository # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository # Please note that for single jars, e.g. bar.jar, you need the URL form # starting with file:. shared.loader= # List of JAR files that should not be scanned using the JarScanner # functionality. This is typically used to scan JARs for configuration # information. JARs that do not contain such information may be excluded from # the scan to speed up the scanning process. This is the default list. JARs on # this list are excluded from all scans. Scan specific lists (to exclude JARs # from individual scans) follow this. The list must be a comma separated list of # JAR file names. # The JARs listed below include: # - Tomcat Bootstrap JARs # - Tomcat API JARs # - Catalina JARs # - Jasper JARs # - Tomcat JARs # - Common non-Tomcat JARs # - Test JARs (JUnit, Cobertura and dependencies) tomcat.util.scan.DefaultJarScanner.jarsToSkip=\ bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\ annotations-api.jar,el-api.jar,jsp-api.jar,servlet-api.jar,websocket-api.jar,\ catalina.jar,catalina-ant.jar,catalina-ha.jar,catalina-tribes.jar,\ jasper.jar,jasper-el.jar,ecj-*.jar,\ tomcat-api.jar,tomcat-util.jar,tomcat-coyote.jar,tomcat-dbcp.jar,\ tomcat-jni.jar,tomcat-spdy.jar,\ tomcat-i18n-en.jar,tomcat-i18n-es.jar,tomcat-i18n-fr.jar,tomcat-i18n-ja.jar,\ tomcat-juli-adapters.jar,catalina-jmx-remote.jar,catalina-ws.jar,\ tomcat-jdbc.jar,\ tools.jar,\ commons-beanutils*.jar,commons-codec*.jar,commons-collections*.jar,\ commons-dbcp*.jar,commons-digester*.jar,commons-fileupload*.jar,\ commons-httpclient*.jar,commons-io*.jar,commons-lang*.jar,commons-logging*.jar,\ commons-math*.jar,commons-pool*.jar,\ jstl.jar,\ geronimo-spec-jaxrpc*.jar,wsdl4j*.jar,\ ant.jar,ant-junit*.jar,aspectj*.jar,jmx.jar,h2*.jar,hibernate*.jar,httpclient*.jar,\ jmx-tools.jar,jta*.jar,log4j.jar,log4j-1*.jar,mail*.jar,slf4j*.jar,\ xercesImpl.jar,xmlParserAPIs.jar,xml-apis.jar,\ junit.jar,junit-*.jar,hamcrest*.jar,org.hamcrest*.jar,ant-launcher.jar,\ cobertura-*.jar,asm-*.jar,dom4j-*.jar,icu4j-*.jar,jaxen-*.jar,jdom-*.jar,\ jetty-*.jar,oro-*.jar,servlet-api-*.jar,tagsoup-*.jar,xmlParserAPIs-*.jar,\ xom-*.jar # Additional JARs (over and above the default JARs listed above) to skip when # scanning for Servlet 3.0 pluggability features. These features include web # fragments, annotations, SCIs and classes that match @HandlesTypes. The list # must be a comma separated list of JAR file names. org.apache.catalina.startup.ContextConfig.jarsToSkip= # Additional JARs (over and above the default JARs listed above) to skip when # scanning for TLDs. The list must be a comma separated list of JAR file names. org.apache.catalina.startup.TldConfig.jarsToSkip=tomcat7-websocket.jar # # String cache configuration. tomcat.util.buf.StringCache.byte.enabled=true #tomcat.util.buf.StringCache.char.enabled=true #tomcat.util.buf.StringCache.trainThreshold=500000 #tomcat.util.buf.StringCache.cacheSize=5000 tomcat7-7.0.52/conf/web.xml0000644000175100017510000047613112271015321015375 0ustar locutuslocutus default org.apache.catalina.servlets.DefaultServlet debug 0 listings false 1 jsp org.apache.jasper.servlet.JspServlet fork false xpoweredBy false 3 default / jsp *.jsp *.jspx 30 123 application/vnd.lotus-1-2-3 3dml text/vnd.in3d.3dml 3ds image/x-3ds 3g2 video/3gpp2 3gp video/3gpp 7z application/x-7z-compressed aab application/x-authorware-bin aac audio/x-aac aam application/x-authorware-map aas application/x-authorware-seg abs audio/x-mpeg abw application/x-abiword ac application/pkix-attr-cert acc application/vnd.americandynamics.acc ace application/x-ace-compressed acu application/vnd.acucobol acutc application/vnd.acucorp adp audio/adpcm aep application/vnd.audiograph afm application/x-font-type1 afp application/vnd.ibm.modcap ahead application/vnd.ahead.space ai application/postscript aif audio/x-aiff aifc audio/x-aiff aiff audio/x-aiff aim application/x-aim air application/vnd.adobe.air-application-installer-package+zip ait application/vnd.dvb.ait ami application/vnd.amiga.ami anx application/annodex apk application/vnd.android.package-archive appcache text/cache-manifest application application/x-ms-application apr application/vnd.lotus-approach arc application/x-freearc art image/x-jg asc application/pgp-signature asf video/x-ms-asf asm text/x-asm aso application/vnd.accpac.simply.aso asx video/x-ms-asf atc application/vnd.acucorp atom application/atom+xml atomcat application/atomcat+xml atomsvc application/atomsvc+xml atx application/vnd.antix.game-component au audio/basic avi video/x-msvideo avx video/x-rad-screenplay aw application/applixware axa audio/annodex axv video/annodex azf application/vnd.airzip.filesecure.azf azs application/vnd.airzip.filesecure.azs azw application/vnd.amazon.ebook bat application/x-msdownload bcpio application/x-bcpio bdf application/x-font-bdf bdm application/vnd.syncml.dm+wbxml bed application/vnd.realvnc.bed bh2 application/vnd.fujitsu.oasysprs bin application/octet-stream blb application/x-blorb blorb application/x-blorb bmi application/vnd.bmi bmp image/bmp body text/html book application/vnd.framemaker box application/vnd.previewsystems.box boz application/x-bzip2 bpk application/octet-stream btif image/prs.btif bz application/x-bzip bz2 application/x-bzip2 c text/x-c c11amc application/vnd.cluetrust.cartomobile-config c11amz application/vnd.cluetrust.cartomobile-config-pkg c4d application/vnd.clonk.c4group c4f application/vnd.clonk.c4group c4g application/vnd.clonk.c4group c4p application/vnd.clonk.c4group c4u application/vnd.clonk.c4group cab application/vnd.ms-cab-compressed caf audio/x-caf cap application/vnd.tcpdump.pcap car application/vnd.curl.car cat application/vnd.ms-pki.seccat cb7 application/x-cbr cba application/x-cbr cbr application/x-cbr cbt application/x-cbr cbz application/x-cbr cc text/x-c cct application/x-director ccxml application/ccxml+xml cdbcmsg application/vnd.contact.cmsg cdf application/x-cdf cdkey application/vnd.mediastation.cdkey cdmia application/cdmi-capability cdmic application/cdmi-container cdmid application/cdmi-domain cdmio application/cdmi-object cdmiq application/cdmi-queue cdx chemical/x-cdx cdxml application/vnd.chemdraw+xml cdy application/vnd.cinderella cer application/pkix-cert cfs application/x-cfs-compressed cgm image/cgm chat application/x-chat chm application/vnd.ms-htmlhelp chrt application/vnd.kde.kchart cif chemical/x-cif cii application/vnd.anser-web-certificate-issue-initiation cil application/vnd.ms-artgalry cla application/vnd.claymore class application/java clkk application/vnd.crick.clicker.keyboard clkp application/vnd.crick.clicker.palette clkt application/vnd.crick.clicker.template clkw application/vnd.crick.clicker.wordbank clkx application/vnd.crick.clicker clp application/x-msclip cmc application/vnd.cosmocaller cmdf chemical/x-cmdf cml chemical/x-cml cmp application/vnd.yellowriver-custom-menu cmx image/x-cmx cod application/vnd.rim.cod com application/x-msdownload conf text/plain cpio application/x-cpio cpp text/x-c cpt application/mac-compactpro crd application/x-mscardfile crl application/pkix-crl crt application/x-x509-ca-cert cryptonote application/vnd.rig.cryptonote csh application/x-csh csml chemical/x-csml csp application/vnd.commonspace css text/css cst application/x-director csv text/csv cu application/cu-seeme curl text/vnd.curl cww application/prs.cww cxt application/x-director cxx text/x-c dae model/vnd.collada+xml daf application/vnd.mobius.daf dart application/vnd.dart dataless application/vnd.fdsn.seed davmount application/davmount+xml dbk application/docbook+xml dcr application/x-director dcurl text/vnd.curl.dcurl dd2 application/vnd.oma.dd2+xml ddd application/vnd.fujixerox.ddd deb application/x-debian-package def text/plain deploy application/octet-stream der application/x-x509-ca-cert dfac application/vnd.dreamfactory dgc application/x-dgc-compressed dib image/bmp dic text/x-c dir application/x-director dis application/vnd.mobius.dis dist application/octet-stream distz application/octet-stream djv image/vnd.djvu djvu image/vnd.djvu dll application/x-msdownload dmg application/x-apple-diskimage dmp application/vnd.tcpdump.pcap dms application/octet-stream dna application/vnd.dna doc application/msword docm application/vnd.ms-word.document.macroenabled.12 docx application/vnd.openxmlformats-officedocument.wordprocessingml.document dot application/msword dotm application/vnd.ms-word.template.macroenabled.12 dotx application/vnd.openxmlformats-officedocument.wordprocessingml.template dp application/vnd.osgi.dp dpg application/vnd.dpgraph dra audio/vnd.dra dsc text/prs.lines.tag dssc application/dssc+der dtb application/x-dtbook+xml dtd application/xml-dtd dts audio/vnd.dts dtshd audio/vnd.dts.hd dump application/octet-stream dv video/x-dv dvb video/vnd.dvb.file dvi application/x-dvi dwf model/vnd.dwf dwg image/vnd.dwg dxf image/vnd.dxf dxp application/vnd.spotfire.dxp dxr application/x-director ecelp4800 audio/vnd.nuera.ecelp4800 ecelp7470 audio/vnd.nuera.ecelp7470 ecelp9600 audio/vnd.nuera.ecelp9600 ecma application/ecmascript edm application/vnd.novadigm.edm edx application/vnd.novadigm.edx efif application/vnd.picsel ei6 application/vnd.pg.osasli elc application/octet-stream emf application/x-msmetafile eml message/rfc822 emma application/emma+xml emz application/x-msmetafile eol audio/vnd.digital-winds eot application/vnd.ms-fontobject eps application/postscript epub application/epub+zip es3 application/vnd.eszigno3+xml esa application/vnd.osgi.subsystem esf application/vnd.epson.esf et3 application/vnd.eszigno3+xml etx text/x-setext eva application/x-eva evy application/x-envoy exe application/octet-stream exi application/exi ext application/vnd.novadigm.ext ez application/andrew-inset ez2 application/vnd.ezpix-album ez3 application/vnd.ezpix-package f text/x-fortran f4v video/x-f4v f77 text/x-fortran f90 text/x-fortran fbs image/vnd.fastbidsheet fcdt application/vnd.adobe.formscentral.fcdt fcs application/vnd.isac.fcs fdf application/vnd.fdf fe_launch application/vnd.denovo.fcselayout-link fg5 application/vnd.fujitsu.oasysgp fgd application/x-director fh image/x-freehand fh4 image/x-freehand fh5 image/x-freehand fh7 image/x-freehand fhc image/x-freehand fig application/x-xfig flac audio/flac fli video/x-fli flo application/vnd.micrografx.flo flv video/x-flv flw application/vnd.kde.kivio flx text/vnd.fmi.flexstor fly text/vnd.fly fm application/vnd.framemaker fnc application/vnd.frogans.fnc for text/x-fortran fpx image/vnd.fpx frame application/vnd.framemaker fsc application/vnd.fsc.weblaunch fst image/vnd.fst ftc application/vnd.fluxtime.clip fti application/vnd.anser-web-funds-transfer-initiation fvt video/vnd.fvt fxp application/vnd.adobe.fxp fxpl application/vnd.adobe.fxp fzs application/vnd.fuzzysheet g2w application/vnd.geoplan g3 image/g3fax g3w application/vnd.geospace gac application/vnd.groove-account gam application/x-tads gbr application/rpki-ghostbusters gca application/x-gca-compressed gdl model/vnd.gdl geo application/vnd.dynageo gex application/vnd.geometry-explorer ggb application/vnd.geogebra.file ggt application/vnd.geogebra.tool ghf application/vnd.groove-help gif image/gif gim application/vnd.groove-identity-message gml application/gml+xml gmx application/vnd.gmx gnumeric application/x-gnumeric gph application/vnd.flographit gpx application/gpx+xml gqf application/vnd.grafeq gqs application/vnd.grafeq gram application/srgs gramps application/x-gramps-xml gre application/vnd.geometry-explorer grv application/vnd.groove-injector grxml application/srgs+xml gsf application/x-font-ghostscript gtar application/x-gtar gtm application/vnd.groove-tool-message gtw model/vnd.gtw gv text/vnd.graphviz gxf application/gxf gxt application/vnd.geonext gz application/x-gzip h text/x-c h261 video/h261 h263 video/h263 h264 video/h264 hal application/vnd.hal+xml hbci application/vnd.hbci hdf application/x-hdf hh text/x-c hlp application/winhlp hpgl application/vnd.hp-hpgl hpid application/vnd.hp-hpid hps application/vnd.hp-hps hqx application/mac-binhex40 htc text/x-component htke application/vnd.kenameaapp htm text/html html text/html hvd application/vnd.yamaha.hv-dic hvp application/vnd.yamaha.hv-voice hvs application/vnd.yamaha.hv-script i2g application/vnd.intergeo icc application/vnd.iccprofile ice x-conference/x-cooltalk icm application/vnd.iccprofile ico image/x-icon ics text/calendar ief image/ief ifb text/calendar ifm application/vnd.shana.informed.formdata iges model/iges igl application/vnd.igloader igm application/vnd.insors.igm igs model/iges igx application/vnd.micrografx.igx iif application/vnd.shana.informed.interchange imp application/vnd.accpac.simply.imp ims application/vnd.ms-ims in text/plain ink application/inkml+xml inkml application/inkml+xml install application/x-install-instructions iota application/vnd.astraea-software.iota ipfix application/ipfix ipk application/vnd.shana.informed.package irm application/vnd.ibm.rights-management irp application/vnd.irepository.package+xml iso application/x-iso9660-image itp application/vnd.shana.informed.formtemplate ivp application/vnd.immervision-ivp ivu application/vnd.immervision-ivu jad text/vnd.sun.j2me.app-descriptor jam application/vnd.jam jar application/java-archive java text/x-java-source jisp application/vnd.jisp jlt application/vnd.hp-jlyt jnlp application/x-java-jnlp-file joda application/vnd.joost.joda-archive jpe image/jpeg jpeg image/jpeg jpg image/jpeg jpgm video/jpm jpgv video/jpeg jpm video/jpm js application/javascript jsf text/plain json application/json jsonml application/jsonml+json jspf text/plain kar audio/midi karbon application/vnd.kde.karbon kfo application/vnd.kde.kformula kia application/vnd.kidspiration kml application/vnd.google-earth.kml+xml kmz application/vnd.google-earth.kmz kne application/vnd.kinar knp application/vnd.kinar kon application/vnd.kde.kontour kpr application/vnd.kde.kpresenter kpt application/vnd.kde.kpresenter kpxx application/vnd.ds-keypoint ksp application/vnd.kde.kspread ktr application/vnd.kahootz ktx image/ktx ktz application/vnd.kahootz kwd application/vnd.kde.kword kwt application/vnd.kde.kword lasxml application/vnd.las.las+xml latex application/x-latex lbd application/vnd.llamagraphics.life-balance.desktop lbe application/vnd.llamagraphics.life-balance.exchange+xml les application/vnd.hhe.lesson-player lha application/x-lzh-compressed link66 application/vnd.route66.link66+xml list text/plain list3820 application/vnd.ibm.modcap listafp application/vnd.ibm.modcap lnk application/x-ms-shortcut log text/plain lostxml application/lost+xml lrf application/octet-stream lrm application/vnd.ms-lrm ltf application/vnd.frogans.ltf lvp audio/vnd.lucent.voice lwp application/vnd.lotus-wordpro lzh application/x-lzh-compressed m13 application/x-msmediaview m14 application/x-msmediaview m1v video/mpeg m21 application/mp21 m2a audio/mpeg m2v video/mpeg m3a audio/mpeg m3u audio/x-mpegurl m3u8 application/vnd.apple.mpegurl m4a audio/mp4 m4b audio/mp4 m4r audio/mp4 m4u video/vnd.mpegurl m4v video/mp4 ma application/mathematica mac image/x-macpaint mads application/mads+xml mag application/vnd.ecowin.chart maker application/vnd.framemaker man text/troff mar application/octet-stream mathml application/mathml+xml mb application/mathematica mbk application/vnd.mobius.mbk mbox application/mbox mc1 application/vnd.medcalcdata mcd application/vnd.mcd mcurl text/vnd.curl.mcurl mdb application/x-msaccess mdi image/vnd.ms-modi me text/troff mesh model/mesh meta4 application/metalink4+xml metalink application/metalink+xml mets application/mets+xml mfm application/vnd.mfmp mft application/rpki-manifest mgp application/vnd.osgeo.mapguide.package mgz application/vnd.proteus.magazine mid audio/midi midi audio/midi mie application/x-mie mif application/x-mif mime message/rfc822 mj2 video/mj2 mjp2 video/mj2 mk3d video/x-matroska mka audio/x-matroska mks video/x-matroska mkv video/x-matroska mlp application/vnd.dolby.mlp mmd application/vnd.chipnuts.karaoke-mmd mmf application/vnd.smaf mmr image/vnd.fujixerox.edmics-mmr mng video/x-mng mny application/x-msmoney mobi application/x-mobipocket-ebook mods application/mods+xml mov video/quicktime movie video/x-sgi-movie mp1 audio/mpeg mp2 audio/mpeg mp21 application/mp21 mp2a audio/mpeg mp3 audio/mpeg mp4 video/mp4 mp4a audio/mp4 mp4s application/mp4 mp4v video/mp4 mpa audio/mpeg mpc application/vnd.mophun.certificate mpe video/mpeg mpeg video/mpeg mpega audio/x-mpeg mpg video/mpeg mpg4 video/mp4 mpga audio/mpeg mpkg application/vnd.apple.installer+xml mpm application/vnd.blueice.multipass mpn application/vnd.mophun.application mpp application/vnd.ms-project mpt application/vnd.ms-project mpv2 video/mpeg2 mpy application/vnd.ibm.minipay mqy application/vnd.mobius.mqy mrc application/marc mrcx application/marcxml+xml ms text/troff mscml application/mediaservercontrol+xml mseed application/vnd.fdsn.mseed mseq application/vnd.mseq msf application/vnd.epson.msf msh model/mesh msi application/x-msdownload msl application/vnd.mobius.msl msty application/vnd.muvee.style mts model/vnd.mts mus application/vnd.musician musicxml application/vnd.recordare.musicxml+xml mvb application/x-msmediaview mwf application/vnd.mfer mxf application/mxf mxl application/vnd.recordare.musicxml mxml application/xv+xml mxs application/vnd.triscape.mxs mxu video/vnd.mpegurl n-gage application/vnd.nokia.n-gage.symbian.install n3 text/n3 nb application/mathematica nbp application/vnd.wolfram.player nc application/x-netcdf ncx application/x-dtbncx+xml nfo text/x-nfo ngdat application/vnd.nokia.n-gage.data nitf application/vnd.nitf nlu application/vnd.neurolanguage.nlu nml application/vnd.enliven nnd application/vnd.noblenet-directory nns application/vnd.noblenet-sealer nnw application/vnd.noblenet-web npx image/vnd.net-fpx nsc application/x-conference nsf application/vnd.lotus-notes ntf application/vnd.nitf nzb application/x-nzb oa2 application/vnd.fujitsu.oasys2 oa3 application/vnd.fujitsu.oasys3 oas application/vnd.fujitsu.oasys obd application/x-msbinder obj application/x-tgif oda application/oda odb application/vnd.oasis.opendocument.database odc application/vnd.oasis.opendocument.chart odf application/vnd.oasis.opendocument.formula odft application/vnd.oasis.opendocument.formula-template odg application/vnd.oasis.opendocument.graphics odi application/vnd.oasis.opendocument.image odm application/vnd.oasis.opendocument.text-master odp application/vnd.oasis.opendocument.presentation ods application/vnd.oasis.opendocument.spreadsheet odt application/vnd.oasis.opendocument.text oga audio/ogg ogg audio/ogg ogv video/ogg ogx application/ogg omdoc application/omdoc+xml onepkg application/onenote onetmp application/onenote onetoc application/onenote onetoc2 application/onenote opf application/oebps-package+xml opml text/x-opml oprc application/vnd.palm org application/vnd.lotus-organizer osf application/vnd.yamaha.openscoreformat osfpvg application/vnd.yamaha.openscoreformat.osfpvg+xml otc application/vnd.oasis.opendocument.chart-template otf application/x-font-otf otg application/vnd.oasis.opendocument.graphics-template oth application/vnd.oasis.opendocument.text-web oti application/vnd.oasis.opendocument.image-template otp application/vnd.oasis.opendocument.presentation-template ots application/vnd.oasis.opendocument.spreadsheet-template ott application/vnd.oasis.opendocument.text-template oxps application/oxps oxt application/vnd.openofficeorg.extension p text/x-pascal p10 application/pkcs10 p12 application/x-pkcs12 p7b application/x-pkcs7-certificates p7c application/pkcs7-mime p7m application/pkcs7-mime p7r application/x-pkcs7-certreqresp p7s application/pkcs7-signature p8 application/pkcs8 pas text/x-pascal paw application/vnd.pawaafile pbd application/vnd.powerbuilder6 pbm image/x-portable-bitmap pcap application/vnd.tcpdump.pcap pcf application/x-font-pcf pcl application/vnd.hp-pcl pclxl application/vnd.hp-pclxl pct image/pict pcurl application/vnd.curl.pcurl pcx image/x-pcx pdb application/vnd.palm pdf application/pdf pfa application/x-font-type1 pfb application/x-font-type1 pfm application/x-font-type1 pfr application/font-tdpfr pfx application/x-pkcs12 pgm image/x-portable-graymap pgn application/x-chess-pgn pgp application/pgp-encrypted pic image/pict pict image/pict pkg application/octet-stream pki application/pkixcmp pkipath application/pkix-pkipath plb application/vnd.3gpp.pic-bw-large plc application/vnd.mobius.plc plf application/vnd.pocketlearn pls audio/x-scpls pml application/vnd.ctc-posml png image/png pnm image/x-portable-anymap pnt image/x-macpaint portpkg application/vnd.macports.portpkg pot application/vnd.ms-powerpoint potm application/vnd.ms-powerpoint.template.macroenabled.12 potx application/vnd.openxmlformats-officedocument.presentationml.template ppam application/vnd.ms-powerpoint.addin.macroenabled.12 ppd application/vnd.cups-ppd ppm image/x-portable-pixmap pps application/vnd.ms-powerpoint ppsm application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsx application/vnd.openxmlformats-officedocument.presentationml.slideshow ppt application/vnd.ms-powerpoint pptm application/vnd.ms-powerpoint.presentation.macroenabled.12 pptx application/vnd.openxmlformats-officedocument.presentationml.presentation pqa application/vnd.palm prc application/x-mobipocket-ebook pre application/vnd.lotus-freelance prf application/pics-rules ps application/postscript psb application/vnd.3gpp.pic-bw-small psd image/vnd.adobe.photoshop psf application/x-font-linux-psf pskcxml application/pskc+xml ptid application/vnd.pvi.ptid1 pub application/x-mspublisher pvb application/vnd.3gpp.pic-bw-var pwn application/vnd.3m.post-it-notes pya audio/vnd.ms-playready.media.pya pyv video/vnd.ms-playready.media.pyv qam application/vnd.epson.quickanime qbo application/vnd.intu.qbo qfx application/vnd.intu.qfx qps application/vnd.publishare-delta-tree qt video/quicktime qti image/x-quicktime qtif image/x-quicktime qwd application/vnd.quark.quarkxpress qwt application/vnd.quark.quarkxpress qxb application/vnd.quark.quarkxpress qxd application/vnd.quark.quarkxpress qxl application/vnd.quark.quarkxpress qxt application/vnd.quark.quarkxpress ra audio/x-pn-realaudio ram audio/x-pn-realaudio rar application/x-rar-compressed ras image/x-cmu-raster rcprofile application/vnd.ipunplugged.rcprofile rdf application/rdf+xml rdz application/vnd.data-vision.rdz rep application/vnd.businessobjects res application/x-dtbresource+xml rgb image/x-rgb rif application/reginfo+xml rip audio/vnd.rip ris application/x-research-info-systems rl application/resource-lists+xml rlc image/vnd.fujixerox.edmics-rlc rld application/resource-lists-diff+xml rm application/vnd.rn-realmedia rmi audio/midi rmp audio/x-pn-realaudio-plugin rms application/vnd.jcp.javame.midlet-rms rmvb application/vnd.rn-realmedia-vbr rnc application/relax-ng-compact-syntax roa application/rpki-roa roff text/troff rp9 application/vnd.cloanto.rp9 rpss application/vnd.nokia.radio-presets rpst application/vnd.nokia.radio-preset rq application/sparql-query rs application/rls-services+xml rsd application/rsd+xml rss application/rss+xml rtf application/rtf rtx text/richtext s text/x-asm s3m audio/s3m saf application/vnd.yamaha.smaf-audio sbml application/sbml+xml sc application/vnd.ibm.secure-container scd application/x-msschedule scm application/vnd.lotus-screencam scq application/scvp-cv-request scs application/scvp-cv-response scurl text/vnd.curl.scurl sda application/vnd.stardivision.draw sdc application/vnd.stardivision.calc sdd application/vnd.stardivision.impress sdkd application/vnd.solent.sdkm+xml sdkm application/vnd.solent.sdkm+xml sdp application/sdp sdw application/vnd.stardivision.writer see application/vnd.seemail seed application/vnd.fdsn.seed sema application/vnd.sema semd application/vnd.semd semf application/vnd.semf ser application/java-serialized-object setpay application/set-payment-initiation setreg application/set-registration-initiation sfd-hdstx application/vnd.hydrostatix.sof-data sfs application/vnd.spotfire.sfs sfv text/x-sfv sgi image/sgi sgl application/vnd.stardivision.writer-global sgm text/sgml sgml text/sgml sh application/x-sh shar application/x-shar shf application/shf+xml sid image/x-mrsid-image sig application/pgp-signature sil audio/silk silo model/mesh sis application/vnd.symbian.install sisx application/vnd.symbian.install sit application/x-stuffit sitx application/x-stuffitx skd application/vnd.koan skm application/vnd.koan skp application/vnd.koan skt application/vnd.koan sldm application/vnd.ms-powerpoint.slide.macroenabled.12 sldx application/vnd.openxmlformats-officedocument.presentationml.slide slt application/vnd.epson.salt sm application/vnd.stepmania.stepchart smf application/vnd.stardivision.math smi application/smil+xml smil application/smil+xml smv video/x-smv smzip application/vnd.stepmania.package snd audio/basic snf application/x-font-snf so application/octet-stream spc application/x-pkcs7-certificates spf application/vnd.yamaha.smaf-phrase spl application/x-futuresplash spot text/vnd.in3d.spot spp application/scvp-vp-response spq application/scvp-vp-request spx audio/ogg sql application/x-sql src application/x-wais-source srt application/x-subrip sru application/sru+xml srx application/sparql-results+xml ssdl application/ssdl+xml sse application/vnd.kodak-descriptor ssf application/vnd.epson.ssf ssml application/ssml+xml st application/vnd.sailingtracker.track stc application/vnd.sun.xml.calc.template std application/vnd.sun.xml.draw.template stf application/vnd.wt.stf sti application/vnd.sun.xml.impress.template stk application/hyperstudio stl application/vnd.ms-pki.stl str application/vnd.pg.format stw application/vnd.sun.xml.writer.template sub text/vnd.dvb.subtitle sus application/vnd.sus-calendar susp application/vnd.sus-calendar sv4cpio application/x-sv4cpio sv4crc application/x-sv4crc svc application/vnd.dvb.service svd application/vnd.svd svg image/svg+xml svgz image/svg+xml swa application/x-director swf application/x-shockwave-flash swi application/vnd.aristanetworks.swi sxc application/vnd.sun.xml.calc sxd application/vnd.sun.xml.draw sxg application/vnd.sun.xml.writer.global sxi application/vnd.sun.xml.impress sxm application/vnd.sun.xml.math sxw application/vnd.sun.xml.writer t text/troff t3 application/x-t3vm-image taglet application/vnd.mynfc tao application/vnd.tao.intent-module-archive tar application/x-tar tcap application/vnd.3gpp2.tcap tcl application/x-tcl teacher application/vnd.smart.teacher tei application/tei+xml teicorpus application/tei+xml tex application/x-tex texi application/x-texinfo texinfo application/x-texinfo text text/plain tfi application/thraud+xml tfm application/x-tex-tfm tga image/x-tga thmx application/vnd.ms-officetheme tif image/tiff tiff image/tiff tmo application/vnd.tmobile-livetv torrent application/x-bittorrent tpl application/vnd.groove-tool-template tpt application/vnd.trid.tpt tr text/troff tra application/vnd.trueapp trm application/x-msterminal tsd application/timestamped-data tsv text/tab-separated-values ttc application/x-font-ttf ttf application/x-font-ttf ttl text/turtle twd application/vnd.simtech-mindmapper twds application/vnd.simtech-mindmapper txd application/vnd.genomatix.tuxedo txf application/vnd.mobius.txf txt text/plain u32 application/x-authorware-bin udeb application/x-debian-package ufd application/vnd.ufdl ufdl application/vnd.ufdl ulw audio/basic ulx application/x-glulx umj application/vnd.umajin unityweb application/vnd.unity uoml application/vnd.uoml+xml uri text/uri-list uris text/uri-list urls text/uri-list ustar application/x-ustar utz application/vnd.uiq.theme uu text/x-uuencode uva audio/vnd.dece.audio uvd application/vnd.dece.data uvf application/vnd.dece.data uvg image/vnd.dece.graphic uvh video/vnd.dece.hd uvi image/vnd.dece.graphic uvm video/vnd.dece.mobile uvp video/vnd.dece.pd uvs video/vnd.dece.sd uvt application/vnd.dece.ttml+xml uvu video/vnd.uvvu.mp4 uvv video/vnd.dece.video uvva audio/vnd.dece.audio uvvd application/vnd.dece.data uvvf application/vnd.dece.data uvvg image/vnd.dece.graphic uvvh video/vnd.dece.hd uvvi image/vnd.dece.graphic uvvm video/vnd.dece.mobile uvvp video/vnd.dece.pd uvvs video/vnd.dece.sd uvvt application/vnd.dece.ttml+xml uvvu video/vnd.uvvu.mp4 uvvv video/vnd.dece.video uvvx application/vnd.dece.unspecified uvvz application/vnd.dece.zip uvx application/vnd.dece.unspecified uvz application/vnd.dece.zip vcard text/vcard vcd application/x-cdlink vcf text/x-vcard vcg application/vnd.groove-vcard vcs text/x-vcalendar vcx application/vnd.vcx vis application/vnd.visionary viv video/vnd.vivo vob video/x-ms-vob vor application/vnd.stardivision.writer vox application/x-authorware-bin vrml model/vrml vsd application/vnd.visio vsf application/vnd.vsf vss application/vnd.visio vst application/vnd.visio vsw application/vnd.visio vtu model/vnd.vtu vxml application/voicexml+xml w3d application/x-director wad application/x-doom wav audio/x-wav wax audio/x-ms-wax wbmp image/vnd.wap.wbmp wbs application/vnd.criticaltools.wbs+xml wbxml application/vnd.wap.wbxml wcm application/vnd.ms-works wdb application/vnd.ms-works wdp image/vnd.ms-photo weba audio/webm webm video/webm webp image/webp wg application/vnd.pmi.widget wgt application/widget wks application/vnd.ms-works wm video/x-ms-wm wma audio/x-ms-wma wmd application/x-ms-wmd wmf application/x-msmetafile wml text/vnd.wap.wml wmlc application/vnd.wap.wmlc wmls text/vnd.wap.wmlscript wmlsc application/vnd.wap.wmlscriptc wmv video/x-ms-wmv wmx video/x-ms-wmx wmz application/x-msmetafile woff application/x-font-woff wpd application/vnd.wordperfect wpl application/vnd.ms-wpl wps application/vnd.ms-works wqd application/vnd.wqd wri application/x-mswrite wrl model/vrml wsdl application/wsdl+xml wspolicy application/wspolicy+xml wtb application/vnd.webturbo wvx video/x-ms-wvx x32 application/x-authorware-bin x3d model/x3d+xml x3db model/x3d+binary x3dbz model/x3d+binary x3dv model/x3d+vrml x3dvz model/x3d+vrml x3dz model/x3d+xml xaml application/xaml+xml xap application/x-silverlight-app xar application/vnd.xara xbap application/x-ms-xbap xbd application/vnd.fujixerox.docuworks.binder xbm image/x-xbitmap xdf application/xcap-diff+xml xdm application/vnd.syncml.dm+xml xdp application/vnd.adobe.xdp+xml xdssc application/dssc+xml xdw application/vnd.fujixerox.docuworks xenc application/xenc+xml xer application/patch-ops-error+xml xfdf application/vnd.adobe.xfdf xfdl application/vnd.xfdl xht application/xhtml+xml xhtml application/xhtml+xml xhvml application/xv+xml xif image/vnd.xiff xla application/vnd.ms-excel xlam application/vnd.ms-excel.addin.macroenabled.12 xlc application/vnd.ms-excel xlf application/x-xliff+xml xlm application/vnd.ms-excel xls application/vnd.ms-excel xlsb application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsm application/vnd.ms-excel.sheet.macroenabled.12 xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlt application/vnd.ms-excel xltm application/vnd.ms-excel.template.macroenabled.12 xltx application/vnd.openxmlformats-officedocument.spreadsheetml.template xlw application/vnd.ms-excel xm audio/xm xml application/xml xo application/vnd.olpc-sugar xop application/xop+xml xpi application/x-xpinstall xpl application/xproc+xml xpm image/x-xpixmap xpr application/vnd.is-xpr xps application/vnd.ms-xpsdocument xpw application/vnd.intercon.formnet xpx application/vnd.intercon.formnet xsl application/xml xslt application/xslt+xml xsm application/vnd.syncml+xml xspf application/xspf+xml xul application/vnd.mozilla.xul+xml xvm application/xv+xml xvml application/xv+xml xwd image/x-xwindowdump xyz chemical/x-xyz xz application/x-xz yang application/yang yin application/yin+xml z application/x-compress Z application/x-compress z1 application/x-zmachine z2 application/x-zmachine z3 application/x-zmachine z4 application/x-zmachine z5 application/x-zmachine z6 application/x-zmachine z7 application/x-zmachine z8 application/x-zmachine zaz application/vnd.zzazz.deck+xml zip application/zip zir application/vnd.zul zirz application/vnd.zul zmm application/vnd.handheld-entertainment+xml index.html index.htm index.jsp tomcat7-7.0.52/conf/server.xml0000644000175100017510000001444312271015321016120 0ustar locutuslocutus tomcat7-7.0.52/conf/catalina.policy0000644000175100017510000002774112271015321017072 0ustar locutuslocutus// Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You 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. // ============================================================================ // catalina.policy - Security Policy Permissions for Tomcat 7 // // This file contains a default set of security policies to be enforced (by the // JVM) when Catalina is executed with the "-security" option. In addition // to the permissions granted here, the following additional permissions are // granted to each web application: // // * Read access to the web application's document root directory // * Read, write and delete access to the web application's working directory // ============================================================================ // ========== SYSTEM CODE PERMISSIONS ========================================= // These permissions apply to javac grant codeBase "file:${java.home}/lib/-" { permission java.security.AllPermission; }; // These permissions apply to all shared system extensions grant codeBase "file:${java.home}/jre/lib/ext/-" { permission java.security.AllPermission; }; // These permissions apply to javac when ${java.home] points at $JAVA_HOME/jre grant codeBase "file:${java.home}/../lib/-" { permission java.security.AllPermission; }; // These permissions apply to all shared system extensions when // ${java.home} points at $JAVA_HOME/jre grant codeBase "file:${java.home}/lib/ext/-" { permission java.security.AllPermission; }; // ========== CATALINA CODE PERMISSIONS ======================================= // These permissions apply to the daemon code grant codeBase "file:${catalina.home}/bin/commons-daemon.jar" { permission java.security.AllPermission; }; // These permissions apply to the logging API // Note: If tomcat-juli.jar is in ${catalina.base} and not in ${catalina.home}, // update this section accordingly. // grant codeBase "file:${catalina.base}/bin/tomcat-juli.jar" {..} grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" { permission java.io.FilePermission "${java.home}${file.separator}lib${file.separator}logging.properties", "read"; permission java.io.FilePermission "${catalina.base}${file.separator}conf${file.separator}logging.properties", "read"; permission java.io.FilePermission "${catalina.base}${file.separator}logs", "read, write"; permission java.io.FilePermission "${catalina.base}${file.separator}logs${file.separator}*", "read, write"; permission java.lang.RuntimePermission "shutdownHooks"; permission java.lang.RuntimePermission "getClassLoader"; permission java.lang.RuntimePermission "setContextClassLoader"; permission java.util.logging.LoggingPermission "control"; permission java.util.PropertyPermission "java.util.logging.config.class", "read"; permission java.util.PropertyPermission "java.util.logging.config.file", "read"; permission java.util.PropertyPermission "org.apache.juli.ClassLoaderLogManager.debug", "read"; permission java.util.PropertyPermission "catalina.base", "read"; // Note: To enable per context logging configuration, permit read access to // the appropriate file. Be sure that the logging configuration is // secure before enabling such access. // E.g. for the examples web application (uncomment and unwrap // the following to be on a single line): // permission java.io.FilePermission "${catalina.base}${file.separator} // webapps${file.separator}examples${file.separator}WEB-INF // ${file.separator}classes${file.separator}logging.properties", "read"; }; // These permissions apply to the server startup code grant codeBase "file:${catalina.home}/bin/bootstrap.jar" { permission java.security.AllPermission; }; // These permissions apply to the servlet API classes // and those that are shared across all class loaders // located in the "lib" directory grant codeBase "file:${catalina.home}/lib/-" { permission java.security.AllPermission; }; // If using a per instance lib directory, i.e. ${catalina.base}/lib, // then the following permission will need to be uncommented // grant codeBase "file:${catalina.base}/lib/-" { // permission java.security.AllPermission; // }; // ========== WEB APPLICATION PERMISSIONS ===================================== // These permissions are granted by default to all web applications // In addition, a web application will be given a read FilePermission // and JndiPermission for all files and directories in its document root. grant { // Required for JNDI lookup of named JDBC DataSource's and // javamail named MimePart DataSource used to send mail permission java.util.PropertyPermission "java.home", "read"; permission java.util.PropertyPermission "java.naming.*", "read"; permission java.util.PropertyPermission "javax.sql.*", "read"; // OS Specific properties to allow read access permission java.util.PropertyPermission "os.name", "read"; permission java.util.PropertyPermission "os.version", "read"; permission java.util.PropertyPermission "os.arch", "read"; permission java.util.PropertyPermission "file.separator", "read"; permission java.util.PropertyPermission "path.separator", "read"; permission java.util.PropertyPermission "line.separator", "read"; // JVM properties to allow read access permission java.util.PropertyPermission "java.version", "read"; permission java.util.PropertyPermission "java.vendor", "read"; permission java.util.PropertyPermission "java.vendor.url", "read"; permission java.util.PropertyPermission "java.class.version", "read"; permission java.util.PropertyPermission "java.specification.version", "read"; permission java.util.PropertyPermission "java.specification.vendor", "read"; permission java.util.PropertyPermission "java.specification.name", "read"; permission java.util.PropertyPermission "java.vm.specification.version", "read"; permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; permission java.util.PropertyPermission "java.vm.specification.name", "read"; permission java.util.PropertyPermission "java.vm.version", "read"; permission java.util.PropertyPermission "java.vm.vendor", "read"; permission java.util.PropertyPermission "java.vm.name", "read"; // Required for OpenJMX permission java.lang.RuntimePermission "getAttribute"; // Allow read of JAXP compliant XML parser debug permission java.util.PropertyPermission "jaxp.debug", "read"; // All JSPs need to be able to read this package permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat"; // Precompiled JSPs need access to these packages. permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.el"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime.*"; // Precompiled JSPs need access to these system properties. permission java.util.PropertyPermission "org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "read"; permission java.util.PropertyPermission "org.apache.el.parser.COERCE_TO_ZERO", "read"; // The cookie code needs these. permission java.util.PropertyPermission "org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "read"; permission java.util.PropertyPermission "org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING", "read"; permission java.util.PropertyPermission "org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR", "read"; // Applications using Comet need to be able to access this package permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.comet"; // Applications using the legacy WebSocket implementation need to be able to access this package permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.websocket"; // Applications using the JSR-356 WebSocket implementation need to be able to access these packages permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.websocket"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.websocket.server"; }; // The Manager application needs access to the following packages to support the // session display functionality. These settings support the following // configurations: // - default CATALINA_HOME == CATALINA_BASE // - CATALINA_HOME != CATALINA_BASE, per instance Manager in CATALINA_BASE // - CATALINA_HOME != CATALINA_BASE, shared Manager in CATALINA_HOME grant codeBase "file:${catalina.base}/webapps/manager/-" { permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.ha.session"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.util"; }; grant codeBase "file:${catalina.home}/webapps/manager/-" { permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.ha.session"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util"; permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.util"; }; // You can assign additional permissions to particular web applications by // adding additional "grant" entries here, based on the code base for that // application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files. // // Different permissions can be granted to JSP pages, classes loaded from // the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/ // directory, or even to individual jar files in the /WEB-INF/lib/ directory. // // For instance, assume that the standard "examples" application // included a JDBC driver that needed to establish a network connection to the // corresponding database and used the scrape taglib to get the weather from // the NOAA web server. You might create a "grant" entries like this: // // The permissions granted to the context root directory apply to JSP pages. // grant codeBase "file:${catalina.base}/webapps/examples/-" { // permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; // permission java.net.SocketPermission "*.noaa.gov:80", "connect"; // }; // // The permissions granted to the context WEB-INF/classes directory // grant codeBase "file:${catalina.base}/webapps/examples/WEB-INF/classes/-" { // }; // // The permission granted to your JDBC driver // grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/driver.jar!/-" { // permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; // }; // The permission granted to the scrape taglib // grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/scrape.jar!/-" { // permission java.net.SocketPermission "*.noaa.gov:80", "connect"; // }; tomcat7-7.0.52/conf/context.xml0000644000175100017510000000256212271015321016275 0ustar locutuslocutus WEB-INF/web.xml tomcat7-7.0.52/conf/logging.properties0000644000175100017510000000633012271015321017630 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler .handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler ############################################################ # Handler specific properties. # Describes specific configuration info for Handlers. ############################################################ 1catalina.org.apache.juli.FileHandler.level = FINE 1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 1catalina.org.apache.juli.FileHandler.prefix = catalina. 2localhost.org.apache.juli.FileHandler.level = FINE 2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 2localhost.org.apache.juli.FileHandler.prefix = localhost. 3manager.org.apache.juli.FileHandler.level = FINE 3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 3manager.org.apache.juli.FileHandler.prefix = manager. 4host-manager.org.apache.juli.FileHandler.level = FINE 4host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 4host-manager.org.apache.juli.FileHandler.prefix = host-manager. java.util.logging.ConsoleHandler.level = FINE java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter ############################################################ # Facility specific properties. # Provides extra control for each logger. ############################################################ org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.FileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.FileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.FileHandler # For example, set the org.apache.catalina.util.LifecycleBase logger to log # each component that extends LifecycleBase changing state: #org.apache.catalina.util.LifecycleBase.level = FINE # To see debug messages in TldLocationsCache, uncomment the following line: #org.apache.jasper.compiler.TldLocationsCache.level = FINE tomcat7-7.0.52/webapps/0000755000175100017510000000000012301126373014602 5ustar locutuslocutustomcat7-7.0.52/webapps/manager/0000755000175100017510000000000012301126372016213 5ustar locutuslocutustomcat7-7.0.52/webapps/manager/status.xsd0000644000175100017510000001042612271304167020267 0ustar locutuslocutus tomcat7-7.0.52/webapps/manager/META-INF/0000755000175100017510000000000012301126372017353 5ustar locutuslocutustomcat7-7.0.52/webapps/manager/META-INF/context.xml0000644000175100017510000000224312271304167021570 0ustar locutuslocutus tomcat7-7.0.52/webapps/manager/images/0000755000175100017510000000000012301126372017460 5ustar locutuslocutustomcat7-7.0.52/webapps/manager/images/tomcat.gif0000644000175100017510000000402211471741013021436 0ustar locutuslocutusGIF89a\Ҧ)u" GB4pl^Wr+дbp.!,\ dihbQ(l,LPC@>pxRq !Q_7eZ%HH`e %νJn_k(q4:Οbc7}" umx?"QU4 uGq[^&U&_[ Z'Z[wXD _ `mǩПV tu( Gd# ͿCGpv@3`@1`R ǏcU^5~tTxw̵ܜ֊YwQ H{n͛3L8nÝ2?n+:Pyտ숇OI5[pW/*@)otle-{a :U0/t$Y/a2Y΃_! D@f=@y@J׫L8 S gXP:$Pd>ډ`DN cB%1@PUE)CH" '"m0c b,8^qsٯ8 "ŇF.$fR98 $P!d 2I}Y%?.J2~`[ C'?Ia( 5aʂ聴LI̘Z FJ,%r`s]8rl6#L*<Ci~(fK0D+Zc 鎆m`jZc(ajE!ShzկJjNrKՀ V' x}Ho*$~C2.kHe 4HV%mH8anU]Q[+g4N {IPD=[!ʴ @!(S"gkZN?XƔ B{5?C@GI&_@w9e}# o:Mw9Q+ 4bg?xɍIc!;tomcat7-7.0.52/webapps/manager/images/code.gif0000644000175100017510000000061210457676032021075 0ustar locutuslocutusGIF89a000///111VVss]]߿..ڊEEJJ/10dd||22KK@@退NNN___kkŰOOO疖002,@pH,Py ((XP80"P, p< 7Zm#dBHSgxg ~E eh tE TqoDg F } B !g"u#$%&' ()*+N,+-.H//#+M00RSA;tomcat7-7.0.52/webapps/manager/images/void.gif0000644000175100017510000000005310457676032021123 0ustar locutuslocutusGIF89a! ,L;tomcat7-7.0.52/webapps/manager/images/add.gif0000644000175100017510000000201510457676032020712 0ustar locutuslocutusGIF89a# ac 4n _IUr 5؉P8Cޘ\CQJSYfĄ 1ݘ]@@CI[dÁ ӵ $ M>Aà ӖЋҠ ^UyI+ 8."0000026/%A/ Йщѕnd>,אЗтҐ~wđ */Bۓ ǩ5/#Ү,-IڏJKR):1!zohxw속7 EP*Odk2wNh2 FR%e*rC), pp&d p(@0p(X @P ,\A<|yD#H0*Vh 1da5lQu:v B)0#H(Y¤'PHIa *V`ɢe .Dz L1c)cCgФQM7ođ3EsԱsO={30~ $hEQ ,7УG(@@;tomcat7-7.0.52/webapps/manager/images/design.gif0000644000175100017510000000114010457676032021431 0ustar locutuslocutusGIF89a???>>>??=@@@=?>>@?*EVeOB?2- z%sJb*FT1Iaooopno@>?Ͽ®¬л~nod|dSkS#}&IJϹͫЦΠБu܃~mskq*w/¯в,ŀ  !"#$%%&&̃''()*++*,-؊./012345667(89:;<=>>? 2H!CgDnPA$%!I4M]ɓ'"Rd"!,ɬ4)Ҥl;tomcat7-7.0.52/webapps/manager/images/fix.gif0000644000175100017510000000053110457676032020751 0ustar locutuslocutusGIF89a OOO{st\N7J<,BK2S .3J2QCK5Q 0QK3R R>O9輱3,~@ȤrY\2K`* B@8 MHN`eCQh8$9`)FCX^B !"K#$C%&'()FaJ*+zVB,&-.*/0V1234BþA;tomcat7-7.0.52/webapps/manager/images/docs.gif0000644000175100017510000000040510457676032021113 0ustar locutuslocutusGIF89a000///111߿/10NNN___ᰰOOO002, diA0(p `i A$&>bX4"M` i˜>Iv_P6.6F@ࢵњ B& Uf}vxr4lxy(-23!;tomcat7-7.0.52/webapps/manager/images/asf-logo.gif0000644000175100017510000001615710457676032021705 0ustar locutuslocutusGIF89ad~fff̙3olJff3OEfffOf3{7O33fffPPPf3333fN@EσYf/XTJϷTffffuf3ff3JmvdfffVPEOVNjE H̙f|~cv3fǰdlԮifIvt33gt|tA{F|{7-}L"Bjx̙OKVE휃0*PjOV]~ff33{M VJqYOCLVAMY UQPw{}Hm~_!tr lT=GQx|N\n{8QuNNNlUHiïNy/f3fQ̙!,d@H*\ȰÇ#JHŋ3jx1,HP8  =p(Pϟ@ JQ:(3ǧ a8 WhB+x FAK͛شB`ǀGfF!@ 5ᆄ+V(`f&<qbwRt@:uL@# Xz+1u@k̗q[W&tkA yB KE ``>CpA 7 W.t7CsjG(hB z6eh^k&U - }(\m]F% @4F +P"QY‘H^A4@W} X_A)P S h@Y lfolq9KkFm#*TxL-VWBf J(xhG{|dp\P (ܰ)74܀DCJRSYGk[by]w.Øk$E\* a&n} D`;=[CMvz7/y?}uwHD/}>͓~Y/ A BgoC@9P̠2,/Bp`FBUՂ%7&70` qXѡ3W1AW@PO/ӜB+xFʉKsVQGez ϤYm|~^ѱ!: <`Zo>06fE"D=I"E* YPpOM^D >AԻmkcB3JWB,3^~kw1 TMؖ -A*ʍ6q(BW(H! GGFdk6Ǔ bA4Ѐء m`9K0^Mk DC8)- hB~P-s!D ]\2Es!`R-,EЀnv@7@S@h %!OHjD@CKBCNpHJ) [ׄTs>Ǖ1{2JC14,c߳mHhd`Qz3:$tCYb:le؍ru臽vc5 .k^zasnZ?G$ժLݡ-qzC6wLj7]겖UucDz2~@s˳ۄδtil~X$򖱤-HZ!"3mo D  ǹQxvϋ1lJN0q#_[I.wL@!/N>2!C$uAo~dm%Pᄏҝ+%Hfz:>5Hb1%kvtwo ڈ#B3h$* h3ELarđ` 6a.vWA1w/X'cWmpyq6X/|!_~Krf $+A5(+lG0A~(3Gmh@M[Jkj@ ,4HQɷ [vF'v 1fK]wI8j޲ V}]a1`"[ 8]hypNOG ن-mxˁRSI'*"ljw0R DUoBv@Ӷp7O M^R4}SST!uHNdc0"Q77 syC1~ P4(@PbPvGzg^uujUgeWrLK/1y[Y\ȅB &g0}(4)NBE*g.7ef&O@UOX% <9|nՄ1:"% W${f%gF;؄R@@=4mcROYX&`osqM4S4-E&XԅdTsWdp^ap/!N]u)apraLOq pO׃B@A9d>*"w\r{Jh_c\{WxUWKqɂ2ypUO0 >BsS٤~ 'lq vtBTv`irPu)1"m&iqW8WdΤ,)ג4ْwWS'CȂ$\L;95G!w$I^a:@qDYQodfKpdVqb]c9K!C5Y?g_V7ҕ]1|LCu%A1sg+4\g9d 8NUW8VyhuK]SX闊4&:ݕ,AL0ty㚥YC!v5i6IRI|a'x3 hV)ǩoi]S^_CgǙLhz^v:i*sY^$LBhq7exguٕFJf`lE  WR&7RVeOS%dg]lW7#ha%#f!7b1v63q0<22&624{6$-6ZIʜ D1ee<ifeDӥAdp$n?Y7$1cd9Î`ZQ/y4֡SL?) = S2کjZD:ڪgcr w,20<=:G ` !%`2P2@ ^H8^J RJ1kii'0'B "ĆEtyTi"x%_m&ER;lwln)PF}LGL_V('RpԮ] gCj gCIv1{}ŒLa?aб?e7WsSr@KUBZ ៨ k6i3isQDA$xs*Ү7'4D)>" 4z:8ZI؄ֵ FF~`#pNkD葨v$RBG1,,}THwI+,}qKw[qsKWpą4DEP#.E5l \K2s48%uez߱iǛhZ3| 0IBV9t $4pD}l"x!1WM!;J3~Wn7«Gqa3\ķ9{$Q 4|rc̿Y3zk8,qCroW}dh!Xʎm]1pnD"TLJ,/2T{.1Z_tWe̼PE1kJ7J'˥|8slX"!HI,pTt$BOǑkrya a$ QMÒP Cmv*0b"tIL+E$Bln}B'GW1+pPpRP@R=ZȿwiH:iǒRMɼ[M{?E^0]vƢ,;@E0&,P.Ru҂ۄxNa"0QE`SKehA`&M0/ Z鎚hOQ`čHas9 qV8;WG50 {p.os6Ex=CMcM `&vTP5/v$)WOH8GpL!KPYPO`tO&0޼qCta#/tM.X,!crҝ& WXs, ?0),a/&U/P}G.0ْm0~ NH;NMWP90p4uku|%1 1ԥ41;FBACiwAQ 0zV^/}oO_ XDŽ5\N` <1GUsd)i`Iݞ 4aaN 1᳇EauXX8^VvrBmawVM^9UXcɄٿ {A 0$H0À D0a@BC hq-`Aɏ%0aCD1M9I0Č) š0L8re̚YQVtVK%{rNNxq@^OjsCy,)pEia<1eLK0ʕxTVވ8g݁beYUC+U\J1}}yuŹOca-S>91d;6춠I'FË:semW >h㋮ .!I;M+žZAAlSQ9 /$1b#>yͿ-22$fS*ro5c !'#z3# ؼHI6O=׌TjȐ,h.D. S5'4uB>&QҳG1QʱpTSOMU8m@肽-X}$_.ٲeXafmڎZj[pw\r5\tUL+ե6dX]z]{|YQ:]3j_7asABaD_ ~ч 1He4EJwҩ H^ $*hD<%iy%%3kRT^+)cׅ0@wX'x-jP^f 'Zfb{kۘ꫒xkk,lT֓k71,n N BA$bV:sQJ;h3߃#\ƫr*u7_w:-Ȼԍݛ_zǾw7׽+ f%}MUΊp?p܍6E0e- 榷H,H?و$ |AX@T1ZNL JYN3eKNJE|{^wCOZ q-_g:@!&QKdbD(FQS4^@;tomcat7-7.0.52/webapps/manager/images/update.gif0000644000175100017510000000116310457676032021447 0ustar locutuslocutusGIF89a???>>>??=@@@=?>>@?*EVeOB?2- z%sJb*FT1Iaooopno@>?Ͽ ®¬2 Ģ5E:л~nod|d$,#}&Y\/t1 /%IJϹͫЦΠ7Бu܃Xjt܅ޡ*~mskq$**w/؆4q5 / ¯ -͵в#,؀  !"#$%&փ''()*++*,-./0123456789:;<=>(?@ABC1rI%K XǤ'PHB+qK,ZpE D(90a\S4`2dDEa0YZiRIH%M:(;tomcat7-7.0.52/webapps/manager/WEB-INF/0000755000175100017510000000000012301126372017242 5ustar locutuslocutustomcat7-7.0.52/webapps/manager/WEB-INF/web.xml0000644000175100017510000001550412271304167020554 0ustar locutuslocutus Tomcat Manager Application A scriptable management web application for the Tomcat Web Server; Manager lets you view, load/unload/etc particular web applications. Manager org.apache.catalina.manager.ManagerServlet debug 2 HTMLManager org.apache.catalina.manager.HTMLManagerServlet debug 2 52428800 52428800 0 Status org.apache.catalina.manager.StatusManagerServlet debug 0 JMXProxy org.apache.catalina.manager.JMXProxyServlet Manager /text/* Status /status/* JMXProxy /jmxproxy/* HTMLManager /html/* SetCharacterEncoding org.apache.catalina.filters.SetCharacterEncodingFilter encoding UTF-8 SetCharacterEncoding /* CSRF org.apache.catalina.filters.CsrfPreventionFilter entryPoints /html,/html/,/html/list,/index.jsp CSRF HTMLManager jsp HTML Manager interface (for humans) /html/* manager-gui Text Manager interface (for scripts) /text/* manager-script JMX Proxy interface /jmxproxy/* manager-jmx Status interface /status/* manager-gui manager-script manager-jmx manager-status BASIC Tomcat Manager Application The role that is required to access the HTML Manager pages manager-gui The role that is required to access the text Manager pages manager-script The role that is required to access the HTML JMX Proxy manager-jmx The role that is required to access to the Manager Status pages manager-status 401 /WEB-INF/jsp/401.jsp 403 /WEB-INF/jsp/403.jsp 404 /WEB-INF/jsp/404.jsp tomcat7-7.0.52/webapps/manager/WEB-INF/jsp/0000755000175100017510000000000012301126372020036 5ustar locutuslocutustomcat7-7.0.52/webapps/manager/WEB-INF/jsp/403.jsp0000644000175100017510000000764511656645503021114 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> 403 Access Denied

403 Access Denied

You are not authorized to view this page.

If you have already configured the Manager application to allow access and you have used your browsers back button, used a saved book-mark or similar then you may have triggered the cross-site request forgery (CSRF) protection that has been enabled for the HTML interface of the Manager application. You will need to reset this protection by returning to the main Manager page. Once you return to this page, you will be able to continue using the Manager appliction's HTML interface normally. If you continue to see this access denied message, check that you have the necessary permissions to access this application.

If you have not changed any configuration files, please examine the file conf/tomcat-users.xml in your installation. That file must contain the credentials to let you use this webapp.

For example, to add the manager-gui role to a user named tomcat with a password of s3cret, add the following to the config file listed above.

<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>

Note that for Tomcat 7 onwards, the roles required to use the manager application were changed from the single manager role to the following four roles. You will need to assign the role(s) required for the functionality you wish to access.

  • manager-gui - allows access to the HTML GUI and the status pages
  • manager-script - allows access to the text interface and the status pages
  • manager-jmx - allows access to the JMX proxy and the status pages
  • manager-status - allows access to the status pages only

The HTML interface is protected against CSRF but the text and JMX interfaces are not. To maintain the CSRF protection:

  • Users with the manager-gui role should not be granted either the manager-script or manager-jmx roles.
  • If the text or jmx interfaces are accessed through a browser (e.g. for testing since these interfaces are intended for tools not humans) then the browser must be closed afterwards to terminate the session.

For more information - please see the Manager App HOW-TO.

tomcat7-7.0.52/webapps/manager/WEB-INF/jsp/404.jsp0000644000175100017510000000504312271304167021073 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ page import="org.apache.catalina.util.RequestUtil" %> 404 Not found

404 Not found

The page you tried to access (<%=RequestUtil.filter((String) request.getAttribute( "javax.servlet.error.request_uri"))%>) does not exist.

The Manager application has been re-structured for Tomcat 7 onwards and some of URLs have changed. All URLs used to access the Manager application should now start with one of the following options:

  • <%=request.getContextPath()%>/html for the HTML GUI
  • <%=request.getContextPath()%>/text for the text interface
  • <%=request.getContextPath()%>/jmxproxy for the JMX proxy
  • <%=request.getContextPath()%>/status for the status pages

Note that the URL for the text interface has changed from "<%=request.getContextPath()%>" to "<%=request.getContextPath()%>/text".

You probably need to adjust the URL you are using to access the Manager application. However, there is always a chance you have found a bug in the Manager application. If you are sure you have found a bug, and that the bug has not already been reported, please report it to the Apache Tomcat team.

tomcat7-7.0.52/webapps/manager/WEB-INF/jsp/sessionsList.jsp0000644000175100017510000002520312271304167023266 0ustar locutuslocutus <%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page session="false" contentType="text/html; charset=ISO-8859-1" %> <%@page import="java.util.Collection" %> <%@page import="java.util.Iterator" %> <%@page import="org.apache.catalina.manager.JspHelper" %> <%@page import="org.apache.catalina.Session" %> <%@page import="org.apache.catalina.ha.session.DeltaSession" %> <%@page import="org.apache.catalina.util.ContextName" %> <%@page import="org.apache.catalina.manager.DummyProxySession"%> <% String path = (String) request.getAttribute("path"); String version = (String) request.getAttribute("version"); ContextName cn = new ContextName(path, version); String submitUrl = JspHelper.escapeXml(response.encodeURL( ((HttpServletRequest) pageContext.getRequest()).getRequestURI() + "?path=" + path + "&version=" + version)); Collection activeSessions = (Collection) request.getAttribute("activeSessions"); %> Sessions Administration for <%= JspHelper.escapeXml(cn.getDisplayName()) %>

Sessions Administration for <%= JspHelper.escapeXml(cn.getDisplayName()) %>

Tips:

  • Click on a column to sort.
  • To view a session details and/or remove a session attributes, click on its id.
<%= JspHelper.escapeXml(request.getAttribute("error")) %>
<%= JspHelper.escapeXml(request.getAttribute("message")) %>
Active HttpSessions informations "/> <% String order = (String) request.getAttribute("order"); if (order == null || "".equals(order)) { order = "ASC"; } %> <%= JspHelper.formatNumber(activeSessions.size()) %> active Sessions
<% if (activeSessions.size() > 10) { %> <%-- is the same as --%> <% } // end if %> <% Iterator iter = activeSessions.iterator(); while (iter.hasNext()) { Session currentSession = (Session) iter.next(); String currentSessionId = JspHelper.escapeXml(currentSession.getId()); String type; if (currentSession instanceof DeltaSession) { if (((DeltaSession) currentSession).isPrimarySession()) { type = "Primary"; } else { type = "Backup"; } } else if (currentSession instanceof DummyProxySession) { type = "Proxy"; } else { type = "Primary"; } %> <% } // end while %>
Session Id Type Guessed Locale Guessed User name Creation Time Last Accessed Time Used Time Inactive Time TTL
Session Id Type Guessed Locale Guessed User name Creation Time Last Accessed Time Used Time Inactive Time TTL
<% if ("Proxy".equals(type)) { out.print(currentSessionId); } else { %> <%= currentSessionId %> <% } %> <%= type %> <%= JspHelper.guessDisplayLocaleFromSession(currentSession) %> <%= JspHelper.guessDisplayUserFromSession(currentSession) %> <%= JspHelper.getDisplayCreationTimeForSession(currentSession) %> <%= JspHelper.getDisplayLastAccessedTimeForSession(currentSession) %> <%= JspHelper.getDisplayUsedTimeForSession(currentSession) %> <%= JspHelper.getDisplayInactiveTimeForSession(currentSession) %> <%= JspHelper.getDisplayTTLForSession(currentSession) %>

<%--div style="display: none;">

Valid HTML 4.01! Valid XHTML 1.0! Valid XHTML 1.1!

tomcat7-7.0.52/webapps/manager/WEB-INF/jsp/401.jsp0000644000175100017510000000627612271304167021101 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> 401 Unauthorized

401 Unauthorized

You are not authorized to view this page. If you have not changed any configuration files, please examine the file conf/tomcat-users.xml in your installation. That file must contain the credentials to let you use this webapp.

For example, to add the manager-gui role to a user named tomcat with a password of s3cret, add the following to the config file listed above.

<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>

Note that for Tomcat 7 onwards, the roles required to use the manager application were changed from the single manager role to the following four roles. You will need to assign the role(s) required for the functionality you wish to access.

  • manager-gui - allows access to the HTML GUI and the status pages
  • manager-script - allows access to the text interface and the status pages
  • manager-jmx - allows access to the JMX proxy and the status pages
  • manager-status - allows access to the status pages only

The HTML interface is protected against CSRF but the text and JMX interfaces are not. To maintain the CSRF protection:

  • Users with the manager-gui role should not be granted either the manager-script or manager-jmx roles.
  • If the text or jmx interfaces are accessed through a browser (e.g. for testing since these interfaces are intended for tools not humans) then the browser must be closed afterwards to terminate the session.

For more information - please see the Manager App HOW-TO.

tomcat7-7.0.52/webapps/manager/WEB-INF/jsp/sessionDetail.jsp0000644000175100017510000001773712271304167023407 0ustar locutuslocutus <%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page session="false" contentType="text/html; charset=ISO-8859-1" %> <%@page import="java.util.Enumeration" %> <%@page import="javax.servlet.http.HttpSession" %> <%@page import="org.apache.catalina.Session" %> <%@page import="org.apache.catalina.manager.JspHelper" %> <%@page import="org.apache.catalina.util.ContextName" %> <%--!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"--%> <% String path = (String) request.getAttribute("path"); String version = (String) request.getAttribute("version"); ContextName cn = new ContextName(path, version); Session currentSession = (Session)request.getAttribute("currentSession"); String currentSessionId = null; HttpSession currentHttpSession = null; if (currentSession != null) { currentHttpSession = currentSession.getSession(); currentSessionId = JspHelper.escapeXml(currentSession.getId()); } else { currentSessionId = "Session invalidated"; } String submitUrl = JspHelper.escapeXml(response.encodeURL( ((HttpServletRequest) pageContext.getRequest()).getRequestURI() + "?path=" + path + "&version=" + version)); %> Sessions Administration: details for <%= currentSessionId %> <% if (currentHttpSession == null) { %>

<%=currentSessionId%>

<% } else { %>

Details for Session <%= currentSessionId %>

Session Id <%= currentSessionId %>
Guessed Locale <%= JspHelper.guessDisplayLocaleFromSession(currentSession) %>
Guessed User <%= JspHelper.guessDisplayUserFromSession(currentSession) %>
Creation Time <%= JspHelper.getDisplayCreationTimeForSession(currentSession) %>
Last Accessed Time <%= JspHelper.getDisplayLastAccessedTimeForSession(currentSession) %>
Session Max Inactive Interval <%= JspHelper.secondsToTimeString(currentSession.getMaxInactiveInterval()) %>
Used Time <%= JspHelper.getDisplayUsedTimeForSession(currentSession) %>
Inactive Time <%= JspHelper.getDisplayInactiveTimeForSession(currentSession) %>
TTL <%= JspHelper.getDisplayTTLForSession(currentSession) %>
<% if ("Primary".equals(request.getParameter("sessionType"))) { %> <% } %>
<%= JspHelper.escapeXml(request.getAttribute("error")) %>
<%= JspHelper.escapeXml(request.getAttribute("message")) %>
<% int nAttributes = 0; Enumeration attributeNamesEnumeration = currentHttpSession.getAttributeNames(); while (attributeNamesEnumeration.hasMoreElements()) { attributeNamesEnumeration.nextElement(); ++nAttributes; } %> <%--tfoot> <% attributeNamesEnumeration = currentHttpSession.getAttributeNames(); while (attributeNamesEnumeration.hasMoreElements()) { String attributeName = (String) attributeNamesEnumeration.nextElement(); %> <% } // end while %>
<%= JspHelper.formatNumber(nAttributes) %> attributes
Remove Attribute Attribute name Attribute value
TODO: set Max Inactive Interval on sessions
<% if ("Primary".equals(request.getParameter("sessionType"))) { %> <% } else { out.print("Primary sessions only"); } %>
<%= JspHelper.escapeXml(attributeName) %> <% Object attributeValue = currentHttpSession.getAttribute(attributeName); %>"><%= JspHelper.escapeXml(attributeValue) %>
<% } // endif%>

<%--div style="display: none;">

Valid HTML 4.01! Valid XHTML 1.0! Valid XHTML 1.1!

tomcat7-7.0.52/webapps/manager/index.jsp0000644000175100017510000000157111420020730020034 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <% response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + "/html")); %>tomcat7-7.0.52/webapps/manager/xform.xsl0000644000175100017510000001076612271304167020116 0ustar locutuslocutus Tomcat Status
Tomcat Status
Memory Pools

JVM: free: total: max:

Name: Type: Initial: Committed: Maximum: Used:
Connector --
threadInfo maxThreads: currentThreadCount: currentThreadsBusy:

requestInfo maxTime: processingTime: requestCount: errorCount: bytesReceived: bytesSent:

StageTimeB SentB RecvClientVHostRequest

?
tomcat7-7.0.52/webapps/docs/0000755000175100017510000000000012301126373015532 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/META-INF/0000755000175100017510000000000012301126373016672 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/META-INF/context.xml0000644000175100017510000000154312271304167021110 0ustar locutuslocutus tomcat7-7.0.52/webapps/docs/images/0000755000175100017510000000000012301126373016777 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/images/tomcat.gif0000644000175100017510000000402211471741013020754 0ustar locutuslocutusGIF89a\Ҧ)u" GB4pl^Wr+дbp.!,\ dihbQ(l,LPC@>pxRq !Q_7eZ%HH`e %νJn_k(q4:Οbc7}" umx?"QU4 uGq[^&U&_[ Z'Z[wXD _ `mǩПV tu( Gd# ͿCGpv@3`@1`R ǏcU^5~tTxw̵ܜ֊YwQ H{n͛3L8nÝ2?n+:Pyտ숇OI5[pW/*@)otle-{a :U0/t$Y/a2Y΃_! D@f=@y@J׫L8 S gXP:$Pd>ډ`DN cB%1@PUE)CH" '"m0c b,8^qsٯ8 "ŇF.$fR98 $P!d 2I}Y%?.J2~`[ C'?Ia( 5aʂ聴LI̘Z FJ,%r`s]8rl6#L*<Ci~(fK0D+Zc 鎆m`jZc(ajE!ShzկJjNrKՀ V' x}Ho*$~C2.kHe 4HV%mH8anU]Q[+g4N {IPD=[!ʴ @!(S"gkZN?XƔ B{5?C@GI&_@w9e}# o:Mw9Q+ 4bg?xɍIc!;tomcat7-7.0.52/webapps/docs/images/code.gif0000644000175100017510000000061210457676032020413 0ustar locutuslocutusGIF89a000///111VVss]]߿..ڊEEJJ/10dd||22KK@@退NNN___kkŰOOO疖002,@pH,Py ((XP80"P, p< 7Zm#dBHSgxg ~E eh tE TqoDg F } B !g"u#$%&' ()*+N,+-.H//#+M00RSA;tomcat7-7.0.52/webapps/docs/images/void.gif0000644000175100017510000000005310457676032020441 0ustar locutuslocutusGIF89a! ,L;tomcat7-7.0.52/webapps/docs/images/add.gif0000644000175100017510000000201510457676032020230 0ustar locutuslocutusGIF89a# ac 4n _IUr 5؉P8Cޘ\CQJSYfĄ 1ݘ]@@CI[dÁ ӵ $ M>Aà ӖЋҠ ^UyI+ 8."0000026/%A/ Йщѕnd>,אЗтҐ~wđ */Bۓ ǩ5/#Ү,-IڏJKR):1!zohxw속7 EP*Odk2wNh2 FR%e*rC), pp&d p(@0p(X @P ,\A<|yD#H0*Vh 1da5lQu:v B)0#H(Y¤'PHIa *V`ɢe .Dz L1c)cCgФQM7ođ3EsԱsO={30~ $hEQ ,7УG(@@;tomcat7-7.0.52/webapps/docs/images/design.gif0000644000175100017510000000114010457676032020747 0ustar locutuslocutusGIF89a???>>>??=@@@=?>>@?*EVeOB?2- z%sJb*FT1Iaooopno@>?Ͽ®¬л~nod|dSkS#}&IJϹͫЦΠБu܃~mskq*w/¯в,ŀ  !"#$%%&&̃''()*++*,-؊./012345667(89:;<=>>? 2H!CgDnPA$%!I4M]ɓ'"Rd"!,ɬ4)Ҥl;tomcat7-7.0.52/webapps/docs/images/fix.gif0000644000175100017510000000053110457676032020267 0ustar locutuslocutusGIF89a OOO{st\N7J<,BK2S .3J2QCK5Q 0QK3R R>O9輱3,~@ȤrY\2K`* B@8 MHN`eCQh8$9`)FCX^B !"K#$C%&'()FaJ*+zVB,&-.*/0V1234BþA;tomcat7-7.0.52/webapps/docs/images/printer.gif0000644000175100017510000000066610457676032021175 0ustar locutuslocutusGIF89a 1Ƶsqsccac0!, $dI.2l\3-4w["C$қ$aH$HRҔv#i:0<8@/A G~rt^ yD"nxz r(#  yoB~ 4TAp o qoɪjDT^kp̌ 픝 C# K6'ъ/< 2hb)8oa53Pi1ƒCac 猦! yr+:EK)6]4F;tomcat7-7.0.52/webapps/docs/images/tomcat.svg0000644000175100017510000020432311656646736021041 0ustar locutuslocutus 2006-05-09T08:17:21Z 2006-05-09T08:37:38Z Illustrator JPEG 256 184 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAuAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXhH/OYHnWfQ/wAurfRLSUxXXmK49GQqaN9VtwJJqH3cxqfYnFXhP5Y/ 85O+f/JU0enaw769okbBJLS8ZvrUKg0IhnarDj/I9R2HHFX2F+Xn5neT/P8ApP6R8u3glKAfW7KS iXNuzdFljqaezCqnsTirK8VdirsVdirsVdirsVdirC/zM/Nvyd+XemC71255Xcqk2WmQUa5nI2+F CRxUd3ag+nbFXx1+Zf8Azkn+YvneaW1tLh9C0NgwXTrB2V3Sm/rzji8m3UDitP2cVfV//OOfmabz D+T3l+6uHMl1aRPYTsxqSbVzEhJ7kxKhxV6VirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVfHn/ADlxdSa7+bvlvyvGx4RW0EVARtNfXJVqf7BY+uRlKgT3JAt5r/zkD5ZGgfmfqSRR+nZ6 gsd9agdOMq0f/ksj5h9nZvEwgnmNi2Z4cMiw/wAqebPMHlTXLfW9BvHstQtjVZEPwstQWjkXo6NT 4lOxzOan3v8Akl+cel/mX5a+tAJa69ZcU1fTlJojGvGWLluYpKbV6GqmtKlV6NirsVdirsVdirsV eWfnr+eGl/lroywwBLzzPfox02wJqqL0+sT03EanoOrnYdyFXwh5i8x655j1i41jW7yS+1K6blNc SmpPgABQKo6BVFB2xVnf5Q+SjrWh+d9Yli5w6XolylsadbqSNnTj8kiYf7IZg6zUeHKERzlIfL8U 3YoWCe4Pff8AnCfVTN5D1zTCamz1P11HcLcQIAPlWE5nNL6KxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KuxV2KvjD8wm/Sv/OX8UTGsdrqGnCMNUU+rW0Mp6f5ammY2sNYZ/1T9zZi+oe9m/8A zkx+Xc/mPytFrunRepqehc3ljUVeS0cAyAU6mMqHA8OXfNB2PqhCfAeUvv8A2uZqcdix0fIedQ69 m35OefrryN+YOla2kpjsjKttqqDo9nMwEoI78ftr/lKMVfaeqf8AOSH5KaaSs3meCZx0W1inuanf YNDG69vHFWM3v/OYn5QW5YQ/pK8ArQwWqitPD1pIuvviqVT/APObH5cKR6GjaxIP2i8dqhB9qTvi qmP+c2fIFd9C1Wnfa2/6q4qmFv8A85n/AJUSvxksdZtx/NJb25H/ACTuHOKp3bf85XfkpPBI7avN BIisywS2lwGcqCeIZUdKmm1WGKvijzz5x1bzl5q1HzFqjlrm+lLrHWqxRDaOFP8AJjSij7+uKpNb W1xdXMVtbRtNcTuscMKAszu54qqgbkkmgwE1uVfbHkL8uk8o/lTPoMiK+o3drPNqZHRrieIhlr4I tEB9q5yWo1fi6gS/hBFfN2UMfDAjqwT/AJwdvyt/5usC20sVlOq77em0yMR2/wB2Cudc619ZYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXxZKTJ/zmFc+oedNTmA5b/ZtG49fCgpmH2h/ cS9zbh+sPqDrsc4t2r57/Nf/AJxkGo3c+teSTFb3ExMlxo0hEcTMdybd/spU/sN8PgQNs3+i7Xoc OX5/rcLLpusWIaF/zif56vFWTVr6y0pG6xgtczL81QLH90mZWTtnFH6bk1x0sjz2Z1pf/OIvlOIL +lNbvrthSv1dYrZSe+zC4ND88wp9uTP0xA9+/wCptGkHUsms/wDnGf8AKS3AEunT3dOpmupxXam/ pNFmPPtjOeRA+H67bBpoPDv+ch/yt03yXrdjeaFbG30HUouCQ8pJBFcQ0DqXkZ2+NSrCrfzeGbns vWHNAiX1BxdRi4TtySH8jfJdn5u/MOy07UIfrGl28ct3fw1IDRxrxUEqQaGV0By7X6g4sRkOfRhh hxSp9N3X/OO/5P3FSdBETGnxRXN0nT/JEvH8M50dq6gfxfYHOOnh3JDqP/OKn5a3NTazajYt+yIp 0dfpEsbn/hsvj21lHMRP497A6SPmwzW/+cQr9A76H5himO/CG9haL5AyxGT/AIhmXj7cifqiR7t/ 1NUtIehZh+S3/OP8Xk+5GveYXivNfTkLSKIloLYGqlwzBecjL3p8P45i9odqeIOCH09fNtw6fh3P N7DfIz2VwijkzRuFA6klTmpxmpD3uRLk+bf+cJrrj+Yet2tT+90hpeP7J9O5hWp9/wB5tneunfZm KuxV2KuxV2KuxV2KuxVZLNFDG0srrHGu7O5CqB7k4qks3nzyNC5jm8xaZHIOqPeW6nf2L4qmFhrW j6iK6ff294KVrbypLt1r8BPjirAvzb/Pnyf+WrW9rqKS6hq90vqRaba8eaxVp6krMQEUkEL1JPbq cVYFof8Azmp5BupVj1fR9Q0wNsZo/SuY1/1qGN6fJDir2Xyf+Yfkrzjam48taxb6iqgGSKNisyA9 PUhcLKn+yXFWRYq7FXYq7FXxRrBNj/zl/NVwC+rL8XtcWw+Hf/jJTMXXC8M/6pbMP1h9SZxLtnYq 7FWG+afzg/LnyvdNZ6vrUSXqGj2sKvcSofB1hV+B/wBamZmHs/NkFxjt8mqWaMeZRPk78zvI/nF5 ItA1RLm5hHKS1dXhmC1pyEcoRmXputRkdRosuLeQ2TDLGXJCfm/5JXzj5D1HSo05X8a/WtNPcXMI JUD/AFxVP9lk+z9R4WUE8jsWOaHFGnl3/OI/lpodN1zzFMlGuJUsLcsKELCPUlpXsWkQfNc2Xbmb eMPj+r9LRpI8y+hc0DmuxV2KuxV2Kvl//nClHP5oas4B4Lok6luwLXdqQPpoc9AdK+08VdirsVdi rsVdiqXeYPMOi+XtIudY1q7jsdNtF5z3EpooHQAd2ZjsqjcnYYq+VfPf/OV3nXzNqp0D8stPlto5 mMcF0IfrGoT+8UIDrGD8mbvVcVSqz/5xn/Pjzs66h5t1RbUueX+5W7kurgA/yxx+sq/6pZaeGKsj h/5wanMYM3nNUk7qmml1/wCCN0n6sVQt7/zhDr8B56Z5stppEIMZntZLfcb1qkk9KHFXzr5mtdUs tfv9O1S5a7vtOuJbKaZndwWt3MZ4mSjcartUDFUsxVFabqeo6XfQ3+m3UtlfW7c4Lq3dopUbxV1I IxV9Sfkr/wA5aNcT2+gfmG6K8hWO18wqAi1OwF2q0Vf+Mi0H8w6tir6lVlZQykMrCqsNwQe4xVvF XYq+Kfzzro3/ADlLa6oxKJLdaReFiaApGsMLeG1ISMqzw4sco94LKBogvqPOEdw7FXkf55/mBrlj Jp3kbykX/wAVeYSFE0Zo8FuzFOSt+wzlW+P9lQx2NDm27N0sZXlyfRFxs+Qj0jmUd5B/IHyP5bsI 31Oyh1zWnAa6vb1BMnqHciKKSqKAehI5e+Q1XamTIfSeGPlzTj08YjfcsJ/PDy5pXkHX/LH5geW7 WPTGhvlt9Rt7RBFHKpBk+wgCjnGkiPQbg5m9m5jnhLFM3s1Z4iBEg+hOu4zn3NQOkaLpuj20ltp8 IghlnnunRe8tzK0sh/4JzQdhtlmXLKZuXdXyYxiByR2VsnYqxjV/zO/L3SJWh1DzDYQzoaPD66PI p/ykQsw+kZlY9Dmnyifu+9qOWI6pvoOvaRr+kwato9yt3p1zz9C4UMob03MbbMFOzoR0ynLiljkY yFEM4yBFhV1WVYdLvJWJCxwSOxHWioTjhFzA8wsuRfPn/OEVoX83eZLzekOnxQnpSsswb/mVneOn fYOKuxV2KuxV2KqF9e2lhZT315KsFpaxtNcTuaKkcYLMzHwAFcVfFHnPzR50/wCchPzJi8veXlaH y7aO5sYnqsUUCkK97dU/bYdB2qFXcklV9U/lj+UnlH8u9IWz0a2WS+dQL7VpVBuLhh1q37KV+yg2 Huakqs1xV2KuxV8v/nf/AM4patrnmG+80eSp4Xn1GR7m/wBIuW9ImdyWd4JSOH7xjUq9KGvxb0Cr 5/1j8mPzX0iRkvfKepgL9qSC3e5jG9P7yASJ1PjiqRjyb5vMvpDQ9QMtePpi1m5culKca1xVPtG/ JT82dYdUsvKepUf7MlxA1rGe395cekn44q+zf+cffKv5m+VvJ50bzvPbzRwFf0RFHK01xbxU+KCV 6cCqmnDizU3FaUAVeo4q7FXx5/zmxpD2vnTy7rcdUN5YPbh12POzmL1qO4FyuKsl/Lz/AJyc8ra2 sNj5mUaHqZAU3TGtnI3Qnn1ir1o/wj+bOY1XY8474/UO7r+1z8epB2Oz2iKWKaJJYnWSKQBkkQhl ZTuCCNiDmnIINFygVGXTNOmvYb6W1hkvbbkLe6eNWljDgq3ByOS1UkGhwjJIDhs0ei0LtE5FLxD/ AJyycP5F0ezQcp59WjaNdt+NvMp/GQZuuxI/vJH+j+lxNWfSPe9rgiEMEcQNRGoQE9+IpmmlKyS5 QCpgSsllihieWVxHFGpeR2NFVVFSST0AGEAk0EEvn2fVfOv5269e6foN9Jof5e6fIYbm9QMst2af ZIBUtyG4QkKqkFqmgzfiGLRQBkOLKfx+C4ZMspobRZzof/OOv5U6VCiyaUdSnUUa4vZZJGb5opSL 7kzBydrZ5HY8PuDbHTQDP9G0XStE02HTNJtks9Pt+Xo20Qoi83LtQe7MTmBkyynLikbJboxAFBJv zO1Aaf8Al35lu60ZNNuljP8AlvEyJ/wzDL9FDizQH9IfYxymol59/wA4P6S0eg+adXI+G6ura0Vv e2jeRgP+kkZ2zqX01irsVdirsVdir50/5zJ/MGbSfK1j5PspOFxrrGa/KmhFpAwon/PWWn0KR3xV mf8Azjd+WEPkj8vrae5iA17XES91KQijorrWG333HpI24/mLYq9YxV2KuxV2KuxV2KuxV2KuxV2K obUdT03TbR7zUbuGytI/7y4uJFijX5u5VRir5U/5yz/MX8tfNfl7S7DQtZh1LW9NvS5W2V3iFvJG yyUnC+kfjVPsscVSv8i/yi/LTzn5Ij1XVLSafU4J5rW9C3EkaFlIdCFQrT926980XaOuy4cnDGqI vk5eDDGQsvdvKXkby35StXtdBgmtrZ6Vge6uZ4wf5ljmkkRCe5UCuaPPqp5Tc9/gHLhjEeSN8x3+ o6foGoX2m2hv9QtoJJbWyFazSKpKxjjv8R22yOCEZTAkaBZTJAsPHv8AlcP53/8Altpv+BuP+ac3 H8n6X/VPti4vjZP5rzz8wfPP5i+bfNvluw1Dyq1rqWjzG+g0ROZmuRVZDVGHPjxgbcDpXNhpdNiw wkYy9Mutj8dWnJOUiAQ9D/5XD+d//ltpv+BuP+ac1/8AJ+l/1T7Yt3jZP5rv+Vw/nf8A+W2m/wCB uP8AmnH+T9L/AKp9sV8bJ/NYp+ZX5v8A5qXnli40LVfKbaCutAWkdyxlWRwWXnHGrheRdfhI8DmV pNBgE+KMuLh9zXkzTIoirR/kbzf+bvlHy1Y+XtO/LedobYENM6zK0kjtyeRzxoOTH6BtkNTp9Plm ZyyfaEwnOIoRej+RPO35o6xr62fmPyf+hdNMTub71C1HWnFaV/azX6rS4IQuE+KXds348kyaIZ7q jaqthKdKSCS/pSBbp3jhr4uY1kbbwA38Rmux8PF6r4fJuldbPlv8+YvzstdPS483apafoO7nEEVh pcjJbl6NIA0bKkjgenWsnKhpnTdnHTH+7HqHfz+f6nAz8f8AFyfQ3/OLHl06N+TWkyOnCfVpJ9Rm Hj6r+nEfphiQ5t3GeuYq7FXYq7FXYq+MfzQhXzz/AM5YWmgz1lsLe7sbB4zvW3gRbi5TvSrNLir7 OxV2KuxV2KuxV2KuxV2KuxV5j59/5yM/K7yb6kFxqQ1TU0qP0dpvG4cMO0kgIij36hn5e2KvAvMv /OWP5p+arl9P8laWukxtXiYIzfXvHpUuy+mg+UdR/NkJ5IwFyIA80xiSaDF/+VT/AJo+b7sah5w1 h1kavx3sz3k617KgYoo9uYp4ZptR7QYIbRuZ8uXzP7XMx6GcuezJYf8AnH3yrBptwjXFxd6g8LrB NIwSNJSpCOEQA7NvRmOak+0eQzGwjCxfU11/FOT/ACfEDnZYH+S+sfmZZeajoHlC8htrq6ZnubC/ K/VnMAPLkrAtyUdfT+Kg8BnSa7HhMOLINg6/CZA1F9k6KdbOmw/pxbZdTp/pH1IyNAW8U9UK9Pnn I5eDi9F8PnzdlG63R2VsmndUUu5CooJZiaAAdSTiBaHhP5N8/On5r+bPzEkBbT7dv0do7EGhWgUM tRswgjUsP+LM3vaH7nBDCOZ5/j3/AHOJh9UzJ7vmicx2KvEf+clQLS78i63cEjT9O1cC6O3H4mjl FR/qwPm77G3GSPUj9f63E1XQvbQQQCDUHoc0jlN4pSXzN5z8q+V7ZLjX9Tg0+OSvpLK37x+PXhGv J3pXfiMuw6bJlNQFsJ5BHmXzJ+dn5haf+Z/mby75e8qtLPbLN6EbyI0YluruRI0oh+KigChIHU50 /ZmilhieL6i4GoyiZ2fbWh6Ra6Noun6PaClpp1tFaW4/4rgQRr+C5s3HR2KuxV2KuxV2KvjfymCP +c0p/rdK/pTU+POlKfUp/S/4144q+yMVdirsVdirsVdirsVeQfmX/wA5Ofl55MaaxtZv0/rcdVNl ZMDEj+E1x8SL4ELyYdxir5W/Mf8A5yD/ADJ88GSC6vjpmjyVC6VYFoYmQ1FJXr6kte/I8fADFXme Kvpj8jdTtb3yJBFFGkdxYyyW9zwVU5MDzRzTqSjipPU1zhvaDHKOosk8Mht5d/6/i7rQSBh5h6Fm ic12Kvnvz6l35B/Nqz8z2CEQyzLqMSqeIY143UVf8upr7Pnedl5RqdLwS5gcJ/R9n2uj1MPDyWPe +wdL1Ky1TTbXUrGQTWd5Ek9vKOjJIoZT9xznMkDCRieYc2JsWisgyYZ+b1p5vvfIGqWPlSFZ9Tu0 9F1LiN/q77TelXYuV+EAkddt6A5vZ8sccoMzsPv6NOYSMdnzl+Wn5m/mVoKR+RtEtNLsrmGWSsOp q1vM87t8Su8ssS+p0UKaGgAGdDqtHhyfvJ2fd3fBwseWUfSHq36V/wCcqf8AqzaN/wAGn/ZRms4N B/OP2/qci83c79K/85U/9WbRv+DT/sox4NB/OP2/qW83c8o/Mj8z/wAy/MAm8i6zaaZfXU0sY9HT Ea4lSdGqqxvFLKvqbFSBXqQc2el0eHH+8jY2693xcfJllL0l9KflXb+bbXyJpVp5riWLV7aIQsqu JGMSbRGUio9ThQNQnx70znNccZyk4+R+9zsIkIi2W5iNqB1xdH/RF2+sxQy6XFE8t4tyiyRelGpZ i6uCpAAyzFxcQ4D6ixlVb8nzj/zjB5UtfNn5xal5tisltNE0Rpbu1tEUCOOa6ZktYgBt+7j5tt3U Z3UIkRAJt1BO77PySHYq7FXYq7FXYq+M/wAyX/wb/wA5b2WsP+7s7q90+7Zz8NILlEt7htqV3EmK vszFXYq7FXYq7FWGfmR+bnkn8vrD6xr16PrkilrXS4KPdTdacY6jitRTmxC++Kvjz80/+clPPvnk TWVq50Py45KfULRj6kqntcTjiz1H7K8V8QeuKsQ/KyLyvP5wtbTzFbC4trn91bc2IjW4JBj9QAjk G+zQ7VIrmB2mcowE4jUh93Vv0wiZgS5Po7zD5J8ta/pa6bf2UfoQrxtWiAjeDbb0io+Hp06eIzht N2jmwz4oyu+d7373dZNPCYoh8/effyj17yuZLu3B1DRgSRdRr8cS9f3yD7P+sPh+XTOz7P7Wxajb 6Z936u90+fSyx78wnP8Azj5r4s/M11o8jUi1OHlED/v63qwA+cbP92YvtDp+PCJjnA/Ydv1NugyV Ou99C5xDuWDeefKvnzV9WiufL+v/AKKskt1jkt+Ui8pQ7sX+AEbqyj6M3XZ2t02LGRlhxyvnQO23 e4eow5JSuJoe8sD81/lL+ZF9pj3Go65Hq7WKPLBbMZGc7VZY+S9WC9O+bnSdsaQTEYQ4OLyAHxou Jl0mWrJuvel/5Q/8rK80ySeXdA85S6P9Qh9W2spZ51RouXx+kEDD4CwqPfbvmz1pw4xxzhxX5Bxc XFLYGnv35Y+RfzR0DXri881+af03p0lq8MVp6s0nGZpI2WSkiqNkRh9OaLW6rBkgBjjwm+4D7nMx Y5g7m3p2axyGGfmF+U3k/wA82pGq23paii8bfVIAFuEpWgLU+NN/st9FDvmZpddkwnbePc1ZMMZ+ 95R/iv8AMz8lbm20/wAzMPMvk2Z/Ssr5XpcIBvxXmSwKr/ut6r2Vxm28HDrAZQ9OTr+P0uNxzxbH cNSeb/zJ/Om9uNM8pk+XPJ0Lelf6g7D13DD7L8DyJZf91oafzNTEYMOjAlP1ZOn7P1qZyymhsHrH 5d/lN5R8i2gXS7f1tRdaXGqTgNcPXqAeiJ/kr9NTvmq1euyZjvtHucjHhEPezPMJuePedvy3/OXV fNF/qGg+c/0ZpM7KbWx9a4X0wI1VhxRSoqwJ2zc6fWaaMAJQuXuDizxZCbB2eNfm7F+Z3lQQaDr3 nKXV21SJmm0+GedgIQwCmVXC7OwIUd6HNtopYcvrhDhrrQcbKJR2JeieSv8AnHD8+9H0SJtG83Q+ XlvlS5udPinuonSR0Hwy+nHxLqPhO5zYtD2r8mvJH5m+V/0x/jjzN/iL659W/R/76eb0PS9X1f75 Vpz5p08MVel4q7FXYq7FXYq+Xv8AnNjya81joXnG3Sv1Vm0y/YCp4SEy25PgquJB82GKva/yY87J 5z/LXRNbaTneNALfUfEXVv8Au5SR25leY9mGKs2xV2KrZJI4o2kkYJGgLO7EBVUCpJJ6AYq+aPzm /wCctrTTWn0L8vmjvL1ax3GvOA9vEehFsh2lYH9tvg8A1cVeMfl95AvPzCvLrzP5l1SW6iNwUueT tJdTyqqsQ7tXgvFgPGmwp1zS9rdrflqjEXMj4OZpdL4m5Oz3O18seXrXSP0PDp0C6ZSjWhjVkb3c NXk3ud842etzSyeIZHi73bDDAR4a2eaeb/yBsLlmvPK9x9QuQeX1OYs0JPX4JN3j/EfLN9ovaIj0 5hfmP0j9XycLNoBzh8noHku+1y50OKLXrV7XWLT9xeB6FZGUCkyOvwsHG549DUds03aOLHHJxYiD jluPLy8v1OXp5SMakPUE9IBBBFQdiDmCDTe841/8pLaHW7bzL5U42OqWkyzvYfZt5+JqyrT+6LrV f5fl1zoNL21xQOLPvGQri6j39/3+9wMujo8UOY6PSB06U9s54uewnzt5H8z69qsV5pXme60W3jgW F7WAyhWcO7GQ+nLGKkMB07Zt9BrsGGBjkxiZvnt5d7iZ8M5m4ypj/wDyqbz9/wBT/f8A/BXP/ZRm d/K+k/1CPyj+pp/K5f55+15z518keZ/y91G01W01SZ2nLiPVrYyW8qTMDzQurFgXQnfl8Qrm90Pa GLVxIrl/CXCz4JYiHv8A+Qeia/NDH5tufO155k0u+s3gGm3Tzt9XufUjZuQkmlUPHwZdh0NQaHfV 9qTgP3YgIyB57bhv04PO7eyZp3KYZ+afm/zN5Z0KGby5okmtanezC1gVAXSF3UlXkRPjYbdqDxYd 83Q6eGWR45cIG7TmmYjYMC8p/kVrGu6ovmj81b1tV1Njyi0YODBEOoWQp8FB/vuP4fEtXM7P2nGE eDAKHf8Aj7y1QwEm5orzX+Rd9pepP5n/ACuvm0HWlq0mlhqWc46lFBqqV/kYFP8AVyODtMSHBnHF Hv8Ax9/NM8BBuGxZB+VP5j+ZPMs9/ovmbQJ9J13R1Q3s3ErbPzNEoGPJWehIA5KQKhu2Ua7RwxgT hK4yZYcplsRuHo2a1yHh35u+SvN1nNrXnD/lYl/omiIFli0yB7gBSEVFiiC3EacpHGwAG5zd6HPi lw4/DEpd+3z5OJmhIXLi2eW/lJ+UXnn829Svtdl1ue0XTjGo127MtzM9ytDHHG5dXrGg5E8vh+Hx zo4QERQFBwSSeb2z/oXX86P/AC8Gq/8AI2+/7Kskh6L+UP5dedPJv6W/xN5wu/Nf1/6v9U+tvO/1 f0fV9Th68s3956i1pT7OKvRcVdirsVdirsVY/wCf/J9l5x8nar5bvKLFqMDRpKRX05R8UUlP8iRV b6MVfLf/ADiz50vvJX5han+XXmGtsmoztDHE/SLU4Dw4jt++Qca9yEpir7ExVK/MnmbQvLOjXGs6 5eR2Om2q8pZ5TT5KoG7M3RVUVJ6Yq+M/zS/PHzr+bWrnyv5Vt5rPy67fDZoaS3CqaerduDRU/wAi vEd+RplWbNDFEymaiGUIGRoc0Nc/846uugI1vqXPX1BaRGFLVtv7tTTmtP5z18BnOw9pInLRj+77 +vv/AB9rsD2eeHY+pV/Io6rofmDWPK2rwSWlzJEl3FBIKCsbem5UjZuYddxUHjke34xy4YZYGwDW 3n/YuhJjMxL2rOSdq7FXYq7FXYq7FXYq7FUt8w6Bp2v6Pc6VqCc7a5XiSPtIw3V0J6Mp3GZGl1M8 GQTjzH2+TXlxicaLxryB5w1r8nPPM+i63yl8v3rKbrgCVKE0ju4V8R0ZR13HUDO3ywx67CJw59P1 H8ebpgZYZ0X1xZXlpfWkN5ZyrPa3CLLBNGQyOjiqspHUEZzE4mJo8w54N7q2RS7FXYq73xVTuLi3 treS4uJFht4VMk00hCoiKKszMdgAOpwxiSaHNBNPlfzv5j8wfnh+Yll5O8qBhoVtKTFKwIQqvwzX 047IgNEB33p9p6Z13Z2iGGNn6zz/AFOtz5eM+T7B8j+TdG8m+V7Hy7o8fCzso+Jc/blkO8ksh7s7 bn7htTNi0J9irsVdirsVdirsVdirsVfLP/OXf5WXENxb/mXoKNHNCY4tbMNVdWQhbe7BG9RtGx/1 PfFWefl3/wA5I+VdQ/KqTzN5mu0ttV0YLbavarT1Z7gqfSaCPbl9YCkgdFIb9la4q+cvNPm3z/8A nr5uCUNnolo1YLRSxtrOIkgSSdPUmYd+p7cV6Yms1mPTw4pn3DqW3FhlkNB695O8l6J5U00Wemx/ vHAN1duB6szDux8B2XoM4LXdoZNTK5cug7vx3u7w4I4xQT/MFvUJbGzluYbqSFGubfl6ExA5oHFG AbrQjqMsjmkImIPplzDEwBIPUNahew2Nhc3s54wWsTzSt4JGpZj9wxw4zOYiP4iB81nLhBPc8w/J Tzn5v8y3mqHV7oXFlaIhjHpojLJKxIAZQtQFQ9a50XbujwYYRMI8MifsH4DgaLNOZNmwHq+cy7F2 KuxV2KuxV2KuxVjXnzyLpnm/SDZ3P7m7hq9leAVaJyO/ijftL/EDNj2d2jLTTsbxPMfjq4+o04yD zeb/AJZ/mj5g/KrXZPKnmyKSTQS9QFq5t+Z/v7c/txP1ZR8x8VQet1Gmx6vGMmM+r8bF1UJyxS4Z PqrTNT0/VLCDUNOuI7qyuVDwXETBkZT3BGczkxygeGQohzgQRYRWRZOxVSurq2tLaW6upUgtoVLz TSMEREUVLMxoABhjEyNDcoJp8v8A5n/mrr/5n65D5E8hQTTadcy+kxQcZL1lNeTV+xbpTl8VNvia nTOp7O7OGL1S+v7v2uvz5+LYcn0j+SX5N6V+Wvlv6uCl1r96FfV9RUGjMKlYoq7iKOu38x+I+A2z jPR8VdirsVdirsVdirsVdirsVSDz3rvlfQ/KWp6h5oaMaGsDx3kUgDCZJFK+iqEjm0leIXvir81d SfTpdTupdPhkt9MedzawyMJJI4WYmNGeihmCbV74q+q/y8tfLEHlOyPlsV06VefqGnqvJ0czH/fl RQ+HQbUzzrtWeY5z4v1D5V5eTv8ATCAgOFkma5yHYq7FWIfm3qBsfy81mRftSxLbge08ixN/wrHN r2Jj4tVHys/Z+txdZKsZSD/nH3TRb+S5rwj4767kYH/IjVYwP+CDZm+0mQnNGPQR+/8AAauz4+gn zenZzrnuxV2KuxV2KuxV2KuxVjnnbyLovm3Tfqt+np3MYJtL1APUiY+Feqn9pe/zocz9B2jk00rj vHqPx1aM+njkG/N4/ovmf8xfyX1w2rr9b0W4fkbVyxtLgDq8T0Jikp12r4gimdkPA12PiHP7R7/x 7nUETwyovpX8vvzc8m+eLZf0ZdCDUgKzaVcEJcKR1KitJF/ykr70O2aHVaDJhO4uPf8Ajk5ePNGX vTXzl578seTtMOoa9eLboa+hAPimmYfsxRjdj+A7kZVp9LPMaiP1Mp5BEbvmXzJ54/Mb87vMcflj y1ZyQ6SzhksENFCKf96L2YbcV60+yDQAM1Cep0eghgF85d/6nX5cxn7n1H+S35IaB+Wmkkxlb3zD eIo1LVGHyJhgrukQbfxbqewGe0vSsVdirsVdirsVdirsVdirsVQup6np+l6fc6jqNwlrY2kbTXNx KeKJGgqzMfYYq+HfzQ/MTzL+dvnmHSNFR4PLtm7fo+2eoUIKh7y5pX42BoB+yPhG5JajU6mGGBnM 7BnjxmZoPQ4Pyv8AK8fk1vK5i5W8g5yXVAJjcU2nr/MO3am3TOGl2xmOfxfs6V3ft73dDSQ4OH7X kehaz5g/KfzbLpWqK0+jXLB5VQfDJGaqlxDU7MKfEv0HsR0uowYu0MAlA+ocvI9x/HmHXY5ywTo8 n0Fp2o2OpWMN9YzLcWlwoeGZDUEH/Pcds4jNhljkYyFSDuYTEhY5KzTQoaPIqnwJAOCOOR3AKmQH VyzQueKyKx8AQTiccgLIKiQPV5t/zkDctD5FijHS5voYm37BJJP1x5vPZwf4Qf6h+8OH2h/dj3p3 +UNt9X/LnRkoQXjklNRQ/vJnf9TbZjdtyvVT+H3Bs0Y/dBmOalynYq7FXYq7FXYq7FXYq7FUHq+j 6ZrFhLYanbJdWkwo8Tjb2II3Vh2I3GXYNRPFLigaLCeMSFF4R50/JTXdCnOq+VpJby1ib1FjjJF5 ARuCvGhenYr8Xt3zstB25jzenJ6Z/Yf1fF1OfRShvHcJFJ5F/M7zRY3PmTUI7m8eKMFHvZHa6mRe 0SvV2CjcdK/s1OZsu0NNimMVgHy5D39zQMGSQ4qfTP8AziV518hXnlX/AA3p1lBpPmi0XnqUIr6l 6F2+sq7lnfr8SV+A9AFIzYtD6BxV2KuxV2KuxV2KuxV2KuxV2KvjX/nI7847/wA+eYk/L/ye7XGj QTiO4kgNRfXSnswNDBEeh6Egt0CnIZMkYRMpGgExiSaDJvy88h2PlDRRbJxl1G4o9/dAfbcDZVPX gn7P3988/wC0+0Zamd8oDkP0+93um04xx82vOP5meVvKoMV7OZ7+lVsLejy+3PcKg/1j8q4dF2Tm 1G4HDDvP6O9c2qhj25l47r/mfzt+ak6aXovlxrmO3f1I47SF7meOuxLzAURT32UZ1/Z/ZcNNdEkn n3fJ1OfUnJzDFvNXl7z35Lu/8P8AmCG60uQoLhbNpaxMsg+2nps0TVpQkHqKHcZseEXdbtFsbySH Yqu9ST0/T5H068uFTx5UpWnjir2HyZ+T/wCfGr+U9O1/yreSS6VdKzWkEOo+iQI5HRlMcjxoPjjI pXKMmmxT+qMT7wGcckhyJCOudA/5yq0IfvtM1G4VDuscNvqFadqwidj07HMXJ2Tpp84D4bfc2x1W QdUvl/Oj8y9CmEPmHQ0iPQpc209pKT1/aNP+FzCyezunly4o/H9bbHX5Bzop1pv/ADkboslBqWkX FsfG3dJx8/j9HNfl9mZfwTB94r9bkR7RHUMv0r82/wAvtSoserx28ndLoNb0/wBlIFT7mzWZuxdT D+HiHlv9nP7HIhrMcutMst7i3uIlmt5Umib7MkbBlPyIqM1s8coGpAg+bkxkDuFTIJdirsVdirsV dirH/PXm608q+XZ9Umo8391ZwH/dk7A8V+Qpyb2GZ/Z2iOoyiP8AD19zRqMwxxvq+cfL9n+Yf19/ Omi29ytzYytfnU41CgPyLOyhqCTqeSqDt1FM7+WoxYyIGQBOwDoxjlIE0+1/yK/O7S/zJ0IpP6dp 5nsVA1LT1OzrsPrEAO5jYncdVOx/ZJyGt6jirsVdirsVdirsVdirsVfO/wDzlT+dh8vaa/kfQJ6a 7qUf+5S4jPxWtrINoxTpJMD8wm/7SnFWA/k3+W48v6eNZ1OL/c1ep8EbDe3hbfhQ9Hbq3h08a8V2 52n4svCgfRHn5n9Q/HR3Gi03COI8yl/5qfm5LYTt5d8sP6mqM3pXd3GOZiY7elFStZa9T+z0+10v 7I7G4gMmUbdI/pP6mGr1demPzZX+UH/OJcl6I/MP5lNKZJj6sehB2EjV35XkoPKp68FNfFuq51wF OqfT2j6Jo+i2Een6RZQafYxf3dtbRrFGPfigAqe5xVj35mflh5Y/MLy++k61CBKgLWGoIB69tKf2 o2PY0HJejD6CFXwV+Z35WeaPy715tL1qHlbyFmsNRjB9C4jBoGU/st/Mh3X5UJVYdirsVfb3/OHX mKPUfyrfSS9Z9EvpovTrUiK4/wBIRvYM7yD6MVe7YqsmhhniaKaNZYnFHjcBlI8CDtirDde/JX8q Ne5HUvK1g0j15zQRC1lJPcyW/pOT9OKvMfMn/OF/5eXwZ9D1K+0aY/ZRit3AP9g/CT/krirzTVv+ cTvzh8tSPdeVNVh1EDoLS4exuWp4rIVj/wCSpyGTHGYqQBHmmMiNwxq58/fnT5ImW382aVMYgeIO oWzRch0pHcRhUfp1+LNVn7C02TcDhPl+rk5UNbkj1tlGgf8AOQHlS94x6rBNpUx6uR68P/BIOf8A wmaPUezmWO+MiX2H9X2uZj7QifqFPRNK1vR9Wg9fTL2G9iHVoHV6V7NQ7H2OaTPpsmI1OJi5sMkZ cjaNyhm7FXYqlGq+VNC1fULe91S2F69opW2hn+OFCxqzekfhLGg3avTbMzDrsuKBhA8N8yOfz/U0 zwRlKzumyqqqFUAKBQKNgAO2YhJJttp84edta0nyl+Y0Gu+Qr/0NQtH9W4WAfuI5wfiRSDxdJBUO lOPUd6D0PsqWc4R4w36d5Hm6HUiAn6H2P+TH5xaN+ZXlwXcIW11u0ATVdM5VMbnpJHXcxP8Asnt0 PTNk470PFXYq7FXYq7FXYqwf84fzP078uvJtxrU/GXUJawaTZMf765YbVA34IPic+G3UjFXyR+U/ lPUvNnmK589+ZXa65XDzRPKB/pF2Wq0h7cIz0AFK7D7NM5/tztLwo+HA+uXPyH6z+OjnaLT8R4jy DOPzf89t5Y8v+hZScdX1HlHbEdY0A/eS/MVovufbNJ2J2f4+TikPRD7T3fr/AGubrM/BGhzKf/8A OK/5HQWtjb/mF5ltxLqV3+90K2mBPoxHpdMD1kk6x+C/F1O3dukfTGKuxV2KpL5v8neXfN+hz6J5 gs0vLCffi2zxuPsyROPiR17EfqxV8N/nR/zj/wCZfy5umvYeep+VpXpb6mq/FFyPwx3Kj7Ddg32W 7UO2KvKcVeu/84z/AJoQeRvPwi1KX0tC11Vs7+RjRIpA1YJ29kZipJ6KxPbFX3sCCKjcHocVbxV2 KuxV2Kqc9vBcQvBcRrNDIOMkUihlYHsVNQcVeX+cP+cZ/wAovM3OQ6QNIvH/AOPrSmFsQf8AjDRo D/yLrirw/wA0f84fef8AQZ21DyRrKal6dTHEWNhejwVH5GJvmXT5ZGURIURYSCRyYf8A8rL/ADW8 jXo03zjpUslK8Y7+JreVlXasU6rxdf8AKo3zzT6rsHBk3j6D5cvl+qnLx62cee7P/LX5zeSdbKxS XJ0y7bb0byiKT/kygmP5VIPtnO6rsLPi3iOOPlz+X6rc/HrYS57FnSsrKGUhlIqCNwRmmIINFywW 8CWLebfLnmTzCG0+PVV0jRm2n+rK0lzOpG6s7FFjXtRa17nembXRavBp/VwmeTz2A93P5uLmxTnt dRSjR/yO8g6cVea2l1GVTUPdyEiv+pH6aEfMHL83tBqJ/TUfcP12whocY57sS80+XfMH5YeaLfz3 5JdorSKStxbAExxBz8UUigjlbydP8n58Tm97H7WGccE/7wf7L9vf8/dhavS8BsfT9z6x/Kf81NB/ MbyzHq2nEQXsVI9U0xmDSW03genJHpVHpuPAggb1wmbYq7FXYq7FVK6ure0tprq5lWG2gRpZ5nIV ERByZmJ2AAFTir4W89eZtV/PD81xHas8Xlyw5RWXb0bJGHqTsDt6s7U/4Vei1zE12rjp8Rmfh5lt w4jOVB7Zp2n2enWMFjZxiG1tkWKGMdAqig655xmyyyTM5G5F6CEREUOTxPS9Gb81/wA/YNJlLNo1 tMUuKbUsrEky0I6es9QD25jPQ+zNL4OCMevM+8/inQ6nJxzJfdcUUUUSRRIscUahY41AVVVRQAAb AAZntC/FXYq7FXYqo3dnaXtrLaXkKXFrOpjnglUOjowoVZWqCD74q+T/AM7f+cTri0a48wfl7E09 pvJdeX6lpY+5NqTu6/8AFZ+Ifs16BV8xyRyRSNHIpSRCVdGBDBgaEEHoRiqLv9b1nUEjS/v7m7SF VjhWeV5QiIOKqocmgUbADFU/8k/mp588l38N1oOrzwxREcrCR2ktJFH7MkDHgRTaoow7EYq/Qb8v POFv5y8laR5mt4/RXUoBI8NeXpyqxjlQNtULIjCuKsixV2KuxV2KuxVB6rpGlavZSWGq2cF/ZS7S W1zGssbfNHBGKvD/AD5/zh75B1r1Lny1PL5cvmqREtbizY/8YnYOlT/K9B/LirxDWPy7/Pr8pmea GKW90OI8nuLOt5ZcQakvERzhHixVfnmJqdDhzj1xvz6/Ntx5pw5FNvKv/OQWi3fCDzDbNp0/Q3UI aWAmnUqKyJv2+L55zWr9nJDfEeLyPP58vudhi7QB2kKepWGo6fqNst1YXMd1bP8AZmhcOp+lSc57 LhnjPDMGJ83YRmJCwbROVMlk0MU8LwzIJIZVKSRsKqysKEEHqCMlCZiQRsQggEUXiepWHmf8m/OM PnDyiS+jSH07i3erxhHYFrafuY2oOD9QadwCe77J7UGojwy2yD7fN0mq0xxmx9L7C/Lr8wvL/n3y zBr+iyExSfBc2z/3tvOAC8Ug8RXY9CNxm5cRk+KuxV2Kvm7/AJzA/NOTTNHg8haVKRf6ugn1ZkJ5 JacqJDt3mdTyH8op0bFUg/KjyOvlfy2n1iMDVr8LNfsaVXb4Ia/8Vg7/AOVXOB7Z1/j5aH0R5fpL vNJg4I2eZZRr1/8Ao/Q9Rv8A/lktZp/+RUZf+Ga7SwE8sInkZAfa35ZVEnyYp/zg/o0Ump+atccV mghtbKJu/Gd3ll/GBM9PecfWeKuxV2KuxV2KuxV2KvOfPf5Aflj521UatrGmtHqRFJ7m0kMDTdKG Xjs7CmzUr+GKsb/6FD/Jv/lmvv8ApLb+mKu/6FD/ACb/AOWa+/6S2/pir0/yZ5Q0byf5as/LmirI mmWPqfV1lcyOPWleZ6sevxyHFU7xV2KuxV2KuxV2KuxV2KvMfzC/5x1/LLzr6lzcaf8AovVn3/Se ncYJGbrWSOhikr3LLy9xir5080f846/nH+XVzJqnlK6k1nT1NTLpwYXHFenrWR58/kvMZTmwQyx4 ZgSDKEzE2DSH8r/85ABZRZea7IwSoeD3lup+FgaH1YT8Qp34/wDA5zes9nBzwn4H9B/X83Y4u0Ok w9b0nWdK1e0W80y7iu7ZukkTBgD4Hup9jvnM59PkxS4ZgxLsYZIyFg2q31jaX9pNZ3kKz2s6lJoX FVZT2ORxZZY5CUTUgmURIUeTxy2svzN/KLzbcaj5Eil1DS9RRkNuIZLqMqDVUnij35Rk/A+3z3YZ 3Wg7YxZYXOQhMc7NfK/wHS59JKMthYZVB/zlL+eWlMZNc8owTWiEmRzaXlsaClaS83jp/sTmxx6r FM1GUZe4guPLHIcwQ9C8jf8AOYH5ea7NFaa9bzeW7uUhRLMwns+RNADOgVl+bxhR3OXsHulvcW9z BHcW0qTW8yh4Zo2Do6MKqysKggjoRir849U/MZtX/M6688azZnUTNdNcxWTSekFVPhtk5cZPhhVV FKb0yjU4pZMZjE8JPVnjkIyBItnP/Qyn/fuf9Pv/AF4zm/8AQx/tn+x/487D+Uv6P2/sQWuf85A/ pXRNQ0z9A+j9etprb1vrfLh60ZTlx9Fa05VpXLcHs74eSM+O+Eg/T3f5zGev4okcPPz/AGPU/wDn B7UUbTvNmmkgPFNaXCjuRIsqH7vTH350zrn1DirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirBPzB/JP8uvPivJremKmpFaJqtofQul2oKuopJTsJFYYq+afOP8AzjN+afkK7fWP JF7LrNjGeX+iVjvVUb0ktqlZh/qcq/yjK8uKGSPDIAjzZRkYmwl/lf8AP1opf0f5vsmgnjb05LyB CCrA0PqwH4lI78f+BzmtZ7OA74T8D+g/r+bsMPaHSfzet6TrOlavZreaZdR3ds3SSJgwB8D3B9jv nMZ9PkxS4ZgxLsoZIyFg2jMpZsJ87flR5Z8zxSTLCthqxBKX0Kgcm/4uQUEg9/te+bjQds5cBAke KHcf0H8BxM+kjPlsWPfkJ+aPmL8t/PS+QfNEjHQbycWyo7FktbiZh6U8LH/dMpYcxsN+WxBr3OHN HLATibiXSzgYmjzfWP8AyrzyB/1LOlf9INt/zRlrF3/KvPIH/Us6V/0g23/NGKu/5V55A/6lnSv+ kG2/5oxVHaV5Z8uaRJJJpOlWenySgLK9rbxQMyg1AYxqtRiqZYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqwT8xvyU/L/AM/xFtbsBHqQXjFq1pSG6XsKuARIB2EisB2x V856t/ziZ+bHl/VpT5M1qO4sZhtcpcPYT0B2SVFJBp4hj8hleTFCYqQEh5i2UZGPI0of9C+f85Nf 9XeT/uLS/wDNWUfkNP8A6nD/AEo/Uz8ef84/N3/Qvn/OTX/V3k/7i0v/ADVj+Q0/+pw/0o/Uvjz/ AJx+aX3n/OK/576ldpcalLBdTgKguLi/MzqoNQAzVagqTTMjHijAVECI8tmEpEmybf/Z image/svg+xml image/svg+xml eJzdffle8sqy6H0B3gFUFGQwEyEBB2YHUEFwwJlJRJlkWGuv88d59lvVSUgICWmQ75x1716/7aed Tnd1dXXN1fF6iuVQsjmot0J8mHG7vN70qFWbDEYxN2l1n3e70/FkhE2+G7+bZcMMdEqeS29qx7vW aNwZ9GPkEXmYw7d951e565vTrN/t80NbpTPptqB1Mug1apPw+K+2X5sLXs7UJvAwciAfMKKbZWJ8 1J28hOepwbTf7PTbqcF/YPyo6OYZzi3AU0GKwuOzzk1rbO4TjrK8jB3DnAy/CLwYluBNQYInDL6V GTSmvVZ/UhwNGq3xOD3oDkbjmDv9T63vvqy14UnNXW11u4O/3alurfHtgtVG3nKdbgsW1qtN3FFc ZfKcfyOv3o7hHXgdf8fm6Nt5D1rKrckEoIKBESXpy2reOB9Aqv7ne7pptTsEw4CIF78ycqXVG3YB KWRRPCCFl0XtX7UHwEOehqJsmJdlGfAmhiMy9BMlPiwwjAC/RMgj5Q193a2/Oq2/Y+6rQb+lLC45 mpQ7/9XCqRg3xzBK68202xrd9jsTWASHTbKy4stBs9VVm8i7uW6NLJT8x+o/lQ6V2qjdmsBODbrT CaEUSZvhator1P5pjfQJroetfmVwR+ALiUJYFMWIWxQY5Rc2HHFLouyOMoA6ScEgC8tUp2TJtKwy No6E42gTRHHvi7Az16NOu9OPsYLoDnHYint2Ouo09S2Lcm5J+UHWEZYM/5e1/ysAw9onk1Zf2eZs v5ke9BDJY6Re2Ng+7Hp30FaezX4nT2C66VCBlfz9BvtRHHX6CIPrijyR3ordKTw6HQ2mw/P+x8Dl U05lEScd9a/78MunOzWajj/dlcGgC6dtroP6SBkFH44mxt5L54C+9uPrA601drrW7Xbao9rws9Ow Gt7i+Wweu3eXTgjbNGrpY5A/Z/8ufbPcIKi0gnL+0WxwizeWz/BPrz7odsY9fWBDi/67E0XARnVb /eZ4Nozypw5YofOX1rh8sEzrA1idYWtJa7b/V6s7GBrQOGup9Zvu+9poaDcsQvfR6TcBK+VpZ9LS N3rQGyIDd5c/a0NsXuipnBA4PcbzEQotPzgrvyArT5ARTv7ptsaug3x/8Hef/OGOuXxPgJLatDt5 8bsPrmq9ljvoOih3gEm3tC6M+9rFqDzwG367cWn8MO/SuCLjfvgH/riAX76g6W+34L50P70w7ia0 Pty4kIE9NF0HxRoA54673AcwLfxLAIQV6eA5rrFY6wI7axEginWXnbhBkMauhdZiY/bGt+XTYmoG gjbTKvgtwHBGpC6skHRYZyNZRnmkHBsc5v+ozTCQqdFmcBVWTV6CclJzed8OtL9hr/GvTgOxURv9 o/z9cFm4ArlI/vBtN9W+QC3lCQzedvv+0+v2oUMIf/SBgvxAQt436+d/1bpTtYPsPjiHOeceT/4Z qk8PkqNRzQqCXmtSawLgvweAXQ+Av2qjTq3eRT1o/G8A4n8dhv9JLMT1Po3PTrc5avXVPiayNXQE mTXq1KcTBDRIHgUX1xIb15Dn4ZH4H95Y6iXNQ4zvOIPp2+2P3xpg5wx6cZvOBpi5/9lt0NawuB3k QewvuuUBHY7/rYvDNQRpyHFNKoC1A7leEYQ44areIeYk++9DlXEVi8TQHTS+W03n9fXB6vv3rU2D /k9SwQq84N98WCiRNL/28cff/2sScNztNP6/EH9kIeXBdNRoEa/Tv3JN8yD/4wjizFN2cNOqdf81 pP6PpcBzXM3MAfjvWs1/rFbzd6c5+XRcEScyYVbk2H/ZilTgF1f12eq0P53VbVYSwgLL/9uWpUG/ uK76YALqYaH1MVEciM4rdB+kBoN/z9IWF/AvEbYgm/4fl7WbEzgbAt7ggMAWRsVd8pxl3TM/BnFA uwu1fntaa7fcxcFwOjSRLnmhOGqNW6O/Wu5K6z8Td7bZmdTqnW5norJoMRLhI7MJZHdtNKkPaqOm u4HBAjfrHmmKnWPP9qilrdexb31GGRFO4CT7rpwOgGNPAwCOfesLQnyx2zzp4vPJqNYfD2uwr41/ YLpO0z3u/Fdrtk0a2mX3sDZsjeBhb9olfjdNWjMax8RO19PJcDpx39TGk9ao81+ko1sPtajgRebe uWyNPx3eYOb2X6Mldwd61SYtWHmL2EhLO3/3QaUfAHBtdAOrx/3pstXsTHuGCV8MJ9+KPNX4CqCC kOHEbbB/TEdCIxfAvIr4qIb55rATNkFb63bGpqZebfytolnUMDasNXWzJHnuTk4ngxn2tP1nDAeM cX/MQB6RfqG/Wo0JkEy91q31G4t7PfcKYKzb6bfcEzhrdD3Hk9HgWzv7rE3nRrczBJJE581/4Dy0 AW0Obwy1Uz/4qzUaooN0xl4ANY3BqNlqLm6D++BqMJl7vCrvcRhOp5YDne8djJqjcVhx4JgV74Vu tX5/MJmtXdnlhU4aHsbjeQ662HHabzh0AXkHJ6ZJdQSML/9nGNYlpdXo0GEwbE4dOoydRmgM5tmY qQOSzvIOgz6QyEShw6VzqT112iasyaonMOJ5lsQzNj1H5p7RiHXHueNnufNDZd+X7zp0AjY038/A lc1dP2vN1qi1fLwuiyezNlnaCXA3Ia6bpX16eGzHRkZu1a/fagPj/2v5YPUOnsF5CWYGvPVXq2s/ yEd/Eh5P6+MlC8Muze5w9DGY8RcrKlO69UDbUbUDS3S3e9/hXm30PR58fIQVdZe6+0jX+yl6TwZD 6r5d0LhnCLDpDPyh1TRDTdHdADVF7xnUFH3noF7ce+xLNJx6bbSMuLHfyBA9dOg6BGHQ6X8MnGYe GVZi3YUsRO0T5iK2C262PlCKGsxZa2ZMOn8N6hNMZHLsqIiij0532RHDjmMMdjr0mZMfVr0ao2Z4 Ahq5ppFZnSDsM240+ssOo9Jn2G38Y9BrFvGmdKt1W+G/KPt9LiE77DUYtbWxlvZRx7Fi8NhlOBh3 lhMZ9oL9Hn4ORv+lcraoXb/BqIO5YA4DdkfhmYJUx3Sx5X01WTkcTJYcG+ypMztrOgNadFAPsEe9 M+nVhmYRadebrKI2Vl6i6DpYTuGzfnXVW7qsY7M17rT7TugeDkdhYkItoxbs9AlMbNxaxhtJt7/p uhndQksGc2Qi0Enfs2iUDwuWjAm6dTCJcE4cROSIU3eDOGClsLVsmnWeSQNWdOqqC4OozNl1NeJI ZG27GZBkxaewS1NJC1nCFqGTs7Y/nnTVXsNh035G7KbOOOtnPyB0wZPZtfLxL/RF2m+N5lyCS6dX +muGgiHlyGoGEL/dFjGVdJM4PnPZYAJRUuvsRpuKyryyO504WW3icNZHoA6Oxi0cbWS/YOw5/u4M gVv2v504HCoEcNzbluu7GNQxvcywOt0TA52yxbL72mS8zvlP1D4FtKIxexGz2IiPa6kHRX3rdFRr ooAgbyk+FTtDZPaO4jc4uFP8ASk7f4AKumrfV3RrybZP2c4HoHRLo/WfVq3/G6P1T+ORwRGWuGFY o9eqP9D9Be5On7gcUCpbuWwWqc/3ZEg3d69B/1Z2Cq6hmMm9pYmN1TG6Lq3IU+uueT0NEKHrE8BI 14aKA7TTWmKyaOOcItbg6FQ+p716v9bpLpGD2juYtwz/5pZKV61zDojqvlXHd5yhIQncmcHffSWR J9/pNw0kTvuamdI5zkols3mZpMcn64O/dFtu+atp3arV4V2+0/NvlaY1fc+5iOOEmFtf1r17yzZ3 VPtndWzOv7UaMuffXQWX+ObKqDS9tAIm8U16RF4O+oPG52jQa1mh09r5s+xdM1KFpRuCI9gjVaCa 2xK1y4+i8gJIHudDXhl1epfoUXDuCvydsich9tRSA37GDQEl50sNc51vEiUGQajMwnN2Jrh5efct BzeM9sI1UdtzgHhA39+D0XdhpqKu9l7KyU1k++bNuqBWlrphtNdS6MAoLPcdzfW9cTBR5jqvAIMR Q8voWQG4019iAWtds716q3meThdHxILUpOjSU16e1hGNg/7kBo1EZ3hmqh+FCFW0m4ohNkelHi0Z C54rmtKVIdNmKbLNL17W/rNED6UaodO31Ulp3lf01JTJb079OmqdqtKp6JyrD6Hqt2WH0ILD6xVj LM1R4Us2RoN6baLUjc3MDuihrmqmdppNDtkc3hrW+pp7XJOx5btTJGGFmCcLHjv1cWHQqC3OAA/J wVGsCJWm9GcAXqOju/4NM2b7jYEerxX0B6TUQufSM00eHpHyHKRdOBANi+daheLik2L7Y7HxoWZO LcDpu53GDKz4ojmgF77M12Lgjik1Griz2jMX2UljC5oYyXL6/FyKZGDcJlbteAPHYmgnMfY/bGXy F42PnL/EJRM/qVefcHL9fhy955lmvBXz9smf8fPx4CP3Xpju5TyBJ8bUFji5qx8wXHcSSd5UcpVE bPgii49i79HlPQy95wZkMJgvPk6Wp7e+ZL/eHqvvHP/0kvn77PZodFzrn3bvvuqp98tSMhnssy/x E/ZOymw3p9lM+uz5hQwVOD4aeoUxv1MKnHxOeAKIy0sBygqAHNWTweHVRSIvj4+ls8P7cG7wKNy5 vNnR8yOTecxVK7mj5FHDCp7jof9wCBOchdLcztF7JjxN3Cajz29VsTpki7nd0kNXna+R3M18DP1s snIxmeptLq/Smn/wT2Cci2kmfP15OBoJmQ7DiVvDxN1eeUfpzjLFWs4/2a1lgy9XBykxyG2p47wP EqNRfFwBeIPnDBv6iunIiqdu0i2XdyzlJnfc6+B7Vyy19gMRT9p/LRyWYpXA0Y34OXphxodhviBz geNTz64w5saXAM2dFD4YS6eC9BP/gj/9fqa5W83MT/o8erl8LpFJgcbmp4V3o6+R2Plr2HLS152r gu2kYid/6rWa1OUdjQ49vtGY9Y6s1jqWiuyzsMXF9q0mHe8FL0M2k0Y+fbW9apZM6vIurFXwPwcO uXbJctKt3KuwfTvsFqwmZXKpfMJqUpcXphW3d/oj/5E1goXqK5P7uCpbT3rqOdxlL94qlpOennEV Mime/UUEc4/HlXcyKbufrGfnd/V+9Dw9LuCk8cU99VX5py7rh0lDQX1SmEUhpQKTUtda3NszTRqJ 9N6GdpO+jV4++xWbSRM1MZrbYV1e07QqKZ2839hNerbD++LP1pMeel7G25+tG9OkwGGUaUtp//HP Tq9gNWkg3o0d20wa+dw/eUxcW08qVKtMTmaugMas1rqVa0d3bnrctdWkTO7lJWczqbjt/e5fpk2T wizatDXmNPh+Zz3pKZPca/miVUv0TraDJ+qk1ZDPhN6TK+Ho2aWcVTb7/J2bW+vjIVOIhlic9HBh 0rPWQLyphTiYlAmZV1p4eqyZJiWzqGuNfjdzr3aTZpjL/RfZetLzn1jia3R1YzlpOb7Hw6m0Xqu4 nW+VecZm0qcQU37zb1lPmj9rXT09+n36pC6vYdq7vX7bdtLyZ+m9bjfpKXOXHx5aTw== WuC9Lu9tLnF4ZLnWu+HFlu2kd2+nWxO7Sa+Z+5N8Rp8U1mKY9vI4+/ZaenmxnPTl+vvcdtKvaqSZ s5n0Gbgl8zLuhqzXevU17F3LEm856dt5qG876chbDnj0SVGKGc/qLZPt9C4sJ5WuQluexEsoC5Py YfOhmb5F39RJ67zfdGhcXv9jobZPpuX2jn1n82stMO/7sSROemyaFIb9+tGYvnhgnnQ82D1SJ52c BGBf5tfqea49+ZVJU1X2fJ4VBkfj22MPTppY5EnnIW2lh6xpUsBY/GxLVKY9YfMhEysMDoUrRdLw O7F0fn7SndGoVu/jpCnzSkfJ1kCj3hTQmFmUR75iqqQ5iZXCJgRvDVrvFUWmtmpv4jxIZ7e7r4OY 1VMikSNn1RLbu7N7+5M5e/dObZ8C683s2jyFHdgNpL0qt2RaX62o6bkosW8a3ONvyfy0/7n1YPs0 WjyPPetPF3Zf4vZv3m3flj5rr3u2T5Pc7mPD6qmqwxQC/RPO9u1C/fojbvv0eqtRP7N5Kp3tnh3e jjWMfez9yKa3bwMdTT39YLdi5qf1i3Lf9uldJvA90p8uYOzeWz/w2L59/5yJHdk+ffe+RnesnqoY +5oUh2e2b3/fcamS7dPed+741e4poKoUj8wwtvj8ghOOH2yfNvr1csHu6a5n9/x53x5ju9nkZb1l +/YFd7LF2j1Nergdf8wWY5EzJnu0r6065oubznSgUhqfqE/T4UPT08r76X7S+FQI3iBDKSnGXDq0 nwbdcjJ8fUm3Pyvo1EseHctnO0hZ9z7VWj5pxGzMvvFD4u7jtpysVLz3hEUlK5dNIVsbPXkDqcH4 Sm8Du7I2etwjfC7GSp4rwsw8+/k46wlmbu49wbvXsif41qx4fE/+Kf5WBBL8TntC+bfIolFYbSdL fFkCqNMBsE4H3+JOVP5AS3yf82h25YuUe5s81xLxIbuVuQhsR7Sl7faSg8wrkOm2vMXtHRWPM639 rJecOzRnnjQsWvdzKT3R2pKX9yT9jmPpp6pjPzDD6js333o/l9e257730DNwHFHcpl0L2GLRG/8L xYg7fT7+RtHPe925rFGsRdxGod6gGHHvvB5ua/22e7n0x4V0cHnRisKf+9vJ6GOXV2xkPwjHj0OF Tpgx101Wkv0ccxER9hWyQfcHWMsRThe84lZVuMw+Nn4+DjpHdb/4KBbOVLs5ujuaCeB0cvBz60cO s7glft/JU3c5eGhLv9AAt5WrhY1eBVvwmFz+sGgCz3I3hKvMuxVwhFvq4FXfqMA73RFpgDstbT8a dH478KSzOWKxxV31ZjlwQGPK1l7l72jAy2ZvczPcZZLl4PcODFCqHnS2Y8G5CQKHZhqLGUBh9yKv mY9KhkeQBVzaob5SNnjLhvRJR1M+zVBMCjr//LREO15z0kBsMMnipEOCFoabJj7Tn8Kbui+gah4P M9lGsSJqbsX2NNuoth6UNo2P5zPnzSPQlHLTbjReui6ib5GbPb3B38AI/5bPAergdy59EiuTbTdY FuPA8XF2D6At7yOMYbLq46GvOVZdNfMORmWlbW83ebt9hFoBs5Usdz2jXFa6OVAHvWr8BI6LuwOY BYWZOPGxp+qLO82MojYDZKmDz1bGq/wAOriHwYqiam3BfLMtIcvIoJMhN7+MjMGrQJbhNfzAmWPv P8WYQbTOgfezEnDkVC4Fr86fWYFnAdy+LXC4FhW8MQ14hEIJVaojXkh2y53q42m7b7tg+HGjLFfx 3VgsF4yrwvLlulbZjb2tNUlF5ckLu3Fa7CERt/EgbStcR7wgauyddCyf3hbBctr1kh/c3glzjoCc z4YqaZyvKELnpwzsCxhId5T7S0F8A3Y/9ZVjWDnyleATj6jB7fpmvosK04Rd9Xq1H8K+eiCJy2Au AhF7H43rsE3xEC0CXXSn7fT55zcI1LVxFYWoJz/++oDoCORSj/IF+i3nULgSAi042o0VR5udympw aMYyM3xNr8fRsgjNqY4RVSJb4+Q0v4sz31jufvb5emLaq8jwQC6a9oqwd5fXlsHPjXjnoRhR/VF7 yCCCzmx3/zXL78Tzhbm92t6z3KtWMbyr7osFxk5ipcvNYCwToNzJXZfKD615w2sWHQX3Jvm6Okgu LwIVpgXKASSwWatWIFnISic8MU4gDQJHugpBWIFyXi6WgJcOPy3F2K6uihhPL3FeamC6vBbnt7xE I6lzCyLf+fSSfbE8vzkrxcpi43Xd6omMqAbW5sZzeZURT3zZPBUpGYTMpWzNI2G5CmOenTqiw5jO nU+yVv3mUG2giNrWJbcci3he5mhCXzq8PTmdLX2ojy1VdvcuTyvPX02GTT23M+Gb26Ae7iczw1C3 I50nqbLSSiYtV2PnRnwYL5dxLu8cITrrWd/SZHW9zeVdOuJ0M5rgTIp9yx6qEY/q+/o5sKJa7HyK 3v0LM082SXYa82JuXz63N70v8s6m90Wmsm5W2RdppMhSJ5UGjVCCVFXtOrXhtM1TXWt1eZeqXTRM St3u07uB7eYAT17nGN4tCJmlqHR5nY/hiK3t7J39BpUmHQaQSafBroLK+hilmKOWvbJhfmsSgzN7 n2BnckxlXNKpsWe6GutAY7pqb6lscKmHT7PSaYUMl8HosN79yQmVNbn0aJowdkLFPuiM5zPdeP4t xqpbu5vB2PGYjvXMrKlFDV3RYYAcTsv9lSxHW5BWtpGtzQYEqTpcCSQlwmsNFBVfoQDpbUR19uct bDulun1moVQv8Y/NLOxyfD70dKMNe+hLRl89Ye5lXE+lP6Nnw0w+/5PSgjVk0q9zprlXyxJkuLz0 RjjJFrIg55dx34EBuLwWODmzwcnX+Yp7pQHnMqd5auBNHNSSleSey8u9TLzUJGBlZpuWu2hk0/iU bHdjEtijBc5FsxuYg3C7qgfIaN3M8eQTX2ZixSDWJ75PbhZ7XUUu2nD58+UuNKOmREvOq7vQiAZr YyAiAokT7TcIJAxu5k9WtY97eyP8hL1YMGcoXWiWnt4LkxNtTe8LvxPz7ZC9Aj7m7ESjON0wYtgs m/XxFnbf8XT3LlZ3odlgbN6JtjbG5B9m8bys46/qXVC40Fy0QPG/caGpUR4FKDsn2sp4iphAAilG QfNzvpI5igezgcI561qmOqgpJ9eGIOJJrDixCyLmkc6zlB5FZ/89UOD2SttkoOR52hnmTT4um2NB ZTKTUwkjvkxTeZqDhj+WSxX+5DbmM+0V6JbWrnT/LuECdhjzbwpjFnJ4HcI+ufXyixHedRgAgPSx 9/NgC9JcJNERKPNpowXJZO8jUAvi1tYba61Pz+2fxypiZUtZ1j5vC1MfyWc7btLQdT72ULY9uusE 3k6LPTb7Mj416fxrBHPSALdg1o+s+RitzEXCPqDWLubtdEtZiTAe0YTWHE4voo0/uatc0u2+E9r8 PmcPPM25I7Sx4M2jXd+8hwRWuPwQ0x5h3ES/brj9msb8C4FxC4pw0UpfMiJtlM48noHGLGIfrz9L Ylen5T6toHN5KUQd7n7lN+GmmY08B+MqLNPrwDJxPDgvjrFCpxEtnBqob/p1Xcflndd20sARYpTH giJ95OGWGCmEJ//2bIy/HRjcjJJpIyPAAFZXeHAtNioPwugQIaTkTrd4XjZhqyBIgUX/prpIrLBb gaVgrk1w9fXNPIomwlj0TK4lX+4GxFzZEI0FFnmN0S9AMiHnA8eOfBPR5hjlmQsbu+hNF8SibeAY xZL9hilnf6WIRxoenI9W2jU7fzLAvWn75eFuo1kEAKHJ8WCVRUB3crLPz2YHqi3aXN5l5A7bvREj BuULUMeiH3HN9Vkn8Gj1lSvwvjsr7+HaNLZW7p21WCYV3DiiTbThN7EGZGEBIpZdXqtMZmAuBUqc 0IhlktO7Ce8hws3ScRh6sfz8s5JYdjl4IhBG4ddiWeEw9xsSywBSyEos28Qslh++2tblatlzth4S WN+mxPLzD3KYTfgRCbJsxbKuw6wqlq3yuezEMkpkLcePTiy/jZaI5ZiPnlvSiGUA7snJWG9Nbg8s rSS7wOrDg0Vm/9JsRf1sl+O2PPlttHG5/7BZuf82WkHu2/mr5rdb3KgljnlDNLa9YTw7Xx9usrMj ZEY7NA4/Jb7vfPZpMl2tvH5c6qGaJF4/l3cxMv9Q3azXD/OUdL+fDcGumEqKKoSZ9VhERqhSSY1k kXr43lq+k2pkhNqtCIDSOpUNbkXAmE1oGGGcmAP/zoqMJYtSzn6VXiLTkG59bFKvl2baL0tRQtwd OKrXKuXMPL3OZz/18OboZFhMTCdYnJf7qtjSdYpUrPMafEiWgw+D5E2/nk+FpMH1Ap5md2iZb8vi xm1PqF96c3mxejrrCSX5V0/oQs6qhdMXctUT/Pyq4I8wtuWw1DpN6q3xBonDZPm795Ft3J80cC1Z rMisZmrl40LOPzpD9+rOXi7zHdrCKmpB1ZSUAuviWaWYDYz5XV3Sikdf9fNsPZRYLLa9OrnR92pJ v+IBM1f3at+zFCtS9BtN38Mhq34u72LPGEsz81bu1XLExX7NA7q1bOW+KGce8lRrwQuyIlQjnoZk Qz+7StnROBYYG+4hsS/kFR4+C7P7CewKeQ+3fLaFvBizMGwJG6YAL3AY7904Aidub/+I02c98m5f Z/xEV6PdcyggV28GY3KDSoUCvN1C67PpXATdMgEH1qtlfftV6YECd0z26umUYmNd3rnCf3vwSmsX Ru8fHRhojLoeG6ux4ytN6vIa1o/3Da0zqeAvKpOqroXCQyKW89ZUGJRYktgflhOHnckDjn2bDew3 w8lr9uQe2qZbJhVrSTgmNx052vu6OWCvwVsZTcXdnl0aRkbX6hwyh/cpyygX6hnnbT9DJNEYMLWv Gl1wp9AAZ2clFXcXsOxcqGILHHKYhYKt3yTwZywMroy5sn4Fk6u4R12XQ1fDu6gTrkYq8xHe4u6A LkccmB5dyXJghXxLGuKjrUyZVwjtq74tAtoOCCT5lsuqvqkSkp0QiLOoKFyIBv7igJgSy5ZU2C1B oBVHqwb7dhwtq9wISmGp0nG0atCSMa/ugX/Nru6gUSq57OLtMOJGEsu03c8+Vx3sXCofZTVkmYq3 DsZWj8lYZ9pjIIXWs+NYCQ1HeANRUQSJMvJOA5RTloS9V8geY/YRiOX2sNXpVXZfO791bmB3fnO/ Ob0WOSR1jio9nDqMUue3qHMUKUq3csSvZ3Xq1PtgLTyFzj7mWo62It5lsXTHCh7QtxM2FTzNU72C Z3nNCH3NqWNRhjqUGk2gKpSkUist9TbLvL5Tytt6qEs5qXXL+XNgX1tsWcA4x5NpzIu5fVmUPr/e F+dLgFbdFzqVdaV9obsJaJVqZXPYCj0kv7mcCauVnSuZXKsdQ0rl1YzK2W3zVoeG7k4gClSqOgwi 0zH6uCoq9Zqm5TWJKxvmk+MfKzGo172aBeH6hvnk2CwG7Whsptpb00H7bCWTY3anyg== wu6fUTK4oKJdvHOv77ZHU8OYhfm8tvE8OTGL+bUxRjK1N4IxOtaj62N2xDDGU7kop5dYjvYgrWwj 2wK1GBCkAsngUZwBRcVXKEDSbbblZ3/ewrYJUGKQaSFlxto/ZrKwna65GX7YX3PzMm6bkxhcXmcj fEkRNOU2uSjLZH/MVudKwJki71/ny1NNV1U/YTxUc2jvhXOq3+JeJj77GxbsfUpLarRXYS5OudZY tLyOB8jCulF48vlyBrH6ck1aiOXtQBZycUnJMoU8cy0e8SUIdDjitgi01GDPraozV0TgnO7h8qrV mezF2M4Iv/i1C22+sp7NL5gf69X1Utw/ttLphhGdXWgu+urMnRhrvuJgreonwJhDSRZ9JTR93oVT 2TF1FcbyGw6xEnoThV0uLwL1+xxUFSQbF9oKt50Y9+9iungVwpJct1m2rVOe1oN9EBFLQilreaj8 9/k1k5mNGRFaES1Lk51EfRXCyW10b+Gum5XuEzVV5tpehbBaLU9+zTxmK4x5Hd2vlJXQs6sQDBHe Ncuzac6ai648+5cpzKq9j0DRJIFSpoDmrSNWK2bSWSYuF3u2GjreBV17o6rGpzu4WFMaNitda90S gHCvFLYy1FjZlomWf51XvFApvJHbgBFtiSnt7juhjTZ25aIqX/5tPZGijZNiY+p7ih0rvReM7LVp bKWbEVzOhb44In2Zr6U0V2ZZLPT9avlsv4zANHePaOr4dEE3k/u2NxB8tRwvTHYMNyla3wxGjr7e XB/Rtn4dxjugvrfHdkSr+vWRla4zu90US1QXfFhWx4IqfQTFpCFErHGY9eqMaS9ypo6MYLVrYbqm wmNTKbwYa1mzuJffzK1NpHh5wb9pnWlPU77sfAWU7fpUzq+XLzuWKlBXeoc3R2M2gWNT2NgQ5XHO 08eqb6c6TMtUApRijiUmoK8cH9sEjkmBqpPPwbVCxOO0Olxz18z+5PRK30Ogqv/Y++E2mUWQts3d mcsioDo51eGiR3Gte+HSK30UwbF4+W5Aa/E5rW9Td0Mpld4L3sO1acz5ywj0lgwZj13re0mOYnkS WHYXNGiFmxTLYCjSaxfLqeieQizPqjgpxXJt640yZ84olpdVCm9GLAPaIpu5S40ULy8Ry6abJ53K l9cUywseElK+vCGxXNu63NDNkwRZTmIZ7f3VKj8BbSuLZWqPYnFZPhcpZF0ill1GK4pKLL+NVq/7 tF7LfC3watmKVnWfCzwZetZpvlpEL/djPmGjch8g/N6hlfsUt35jzfcKdZ8UlvjbiD6J16buU/X1 kfp+2spP6rrPvaM71vnsr5DpOuf1q49NXr85ywJLWTfo9eNSD82p453DK6aSYuG3zXUFhsiI/YUF NmRRH9O6Falvn6tu+va5+pjarUhzXUE6HF3h7NOVLK9834X9Jq96XQHF2Qfq/+11BarcV8SWzhuO xRKfvBkkaqluNN87DDCZV4tjMftQ9eInqX03O1GsmC5jxXTB5fWEpNCb5Yeq9ytJcc0PVZs+U+3y /pEPVZs+U004/+Y/VG3q5/L+kQ9Vmz5TvXwta3+o2nYtG/1Qtekz1XgTxR/4ULXVl743/6FqE3Au 7x/5UHVg/jPVsJY/8aFqE3DEB7v5D1WbPlOt1b5t+EPVps9UY5baH/hQtWlS/Dr2H/hQNcJg+Ez1 zKuw2Q9Vz0sfowd+kx+qXjVz2KGM0uZD1RaRRINm88sPVdsBZ7aSaD9UTVtAPqar4V3vQ9Wm8Rbv 6nQ0uWg+VL1SDS/dh6qdSUVZC/WHqqlLluc/U22fb0lLfJYfqnbOt/zth6otEGj7pe8Vk8eXIxDv 7KK6LJP2gAysvrFjVWFHjcAF14nTLQEOZu+y8uwNR3lsyrMp/HYLX5Te4P15enE27dcZnDJLlxdn r+KDtSnPXgdjm7ky11Sc/ZuoqFqevYGsG4rybAqQyL78rjybojjbDmNrOq1sirO1L0pv8nKFxeJs my8ZrVKeTZ2j+KvybAqPmm2Uh748m6I4Wz+Va5dnU3A527XQl2dTf7X8V+XZFptoLs6212FWGNGx dtFKiq1Ynm2gWrvi7CX7QluevcK+/KI82xKL87GGjeyLo/a74l2dVuXZv/8CO015NoWyoX+Vae3y bIribGM04beV7vbF2evdaj5Xnk2BSrv85BXKsymKs1eOii6WZ1OUGlvl9a1Ynk1RnO1wLxxNeTZF cfZ81s1a5dlrY2zFCkrH4myn80JRdkwhpV2UQK1YfWkCaZZtu3559iJIFnnjvy7Ppqys/2V5tnNx tjHXGtfaMicOUq/U6uad2bezre7oNn49m75Wfdm3s6m+J05dNm7HmEw1VrTgrfjtbKdM+818O1uX yNZfz157N+a+nU19k96vvp1tpcEuq6OmUmkWlmv7bfRPuotcHAvRSRU1sffX8Out9u1sy7s6qRFI p8jQ36vwuVAZR319CahDBj9//s9VjNvc1LrhinEKL9wGKsYXa0X/RMW4PcY2WTG+gRsOKSrGaW84 /F3FuDHn6s9VjNN80eD3FeMuh4SjzVSML2YQ/YmK8VmFnWWx8aYqxvVK4SjlQVunYnzdb9itVjG+ HGObqhjH/OT1a6doK8bNsdc/UzFuWVm/8Ypx+rsIflMxPl+V9qcqxpfljm6uYnyluwfXrhi3/VrW RivGN1OX5FQxvkJd0i8qxhdy4P9IxfgGaIyiYtxFL31/UTE+R2N/rGJ8lW/Wr18xbvPN+g1XjJMb QTna6Oq6FeMu7+I3zzdfMb6hGiuHinEDJdOXpq1cMa74+uxUnk1VjCvaBb8ptNmUpq1e97pOxbi1 72LTFeObo7HFWPbi3YMrlqatWDHuWsl0Wbdi3Hxn15+pGLe/qXWTFeOz6qc96vvX1qgY/81dN/QV 4y6KD17/XtnQvlpOUdLyi4pxu+/ybLZifDmNLVaMr1rfPXc7kOVHHzZXMY7f4LbKl95sxbjyjdTf 524trxg3c5g/UzHucvZEbKBifMZh2C3ar5KuUTG+5t1QK1aML/GQbLBiHLTxWc34H6kYJ2LZ/gsg m6wY178AssK3gleuGKeIjGygYtzCSvoDFeNk923LiTdVMW6oeqZ1WK9RMb7eDYerVoyvZImvXTFu cUfEH6gYJxVDd5v8NtKc10+tGHd5rT9xv9mKcVjLrGb8z1WMW0ZGNl4xrkdGqN2Ka1SMk7w+20/c b6pifHb20+Hon6sYd8i031DF+Er3j61dMW5z/9jyivFFPC2pGMfacPwG95+qDtdrw+Hs/7HqcL0f YuxPVYfr/VzeP1cdvnwtm6oO1/u5vH+uOlwvtl380vfmqsP12nC9amDz1eE6cHNfYd5wdThdZf1v q8NNlfV/qDrcsbJ+I9Xhepk26Px/rDpcrw3X5MufqA5XRUK3PQWM/bHqcF0xVK2kP1IdbpcDv9nq cJMO84eqw80+pT9THb65L+Utqw5fo15sjerwpV8v3Vh1uF4bvkZOL3V1uL5cy69mbKg63CKj+w9U h1tmdG+8OlwPYzvUWfyqOtzKStpYdbiGO6s6iz9QHa4jw+VIT+tXhy/U8P6R6nC6/LHfVocbswj+ XHX4YtXzn6gOX5ajuLnqcKcI72aqw/XacIds219Vh9thbLPV4XptOE3m8LrV4TbZgxuuDtdlvVrN 8Ueqw3VEm+5V2Gh1uJ6M5PL+uepw27VstDpcrw0309gmq8PtdZhNVodbSbHNV4cv2ZcNVofrteGb 3Re7T3f/Yl9W+HT3Eovv19Xh+mZb6Pwbqw7XNxtj4n+qOtypinMz1eFzttgfqw6nuleB+SgIz0tR afAbqAs3xpENCRIur5Yi0WvZf8A39fC6+gdAz23PfvtsU4W8lLdq6NLeUsOD9X1TfQH4nXtFz1Wn +MA6kFLq4cd8K/ZKpZwLGFuxlNMOY7T3XThjbPHm3xXu7Jpbmq0JvxJIJJL4RpWO5Py9dFtmZZ/X Z4unFYtI56xXE1Br3OJmF+giX2Cnrfek0PlxpQu5O7jSOZ3fwlK31/RPfJmRnaZ/brLTf/0V5uxC GZoN56er9l3L6Wh7EziAt2AU/8bpCON5V/gyi6PT8dzW6bg8D9Z+N/ZWOjQOVtL5eldSLqust0gJ +90nwGcC0eXdxM0Jnwvp7fMItPkO7xIELknctkWgrQ6DxetOyWHUCMRZsHjdyZ5QcWchIS0yRsft JbVv/I48pKlsoPPB9i6sdn+NrMCLjX/172KzXzQALrFwsNcrfdbzvX+LMccP/tH5LbF6ekPfSL0g Gd+/zxsnIFmkelvd1EqBJ0c/03zKnlLLY5eihcXrv/w86sw7Olfsxp9UJhkb79Iwv2aWt7UPlj+5 DZhvgFlnm2IlLSrqlFNHK95jJftjtsaN0/nVE7xtMXbk3wjGPFq92C8TqfMUSWR0X/xEoH6T222I 8eWtfBtr4skUNVoe5XFS8rF0nSYd0LV6gcZwScIClsZaHNy1b5zGuBB1kY/L61RTTCdzl0vcue8j n73HzO6W9S+KwNJ17fQaIrxrfWm39kZzwYOLshSbSvDakrj+FWasW9/EbRFK1fr8EV73Vg1StR7c HI2tKn2tZK9uv5AR69Q0tkLyeLmPPNnGj4iOHqoybmdBp+9+uW97HdLqYWyEcF9nmY66pWFEuzIP MuLSa3VcXooRLWtT95ORI7simFtLD8n6sVAQkxTizUVzNgDuHA3x2TruF+ssgAHQ3j1DVZu6nywu 3j24VvnY3WB5berc7juWYu+vaT6Z/MmEOjZTm4rl15qz9LfyBavWnWtTaWksvpAgYXYiLctAsPlm vQXfNDtCKArlZoFxwpO1ezoAj/u2yaJs9jlNYxRa+Rws13K30lVZSyuKKb9dSx01A/N3o3fcIYyr 3fdg/33ku5Xuy1peiK1V1/76kga7FCVLi8/5S+freB+svl+JdetrXZplhSyrexStXKSUH8PEEe3C H1Y0tsKVEbWt0xM7sXyvi2UHbkkplp9/lovlFeRLbeuBxqtpJZZt7iGB3ac9dzRimdS91jfgc0G0 2Yrlxd13/Hg3taavHz1Lnny/MbGM5dcgljdwi6ZStb5ULK9EY5eOFzzYiOVl36zfnFhe8Chi2DVo K5YBxlsa08wklu3X8uAslqkrV3Ur6W3kqFgtfPPcuX6d27TcfxttWO7HfLQXSnjnIolLyuv7v7xq cd4Sf1jBEaKOaIs7kxuEourZWUxi/brz2aepYLfw+r15lnn96oaPECy3xOm8fh/psIONiH4YmysX lpU0fzpduDCfgeuiuNOg+mu34sI9ilY5Sb9wK1Yt8y3Xvn2YlK7TS2S6z50fUKvXWi2PjdiyTC1a 48KF+bNfpfHzr2JN6kIL8y0LQthebL2M2w7Xg6nLWPZdiHnr9TZ2YDsfRcTcdr7ZjTqqxxHxWKhk 6weNXrLfCA2Ske700iQDyFSpbktkEoff18+5/d1rjbk0kruZj6GfTebvHwuzfQYrSQ== r7xXT5G5+/uV3l3vrNRqqTgpXKe6kodNX92XWrnD7HMY1nfvy/lLXDLxk3r1YWWKYg7MWk8aORyx mIhXSlOsjz6TQp7dafY+de+ZP1zFTCNWa2Yb79niaMSNk5799qh0EPLGdvn7y0gyIgbGn+cHg2nN 5d07a0ny/snTzuOW53zi9yRzNwdb1VcxtlO+3854v/vlwl7rcxgSy4Wft+h3s9BOfL9ffeZbZVm+ ej77uSuzw/xH+bPU6d6eHlxO795O/b63t3TA/1WNfF33ioH4h8s7DDwmJiNv2bc3GvE7nq1Ba3Dg ZXY+4/7HQuMuIAcufcc/O71CjHu/OUoyh4dbo9FJrOjZfzm99HCp624g3hASTI45OWZylfscc7o9 uGJOr68+R6POSWg0/TwGbjneC17Vw3xBjiXL2+09UkIO63vOhqKF3S8pepLOp7rRUoAUb8NKKxWA odUMWFy4YJHnoOyky2t55YK/05U9ga5Qwul5nXRjXG2vlDgMnQlKQfte6ufGGsddVih/3u78jBJ9 8crl9dxf5QMOKJq+h3f2d70PxR0p3k15i+XTi7338vmRIO9eirCqlCdZOaifYIF8JXB0ELpH4KKJ +MtrN3Ph852Qr2NXS0z2Lvo2Grcvthmu9LydjL4kWpnz3slDIjZ8OTR58oFHXv5kg9I4LBcvSp3Z 6TXQOciFYlo/FC6vdixeLnXxznDdyWH6U7yuwl6NX5OwF/dz4zx5rcY2433/JTf1BD+/HvC+i7vX rCd4ef/g8YVqW3jLxQX+iHtCSb7oCR3svuI2HXtC/dKzJ9AIy4iOSPKm8ryXrTPxKBk7es8zTXLz Bfkt3notfgL3vffBqrYP8Tbgs4+XTGs0CiZ7g8IYVnX/g23NXDrl2Up8bSe76U7tgGWY8ftupn79 dpWUgsNBIHv3cAadH7ZgvsA7ov+ceztrBhn2ddub6l2/SLl0clpLDMdsXfvi57HYCGYbje39RPzi G459Pj8hRhPDTSfbidF2c5QKSd0rht3zt5Plxt40WdqX7pKDQbiAiuqOWM3384nYdfor+x5qTxKH J4I3kyrcNXAtUZc39/52PUxWMo8ckHvwKPPBVPFaD5kla8U/3xOHomeEx8I/a+sd+hOFcqrb3wvh YLe4k5HU90/Mmyold8SUMAk85XyDdzbzEXq6Jpz/XQCiak5wnGrm4+U+muomujyOSOJBnvTnU2Ma uwzwT0gHeQI8kFfoIpe9vJNynuBNLvfmf8qLk+FrEfbqJAiAeHynk7dhHVb1ICBPvpgGEvGCB+/V 3d/O5PNnUXh7Ozw3jm9P25zMCBc+zqVboaeUEOn7CQloe/rgTX+Gzptn22FvVN9nPPvv51sAfI8N ZILeac53dn4eu0pNnzLn54ldvS3e5qrfqbPb/o8yHzethmCRzS29i/gofj0lbz7ao8zHwc5btrH9 fUKmgrUAAP5c9uc5ltv3BwPiduyhnG0ED0Nzi7ziYNJUn7iOdBhT35c3B0AHzyO8iyBNeFvmI3Uv 5TKRRw4IqVrIZTk/6DAGdHDbb98JPnXwpfzJtqMDgDa9bVhQ/vF0YAD+KPdzRnYNtuSplBhNc3tA DNU7hvdsSZnw9WeGbCLoYx+9+E6y5Km2YRnRi8zF+3gX5N3RC8MFW92UmLj/IfKVYQfVLrCmh0ny mg2V1c1pDktkf9UuqXorcfdxew8Mda+QKlVPGYIMQmMfsIM3vXLu+azQSl6nU9VM/txzt/CgzVyQ 033kCwXfxWrhNpF7be1UM+fdwFXmYzA6VhgXHy/vptqPpbv4x7SYRsJ9hrOPh1PRrggLm3U68k25 99PDoa+We/fHMhhuu1ZhfNr/zgY6jxNxO339tgCS2JzAvpzswMjnfTwvd2Qtzy9HL/nsQaYd8tWT khgN5zLVShDQFn1iuEk8KRe97Yf4RapxnzsZnxZz73fVJChTFQGPVCpZDu1cpi+P+mmVWzQK41Sp dH2bavSnr+q+SP32M5+tlx5QF8yHxRPx4TSdvREmKgnkq9108z54n/kojd+QCd/msuxoJxOs/eAK HkOZg9rhbqzd37sFuCK+TGt8Iqi48wgyUYJAt+S5wiT3FryLoRpbMpoNVr4prnAPxBmXcP+KtDOD fLGYe+WZc+nPaF710CJHAz6dq6AElMXbI7wVMHm7G38nnfAukXt85yLV9VYq6XZ77AG4LyUET8o2 Iu/+6F23cKqfl+hd6akCP3q13OHp0ylhZqQtdtWOd2KdV+kDHrCwFvVAAgCZVmfwdOo9ff7K1ivZ iD4YcLTUrfhQG96R7UbiLGdaD35+9ud76ps78mhC5GwPr35pprrhmwBYQS9+QmPZXaB5IZvztU5e koPP633VAtMfNL+esrVaRD6Wz7mBgtnLs7vvxOi0B/qD/7WUCd80OPJ0XudPI59+gbW0PytvoFsn jyx02ZjBLQ5MagtY6+1OIj7oVVPXk9o43op5+4oFdj4efOTeC9M9PUtAb5vd1nj80yNX1YDiGN2L 7Q44ARTjn7vEwWQ/E5AjwiH8dniROBgPT+DB5UVmWitew4Ojk5y8c9NMv1xsnxEFK3oX2rrMvV/u RlWn4zAJVtL8Mb0GkLlptvF4RITjDUixwxGezw7uwTnoAjxPfBd44ivkyEXjjYeQqV82sC9+iEdf 9fNsPZQ4V7I7duIfZweV5DUzvERCO1dE+bTH12HPfyrkphhyKxdwgYc0UWjhnAs+YKg/DaJsHIbe cwP99i5JHhx8JMuT4TSZf/RLsBYkP0PrTf/7OVvf3X87O3rm7xV1+PrH30hdT/d8yMzOMh+vW99n 2zenYeDyz/d4MdBPznfx5QO0DBh1qGmJUCAcXCZ44PKysOXHMJjMAQNsbwMf37uA/f3ZBUWm6kve dIf72cb3jwwaUDKEU3WIiILDEHwE9p/YIlRCrhc68t8HOgQtZLnECsTPI4XVbFv29DWMBS/ZrVw2 44+aepqdFWyl4wOQmE9QjbY+U6FYZkdhlLMfYBS2PDDAzVaydNX6grMvtKeNeRLA+wKkQeZi/2kH hmgNDVpfIwVSG9EvC29PN4fBx8xzLhMUAwb5eXJzeJ/z7b50svVyfpoNFMJKpXDKm8mn3vncc3On TXYf21hgAPEJKMHXHrmbazzHW7f+TqrxszVSucXO1jjnL3ZigePo3Vn6/Tu1n2m9Tx9zb5PPbiKW 89ZmD7ZcXmApL8cKD3kU28+gj+UN2gxYP2I0l+kGFUGIBzslTvKTo9xb98CTiGXjxaQcz4e03Q0O QPdoT3PJXiyo3X7Uvp73Wq9iNhivwQvtJMb+h61M/uLxPc3e9sY5z345pD/AL0tefLRhzyPRlBhk H3DEi9Q3W2tkcs+X7Wzg8/URT+A78TilO1/iAehM99PoiD/rpAqPgwc4i7FnEOSfO8Ajr4RE7Opb Tl0Xhx1QaWK78tfI8+TyqqSksLAPJtXtDUPK0dUV7MdGixmNjg6wyzZoLh95llC8PphisOxGBvr1 WFWQcjdbOX+1OAEau06HjomCiRufRMM9hBYKo8O9ON8ooHuzjnzdeAfw2fYkfpLbicRhsNkkl34R X8H2jzi9dHkNyuTifEXDDVx2OFHuvkrvnGRtVwq7r6z1kbuwWqvFzNuOKx3sm1ZK/DBWawXb3pva ySxdaYl2pWBX8udPPaPF0GyXTLhlcw+n7MztlIpx9YMO2mw1NCC+iDwj/EB7UM+bpB2efXgeb3u8 X9lG9Z1LdS8OemAWHkfQ45jCjwsUcu+xgZDzyaI/GwoMhrqNddAJxvAsPsqJ+5J3y/Ld1w+s5AJG ko/GOunMJ+G1KPJ9yDyD8Y/g6DHdvLu/VC3e42wQDTcZTIlTwGKd2cl8fJT4mR3rz4TD58E4c/Lh gS4Hr7psdnnl67v2de71eaAIodgV030Tpzf8Pdj7500Ypxgh3hC8bxF08OHTa/K6cPaIqn0p984l IwqNHcZ7Nwx3dj3NnE6irVQkE7rTnwLG4o3rS5BExQFIIrkGnLgxVuAhasD0nTXc9mcECeSnPUhP I5CzM5BA5zcDlRmXbYEKxLu3V6uDhLtf3O3ZAKXcI3lli6f52wqvwIZ6207ExqEBbvxZNnA1qIBh cwUWX7LYK7dz6cZNGv0+j3jkuHTnKBWwnPSmx71qzuLMOHMR2N9OCfdcCk1PJlke98tAVAfTufUl eCLF/FOQKhcPZNq5Sf3PhnNnNAA7JQWpuWSmYYlyBanntQcyKdiVxmljrPVOT45/aHd6YVKuXTJE RgxoxS8bF3S0Lq7PFqkwaeJ+v0ZAgmMWfCVP0T+mPce7Sp8VoEr78Wcr8rICCXSh70s7kF4JSGhZ 2AGFmDABpT/FOzhfaEGC86IDdVKZXC0Hak2QXN6VgNJBwrinn5YdWZz9ZQxpTXZEfH3V4UrUbzpy 6oGc5J4tJ8XjiDT2ctFWVNq5jajaHMiX2rJzDgfO4pRjnpI6LF7IKh/j7jcsJn3Qd9+O5LoWrOcE bwS6ACm2ucNne/RA66Mlqo90OLQmm4Hd/xMCBUjqc6qTlI0UW0JUR5z1sMVne0rV1rJkWDs+XXz7 oT0AQGP00LbGtsMyuZR4bQuryzveyrUZm2EHnvWPK8A6O654e7bNgV31uL63bY8rruX0LLVMLFf7 NsM23myHBQR9GbgAcpiFYV/smMuLDdWW+9YnrCAc6XFkI0fgT24LBQt0vNpsXXVgqSkFC4G4znDI rebKBAkuVWXPLSZozaLHX9n6wQfGNkqvROlW3kD/fOr7MjQBdf/5PtvYFncUV/j1q3hMwhHogVfM WX6XuInU3y4+vtEPc8MGvqN7DJtP9k4fTo7qSeb4oqc5Z6Gtuu9ppD+fUt6Z77+L8ZwfLb7kF4l3 BTO7NL8QrL8bRhfNceajUsJgzuN++uPos4iGu+KwP6yL8X7q23fzEW/tiUXcqyd84wIMlrO+4myC P6VZXOgZzDrf9uyrGaL/Z2YbfQEXzDJKqIfkTighsVz1VQkVsPnvSS7BXNwCHsKP6p97mXsllKV4 /LEtefotkKgRWuJq3OgcgxhcsnJ3GwC6ewkYbRowOQ5Pu8fVbH1wFkoWm/GmIVjF+/vbYMfd7mTO u7e3JscnCQShlcTEo5pDNzhGk8urhE8OQ/et1Hfha6T4B+eCObXk7e7hMWz33fViQOm+q9u2JCKF 33ycj0lxZ+mhQiL5armv7fTkSwmu5E9+BD3yg9vZSXde3zit7TEOW7LvnwWw9mHNzD5Sss/vM8TF Lr62f8haovf8Yc04PYnHPo2F1PfeaU4z631eY6ArffyilmvNXmPzVZT775feLkasRMXi67xe9IHG RiLG6bbk72QW0ObnZzHTBw8cvvxohp2JEj0ddRp+DdZ7KfHA+MPan7tg7+d8ecaLzulLOHK1XYUY mrvBfG6fO+a0bXyU0Oru5N738i9wAo+2SWQE3ZgZA0sBGkqA/f3QS1Yus3l9c1xezQ== /+uVsVMcWj1fydIVaJkY6tHRMYsgyXgOCkrwCO24+QfFRLx3nDYEfV74bBdsZOKA04JCxEFV1UJG 4ihRTudvQA/xn5MoHjpBJQw4PGldUl9JqfH4kDl4KEWVcNosGAXblPlIxJ+TF4Qnm4GKYrToKNmv 196V84K35xzujVvtrG/rrp3JeT8u5gNKF+J9zz9IDobDekqYpkqmiJTCYT5zJ+Pnu8Dx9uE2vnMG mA/siNssc39wWf5GHfVkB/Sj/SfVEfJ+fgyc6mRsiFx2vZWSIZQzH4QBi6/16v8A7SqHmTPbEvqg B7MY0d3Z9s1RHInhEihmb0LcEYpD15wHqmVuzYIs1/qkuJa5aTc+Kbt3gRbfee27uBjb8l9IJVk6 BS7YqpDAuPoOCcaNIoVUKB6PEe89MArvNF0YTK4RzKF2Srhp+nN6U8HARA45jMLCSGvvK1lJ336Q ZcyOoV8JtxWfLp6zb8PmF9DiVkQbjASC2Ex2J/R5z3Ah3yRZDHUraswf/yxdle8wMuJvXish++/W C4xTYGup7vd5WQvjA51PfOHLxfi++kDc/vGUT4c7hyL63bcQqYVovHF7Q4QWSfZAWQm41aJFC6I1 1u6nSing0lupwmMpqbJWRbqeMBhFD6NQ68/kx2Gq+yzHCAx6nGYWf+metnOJduJZOQJkG9lU/dMU 0VHjNPL4hHwyQOmH9/wnfhKjQ+IdVN+VO57sXn+3BCCxTy6vOTfk+DTvI9GLROzB10lxX2E1Jq70 C4Z7Sngk3SjHzCGTdGtag+mTLVX3eKgWsvVws4VWUqe9rTiWQDiO1SDN6O5UTZBIpTygMBwntFCP b5cczePdcqwTOK4OFE1BCfoQl+xD7eeC8Omzo9c7hhAX0cf0AI/gzZxWE/Vk/8QzyJw/idtKyi1/ 6BOSkebpbeLno91XL/h6mISVQodOMBZAPWqQrNzv7GffxWHD0M/iTntxB4DK/aAH/gsTaUZqoHP2 A0OQmon31MzWvc26iQQQTxktEUqVj2QtO3u5zHfw9Oj+I51guO3vj6z/tdYGPaMyzj62Jruq0Nv7 8CYOI18dZMcvChcAZCW1lL5sH/NdSMpQEiQJxyditUI/9fl+iXZlJ/n8nq2XqjPZpgV97t+PK6nu Vj9HojyyeOpvYDgGtbCHDHkQPbwX3zDtpYMh8lI2WPk4MMCFn6AA6v0Za7qlwj7k5Hvi8CwdxsHi amhY3d9YshxMgLLRqUxIsgtqzJdaduT4v49dAsMKbiHKiu6Dm2m3NboeddqdvjvoirsOkucse9tv DnKjVqvS+s8kM2hMe63+xB1zHyTL6fNzCfhrY9BsQXfvXDyn8aFnOuppV7QxX8sg/aPYe3R5SehT zeES42PMMPWBrGuPF6LEx7X+affuq556vywlk8E++xI/Ye+kzHZzms2kz55ftCjq0FyxBKLIGZQV AAHdPji8ukjk5fGxdHZ4H84NHgVgrNnR8yOTecxVK7mj5FHDCh6NISo6z9dKkfOZwFseORfqB6ks d5YgQfPEx23lKnkmvl9RRc5Re1dVBEWT7/a30KR4UyLit6+5GvD8pytDogS2SZXn1H3qe1eaaCcE j+VXp6bwx5kQ1APgbLDdPlaYkS9br3QOM/n84d68CVMAtb8XxByeoprIo6RHvEQTsWtfCznJKVE0 NTWz9pT6zpwxKg9nMi8khIRhp/RTCxihvK9EX0h8ngTkhffQi/IlF9x4NVyvpRLqOVN6WyzPHhzo gRwlf6ReOdxGsRp8ieTejpM1+4w5e6PncXAJyziVVaEU8vWUPKrKxVRWRYh8+ePyJkaNMFGkJ9lm 7LhnYbj00UwMn748+2LpVrl4OxtnlohmCAKWrYwjlzd2WSudKOaBvtP3l8NzAvycDXSHcfeTH2Nb z7eX8zWeZ+zyBZTP4uOBIeqO6QioVPWOMDmvWwWB+CIbktfQqkp1Wyk20bseltQw3selrKf7YZxw V8lHNybtFB7A0mC+CWtE5OfwEz6RgYRZmSJIxZNbEA3j4JzhkhxlznOPW9qfhwB3/uHDuKDGjxfU ndeQJky07M3rglgiGYGouIeeMOVd+diaoOkWJGW20Mrkdv2lVOSuNNEyygw+EYwEHqN0vP/J+c4f bmabc6mmuoYS6J5gdmD3MTdAswwq9Rk6QpqZ4XlDFfBmMauNPDg6U3TDxWS5C80weQ7PJeeh7UOU Lu1oPj5ye8e+M2OXe/kj0w7kaxa2y2G2cfyyDasPPphAArFaehx2zGL+ZVwvgfWSDYPpIbfErdxb CbpIrOZveX45er5KH+WSjXYDU+Su0vxR5ZjYuEoCByba6VYMWct9kFhBhgQ7dvBzBiRXJCSSydQu Lm4T8ZPpZE4rP79Pd46OYwoTBu39OxEvT4qpkPQVSHXD7f1ksfFRQLjK5FNkzcfsY/MCY7Avx5ge gihq+NKd8SFL6iTmy2FN18KkNPPg+9p2UnSmzE3760nF41vhKskcTscqHzt4BEpW0unZg+3xYeA2 PlI6oXZE3lET4zBZbhZZVlMAX/NZ4xFXbKDgI1ZonKksDNtaA6EBp3LBelET8UwJduoJROvlOtXL qZuMVsDgIvui/4kZna3UWWX7Ffc0jSkfQWK0n2DKSLo3S7W7RLfLQ7J/tv8zy+vSH1zMvvU10JBa 64FmXPlBsVVNxCs3Y+Xp3AUcqyfMcIUK+t0+QUQNt+OtyvsNCNtaz1yaUrmYTGdyXy9YUT7seDHF xN3D0Yib7Hr8h1eCJ3Swd4cp9BnPTkY6nGXUn+CDC0/wZ3iND04wwb7pCV4+nHn2f7ZHsC+XLyYX J70RtroJhqkzqxphq5tgcF5WNsJWN8HURJCVjLDVTTDtoodVjLDVTTDislnRCFvdBMOSjFWNsNVN MCUpfzUjbHUTzOVdNMK0mljiifZXR6TqoZ87zDVZs0Kv2AbG4rezTMszDOIZaiTuKue1XFYqtZRy 39zsURv3PEw+5KoU3UrcbS5ZnmyVcZObWPNxrBTKGzKq2qXXWXrdrVVaHGoXmL71Vpm8ZANjfnfG wpZngiUcM8Eau0ZbbHnWG36is7Q0E+yOIhNMS2jzTHzj5ZlgzPlzMKxFkpalCk7rxR/TSkHuO2e9 2a50a+v45HTpSm/nPnW5NOuNyR5eZx1W2tqKHNiuVNt9ZRmpg0untMiz3TNjcdjJaSATDouPxGhQ 5JlS/aA+uCfSjhTkaPJOed7bAuMk86Vkus1y2fb53fgTO59e92Wwqy4i4bieJ2d61+VV3gbl9gvs pdhuLlnqjWcxpQZ7+tpmQOa8jlDNO8/6b8/HimoL6ucNBu5bWAHYIlFivZgJU+7ec8kn1gPyI/WK 7lq9sH2+NsY+2sy1S7TRZhJrNiVOhUNrRZtfLpcHwNHe/2XGCgVIJPBgCMlerRnsXxLqrwZBVm48 L6+2dXpuymExpM44pUYZP1JtMPvSy/PyDGlAq+TldW9WT3UgsnJZvgdGnH6dFApr2VwWFl6BPbYC yeWlShb8ZQ6P8ZpCI1Cx4mTt/MVFkDBM+/vEorvBcna0/OwvMKQ12ZHp7L+8U1C/He2/2uaqkQJp Mu062WpW59wqVw3k/m+z1Shy1VAik1yamC/4RzKyydGb7f5qRFW3T9SiSP/dlECZJ6kW8fasS1R2 qU/vZkq1Wsvq+dPvS9M1HdOybaFtLMv/ah6YBjWnmD/ZDfvxG8wCT16WXLrmcU2Y8pXNa+ktT5dH dvxjMWwSTbysDReoPitrsR8W7Zd31SF06x0ky4+eSYp7v/wislmpNrlKH7wSp/l83cmLfrOBegH6 8rsNfn2zAWDM+W6DX99soAbpl99t8OubDVxeirsNAr+92YAU4TvdbfDrmw3UhLbldxv8+mYDl5fi boNf32wANOZ8t8GvbzZweSnuNvj1zQbouXK82yDw25sNMC7meLfBr282wFJMx7sNAr+92QB23/lu g1/fbABrcbrbAAxgh/sFHC81QHt/tQsVVptUuc9gVh6/eKPBBu8zUEvKrW402OB9Bvq1OAs3GgQ2 d58BXryl3mhgIVoNlZsF081B0jDIjVPfmb3PmTC6RWob5fZ9/g7AkL4HWVHdJnC5lExV9Au9zF8K EM+cN47u9J7Yj/jopGQ5+L1DHEuGywO2qsJl9rHpbRNXMuxVXxV0IPck5YqfWUq47+ygs1XcnaVN vM2c5kRg9vQwgybU78d6W1LknzvJSJNrq36B0vM2iWjgqVRiGiUmt783muphDxQE7yAIvv2pXmC3 qgyWPxmWofMgljn/+jnjMqGngDGW0mxfZAPj7G7685kPJpnjaZQQl8ur31iAQraRhR0ZAPqDUzWO fFS8IUEYY1TiOBuaRSXUT3ZwwZEHyed7vp93ti/aB8qUKvGr3e/qLBSSnt3Nu6uFQuDgoslBrihY JIHPJ4Z9ufxMRfziyJgRQfJFMOuWI/EJvK/sKdPKPuwBEvQ06fte7r0w4MFw2/pMdfKJseoO1Or9 UUDf4+5Xoe00DIpKqJ3zfUivWP5fx5i4d7hvOGiRA7meaX1dHDKRev4ED1Ioze0cvWfC0/EDSJ/K VHvABJOV7G5HzWzeO+NzvnxSVyH2E7HsAXDQVP1E0S0vSbRBi2Tc1xOVG6mMmaEldX+1AIia4Y4R R/2GgMF/H7viQEbnLPuW7TeNuWQurxdayq3JdIgdIm+pVrvTL9T+aY1crFv5j4H/WDfnjspuLhLB fxg3D/8v1F2+xqA7GI397kLf5X07SI4mmU5j0hn0a6N/3DFsergs3J5n3DH3rGvc7QNImDfoDE/8 mLz2BtC9uRh3Ev7/8LdrfwpzZ+D3axcTZjg+4mbCLCcL8E+EkSWY+tvFqIDBC//AHxfwyxc0/e0W 3JfupxfG3cSxblwCK4R5GcAWInyYkeDtntIWjUKTFGZFRnRjQ1SGhQnRaDgiwUwCy4Yl8prEhwWZ 4dxpl8AIAI0IDyUAxM3LXDjKiCym74UlkHxuXpLDgihIbkFkw5gCBC/xUT4s8xzMIQphjmOjbj4i hAWOg8lEeCREeTfPywCaQF7jZFguvMaL4QjHRsjgcoQX3TwnhMWIDFBH5TDLsvAaQC1HRAXGKBPF 11gmLIk8QBAVwxLDYCc2zETgF5wtKokiaYmwLC6fA0AkjrzHwioFVmljYd2kJRpRWxgYkrREohHS wsusSN7jw1wEloC4EWVWgLXwAGaUcwOCw7LMwS+48IgIA0RkpQXekyPhKC/xSi+JgUHZCKBHgl8Y QIYgSWRT+EhUIDsHC5ZwC8jOMazSxghKJwkXjNsr46YubHja9QETQn+YXMGxBLvWI22wgIjSJsJa sUXgcBBsEQSlJSLwSgP8z91wKZ0krRMfdSsDCbOBRPfidA0AggGiBsTBS6zyROQEAgduiCiSpoiE hAQtUVmQlRYetxGIjYmyCiCw3wIBZLEXjiSpI0UlZaS56RCO/Vvrw0pOoXb4wiyMzA== IPBw1sNSVMLjx8Ay4fBxoFlGOaQlwDEflWRcBeCdY4AKeUEGJCBa4HiJER7pmwHqwpPCSHBSgKp5 IBegdDwgAg/HgQFUzdoKpC0aZZR+oN5ESFtEwSTPiGExipvEc2FJ4pAykT/g8YWJGFw/0iXP424J XAQQF4XXWJhbJCQjKQTCs3Bco4h3eJ8nYEELJ/HaYQfCBrA4EagPVyHKYZ6JwuBwklgBtrvqQtqO EMKOIow8TAa/8BKLrUDRPJwVNxx2RAgH/Tl8EoFfkUphRs7NCZEwnGGBkIyMZMVxeKwFmCfKAb9D YIBvhCWYi8DAsTATxwHIwK2gJRoWETwOliUzEraIsE+AKGA2wEMAoQilIMEpbbhYOHiiRHYJUCVE ZDcL7AQISybwwiRzLSpXSLv0Njie5GQADAycDQ4OmKmN4QSln8wqsDLALqMRmBMQIUUA8xwTBUaJ x59H/gHUzOGGMQJH4OJkgKLhQvgJqQMWYbGMRFCj8KIIo5x2DqkCuQ3wpGiEENQicRacaL6QUoQf iEIi+kKhtYThZNBr1CZUwlDrSiUMiSB0t1eQeVGNBQq6zIuqMk/WZF5ElXkozRSZx2kyT9RlXkST eTyReYwm83hN5kU1mcfrMo/VZJ64IPMiZpnHW8g8XpN5vCrzJE6Tebwm80RN5gGlqTJPVmUesBmT zIOWBZkHbSaZhy3zMg9bFmQeYy/zhAWZJ1rIPEGTeZIq81hGk3lRTeYJusyLajJPUGVeVJN5gibz zBuuyDxWE0K8LvNYTebxmsxjNZnHazKPVWUer8s8VpN5vCbzWE3m8ZrMM083k3mSrAkhXpN50KTK PF6VedCiSjNek2aMJvP4mcxb7EVGktSRiMwzT4dwIHELMuKMCYtAKeRI8ApDR/TLEYmwYCaCHB4o CTghS/YxCoyHsHxRIrsv4mmRCOETKQBDANkCBxeEqCInkZNGeZacLAGJFV8DkmR5RCD8AhySMEMg OlwdSC+ZQTICBHKIUiAaEJ4CvofgImkRlVKAo4AaUwQXIIiEJHG/kGgiynuyQtx4bkVCLNBL5nBX NNkrgFgBquHIsiMRWSRwskyUSGNAU1RAARVl8OiwbgVxiE0CCse7F1CZduKvU3K2EYG8DP/KcHh6 5NzKHApWra1gbOPIlhQMby62zN77mDXCsQ3LUZCehglmbQVjG6yPFwTDeJZNszfxPAE9inxkBgqS kKjqBDPoDE36svQ3rdq0Vw1TzGAxzGGAz9CmL01/16pt9u4HbgfsuETYAHBYVuIJa4jgaRH1poJC fUwkMtfGAwELeAIt20D3kGUydQQYRASp2dgGS5WRunhU6YncRtUZGR7IA4kTUFSwirAXBGQ/ArIR hANoH4hRAJYbxbMCSiacF2xRtSzQhsKiGNUb4DXUcfA8651gX4Fjw2t8FMSOzJOWqERAEhXJogii qBTR2mSi2oFKysC5I2/KyIyUNo5lUO+UUF7gaHjM4QVBANYuskaw1AZlNaAyCoZOEdT0WMJBQNuV CVok5ABkwShj8DUQpiIyOgHPLbK+CAhTCTkPoJOXREXOwmAGpKM0jhJJqTaR/cLtZ/Dko/rECgo3 4ySJJfsQAWUayBKMYxaPu9aCImzWBlwQeQiOBaQYlWW9DWQTTITyiVdsDpwO6JHVQUgrVpQEG2Ak D2xTCVCWOA3QOTolupxiovCgFER5lKPA2qISCKqe0oaESJoiZAxg5qh5ALeXJNRCo7AIGeUbil8B dWHoIQqMYWbEGlgZojxP5lFgqjzqOmAnSBLuN/RiCC9EWxwsFTJ6RJYUoSICTnAs2GdgOpLephyt KIeUgnZTBAWKonQocImipFDB3IlMW59INLhA8qmWTZTQHEgunqwZ9CeOaNDA9QRiXcvAEQhUAop5 BVeirFC0iDJc5MnuE9JWDrLEsaoNilZVgfAK2DhJkb6oguC7qABGFH4eYSKyijGOVfuBbCNNomrb oZohs4Sjo56IG4jTMqgN4NaDwBNV8ECdB4YqabIJNxctzDuVBiReaSPDkhY8FKQFjaYFOklrigmA LEWJwQ1oifJEakTQRANyB8qAHZIi2sZzgtrEaaudf1W1Mm5dstvndz/cu5ZJRK0Ph4pVhKiAcGii HApGMKlQj5VUHQtW0HVxUcQpSm+wfjng5Ni28G4XQLCfkxMRUlRv0XCLAP5gLmAOIOUVNUqG0wHD ossCSJNsBuEqXYtXHaYCWgazQVaEG2jvOFUE7UtBUa4icNpgWCBB0CZEhf3wUVzB4qvLp0IHGyIB 2WOEiaJURnKKsGhBC7hvcIi7hAswHE6vyZfu4qsOM0mCIkN5kEwysapwBKJO88hIQVTgqBJaNsjE gXEC5ZAm05sOExGjAfmliLiAXcc1RZQTh2IRrG6ewI/ePpRT0I8YUV2Ldx3mQncZw0pEFBDeDHNx ILPwBHBwGkEq4LCg0ooiylt4xrEcWejCq05TgeYqEi0BmJhEDhs6TDhUldHW59RhkVsSLhuBbZTJ qsyvLp9J0WKRXDkZLVFclMAAGxNR7YU5QQ1EaJEfS0TX4HhFu+5avOswF4NMl0eGDxKDEYkvDHkC 4V3o5kEGDOPCwY2KaIKybDjKsjJpM7+7fC5V8KG4n3Nzwepwq2zcXBxrdnNxrIWbS1LdXGC8L7q5 ZDRaoIlRLCvQQBn0I6C1CFsDz4jbDu0oBjUAaGPRVIA2dF2xqGihBSSJskpVHDrIOFSyZYJpURkL IOTRT4WePEmUOGKBy+iDRGUClKYosbeiRNxBi4xuCvQIRlVvInE7RfQmlFUo/1nF18QSrzlxcxG5 xqMfh7jQ0JeG+pQiHBUnEqpmcIyEKJxiOHthiZhbyAtZ0c0BouDoKwoFx0RY8hpOi2tDJicR4cYR 7xu6xMhxBV7LEZNZVjGM/jD8BRBEOBF6z2CkCApgVlaYUxQ9hRFeUxRgEjTUOaI/otNMa2kQlspw 6GDRezEKmnliVgLj5UBTg8MkkwWjcgrT8cAtRBRnuMXoSOOQIEgngB+1EHS+SRySmIiCNYLmKScg USP5yKjqwUpA1spIh3iMiJwiXEIhSPTTRKNq2EB1jQqKaxTQBBhTXaOi5hrlFlyj7IJrFOYBjosi JIKyBNaLvh5CKKCHMKiHKO5GpBiM4PACKuEcg5qbdkRBhSDvCSIwaWQGQjQCK4ZHgog8F6hRBnMD 34OHircJoBPRaObQlGAjCmcGUgYwQUkDBRNb0KJnRLKfwLii2AtMBOLcIr1ERlGcJVDHoQU1LZkl DJUokQ0iNVEnBgg4Hl7n0HkUVZkzUfU5UMBFDq0HHmMVMiHfqKS4YdHyAWQAMmFfRRZ1woga2MGR 0Y0gYDhJIjhBB5PMysQw4XmwylAYK6cPNlpGjxi2sCKgXiAqJfH3gdmGDjTSiZFYluxcFIQPaYmi 3sfxsuo0gxYRthIxGVUIDJvIatHhSxyR8DqPh59DhiKyioEDFEe8wgxhqVGVj+PSgLMD61HCeBLL oH8ZGST6LOAXYLKc+l6EHAwZNw5sKw4dh1FB8dezHJIOMk+Dnz1NfNBmP3tkwc8uWPjZuQU/u6h5 1XnNzy7qPvWZn33WFtV96hHNzz7Xtuhn51H9jxBWSyw2JHJRwBYOYzLYMvOzEwPY7GfnzH52IAST n52Z+dmB04DOAfwAqJwHBgK0gfChps6rMoSLomcN0QAnV0RhAu/JnGKdzNoKxjYeScDUJoaBAGA0 9DAyRKRhZAnIEpQTVbrA+WAjxE7mkBGAugRtOABuGViRsEkCacHzzEWRVyBeAFCGJxYBgioJguIj YDmF4cObPEGLwn70yAKrRBbSxrBX1Bz24qSFsBenh71ELezF6WEv0SLsFV0Ie0UWwl68Oeyl2DeE wnlZIFSIZlhPDdDwircRaE5ws6CskOOD+8FEyYFCZiMpwWMiQ4AwgbEz6GuYtRWgDf2caCkAaxcx ukDeRCUHcSZE8HDAoMSYAP01wiiEg5FscoCA3eHZQk4gS0TWgcxB1zOHngMGhS0GDnji58eRMPSA yFdpGTkB8E0SH4oi3zGv1zHaaRX58RZr7VZlVOt0WyNXe1z7q+Wu9fuDSW3SGsITd3vUGk8Go5Z7 /Dn4G1vgFa2715u9zrn+L1T7Dxc= TM tomcat7-7.0.52/webapps/docs/images/docs.gif0000644000175100017510000000040510457676032020431 0ustar locutuslocutusGIF89a000///111߿/10NNN___ᰰOOO002, diA0(p `i A$&>bX4"M` i˜>Iv_P6.6F@ࢵњ B& Uf}vxr4lxy(-23!;tomcat7-7.0.52/webapps/docs/images/cors-flowchart.png0000644000175100017510000025103312153605676022463 0ustar locutuslocutusPNG  IHDRkH+sRGBgAMA a pHYsodIDATx^w׹?`8_ϧ=1>pF cl5fEcĶQl#0 c.|hcٖl`qU #Ers&cyTdVKVuwuPfUWwW=]gE8]!"`޽MMM 54Ip.x?gwȅBQ\|eѢEcǎv/3a f(e$B-B-x32=yd4z۶m7nܸ=( `Yݥ@HB򤩩iԩx󐞝"3N !B!ʍު_ݷF3 S1Z!B!ʊCΚG S1!Ӻ A] $B!D2k֬N v۶mn3Dp BQ&?vyiO>q@HBrc̙ym&Ep Bxz{{QoƩq`ӦMqF] $B!D⩮>p͂g6w߹m#.n!"lܸ?uW.6l?5 [a[$Bݻ&`ժU4J !D>sspĉiӦ:u턈+Gmmm=k=Z]@kt]BƏok}?Q@`;Vhڀ| eKWW]]]=yd  xi.]c>se!DW_իW_~퇈% K/}>h(z+M$ޒm-ump8Lkӂ7rKZ 3?䞘m٘! HE»~j}A;Ń?ԼM$ӧ6:qn" .>kX")N@~092%? &ܮ`o4S2oFwbۮ`m" } 0iyыa[˜{N/Ztv !޽{g͚O\r퍈w&)"Xpx{fpcKE?|.@Ӳ KÆ"~H OƓ& #eB__ߢE1f]O2.n^xٳgވ1p\FUӏG7'? WaYtۄawbKVLY|`L;e5S> YvLmRx (z{{Qm۶9_ׯ׿^p!!SLM ~衇ۛ7o1#&: 4YedT 8 [ǯ+:[Mcuh 3p2ٳVxȴ!ݙr O=K1_ee; tA"&+Z>LEEE[[kdصk˗>1po5B`~<wןi?ޓIg6EpI&a7of-gs#x".n<{O>)p>|E1}tpi.3noHMBEEh8p⦦&tlp`O[Ĺ ~&{D] $"a:th̙g.Z&~Lƺ?=zkuV&t.*?cn߾I!޽{~ig#fgPmqXضm­)'! ti&@Yvuul\t}-[9BtbǏojjrx߯?-!IwN{0Ezxӧ[`V\i]\pkL3gN0S?֕_ׇz̙3-(.SNmoow[p#D] $"I|xڴi\f;8B2eʔ'N8. l&їp wpQYY~k!Ҽpٳgд?,@YVan:?LEEMF`?x@!Dٸqŋ.(9 >}Zb@HEbؽ{ܹs4ö&)1-[f0iҤÇ;wB\) lt3!~g={kdn̙3nHΛ7ϹpAxg8'pwn?Dp H gg}?bO!Gmm~t8|؅ٶnoǜ{oγ% Rǂ)Syrnk.mnqSLA_n%Yfaޜ܃2|g5j믿w)akd۳g[+ۧM?R0!z,$wԬ] iyWUUutt `޽O? Ǐwjɓ'-8`q6;v JTLxa^J ;K79w,Pp4iҵAAO8aK'իW5ʂ رc4a&6]FO!b˗9=S#L2|+ImnO3gox'xOSNg2eɓ'My1&X@@755xNnRrH޸qy>}B 2~3~:t0aVduc$)-$N___MMM[[gr…JL1(7 ${&̓իYn%n"f (~#<裿: `Y~j8s%}'I ".w#G̘1C'lػwSO=u5Xڵk? 1m42;@/YfKq'#3 !bN___oo={~'ӧ$ĉ@"8{ nJ wYQYY|Sܼꫯ^{Ueq8; ^:Ԗ[$,X@C}qĚ$MB0pv)W!J7nݧO޿ ,,`H)D ".kjkkw'Gyľ}#wyǙo7oO3gn !D)p-NbΝ3F .\~.I @]>4{e˖]r&ުoܷ𴵵M6.K/^t%pqFKeѢE[lq)p'={VurCԴ|rEgٸq 7O'!(An".S|Cy/p1no !;H˔Kw5g^buHVTTXɐ>o+2`…$e7͞늜zSUI,X<|իWmwww @x$eJMM_|3j0c}lkk#C@ @HX)8|f0cX^wĠ=S|⼱v{7 !;H˔Svtt8芊 d9̧}M%Ӆ&ŒuQv28zxL^4iÇϞ=뎗 lxΜ9k֬7-[xbmirBGx$eJUUաCL.#nciތUtg#赭by`\ ?};^" 8nկb'qԩzꭷr۪B&?JnQp)-0>y$md/_yf CKL@_U`i3`<Ӄpع%֭[?c'#棏>zGmf\ !JީSZ1½w^$UИ<$eJ]]ݺu`F lAww7bM+骩!:c?md=z3sK ??:tq`ӧO7oÇI׍!DbZjsn $e;oo׊͂׈ fBU9a /l߾tv`}ڵTzzzWB$,'OmD".S{1")5bË/hO;ww˃>_bÆ /֬Y3gΜۼyul˗ Bs9hjjr"YH˗S;!&Nh5 .\pKJ__[;~?#vQy'MON>23fXxEٳ~KRTۨrY8$˪Ux㍫nL#ƍ|z9}XOl۶-\49sLwwKTC"H477s>umD$eM}};#ӦM3 䣈;L"?pawߩbDQM<õEp5Ms9,{y_C$ B9]]]d#.wZ[[]/˖-3C;@"oHږ.+[ѬwY|'ۆno 뫫[hѥKn߾} ,F!Xϙ3g߾}?P:;;9=Cׯ7܁G-(+2dB%IB-R~ƍM裏bI2oN[?ĉW^D;@uۅG-(p8yK[ ={`7b>=qi=ǰe˖}βz{{$EgEB\d…/^t=_+ԑphcǶm۶k.\5|l`>wqڜݣG-H ԩS,leM{HH&2LpasMEG￿?n!DRaI&T^RHE,{!z҅k̙a֭*/)9$"Ƚ=B҂m;;'N`+*/)!$"Ƚ=B$H.\8\vM%%[W']]F n ^et!D|r}}kK,qQXɑ#Gnn ^eBGGǩS,?:B5{g[0B|W*/3n $eBooرc{9􆆆کS BAΝ;fSR/&Mo-=ioٲeKb[ wPWWӝªU\B{InMӄ۶fss3?.k[F  (D0LHE,@\$<ۄv)!/_޾}+q̄,XܹsgK+W$&HE,p<鵵-qTH28 @]nMx @Ͱv`wY +C#@xѣβ靈\܍B"+7ˊNk sܹ5nX@el 7MmFMt`HE,p'H2_%Bb҂}:td47La˖-q[[5=htXH`Jn:T^'lG@-b;d*#ɄKn iyhp7440ݜsԨQ c6> +V`uo~@ .]z饗t#HE,p'+#ioo5N<!DayIL% [m0`>&iux?z kDK[ w°;F\3.^}:L'm[&2LFR^"J 7&Eȑ#*#-nQ|0cF"a=Hm &`0o4k`Y(%QHE%k׮u[pX͘]+V @a{6fļIIQ$HE!)byHJ (}A%âE.]tmL ?>GSihnxF&72m]a3&L0.ՃR 4%2BxɽKz% (0N,HJ (]]]|'0۶m`nE L'P^Y˻%uǹ}~U"A% F-//9}ۻl2nQѣβi3wE$O̞=r3*/I*nQ,߿ꫯTFRrHEAI)#&ȉ$YkgZ xQyI"p"U,%*#)Q$ܢpd*#ɄK駟o~4S͛o//XH u/D%NQI"H ='OTyITJĦM쎑n% d߾}Κs*#)i$"X%… /^h=,_+#by*@7Xvȿ.c/RQoo;XppNyɚ5kLs࣏>RI#ŗ=K_,>DNW-\H0j(ˌZԼ47oFѣGu(HEȹH[H2w\֭[sd(253>ìiRׯ6e$v 1Jn7r(/QIpHX}t\vM%Qaw\ϟIhN,_3?i&Of,e{6.LB/]4 $󄅛1l5rŋ)e$c<$"K8 H[DOWW̙3}QuVDB%v+:7y6&LP0nl[Ӧ%& n[f/~ ?NsҥKuS aHEĴ`ΎÉ'؊KFKaߊ|ubUg{f|0x Z*#)$"΄KeNȺ)<$"2TF D// xǎ>4KygϞe/Aٿ?mIƐ!0@eyM<_|Qw 9$HE4仌$*/ _^rAgف^79]jDkӦM6&q,YLY v1*7$ܢ$%*#I6nVFr$*%UK7Q"Wc@pHߢp՗_~yK`$%Be$匄[ok)MDRjiii2e /҂}gHz!_FⴷlٲE%򒶶6>̔"*#)s8WHRWkN>IpZjjEL=Ңsڵ|]]]uuɓ vgP2L$*x[yISSs?VI#^}) ~UӃ"{u\|5%K("dΝ.~\rE%QKΞ=d6 *# }^'M2e۶mN[[۬Y0{ޞ={>Dlذm\QyIT,Ez&< 7YSSvZ'^UUU\CΝ;fS/|4iRee%"bbe$_}Im9~K"v)DBē/8/4V]]ycQp%5Mnlۚhw2L$B?s 6>THA"JWoj%/;so6Iqڵ),&cƌioo7&&dIdB%QK8`[t92[Fl;,ߢD^jjjڜ{+.\݂R@ptVU>|g6B<dcǎ$|yڵkLHEifw=2V:NS.^*D/uuu>~6q a/aÆ 4ӧ3`Mضmel Kk`sq` 7xᶒ|mɐVFkښE}}&LpP_~ѢE| aVt64zh5PyITDe$bp$ܢzܹvAooorP4M9'bk޽;j( R` #]#!]̛1oeͰMmfVyW Rf3+2Հٌ{zPn߾bޓOüo,2t N!<. ?lJ户njN63d07oVyI$nnn~K|W*#)3ӧ֗>5% 7'7?\~6XRKvǎ\>EP`YNfzg `` vc$nMnwIW\itޔ=a'-;C̞$&ɒ؊ey i6D o]y6qmwJHx.8:Iu3aKe9 1fϞ̈́,k1ǹPyITK ?*#'eܸqTWW[nd@ᆰpϝ;wO=K666DR[[[}YM 6C4M#3Q>cq& `I}oMuY3LVglOs= }NyP`i$~]x-[V*ٍYF`G9XyeRj6l0Mbi4}!mnyB=\U^F7xUVRs=yB^./ܜoS-iD̉R-[e"4 ̷Mmigijk$6؊V6d708ES$]J=]~z0u 8q3g'_od E7n-={6y; ZWἍeWTTXmW6mRyI$De$"&ٞ㺅+V]t7 d "D&}}}&Mw7wڅI ؖ`7> "_la[~Nճa5RߊugDObuˤ0sO?4ӭ8JKK gّ.d֭[G`@MôE|:]FACCmCKpͣVykyHDZ!b Up޽{ܹN0C Ȯ)>j1T+3I2\rTL%GKnV`1=Ik$>?T6Mdlyz̙3`a޽SLq"ZIOOЬ #<|T&*LoN@L`Ҝ.ܝL00 Y/H.]K/$|yɩS8#פHİDa w"~VUU)+J@@$]nH 7/7|)L@|P)G/Ip;kd,`][= N?6g <灌o߾3f 7o޴ÅrC$ҒE!20Pس],tp|vx)giA D//e9W>21\?ک0νXCuH"Kw"}衇]PD˭[^p!]QQy@%QK֬Yc}HDnطL0+\w<'Os"AD&555_|3"wݸqM)J%HHλc$Oy*/KxMDǏsjBĘoijjr"YD&SN僚Ƅ 7nݼO={eCyHZZZpSR0eʔzv1:t{TBpUUU.+Gdͫ$ MUSSUw;v;:i&dPC$K.H m.Z(/WHirڵ,8ܴLY)KlTɐ-\^2r{nFZ|V`鎂Y3 .4Wzի-6貵<ӦMc[3e+"/ VgJYX297Mp\[cg-ӑ^Ob#]#'TFR\x='ZY=ƅ)_`؇3g"Df۟9Cѣ?O܉$J}ᇹp:3`x1]D@Xm,3)m&AVlc9r͛OV:a%np~p 0!=q2<ku555/Jill`Z\__?"</tO5knW_}î5/]*aÆl2 $y7,pQpoZqzqFmȹJ jy.#{ X^Ó(V`~f͚e,I6ƍMnSg#o+-sι{TXyMRcNnLiMA5{zM2X?KUF'+++ 8ȓ&M .I׀fwva- -cm=XN`IĚ%m6ƐY˖-#pHLmȹIm71Ke3<ؕ%UK 1cưDz&F?I;y| ah"̃΄%?j(2`Μ9K@֢ tBWWlٺ eFW|ꎑ({mCΝ<"nhmm~vY\o/[ĮnoIyIPIa6͡`"~}^ w°4~|*̩̉Qޭ[Ę1Ý1ݿ3Kb"?. {lIb]1Pn-[@ކKZ2m--V0.}W̝;wƍ&1,6܉!_ uuu˖-TfYf֬Y޶///9{xXxᶸfcc#M|$g3g:& }L/~3&~ٳg?&$m$$I`z6rJ֭[w#vN|qK%9ض!NynzjǎNEbsb2;ww8J*/QI! JJL1H;FN޴;w|wvvZlZ &IɄb `%ÃKGG#<vKf۷r+ɯp_|Euu9sk%pR{衇֯_]?ϟOm<$p' >MN0Dt%wD91B6ܥN~۸rƍM裏bI2|ĉW63MDb%?3gx~ùsTFR*Hs=? Hcܸq8%ʆHlېs4nݳgVysO>C?яs _l٧~jngpJ-7%0-:GQI ;E/]4~9s/Q}Η@]H N:mOR Ç]I_mK֮]뜷xp' ps^rK rȹK ߣGfE4x\E//QI"NK. jH4ymC]ASn޼Z<W_Dp'UV.se…?ɓ.5r⚚"nnVTT؀H4qDNJ_ҋtjۆ(pd./q.?tp' >rFƂ vA|rג`I aO8xhaV^m$6m={vԨQ"X3*KTUG]ZHE+NCooeTFRHĩS~a'⅛̏Yd [{f-. ݮm`ne~D~_ל0{wDB)mrB-"%*#IQ]]_: {I%/_Vg=wI6m'غlZlcٳ3չsImȹK $1H;v>g}vd즵+K 2]!|{%Iȯ^z l5F>d?3 4o[gE]HE%N!===*#I裏={D30`庺Yf wOت+cMff]6mO6ͺl6`.xN>[Ieƍկ9wp2ՅYn!J˗[gN̟?{w5k~nN#dI7Z`y y,a?fck$&KH9svNY/Fmېs / sG$cǎ~کS$)SuY̛7?rY!&mȹ㌄[KTFݚ7O94>M@ƺ C8=z5bYһm6bp 9wܐp"d{Hm|HO>ĩh3Ƽy|% ۷o!ݻ_z kyԨQȷ/IT3g`kva* ^i4Y;VHEqDe$Z W5k֓O>_y쬫{衇֯_N^mFضe;2 [jK0f30VG]#r1Kq2vK;mbs (&ɓ*#)+&O._YG?Vc իmāȆmp_ٷ%/2%[2 ׵m+F![̞%뚩6 X9wLp"頹yر*#)+PZ wܹsJxCE\l\7np\$lgr &СCxk|연uӧ[΂0Ma l9Mb:2lѢE+W ~GVdɊ8J]t$ܢܾ}KX hiil-IӼm۶'xB% Fr>1]6j{ZS9wޟ mC]D$"pitH(V@rQgwi.F +?Ͷe>fͲ" .n 4H$2LDm#7EImr 뢋DTF m&ȁ۶!.<n .H$+#ioo5N<鷷 ~ymݺuQ|]]]4#a׮]&LpVÇ܅D-bEDټn…͝Gׯ+*/"܉E}}kK,q 6;zh`:]#7ӺFٳgd+YnhXg!.$n (H>sDd~Ŋ,aĉOfϞ=wlb KضaԨQ>6֯_|uaĒ-$*$ ȣtH?l@.` l[lCx3y뵛m 3ƌ} &C 9wqpX N dB%"K˰UR$;w1cļpO4o 3g􆝮ň,0ҺX5]d,@%0Pb ( 8a7/p8LcDW,nqkFKlu?&` $60KVl*[o:x?`pq[nn 8'H+#9|p_ pA9v3l쓡p^RO?tO{IY V7|2Jva3 ,JDh[f&NOL08ջv , :xѣG[h"kZ ׯwkbCrV^bVmO&;3`M:097jI ˫wܹevc)L4;;;&òn6Zc{EJJ 1@mNs#+F-bqH̉xB96c[uVK +[k-/AY9p[5_&X,N)"j`i@j}`fƸ/M,Z l&Kk_ada ȷpnmwpXcI)#1EF `2%N̞=ۖ `{ r^qE_$5رcn.-vp+9:ts_/W6o޼|rvTHE,ձVF6e~C\hn1]]]:L4cM:pŴ{9k~-|r%&܀dzEl)E {Xȶ#D-b}'WweY *úpi`8MmHD-s$,$KC%?!a._Z2~-ϦM)/illtQ[wov_#N)"r,mG[]BKK 9ӆڪ]#'&pӴFO&??]*҅m~'"A=$ӦMmG[] Lߝ2.9C J;***XC&$cm]'Ikr`Z9påK^zD :й8,t8nrv 9VWW߿_!n tu,$HX]N)u f)]&m&ӆG fiF%)E ;.9X<8 ckĨQX`#}H& Ù3lݲHpXc QyIR)EdH۫j;;Ŷ{{{{wȐpXcsQLgժUn'.\Xx9: >ve4SFayfyLY0dZ 7]˗/wsŔ2+Wq3&)[T*#)8HHs˶[ZSmrYQX|yp!<;ifϞ-͝K 9n-8if͚r4SJȰܴiݜyY03dt^vmnRlܹsovL (2---նD\V_^٥22G-"ǜ̙3W{e9?7غ7nD-Òk5kcǎY/ZlakdO?m (}}}uuu-t7nc˗Ql|yI>b2nwntEۖcl@dXY<,o])e@$ܢ8xٶmOv5kt]]Y6Íh >cv|p"`$G5N\܍ņ'%%*#a$"drn]"vzͼYҵqF[҆4sf-*͓m (()e$PyI >B…De$" +sl׷!ȶ〄[Le$PyI%pbst$"ֹSl\ON!Ho 'O$Vpk׺{PȄ[:wm_p(6nwd…/^4ׯ_WT^+^^218nQ̹O>ȶ㌄[_F9WT^7߿; p*###&-ێ9nGr+#ɄKFĝ!pBRt~e1G-/#m}t\vM%q×bۻl2lpSDo˹Ί ێ'n=]]]3g|&G֭[U^+ P^21,$ܢŹ_(ێ1n1---v{{p "EΝb/^t!⇄[DFH2KN:u) zzzTF"r@-E;Ŷ9a=D-!e$PyI%3iΙÇD䆄[s; lp2#G [G%q×YƮ 9GD䌄[:lpH!ի/KbE%*##G-Nӣl)pwuu4L2bi>׳͇r,e$N{͖-[T^+xR[^2 ]$Dܹ_x鑌ے=nlժUS-Zd}ۥFggڵkɓ'޽=βe$PyI-K.HDTHELйw}םeۥF!gتikbAjkk{\T._\__%K\VF`s}?\a%/H8KDD[ćH;Ŷuz,9.ܘߔ)Smv+鴵͚5 .ٳMlA$XɆ čgw[*#"bΝbW^u!wԬ] iyWUUs3 7~&MTYY2H8qƜǏ$VDe$"HEOrs羬m'| 7Ɖw~嗦ejp/ ipclnnF dB%1ė좻Ń}DUq) ^fvpH8<˱cT^+n߾ˈHDHElƹͶ?C;Clԉ^ӧOwp=zݻ_p 6L xW-Lb7x2~L?rȑ3f 7xᶒ|mɐVFkZD$466rUِ%vӧUF""G-mqm's5H 7_m_Cm3XN`I1x۶mh!3PDW^߻T۷[ގX!98VF~zİyf ^`YW]6' %C.s29wm_~ݭ#JvǎV8=&L`y!@y]2F [0g% IZ4- &c\#O h%lٺ eFӧyrmwJddB%<|71M@$)zu} 7Z8Q wkk>Ls8xcF[n%qV}ǘIyoVXz ~Z GI{oٲehH2=q3g&7'X~=or`ӦM*/noL@@"6RJ$^]T0>yl;D&}}}&M(r׮]حe` ` .VkUL-&=,-˶nK`Z اʙ3g~駙nr3.**---'jLFlG߇bIZSJ$^]ǎ+N6 ݻΝs "ӧO1Ϥٳblaƞ@d$ LU&V\Wٺu+cn[oUWWwww)Sv`4Գe˖u! bΝ<1Q ,cA̜n: qҥ^zI%Qf4Yr+oˡ)%C.QZu-N( U|M3֖`]Oy2e+;2$%ފ6Қ}f̘͛vN:s$ՒEa2T5G^nO#4I*63sWXCѯՁXl {yUIG%QB@^VRbMBD^]k5\\J$Ȅ{ҥ]D HC=|\t A;EE!HVnv„ aE͌SԢ$Bv$/@/#ɐ70}`Ȋ@"S]4*/)0]$D%J bOd]SS_8si^Bߍ78LQ*)# "ܨ&1#Y%knȰ:fӻe[acs$d RN/SYÊ}ͧB‹EBD^]+6D&SNp"~7n24) $ܶ"xFI2~S&2@[Fn?{hk śoSOW]$D%J bOd]UUUn_p1,|֚~ 1vXw KWWWuuzoFX!G)gv:P⡅`mX$3gŊ!ٴiӌ3vu[n% 5zuBp"@ {{Ikߡ׷xJV(j0y+ GdRyp:j olXF" =USX=ɼy;fOV2Di]d8w(Y":D f I?ɓ.bp\arƶ.ߌG>#pv6n8y~~ݻw[ܼynp ]H)-_V,95 <adxX: clCl6du 淌 rxf̘[o|ܑy #DT%JWleeec,)JȄwk#c;v @2K8qb3,&_+իM7md[9{QlEDEkkYpWq=nܸET1}6k an/#1Փ)zu"˕h̘1I&!DiKȄs+^X#PSSFڀ.u]CYRuXǁiVa{A~$v봧;655Fpŋϟ: {…XŋSH8~TDHDi1+;w)u{{;zMg&\pԩSy8 /滸2u ~wp{K& iӦp߃Mba'>|w^V$yHDЫKb*w}v?,ۥE½jժ7x?3gΠǏ'}1`| l0]0.L$}"^ۢlO>r`usȷ;X0%1Ae$EGJ$^] ܹspdcc/81'J}ᇱg6Q5k[s}YM`ӦMæi-a_|E)zubHR[p777_|y햴"D)P__;.䵶Z|Dn7n%.kBW0 '=ـՉYko29H`ܹs0_^rAgI]e$EԩS!Ĉp"+6\4a,YB@3pMnf3!Į.\^\PIq1vؚUVqihhSzUUI/B (-M< 7g?,._~-[fbWB$De$񡮮KK " xQHR@pY__דּ\Of߽mnт//ikkse饆HbEGGG`}}}[(u"!ݻ[[[-bIDȋpüynΝ;RKÖHs=#_E/+ Wn555bYM%| 7-[Rf͚Yfyێwo _^rY'VIqium!"W7*++ƕM裏bI2o>666>'N\z˗/ǟD?s o|8wHJɓ'뻷E@\\$DQ]P.{wU>=JG9M/[O?530r _^rݢs |"}gT."Į(p7n@̄;m۶GHWWZ Ç]gΜ~{e//Yvs2Ϯٸq#K9nQBĮ(p=z(PUEիyx aQfVL'xu nQBĮ(pwݼy5^mjg͹ra\Tf͚~k80^-F[ĖlnCps'woooتSζbK֬Yy|G*#)9rmC-F[ēӏ+]UU'C(qGmcE%*#)QFbۆ[]D ޶ .s' (9Dmrn31\6W_}f%[(Qٶ!K#91rd]9w#K~_ЁZݽtR"ڶ!9K#?1rs:nQ%c2R_T9.mNrF-À%*#)]gۆ[ ]D?8ʹK (&ɓ*#)]mۆ[d.Dk';vmA-;Ve$%Jalېs,%@|ضqrC-۷yk(mUUU{ņq'msgn{pXuڵӧO(m%ܼP ωWQ, sb).-$"*9rȑŀ햐spRDQ(m9wi!@WiQ\6JȹM=S(_\njC`K'M7E>R]][o91_ oK \# =,,^5BLO8/pL (Ck۞_W~'?$"d|UVVΝ;ה& g:8\铊]T֯_? o&M"y.*_}hѢn֭&L@=H3I]]] &J  4YZob]'' Tl4X-}sKym'Nt[~di#fpGduHuٴ7XgnQV؉1>%v_RO$ܢ8ړ'O7n\mmmCCKjʔ)cǎu&,܍{,dȻoxnܹsh1A!&@W\HƐ!=z4y؛716& cL&a~؊m7x:7/owj(>,C7_J^.<ϫlk#Y*M٬ l0+ (rϻ(?ȹ㉄[&tVZF4޾};'>\%ܑmCXF{SgU,IͶ AwV8*oI}}=5rWҡxgL}k>henx$0Mhx</7azC#pr۶}u) r"$''OL kMn1m"Rlp֭[8i h1r$1{67l f6#Y!FCT t(.`Ae7ޡ!eHKꫯ .03$aVֲ{۬H ^sU[ }|vA _Gͅb%ŠH94])_H)pJEImtvӚi1mDś+u GmHԜۓm۶'xB%l3ϰعsOؒ#aak ,wXtnx [n%nhh? aL'ٳg#VmLf[$DڶGɹ [+ 9z4wE>m[cnYLn6`˖-<6X`3?l#,6$Mb mQFe#P$<+WFkqbD˒'6Ȑ"0&C YfNf`N,N_~pd`6pnъ Kr$K pmX"&ʾX&,19-+**3[xuaf X%l~![yn(sgnS^KCvk@ƜY2k7Sfclցly{Cރp`'eoOEHETF ڶawRMp!lޛ-Òxm%Ԭ$`h+ ka~,)s"f6 ֕`1ưh_h$ l N6޳'@lMT$ܢIm^>IFͰm+ 9e9w!pae$ɓ'U^rm֭#0kMzl tMҌnftvv\laLb omj]s:uEip:r[CaǓd |H#r@l lc&?bD"%Mm{zy, ,ƌ=]>?pۧܔT`Mۨ-S " cr?9wp[ 6rRN:uݮ"p{nǎáIO/>:%FҎ!b5^/~,Y6mn6!A-z}wHmT5E oӧF&FBLX AnzmfV! iM`{ k3ev1*`tp_@ sݢv+*/mp5_M`r~ o a ȁոq8ԤPnzô&'iI l@8c>b4& o3!EaϞ=wlb 'Ŷ!]`bYׯ7^pI0`>=p#t{~rJi AIM6ټy![H23BN$:74<ҥK4ZXJEAΝ;fNq4pO4rdm9k5o[/Az󄅛i26GI`m鳥l8 'Xhٱcͻ5nxZɅ k׮$gdۙʹRr; m)H%ܢ Kpk&ض5q1mH/hy;oZMZ>%cIټ~zf`2`<غXnoFmP c }q;3r";̙,_82/y#r&Om&H%ܢp3݄|[!v_8 մjЋ tuwefӿ;,oM %cl} [ܲe5g}&n1---6|:Q?믿w ׸FQ ( -nooǰ-nllD}S]0p'|ҥK#`e$GY T^2\s;K'Oz"7%ZӠ9ҏ$ie[7<>/_#fS f0Ѡ 655يl'zȍz$"ȶ*_-g$"w|bedπ΍Ny LnfF Cq8`],YOH̜`{`W1Io%,mm4L=8ر5]c $M0M O{Y?a-O8acLe1߿?}w7\йUaLO@#xNyY澶p 'O2&ۨ 6w nwmn3cϞ=A}i2n->08eXUߨG-Ink3>0hvvvƍmmm4-c`c8Y85rQ@J3}t=L#G-lذ6${΍l+ YTT[2,1c2\|5mbNEyyx+dkWd-2vpŶa@,`2a%Ԓ!CLw_f1дx,P K*6fCn#1$JtFj 8e,iYwgϞMҾ1<"Œ{0-)[$0 e)؄ 9pa`e$Im9~KĜyS8h'q]Ql8]>#8s % Ok׮-Άq!Cn?I5LdVmlÀ.w7-C@ߤff^bJa=A)͓i(5o7e<0#urF@4Qs#!e$PyId59(ѶӑNM6yYfMR##1  ,K .y6 <1$m]/ 0?-<]f#f1>< grs瀄;ٳ=OR)#U^ Y.9k0.-$"ت^d-n`[wvqh w F[Zːx۶78gQwdEH=w1cm]/&MH>7bxn<袼q1dC n!܆a&F[MmjifILƒ 24IXa H-[l4ͼS2 MHLYnۅ?& wA4Mmk677bʕ[`.#3K`cљ\P0+>RmC$]a߾}ӦMs<#1;rž)Kd"N ^fvpYme$555ӧO0aKVX~=DK-ZhʕŒ^x&܌a tpa[6lBS$`X0?hnݺ՚ `{KSO=^Z'Ei Ww!r̙M6?~.:pp5[9wȶE@pn+)ז jF[ 8.0Z@,겑9~shK2Upd?clp*~* Q;7i˗%C\Ks`-zyXlxN•Xcy[WG@Wnm[$OV1bepRWsL,>vXp,qFVYfxd5#A-J/^tj)ҐmG; ۷oE`cc#"頪Op GKK -.<{p["Z6~ l,yB )x-N]Ul*)H Qdm*l^bx A?ljmmno#6kdL! Q y'\y޽,ɒ.^{/12mI>%΀pbpaRQQa?!31r N'$e$͜ ,kfor ®1K6G[./IF2 txӯbe ='sRK^z%>܁ dM`K4g|R+i>lɌamۊ?x; o dZ lW7}NdC]-^woJVXf4Qp)'7oޱc,q7qpRmp Q*|PQQ~ HŠjbZ/dhO8mv#wɑp3f[v_A(sm[ˢϝ`dF]ܾ}5׭[3W싇@t9p92'}]Э28|w@$`f [,넄["-.<nυ /^<'[tieO,\$1BʺִL $S|}X)e$+W"]r 7>=/ Q\jAp Kn>4 v)J͛76%0qU#˃+,}a DB!mc\0_(eܲb!`%^ͪ%|JI .L205H"0]Ҷ ya(pHcywVX\m Hŗtwwj@-@-@w-~ X`_rd]5ב.Kv?ۺ N됆_TI۹Kݶ "!Xu8uKeF>5^_%o>vqp%tMFٳ 7k&mIFִ$OϹe9 "*rsnD%\ }qk׮hAm pysgƍ*#+ܧNfu"$BDo!h Y$clL>}ќ6mZpN52 ێn19 h[3n!eHm?i^z5VM6Qi%ƶv)Dܦ̈́l;&H򒶶6-5TFR`rnHp 9?^{m{/1XӖpر-I"ܬȒVfiZl0\c J7’[ //ijjr[:|*#)<#wnp qnx͚58mVMR3iFӉ-ɒ&[uY҃h d۱B-ŗ={lAUFRDFܲ#"Oս;&aPj.7X"ƌ%3ƍqh6.~nmeu6-I2tQ!àKTFrsnv$H/|15͘M1]$ȃ'f`yݍl;H(ć:l;*$B;ȶ㉄[䂕<)ιsTF7p'|P0F׉p*{YCv,YhQܜ[[$"G|yɁ9rDe$$W׉A\$ Esbܲ8#K֮]Ce$1gp&DȄ ǜbYC AYb~xyc[Tdt w)[wʕ;l;HEXy?~/8HJt&u"H ׭[+Samn y}y;?*#)9R׉zC]x8|/+$a ܲB-"%*#I2pWVVO4ɒ #+:c}֌=… ,o /`ydlzY˖Up؄4.` pWD9lDpK֬Y磏>RII0fh 0ob䛀&Ibr“p(`7yT "VaLBW1b6Vu 2_]cH~'?+YȶK (96SveqdWFWtx O"?F- 㭚2 7Lކ1[^ư-nr[]lpW1{kȶK (9pPIunoٳxIM\xm0,9Fv1pgM﫯j3 q;,S< `* p-O~2rm:nQ8% HJ1c,-+)\5eyEpofr+)1 #+:G- 9]첄c+NnQ,/QIY!#+:G-ܰ+N nQL|yɓ'UFRnoCe{ӧO0l;IHE;Ve$册0 Ȇo?Ownl;aHE}?kHa^-o\{-ZdLq~ԨQ~+~ ID;g)N$n $e[x8}mâXk֭fLlV1cLS6T$ϴ"ۥ!psG^pol;HE,R,Y]$Ja^-<W^kw<~6N 916-d[1& f~Mi< >?g&$#ǜ{޽d#`H9 x%EI##+:c~#/.Ν;}MJϰ t1l`]Y̲b˖-"dpGϲd#`H94f[=i$/ߍᦈ?2¼[xn@vQXu֡沸x6 $jt'clM۲d6 .}}}.Cij9" 9;w)5MlvL}CdyEp̝D[["kM``2 J~LI[`3̏a-˧l|LZr۩'ލ7ԸvRpXpN,FMYN4noN8p ټDp̝ <FLBD x$"dy wcc_p" =vؚUV%q ~в۫w^;,"8b. E-bA/ܸuee /_̒;]D;-xȜx}ݰjNrEdGEwmpX~  vsbzEl.`H вC EUU;ɂ;軹[ĂsH0=\pt455XB1wZ6?w73(Y?.n'M[/n zAHñu(rɝ;wtX!Ə&/zҥo;䩆],|\joooسgpXsM~ۥD=Ux8C_.\f  K5jx5rlmG y fvQqq`_.v?,ۥ[ĂCE&ykkk][DSc<4FIzFn͚.3ܼy3Mb&g,Yd?6lbsya6LLڑvsWި*$"Hʍɓ'뻷Sc<4 g@Ǐz]Fƃdd.MZȶ 3ܹӦiMlFi1Agff[`30؍rphw>3/L 76nnnwsn $1Wz$2QH ,p\yӦM'`rlcl3WĿ!&a3ܟ8qudvʈE#vAɝ "HE,I _`zO4_5"ĆM/_N&Ed#l{ 7`綊-yxpA!K#Ao#@皘5YtwwY=Ux8C['NjSd >{uYFVTT\Lmu[+H`wms,S>'`, 6HE,й&&D8EMׂT;l#,7$MtٚNץ7<[1=I/K4;@3 .N63-QwVR_z& :ɢZPt*<eFYI}a x$"\x"n%kA{p̝ g%[UUܼw^KY]]/xE-b &D8EMׂT;- J P__EpX)ED8EM<kA{p̝ g%# 3vXN$n 8˸HZPt*<+eFY{aO<"DQp,x\ւT;iӦ;v5Ikk]#j J evpXED8E/E!^ p'.\8|kW=Ux8C#e͚57,=%g%a N0n 8ѸHy7to~!5;?NOW=Ux8C#]3gc;vlq`%mFZd=Ono' qs(&NXO>ݵo|7^}9s搧_l۶mԨQ63zhVdk߼Ɋ*[Ӧ͔!) r> {޽{?{4zI? HԩS?5FY|a۟NvpX 9 <NQ3L#<Fm H7cOa 7 ݻw[d$F~pL34ׂT;n=`$m]ﬤLF-b &D8E X/KzYZ&EQg{mNlA/mu 0ups0kfZPt*<s4`H&6!yD}َID-g>kϡ{=tkݠ0a[kQ.&ʕ+?s&q}d,&`MHKٰaC8޺u 1(DzI;/)?$3uTK0 ]Oay佰VWWo۶{ud!՞vWWWuu|jٶmی3[n"HE1fɾDɂU`-(:-\#3cLmUڭ8Lu/nQ0N>m/BR\!ƭΝkJގ^ٳ8tuu͜9w5[nUyI!az'T^R,nSgo`]MJSl]wa^-1~^V[`K0ż%"ٔӝG)`,oo`p B- #[- Hpޡu؃n;tOOK `̞mX׭[GYX[$ wT{ܹ{2LpRF I%E'Oă_u/_ǵN655x?ؼy33F˦m *֤LMM 1gHEpGnN wss3۷[Hn-[$Hpf%!%O:Ɖ⑩$*/)<) m "ܾM$- 4\1k]@/뼋h7ď> H6`%K )Xɑ#G-Hƍ-Z4vq;)Sxp!|+#GT^R0x8EM<. H0t2;-W^}U^gJRZ${ҥ۶mqㆻ):(_~%:|WUU2GG#[*/)  .+$EXe$PyI)1FyϝGG"6Ooo]_Fb3*/) \̮% H6U]*/-$7nDWZ5 D9o=dB%@$e.Xܹsx0a"ʕ+*/!!܇ZtiOO3|ԩSz=1b|I>~dK%C$e`XɆ ގE+jtQ2k֬fWկkU1|YٺuKrq>ի]*y2m46 }[ٷoIۀpd#. VFW_9QFY3B8a$>]WZe8Ϭ]gӑ`ȖK"gpƛ*6t1`> ; hȱqΰE66yC@-;D[FƄ7=z4KKFKC|s=o;._.Q2L\SyI\Ǐի7Kܗ$]Ǐ7-2<;8:@/#ɐOo^6$YXk4D-;ۮ_\ .>}]\#:6oެSFxqέ ˉ'*++ވ,wI&T^- X"dlM̙3tD߶Jw8"A]0'yf#ppd#߶v5&ܨvCCѣ0ftuuY2\|Y%E$]__ڙohkkRvK aG1-N*/! 7BqF׸:x3od 7m3k~@8[$y HZFRDT^R,b'ͯsbuV> wH-[dp13Cƹc&il̤Qml>\G̙3v݈,`]LHEpGKHKB{޽?O^*~۷o]w(nI&T^2B]?e|iɳO XCa*29g֛ lnnl$QZIOOύrҥ^zI%$Fͫw*++KzQ__%K\v>*zI&T^2l{MNJEE-;x;-M:6mRyIp744^ISسgOuu5lg[ VFl F$aWϟw^*6nl$#ơC===+VpaG}cUL?~X*/G{ܹcƌ3hzᮯ4iReeeae$VRyɰDc[$ H(JICCfΝ X[eVqAp*/) qn\s?PiӦ;wnA4M9lnnF >GʕGT^=\8& H63%ⶶ6 z"gcyOpOx)$ByジX_w%p;cL ƌnML>-ȒR)#ɄKG$eBUUq\;DkDŽ .\QF$?{슊 C4I~552kka4m]^Hml'o2kS$$ioV: Xw]]]e\kP.Z52pGytm7Ӆ{XUݹ};R~++ܴ} KD$eB=Q=^ CX[8p3,m6k~en6>ɜ`AX%}ډm0r^uV|z3goypׯ+^ kKğӧ(s $0{X^/2;=;@v2<;&^-Sie@O kyLd$܉ATRNOtp9xϟ^˗Z& K`dpeb?xߵ.[f njj"OOB&P其 Mdu `+~M9? KަéIJr|b(pO:Lh5T *Ms8%0&a ̌X%dҤIhիW' e$a8t17R?e.m-{=],(ee㐪QyI&$܉AT89WUU;iOSZZZ81pٶmݤάѣ3fx뭷Tz)pcH=,@OҼy]1Wlx9+.<w/639X2\#'6.m-  .ִ 6+V2$6mRyI QGƍ|Ю"q';Lli/woi^`>gk#} !G.[ӷov!) Hpv])Ga YlS1gǒVF@ 7SJx~F]#;[T^i\T@#,8.o]}G+o8C}F϶#ga B B r4 ڱ6[`D.AmBBM{>3WRתUyY9Zs=2S=t 9z;gB-r٦2 wKK gڹOjp,t ҒLc#] *:ðٔd.(L]BÈߎDL'@cƟ5:Su,71=z 5 $^EvVt8^oOK*FRJ,܋/^r_)B#@uTOk|eɰYfȑ4eUYM# ~L^щ]1p?SuًT5M/)=("`o^rB᧗\;6YgϞ׿)OA+pGKd>yeٳ~ӿTN#76p˸(ֽ'^o?if|g. 1/% ͛,5ƌOs8p rٰa tYfHB{ǏwS!1bO=TbW,Vur'x]F:tQ{E"%K.O{F 6oTjދ˞UoLl*a0 M#)#eqU|/|7{5СC]*Ƒ d`Dxd w"`[ twwADG I94ȭCCcc#u(%tذaĝڎ2 Ecƌ i$e=uO?ԙNѷadŕ+W~_q={v߾}|`dQY̙3+tVI(1VTe\dғD1Ե:C]K kpg ɓcǎ/Eʅ4^8w7"\pD2 7 wv>;uN-FnH@OM>53ҥKwm]b^ҕl6O_,w>I&Q=,Iv$ I1>ŌX>|K2dHa8W- e!#[^3¢b[znرc,ļ^K1rHyp8_g]*փSLɄ8[LÔ}zM#/0z趶6gѣ\ͱ/9O/I­%ƦD3¢b[z2ccǎ%{[,$ܾ19zʕZd ElVÛJlVp'm۶{WK lIE ^|ŋFݻwЫ?dي,6$6GMMhTNH~W1c3fHAL&('IkpMW&^ck:|=s {zhRr#O/q.\|>FR)DBhFw9?$E1״O/ِGIxZg #d.xDޣGJFǧLCcTЊT⾕ Z"9T%Htwwϙ3ǦTn͛LF"[nmjjrewU^ҙGbmH 3og+}Q} O>I>={Μ93h LzT`u}"jJ)b;I*x;WRk8XpKlI%C?Jpرcܹs|Y3VFMN8F޽% 2P#p۷1f%l/ q+C8Ib'b= ^nݺ+߷i$HTo /Hp#gΜj_o{*bzM#,7ꚚzԿS*FepLKΞ=d9?kFRDHg޽{Fs΍5h$;FK#[wmD1cN{F•4R Fj4dΚs "Un>N0̙3nR2eJkko0^{A>/K5Wl 3N5@K5ƺizM#n8|O<--/[tN{^ ۿ[`ڎF%4R @<ĦĆ 7|\yGx6X{>}zM#8/^v/r z^zEQZֵ ?rf蕖M#Qnxx go[CCC{{7n#3KlIgoe׳|4'|ހxe9F\"5 rQ%zݙyRF%ΩScHbFD^~f7U^___ԄCK ȖŒ3xf#.mt}QŌW / r@XAI12 eWRu6> L;wo[:u_fϞmHbFtVZ'B}N,Z'Lz~zId @eI/GaT>NY&OLIT7n<|0 `41T2I3E MM-:=B>]Ա8;"H w^bHJΝ;<"*c{_u]pGlR g?~q6'p'h1d $Q^y?pT \Wdᦎm];y,/_.1 i0.%6$DZvU[[zjo{y4;#K:ĦĀ۷k3kN[dh0sYJlW%}e&f]̛$E,d w35ԩS6$TpWޜ9s~lٲE 񆆆{jk׮}⧗G^T<]ysB`vMӦM㣔a %̘1cOСCO{ fJUa׮]*JCe>e"AR cd6krT%Ay: ٲm۶C;M`).2*nѣG{>r~?~\ʡ'p{5O/)l8򗿠a'L`KJ'p.+n8)&@RA@ֵ˷~(* 7A®C0 "pگ]z[$ {π Jb% feaxZ7nܨQC\t&'tJK #[¦T@_K8}\6 $pnjdF~a򛛛] tB uuuC Q w[[۬Y0%[ܾ}… \zmmo~ٳgر#|#ٟ}8 Un%ܘ2)1bDPhT10pBuG.; i{nY6 N"i1O)ʮ`2P_+YCN;eJ nK$͙E٘sQPldE;'gi$۱6gɓrpKC3aʔ)C qd~.jv89x`>ǺD9낸C{'(Xn޼Y9ڒO@ibqKϭޠm$Ýz*%'gsQPldE\ɐjQ WmSi$"%\C3o>|G}?|ر., =3@1=vX66} L(e-+8Doe sU766* «@eI1cƐRWpNpJ/28@RK!wbV&cZ[rV;QldE|;+ڭ=6TFW_.8y@t/X T(_ 7HM}rq9@e:! ڂ7o9.)2/U Val睷+HZd&;pd"~f+RldEicnea竂H.^\vmܹB|"w:@rJ [/,I zK_iU a-bV!%9a'V`QֲC{,scРAΝ#ew3[JP*Gŋ]#LH01bĎ;VZUWWL4h;c!ؽ{K/x+VP?^2+2d2 Ъ&GY :80!qńۈ/l&`Q 1Q(4رcj 3PĉO/gs9N9-R ľ(sȝV 492,6lΝ;]"^ p"3;%R<grHL16"A& [ZZHݻ$1>DX4iӦ]pl! wam[`yN/AQjz OĹ ;Ī&GY 핏wm'+G$'*JL(vYF06"A R455 g3'Fr[E?dz l'O&'()0|MK,tY%T6ȝȑ#|q裏Yޑ*492,@e+' RI|dE;]w݅p$.?>PCKK |x</\M/­XK/󞯐!\C~Cʿ_EN:O>K%K+ :@BA+3Yr3A$oV:[#H95I*T $g6Jt`9rdmDn#dx/>vwFhƍea˖-N/ ۠P8+%|[nſY*y!g`X c8Ff:@6H _JOĵ^'y,ܸ595 dɒTP@"~f3|DgN:F16"Si$e'%MpN<!F)B  c䨂r ,EFQd8E­:^U|>{x̎엘%Ys "e^4 _r_~I?4is~pl8O"~f+끲gϞqm۶OdaMH`竌 FŞF:PpCIB8ÇT6 *JX ̲Ց@|gޭ#'_EZj M4JiH\dbz>APp?}+ۉdgשSҥwܹyrQ关F'5pWhoo0aƍ뫁͛78E"1c̟?%phO{vR9*J΁٦}9Ck, D*~mlo:AQֲC{壱'g۴(jTyY/۶mcbdvΚx˄ۈvُ9:iu駗p#HmEjqkŇDڰnV ?^,-D7H&:6K: Ҡ'Md^'q'g;nڪ!ƍ{n'e}a(tӦMvuYsf16"swԪd8b.=bv٭..rЛcPh`BҷL(9+ d-U`a]PnK[ZZEFMMM94?ƍ1Vg)j7  |rM#u57)fԿT;bL/~d&jOq:!;?F's}={D;Ǫ$xWigiٴiرcdz g5;^ńۈvJƀH/AIJT:{!4Ɂ|S{4ΔUk vDuZ :&S%\"Aq{h4 uBw"~f9<卄eSS:{ ٳgmeƩSXk۶mn+/bmD;_% i$cV~'R} :+",Y+N<| l~ =ůuY{HT9\$*};t|z snUM֓F={hҸ3(opn-P:"7޳gO]?eϥKΝ%5,&F$U&Mk9Jn_&)x WWE+*~C (WNr-7sҳr_\EfvV5d=i%wjjj(YEy"_5o`)ƞ!X|SO=7;Ήw}wB/hnn#*NـWef(aUWceM )NUA4l޼yŋg_ŜٳϞ=KW5d=i\Tjr\\#}r[l@'N' Κkgw  |[n͜93ͬت]$5QR&c&@F4ǕF}OJ! :T⷏^S\K5 o-'ygݮr"<*"y#-P]"8o}2ٔK2/%r&WUBGGZ]|'Z1ǏIޙW!ts=ꫯoz g5254ѣ.b. رc]2#Cn;ԄۈvJ۷[ZZNB466 )RB A2E%A[K _lY^X* ɫP}8zoFCGS9o)j 2ݎ#8@'G%\"5l͟SN)6pa8ql\x{7ܾ CŃ4'y"LW*PI*oT @2 V'!TvR4 "`g2%듫Wb?>:pPd$|˖-sGVPU Bcq&%ҢYS?䓊4\L cG@pSwQ M>뼩foJ6An<?~|Ν.|QP0J%vVͥaҿXM\HpZɞ U>'W Y-xq *92Ibϛ7S *EǩϲgÆiOF]2%BI*<k 19˥+c?0iҤBM/AϦ)V͂Ys$RQXzE& Xr\@몈>W:X1EaЄ(n9rdMMԩS/_b:ьLO/q4. ᱄Djgg; eFZ4 "`dJ'3gΠR1mɓ'RIJ;_7n$I|CKr*l#㒝7+`s){5kֈ#Xª`V 5;ҴYs/0hm 6pYxam^bҚ[b|crXT@WzUEuh Dz0$ ׶Ъ&]ENvK Ŷ*bA!&@,X@@59>|0 d|XE VjT'MT%^wء% ⢼M~46ɸq8SaFꊍ2᧗:tȩS Yn޼ĉx{t{4dHd~ĬTS,ohhP)uDdI.owpUMV.0"boƍrbYx0hJ6Wj3*JBuzl:X WZotUw9~@McW755!faЄ(';wLٰa+3ʊ^qc1cs=WԪ 3Ibլ˒HD 6mi$aU 4Y(t^'{;z(.%'WmݺKk@c*L<9*%q=6WE5WH8|g<#;hYa ? pefԩ,1n8kD?9T_hUunz^i+̅{]" :RHps$UMYp]`:EF/Qf]ON@>cƌ!GEGO>TdR&?|%.h-Fl?\!yٳ&LXzk@ioowQ5w&F9~8'KĈ駗ȏ o޼$,>wPe<i~EeS6:ODpIp硅wQi \dF]dR>wNaPdE/XRv TvѺnԜI0ڳ>8z~2Fh> 2. T6,ß^r&F={6狱̥fz &hnn^~<[NӦ%`E,tM OTo9$ Ђ'$g9!I(K}r:>;*'ONpA%cƌ!pGфO/immM2ݱ3|A hM ~|!HM;@ ҄{`h=tЄ{ψ^ /Χ ";$ b<.`ݺu(8&M@B5bP@kST4 "`d '_{{‘mӧ/31h¤I֯_V^̞=PIwhq«z>`ԠW|\Q*dOR$dj,TVjpw)rj >'ڥaЄ(?S]eO/9xSrW_EyI%."qw/Y&OI@`ȋI'.Bɭ?\rSCC,XP%CyH.Q&MTw|۰4e &f#X2T;Y$;yڂL/Kà Qf[[[Yq02O/Y~si$a‹G[ xKuҸ.0=쒩[kΛbڵk_FF#GtןpeUe(9^'e~ڠj%+b0|L]SU@0hm~"*2L٧T40 J"p744qSi$aV I(+%~zÇ҆u+^1rr$+K9KgT>;wֶ6n1q ? psж9w᧗={9W~?aPb*uQaWbx6%Np 6`[/ T޼ycƌkekE7[`.OSCCѣGu#*=ݡ ? p%okk9o]Y%4 JFAIZ='î,$O/AO<.+4fLRzMNcc#E͛YE,ɗݩP%N:5a„_]wp7otU]MRm sÿZnsyc0$ 4zOF]K:t5-ƘdssQ%O8AR $ $ׯ_OүݿK\iӦڏ?XtwwWɕڐ CKK,d:V甤$(? pE'ܕHK4$ 4zOF]/6l|\x!7dwRfd0hmm[sW"9L/40 It]`EFK:;;dCu;J+5& ȮK/ X@K^?(i&Vfɡ ;lA!_5jfzhΈ QD eœ O/ ^z#~Hq +!~/#F]H^Rb֬Y 'מ$O?f9h !VX]wK «VFћos Q\mTh̹+IGOXN#6; *섫hݻwԨQfduRinڈ D F3#RFPse$-.PL"R<JKaIy0~zsŋ3rf1DF'Fƌ{5l^oy0Yv<.nX۶9w⧗:uJ ㍝^39s[pMlWka ^yIvttM=Ě|*R*v@MK%]qfhi06V l[sW.z4tPFRl07v~#^ɽg֭F 6#g<$8p,F~[nLÅU2ܕ˝;w06x`oF+~Lww9sʕ+nOWkjlڴ_\dKG36 WUm[sW.ܤׯ_i$Exc7dzɱcjkk쬬dxAtL%mW|/=ל4X?;^/ºul_p!~Jv Kg̈́ȗڶ0D&- o5sqtL=5q Wkv]:w&F^D9wDػw\vxc緂5ӱݸqt mvn[+ٵ<^.>n#wcœ; 3gϘ1 XMrQ@Pa7ii~7v~+V~yӏ?xsss i=tuu]~ݭ_] ڥhmիW瞍7JsfPwyV|{'TPs#FZ% vxcB O/;Fm6)?~rd vTpY$w1`+VTXƿqn%IHDLI o֭[r1sr!fɓC½hѢYfR?n`oV4~zӧyk+Y3hΦ mEY|… 2`cDY2hp"*EA $ܔ"K)[#db].$6]WWg]b㍝Jv0dK.Af{@jjj}ݧsjmdmŏqbyz&k!iQIDAT9 jh Af7vmJeIs z-&Ǧxc7ܹsG w]n#S¶ x-Zc::{I> Re*QPǜ _lijf"ݤ9 ˻@vZ\J/ܴ˄Ȉ|׫mnhooǃIj ~;7Zlm.J8rKVI0,vxc0,w 10ɶ hfn(ͱ^RDV}T2[Ii޶x̹ݤ95l1.$6 l{ҤIGUpQĉ7FA05l1.$6xض07fMMM}}=ACC_"W((6;-ekLI[[eKl[sG1cp{&bн.2∝_Ȗ5&1 _vGF1!w]]c/mmmfZji(mwD90.;oy]QaqίadKYp#8~OҢkjjߔ/a~4uEїDg!!P$9wyYx1wk:EFkRƄ;Hf {ĈBI&a۾{Qa[nܸ10t|InK'Jc]^lnRԸN7EadFY"&`$'Vlȑ#7oxϮ]N>M=3yd-I?h $yС˗ژ1c(@! :ZHR!f a 1Ձà6s3fpr\006l1.$&܊qk 7LJG!lې8k#ʡT r>X7y$1i@ʫ[к:(@ʧ~m!G9wz&裏\006l1.$<-ZHqKK뺺:biHmHpV 1pA8fAy&.S–UJ@#Kk@}0@L]C{Ŝ,:.mFN3*eWJ2΄Ƕ!pyD^Vp4{H2O*b@x>Cx00.1۷oaFb{L~m[}0Kc$Wm>} qqYW+$PIUU6Zf鷯 djGAv pkd#c]nݺK/]rΝ;@'}5۔Rs 賺b Ni2Ŧ/ f۶m&L%aT_|*@E@ $naÆ)S] p pJk;*vmI*8qrwJSnr7 #I{oLt΍"ذu˖-fpY/[ u&Lܰa+Ccc#9{\I 7|f ,T,Sh\LjLpta]4K.T8_%&܆am C*pИ+IF[' #U>>I2u$y 7 AX?gNvAhoo8q4lݺҧ }u`m9eʔ#GGL G-&@XcY,Ky0xViIbrR *-PM{VS0.۷oǶڜ'Oʝ^bmF2m۶5kָ\#vp$ٹT`v^K^Ke]NxFIyÝj ¯ؒp :0fSi$%&܆a͛/njjajT4?`m!T6|I^!KvIq,2xܳ$PNf5ig[?AͶHRQK]ګ˵0~lH۞={\ELVpȹZg'FW_.8Ą0 i$_쾜?~ԩoƭ[ U#k%qp amCl;O4/:-׮];wnM/16 Ï(իy5Nqτ蟸:vi$N{͇~X)KL HSġCm6~169vٳGʛ9>ѣG]"^ p$*ez ; xb}ЇD3Μ98sT@L #d`/_>}~O/apmdLsmC4nРAi$_N/q袾qd%h4=!{s;GĄ0?s6>`رCbmT;v͛7IpIU̶AHy:M)Iх ,XuV,9+V(S[&( ʡO>|_"(Y\'C QfAJ+t𚟤m۶! wpV/ȵAdRD%USoY2DŽ01J;~zam=Otvv^+ 'N`y=BÑm猦p HjX$!Ӏ,ϓF5EB5HRIIA E~~k)%l{ժU!Xhb Epd~]MKc­>T'*K"H6h6pB(.\SOU #kg.]bs \. رc]2K3„ȗ:(pm :m4Fs 03/w&}A9,1c  (BZujA[udˊP:T뷾`|79O/[dLuV)1RӐpc2]fL$c b#V2Ii7k‘#GؔLdEeB{I Qh,!8mYs$$E5/+N+M%'ų0lP[5D*FQj 1'7 ZuTS5΍+q2Uǻx&Fs;wBP[[n:l;O#ɖÇO<%"@>K a<%W cǎEn`֬Y#FHeM(8P 1\cB,Hb53'8*SjmGIQ|PؑTAO Qx ܅l;pHAK a.~)0OLl9qNk/;v C  +Hp;ėWkؑ&к* ߟ#"Vo<&FQsmʄ 6nx:ؼys?&܆3?3FՐ4,spܹ=\n/}슋@]qp":m۷o>9l:iu駗0#Lx4A.ySܚɓ'C*˕L7TرGa`wZ!pDͶAY=E3?%ʕ+1ٳK%p p1f̘CDI\V16?3ǃ v.+w2 իW+n׹Ͷ!,H $ӧODLpQ% ?˹]V/ =Cyv԰&G}.ȘpۜnL fS-xS?&kM4)y,&&܆rn>U_--l;+Fr(u~ycI2$_I/ܬ~]}ytLn9 (C={6f۟pɯicQ5PsT$:-YyZ(T.:SIJdB~16Gn'CY帝$KyUʭMr/xGaL #SJfYX4cd) O G@ P[ PST={ WrK8H\ԩS#vFuuԡdLz%T=@iJju;IºlLpj;SLDH4=O{uc[ gԝ-;,e"HzZYQeԴpBS>0GHi+09f36 I)l;[&MkQ!W3qG z$ABR)]Y VWa vg; UQά\׿5ce=z4K^ 𫬰 +GniO$,UDųI @)L$!Њ@iU!N~>^ݛ3%ixrGPRw ]DJ!X5/\v-Mͭ,9À7Cj(5t`L?fKqτ(0qn`ݣlI­LÀ!LA?R#^ l0(VIدrcǏrx?+W6lȑ#nЄt j/A(ӔGu)tB3Fz^ WèLbmN4nӦMa倇u0(0Ώ;dy)2Ei"+Ѻښ6*)}4=cAAEku]$LcΗ k _* rMZ[h-eIM~_C‡1Zj36ٳ|.ll;ܹm|wrT}i$ I&xb>^ݾ# !.Q8- x$O}"3F1RezV7eM/XrCO19*`&A+R{&F)smK.͜9_dqT\|9a =?~ɏǏsD_D"̓0*[n1V0b rJU1H%} MX`ASSSg#'aҝ;ZԩS6l@14vX>*ԻqCzoɧTEͪ2[P෣`#`Z@+ԷjTnʹͶAK*"M#ɄII1 q??'M. %p C态/ 0e˖iJӧiҥKuWZh{{;# 8.(gKń0 Cnm]2Ç;c'эsSO6JEhtې>`I*j$})P9x3NCe'mWN/)82$ aTϜ9nzpD%,\nd06ר !%16c]]/œ9susuuuݸqaĸK,>&F1DK0V40?N a/_\9pCƍu[AwwO?vSc46΀½w^㧗V(x̙316DO={Yn:lg)|;wb a{Ĉ;v XjU]]2%=؁cǎU40&܆Q$`{fΜ駑suam`@ƶqnf͚% 2IuzIN# cmU1w7@P6<۾}\`ĸ\pQg@Tۿnii!w^\C !IFYKri<]*zIx5ת&F$2uQZpً-R|U(79O/40\Z^>~0o \lg._N~@i$ɸf?(מ&F$P/>vŭwFazI̦I0 1ӳgNxp5WjP㒋 p amDn"<ĽIM$VBJIkao :th,_4D  L㍦A/]]]owb0$ woz H |_4)oam&'ۧ8|缻QPL #\zuv+Wܹsŋ755ܒb`mT#XȀE-_ۀ%=M;pfkjjxO?o'xp0n8.JVTGߴif4$N(\!.*&Fذa|jqٝvҋ"H ׉ӽ$\2sL1bĈ.0x`G-\%O]k֬ill<};?~ԩo?cg_@kkk|Dy͚5jիW]" G뤵//* H3d.qx]|=\ l $Gc1PGЊƹ Xj ,-Z%=YfIʳbC;ɓ''N~z]#K<\TL=tP^U{!>crGxMMMc1&V|ŋeÆ gϞu\'NBpe{oE}ݕ+WG%`ƌ个?@꫊Y:&e*hEU 6*Թtرc `*n@m68wSS{miiQLJҝ>}:1?_p§z*ߢ Q0X˗W2+3ꁇg3RG ]!U Jk1~饗6mڤ_ _~%F됰r\'BpK*(+S$$Yj–jz'6H֔C Њsn Z3ycؠLjf|p|r6eKyCn9rQ¿")74rHI;wV6 l g猬^͛*ӧOrBh~jkgQApl-e֯pWy 7 f͚5bY%lִsĉO+ p1G^z?]-| [‰O/˖-s=[MpYN>}ҥ/bMą{ѢE֭sY|whr`|gHq \y睱cۈ۷og)KSl… nUorJ%2w\J޽{]溦p8q^ziH* rQEw#<ؽ{Cpk:[`;qQEt>Xw /01n#>`GGҒp#.\pwy,\ItLVAI TDM$P{R9qF6` s&O6SSk .u-.h;vxGk06bBYb:t??nܸFzG{W=vjhh[\Ŏh ^oNW_}uҥtu[FUR>|N+" QH._@ElS$' Z%lo~d  wBWJRmp6qիW#6LxYpiO^V6lF>{q->ŋ[ IÇ;w\O<[v車 "M]9#w̜իW9sh$M&ظqoxrDkT| pF9^4ilW7&FsȑׯˀK… W\YGTG)VEcǎ;"G4{fĉq_rg%ܐ RLE#k$oǿU5S 3în˖-n][w9n[]ת<\^% {qmbLʆS0O?wN3S1"ގ8Kd}ym_&0 73Dt,GHWCUFwD뭷Q]gxur31cڵ?$8t=C&2#</RF(%TQnNrb͚5&L`#ngXP Oh#FĬN~ʽPE7oW'L(J2ySS… \cҲo> n={|ഷ|]ǹ~/Z:ApQB$(b-ep5JU z&\^%k׮ת$ee n9~x]]'wpF_虚?¯"w :ZOaq@xfp,(_29ofԨQ CMMMMnMzE7 TLu] U"Ȗ*C{qԌ1ѣ sgngKW } 6o/n|T9\!\~]ȡ_<5Z*GpIPk%19):@&{UJ9x+ֺ\ὐjiW'|?)?6v_ {嶭 qqԌApȰ_$>͚5jK75?~:n#wv:ۍ̙S/Պ>sA@)Cy"1$Z ^gZ poJHq/o|rWeF>PWr^zjQ2uuuE_%)3_S/\QR\$yג|b5Z%PMkLToA삍-:*N^חǛSkW2bjN ,pk׮}ƍZ ;ȁFT{ȑ'Oɠ,oFc"^kz}Ӱ9z>_E,ˍT7RR:ZCMbjőO¡C6F@R{I@SS__wXp. i %^2+@*t-I*V|Mm [WH/!+j`) d1`n /ՇƍG}T[[yO=^p~p9ݍ:ύӦMc|G# (N |Nd|PK˙T~S +rQN':ΉFQO#|M`\9 g: )%?˄wERv_<Z38{ٳ>s0nݺ5sL+ހ$|.  ,hjjoQ<bM؀… _/~-`y16rے{2sBt%wF@kOnMzE 9)sH2W=tY=[ |+8PY? Vr#IAH#|6;vlW/ś;B{iuPiߴ"^($.>A=>l5]/=W믿n.ʂ |/ϟkdvU$YT&a0*=3,6$PSShFb#ݻf0d~bŋWXqw}7|Q/$|57oGGn-U0Q w i[Ǐommu{%R 4K5|$O5P} 7*(=TvQ kF O#a`m˕+W:j6C % AIT&߿ѐO3{l>,1|\3x3M#_KK G(Ad 8LM$ȥ*I [!gy/]B]{z* %A5kK?YdI}}}x=ˋ x_W}AzۿF1 N}.bT@rϩ,~BZQt^_6;;wpv#5SJ-Zf͚^[.}! >纩Tf%]Ce644`JBss3'Ce*?OJ&p0a^,4YokF fI52O19QZWIjTOүaצ$3n8>m۶&=x\OEF//\|A0*]$]7\K\CĹ[Ʉ|(p?_?1Dnr"u>r:_S޽?%aH" G>~6<-FY&<ziRlJ1lȗT1ѣ]]]^[xC;?d_^bZZZ^~ew.pG @>OZbE}}=>uoEn#ƍw}A",JsM@M)f /|ճf͚9sé\,\pW'N7%*7Ok֬ai$DŽȅ˗/Ymiޟϖ={;IZjΜ9R*F;!eꫜoF&{pիWU_UuF1{W\]֭[/0a·~뤸8{g8iUL\H}v{/"4wF]'8{SAtmZv8QF577>}rywh)26d.ܟ| ~ř@%@4D?:ݻ \B6En#7i$cɒ% .#6Rk.F?Щh׊~& }mFA.]J9ANQcg} Z{#UU)g 4I]zpHB8+""ܢ7pW8×W۫ULoy1(N8裏bי3g:rƍnƍX}x3dNUV|Wh lj';wr-/+dn@d^dO^x+GF7U@(*R>5YlXתrs֭?O<ę3g! /6 -gDn#G"#N1\fT/7NQc-[еÇP#-8M֮] .ח{j'hݕ+WsЀ wuZ d2YjrڤIΝT|cI>I\a_lp۵k\a?~U7o#n*. H6 ɍv}أX>:,g~_~%޿V]"^~\8ְo2 Lu֯V2O<ĶWmy0c52 z3WyXMl/+NcpBG$v&_l?nZxV=/Ydnn1i$m!ݑnO ϟsfΜbrkT&F<847"|w>F%)wF 7?Å 4ùs\Tٗ/_F6l@˭J聞 X> ֮]C//*(&:fo}MƲmܹ!BkU`h9jԨ9zhmmmx myRpsc:Ս݁q+%*~ö' .E}}' ZIǏ/=ضM#&F^,Zh͚5?D26iT$a'z[TKn/ghhUQ͛9Tw}6cƌ_|O#!ǦT4&F^tww?C.\p[Vy+6y04$B%s}Za~M6&+ԑ#GƏvZmc]cmKD^r_o1aF$U>[Ch p<|M}}Uk_c) q%FL|u~}wQ9_6 # z -Z|9fqUKn_X מJO>}z<_+eĄ(gϞ} KZ90eʔVPsa}߾}.L_vQ0ٟȌO?:t[o`~}hA8}tssQw#-0ۈY 7n[1"(4" Q,n߾u3f Ns_G.]*/I0DŽۈ\mmm-R_hD nk׮}ov1}Yss3[Xp9` a :7&Fѹu~v?3կ~u֥jrqG.]zQy6tvvQ(Lt(`a16Jϝ;.{3gάepG}|s=JB/(5 F0ޘp%tRGG3?ٳ/^vڝ;w܆ 0 :7&Fyu˗%a9RfQTLt(`a16"? WH0J:7&܆aFUSSSFy:tWGL 0 0 hm4HoIENDB`tomcat7-7.0.52/webapps/docs/images/asf-logo.gif0000644000175100017510000001615710457676032021223 0ustar locutuslocutusGIF89ad~fff̙3olJff3OEfffOf3{7O33fffPPPf3333fN@EσYf/XTJϷTffffuf3ff3JmvdfffVPEOVNjE H̙f|~cv3fǰdlԮifIvt33gt|tA{F|{7-}L"Bjx̙OKVE휃0*PjOV]~ff33{M VJqYOCLVAMY UQPw{}Hm~_!tr lT=GQx|N\n{8QuNNNlUHiïNy/f3fQ̙!,d@H*\ȰÇ#JHŋ3jx1,HP8  =p(Pϟ@ JQ:(3ǧ a8 WhB+x FAK͛شB`ǀGfF!@ 5ᆄ+V(`f&<qbwRt@:uL@# Xz+1u@k̗q[W&tkA yB KE ``>CpA 7 W.t7CsjG(hB z6eh^k&U - }(\m]F% @4F +P"QY‘H^A4@W} X_A)P S h@Y lfolq9KkFm#*TxL-VWBf J(xhG{|dp\P (ܰ)74܀DCJRSYGk[by]w.Øk$E\* a&n} D`;=[CMvz7/y?}uwHD/}>͓~Y/ A BgoC@9P̠2,/Bp`FBUՂ%7&70` qXѡ3W1AW@PO/ӜB+xFʉKsVQGez ϤYm|~^ѱ!: <`Zo>06fE"D=I"E* YPpOM^D >AԻmkcB3JWB,3^~kw1 TMؖ -A*ʍ6q(BW(H! GGFdk6Ǔ bA4Ѐء m`9K0^Mk DC8)- hB~P-s!D ]\2Es!`R-,EЀnv@7@S@h %!OHjD@CKBCNpHJ) [ׄTs>Ǖ1{2JC14,c߳mHhd`Qz3:$tCYb:le؍ru臽vc5 .k^zasnZ?G$ժLݡ-qzC6wLj7]겖UucDz2~@s˳ۄδtil~X$򖱤-HZ!"3mo D  ǹQxvϋ1lJN0q#_[I.wL@!/N>2!C$uAo~dm%Pᄏҝ+%Hfz:>5Hb1%kvtwo ڈ#B3h$* h3ELarđ` 6a.vWA1w/X'cWmpyq6X/|!_~Krf $+A5(+lG0A~(3Gmh@M[Jkj@ ,4HQɷ [vF'v 1fK]wI8j޲ V}]a1`"[ 8]hypNOG ن-mxˁRSI'*"ljw0R DUoBv@Ӷp7O M^R4}SST!uHNdc0"Q77 syC1~ P4(@PbPvGzg^uujUgeWrLK/1y[Y\ȅB &g0}(4)NBE*g.7ef&O@UOX% <9|nՄ1:"% W${f%gF;؄R@@=4mcROYX&`osqM4S4-E&XԅdTsWdp^ap/!N]u)apraLOq pO׃B@A9d>*"w\r{Jh_c\{WxUWKqɂ2ypUO0 >BsS٤~ 'lq vtBTv`irPu)1"m&iqW8WdΤ,)ג4ْwWS'CȂ$\L;95G!w$I^a:@qDYQodfKpdVqb]c9K!C5Y?g_V7ҕ]1|LCu%A1sg+4\g9d 8NUW8VyhuK]SX闊4&:ݕ,AL0ty㚥YC!v5i6IRI|a'x3 hV)ǩoi]S^_CgǙLhz^v:i*sY^$LBhq7exguٕFJf`lE  WR&7RVeOS%dg]lW7#ha%#f!7b1v63q0<22&624{6$-6ZIʜ D1ee<ifeDӥAdp$n?Y7$1cd9Î`ZQ/y4֡SL?) = S2کjZD:ڪgcr w,20<=:G ` !%`2P2@ ^H8^J RJ1kii'0'B "ĆEtyTi"x%_m&ER;lwln)PF}LGL_V('RpԮ] gCj gCIv1{}ŒLa?aб?e7WsSr@KUBZ ៨ k6i3isQDA$xs*Ү7'4D)>" 4z:8ZI؄ֵ FF~`#pNkD葨v$RBG1,,}THwI+,}qKw[qsKWpą4DEP#.E5l \K2s48%uez߱iǛhZ3| 0IBV9t $4pD}l"x!1WM!;J3~Wn7«Gqa3\ķ9{$Q 4|rc̿Y3zk8,qCroW}dh!Xʎm]1pnD"TLJ,/2T{.1Z_tWe̼PE1kJ7J'˥|8slX"!HI,pTt$BOǑkrya a$ QMÒP Cmv*0b"tIL+E$Bln}B'GW1+pPpRP@R=ZȿwiH:iǒRMɼ[M{?E^0]vƢ,;@E0&,P.Ru҂ۄxNa"0QE`SKehA`&M0/ Z鎚hOQ`čHas9 qV8;WG50 {p.os6Ex=CMcM `&vTP5/v$)WOH8GpL!KPYPO`tO&0޼qCta#/tM.X,!crҝ& WXs, ?0),a/&U/P}G.0ْm0~ NH;NMWP90p4uku|%1 1ԥ41;FBACiwAQ 0zV^/}oO_ XDŽ5\N` <1GUsd)i`Iݞ 4aaN 1᳇EauXX8^VvrBmawVM^9UXcɄٿ {A 0$H0À D0a@BC hq-`Aɏ%0aCD1M9I0Č) š0L8re̚YQVtVK%{rNNxq@^OjsCy,)pEia<1eLK0ʕxTVވ8g݁beYUC+U\J1}}yuŹOca-S>91d;6춠I'FË:semW >h㋮ .!I;M+žZAAlSQ9 /$1b#>yͿ-22$fS*ro5c !'#z3# ؼHI6O=׌TjȐ,h.D. S5'4uB>&QҳG1QʱpTSOMU8m@肽-X}$_.ٲeXafmڎZj[pw\r5\tUL+ե6dX]z]{|YQ:]3j_7asABaD_ ~ч 1He4EJwҩ H^ $*hD<%iy%%3kRT^+)cׅ0@wX'x-jP^f 'Zfb{kۘ꫒xkk,lT֓k71,n N BA$bV:sQJ;h3߃#\ƫr*u7_w:-Ȼԍݛ_zǾw7׽+ f%}MUΊp?p܍6E0e- 榷H,H?و$ |AX@T1ZNL JYN3eKNJE|{^wCOZ q-_g:@!&QKdbD(FQS4^@;tomcat7-7.0.52/webapps/docs/images/update.gif0000644000175100017510000000116310457676032020765 0ustar locutuslocutusGIF89a???>>>??=@@@=?>>@?*EVeOB?2- z%sJb*FT1Iaooopno@>?Ͽ ®¬2 Ģ5E:л~nod|d$,#}&Y\/t1 /%IJϹͫЦΠ7Бu܃Xjt܅ޡ*~mskq$**w/؆4q5 / ¯ -͵в#,؀  !"#$%&փ''()*++*,-./0123456789:;<=>(?@ABC1rI%K XǤ'PHB+qK,ZpE D(90a\S4`2dDEa0YZiRIH%M:(;tomcat7-7.0.52/webapps/docs/realm-howto.xml0000644000175100017510000014670312275241511020527 0ustar locutuslocutus ]> &project; Craig R. McClanahan Yoav Shapira Andrew R. Jaquith Realm Configuration HOW-TO

This document describes how to configure Tomcat to support container managed security, by connecting to an existing "database" of usernames, passwords, and user roles. You only need to care about this if you are using a web application that includes one or more <security-constraint> elements, and a <login-config> element defining how users are required to authenticate themselves. If you are not utilizing these features, you can safely skip this document.

For fundamental background information about container managed security, see the Servlet Specification (Version 2.4), Section 12.

For information about utilizing the Single Sign On feature of Tomcat (allowing a user to authenticate themselves once across the entire set of web applications associated with a virtual host), see here.

A Realm is a "database" of usernames and passwords that identify valid users of a web application (or set of web applications), plus an enumeration of the list of roles associated with each valid user. You can think of roles as similar to groups in Unix-like operating systems, because access to specific web application resources is granted to all users possessing a particular role (rather than enumerating the list of associated usernames). A particular user can have any number of roles associated with their username.

Although the Servlet Specification describes a portable mechanism for applications to declare their security requirements (in the web.xml deployment descriptor), there is no portable API defining the interface between a servlet container and the associated user and role information. In many cases, however, it is desirable to "connect" a servlet container to some existing authentication database or mechanism that already exists in the production environment. Therefore, Tomcat defines a Java interface (org.apache.catalina.Realm) that can be implemented by "plug in" components to establish this connection. Six standard plug-ins are provided, supporting connections to various sources of authentication information:

  • JDBCRealm - Accesses authentication information stored in a relational database, accessed via a JDBC driver.
  • DataSourceRealm - Accesses authentication information stored in a relational database, accessed via a named JNDI JDBC DataSource.
  • JNDIRealm - Accesses authentication information stored in an LDAP based directory server, accessed via a JNDI provider.
  • UserDatabaseRealm - Accesses authentication information stored in an UserDatabase JNDI resource, which is typically backed by an XML document (conf/tomcat-users.xml).
  • MemoryRealm - Accesses authentication information stored in an in-memory object collection, which is initialized from an XML document (conf/tomcat-users.xml).
  • JAASRealm - Accesses authentication information through the Java Authentication & Authorization Service (JAAS) framework.

It is also possible to write your own Realm implementation, and integrate it with Tomcat. To do so, you need to:

  • Implement org.apache.catalina.Realm,
  • Place your compiled realm in $CATALINA_HOME/lib,
  • Declare your realm as described in the "Configuring a Realm" section below,
  • Declare your realm to the MBeans Descriptor.

Before getting into the details of the standard Realm implementations, it is important to understand, in general terms, how a Realm is configured. In general, you will be adding an XML element to your conf/server.xml configuration file, that looks something like this:

<Realm className="... class name for this implementation" ... other attributes for this implementation .../>

The <Realm> element can be nested inside any one of of the following Container elements. The location of the Realm element has a direct impact on the "scope" of that Realm (i.e. which web applications will share the same authentication information):

  • Inside an <Engine> element - This Realm will be shared across ALL web applications on ALL virtual hosts, UNLESS it is overridden by a Realm element nested inside a subordinate <Host> or <Context> element.
  • Inside a <Host> element - This Realm will be shared across ALL web applications for THIS virtual host, UNLESS it is overridden by a Realm element nested inside a subordinate <Context> element.
  • Inside a <Context> element - This Realm will be used ONLY for THIS web application.

For each of the standard Realm implementations, the user's password (by default) is stored in clear text. In many environments, this is undesirable because casual observers of the authentication data can collect enough information to log on successfully, and impersonate other users. To avoid this problem, the standard implementations support the concept of digesting user passwords. This allows the stored version of the passwords to be encoded (in a form that is not easily reversible), but that the Realm implementation can still utilize for authentication.

When a standard realm authenticates by retrieving the stored password and comparing it with the value presented by the user, you can select digested passwords by specifying the digest attribute on your <Realm> element. The value for this attribute must be one of the digest algorithms supported by the java.security.MessageDigest class (SHA, MD2, or MD5). When you select this option, the contents of the password that is stored in the Realm must be the cleartext version of the password, as digested by the specified algorithm.

When the authenticate() method of the Realm is called, the (cleartext) password specified by the user is itself digested by the same algorithm, and the result is compared with the value returned by the Realm. An equal match implies that the cleartext version of the original password is the same as the one presented by the user, so that this user should be authorized.

To calculate the digested value of a cleartext password, two convenience techniques are supported:

  • If you are writing an application that needs to calculate digested passwords dynamically, call the static Digest() method of the org.apache.catalina.realm.RealmBase class, passing the cleartext password and the digest algorithm name as arguments. This method will return the digested password.
  • If you want to execute a command line utility to calculate the digested password, simply execute CATALINA_HOME/bin/digest.[bat|sh] -a {algorithm} {cleartext-password} and the digested version of this cleartext password will be returned to standard output.

If using digested passwords with DIGEST authentication, the cleartext used to generate the digest is different and the digest must use the MD5 algorithm. In the examples above {cleartext-password} must be replaced with {username}:{realm}:{cleartext-password}. For example, in a development environment this might take the form testUser:Authentication required:testPassword. The value for {realm} is taken from the <realm-name> element of the web application's <login-config>. If not specified in web.xml, the default value of Authentication required is used.

Non-ASCII usernames and/or passwords are supported using CATALINA_HOME/bin/digest.[bat|sh] -a {algorithm} -e {encoding} {input} but care is required to ensure that the non-ASCII input is correctly passed to the digester. The digester returns {input}:{digest}. If the input appears corrupted in the return, the digest will be invalid.

The example application shipped with Tomcat includes an area that is protected by a security constraint, utilizing form-based login. To access it, point your browser at http://localhost:8080/examples/jsp/security/protected/ and log on with one of the usernames and passwords described for the default UserDatabaseRealm.

If you wish to use the Manager Application to deploy and undeploy applications in a running Tomcat installation, you MUST add the "manager-gui" role to at least one username in your selected Realm implementation. This is because the manager web application itself uses a security constraint that requires role "manager-gui" to access ANY request URI within the HTML interface of that application.

For security reasons, no username in the default Realm (i.e. using conf/tomcat-users.xml is assigned the "manager-gui" role. Therefore, no one will be able to utilize the features of this application until the Tomcat administrator specifically assigns this role to one or more users.

Debugging and exception messages logged by a Realm will be recorded by the logging configuration associated with the container for the realm: its surrounding Context, Host, or Engine.

Introduction

JDBCRealm is an implementation of the Tomcat Realm interface that looks up users in a relational database accessed via a JDBC driver. There is substantial configuration flexibility that lets you adapt to existing table and column names, as long as your database structure conforms to the following requirements:

  • There must be a table, referenced below as the users table, that contains one row for every valid user that this Realm should recognize.
  • The users table must contain at least two columns (it may contain more if your existing applications required it):
    • Username to be recognized by Tomcat when the user logs in.
    • Password to be recognized by Tomcat when the user logs in. This value may in cleartext or digested - see below for more information.
  • There must be a table, referenced below as the user roles table, that contains one row for every valid role that is assigned to a particular user. It is legal for a user to have zero, one, or more than one valid role.
  • The user roles table must contain at least two columns (it may contain more if your existing applications required it):
    • Username to be recognized by Tomcat (same value as is specified in the users table).
    • Role name of a valid role associated with this user.

Quick Start

To set up Tomcat to use JDBCRealm, you will need to follow these steps:

  1. If you have not yet done so, create tables and columns in your database that conform to the requirements described above.
  2. Configure a database username and password for use by Tomcat, that has at least read only access to the tables described above. (Tomcat will never attempt to write to these tables.)
  3. Place a copy of the JDBC driver you will be using inside the $CATALINA_HOME/lib directory. Note that only JAR files are recognized!
  4. Set up a <Realm> element, as described below, in your $CATALINA_BASE/conf/server.xml file.
  5. Restart Tomcat if it is already running.

Realm Element Attributes

To configure JDBCRealm, you will create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file, as described above. The attributes for the JDBCRealm are defined in the Realm configuration documentation.

Example

An example SQL script to create the needed tables might look something like this (adapt the syntax as required for your particular database):

create table users ( user_name varchar(15) not null primary key, user_pass varchar(15) not null ); create table user_roles ( user_name varchar(15) not null, role_name varchar(15) not null, primary key (user_name, role_name) );

Example Realm elements are included (commented out) in the default $CATALINA_BASE/conf/server.xml file. Here's an example for using a MySQL database called "authority", configured with the tables described above, and accessed with username "dbuser" and password "dbpass":

<Realm className="org.apache.catalina.realm.JDBCRealm" driverName="org.gjt.mm.mysql.Driver" connectionURL="jdbc:mysql://localhost/authority?user=dbuser&amp;password=dbpass" userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles" roleNameCol="role_name"/>

Additional Notes

JDBCRealm operates according to the following rules:

  • When a user attempts to access a protected resource for the first time, Tomcat will call the authenticate() method of this Realm. Thus, any changes you have made to the database directly (new users, changed passwords or roles, etc.) will be immediately reflected.
  • Once a user has been authenticated, the user (and his or her associated roles) are cached within Tomcat for the duration of the user's login. (For FORM-based authentication, that means until the session times out or is invalidated; for BASIC authentication, that means until the user closes their browser). The cached user is not saved and restored across sessions serialisations. Any changes to the database information for an already authenticated user will not be reflected until the next time that user logs on again.
  • Administering the information in the users and user roles table is the responsibility of your own applications. Tomcat does not provide any built-in capabilities to maintain users and roles.

Introduction

DataSourceRealm is an implementation of the Tomcat Realm interface that looks up users in a relational database accessed via a JNDI named JDBC DataSource. There is substantial configuration flexibility that lets you adapt to existing table and column names, as long as your database structure conforms to the following requirements:

  • There must be a table, referenced below as the users table, that contains one row for every valid user that this Realm should recognize.
  • The users table must contain at least two columns (it may contain more if your existing applications required it):
    • Username to be recognized by Tomcat when the user logs in.
    • Password to be recognized by Tomcat when the user logs in. This value may in cleartext or digested - see below for more information.
  • There must be a table, referenced below as the user roles table, that contains one row for every valid role that is assigned to a particular user. It is legal for a user to have zero, one, or more than one valid role.
  • The user roles table must contain at least two columns (it may contain more if your existing applications required it):
    • Username to be recognized by Tomcat (same value as is specified in the users table).
    • Role name of a valid role associated with this user.

Quick Start

To set up Tomcat to use DataSourceRealm, you will need to follow these steps:

  1. If you have not yet done so, create tables and columns in your database that conform to the requirements described above.
  2. Configure a database username and password for use by Tomcat, that has at least read only access to the tables described above. (Tomcat will never attempt to write to these tables.)
  3. Configure a JNDI named JDBC DataSource for your database. Refer to the JNDI DataSource Example HOW-TO for information on how to configure a JNDI named JDBC DataSource.
  4. Set up a <Realm> element, as described below, in your $CATALINA_BASE/conf/server.xml file.
  5. Restart Tomcat if it is already running.

Realm Element Attributes

To configure DataSourceRealm, you will create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file, as described above. The attributes for the DataSourceRealm are defined in the Realm configuration documentation.

Example

An example SQL script to create the needed tables might look something like this (adapt the syntax as required for your particular database):

create table users ( user_name varchar(15) not null primary key, user_pass varchar(15) not null ); create table user_roles ( user_name varchar(15) not null, role_name varchar(15) not null, primary key (user_name, role_name) );

Here is an example for using a MySQL database called "authority", configured with the tables described above, and accessed with the JNDI JDBC DataSource with name "java:/comp/env/jdbc/authority".

<Realm className="org.apache.catalina.realm.DataSourceRealm" dataSourceName="jdbc/authority" userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles" roleNameCol="role_name"/>

Additional Notes

DataSourceRealm operates according to the following rules:

  • When a user attempts to access a protected resource for the first time, Tomcat will call the authenticate() method of this Realm. Thus, any changes you have made to the database directly (new users, changed passwords or roles, etc.) will be immediately reflected.
  • Once a user has been authenticated, the user (and his or her associated roles) are cached within Tomcat for the duration of the user's login. (For FORM-based authentication, that means until the session times out or is invalidated; for BASIC authentication, that means until the user closes their browser). The cached user is not saved and restored across sessions serialisations. Any changes to the database information for an already authenticated user will not be reflected until the next time that user logs on again.
  • Administering the information in the users and user roles table is the responsibility of your own applications. Tomcat does not provide any built-in capabilities to maintain users and roles.

Introduction

JNDIRealm is an implementation of the Tomcat Realm interface that looks up users in an LDAP directory server accessed by a JNDI provider (typically, the standard LDAP provider that is available with the JNDI API classes). The realm supports a variety of approaches to using a directory for authentication.

Connecting to the directory

The realm's connection to the directory is defined by the connectionURL configuration attribute. This is a URL whose format is defined by the JNDI provider. It is usually an LDAP URL that specifies the domain name of the directory server to connect to, and optionally the port number and distinguished name (DN) of the required root naming context.

If you have more than one provider you can configure an alternateURL. If a socket connection can not be made to the provider at the connectionURL an attempt will be made to use the alternateURL.

When making a connection in order to search the directory and retrieve user and role information, the realm authenticates itself to the directory with the username and password specified by the connectionName and connectionPassword properties. If these properties are not specified the connection is anonymous. This is sufficient in many cases.

Selecting the user's directory entry

Each user that can be authenticated must be represented in the directory by an individual entry that corresponds to an element in the initial DirContext defined by the connectionURL attribute. This user entry must have an attribute containing the username that is presented for authentication.

Often the distinguished name of the user's entry contains the username presented for authentication but is otherwise the same for all users. In this case the userPattern attribute may be used to specify the DN, with "{0}" marking where the username should be substituted.

Otherwise the realm must search the directory to find a unique entry containing the username. The following attributes configure this search:

  • userBase - the entry that is the base of the subtree containing users. If not specified, the search base is the top-level context.
  • userSubtree - the search scope. Set to true if you wish to search the entire subtree rooted at the userBase entry. The default value of false requests a single-level search including only the top level.
  • userSearch - pattern specifying the LDAP search filter to use after substitution of the username.

Authenticating the user

  • Bind mode

    By default the realm authenticates a user by binding to the directory with the DN of the entry for that user and the password presented by the user. If this simple bind succeeds the user is considered to be authenticated.

    For security reasons a directory may store a digest of the user's password rather than the clear text version (see Digested Passwords for more information). In that case, as part of the simple bind operation the directory automatically computes the correct digest of the plaintext password presented by the user before validating it against the stored value. In bind mode, therefore, the realm is not involved in digest processing. The digest attribute is not used, and will be ignored if set.

  • Comparison mode

    Alternatively, the realm may retrieve the stored password from the directory and compare it explicitly with the value presented by the user. This mode is configured by setting the userPassword attribute to the name of a directory attribute in the user's entry that contains the password.

    Comparison mode has some disadvantages. First, the connectionName and connectionPassword attributes must be configured to allow the realm to read users' passwords in the directory. For security reasons this is generally undesirable; indeed many directory implementations will not allow even the directory manager to read these passwords. In addition, the realm must handle password digests itself, including variations in the algorithms used and ways of representing password hashes in the directory. However, the realm may sometimes need access to the stored password, for example to support HTTP Digest Access Authentication (RFC 2069). (Note that HTTP digest authentication is different from the storage of password digests in the repository for user information as discussed above).

Assigning roles to the user

The directory realm supports two approaches to the representation of roles in the directory:

  • Roles as explicit directory entries

    Roles may be represented by explicit directory entries. A role entry is usually an LDAP group entry with one attribute containing the name of the role and another whose values are the distinguished names or usernames of the users in that role. The following attributes configure a directory search to find the names of roles associated with the authenticated user:

    • roleBase - the base entry for the role search. If not specified, the search base is the top-level directory context.
    • roleSubtree - the search scope. Set to true if you wish to search the entire subtree rooted at the roleBase entry. The default value of false requests a single-level search including the top level only.
    • roleSearch - the LDAP search filter for selecting role entries. It optionally includes pattern replacements "{0}" for the distinguished name and/or "{1}" for the username and/or "{2}" for an attribute from user's directory entry, of the authenticated user. Use userRoleAttribute to specify the name of the attribute that provides the value for "{2}".
    • roleName - the attribute in a role entry containing the name of that role.
    • roleNested - enable nested roles. Set to true if you want to nest roles in roles. If configured, then every newly found roleName and distinguished Name will be recursively tried for a new role search. The default value is false.
  • Roles as an attribute of the user entry

    Role names may also be held as the values of an attribute in the user's directory entry. Use userRoleName to specify the name of this attribute.

A combination of both approaches to role representation may be used.

Quick Start

To set up Tomcat to use JNDIRealm, you will need to follow these steps:

  1. Make sure your directory server is configured with a schema that matches the requirements listed above.
  2. If required, configure a username and password for use by Tomcat, that has read only access to the information described above. (Tomcat will never attempt to modify this information.)
  3. Set up a <Realm> element, as described below, in your $CATALINA_BASE/conf/server.xml file.
  4. Restart Tomcat if it is already running.

Realm Element Attributes

To configure JNDIRealm, you will create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file, as described above. The attributes for the JNDIRealm are defined in the Realm configuration documentation.

Example

Creation of the appropriate schema in your directory server is beyond the scope of this document, because it is unique to each directory server implementation. In the examples below, we will assume that you are using a distribution of the OpenLDAP directory server (version 2.0.11 or later), which can be downloaded from http://www.openldap.org. Assume that your slapd.conf file contains the following settings (among others):

database ldbm suffix dc="mycompany",dc="com" rootdn "cn=Manager,dc=mycompany,dc=com" rootpw secret

We will assume for connectionURL that the directory server runs on the same machine as Tomcat. See http://java.sun.com/products/jndi/docs.html for more information about configuring and using the JNDI LDAP provider.

Next, assume that this directory server has been populated with elements as shown below (in LDIF format):

# Define top-level entry dn: dc=mycompany,dc=com objectClass: dcObject dc:mycompany # Define an entry to contain people # searches for users are based on this entry dn: ou=people,dc=mycompany,dc=com objectClass: organizationalUnit ou: people # Define a user entry for Janet Jones dn: uid=jjones,ou=people,dc=mycompany,dc=com objectClass: inetOrgPerson uid: jjones sn: jones cn: janet jones mail: j.jones@mycompany.com userPassword: janet # Define a user entry for Fred Bloggs dn: uid=fbloggs,ou=people,dc=mycompany,dc=com objectClass: inetOrgPerson uid: fbloggs sn: bloggs cn: fred bloggs mail: f.bloggs@mycompany.com userPassword: fred # Define an entry to contain LDAP groups # searches for roles are based on this entry dn: ou=groups,dc=mycompany,dc=com objectClass: organizationalUnit ou: groups # Define an entry for the "tomcat" role dn: cn=tomcat,ou=groups,dc=mycompany,dc=com objectClass: groupOfUniqueNames cn: tomcat uniqueMember: uid=jjones,ou=people,dc=mycompany,dc=com uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com # Define an entry for the "role1" role dn: cn=role1,ou=groups,dc=mycompany,dc=com objectClass: groupOfUniqueNames cn: role1 uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com

An example Realm element for the OpenLDAP directory server configured as described above might look like this, assuming that users use their uid (e.g. jjones) to login to the application and that an anonymous connection is sufficient to search the directory and retrieve role information:

<Realm className="org.apache.catalina.realm.JNDIRealm" connectionURL="ldap://localhost:389" userPattern="uid={0},ou=people,dc=mycompany,dc=com" roleBase="ou=groups,dc=mycompany,dc=com" roleName="cn" roleSearch="(uniqueMember={0})" />

With this configuration, the realm will determine the user's distinguished name by substituting the username into the userPattern, authenticate by binding to the directory with this DN and the password received from the user, and search the directory to find the user's roles.

Now suppose that users are expected to enter their email address rather than their userid when logging in. In this case the realm must search the directory for the user's entry. (A search is also necessary when user entries are held in multiple subtrees corresponding perhaps to different organizational units or company locations).

Further, suppose that in addition to the group entries you want to use an attribute of the user's entry to hold roles. Now the entry for Janet Jones might read as follows:

dn: uid=jjones,ou=people,dc=mycompany,dc=com objectClass: inetOrgPerson uid: jjones sn: jones cn: janet jones mail: j.jones@mycompany.com memberOf: role2 memberOf: role3 userPassword: janet

This realm configuration would satisfy the new requirements:

<Realm className="org.apache.catalina.realm.JNDIRealm" connectionURL="ldap://localhost:389" userBase="ou=people,dc=mycompany,dc=com" userSearch="(mail={0})" userRoleName="memberOf" roleBase="ou=groups,dc=mycompany,dc=com" roleName="cn" roleSearch="(uniqueMember={0})" />

Now when Janet Jones logs in as "j.jones@mycompany.com", the realm searches the directory for a unique entry with that value as its mail attribute and attempts to bind to the directory as uid=jjones,ou=people,dc=mycompany,dc=com with the given password. If authentication succeeds, she is assigned three roles: "role2" and "role3", the values of the "memberOf" attribute in her directory entry, and "tomcat", the value of the "cn" attribute in the only group entry of which she is a member.

Finally, to authenticate the user by retrieving the password from the directory and making a local comparison in the realm, you might use a realm configuration like this:

<Realm className="org.apache.catalina.realm.JNDIRealm" connectionName="cn=Manager,dc=mycompany,dc=com" connectionPassword="secret" connectionURL="ldap://localhost:389" userPassword="userPassword" userPattern="uid={0},ou=people,dc=mycompany,dc=com" roleBase="ou=groups,dc=mycompany,dc=com" roleName="cn" roleSearch="(uniqueMember={0})" />

However, as discussed above, the default bind mode for authentication is usually to be preferred.

Additional Notes

JNDIRealm operates according to the following rules:

  • When a user attempts to access a protected resource for the first time, Tomcat will call the authenticate() method of this Realm. Thus, any changes you have made to the directory (new users, changed passwords or roles, etc.) will be immediately reflected.
  • Once a user has been authenticated, the user (and his or her associated roles) are cached within Tomcat for the duration of the user's login. (For FORM-based authentication, that means until the session times out or is invalidated; for BASIC authentication, that means until the user closes their browser). The cached user is not saved and restored across sessions serialisations. Any changes to the directory information for an already authenticated user will not be reflected until the next time that user logs on again.
  • Administering the information in the directory server is the responsibility of your own applications. Tomcat does not provide any built-in capabilities to maintain users and roles.

Introduction

UserDatabaseRealm is an implementation of the Tomcat Realm interface that uses a JNDI resource to store user information. By default, the JNDI resource is backed by an XML file. It is not designed for large-scale production use. At startup time, the UserDatabaseRealm loads information about all users, and their corresponding roles, from an XML document (by default, this document is loaded from $CATALINA_BASE/conf/tomcat-users.xml). The users, their passwords and their roles may all be editing dynamically, typically via JMX. Changes may be saved and will be reflected in the XML file.

Realm Element Attributes

To configure UserDatabaseRealm, you will create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file, as described above. The attributes for the UserDatabaseRealm are defined in the Realm configuration documentation.

User File Format

The users file uses the same format as the MemoryRealm.

Example

The default installation of Tomcat is configured with a UserDatabaseRealm nested inside the <Engine> element, so that it applies to all virtual hosts and web applications. The default contents of the conf/tomcat-users.xml file is:

<tomcat-users> <user name="tomcat" password="tomcat" roles="tomcat" /> <user name="role1" password="tomcat" roles="role1" /> <user name="both" password="tomcat" roles="tomcat,role1" /> </tomcat-users>

Additional Notes

UserDatabaseRealm operates according to the following rules:

  • When Tomcat first starts up, it loads all defined users and their associated information from the users file. Changes made to the data in this file will not be recognized until Tomcat is restarted. Changes may be made via the UserDatabase resource. Tomcat provides MBeans that may be accessed via JMX for this purpose.
  • When a user attempts to access a protected resource for the first time, Tomcat will call the authenticate() method of this Realm.
  • Once a user has been authenticated, the user (and his or her associated roles) are cached within Tomcat for the duration of the user's login. (For FORM-based authentication, that means until the session times out or is invalidated; for BASIC authentication, that means until the user closes their browser). The cached user is not saved and restored across sessions serialisations.

Introduction

MemoryRealm is a simple demonstration implementation of the Tomcat Realm interface. It is not designed for production use. At startup time, MemoryRealm loads information about all users, and their corresponding roles, from an XML document (by default, this document is loaded from $CATALINA_BASE/conf/tomcat-users.xml). Changes to the data in this file are not recognized until Tomcat is restarted.

Realm Element Attributes

To configure MemoryRealm, you will create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file, as described above. The attributes for the MemoryRealm are defined in the Realm configuration documentation.

User File Format

The users file (by default, conf/tomcat-users.xml must be an XML document, with a root element <tomcat-users>. Nested inside the root element will be a <user> element for each valid user, consisting of the following attributes:

  • name - Username this user must log on with.
  • password - Password this user must log on with (in clear text if the digest attribute was not set on the <Realm> element, or digested appropriately as described here otherwise).
  • roles - Comma-delimited list of the role names associated with this user.

Additional Notes

MemoryRealm operates according to the following rules:

  • When Tomcat first starts up, it loads all defined users and their associated information from the users file. Changes to the data in this file will not be recognized until Tomcat is restarted.
  • When a user attempts to access a protected resource for the first time, Tomcat will call the authenticate() method of this Realm.
  • Once a user has been authenticated, the user (and his or her associated roles) are cached within Tomcat for the duration of the user's login. (For FORM-based authentication, that means until the session times out or is invalidated; for BASIC authentication, that means until the user closes their browser). The cached user is not saved and restored across sessions serialisations.
  • Administering the information in the users file is the responsibility of your application. Tomcat does not provide any built-in capabilities to maintain users and roles.

Introduction

JAASRealm is an implementation of the Tomcat Realm interface that authenticates users through the Java Authentication & Authorization Service (JAAS) framework which is now provided as part of the standard Java SE API.

Using JAASRealm gives the developer the ability to combine practically any conceivable security realm with Tomcat's CMA.

JAASRealm is prototype for Tomcat of the JAAS-based J2EE authentication framework for J2EE v1.4, based on the JCP Specification Request 196 to enhance container-managed security and promote 'pluggable' authentication mechanisms whose implementations would be container-independent.

Based on the JAAS login module and principal (see javax.security.auth.spi.LoginModule and javax.security.Principal), you can develop your own security mechanism or wrap another third-party mechanism for integration with the CMA as implemented by Tomcat.

Quick Start

To set up Tomcat to use JAASRealm with your own JAAS login module, you will need to follow these steps:

  1. Write your own LoginModule, User and Role classes based on JAAS (see the JAAS Authentication Tutorial and the JAAS Login Module Developer's Guide) to be managed by the JAAS Login Context (javax.security.auth.login.LoginContext) When developing your LoginModule, note that JAASRealm's built-in CallbackHandler only recognizes the NameCallback and PasswordCallback at present.
  2. Although not specified in JAAS, you should create seperate classes to distinguish between users and roles, extending javax.security.Principal, so that Tomcat can tell which Principals returned from your login module are users and which are roles (see org.apache.catalina.realm.JAASRealm). Regardless, the first Principal returned is always treated as the user Principal.
  3. Place the compiled classes on Tomcat's classpath
  4. Set up a login.config file for Java (see JAAS LoginConfig file) and tell Tomcat where to find it by specifying its location to the JVM, for instance by setting the environment variable: JAVA_OPTS=$JAVA_OPTS -Djava.security.auth.login.config==$CATALINA_BASE/conf/jaas.config
  5. Configure your security-constraints in your web.xml for the resources you want to protect
  6. Configure the JAASRealm module in your server.xml
  7. Restart Tomcat if it is already running.

Realm Element Attributes

To configure JAASRealm as for step 6 above, you create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file within your <Engine> node. The attributes for the JAASRealm are defined in the Realm configuration documentation.

Example

Here is an example of how your server.xml snippet should look.

<Realm className="org.apache.catalina.realm.JAASRealm" appName="MyFooRealm" userClassNames="org.foobar.realm.FooUser" roleClassNames="org.foobar.realm.FooRole"/>

It is the responsibility of your login module to create and save User and Role objects representing Principals for the user (javax.security.auth.Subject). If your login module doesn't create a user object but also doesn't throw a login exception, then the Tomcat CMA will break and you will be left at the http://localhost:8080/myapp/j_security_check URI or at some other unspecified location.

The flexibility of the JAAS approach is two-fold:

  • you can carry out whatever processing you require behind the scenes in your own login module.
  • you can plug in a completely different LoginModule by changing the configuration and restarting the server, without any code changes to your application.

Additional Notes

  • When a user attempts to access a protected resource for the first time, Tomcat will call the authenticate() method of this Realm. Thus, any changes you have made in the security mechanism directly (new users, changed passwords or roles, etc.) will be immediately reflected.
  • Once a user has been authenticated, the user (and his or her associated roles) are cached within Tomcat for the duration of the user's login. For FORM-based authentication, that means until the session times out or is invalidated; for BASIC authentication, that means until the user closes their browser. Any changes to the security information for an already authenticated user will not be reflected until the next time that user logs on again.
  • As with other Realm implementations, digested passwords are supported if the <Realm> element in server.xml contains a digest attribute; JAASRealm's CallbackHandler will digest the password prior to passing it back to the LoginModule

Introduction

CombinedRealm is an implementation of the Tomcat Realm interface that authenticates users through one or more sub-Realms.

Using CombinedRealm gives the developer the ability to combine multiple Realms of the same or different types. This can be used to authenticate against different sources, provide fall back in case one Realm fails or for any other purpose that requires multiple Realms.

Sub-realms are defined by nesting Realm elements inside the Realm element that defines the CombinedRealm. Authentication will be attempted against each Realm in the order they are listed. Authentication against any Realm will be sufficient to authenticate the user.

Realm Element Attributes

To configure a CombinedRealm, you create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file within your <Engine> or <Host>. You can also nest inside a <Context> node in a context.xml file.

Example

Here is an example of how your server.xml snippet should look to use a UserDatabase Realm and a DataSource Realm.

<Realm className="org.apache.catalina.realm.CombinedRealm" > <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> <Realm className="org.apache.catalina.realm.DataSourceRealm" dataSourceName="jdbc/authority" userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles" roleNameCol="role_name"/> </Realm>

Introduction

LockOutRealm is an implementation of the Tomcat Realm interface that extends the CombinedRealm to provide lock out functionality to provide a user lock out mechanism if there are too many failed authentication attempts in a given period of time.

To ensure correct operation, there is a reasonable degree of synchronisation in this Realm.

This Realm does not require modification to the underlying Realms or the associated user storage mechanisms. It achieves this by recording all failed logins, including those for users that do not exist. To prevent a DOS by deliberating making requests with invalid users (and hence causing this cache to grow) the size of the list of users that have failed authentication is limited.

Sub-realms are defined by nesting Realm elements inside the Realm element that defines the LockOutRealm. Authentication will be attempted against each Realm in the order they are listed. Authentication against any Realm will be sufficient to authenticate the user.

Realm Element Attributes

To configure a LockOutRealm, you create a <Realm> element and nest it in your $CATALINA_BASE/conf/server.xml file within your <Engine> or <Host>. You can also nest inside a <Context> node in a context.xml file. The attributes for the LockOutRealm are defined in the Realm configuration documentation.

Example

Here is an example of how your server.xml snippet should look to add lock out functionality to a UserDatabase Realm.

<Realm className="org.apache.catalina.realm.LockOutRealm" > <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm>
tomcat7-7.0.52/webapps/docs/ssl-howto.xml0000644000175100017510000006747512271304167020243 0ustar locutuslocutus ]> &project; Christopher Cain Yoav Shapira SSL Configuration HOW-TO

The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

To install and configure SSL support on Tomcat, you need to follow these simple steps. For more information, read the rest of this HOW-TO.

  1. Create a keystore file to store the server's private key and self-signed certificate by executing the following command:

    Windows:

    %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA

    Unix:

    $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA

    and specify a password value of "changeit".


  2. Uncomment the "SSL HTTP/1.1 Connector" entry in $CATALINA_BASE/conf/server.xml and modify as described in the Configuration section below.


SSL, or Secure Socket Layer, is a technology which allows web browsers and web servers to communicate over a secured connection. This means that the data being sent is encrypted by one side, transmitted, then decrypted by the other side before processing. This is a two-way process, meaning that both the server AND the browser encrypt all traffic before sending out data.

Another important aspect of the SSL protocol is Authentication. This means that during your initial attempt to communicate with a web server over a secure connection, that server will present your web browser with a set of credentials, in the form of a "Certificate", as proof the site is who and what it claims to be. In certain cases, the server may also request a Certificate from your web browser, asking for proof that you are who you claim to be. This is known as "Client Authentication," although in practice this is used more for business-to-business (B2B) transactions than with individual users. Most SSL-enabled web servers do not request Client Authentication.

It is important to note that configuring Tomcat to take advantage of secure sockets is usually only necessary when running it as a stand-alone web server. When running Tomcat primarily as a Servlet/JSP container behind another web server, such as Apache or Microsoft IIS, it is usually necessary to configure the primary web server to handle the SSL connections from users. Typically, this server will negotiate all SSL-related functionality, then pass on any requests destined for the Tomcat container only after decrypting those requests. Likewise, Tomcat will return cleartext responses, that will be encrypted before being returned to the user's browser. In this environment, Tomcat knows that communications between the primary web server and the client are taking place over a secure connection (because your application needs to be able to ask about this), but it does not participate in the encryption or decryption itself.

In order to implement SSL, a web server must have an associated Certificate for each external interface (IP address) that accepts secure connections. The theory behind this design is that a server should provide some kind of reasonable assurance that its owner is who you think it is, particularly before receiving any sensitive information. While a broader explanation of Certificates is beyond the scope of this document, think of a Certificate as a "digital driver's license" for an Internet address. It states what company the site is associated with, along with some basic contact information about the site owner or administrator.

This "driver's license" is cryptographically signed by its owner, and is therefore extremely difficult for anyone else to forge. For sites involved in e-commerce, or any other business transaction in which authentication of identity is important, a Certificate is typically purchased from a well-known Certificate Authority (CA) such as VeriSign or Thawte. Such certificates can be electronically verified -- in effect, the Certificate Authority will vouch for the authenticity of the certificates that it grants, so you can believe that that Certificate is valid if you trust the Certificate Authority that granted it.

In many cases, however, authentication is not really a concern. An administrator may simply want to ensure that the data being transmitted and received by the server is private and cannot be snooped by anyone who may be eavesdropping on the connection. Fortunately, Java provides a relatively simple command-line tool, called keytool, which can easily create a "self-signed" Certificate. Self-signed Certificates are simply user generated Certificates which have not been officially registered with any well-known CA, and are therefore not really guaranteed to be authentic at all. Again, this may or may not even be important, depending on your needs.

The first time a user attempts to access a secured page on your site, he or she is typically presented with a dialog containing the details of the certificate (such as the company and contact name), and asked if he or she wishes to accept the Certificate as valid and continue with the transaction. Some browsers will provide an option for permanently accepting a given Certificate as valid, in which case the user will not be bothered with a prompt each time they visit your site. Other browsers do not provide this option. Once approved by the user, a Certificate will be considered valid for at least the entire browser session.

Also, while the SSL protocol was designed to be as efficient as securely possible, encryption/decryption is a computationally expensive process from a performance standpoint. It is not strictly necessary to run an entire web application over SSL, and indeed a developer can pick and choose which pages require a secure connection and which do not. For a reasonably busy site, it is customary to only run certain pages under SSL, namely those pages where sensitive information could possibly be exchanged. This would include things like login pages, personal information pages, and shopping cart checkouts, where credit card information could possibly be transmitted. Any page within an application can be requested over a secure socket by simply prefixing the address with https: instead of http:. Any pages which absolutely require a secure connection should check the protocol type associated with the page request and take the appropriate action if https is not specified.

Finally, using name-based virtual hosts on a secured connection can be problematic. This is a design limitation of the SSL protocol itself. The SSL handshake, where the client browser accepts the server certificate, must occur before the HTTP request is accessed. As a result, the request information containing the virtual host name cannot be determined prior to authentication, and it is therefore not possible to assign multiple certificates to a single IP address. If all virtual hosts on a single IP address need to authenticate against the same certificate, the addition of multiple virtual hosts should not interfere with normal SSL operations on the server. Be aware, however, that most client browsers will compare the server's domain name against the domain name listed in the certificate, if any (applicable primarily to official, CA-signed certificates). If the domain names do not match, these browsers will display a warning to the client user. In general, only address-based virtual hosts are commonly used with SSL in a production environment.

Tomcat currently operates only on JKS, PKCS11 or PKCS12 format keystores. The JKS format is Java's standard "Java KeyStore" format, and is the format created by the keytool command-line utility. This tool is included in the JDK. The PKCS12 format is an internet standard, and can be manipulated via (among other things) OpenSSL and Microsoft's Key-Manager.

Each entry in a keystore is identified by an alias string. Whilst many keystore implementations treat aliases in a case insensitive manner, case sensitive implementations are available. The PKCS11 specification, for example, requires that aliases are case sensitive. To avoid issues related to the case sensitivity of aliases, it is not recommended to use aliases that differ only in case.

To import an existing certificate into a JKS keystore, please read the documentation (in your JDK documentation package) about keytool. Note that OpenSSL often adds readable comments before the key, keytooldoes not support that, so remove the OpenSSL comments if they exist before importing the key using keytool.

To import an existing certificate signed by your own CA into a PKCS12 keystore using OpenSSL you would execute a command like: openssl pkcs12 -export -in mycert.crt -inkey mykey.key \ -out mycert.p12 -name tomcat -CAfile myCA.crt \ -caname root -chain For more advanced cases, consult the OpenSSL documentation.

To create a new keystore from scratch, containing a single self-signed Certificate, execute the following from a terminal command line:

Windows:

%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA

Unix:

$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA

(The RSA algorithm should be preferred as a secure algorithm, and this also ensures general compatibility with other servers and components.)

This command will create a new file, in the home directory of the user under which you run it, named ".keystore". To specify a different location or filename, add the -keystore parameter, followed by the complete pathname to your keystore file, to the keytool command shown above. You will also need to reflect this new location in the server.xml configuration file, as described later. For example:

Windows:

%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA \ -keystore \path\to\my\keystore

Unix:

$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA \ -keystore /path/to/my/keystore

After executing this command, you will first be prompted for the keystore password. The default password used by Tomcat is "changeit" (all lower case), although you can specify a custom password if you like. You will also need to specify the custom password in the server.xml configuration file, as described later.

Next, you will be prompted for general information about this Certificate, such as company, contact name, and so on. This information will be displayed to users who attempt to access a secure page in your application, so make sure that the information provided here matches what they will expect.

Finally, you will be prompted for the key password, which is the password specifically for this Certificate (as opposed to any other Certificates stored in the same keystore file). The keytool prompt will tell you that pressing the ENTER key automatically uses the same password for the key as the keystore. You are free to use the same password or to select a custom one. If you select a different password to the keystore password, you will also need to specify the custom password in the server.xml configuration file.

If everything was successful, you now have a keystore file with a Certificate that can be used by your server.

Tomcat can use two different implementations of SSL:

  • the JSSE implementation provided as part of the Java runtime (since 1.4)
  • the APR implementation, which uses the OpenSSL engine by default.
The exact configuration details depend on which implementation is being used. The implementation used by Tomcat is chosen automatically unless it is overriden as described below. If the installation uses APR - i.e. you have installed the Tomcat native library - then it will use the APR SSL implementation, otherwise it will use the Java JSSE implementation.

To avoid auto configuration you can define which implementation to use by specifying a classname in the protocol attribute of the Connector.
To define a Java (JSSE) connector, regardless of whether the APR library is loaded or not do: <!-- Define a blocking Java SSL Coyote HTTP/1.1 Connector on port 8443 --> <Connector protocol="org.apache.coyote.http11.Http11Protocol" port="8443" .../> <!-- Define a non-blocking Java SSL Coyote HTTP/1.1 Connector on port 8443 --> <Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="8443" .../> Alternatively, to specify an APR connector (the APR library must be available) use: <!-- Define a APR SSL Coyote HTTP/1.1 Connector on port 8443 --> <Connector protocol="org.apache.coyote.http11.Http11AprProtocol" port="8443" .../>

If you are using APR, you have the option of configuring an alternative engine to OpenSSL. <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="someengine" SSLRandomSeed="somedevice" /> The default value is <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" SSLRandomSeed="builtin" /> So to use SSL under APR, make sure the SSLEngine attribute is set to something other than off. The default value is on and if you specify another value, it has to be a valid engine name.
If you haven't compiled in SSL support into your Tomcat Native library, then you can turn this initialization off <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" /> SSLRandomSeed allows to specify a source of entropy. Productive system needs a reliable source of entropy but entropy may need a lot of time to be collected therefore test systems could use no blocking entropy sources like "/dev/urandom" that will allow quicker starts of Tomcat.

The final step is to configure the Connector in the $CATALINA_BASE/conf/server.xml file, where $CATALINA_BASE represents the base directory for the Tomcat instance. An example <Connector> element for an SSL connector is included in the default server.xml file installed with Tomcat. To configure an SSL connector that uses JSSE, you will need to remove the comments and edit it so it looks something like this:

<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 --> <Connector protocol="HTTP/1.1" port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="${user.home}/.keystore" keystorePass="changeit" clientAuth="false" sslProtocol="TLS"/>

The example above will throw an error if you have the APR and the Tomcat Native libraries in your path, as Tomcat will try to use the APR connector. The APR connector uses different attributes for many SSL settings, particularly keys and certificates. An example of an APR configuration is: <!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 --> <Connector protocol="HTTP/1.1" port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" SSLCertificateFile="/usr/local/ssl/server.crt" SSLCertificateKeyFile="/usr/local/ssl/server.pem" SSLVerifyClient="optional" SSLProtocol="TLSv1"/>

You will note that the example SSL connector elements are commented out by default. You can either remove the comment tags from around the the example SSL connector you wish to use or add a new Connector element of your own. In either case, you will need to configure the SSL Connector for your requirements and environment. The configuration options and information on which attributes are mandatory, are documented in the SSL Support section of the HTTP connector configuration reference. Make sure that you use the correct attributes for the connector you are using. The BIO and NIO connectors use JSSE whereas the APR/native connector uses APR.

The port attribute (default value is 8443) is the TCP/IP port number on which Tomcat will listen for secure connections. You can change this to any port number you wish (such as to the default port for https communications, which is 443). However, special setup (outside the scope of this document) is necessary to run Tomcat on port numbers lower than 1024 on many operating systems.

If you change the port number here, you should also change the value specified for the redirectPort attribute on the non-SSL connector. This allows Tomcat to automatically redirect users who attempt to access a page with a security constraint specifying that SSL is required, as required by the Servlet Specification.

After completing these configuration changes, you must restart Tomcat as you normally do, and you should be in business. You should be able to access any web application supported by Tomcat via SSL. For example, try:

https://localhost:8443

and you should see the usual Tomcat splash page (unless you have modified the ROOT web application). If this does not work, the following section contains some troubleshooting tips.

To obtain and install a Certificate from a Certificate Authority (like verisign.com, thawte.com or trustcenter.de), read the previous section and then follow these instructions:

In order to obtain a Certificate from the Certificate Authority of your choice you have to create a so called Certificate Signing Request (CSR). That CSR will be used by the Certificate Authority to create a Certificate that will identify your website as "secure". To create a CSR follow these steps:

  • Create a local Certificate (as described in the previous section): keytool -genkey -alias tomcat -keyalg RSA \ -keystore <your_keystore_filename> Note: In some cases you will have to enter the domain of your website (i.e. www.myside.org) in the field "first- and lastname" in order to create a working Certificate.
  • The CSR is then created with: keytool -certreq -keyalg RSA -alias tomcat -file certreq.csr \ -keystore <your_keystore_filename>

Now you have a file called certreq.csr that you can submit to the Certificate Authority (look at the documentation of the Certificate Authority website on how to do this). In return you get a Certificate.

Now that you have your Certificate you can import it into you local keystore. First of all you have to import a so called Chain Certificate or Root Certificate into your keystore. After that you can proceed with importing your Certificate.

  • Download a Chain Certificate from the Certificate Authority you obtained the Certificate from.
    For Verisign.com commercial certificates go to: http://www.verisign.com/support/install/intermediate.html
    For Verisign.com trial certificates go to: http://www.verisign.com/support/verisign-intermediate-ca/Trial_Secure_Server_Root/index.html
    For Trustcenter.de go to: http://www.trustcenter.de/certservices/cacerts/en/en.htm#server
    For Thawte.com go to: http://www.thawte.com/certs/trustmap.html
  • Import the Chain Certificate into your keystore keytool -import -alias root -keystore <your_keystore_filename> \ -trustcacerts -file <filename_of_the_chain_certificate>
  • And finally import your new Certificate keytool -import -alias tomcat -keystore <your_keystore_filename> \ -file <your_certificate_filename>

Here is a list of common problems that you may encounter when setting up SSL communications, and what to do about them.

  • When Tomcat starts up, I get an exception like "java.io.FileNotFoundException: {some-directory}/{some-file} not found".

    A likely explanation is that Tomcat cannot find the keystore file where it is looking. By default, Tomcat expects the keystore file to be named .keystore in the user home directory under which Tomcat is running (which may or may not be the same as yours :-). If the keystore file is anywhere else, you will need to add a keystoreFile attribute to the <Factory> element in the Tomcat configuration file.

  • When Tomcat starts up, I get an exception like "java.io.FileNotFoundException: Keystore was tampered with, or password was incorrect".

    Assuming that someone has not actually tampered with your keystore file, the most likely cause is that Tomcat is using a different password than the one you used when you created the keystore file. To fix this, you can either go back and recreate the keystore file, or you can add or update the keystorePass attribute on the <Connector> element in the Tomcat configuration file. REMINDER - Passwords are case sensitive!

  • When Tomcat starts up, I get an exception like "java.net.SocketException: SSL handshake errorjavax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled."

    A likely explanation is that Tomcat cannot find the alias for the server key within the specified keystore. Check that the correct keystoreFile and keyAlias are specified in the <Connector> element in the Tomcat configuration file. REMINDER - keyAlias values may be case sensitive!

If you are still having problems, a good source of information is the TOMCAT-USER mailing list. You can find pointers to archives of previous messages on this list, as well as subscription and unsubscription information, at http://tomcat.apache.org/lists.html.

This is a new feature in the Servlet 3.0 specification. Because it uses the SSL session ID associated with the physical client-server connection there are some limitations. They are:

  • Tomcat must have a connector with the attribute isSecure set to true.
  • If SSL connections are managed by a proxy or a hardware accelerator they must populate the SSL request headers (see the SSLValve) so that the SSL session ID is visible to Tomcat.
  • If Tomcat terminates the SSL connection, it will not be possible to use session replication as the SSL session IDs will be different on each node.

To enable SSL session tracking you need to use a context listener to set the tracking mode for the context to be just SSL (if any other tracking mode is enabled, it will be used in preference). It might look something like: package org.apache.tomcat.example; import java.util.EnumSet; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.SessionTrackingMode; public class SessionTrackingModeListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent event) { // Do nothing } @Override public void contextInitialized(ServletContextEvent event) { ServletContext context = event.getServletContext(); EnumSet<SessionTrackingMode> modes = EnumSet.of(SessionTrackingMode.SSL); context.setSessionTrackingModes(modes); } }

Note: SSL session tracking is implemented for the BIO and NIO connectors. It is not yet implemented for the APR connector.

To access the SSL session ID from the request, use:
String sslID = (String)request.getAttribute("javax.servlet.request.ssl_session_id");
For additional discussion on this area, please see Bugzilla.

To terminate an SSL session, use: // Standard HTTP session invalidation session.invalidate(); // Invalidate the SSL Session org.apache.tomcat.util.net.SSLSessionManager mgr = (org.apache.tomcat.util.net.SSLSessionManager) request.getAttribute("javax.servlet.request.ssl_session_mgr"); mgr.invalidateSession(); // Close the connection since the SSL session will be active until the connection // is closed response.setHeader("Connection", "close"); Note that this code is Tomcat specific due to the use of the SSLSessionManager class. This is currently only available for the BIO and NIO connectors, not the APR/native connector.

tomcat7-7.0.52/webapps/docs/comments.xml0000644000175100017510000001050312271304167020105 0ustar locutuslocutus ]> &project; Documentation User Comments

The Tomcat documentation integrates the Apache Comments System. It allows users to add comments to most documentation pages. The comments section can be found at the end of each page.

Please use the Apache Comments System responsibly. We can only provide this service to the community as long as it isn't misused.

The comments are not for general Q&A. Comments should be pointed towards suggestions on improving the documentation or server. Questions on how to use Apache Tomcat should be directed to our mailing lists.

Comments may be removed by moderators if they are either implemented or considered invalid/off-topic.

HTML is not allowed in comments, and will just display as raw source code if attempted. Links that do not point to an Apache site (*.apache.org) will need approval by a moderator before the comment is visible to regular visitors.

Any submitted comments must be contributed under the terms of the Apache License, Version 2.0.

Verified users gain the Apache feather next to their name, and may post comments with links in them without requiring approval by a moderator before the comments are shown. Being a verified user in itself does not give you moderating rights. If you are interested in becoming a verified user, please contact us on the users mailing list.

All ASF committers are automatically verified users.

Moderators are allowed to mark comments as "Resolved", "Invalid" or "Sticky", remove marks, approve comments e.g. if they contain a link, and delete comments. Moderators can also subscribe to new comments and comment updates and use the dashboard to gain some overview over all comments of a site.

To use the moderation features, you need to login to the comments system. Furthermore you will need to allow cookies to be set for comments.apache.org (this is done using a secure https cookie). Once logged in as a moderator you will see additional moderation options attached to each comment.

If you are a long time follower of the Apache Tomcat projects and you are interested in becoming a moderator, please contact us on the users mailing list.

No data except what you personally submit is kept on record. A cookie is used to keep track of moderators and other people who wish to create an account to avoid having to enter their credentials whenever they wish to post a comment.

To prevent spam and unsolicited comments, we use a digest of visitors' IPs to keep track of comments posted by them.

Entering an email address when you post a comment is completely optional, and will not be shared with anyone. If you enter an email address, it will be used to notify you when someone posts a reply to one of your comments, provided you have registered an account and validated your email address.

tomcat7-7.0.52/webapps/docs/aio.xml0000644000175100017510000003443412271304167017041 0ustar locutuslocutus ]> &project; Advanced IO and Tomcat Remy Maucherat

With usage of APR or NIO APIs as the basis of its connectors, Tomcat is able to provide a number of extensions over the regular blocking IO as provided with support for the Servlet API.

IMPORTANT NOTE: Usage of these features requires using the APR or NIO HTTP connectors. The classic java.io HTTP connector and the AJP connectors do not support them.

Comet support allows a servlet to process IO asynchronously, receiving events when data is available for reading on the connection (rather than always using a blocking read), and writing data back on connections asynchronously (most likely responding to some event raised from some other source).

Servlets which implement the org.apache.catalina.comet.CometProcessor interface will have their event method invoked rather than the usual service method, according to the event which occurred. The event object gives access to the usual request and response objects, which may be used in the usual way. The main difference is that those objects remain valid and fully functional at any time between processing of the BEGIN event until processing an END or ERROR event. The following event types exist:

  • EventType.BEGIN: will be called at the beginning of the processing of the connection. It can be used to initialize any relevant fields using the request and response objects. Between the end of the processing of this event, and the beginning of the processing of the end or error events, it is possible to use the response object to write data on the open connection. Note that the response object and dependent OutputStream and Writer are still not synchronized, so when they are accessed by multiple threads, synchronization is mandatory. After processing the initial event, the request is considered to be committed.
  • EventType.READ: This indicates that input data is available, and that one read can be made without blocking. The available and ready methods of the InputStream or Reader may be used to determine if there is a risk of blocking: the servlet should read while data is reported available. When encountering a read error, the servlet should report it by propagating the exception properly. Throwing an exception will cause the error event to be invoked, and the connection will be closed. Alternately, it is also possible to catch any exception, perform clean up on any data structure the servlet may be using, and using the close method of the event. It is not allowed to attempt reading data from the request object outside of the execution of this method.
    On some platforms, like Windows, a client disconnect is indicated by a READ event. Reading from the stream may result in -1, an IOException or an EOFException. Make sure you properly handle all these three cases. If you don't catch the IOException, Tomcat will instantly invoke your event chain with an ERROR as it catches the error for you, and you will be notified of the error at that time.
  • EventType.END: End may be called to end the processing of the request. Fields that have been initialized in the begin method should be reset. After this event has been processed, the request and response objects, as well as all their dependent objects will be recycled and used to process other requests. End will also be called when data is available and the end of file is reached on the request input (this usually indicates the client has pipelined a request).
  • EventType.ERROR: Error will be called by the container in the case where an IO exception or a similar unrecoverable error occurs on the connection. Fields that have been initialized in the begin method should be reset. After this event has been processed, the request and response objects, as well as all their dependent objects will be recycled and used to process other requests.

There are some event subtypes which allow finer processing of events (note: some of these events require usage of the org.apache.catalina.valves.CometConnectionManagerValve valve):

  • EventSubType.TIMEOUT: The connection timed out (sub type of ERROR); note that this ERROR type is not fatal, and the connection will not be closed unless the servlet uses the close method of the event.
  • EventSubType.CLIENT_DISCONNECT: The client connection was closed (sub type of ERROR).
  • EventSubType.IOEXCEPTION: An IO exception occurred, such as invalid content, for example, an invalid chunk block (sub type of ERROR).
  • EventSubType.WEBAPP_RELOAD: The web application is being reloaded (sub type of END).
  • EventSubType.SESSION_END: The servlet ended the session (sub type of END).

As described above, the typical lifecycle of a Comet request will consist in a series of events such as: BEGIN -> READ -> READ -> READ -> ERROR/TIMEOUT. At any time, the servlet may end processing of the request by using the close method of the event object.

Similar to regular filters, a filter chain is invoked when comet events are processed. These filters should implement the CometFilter interface (which works in the same way as the regular Filter interface), and should be declared and mapped in the deployment descriptor in the same way as a regular filter. The filter chain when processing an event will only include filters which match all the usual mapping rules, and also implement the CometFiler interface.

The following pseudo code servlet implements asynchronous chat functionality using the API described above:

public class ChatServlet extends HttpServlet implements CometProcessor { protected ArrayList<HttpServletResponse> connections = new ArrayList<HttpServletResponse>(); protected MessageSender messageSender = null; public void init() throws ServletException { messageSender = new MessageSender(); Thread messageSenderThread = new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]"); messageSenderThread.setDaemon(true); messageSenderThread.start(); } public void destroy() { connections.clear(); messageSender.stop(); messageSender = null; } /** * Process the given Comet event. * * @param event The Comet event that will be processed * @throws IOException * @throws ServletException */ public void event(CometEvent event) throws IOException, ServletException { HttpServletRequest request = event.getHttpServletRequest(); HttpServletResponse response = event.getHttpServletResponse(); if (event.getEventType() == CometEvent.EventType.BEGIN) { log("Begin for session: " + request.getSession(true).getId()); PrintWriter writer = response.getWriter(); writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">"); writer.println("<head><title>JSP Chat</title></head><body bgcolor=\"#FFFFFF\">"); writer.flush(); synchronized(connections) { connections.add(response); } } else if (event.getEventType() == CometEvent.EventType.ERROR) { log("Error for session: " + request.getSession(true).getId()); synchronized(connections) { connections.remove(response); } event.close(); } else if (event.getEventType() == CometEvent.EventType.END) { log("End for session: " + request.getSession(true).getId()); synchronized(connections) { connections.remove(response); } PrintWriter writer = response.getWriter(); writer.println("</body></html>"); event.close(); } else if (event.getEventType() == CometEvent.EventType.READ) { InputStream is = request.getInputStream(); byte[] buf = new byte[512]; do { int n = is.read(buf); //can throw an IOException if (n > 0) { log("Read " + n + " bytes: " + new String(buf, 0, n) + " for session: " + request.getSession(true).getId()); } else if (n < 0) { error(event, request, response); return; } } while (is.available() > 0); } } public class MessageSender implements Runnable { protected boolean running = true; protected ArrayList<String> messages = new ArrayList<String>(); public MessageSender() { } public void stop() { running = false; } /** * Add message for sending. */ public void send(String user, String message) { synchronized (messages) { messages.add("[" + user + "]: " + message); messages.notify(); } } public void run() { while (running) { if (messages.size() == 0) { try { synchronized (messages) { messages.wait(); } } catch (InterruptedException e) { // Ignore } } synchronized (connections) { String[] pendingMessages = null; synchronized (messages) { pendingMessages = messages.toArray(new String[0]); messages.clear(); } // Send any pending message on all the open connections for (int i = 0; i < connections.size(); i++) { try { PrintWriter writer = connections.get(i).getWriter(); for (int j = 0; j < pendingMessages.length; j++) { writer.println(pendingMessages[j] + "<br>"); } writer.flush(); } catch (IOException e) { log("IOExeption sending message", e); } } } } } } }

If you are using the NIO connector, you can set individual timeouts for your different comet connections. To set a timeout, simply set a request attribute like the following code shows: CometEvent event.... event.setTimeout(30*1000); or event.getHttpServletRequest().setAttribute("org.apache.tomcat.comet.timeout", new Integer(30 * 1000)); This sets the timeout to 30 seconds. Important note: in order to set this timeout, it has to be done on the BEGIN event. The default value is soTimeout

If you are using the APR connector, all Comet connections will have the same timeout value. It is soTimeout*50

When APR or NIO is enabled, Tomcat supports using sendfile to send large static files. These writes, as soon as the system load increases, will be performed asynchronously in the most efficient way. Instead of sending a large response using blocking writes, it is possible to write content to a static file, and write it using a sendfile code. A caching valve could take advantage of this to cache the response data in a file rather than store it in memory. Sendfile support is available if the request attribute org.apache.tomcat.sendfile.support is set to Boolean.TRUE.

Any servlet can instruct Tomcat to perform a sendfile call by setting the appropriate request attributes. It is also necessary to correctly set the content length for the response. When using sendfile, it is best to ensure that neither the request or response have been wrapped, since as the response body will be sent later by the connector itself, it cannot be filtered. Other than setting the 3 needed request attributes, the servlet should not send any response data, but it may use any method which will result in modifying the response header (like setting cookies).

  • org.apache.tomcat.sendfile.filename: Canonical filename of the file which will be sent as a String
  • org.apache.tomcat.sendfile.start: Start offset as a Long
  • org.apache.tomcat.sendfile.end: End offset as a Long
tomcat7-7.0.52/webapps/docs/logging.xml0000644000175100017510000006176012271304167017721 0ustar locutuslocutus ]> &project; Logging in Tomcat Allistair Crossley Yoav Shapira

Logging in Apache Tomcat is implemented with the help of Apache Commons Logging library. That library is a thin wrapper above different logging frameworks. It provides Tomcat with the ability to log hierarchically across various log levels without the need to rely on a particular logging implementation.

Since Tomcat 6.0, Tomcat uses a private package-renamed implementation of Apache Commons Logging, to allow web applications to use their own independent copies of the original Apache Commons Logging library. In the default distribution this private copy of the library is simplified and hardcoded to use the java.util.logging framework.

To configure Tomcat to use alternative logging frameworks for its internal logging, one has to replace the logging library with the one that is built with the full implementation. Such library is provided as an extras component. Instructions on how to configure Tomcat to use Log4j framework for its internal logging may be found below.

A web application running on Apache Tomcat can:

  • Use system logging API, java.util.logging.
  • Use the logging API provided by the Java Servlets specification, javax.servlet.ServletContext.log(...)
  • Use any logging framework of its choice.

The logging frameworks used by different web applications run independently of each other. See class loading for more details. The exception to this rule is java.util.logging, if it used directly or indirectly by your logging library. That is because it is loaded by the system and is shared across web applications.

Apache Tomcat has its own implementation of several key elements of java.util.logging API. This implementation is called "JULI". The key component there is a custom LogManager implementation, that is aware of different web applications running on Tomcat (and their different class loaders). It supports private per-application logging configurations. It is also notified by Tomcat when a web application is unloaded from memory, so that the references to its classes can be cleared, preventing memory leaks.

This java.util.logging implementation is enabled by providing certain system properties when starting Java. The Apache Tomcat startup scripts do this for you, but if you are using different tools to run Tomcat (such as jsvc, or running Tomcat from within an IDE), you should take care of them by yourself.

More details about java.util.logging may be found in the documentation for your JDK and on its Javadoc pages for the java.util.logging package.

More details about Tomcat JULI may be found below.

The calls to javax.servlet.ServletContext.log(...) to write log messages are handled by internal Tomcat logging. Such messages are logged to the category named

org.apache.catalina.core.ContainerBase.[${engine}].[${host}].[${context}]

This logging is performed according to the Tomcat logging configuration. You cannot overwrite it in a web application.

The Servlets logging API predates the java.util.logging API that is now provided by Java. As such, it does not offer you much options. E.g., you cannot control the log levels. It can be noted, though, that in Apache Tomcat implementation the calls to ServletContext.log(String) or GenericServlet.log(String) are logged at the INFO level. The calls to ServletContext.log(String, Throwable) or GenericServlet.log(String, Throwable) are logged at the ERROR level.

When running Tomcat on unixes, the console output is usually redirected to the file named catalina.out. The name is configurable using an environment variable. (See the startup scripts). Whatever is written to System.err/out will be caught into that file. That may include:

  • Uncaught exceptions printed by java.lang.ThreadGroup.uncaughtException(..)
  • Thread dumps, if you requested them via a system signal

When running as a service on Windows, the console output is also caught and redirected, but the file names are different.

The default logging configuration in Apache Tomcat writes the same messages to the console and to a log file. This is great when using Tomcat for development, but usually is not needed in production.

Old applications that still use System.out or System.err can be tricked by setting swallowOutput attribute on a Context. If the attribute is set to true, the calls to System.out/err during request processing will be intercepted, and their output will be fed to the logging subsystem using the javax.servlet.ServletContext.log(...) calls.
Note, that the swallowOutput feature is actually a trick, and it has its limitations. It works only with direct calls to System.out/err, and only during request processing cycle. It may not work in other threads that might be created by the application. It cannot be used to intercept logging frameworks that themselves write to the system streams, as those start early and may obtain a direct reference to the streams before the redirection takes place.

A related, but different feature is access logging. It can be configured as a valve at the Context, or Host, or Engine. See Valves documentation for more details.

The default implementation of java.util.logging provided in the JDK is too limited to be useful. A limitation of JDK Logging appears to be the inability to have per-web application logging, as the configuration is per-VM. As a result, Tomcat will, in the default configuration, replace the default LogManager implementation with a container friendly implementation called JULI, which addresses these shortcomings. It supports the same configuration mechanisms as the standard JDK java.util.logging, using either a programmatic approach, or properties files. The main difference is that per-classloader properties files can be set (which enables easy redeployment friendly webapp configuration), and the properties files support slightly extended constructs which allows more freedom for defining handlers and assigning them to loggers.

JULI is enabled by default, and supports per classloader configuration, in addition to the regular global java.util.logging configuration. This means that logging can be configured at the following layers:

  • Globally. That is usually done in the ${catalina.base}/conf/logging.properties file. The file is specified by the java.util.logging.config.file System property which is set by the startup scripts. If it is not readable or is not configured, the default is to use the ${java.home}/lib/logging.properties file in the JRE.
  • In the web application. The file will be WEB-INF/classes/logging.properties

The default logging.properties in the JRE specifies a ConsoleHandler that routes logging to System.err. The default conf/logging.properties in Apache Tomcat also adds several FileHandlers that write to files.

A handler's log level threshold is INFO by default and can be set using SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST or ALL. You can also target specific packages to collect logging from and specify a level.

Here is how you would set debugging from Tomcat. You would need to ensure the ConsoleHandler's (or FileHandler's') level is also set to collect this threshold, so FINEST or ALL should be set. Please refer to java.util.logging documentation in the JDK for the complete details:

org.apache.catalina.level=FINEST

The configuration used by JULI is extremely similar to the one supported by plain java.util.logging, but uses a few extensions to allow better flexibility in assigning loggers. The main differences are:

  • A prefix may be added to handler names, so that multiple handlers of a single class may be instantiated. A prefix is a String which starts with a digit, and ends with '.'. For example, 22foobar. is a valid prefix.
  • System property replacement is performed for property values which contain ${systemPropertyName}.
  • As in Java 6, loggers can define a list of handlers using the loggerName.handlers property.
  • By default, loggers will not delegate to their parent if they have associated handlers. This may be changed per logger using the loggerName.useParentHandlers property, which accepts a boolean value.
  • The root logger can define its set of handlers using the .handlers property.

There are several additional implementation classes, that can be used together with the ones provided by Java. The notable one is org.apache.juli.FileHandler.

org.apache.juli.FileHandler supports buffering of the logs. The buffering is not enabled by default. To configure it, use the bufferSize property of a handler. The value of 0 uses system default buffering (typically an 8K buffer will be used). A value of <0 forces a writer flush upon each log write. A value >0 uses a BufferedOutputStream with the defined value but note that the system default buffering will also be applied.

Example logging.properties file to be placed in $CATALINA_BASE/conf: handlers = 1catalina.org.apache.juli.FileHandler, \ 2localhost.org.apache.juli.FileHandler, \ 3manager.org.apache.juli.FileHandler, \ java.util.logging.ConsoleHandler .handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler ############################################################ # Handler specific properties. # Describes specific configuration info for Handlers. ############################################################ 1catalina.org.apache.juli.FileHandler.level = FINE 1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 1catalina.org.apache.juli.FileHandler.prefix = catalina. 2localhost.org.apache.juli.FileHandler.level = FINE 2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 2localhost.org.apache.juli.FileHandler.prefix = localhost. 3manager.org.apache.juli.FileHandler.level = FINE 3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 3manager.org.apache.juli.FileHandler.prefix = manager. 3manager.org.apache.juli.FileHandler.bufferSize = 16384 java.util.logging.ConsoleHandler.level = FINE java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter ############################################################ # Facility specific properties. # Provides extra control for each logger. ############################################################ org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = \ 2localhost.org.apache.juli.FileHandler org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \ 3manager.org.apache.juli.FileHandler # For example, set the org.apache.catalina.util.LifecycleBase logger to log # each component that extends LifecycleBase changing state: #org.apache.catalina.util.LifecycleBase.level = FINE

Example logging.properties for the servlet-examples web application to be placed in WEB-INF/classes inside the web application: handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler ############################################################ # Handler specific properties. # Describes specific configuration info for Handlers. ############################################################ org.apache.juli.FileHandler.level = FINE org.apache.juli.FileHandler.directory = ${catalina.base}/logs org.apache.juli.FileHandler.prefix = servlet-examples. java.util.logging.ConsoleHandler.level = FINE java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

See the following resources for additional information:

You may want to take note of the following:

  • Consider removing ConsoleHandler from configuration.

    By default (thanks to the .handlers setting) logging goes both to a FileHandler and to a ConsoleHandler. The output of the latter one is usually captured into a file, such as catalina.out. Thus you end up with two copies of the same messages.

  • Consider removing FileHandlers for the applications that you do not use. E.g., the one for host-manager.

  • The handlers by default use the system default encoding to write the log files. It can be configured with encoding property. See Javadoc for details.

  • Consider configuring an Access log.

This section explains how to configure Tomcat to use log4j rather than java.util.logging for all Tomcat's internal logging.

Note: The steps described in this section are needed when you want to reconfigure Tomcat to use Apache log4j for its own logging. These steps are not needed if you just want to use log4j in your own web application. — In that case, just put log4j.jar and log4j.properties into WEB-INF/lib and WEB-INF/classes of your web application.

The following steps describe configuring log4j to output Tomcat's internal logging.

  1. Create a file called log4j.properties with the following content and save it into $CATALINA_BASE/lib
log4j.rootLogger=INFO, CATALINA # Define all the appenders log4j.appender.CATALINA=org.apache.log4j.DailyRollingFileAppender log4j.appender.CATALINA.File=${catalina.base}/logs/catalina. log4j.appender.CATALINA.Append=true log4j.appender.CATALINA.Encoding=UTF-8 # Roll-over the log once per day log4j.appender.CATALINA.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.LOCALHOST=org.apache.log4j.DailyRollingFileAppender log4j.appender.LOCALHOST.File=${catalina.base}/logs/localhost. log4j.appender.LOCALHOST.Append=true log4j.appender.LOCALHOST.Encoding=UTF-8 log4j.appender.LOCALHOST.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayout log4j.appender.LOCALHOST.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.MANAGER=org.apache.log4j.DailyRollingFileAppender log4j.appender.MANAGER.File=${catalina.base}/logs/manager. log4j.appender.MANAGER.Append=true log4j.appender.MANAGER.Encoding=UTF-8 log4j.appender.MANAGER.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayout log4j.appender.MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.HOST-MANAGER=org.apache.log4j.DailyRollingFileAppender log4j.appender.HOST-MANAGER.File=${catalina.base}/logs/host-manager. log4j.appender.HOST-MANAGER.Append=true log4j.appender.HOST-MANAGER.Encoding=UTF-8 log4j.appender.HOST-MANAGER.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayout log4j.appender.HOST-MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Encoding=UTF-8 log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c- %m%n # Configure which loggers log to which appenders log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, LOCALHOST log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]=\ INFO, MANAGER log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]=\ INFO, HOST-MANAGER
  1. Download Log4J (v1.2 or later).
  2. Download or build tomcat-juli.jar and tomcat-juli-adapters.jar that are available as an "extras" component for Tomcat. See Additional Components documentation for details.

    This tomcat-juli.jar differs from the default one. It contains the full Apache Commons Logging implementation and thus is able to discover the presense of log4j and configure itself.

  3. If you want to configure Tomcat to use log4j globally:

    • Put log4j.jar and tomcat-juli-adapters.jar from "extras" into $CATALINA_HOME/lib.
    • Replace $CATALINA_HOME/bin/tomcat-juli.jar with tomcat-juli.jar from "extras".
  4. If you are running Tomcat with separate $CATALINA_HOME and $CATALINA_BASE and want to configure to use log4j in a single $CATALINA_BASE only:

    • Create $CATALINA_BASE/bin and $CATALINA_BASE/lib directories if they do not exist.
    • Put log4j.jar and tomcat-juli-adapters.jar from "extras" into $CATALINA_BASE/lib
    • Put tomcat-juli.jar from "extras" as $CATALINA_BASE/bin/tomcat-juli.jar
    • If you are running with a security manager, you would need to edit the $CATALINA_BASE/conf/catalina.policy file to adjust it to using a different copy of tomcat-juli.jar.
  5. Delete $CATALINA_BASE/conf/logging.properties to prevent java.util.logging generating zero length log files.

  6. Start Tomcat

This log4j configuration mirrors the default java.util.logging setup that ships with Tomcat: both the manager and host-manager apps get an individual log file, and everything else goes to the "catalina.log" log file. Each file is rolled-over once per day.

You can (and should) be more picky about which packages to include in the logging. Tomcat defines loggers by Engine and Host names. For example, for a more detailed Catalina localhost log, add this to the end of the log4j.properties above. Note that there are known issues with using this naming convention (with square brackets) in log4j XML based configuration files, so we recommend you use a properties file as described until a future version of log4j allows this convention.

log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=DEBUG
log4j.logger.org.apache.catalina.core=DEBUG
log4j.logger.org.apache.catalina.session=DEBUG

Be warned: a level of DEBUG will produce megabytes of logging and slow startup of Tomcat. This level should be used sparingly when debugging of internal Tomcat operations is required.

Your web applications should certainly use their own log4j configuration. This is valid with the above configuration. You would place a similar log4j.properties file in your web application's WEB-INF/classes directory, and log4jx.y.z.jar into WEB-INF/lib. Then specify your package level logging. This is a basic setup of log4j which does *not* require Commons-Logging, and you should consult the log4j documentation for more options. This page is intended only as a bootstrapping guide.

Additional notes

  • This exposes log4j libraries to the web applications through the Common classloader. See class loading documentation for details.

    Because of that, the web applications and libraries using Apache Commons Logging library are likely to automatically choose log4j as the underlying logging implementation.

  • The java.util.logging API is still available, for those web applications that use it directly. The ${catalina.base}/conf/logging.properties file is still referenced by Tomcat startup scripts.

    Removal of ${catalina.base}/conf/logging.properties file, mentioned as one of the steps, just causes java.util.logging to fallback to the default configuration as configured in JRE, which is to use a ConsoleHandler and do not create any files.

tomcat7-7.0.52/webapps/docs/tomcat-docs.xsl0000644000175100017510000006025112271304167020510 0ustar locutuslocutus /comments.html <xsl:value-of select="project/title"/> (<xsl:value-of select="$version"/>) - <xsl:value-of select="properties/title"/> PAGE HEADER
PROJECT LOGO {$alt}

Version ,
APACHE LOGO Apache Logo
HEADER SEPARATORLEFT SIDE NAVIGATIONRIGHT SIDE MAIN BODY FOOTER SEPARATORPAGE FOOTER

Comments

Notice: This comments section collects your suggestions on improving documentation for Apache Tomcat.

If you have trouble and need help, read Find Help page and ask your question on the tomcat-users mailing list. Do not ask such questions here. This is not a Q&A section.

The Apache Comments System is explained here. Comments may be removed by our moderators if they are either implemented or considered invalid/off-topic.


Copyright © 1999-, Apache Software Foundation

  • ()
    2
    ()
  •             
              

    Attribute Description
    Property Description
    /images/add.gif add /images/update.gif update /images/design.gif design /images/docs.gif docs /images/fix.gif fix /images/code.gif code
    Priority Action Item Volunteers
    r
    tomcat7-7.0.52/webapps/docs/windows-auth-howto.xml0000644000175100017510000003444112246214221022047 0ustar locutuslocutus ]> &project; Windows Authentication How-To

    Integrated Windows authentication is most frequently used within intranet environments since it requires that the server performing the authentication and the user being authenticated are part of the same domain. For the user to be authenticated automatically, the client machine used by the user must also be part of the domain.

    There are several options for implementing integrated Windows authentication with Apache Tomcat. They are:

    • Built-in Tomcat support.
    • Use a third party library such as Waffle.
    • Use a reverse proxy that supports Windows authentication to perform the authentication step such as IIS or httpd.
    The configuration of each of these options is discussed in the following sections.

    Kerberos (the basis for integrated Windows authentication) requires careful configuration. If the steps in this guide are followed exactly, then a working configuration will result. There may be some flexibility in some of the steps below but further testing is required to explore this. From the testing to date it is known that:

    • The host name of the Tomcat server must match the host name in the SPN exactly else authentication will fail. A checksum error may be reported in the debug logs in this case.
    • The client must be of the view that the server is part of the local trusted intranet.

    The areas where further testing is required include:

    • Does the domain name have to be in upper case?
    • Does the SPN have to start with HTTP/...?
    • Can a port number be appended to the end of the host in the SPN?
    • Can the domain be left off the user in the ktpass command?
    • What are the limitations on the account that Tomcat can run as? SPN associated account works, domain admin works, local admin doesn't work

    There are four components to the configuration of the built-in Tomcat support for Windows authentication. The domain controller, the server hosting Tomcat, the web application wishing to use Windows authentication and the client machine. The following sections describe the configuration required for each component.

    The names of the three machines used in the configuration examples below are win-dc01.dev.local (the domain controller), win-tc01.dev.local (the Tomcat instance) and win-pc01.dev.local (client). All are members of the DEV.LOCAL domain.

    Note: In order to use the passwords in the steps below, the domain password policy had to be relaxed. This is not recommended for production environments.

    These steps assume that the server has already been configured to act as a domain controller. Configuration of a Windows server as a domain controller is outside the scope of this how-to. The steps to configure the domain controller to enable Tomcat to support Windows authentication are as follows:

    • Create a domain user that will be mapped to the service name used by the Tomcat server. In this how-to, this user is called tc01 and has a password of tc01pass.
    • Map the service principal name (SPN) to the user account. SPNs take the form <service class>/<host>:<port>/<service name>. The SPN used in this how-to is HTTP/win-tc01.dev.local. To map the user to the SPN, run the following: setspn -A HTTP/win-tc01.dev.local tc01
    • Generate the keytab file that the Tomcat server will use to authenticate itself to the domain controller. This file contains the Tomcat private key for the service provider account and should be protected accordingly. To generate the file, run the following command (all on a single line): ktpass /out c:\tomcat.keytab /mapuser tc01@DEV.LOCAL /princ HTTP/win-tc01.dev.local@DEV.LOCAL /pass tc01pass /kvno 0
    • Create a domain user to be used on the client. In this how-to the domain user is test with a password of testpass.

    The above steps have been tested on a domain controller running Windows Server 2008 R2 64-bit Standard using the Windows Server 2003 functional level for both the forest and the domain.

    These steps assume that Tomcat and a Java 6 JDK/JRE have already been installed and configured and that Tomcat is running as the tc01@DEV.LOCAL user. The steps to configure the Tomcat instance for Windows authentication are as follows:

    • Copy the tomcat.keytab file created on the domain controller to $CATALINA_BASE/conf/tomcat.keytab.
    • Create the kerberos configuration file $CATALINA_BASE/conf/krb5.ini. The file used in this how-to contained:[libdefaults] default_realm = DEV.LOCAL default_keytab_name = FILE:c:\apache-tomcat-7.0.x\conf\tomcat.keytab default_tkt_enctypes = rc4-hmac,aes256-cts-hmac-sha1-96,aes128-cts-hmac-sha1-96 default_tgs_enctypes = rc4-hmac,aes256-cts-hmac-sha1-96,aes128-cts-hmac-sha1-96 forwardable=true [realms] DEV.LOCAL = { kdc = win-dc01.dev.local:88 } [domain_realm] dev.local= DEV.LOCAL .dev.local= DEV.LOCAL The location of this file can be changed by setting the java.security.krb5.conf systm property.
    • Create the JAAS login configuration file $CATALINA_BASE/conf/jaas.conf. The file used in this how-to contained:com.sun.security.jgss.krb5.initiate { com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=true principal="HTTP/win-tc01.dev.local@DEV.LOCAL" useKeyTab=true keyTab="c:/apache-tomcat-7.0.x/conf/tomcat.keytab" storeKey=true; }; com.sun.security.jgss.krb5.accept { com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=true principal="HTTP/win-tc01.dev.local@DEV.LOCAL" useKeyTab=true keyTab="c:/apache-tomcat-7.0.x/conf/tomcat.keytab" storeKey=true; }; The location of this file can be changed by setting the java.security.auth.login.config system property. The LoginModule used is a JVM specific one so ensure that the LoginModule specified matches the JVM being used. The name of the login configuration must match the value used by the authentication valve.
    • The system property javax.security.auth.useSubjectCredsOnly is automatically set to the required value of false if a web application is configured to use the SPNEGO authentication method.

    The SPNEGO authenticator will work with any Realm but if used with the JNDI Realm, by default the JNDI Realm will use the user's delegated credentials to connect to the Active Directory.

    The above steps have been tested on a Tomcat server running Windows Server 2008 R2 64-bit Standard with an Oracle 1.6.0_24 64-bit JDK.

    This was tested with:

    • Java 1.7.0, update 45, 64-bit
    • Ubuntu Server 12.04.3 LTS 64-bit
    • Tomcat 8.0.x (r1546570)

    It should work with any Tomcat 7 release from 7.0.12 onwards although it is recommended that the latest stable release is used.

    The configuration is the same as for Windows but with the following changes:

    • The Linux server does not have to be part of the Windows domain.
    • The path to the keytab file in krb5.ini and jass.conf should be updated to reflect the path to the keytab file on the Linux server using Linux style file paths (e.g. /usr/local/tomcat/...).

    The web application needs to be configured to the use Tomcat specific authentication method of SPNEGO (rather than BASIC etc.) in web.xml. As with the other authenticators, behaviour can be customised by explicitly configuring the authentication valve and setting attributes on the Valve.

    The client must be configured to use Kerberos authentication. For Internet Explorer this means making sure that the Tomcat instance is in the "Local intranet" security domain and that it is configured (Tools > Internet Options > Advanced) with integrated Windows authentication enabled. Note that this will not work if you use the same machine for the client and the Tomcat instance as Internet Explorer will use the unsupported NTLM protocol.

    Correctly configuring Kerberos authentication can be tricky. The following references may prove helpful. Advice is also always available from the Tomcat users mailing list.

    1. IIS and Kerberos
    2. SPNEGO project at SourceForge
    3. Oracle JGSS tutorial
    4. Geronimo configuration for Windows authentication
    5. Encryption Selection in Kerberos Exchanges
    6. Supported Kerberos Cipher Suites

    Full details of this solution can be found through the Waffle web site. The key features are:

    • Drop-in solution
    • Simple configuration (no JAAS or Kerberos keytab configuration required)
    • Uses a native library

    Full details of this solution can be found through the Kerberos extension web site. The key features are:

    • Extension to Spring Security
    • Requires a Kerberos keytab file to be generated
    • Pure Java solution

    Full details of this solution can be found through the project site. The key features are:

    • Uses Kerberos
    • Pure Java solution

    Full details of this solution can be found through the project web siteThe key features are:

    • Pure Java solution
    • Advanced Active Directory integration

    There are three steps to configuring IIS to provide Windows authentication. They are:

    1. Configure IIS as a reverse proxy for Tomcat (see the IIS Web Server How-To).
    2. Configure IIS to use Windows authentication
    3. Configure Tomcat to use the authentication user information from IIS by setting the tomcatAuthentication attribute on the AJP connector to false.

    Apache httpd does not support Windows authentication out of the box but there are a number of third-party modules that can be used. These include:

    1. mod_auth_sspi for use on Windows platforms.
    2. mod_auth_ntlm_winbind for non-Windows platforms. Known to work with httpd 2.0.x on 32-bit platforms. Some users have reported stability issues with both httpd 2.2.x builds and 64-bit Linux builds.

    There are three steps to configuring httpd to provide Windows authentication. They are:

    1. Configure httpd as a reverse proxy for Tomcat (see the Apache httpd Web Server How-To).
    2. Configure httpd to use Windows authentication
    3. Configure Tomcat to use the authentication user information from httpd by setting the tomcatAuthentication attribute on the AJP connector to false.
    tomcat7-7.0.52/webapps/docs/web-socket-howto.xml0000644000175100017510000001764012250701331021461 0ustar locutuslocutus ]> &project; WebSocket How-To

    Tomcat provides support for WebSocket as defined by RFC 6455.

    Tomcat implements the Java WebSocket 1.0 API defined by JSR-356.

    There are several example applications that demonstrate how the WebSocket API can be used. You will need to look at both the client side HTML and the server side code.

    The JSR-356 Java WebSocket 1.0 implementation is only available when Tomcat is running on Java 7 or later.

    Tomcat provides a number of Tomcat specific configuration options for WebSocket. It is anticipated that these will be absorbed into the WebSocket specification over time.

    The write timeout used when sending WebSocket messages in blocking mode defaults to 20000 milliseconds (20 seconds). This may be changed by setting the property org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT in the user properties collection attached to the WebSocket session. The value assigned to this property should be a Long and represents the timeout to use in milliseconds. For an infinite timeout, use -1.

    If the application does not define a MessageHandler.Partial for incoming binary messages, any incoming binary messages must be buffered so the entire message can be delivered in a single call to the registered MessageHandler.Whole for binary messages. The default buffer size for binary messages is 8192 bytes. This may be changed for a web application by setting the servlet context initialization parameter org.apache.tomcat.websocket.binaryBufferSize to the desired value in bytes.

    If the application does not define a MessageHandler.Partial for incoming text messages, any incoming text messages must be buffered so the entire message can be delivered in a single call to the registered MessageHandler.Whole for text messages. The default buffer size for text messages is 8192 bytes. This may be changed for a web application by setting the servlet context initialization parameter org.apache.tomcat.websocket.textBufferSize to the desired value in bytes.

    The Java WebSocket specification 1.0 does not permit programmatic deployment after the first endpoint has started a WebSocket handshake. By default, Tomcat continues to permit additional programmatic deployment. This behavior is controlled by the org.apache.tomcat.websocket.noAddAfterHandshake servlet context initialization parameter. The default may be changed by setting the org.apache.tomcat.websocket.STRICT_SPEC_COMPLIANCE system property to true but any explicit setting on the servlet context will always take priority.

    The Java WebSocket 1.0 specification requires that callbacks for asynchronous writes are performed on a different thread to the thread that initiated the write. Since the container thread pool is not exposed via the Servlet API, the WebSocket implementation has to provide its own thread pool. This thread pool is controlled by the following servlet context initialization parameters:

    • org.apache.tomcat.websocket.executorCoreSize: The core size of the executor thread pool. If not set, the default of 0 (zero) is used.
    • org.apache.tomcat.websocket.executorMaxSize: The maximum permitted size of the executor thread pool. If not set, the default of 10 is used.
    • org.apache.tomcat.websocket.executorKeepAliveTimeSeconds: The maximum time an idle thread will remain in the executor thread pool until it is terminated. If not specified, the default of 60 seconds is used.

    When using the WebSocket client to connect to server endpoints, the timeout for IO operations while establishing the connection is controlled by the userProperties of the provided javax.websocket.ClientEndpointConfig. The property is org.apache.tomcat.websocket.IO_TIMEOUT_MS and is the timeout as a String in milliseconds. The default is 5000 (5 seconds).

    When using the WebSocket client to connect to secure server endpoints, the client SSL configuration is controlled by the userProperties of the provided javax.websocket.ClientEndpointConfig. The following user properties are supported:

    • org.apache.tomcat.websocket.SSL_CONTEXT
    • org.apache.tomcat.websocket.SSL_PROTOCOLS
    • org.apache.tomcat.websocket.SSL_TRUSTSTORE
    • org.apache.tomcat.websocket.SSL_TRUSTSTORE_PWD

    The default truststore password is changeit.

    If the org.apache.tomcat.websocket.SSL_CONTEXT property is set then the org.apache.tomcat.websocket.SSL_TRUSTSTORE and org.apache.tomcat.websocket.SSL_TRUSTSTORE_PWD properties will be ignored.

    Prior to the development of JRS-356, Tomcat provided a proprietary WebSocket API. This API has been deprecated in Tomcat 7 and will be removed in Tomcat 8. There is unlikely to be any further development of this proprietary API apart from bug fixes.

    For information on this API, please see the Javadoc for the org.apache.catalina.websocket package. The Javadoc pages are not included with Tomcat binary distributions. To view them locally you would have to download and install "Full documentation" distribution, or build it from sources. You can also read this on the Apache Tomcat web site. Start with the WebSocketServlet class.

    There are also several example applications that demonstrate how the WebSocket API can be used. You'll need to look at both the client side HTML and the server side code.

    tomcat7-7.0.52/webapps/docs/extras.xml0000644000175100017510000000772212271304167017577 0ustar locutuslocutus ]> &project; Additional Components Remy Maucherat

    A number of additional components may be used with Apache Tomcat. These components may be built by users should they need them or they can be downloaded from one of the mirrors.

    To download the extras components open the Tomcat download page and select "Browse" from the Quick Navigation Links. The extras components can be found in bin/extras.

    The additional components are built using the extras target of the standard Tomcat Ant script which is present in the source bundle of Tomcat.

    The build process is the following:

    • Follow the build instructions to build a Tomcat binary from the source bundle (note: it will be used by the build process of the additional components, but does not need to be actually used later on)
    • Execute the command ant extras to run the build script
    • The additional components JARs will be placed in the output/extras folder
    • Refer to the documentation below about the usage of these JARs

    Tomcat uses a package renamed commons-logging API implementation which is hardcoded to use the java.util.logging API. The commons-logging additional component builds a full fledged package renamed commons-logging implementation which can be used to replace the implementation provided with Tomcat. See the logging page for usage instructions.

    Tomcat provides factories for JSR 109 which may be used to resolve web services references. Place the generated catalina-ws.jar as well as jaxrpc.jar and wsdl4j.jar (or another implementation of JSR 109) in the Tomcat lib folder.

    Users should be aware that wsdl4j.jar is licensed under CPL 1.0 and not the Apache License version 2.0.

    The JMX protocol requires the JMX server (Tomcat in this instance) to listen on two network ports. One of these ports can be fixed via configuration but the second is selected randomly. This makes it difficult to use JMX through a firewall. The JMX Remote Lifecycle Listener allows both ports to be fixed, simplifying the process of connecting to JMX through a firewall. See the listeners page for usage instructions.

    tomcat7-7.0.52/webapps/docs/connectors.xml0000644000175100017510000000557512271304167020452 0ustar locutuslocutus ]> &project; Remy Maucherat Connectors How To

    Choosing a connector to use with Tomcat can be difficult. This page will list the connectors which are supported with this Tomcat release, and will hopefully help you make the right choice according to your needs.

    The HTTP connector is setup by default with Tomcat, and is ready to use. This connector features the lowest latency and best overall performance.

    For clustering, a HTTP load balancer with support for web sessions stickiness must be installed to direct the traffic to the Tomcat servers. Tomcat supports mod_proxy (on Apache HTTP Server 2.x, and included by default in Apache HTTP Server 2.2) as the load balancer. It should be noted that the performance of HTTP proxying is usually lower than the performance of AJP, so AJP clustering is often preferable.

    When using a single server, the performance when using a native webserver in front of the Tomcat instance is most of the time significantly worse than a standalone Tomcat with its default HTTP connector, even if a large part of the web application is made of static files. If integration with the native webserver is needed for any reason, an AJP connector will provide faster performance than proxied HTTP. AJP clustering is the most efficient from the Tomcat perspective. It is otherwise functionally equivalent to HTTP clustering.

    The native connectors supported with this Tomcat release are:

    • JK 1.2.x with any of the supported servers
    • mod_proxy on Apache HTTP Server 2.x (included by default in Apache HTTP Server 2.2), with AJP enabled

    Other native connectors supporting AJP may work, but are no longer supported.

    tomcat7-7.0.52/webapps/docs/jspapi/0000755000175100017510000000000012301126373017020 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/jspapi/index.html0000644000175100017510000000242711656646736021050 0ustar locutuslocutus API docs The JSP Javadoc is not installed by default. Download and install the "fulldocs" package to get it. You can also access the javadoc online in the Tomcat documentation bundle. tomcat7-7.0.52/webapps/docs/ssi-howto.xml0000644000175100017510000002631412271304167020223 0ustar locutuslocutus ]> &project; Glenn L. Nielsen SSI How To

    SSI (Server Side Includes) are directives that are placed in HTML pages, and evaluated on the server while the pages are being served. They let you add dynamically generated content to an existing HTML page, without having to serve the entire page via a CGI program, or other dynamic technology.

    Within Tomcat SSI support can be added when using Tomcat as your HTTP server and you require SSI support. Typically this is done during development when you don't want to run a web server like Apache.

    Tomcat SSI support implements the same SSI directives as Apache. See the Apache Introduction to SSI for information on using SSI directives.

    SSI support is available as a servlet and as a filter. You should use one or the other to provide SSI support but not both.

    Servlet based SSI support is implemented using the class org.apache.catalina.ssi.SSIServlet. Traditionally, this servlet is mapped to the URL pattern "*.shtml".

    Filter based SSI support is implemented using the class org.apache.catalina.ssi.SSIFilter. Traditionally, this filter is mapped to the URL pattern "*.shtml", though it can be mapped to "*" as it will selectively enable/disable SSI processing based on mime types. The contentType init param allows you to apply SSI processing to JSP pages, javascript, or any other content you wish.

    By default SSI support is disabled in Tomcat.

    CAUTION - SSI directives can be used to execute programs external to the Tomcat JVM. If you are using the Java SecurityManager this will bypass your security policy configuration in catalina.policy.

    To use the SSI servlet, remove the XML comments from around the SSI servlet and servlet-mapping configuration in $CATALINA_BASE/conf/web.xml.

    To use the SSI filter, remove the XML comments from around the SSI filter and filter-mapping configuration in $CATALINA_BASE/conf/web.xml.

    Only Contexts which are marked as privileged may use SSI features (see the privileged property of the Context element).

    There are several servlet init parameters which can be used to configure the behaviour of the SSI servlet.

    • buffered - Should output from this servlet be buffered? (0=false, 1=true) Default 0 (false).
    • debug - Debugging detail level for messages logged by this servlet. Default 0.
    • expires - The number of seconds before a page with SSI directives will expire. Default behaviour is for all SSI directives to be evaluated for every request.
    • isVirtualWebappRelative - Should "virtual" SSI directive paths be interpreted as relative to the context root, instead of the server root? Default false.
    • inputEncoding - The encoding to be assumed for SSI resources if one cannot be determined from the resource itself. Default is the default platform encoding.
    • outputEncoding - The encoding to be used for the result of the SSI processing. Default is UTF-8.
    • allowExec - Is the exec command enabled? Default is false.

    There are several filter init parameters which can be used to configure the behaviour of the SSI filter.

    • contentType - A regex pattern that must be matched before SSI processing is applied. When crafting your own pattern, don't forget that a mime content type may be followed by an optional character set in the form "mime/type; charset=set" that you must take into account. Default is "text/x-server-parsed-html(;.*)?".
    • debug - Debugging detail level for messages logged by this servlet. Default 0.
    • expires - The number of seconds before a page with SSI directives will expire. Default behaviour is for all SSI directives to be evaluated for every request.
    • isVirtualWebappRelative - Should "virtual" SSI directive paths be interpreted as relative to the context root, instead of the server root? Default false.
    • allowExec - Is the exec command enabled? Default is false.

    Server Side Includes are invoked by embedding SSI directives in an HTML document whose type will be processed by the SSI servlet. The directives take the form of an HTML comment. The directive is replaced by the results of interpreting it before sending the page to the client. The general form of a directive is:

    <!--#directive [parm=value] -->

    The directives are:

    • config - <!--#config timefmt="%B %Y" --> Used to set the format of dates and other items processed by SSI
    • echo - <!--#echo var="VARIABLE_NAME" --> will be replaced by the value of the variable.
    • exec - Used to run commands on the host system.
    • include - <!--#include virtual="file-name" --> inserts the contents
    • flastmod - <!--#flastmod file="filename.shtml" --> Returns the time that a file was lost modified.
    • fsize - <!--#fsize file="filename.shtml" --> Returns the size of a file.
    • printenv - <!--#printenv --> Returns the list of all the defined variables.
    • set - <!--#set var="foo" value="Bar" --> is used to assign a value to a user-defind variable.
    • if elif endif else - Used to create conditional sections. For example:
    • <!--#config timefmt="%A" -->
      <!--#if expr="$DATE_LOCAL = /Monday/" -->
      <p>Meeting at 10:00 on Mondays</p>
      <!--#elif expr="$DATE_LOCAL = /Friday/" -->
      <p>Turn in your time card</p>
      <!--#else -->
      <p>Yoga class at noon.</p>
      <!--#endif -->

    See the

    Apache Introduction to SSI for more information on using SSI directives.

    The SSI servlet currently implements the following variables:

    Variable Name Description
    AUTH_TYPE The type of authentication used for this user: BASIC, FORM, etc.
    CONTENT_LENGTH The length of the data (in bytes or the number of characters) passed from a form.
    CONTENT_TYPE The MIME type of the query data, such as "text/html".
    DATE_GMT Current date and time in GMT
    DATE_LOCAL Current date and time in the local time zone
    DOCUMENT_NAME The current file
    DOCUMENT_URI Virtual path to the file
    GATEWAY_INTERFACE The revision of the Common Gateway Interface that the server uses if enabled: "CGI/1.1".
    HTTP_ACCEPT A list of the MIME types that the client can accept.
    HTTP_ACCEPT_ENCODING A list of the compression types that the client can accept.
    HTTP_ACCEPT_LANGUAGE A list of the languages that the client can accept.
    HTTP_CONNECTION The way that the connection from the client is being managed: "Close" or "Keep-Alive".
    HTTP_HOST The web site that the client requested.
    HTTP_REFERER The URL of the document that the client linked from.
    HTTP_USER_AGENT The browser the client is using to issue the request.
    LAST_MODIFIED Last modification date and time for current file
    PATH_INFO Extra path information passed to a servlet.
    PATH_TRANSLATED The translated version of the path given by the variable PATH_INFO.
    QUERY_STRING The query string that follows the "?" in the URL.
    QUERY_STRING_UNESCAPED Undecoded query string with all shell metacharacters escaped with "\"
    REMOTE_ADDR The remote IP address of the user making the request.
    REMOTE_HOST The remote hostname of the user making the request.
    REMOTE_PORT The port number at remote IP address of the user making the request.
    REMOTE_USER The authenticated name of the user.
    REQUEST_METHOD The method with which the information request was issued: "GET", "POST" etc.
    REQUEST_URI The web page originally requested by the client.
    SCRIPT_FILENAME The location of the current web page on the server.
    SCRIPT_NAME The name of the web page.
    SERVER_ADDR The server's IP address.
    SERVER_NAME The server's hostname or IP address.
    SERVER_PORT The port on which the server received the request.
    SERVER_PROTOCOL The protocol used by the server. E.g. "HTTP/1.1".
    SERVER_SOFTWARE The name and version of the server software that is answering the client request.
    UNIQUE_ID A token used to identify the current session if one has been established.
    tomcat7-7.0.52/webapps/docs/monitoring.xml0000644000175100017510000007601112271304167020453 0ustar locutuslocutus ]> &project; Monitoring and Managing Tomcat

    Monitoring is a key aspect of system administration. Looking inside a running server, obtaining some statistics or reconfiguring some aspects of an application are all daily administration tasks.

    Note: This configuration is needed only if you are going to monitor Tomcat remotely. It is not needed if you are going to monitor it locally, using the same user that Tomcat runs with.

    The Oracle website includes the list of options and how to configure JMX Remote on Java 6: http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html.

    The following is a quick configuration guide for Java 6:

    Add the following parameters to setenv.bat script of your Tomcat (see RUNNING.txt for details).
    Note: This syntax is for Microsoft Windows. The command has to be on the same line. It is wrapped to be more readable. If Tomcat is running as a Windows service, use its configuration dialog to set java options for the service. For un*xes remove "set " from beginning of the line.

    set CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=%my.jmx.port% -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
    1. If you require authorization, add and change this: -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access
    2. edit the access authorization file $CATALINA_BASE/conf/jmxremote.access: monitorRole readonly controlRole readwrite
    3. edit the password file $CATALINA_BASE/conf/jmxremote.password: monitorRole tomcat controlRole tomcat Tip: The password file should be read-only and only accessible by the operating system user Tomcat is running as.

    Note: The JSR 160 JMX-Adaptor opens a second data channel on a random port. That is a problem when you have a local firewall installed. To fix it, configure a JmxRemoteLifecycleListener, as described in listeners documentation.

    To simplify JMX usage with Ant 1.6.x, a set of tasks is provided that may be used with antlib.

    antlib: Copy your catalina-ant.jar from $CATALINA_HOME/lib to $ANT_HOME/lib.

    The following example shows the JMX Accessor usage:
    Note: The name attribute value was wrapped here to be more readable. It has to be all on the same line, without spaces.

    <project name="Catalina Ant JMX"
          xmlns:jmx="antlib:org.apache.catalina.ant.jmx"
          default="state"
          basedir=".">
      <property name="jmx.server.name" value="localhost" />
      <property name="jmx.server.port" value="9012" />
      <property name="cluster.server.address" value="192.168.1.75" />
      <property name="cluster.server.port" value="9025" />
    
      <target name="state" description="Show JMX Cluster state">
        <jmx:open
          host="${jmx.server.name}"
          port="${jmx.server.port}"
          username="controlRole"
          password="tomcat"/>
        <jmx:get
          name=
    "Catalina:type=IDataSender,host=localhost,
    senderAddress=${cluster.server.address},senderPort=${cluster.server.port}"
          attribute="connected"
          resultproperty="IDataSender.backup.connected"
          echo="false"
        />
        <jmx:get
          name="Catalina:type=ClusterSender,host=localhost"
          attribute="senderObjectNames"
          resultproperty="senderObjectNames"
          echo="false"
        />
        <!-- get current maxActiveSession from ClusterTest application
           echo it to Ant output and store at
           property <em>clustertest.maxActiveSessions.orginal</em>
        -->
        <jmx:get
          name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
          attribute="maxActiveSessions"
          resultproperty="clustertest.maxActiveSessions.orginal"
          echo="true"
        />
        <!-- set maxActiveSession to 100
        -->
        <jmx:set
          name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
          attribute="maxActiveSessions"
          value="100"
          type="int"
        />
        <!-- get all sessions and split result as delimiter <em>SPACE</em> for easy
           access all session ids directly with Ant property sessions.[0..n].
        -->
        <jmx:invoke
          name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
          operation="listSessionIds"
          resultproperty="sessions"
          echo="false"
          delimiter=" "
        />
        <!-- Access session attribute <em>Hello</em> from first session.
        -->
        <jmx:invoke
          name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
          operation="getSessionAttribute"
          resultproperty="Hello"
          echo="false"
        >
          <arg value="${sessions.0}"/>
          <arg value="Hello"/>
        </jmx:invoke>
        <!-- Query for all application manager.of the server from all hosts
           and bind all attributes from all found manager MBeans.
        -->
        <jmx:query
          name="Catalina:type=Manager,*"
          resultproperty="manager"
          echo="true"
          attributebinding="true"
        />
        <!-- echo the create properties -->
    <echo>
    senderObjectNames: ${senderObjectNames.0}
    IDataSender.backup.connected: ${IDataSender.backup.connected}
    session: ${sessions.0}
    manager.length: ${manager.length}
    manager.0.name: ${manager.0.name}
    manager.1.name: ${manager.1.name}
    hello: ${Hello}
    manager.ClusterTest.0.name: ${manager.ClusterTest.0.name}
    manager.ClusterTest.0.activeSessions: ${manager.ClusterTest.0.activeSessions}
    manager.ClusterTest.0.counterSend_EVT_SESSION_EXPIRED:
     ${manager.ClusterTest.0.counterSend_EVT_SESSION_EXPIRED}
    manager.ClusterTest.0.counterSend_EVT_GET_ALL_SESSIONS:
     ${manager.ClusterTest.0.counterSend_EVT_GET_ALL_SESSIONS}
    </echo>
    
      </target>
    
    </project>
    

    import: Import the JMX Accessor Project with <import file="${CATALINA.HOME}/bin/catalina-tasks.xml" /> and reference the tasks with jmxOpen, jmxSet, jmxGet, jmxQuery, jmxInvoke, jmxEquals and jmxCondition.

    List of Attributes
    Attribute Description Default value
    url Set JMX connection URL - service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi
    host Set the host, shortcut the very long URL syntax. localhost
    port Set the remote connection port 8050
    username remote JMX connection user name.
    password remote JMX connection password.
    ref Name of the internal connection reference. With this attribute you can configure more the one connection inside the same Ant project. jmx.server
    echo Echo the command usage (for access analysis or debugging) false
    if Only execute if a property of the given name exists in the current project.
    unless Only execute if a property of the given name not exists in the current project.

    Example to open a new JMX connection
    <jmx:open host="${jmx.server.name}" port="${jmx.server.port}" />

    Example to open a JMX connection from URL, with authorization and store at other reference
    <jmx:open url="service:jmx:rmi:///jndi/rmi://localhost:9024/jmxrmi" ref="jmx.server.9024" username="controlRole" password="tomcat" />

    Example to open a JMX connection from URL, with authorization and store at other reference, but only when property jmx.if exists and jmx.unless not exists
    <jmx:open url="service:jmx:rmi:///jndi/rmi://localhost:9024/jmxrmi" ref="jmx.server.9024" username="controlRole" password="tomcat" if="jmx.if" unless="jmx.unless" />

    Note: All properties from jmxOpen task also exists at all other tasks and conditions.

    List of Attributes
    Attribute Description Default value
    name Full qualified JMX ObjectName -- Catalina:type=Server
    attribute Existing MBean attribute (see Tomcat MBean description above)
    ref JMX Connection reference jmx.server
    echo Echo command usage (access and result) false
    resultproperty Save result at this project property
    delimiter Split result with delimiter (java.util.StringTokenizier) and use resultproperty as prefix to store tokens.
    separatearrayresults When return value is an array, save result as property list ($resultproperty.[0..N] and $resultproperty.length) true

    Example to get remote MBean attribute from default JMX connection
    <jmx:get name="Catalina:type=Manager,context=/servlets-examples,host=localhost" attribute="maxActiveSessions" resultproperty="servlets-examples.maxActiveSessions" />

    Example to get and result array and split it at separate properties
    <jmx:get name="Catalina:type=ClusterSender,host=localhost" attribute="senderObjectNames" resultproperty="senderObjectNames" /> Access the senderObjectNames properties with: ${senderObjectNames.length} give the number of returned sender list. ${senderObjectNames.[0..N]} found all sender object names

    Example to get IDataSender attribute connected only when cluster is configured.
    Note: The name attribute value was wrapped here to be more readable. It has to be all on the same line, without spaces.

    <jmx:query failonerror="false" name="Catalina:type=Cluster,host=${tomcat.application.host}" resultproperty="cluster" /> <jmx:get name= "Catalina:type=IDataSender,host=${tomcat.application.host}, senderAddress=${cluster.backup.address},senderPort=${cluster.backup.port}" attribute="connected" resultproperty="datasender.connected" if="cluster.0.name" />

    List of Attributes
    Attribute Description Default value
    name Full qualified JMX ObjectName -- Catalina:type=Server
    attribute Existing MBean attribute (see Tomcat MBean description above)
    value value that set to attribute
    type type of the attribute. java.lang.String
    ref JMX Connection reference jmx.server
    echo Echo command usage (access and result) false

    Example to set remote MBean attribute value
    <jmx:set name="Catalina:type=Manager,context=/servlets-examples,host=localhost" attribute="maxActiveSessions" value="500" type="int" />

    List of Attributes
    Attribute Description Default value
    name Full qualified JMX ObjectName -- Catalina:type=Server
    operation Existing MBean operation (see Tomcat funcspecs/fs-admin-opers.html).
    ref JMX Connection reference jmx.server
    echo Echo command usage (access and result) false
    resultproperty Save result at this project property
    delimiter Split result with delimiter (java.util.StringTokenizier) and use resultproperty as prefix to store tokens.
    separatearrayresults When return value is an array, save result as property list ($resultproperty.[0..N] and $resultproperty.length) true

    stop an application
    <jmx:invoke name="Catalina:type=Manager,context=/servlets-examples,host=localhost" operation="stop"/> Now you can find the sessionid at ${sessions.[0..N} properties and access the count with ${sessions.length} property.

    Example to get all sessionids
    <jmx:invoke name="Catalina:type=Manager,context=/servlets-examples,host=localhost" operation="listSessionIds" resultproperty="sessions" delimiter=" " /> Now you can find the sessionid at ${sessions.[0..N} properties and access the count with ${sessions.length} property.

    Example to get remote MBean session attribute from session ${sessionid.0}
    <jmx:invoke name="Catalina:type=Manager,context=/ClusterTest,host=localhost" operation="getSessionAttribute" resultproperty="hello"> <arg value="${sessionid.0}"/> <arg value="Hello" /> </jmx:invoke>

    Example to create a new access logger valve at vhost localhost <jmx:invoke name="Catalina:type=MBeanFactory" operation="createAccessLoggerValve" resultproperty="accessLoggerObjectName" > <arg value="Catalina:type=Host,host=localhost"/> </jmx:invoke> Now you can find new MBean with name stored at ${accessLoggerObjectName} property.

    List of Attributes
    Attribute Description Default value
    name JMX ObjectName query string -- Catalina:type=Manager,*
    ref JMX Connection reference jmx.server
    echo Echo command usage (access and result) false
    resultproperty Prefix project property name to all founded MBeans (mbeans.[0..N].objectname)
    attributebinduing bind ALL MBean attributes in addition to name false
    delimiter Split result with delimiter (java.util.StringTokenizier) and use resultproperty as prefix to store tokens.
    separatearrayresults When return value is an array, save result as property list ($resultproperty.[0..N] and $resultproperty.length) true

    Get all Manager ObjectNames from all services and Hosts
    <jmx:query name="Catalina:type=Manager,* resultproperty="manager" /> Now you can find the Session Manager at ${manager.[0..N].name} properties and access the result object counter with ${manager.length} property.

    Example to get the Manager from servlet-examples application an bind all MBean properties
    <jmx:query name="Catalina:type=Manager,context=/servlet-examples,host=localhost*" attributebinding="true" resultproperty="manager.servletExamples" /> Now you can find the manager at ${manager.servletExamples.0.name} property and can access all properties from this manager with ${manager.servletExamples.0.[manager attribute names]}. The result object counter from MBeans is stored ad ${manager.length} property.

    Example to get all MBeans from a server and store inside an external XML property file
    <project name="jmx.query" xmlns:jmx="antlib:org.apache.catalina.ant.jmx" default="query-all" basedir="."> <property name="jmx.host" value="localhost"/> <property name="jmx.port" value="8050"/> <property name="jmx.username" value="controlRole"/> <property name="jmx.password" value="tomcat"/> <target name="query-all" description="Query all MBeans of a server"> <!-- Configure connection --> <jmx:open host="${jmx.host}" port="${jmx.port}" ref="jmx.server" username="${jmx.username}" password="${jmx.password}"/> <!-- Query MBean list --> <jmx:query name="*:*" resultproperty="mbeans" attributebinding="false"/> <echoproperties destfile="mbeans.properties" prefix="mbeans." format="xml"/> <!-- Print results --> <echo message= "Number of MBeans in server ${jmx.host}:${jmx.port} is ${mbeans.length}"/> </target> </project> Now you can find all MBeans inside the file mbeans.properties.

    List of Attributes
    Attribute Description Default value
    name Full qualified JMX ObjectName -- Catalina:type=MBeanFactory
    className Existing MBean full qualified class name (see Tomcat MBean description above)
    classLoader ObjectName of server or web application classloader
    ( Catalina:type=ServerClassLoader,name=[server,common,shared] or
    Catalina:type=WebappClassLoader,context=/myapps,host=localhost)
    ref JMX Connection reference jmx.server
    echo Echo command usage (access and result) false

    Example to create remote MBean
    <jmx:create ref="${jmx.reference}" name="Catalina:type=MBeanFactory" className="org.apache.commons.modeler.BaseModelMBean" classLoader="Catalina:type=ServerClassLoader,name=server"> <arg value="org.apache.catalina.mbeans.MBeanFactory" /> </jmx:create>

    Warning: Many Tomcat MBeans can't be linked to their parent once
    created. The Valve, Cluster and Realm MBeans are not automatically
    connected with their parent. Use the MBeanFacrory create
    operation instead.

    List of Attributes
    Attribute Description Default value
    name Full qualified JMX ObjectName -- Catalina:type=MBeanFactory
    ref JMX Connection reference jmx.server
    echo Echo command usage (access and result) false

    Example to unregister remote MBean
    <jmx:unregister name="Catalina:type=MBeanFactory" />

    Warning: A lot of Tomcat MBeans can't be unregister.
    The MBeans are not unlinked from their parent. Use MBeanFacrory
    remove operation instead.

    List of Attributes
    Attribute Description Default value
    url Set JMX connection URL - service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi
    host Set the host, shortcut the very long URL syntax. localhost
    port Set the remote connection port 8050
    username remote JMX connection user name.
    password remote JMX connection password.
    ref Name of the internal connection reference. With this attribute you can configure more the one connection inside the same Ant project. jmx.server
    name Full qualified JMX ObjectName -- Catalina:type=Server
    echo Echo condition usage (access and result) false
    if Only execute if a property of the given name exists in the current project.
    unless Only execute if a property of the given name not exists in the current project.
    value (requiered) Second arg for operation
    type Value type to express operation (support long and double) long
    operation express one
    • == equals
    • != not equals
    • > greater than (&gt;)
    • >= greater than or equals (&gt;=)
    • < lesser than (&lt;)
    • <= lesser than or equals (&lt;=)
    ==

    Wait for server connection and that cluster backup node is accessable
    <target name="wait"> <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" > <and> <socket server="${server.name}" port="${server.port}"/> <http url="${url}"/> <jmx:condition operation="==" host="localhost" port="9014" username="controlRole" password="tomcat" name= "Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025" attribute="connected" value="true" /> </and> </waitfor> <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" /> <echo message="Server ${url} alive" /> </target>

    List of Attributes
    Attribute Description Default value
    url Set JMX connection URL - service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi
    host Set the host, shortcut the very long URL syntax. localhost
    port Set the remote connection port 8050
    username remote JMX connection user name.
    password remote JMX connection password.
    ref Name of the internal connection reference. With this attribute you can configure more the one connection inside the same Ant project. jmx.server
    name Full qualified JMX ObjectName -- Catalina:type=Server
    echo Echo condition usage (access and result) false

    Wait for server connection and that cluster backup node is accessible
    <target name="wait"> <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" > <and> <socket server="${server.name}" port="${server.port}"/> <http url="${url}"/> <jmx:equals host="localhost" port="9014" username="controlRole" password="tomcat" name= "Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025" attribute="connected" value="true" /> </and> </waitfor> <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" /> <echo message="Server ${url} alive" /> </target>

    Tomcat offers an alternative to using remote (or even local) JMX connections while still giving you access to everything JMX has to offer: Tomcat's JMXProxyServlet.

    The JMXProxyServlet allows a client to issue JMX queries via an HTTP interface. This technique offers the following advantages over using JMX directly from a client program:

    • You don't have to launch a full JVM and make a remote JMX connection just to ask for one small piece of data from a runing server
    • You don't have to know how to work with JMX connections
    • You don't need any of the complex configuration covered in the rest of this page
    • Your client program does not have to be written in Java

    A perfect example of JMX overkill can be seen in the case of popular server-monitoring software such as Nagios or Ichinga: if you want to monitor 10 items via JMX, you will have to launch 10 JVMs, make 10 JMX connections, and then shut them all down every few minutes. With the JMXProxyServlet, you can make 10 HTTP connections and be done with it.

    You can find out more information about the JMXProxyServlet in the documentation for the Tomcat manager.

    tomcat7-7.0.52/webapps/docs/default-servlet.xml0000644000175100017510000002430712271304167021375 0ustar locutuslocutus ]> &project; Tim Funk Default Servlet Reference
    The default servlet is the servlet which serves static resources as well as serves the directory listings (if directory listings are enabled).
    It is declared globally in $CATALINA_BASE/conf/web.xml. By default here is it's declaration: <servlet> <servlet-name>default</servlet-name> <servlet-class> org.apache.catalina.servlets.DefaultServlet </servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> ... <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> So by default, the default servlet is loaded at webapp startup and directory listings are disabled and debugging is turned off.
    The DefaultServlet allows the following initParamters:
    debug Debugging level. It is not very useful unless you are a tomcat developer. As of this writing, useful values are 0, 1, 11, 1000. [0]
    listings If no welcome file is present, can a directory listing be shown? value may be true or false [false]
    Welcome files are part of the servlet api.
    WARNING: Listings of directories containing many entries are expensive. Multiple requests for large directory listings can consume significant proportions of server resources.
    readmeFile If a directory listing is presented, a readme file may also be presented with the listing. This file is inserted as is so it may contain HTML.
    globalXsltFile If you wish to customize your directory listing, you can use an XSL transformation. This value is an absolute file name which be used for all directory listings. This can be overridden per context and/or per directory. See contextXsltFile and localXsltFile below. The format of the xml is shown below.
    contextXsltFile You may also customize your directory listing by context by configuring contextXsltFile. This should be a context relative path (e.g.: /path/to/context.xslt). This overrides globalXsltFile. If this value is present but a file does not exist, then globalXsltFile will be used. If globalXsltFile does not exist, then the default directory listing will be shown.
    localXsltFile You may also customize your directory listing by directory by configuring localXsltFile. This should be a relative file name in the directory where the listing will take place. This overrides globalXsltFile and contextXsltFile. If this value is present but a file does not exist, then contextXsltFile will be used. If contextXsltFile does not exist, then globalXsltFile will be used. If globalXsltFile does not exist, then the default directory listing will be shown.
    input Input buffer size (in bytes) when reading resources to be served. [2048]
    output Output buffer size (in bytes) when writing resources to be served. [2048]
    readonly Is this context "read only", so HTTP commands like PUT and DELETE are rejected? [true]
    fileEncoding File encoding to be used when reading static resources. [platform default]
    sendfileSize If the connector used supports sendfile, this represents the minimal file size in KB for which sendfile will be used. Use a negative value to always disable sendfile. [48]
    useAcceptRanges If true, the Accept-Ranges header will be set when appropriate for the response. [true]

    You can override DefaultServlet with you own implementation and use that in your web.xml declaration. If you can understand what was just said, we will assume you can read the code to DefaultServlet servlet and make the appropriate adjustments. (If not, then that method isn't for you)

    You can use either localXsltFile or globalXsltFile and DefaultServlet will create an xml document and run it through an xsl transformation based on the values provided in localXsltFile and globalXsltFile. localXsltFile is first checked, followed by globalXsltFile, then default behaviors takes place.

    Format: <listing> <entries> <entry type='file|dir' urlPath='aPath' size='###' date='gmt date'> fileName1 </entry> <entry type='file|dir' urlPath='aPath' size='###' date='gmt date'> fileName2 </entry> ... </entries> <readme></readme> </listing>

    • size will be missing if type='dir'
    • Readme is a CDATA entry

    The following is a sample xsl file which mimics the default tomcat behavior: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xhtml" encoding="iso-8859-1" indent="no"/> <xsl:template match="listing"> <html> <head> <title> Sample Directory Listing For <xsl:value-of select="@directory"/> </title> <style> h1{color : white;background-color : #0086b2;} h3{color : white;background-color : #0086b2;} body{font-family : sans-serif,Arial,Tahoma; color : black;background-color : white;} b{color : white;background-color : #0086b2;} a{color : black;} HR{color : #0086b2;} </style> </head> <body> <h1>Sample Directory Listing For <xsl:value-of select="@directory"/> </h1> <hr size="1" /> <table cellspacing="0" width="100%" cellpadding="5" align="center"> <tr> <th align="left">Filename</th> <th align="center">Size</th> <th align="right">Last Modified</th> </tr> <xsl:apply-templates select="entries"/> </table> <xsl:apply-templates select="readme"/> <hr size="1" /> <h3>Apache Tomcat/7.0</h3> </body> </html> </xsl:template> <xsl:template match="entries"> <xsl:apply-templates select="entry"/> </xsl:template> <xsl:template match="readme"> <hr size="1" /> <pre><xsl:apply-templates/></pre> </xsl:template> <xsl:template match="entry"> <tr> <td align="left"> <xsl:variable name="urlPath" select="@urlPath"/> <a href="{$urlPath}"> <tt><xsl:apply-templates/></tt> </a> </td> <td align="right"> <tt><xsl:value-of select="@size"/></tt> </td> <td align="right"> <tt><xsl:value-of select="@date"/></tt> </td> </tr> </xsl:template> </xsl:stylesheet>
    Use web.xml in each individual webapp. See the security section of the Servlet specification.
    tomcat7-7.0.52/webapps/docs/cgi-howto.xml0000644000175100017510000000754212271304167020171 0ustar locutuslocutus ]> &project; Glenn L. Nielsen CGI How To

    The CGI (Common Gateway Interface) defines a way for a web server to interact with external content-generating programs, which are often referred to as CGI programs or CGI scripts.

    Within Tomcat, CGI support can be added when you are using Tomcat as your HTTP server and require CGI support. Typically this is done during development when you don't want to run a web server like Apache httpd. Tomcat's CGI support is largely compatible with Apache httpd's, but there are some limitations (e.g., only one cgi-bin directory).

    CGI support is implemented using the servlet class org.apache.catalina.servlets.CGIServlet. Traditionally, this servlet is mapped to the URL pattern "/cgi-bin/*".

    By default CGI support is disabled in Tomcat.

    CAUTION - CGI scripts are used to execute programs external to the Tomcat JVM. If you are using the Java SecurityManager this will bypass your security policy configuration in catalina.policy.

    Remove the XML comments from around the CGI servlet and servlet-mapping configuration in $CATALINA_BASE/conf/web.xml.

    Only Contexts which are marked as privileged may use the CGI servlet (see the privileged property of the Context element).

    There are several servlet init parameters which can be used to configure the behaviour of the CGI servlet.

    • cgiPathPrefix - The CGI search path will start at the web application root directory + File.separator + this prefix. The default cgiPathPrefix is WEB-INF/cgi
    • debug - Debugging detail level for messages logged by this servlet. Default 0.
    • executable - The of the executable to be used to run the script. You may explicitly set this parameter to be an empty string if your script is itself executable (e.g. an exe file). Default is perl.
    • executable-arg-1, executable-arg-2, and so on - additional arguments for the executable. These precede the CGI script name. By default there are no additional arguments.
    • parameterEncoding - Name of the parameter encoding to be used with the CGI servlet. Default is System.getProperty("file.encoding","UTF-8").
    • passShellEnvironment - Should the shell environment variables (if any) be passed to the CGI script? Default is false.
    • stderrTimeout - The time (in milliseconds) to wait for the reading of stderr to complete before terminating the CGI process. Default is 2000.

    tomcat7-7.0.52/webapps/docs/WEB-INF/0000755000175100017510000000000012301126373016561 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/WEB-INF/web.xml0000644000175100017510000000232412271304167020066 0ustar locutuslocutus Tomcat Documentation Tomcat Documentation. tomcat7-7.0.52/webapps/docs/changelog.xml0000644000175100017510000123611212276703610020217 0ustar locutuslocutus ]> &project; Remy Maucherat Filip Hanik Rainer Jung Konstantin Kolinko Peter Rossbach Keiichi Fujino Tim Whittington Mladen Turk Christopher Schultz Sylvain Laurent Violeta Georgieva Changelog
    Generate a valid root element for the effective web.xml for a web application for all supported versions of web.xml. (markt) Pull up SocketWrapper to AbstractProcessor. (markt) In some circumstances asynchronous requests could time out too soon. (markt)
    55287: ServletContainerInitializer defined in the container may not be found. (markt/jboynes) 55855: Provide a per Context option (containerSciFilter) to exclude container SCIs. (markt) 55937: When deploying applications, treat a context path of /ROOT as equivalent to /. (markt) 55943: Improve the implementation of the class loader check that prevents web applications from trying to override J2SE implementation classes. As part of this fix, refactor the way a null parent class loader is handled which enables a number of null checks and object creation calls to be removed. (markt) 55958: Differentiate between foo.war the WAR file and foo.war the directory. (markt) 55960: Improve the single sign on (SSO) unit tests. Patch provided by Brian Burch. (markt) 55974: Retain order when reporting errors and warnings while parsing XML configuration files. (markt) 56013: Fix issue with SPNEGO authentication when using IBM JREs. IBM JREs only understand the option of infinite lifetime for Kerberos credentials. Based on a patch provided by Arunav Sanyal. (markt) 56016: When loading resources for XML schema validation, take account of the possibility that servlet-api.jar and jsp-api.jar may not be loaded by the same class loader. Patch by Juan Carlos Estibariz. (markt) 56025: When creating a WebSocket connection, always call ServerEndpointConfig.Configurator.getNegotiatedSubprotocol() and always create the EndPoint instance after calling ServerEndpointConfig.Configurator.modifyHandshake(). (markt) 56032: Ensure that the WebSocket connection is closed after an IO error or an interrupt while sending a WebSocket message. (markt) 56042: If a request in async mode has an error but has already been dispatched don't generate an error page in the ErrorReportValve so the dispatch target can handle it. (markt) Add missing javax.annotation.sql.* classes to annotations-api.jar. (markt) The type of logger attribute of Context MBean should be not org.apache.commons.logging.Log but org.apache.juli.logging.Log. (kfujino) 56082: Fix a concurrency bug in JULI's LogManager implementation. (markt) 56096: When the attribute rmiBindAddress of the JMX Remote Lifecycle Listener is specified it's value will be used when constructing the address of a JMX API connector server. Patch is provided by Jim Talbut. (violetagg) When environment entry with one and the same name is defined in the web deployment descriptor and with annotation then the one specified in the web deployment descriptor is with priority. (violetagg) Change default value of xmlBlockExternal attribute of Context. It is true now. (kkolinko) Avoid possible NPE if a content type is specified without a character set. (markt) 55956: Make the forwarded remote IP address available to the Connectors via a request attribute. (markt) 55976: Fix sendfile support for the HTTP NIO connector. (markt) 55996: Ensure Async requests timeout correctly when using the NIO HTTP connector. (markt) 56021: Make it possible to use the Windows-MY key store with the BIO and NIO connectors for SSL configuration. It requires a keystoreFile="" keystoreType="Windows-My" to be set on the connector. Based on a patch provided by Asanka. (markt) Correct a regression in the XML refactoring that meant that errors in TLD files were swallowed. (markt) 55671: Correct typo in the log message for a wrong value of genStringAsCharArray init-param of JspServlet. This parameter had a different name in Tomcat 6. (kkolinko) 55973: Fix processing of XML schemas when validation is enabled in Jasper. (kkolinko) 56010: Don't throw an IllegalArgumentException when JspFactory.getPageContext is used with JspWriter.DEFAULT_BUFFER. Based on a patch by Eugene Chung. (markt) 56012: When using the extends attribute of the page directive do not import the super class if it is in an unnamed package as imports from unnamed packages are now explicitly illegal. (markt) 56029: A regression in the fix for 55198 meant that when EL containing a ternary expression was used in an attribute a compilation error would occur for some expressions. (markt) Correct several errors in jspxml Schema and DTD. (kkolinko) Change default value of the blockExternal attribute of JspC task. The default value is true. Add support for -no-blockExternal switch when JspC is run as a standalone application. (kkolinko) Simplify the code of o.a.c.ha.tcp.SimpleTcpCluster.createManager(String). Remove unnecessary class cast. (kfujino) Do not return an empty string for the Sec-WebSocket-Protocol HTTP header when no sub-protocol has been requested or no sub-protocol could be agreed as RFC6455 requires that no Sec-WebSocket-Protocol header is returned in this case. (markt) Add index.xhtml to the welcome files list for the examples web application. (kkolinko) Clarify that the connectionTimeout may also be used as the read timeout when reading a request body (if any) in the documentation web application. (markt) Clarify the behaviour of the maxConnections attribute for a connector in the documentation web application. (markt) 55888: Update the documentation web application to make it clearer that a Container may define no more than one Realm. (markt) 55956: Where available, displayed the forwarded remote IP address available on the status page of the Manager web application. (markt) Correct links to the Tomcat mailing lists in the ROOT web application. (kkolinko) In Manager web application improve handling of file upload errors. Display a message instead of error 500 page. Simplify parts handling code, as it is known that Tomcat takes care of them when recycling a request. (kkolinko) 55166, 56045: Copy the XML schemas used for validation that are packaged in jsp-api.jar to servlet-api.jar so that an embedded Tomcat instance can start without Jasper being available. This also enables validation to work without Jasper being available. (markt/kkolinko) 56039: Enable the JmxRemoteLifecycleListener to work over SSL. Patch by esengstrom. (markt) 55743: Enable the stop script to work when the shutdown port is disabled and a PID file is defined. This is only available on platforms that use catalina.sh. (markt) 55986: When forcing Tomcat to stop via kill -9 $CATALINA_PID, the catalina.sh script could incorrectly report that Tomcat had not yet completely stopped when it had. Based on a patch by jess. (markt) Package correct license and notice files with embedded JARs. (markt) Remove svn keywords (such as $Id) from source files and documentation. (kkolinko) Fix CVE-2014-0050, a denial of service with a malicious, malformed Content-Type header and multipart request processing. Fixed by merging latest code (r1565163) from Commons FileUpload. (markt) 56115: Expose the httpusecaches property of Ant's get task as some users may need to change the default. Based on a suggestion by Anthony. (markt)
    Handle the case where a context.xml file is added to a web application deployed from a directory. Previously the file was ignored until Tomcat was restarted. Now (assuming automatic deployment is enabled) it will trigger a redeploy of the web application. (markt) Fix string comparison in HostConfig.setContextClass(). (kkolinko) Streamline handling of WebSocket messages when no handler is configured for the message currently being received. (markt) Handle the case where a WebSocket annotation configures a message size limit larger than the default permitted by Tomcat. (markt) 55855: This is a partial fix that bypasses the relatively expensive check for a WebSocket upgrade request if no WebSocket endpoints have been registered. (markt) 55905: Prevent a NPE when web.xml references a taglib file that does not exist. Provide better error message. (violetagg) When using the BIO connector with an internal executor, do not display a warning that the executor has not shutdown as the default configuration for BIO connectors is not to wait. This is because threads in keep-alive connections cannot be interrupted and therefore the warning was nearly always displayed. (markt) JspC uses servlet context initialization parameters to pass configuration so ensure that the servlet context used supports initialization parameters. (markt) In AbstractReplicatedMap#finalize, remove rpcChannel from channel Listener of group channel before sending MapMessage.MSG_STOP message. This prevents that the node that sent the MapMessage.MSG_STOP by normal shutdown is added to member map again by ping at heartbeat thread in the node that received the MapMessage.MSG_STOP. (kfujino) Add time stamp to GET_ALL_SESSIONS message. (kfujino) Fix the sample configuration of StaticMembershipInterceptor in order to prevent warning log. uniqueId must be 16 bytes. (kfujino) Update dependencies that are used to build tomcat-juli extras component. Apache Avalon Framework is updated to version 4.1.5, Apache Log4J to version 1.2.17. (rjung)
    Correct a regression in the new XML local resolver that triggered false failures when XML validation was configured. (markt) Prevent a NPE when destroying HTTP upgrade handler for WebSocket connections. (violetagg)
    51294: Add support for unpacking WARs located outside of the Host's appBase in to the appBase. (markt) 55656: Configure the Digester to use the server class loader when parsing server.xml rather than the class loader that loaded StandardServer. Patch provided by Roberto Benedetti. (markt) 55664: Correctly handle JSR 356 WebSocket Encoder, Decoder and MessageHandler implementations that use a generic type such as Encoder.Text<List<String>>. Includes a test case by Niki Dokovski. (markt) Correctly handle WebSocket Encoders, Decoders and MessageHandlers that use arrays of generic types. (markt) 55681: Ensure that the WebSocket session is made available to MessageHandler method calls. (markt) Updated servlet spec version and documentation section-number reported when JAR files are rejected for containing a trigger class (e.g. javax.servlet.Servlet). (schultz) Modify the WebSocket handshake process so that the user properties Map exposed by the ServerEndpointConfig during the call to Configurator.modifyHandshake() is unique to the connection rather than shared by all connections associated with the Endpoint. This allows for easier configuration of per connection properties from within modifyHandshake(). (markt) 55684: Log a warning but continue if the memory leak detection code is unable to access all threads to check for possible memory leaks when a web application is stopped. (markt) Define the web-fragment.xml in tomcat7-websocket.jar as a Servlet 3.0 web fragment rather than as a Servlet 3.1 web fragment. (markt) 55715: Add a per web application executor to the WebSocket implementation and use it for calling SendHandler.onResult() when there is a chance that the current thread also initiated the write. (markt) Prevent file descriptors leak and ensure that files are closed when configuring the web application. (violetagg) Fixed the name of the provider-configuration file located in tomcat7-websocket.jar!/META-INF/services that exposes information for javax.websocket.server.ServerEndpointConfig$Configurator implementation. (violetagg) 55760: Remove the unnecessary setting of the javax.security.auth.useSubjectCredsOnly system property in the SpnegoAuthenticator as in addition to it being unnecessary, it causes problems with using SPNEGO with IBM JDKs. Patch provided by Arunav Sanyal. (markt) 55772: Ensure that the request and response are recycled after an error during asynchronous processing. Includes a test case based on code contributed by Todd West. (markt) 55778: Add an option to the JNDI Realm to control the QOP used for the connection to the LDAP server after authentication when using SPNEGO with delegated credentials. This value is used to set the javax.security.sasl.qop environment property for the LDAP connection. (markt) 55798: Log an error if the MemoryUserDatabase is unable to find the specified user database file. (markt) 55799: Correctly enforce the restriction in JSR356 that no more than one data message may be sent to a remote WebSocket endpoint at a time. (markt) When Catalina parses TLD files, always use a namespace aware parser to be consistent with how Jasper parses TLD files. The tldNamespaceAware attribute of the Context is now ignored. (markt) Deprecate the tldNamespaceAware Context attribute as TLDs are always parsed with a namespace aware parser. (markt) Correct a logic error that meant that unpackWARs was ignored and the WAR was always expanded if a WAR failed to deploy. (markt) Add support for defining copyXML on a per Context basis. (markt) Define the expected behaviour of the automatic deployment and align the implementation to that definition. (markt) When running under a security manager, change the default value of the Host's deployXML attribute to false. (markt) If a Host is configured with a value of false for deployXML, a web application has an embedded descriptor at META-INF/context.xml and no explicit descriptor has been defined for this application, do not allow the application to start. The reason for this is that the embedded descriptor may contain configuration necessary for secure operation such as a RemoteAddrValve. (markt) Prevent an NPE in the WebSocket ServerContainer when processing an HTTP session end event. (markt) 55801: Add the ability to set a custom SSLContext to use for client wss connections. Patch provided by Maciej Lypik. (markt) 55804: If the GSSCredential for the cached Principal expires when using SPNEGO authentication, force a re-authentication. (markt) 55811: If the main web.xml contains an empty absolute-ordering element and validation of web.xml is not enabled, skip parsing any web-fragment.xml files as the result is never used. (markt) 55839: Extend support for digest prefixes {MD5}, {SHA} and {SSHA} to all Realms rather than just the JNDIRealm. (markt) 55842: Ensure that if a larger than default response buffer is configured that the full buffer is used when a Servlet outputs via a Writer. (markt) 55851: Further fixes to enable SPNEGO authentication to work with IBM JDKs. Based on a patch by Arunav Sanyal. (markt) Add an option to the Context to control the blocking of XML external entities when parsing XML configuration files and enable this blocking by default when a security manager is used. The block is implemented via a custom resolver to enable the logging of any blocked entities. (markt) Implement a number of small refactorings to the APR/native handler for upgraded HTTP connections. (markt) Fix an issue with upgraded HTTP connections over HTTPS (e.g. secure WebSocket) when using the APR/native connector that resulted in the unexpected closure of the connection. (markt) Ensure that the application class loader is used when calling the ReadListener and WriteListener methods when using non-blocking IO. A side effect of not doing this was that JNDI was not available when processing WebSocket events. (markt) Make the time that the internal executor (if used) waits for request processing threads to terminate before continuing with the connector stop process configurable. (markt) 55749: Improve the error message when SSLEngine is disabled in the AprLifecycleListener and SSL is configured for an APR/native connector. (markt) If a request that includes an Expect: 100-continue header receives anything other than a 2xx response, close the connection This protects against misbehaving clients that may not sent the request body in that case and send the next request instead. (markt) Improve the parsing of trailing headers in HTTP requests. (markt) 55735: Fix a regression caused by the fix to 55198. When processing JSP documents, attributes in XML elements that are template content should have their text xml-escaped, but output of EL expressions in them should not be escaped. (markt) 55807: The JSP compiler used a last modified time of -1 for TLDs in JARs expanded in to WEB-INF/classes (IDEs often do this expansion) when creating the dependency list for JSPs that used that TLD. This meant JSPs using that TLD were recompiled on every access. (markt) Add log message that initialization of AbstractReplicatedMap has been completed. (kfujino) The logger of AbstractReplicatedMap should be non-static in order to enable logging of each application. Side-effects of this change is to throw RuntimeException in MapMessage#getKey() and getValue() instead of Null return and error log. (kfujino) Simplify the code of DeltaManager#startInternal(). Reduce unnecessary nesting for acquisition of cluster instance. (kfujino) Remove unnecessary attributes of stateTransferCreateSendTime and receiverQueue from cluster manager template. These attributes should not be defined as a template. (kfujino) Fix MBean attribute definition of stateTransfered. The method name is not isStateTransfered() but getStateTransfered(). (kfujino) Correct stop failure log of cluster. Failure cause is not only Valve. (kfujino) Remove unnecessary sleep when sending session blocks on session sync phase. (kfujino) Expose stateTimestampDrop of org.apache.catalina.ha.session.DeltaManager via JMX. (kfujino) When the ping timeouted, make sure that memberDisappeared method is not called by specifying the members that has already been removed. (kfujino) Add log message of session relocation when member disappeared. (kfujino) If ping message fails, prevent wrong timeout detection of normal member that is no failure members. (kfujino) Add some documentation on the SSL configuration options for WebSocket clients. (markt) Add to cluster document a description of notifyLifecycleListenerOnFailure and heartbeatBackgroundEnabled. (kfujino) Update the documentation with information for WebSocket 1.0 specification and javadoc. (violetagg) 55703: Clarify the role of the singleton attribute for JNDI resource factories. (markt) 55746: Add documentation on the allRolesMode to the CombinedRealm and LockOutRealm. Patch by Cédric Couralet. (markt) Expand the information on web applications that ship as part of Tomcat in the security how-to section of the documentation web application. (markt) Expand the description of the WebSocket buffers in the documentation web application to clarify their purpose. (markt) Correct the documentation for Cluster manager. (kfujino) Add information on how to configure integrated Windows authentication when Tomcat is running on a non-Windows host. (markt) Update commons-logging to version 1.1.3. (rjung) 52323: Add support for the Cobertura code coverage tool when running the unit tests. Based on a patch by mhasko. (markt/kkolinko) Update sample Eclipse IDE project. Explicitly use a Java 6 SE JDK. Exclude JSR356 WebSocket classes from build path, as they cannot be compiled with Java 6. (kkolinko) Update the Eclipse compiler to 4.3.1. (kkolinko/markt)
    Fix regression with legacy WebSocket implementation in NIO and APR connectors. (markt) Avoid hang observed with Java 6 on Windows when stopping the Tomcat process via CTRL-C. (markt) 55663: NOTICE files are corrected according to NOTICE files requirements. (violetagg)
    Only send a WebSocket close message on an IOException if the client has not yet received a close control message from the server as the IOException may be in response to the client continuing to send a message after the server sent a close control message. (markt) 49134: Ensure nested realms are correctly destroyed, when a CombinedRealm is destroyed. This ensures that the associated MBeans are deregistered. (markt) Refactor APR/native connector to reduce the scope of localAddList. (markt) 55602: Ensure that sockets removed from the Poller and then closed in the APR/native connector are removed and then closed in a thread-safe manner. (markt) Update the APR/native connector to version 1.1.29. (violetagg) 55642: Correct logic error in the JSP parser that was incorrectly identifying EL expressions in jsp:param element values as a literal string. (markt) Add support for notify periodic event of cluster. (kfujino) Correct the javadoc for org.apache.catalina.Lifecycle. (kfujino) Add document for sessionIdAttribute attribute in org.apache.catalina.ha.session.JvmRouteBinderValve. (kfujino) Handle the case when a user closes the browser whilst playing the snake game in the JSR356 WebSocket examples. (markt) Ensure Javadoc comments are associated with the correct elements in org.apache.tomcat.jni.Poll. (markt) Expand Context documentation for the use of sessionCookiePath="/" to make the implications for session fixation protection clearer. (markt) 55629: Ensure that the JMX notification listener added during initialization of the servlet org.apache.catalina.manager.StatusManagerServlet is removed in the destroy phase. (violetagg) Correct the documentation for Deployment Organization in the App Dev Guide. (violetagg) 55639: Add a Drawboard WebSocket example. (kpreisser)
    55576: Preserve the order in which request parameters were received when accessing them via the Servlet API. (markt) Logger instance of cluster session manager is changed to non-static in order to enable logging of each application. (kfujino)
    55582: Correct concurrency issue that can result in two instances of JspServletWrapper being created for one tag Patch provided by Sheldon Shao. (markt)
    51526: o.a.catalina.startup.Tomcat#addWebapp methods now process the web application's META-INF/context.xml when it is available in the provided path. (violetagg) 55186: Ensure local name is recycled between requests so IP virtual hosting works correctly. (markt) 55210: Correct the processing of the provider-configuration file for javax.servlet.ServletContainerInitializer in the resource directory META-INF/services when this file contains comments and multiple SCIs. Patch provided by Nick Williams. (violetagg) 55230: Use the correct resource path when obtaining an InputStream for resources served by a ProxyDirContext. (markt) Ensure that the JAR scanning process scans the Apache Log4j version 2 JARs. Patch provided by Nick Williams. (markt) 55261: Fix failing unit test for file upload checks when running on platform / JVM combinations that have large network buffers. (markt) 55268: Added optional --service-start-wait-time command-line option to change service start wait time from default of 10 seconds. The contextClass attribute of HostConfig refers to the value of the contextClass attribute of Host. (kfujino) 55331: Dispatching to an asychronous servlet from AsyncListener.onTimeout() should not trigger an IllegalStateException. (markt) 55333: Correct a regression in the fix for 55071. (markt) When using a security manager, ensure that calls to the ServletContext that are routed via an AccessController.doPrivileged block do not result in a call to a different underlying method on the ServletContext. (markt) 55354: Ensure that the naming context environment parameters are restored after associating the Principle with the user name. Based on patch provided by Richard Begg. (violetagg) 55357: Ensure the web application class loader is set as a thread context class loader during session deserialization. (violetagg) 55404: Log warnings about using security roles in web.xml without defining them as warnings. (markt) 55439: Don't try a forced stop when stop -force is used if Tomcat has already been stopped. This avoids error messages when the PID file has been cleared. If a forced stop is required, improve handling of the case when the PID file can be read from or written to but not deleted. (markt) 55454: Avoid NPE when parsing an incorrect content type. (violetagg) Back-port the JSR-356 Java WebSocket 1.0 implementation from Tomcat 8. Note that use of this functionality requires Java 7. (markt) Deprecate the Tomcat proprietary WebSocket API in favour of the new JSR-356 implementation. (markt) 55494: Reduce severity of log message from warning to information for JNDI Realm connection issues where the JNDI Realm automatically re-tries the action that failed. Make clear in the log message that the action is being re-tried. (markt) Correct several incorrect formats of JdkLoggerFormatter. (kfujino) 55521: Ensure that calls to HttpSession.invalidate() do not return until the session has been invalidated. Also ensure that checks on the validity of a session return a result consistent with any previous call to HttpSession.invalidate(). (markt) 55524: Refactor to avoid a possible deadlock when handling an IOException during output when using Tomcat' proprietary (and deprecated) WebSocket API. (markt) The loaded attribute never exists in PersistentManager. isLoaded is defined as operation in mbeans-descriptors. (kfujino) Added logging of logging.properties location when system property org.apache.juli.ClassLoaderLogManager.debug=true is set. 55570: Correctly log exceptions for all error conditions in the SPNEGO authenticator. (markt) 55228: Allow web applications to set a HTTP Date header. (markt) Expose the current connection count for each protocol handler via JMX. (markt) 55267: If an application configures a timeout for a Comet connection ensure it is only used for read and not write operations. This prevents a long timeout delaying the closing of the socket associated with a Comet connection after an error occurs. (markt) Ensure that java.lang.VirtualMachineErrors are not swallowed when using the HTTP or AJP NIO connectors. (markt) 55399: Use the response locale to select the language to use for the status message in the HTTP response. (markt) Refactor the connectors to support the new JSR-356 Java WebSocket 1.0 implementation. The most noticeable change is that the AJP APR/native and HTTP APR/native connectors no longer support multiple poller threads. Both connectors now use a single poller thread. (markt) Internally, content length is managed as a long. Fix a few places in the AJP connector where this was restricted to an int. (markt) 55453: Ensure that the AJP connector does not permit response bodies to be included for responses with status codes and/or request methods that are not permitted to have a response body. (markt) 55500: Don't ignore the value of an asynchronous context timeout when using the AJP NIO connector. (markt) Better adherence to RFC2616 for content-length headers. (markt) Add support for limiting the size of chunk extensions when using chunked encoding. (markt) Update the APR/native connector to version 1.1.28. Make this the minimum acceptable version as the correct behaviour of the JSR-356 WebSocket implementation when using the APR/native HTTP connector depends on a bug fix in the 1.1.28 release. (markt) 55198: Ensure attribute values in tagx files that include EL and quoted XML characters are correctly quoted in the output. (markt) Ensure that javax.el.ELContext.getContext(Class) will throw NullPointerException when the provided class is null. (violetagg) Ensure that FeatureDescriptor objects returned by javax.el.MapELResolver.getFeatureDescriptors(ELContext,Object) will be created with a correct shortDescription - an empty string and a named attribute ELResolver.RESOLVABLE_AT_DESIGN_TIME - true. (violetagg) Ensure that FeatureDescriptor objects returned by javax.el.ResourceBundleELResolver.getFeatureDescriptors(ELContext,Object) will be created with a correct shortDescription - an empty string. javax.el.ResourceBundleELResolver.isReadOnly(ELContext,Object,Object) returns true if the base object is an instance of ResourceBundle. (violetagg) 55207: Enforce the restriction that a <jsp:text> element may not contain any sub-elements from any namespace. Patch provided by Jeremy Boynes. (markt) Ensure that javax.el.ListELResolver.getFeatureDescriptors(ELContext,Object) will always return null. javax.el.ListELResolver.isReadOnly(ELContext,Object,Object) will return a result when the property cannot be coerced into an integer. (violetagg) Ensure that javax.el.ArrayELResolver.getFeatureDescriptors(ELContext,Object) will always return null. javax.el.ArrayELResolver.isReadOnly(ELContext,Object,Object) and javax.el.ArrayELResolver.getType(ELContext,Object,Object) will return a result when the property cannot be coerced into an integer. (violetagg) 55309: Fix concurrency issue with JSP compilation and the tag plug-in manager. Patch provided by Sheldon Shao. (markt) Ensure that javax.el.BeanELResolver.getFeatureDescriptors(ELContext,Object) and javax.el.BeanELResolver.getCommonPropertyType(ELContext,Object) do not throw NullPointerException when the provided context is null. (violetagg) Add new attribute terminateOnStartFailure. Set to true if you wish to terminate replication map when replication map fails to start. If replication map is terminated, associated context will fail to start. If you set this attribute to false, replication map does not end. It will try to join the map membership in the heartbeat. Default value is false. (kfujino) Avoid ConcurrentModificationException when sending a heartbeat. (kfujino) Avoid NPE when the channel fails to start. (kfujino) 55301: Fix IllegalArgumentException thrown by simple test for McastService. (kfujino) 55332: Fix NPE in FileMessageFactory.main when specify empty file as arguments. (kfujino) More definite thread name for MessageDispatch15Interceptor. (kfujino) Remove the experimental label from the AJP NIO connector documentation. (markt) Correctly associated the default resource bundle with the English locale so that requests that specify an Accept-Language of English ahead of French, Spanish or Japanese get the English messages they asked for. (markt) 55469: Fixed tags that were not properly closed. Based on a patch provided by Larry Shatzer, jr. (violetagg) The WebSocket examples in the examples web application have been changed to use the new JSR-356 Java WebSocket 1.0 implementation. (markt) Add document for org.apache.catalina.tribes.group.GroupChannel. (kfujino) Correct Realm Component page of Tomcat documentation. (violetagg) 54693: Add a validationQueryTimeout property. Patch provided by Daniel Mikusa. (kfujino) 54693#c6: Avoid NPE caused by createConnection() method returns null. Patch provided by Daniel Mikusa. (kfujino) 55342: Remove unnecessary reset of interrupted flag. If InterruptedException is thrown, the interrupted flag has been cleared. (kfujino) 55343: Add flag to ignore exceptions of connection creation while initializing the pool. (kfujino) Add undefined attributes and operations to mbeans-descriptor. (kfujino) 45428: Trigger a thread dump written to standard out if Tomcat fails to stop in a timely manner to aid diagnostics. This is only available on platforms that use catalina.sh. (markt) 55204: Correct namespace used in Servlet 2.4 test web application. Patch provided by Jeremy Boynes. (markt) 55205: Reorder elements so web.xml complies with schema for Servlet 3.0 test web application. Patch provided by Jeremy Boynes. (markt) 55211: Correct namespace in TLD files used in test web applications. Rename elements tagclass to tag-class so TLD files complies with DTD/schema. Patch provided by Jeremy Boynes. (violetagg) Update package renamed version of Commons BCEL to the latest code from Commons BCEL trunk. (markt) Update package renamed version of Commons FileUpload to the latest code from Commons FileUpload trunk. (markt) 55297: When looking for the jsvc executable, if an explicit path is not set and it is not found in $CATALINA_BASE, look in $CATALINA_HOME as well. (markt) 55336: Correctly escape parameters passed to eval in the catalina.sh script to ensure that Tomcat starts when installed on a path that contains multiple consecutive spaces. (markt)
    Enforce the restriction described in section 4.4 of the Servlet 3.0 specification that requires the new pluggability methods only to be available to ServletContextListeners defined in one of the specified ways. (markt) Better handle FORM authentication when requesting a resource as an unauthenticated user that is only protected for a sub-set of HTTP methods that does not include GET. (markt) 53777: Add support for a JAAS Realm instance to use a dedicated configuration rather than the JVM global JAAS configuration. This is most likely to be useful for per web application JAAS Realms. Based on a patch by eolivelli. (markt) 54745: Fix JAR file scanning when Tomcat is deployed via Java Web Start. Patch provided by Nick Williams. (markt) 55017: Add the ability to configure the RMI bind address when using the JMX remote lifecycle listener. Patch provided by Alexey Noskov. (markt) 55071: Ensure original exception is reported if JDBC Realm fails to read a user's credentials. (markt) 55073, 55108, 55109, 55110, 55158 & 55159: Small performance improvements. Patches provided by Adrian Nistor. (markt/violetagg) 55102: Add support for time to first byte in the AccessLogValve. Patch provided by Jeremy Boynes. (markt) 55125: If the Server container fails to start, don't allow the Catalina wrapper to start (used when running from the command line and when running as a service) since Tomcat will not be able to do any useful work. (markt) Update the JreMemoryLeakPreventionListener to take account of changes in the behaviour of java.beans.Introspector.flushCaches() and sun.awt.AppContext.getAppContext() in Java 7. (markt) Avoid WARNING log message of Users:type=UserDatabase,database=UserDatabase at Tomcat shutdown. (pero) Avoid ClassCastException when an asynchronous dispatch is invoked in an asynchronous cycle which is started by a call to ServletRequest.startAsync(ServletRequest,ServletResponse) where ServletRequest/ServletResponse are custom implementations. (violetagg) Correct a regression introduced in 7.0.39 (refactoring of base 64 encoding and decoding) that broke the JNDI Realm when userPassword was set and passwords were hashed with MD5 or SHA1. (markt/kkolinko) Correct the mechanism for the path calculation in AsyncContext.dispatch(). (violetagg) 55155: Avoid constant focus grabbing when running the Tomcat unit tests under Java 6 on OSX. Patch provided by Casey Lucas. (markt) 55160: Don't ignore connectionUploadTimeout setting when using HTTP NIO connector. (markt) 55176: Correctly handle regular expressions within SSI expressions that contain an equals character. (markt) 55177: Correctly handle infinite soTimeout for BIO HTTP connector. Based on a patch by Nick Bunn. (markt) 55180: Correctly handle infinite soTimeout when disableUploadTimeout is set to false. Patch provided by Nick Bunn. (violetagg) Delete leftover of war file from tempDir when removing invalid FileMessageFactory. (kfujino) Ensure that the keepAlive of NioSender works correctly when keepAliveCount/keepAliveTime is set to a value greater than 0. (kfujino) Add logging of when a member is unable to join the cluster. (kfujino) Replace Tribes's TaskQueue as executor's workQueue in order to ensure that executor's maxThread works correctly. (kfujino) 54086: Fix an additional code path that could lead to multiple threads attempting to modify the same selector key set. (markt) Complete the document for MessageDispatch15Interceptor. (kfujino) 53655: Document the circumstances under which Tomcat will add a javax.mail.Authenticator to mail sessions created via a JNDI resource. (markt) 55179: Correct the Javadoc for the remote IP valve so the correct name is used to refer to the proxiesHeader property. (markt) 55031: Fixed Export-Package header and uses directives in MANIFEST.MF. Change the version for package org.apache.juli.logging to "0" in Import-Package header. Thus any version of that package can be used. Patch provided by Martin Lichtin. (violetagg) Update Maven Cental location used to download dependencies at build time to be repo.maven.apache.org. (kkolinko) Update JUnit to version 4.11. Configure separate download for Hamcrest 1.3 core library as its classes are no longer included in junit.jar. (kkolinko) 54013: When using a forced stop, allow a short period of time (5s) for the process to die before returning. Patch provided by mukarram.baig. (markt) 55119: Ensure that the build process produces Javadoc that is not vulnerable to CVE-2013-1571. Based on a patch by Uwe Schindler. (markt)
    54703: Make parsing of HTTP Content-Type headers tolerant of any CR or LF characters that appear in the value passed by the application. Also fix some whitespace parsing issues identified by the additional test cases. (markt) Prevent possible WAR file locking when reading a context.xml file from an unexpanded WAR file. Note that in normal usage, the JreMemoryLeakPreventionListener would protect against this. (markt) Ensure that when auto deployment runs for a Host, it uses the latest values for copyXML, deployXML and unpackWARs. (markt) 54939: Provide logging (using a UserDataHelper) when HTTP header parsing fails (e.g. when maxHeaderCount is exceeded). (markt) 54944: Enhancements to the unit tests for FORM authentication. Patch provided by Brian Burch. (markt) 54955: When a reload of the application is performed ensure that a subsequent request to the context root does not result in a 404 response. (violetagg) 54971: Ensure that the correct location is used when writing files via javax.servlet.http.Part.write(String). (markt) 54974: Ensure that SessionCookieConfig#set<methods> will throw IllegalStateException if the ServletContext from which this SessionCookieConfig was acquired has already been initialized. (violetagg) 54981: Ensure that ServletContext#getJspConfigDescriptor() will return null when there is no jsp configuration provided by web.xml/web-fragment.xml. (violetagg) Ensure that when Tomcat's anti-resource locking features are used that the temporary copy of the web application and not the original is removed when the web application stops. (markt) 54984: Use the correct encoding when processing a form data posted as multipart/form-data even when the request parameters are not parsed. (violetagg) 54999: The old JSESSIONIDSSO needs to be removed when SSO is being used and logout() and login() occur within a single request. Patch provided by Keith Mashinter. (markt) 55035: Add support for the version attribute to the deploy command of the Ant tasks for interfacing with the text based Manager application. Patch provided by Sergey Tcherednichenko. (markt) 55046: Add a Servlet Filter that implements CORS. Patch provided by Mohit Soni. (markt) 55052: JULI's LogManager now additionally looks for logging properties without prefixes if the property cannot be found with a prefix. (markt) Ensure that only the first asynchronous dispatch operation for a given asynchronous cycle will be performed. Any subsequent asynchronous dispatch operation for the same asynchronous cycle will be ignored and IllegalStateException will be thrown. (violetagg) 54947: Fix the HTTP NIO connector that incorrectly rejected a request if the CRLF terminating the request line was split across multiple packets. Patch by Konstantin Preißer. (markt) 54964: Allow tag plug-ins to be packaged with a web application. Patch provided by Sheldon Shao. (markt) 54968: Return the correct version number (2.2) of the JSP specification that is supported by the JSP engine when javax.servlet.jsp.JspEngineInfo#getSpecificationVersion() is invoked. (violetagg) Add maxValidTime attribute to prevent the leak of FileMessageFactory in FarmWarDeployer. (kfujino) Simplify the code of ReplicationValve: Rather than get cluster instance from container on every request, use instance variable. (kfujino) Add maxWait attribute that the senderPool will wait when there are no available senders. (kfujino) Improve error message by including specified timeout if failed to retrieve a data sender. (kfujino) Add removeSuspectsTimeout attribute in order to remove a suspect node in TcpFailureDetector. (kfujino) 54931: Add information to the Window Service how-to about installing and running multiple instances. Based on a patch by Chris Derham. (markt) 54932: Correct the link to Tribes documentation. (violetagg) Add document for o.a.c.tribes.group.interceptors.TcpFailureDetector. (kfujino)
    Update Tomcat's internal copy of Commons FileUpload to FileUpload 1.3. (markt) 54178: Protect against AsyncListener implementations that throw RuntimeExceptions in response to an event. (markt) 54791: Restore tools.jar entry in jarsToSkip property to prevent warnings when running Tomcat from Eclipse. (markt) 54851: When scanning for web fragments, directories without any web-fragment.xml should not impact the status of distributable element. Patch provided by Trask Stalnaker. (violetagg) When an error occurs during the sending of a WebSocket message, notify the Inbound side (where all the events occur that the application reacts to) that an error has occurred and that the connection is being closed. (markt) 54906: Better error message if a ConcurrentModificationException occurs while checking for memory leaks when a web application stops. Also ensure that the exception does not cause remaining checks to be skipped. Based on a patch by NateC. Allow 204 responses (no content) to include entity headers as required by RFC2616. (markt) Ensure write errors when using HTTP Upgrade with the APR/native connector result in IOExceptions rather than errors being silently swallowed. (markt) 54802: Provide location information for exceptions thrown by JspDocumentParser. (kkolinko) 54801: Do not attempt to parse text that looks like an EL expressions inside a scriptlet in a JSP document because EL expressions are not permitted in scriptlets. (kkolinko/markt) 54821: Do not attept to parse text that looks like an EL expressions in a JSP document if EL expressions have been disabled. (kkolinko/markt) 54888: Add support for CSV lists with the ForEach tag plugin. Patch provided by Sheldon Shao. (markt) Add several improvements for FarmWarDeployer. (kfujino) 54872: Correct Cluster Receiver page of Tomcat documentation. (violetagg) Document StatementCache interceptor. (kkolinko) Fix minor threading issue in ConnectionPool. (markt/kkolinko) 54732: Fix leak of statements in StatementCache interceptor. (kkolinko) Fix NPE in SlowQueryReportJmx when running TestSlowQueryReport test. (kkolinko) Update to Eclipse JDT Compiler 4.2.2. (kkolinko) 54890: Update to Apache Commons Daemon 1.0.15. (mturk) Convert remaining unit tests to JUnit 4 and enable Checkstyle rule that forbids use of methods from JUnit 3. (markt/kkolinko) Remove unneeded permissions for reading UserDataHelper properties from catalina.policy file. The class that needed those was moved in 7.0.26. (kkolinko)
    Ensure a log message is generated when a web application fails to start due to an error processing a ServletContainerInitializer. (markt) Prevent NPE in JAR scanning when running in an environment where the bootstrap class loader is not an ancestor of the web application class loader such as OSGi environments. (violetagg) Ensure that, if a call to UEncoder#encodeURL is made, all internal structures are properly cleaned. (violetagg) 54660: Enable the modification of an access log's fileDateFormat attribute while the access log is in use. The change will take effect when the next entry is made to the access log. (markt) Update Tomcat's internal copy of Commons FileUpload to FileUpload trunk, revision 1458500 and the associated extract from Commons IO to 2.4. (markt) 54702: Prevent file descriptors leak and ensure that files are closed when parsing web application deployment descriptors. (violetagg) 54707: Further relax the parsing of DIGEST authentication headers to allow for buggy clients that quote values that RFC2617 states should not be quoted. (markt/kkolinko) Enable support for MBeans with multiple operations with the same name but different signatures. (markt) Deprecate Tomcat's internal Base 64 encoder/decoder and switch to using a package renamed copy of the Commons Codec implementation. (markt) Ensure that StandardJarScanner#scan will use the provided class loader when scanning the class loader hierarchy. (violetagg) 54690: Fix a regression caused by the previous fix for 54406. If no values are specified for sslEnabledProtocols or ciphers use the default values for server sockets rather than the default values for client sockets. (markt) Correct Deployer, Manager and Context pages of Tomcat documentation. (kkolinko) 52318: Version for imported package org.apache.juli.logging is extended to include also 7.0.x versions. The fix is applicable only when running in OSGi environment. Patch provided by Martin Lichtin. (violetagg) 54599: Do not print connection password in PoolProperties.toString(). Based on a patch by Daniel Mikusa. (kkolinko) 54684: Add javax.naming.spi to Import-Package header in MANIFEST.MF in order to resolve ClassNotFoundException when running in OSGi environment. (violetagg) Update to Apache Commons Daemon 1.0.14 to resolve 54609 which meant that installation of Windows service could fail producing incorrect service launch command. (mturk) Ensure HEAD requests return the correct content length when the requested resource uses a Writer. Patch by Nick Williams. (markt)
    Ensure that the request start time (used by the access log valve to calculate request processing time) is correctly recorded for the HTTP NIO connector. In some cases the request processing time may have been longer than that recorded. (markt) Add one more library from JDK 7 to the value of jarsToSkip property in the catalina.properties file. (kkolinko) 53871: If annotation scanning results in a StackOverflowError due to broken class dependencies, add the class hierarchy that triggered the exception to the error message. (markt) Add a new option to the standard JarScanner implementation (scanBootstrapClassPath) to control if the bootstrap classpath is scanned or not. By default, it will not be scanned. (markt) Provide more consolidated servlet MBean data in the webapp MBean. (rjung) 54584: Take account of the delegate attribute when building the web application class path to pass to the JSP compiler. (markt) Copy the updated and re-packaged UTF-8 decoder from Tomcat 8.0.x and use this improved decoder for WebSocket connections. Remove the WebSocket specific UTF-8 decoder. (markt) 54602: Recycle the byte to character converter used for URIs between requests to ensure an error in one request does not trigger a failure in the next request. (markt) Use the newly added improved UTF-8 decoder for decoding UTF-8 encoded URIs and UTF-8 encoded request bodies. Invalid UTF-8 URIs will not cause an error but will make use of the replacement character when an error is detected. This will allow web applications to handle the URI which will most likely result in a 404 response. The fall-back to decoding with ISO-8859-1 if UTF-8 decoding fails has been removed. Invalid UTF-8 sequences in a request body will trigger an IOException. The way the decoder is used has also been improved. The notable change is that invalid sequences at the end of the input now trigger an error rather than being silently swallowed. (markt) 54624: Ensure that the correct request body length is used when swallowing a request body after FORM authentication prior to restoring the original request preventing possible hanging when restoring POST requests submitted over AJP. (markt) 54628: When writing binary WebSocket messages write from start position in array rather than the start of the array. Patch provided by blee. (markt) Refactor char encoding/decoding using NIO APIs. (remm) 54203: Complete the Javadoc for javax.servlet.http.Part. (markt) 54638: Fix display of "Used" memory value for memory pools on the status page in Manager web application when the page is rendered as XML. (kkolinko) Correct typos in configuration samples on SSL Configuration page of Tomcat documentation. (kkolinko) Disable support for comments on Changelog page of Tomcat documentation. (kkolinko) Fix several issues with status.xsd schema in Manager web application, testing it against actual output of StatusTransformer class. (kkolinko) Clarify the documentation on how context paths may be configured for web applications. (markt) 54601: Change catalina.sh to consistently use LOGGING_MANAGER variable to configure logging, instead of modifying JAVA_OPTS one. (kkolinko)
    54521: Ensure that concurrent requests that require a DIGEST authentication challenge receive different nonce values. (markt) 54534: Ensure that, if a call to StandardWrapper#isSingleThreadModel() triggers the loading of a Servlet, the correct class loader is used. (markt) 54536: Ensure the default error page is displayed if a custom HTTP status code is used when calling HttpServletResponse#sendError(int, String). (markt) 54456: Ensure that if a client aborts a request when sending a chunked request body that this is communicated correctly to the client reading the request body. (markt) Update the native component of the APR/native connector to 1.1.27 and make that version the recommended minimum version. (markt) 54239: Enable web applications to provide their own Expression Language interpreter to enable them to optimise processing of expressions. Based on a patch by Sheldon Shao. (markt) 54505: Create clearer links from the JNDI How-To to the Tomcat specific options for configuring JNDI resources. (markt) Update to Apache Commons Daemon 1.0.13. (markt)
    Make additional allowances for buggy client implementations of HTTP DIGEST authentication. This is a follow-on to 54060. (markt) 54438: Fix a regression in the fix for 52953 that triggered a NPE when digested passwords were used and an authentication attempt was made for a user that did not exist in the realm. (markt) 54448: Correctly handle @Resource annotations on primitives. Patch provided by Violeta Georgieva. (markt) 54450: Correctly handle resource injection when part of the servlet properties uses @Resource and the other uses injection-target. Patch provided by Violeta Georgieva. (markt) 54458: Include exception when logging errors in the DataSourceRealm. Patch provided by Violeta Georgieva. (markt) 54483: Correct one of the Spanish translations. Based on a suggestion from adinamita. (markt) Prevent the SSO deregister when web application is stopped or reloaded. When StandardManager(pathname="") or DeltaManager stops normally, all sessions in the context are expired. In this case, because most sessions is not time-out, SSO deregister was triggered. (kfujino) Include the exception in the log message if the parsing of the context.xml file fails. (markt/kkolinko) 54497: Make memory leak detection code more robust so a failure in the leak detection code does not prevent the Context from stopping unless the error is fatal to the JVM. (markt) 54507: Do not start the background thread that is used for expiring sessions (amongst other things) until the web application is fully started. Stop the background thread as soon as the web application is stopped. (markt) Allow WebSocket Ping/Pong messages to be sent between fragments of a fragmented message. (markt) 54612: Check if the socket is closed before trying to write a WebSocket message to it. Also, flush any partial buffered data before closing the socket. (markt) 54324: Allow APR connector to disable TLS compression if OpenSSL supports it. (schultz) 54406: Fix NIO HTTPS connector to prune specified ciphers and sslEnableProtocols options to those supported by the SSL implementation, sharing logic with the BIO connector. Modified ciphers and sslEnabledProtocols option pruning to not silently revert to JVM defaults when none of the options specified are supported - new behaviour is to warn and explicitly enable no options. (timw) Align NIO HTTP connector with other HTTP connectors and include leading blank lines when determining the size of the HTTP headers. (markt) 53869: Performance improvement for pages with lots of heavily nested tags. Retain a reference to the root JSP context rather than traversing the hierarchy on every call. Based on a patch suggested by Sheldon Shao. (markt) 54440: Correct a regression caused by the changes for 54240 that broke compilation of JSPs with JspC. Patch provided by Sheldon Shao. (markt) 54466: Improve error message by including the name of the file when the java file generated from a tag file cannot be compiled. Based on a patch by Sheldon Shao. (markt) Fix incorrect increment of counterSend_EVT_SESSION_EXPIRED and counterSend_EVT_CHANGE_SESSION_ID. These values are not incremented if no members active in cluster group. (kfujino) 54476: Correct error in Javadoc of GroupChannel send methods to maker clear that the minimum length of the destination member array is one, not two. (markt) Prevent SSO deregister when node shutdown normally in cluster environment. (kfujino) Check cluster member before sending replicate message in ClusterSingleSignOn. (kfujino) 54461: Improve the documentation for the compiler attribute in the Jasper how-to. (markt) Add Jespa to the list of third-party Windows authentication providers and make external links in the documentation for those providers no-follow. (markt) 54496: Don't use a hard-coded class name in MemberImpl.toString(). (markt) Update to Apache Commons Daemon 1.0.12. (markt)
    54247: Prevent ClassNotFoundExceptions on stop when running as a service. (markt) 54249: Ensure resource properties are available when the context path contains encoded characters such as a space. This triggered compilation issues in Jasper. Patch provided by Polina Genova. (markt) 54256: Improve error reporting when a JAR file fails extension validation by including the name of the JAR file in the exception. (markt) Allow web applications to be stopped cleanly even if filters throw exceptions when their destroy() method is called. (markt/kkolinko) Fix memory leak of servlet instances when running with a SecurityManager and either init() or destroy() methods fail or the servlet is a SingleThreadModel one. (kkolinko) Cleanup method cache lookup code in SecurityUtil class. (kkolinko) Make the Tomcat 7 non-JSR356 WebSocket implementation non-blocking (where supported by the connector) between the HTTP upgrade and the first WebSocket message from the client to the server. (markt) 54262: Ensure that an empty <absolute-ordering /> element in the main web.xml file disables scanning for web fragments. Based on a patch by Violeta Georgieva. (markt) 54284: As per clarification from the Servlet EG, anonymous Filters and Servlets are not permitted. Patch by Violeta Georgieva. (markt) 54371: Prevent exceptions when processing web fragments for unexpanded WAR files when the context path contains characters that need to be encoded in URLs such as spaces. Based on a patch by Polina Genova. (markt) 54372: Make HTTP Digest authentication header parsing tolerant of invalid headers sent by known buggy clients. (markt) 54377: Correctly set request attributes for AccessLog in RemoteIpFilter. Patch by Violeta Georgieva. (markt) 54379: Implement support for post-construct and pre-destroy elements in web.xml. Patch by Violeta Georgieva. (markt) 54380: Do not try to register servlets or contexts into the mapper too early (which just caused a warning to be logged). (kkolinko) Fix NPE in WebappLoader.stopInternal when stop is called after a failed start. (kkolinko) 54381: Add support for receiving WebSocket pong messages. (markt) 54382: Fix NPE when SSI processing is enabled and an empty SSI directive is present. (markt) Fix ArrayIndexOutOfBoundsException in HttpParser when parsing incorrect HTTP headers. (kkolinko) 54387: Deployment must fail when multiple servlets are mapped to the same url-pattern. (markt) 54391: Provide a value for the javax.servlet.context.orderedLibs attribute. (markt) 54248: Ensure that byte order marks are swallowed when using a Reader to read a request body with a BOM for those encodings that require byte order marks. (markt) Fix release of processors in AjpNioProtocol. Wrong object was used as a key in the connections map. (kkolinko) 54240: Add support for auto-detection and configuration of JARs on the classpath that provide tag plug-in implementations. Based on a patch by Sheldon Shao. (markt) 54241: Revert the fix for 35410 as it was not compliant with the JSP specification, specifically that <%= obj %> must be translated to out.print(obj) which in turn becomes out.write(String.valueOf(obj)). This will trigger a NullPointerException if obj.toString() returns null. The fix for 35410 incorrectly suppressed the NullPointerException in this case. (markt) 54242: Correct handle null iterations with in the JSTL ForEach tag plug-in implementation. Patch provided by Sheldon Shao. (markt) 54260: Avoid NullPointerException when using JSP unloading and tag files. (markt) 54370: Improve handling of nulls when trying to match sets of parameters to a method in EL. (markt) 54338: Correctly coerce the value to the expected type when using the tag plug-in for the JSTL set tag. Patch provided by Sheldon Shao. (markt) 54244: Clarify the documentation for the BIO and NIO SSL configuration attributes sslEnabledProtocols and sslProtocol within the documentation web application. (markt) Integrate documentation of Tomcat 7 with Apache Comments System. People can leave their comments when reading documentation online at the tomcat.apache.org site. (rjung) 54390: Use 'java_home' on Mac OS X to auto-detect JAVA_HOME. (schultz)
    53871: Improve error message if annotation scanning fails during web application start due to poor configuration or illegal cyclic inheritance with the application's classes. (markt) Fix unit test for AccessLogValve when using non-GMT time zone. (rjung) 54170: Ensure correct registration of Filters and Servlets in the JMX registry if the Filter or Servlet name includes a character that must be quoted if used in an ObjectName value. (markt) Add new attribute renameOnRotate to the AccessLogValve. (rjung) 54190: Correct unit tests for BASIC authentication so that session timeout is correctly tested. Also refactor unit test to make it easier to add additional tests. Patch by Brian Burch. (markt) 54220: Ensure the ErrorReportValve only generates an error report if the error flag on the response has been set. (markt) Simplify time zone handling in the access log valve and correctly handle various edge cases for non-standard DST changes. (markt) 54198: Clarify that HttpServletResponse.sendError(int) results in an HTML response by default. (markt) 54207: Correct JNDI factory package name in Javadoc for org.apache.naming.java.javaURLContextFactory. (markt) Fix a handful of Eclipse warnings in the JDBC pool source code including the warnings reported in 53565. (markt) 54150: Make sure that SlowQueryReportJmx mbean deregistered during webapp shutdown. Reported by Alex Franken. (kfujino) 54194: Make sure that connection pool mbean is not registered when jmxEnabled is false. Patch provided by tobias.gierke. (kfujino) Update to Eclipse JDT Compiler 4.2.1. (markt)
    53960, 54115: Extensions to HttpClient test helper class. Patches by Brian Burch. (markt/kkolinko) 53993: Avoid a possible NPE in the AccessLogValve when the session ID is logged and a session is invalidated. (markt) Add support for LAST_ACCESS_AT_START system property to PersistentManager. (kfujino) Update MIME type mapping with additional / updated mime.types from the Apache web server. (markt) 54007: Fix a memory leak that prevented deletion of a context.xml file associated with a Context that had failed to deploy. Also fix the problems uncovered with undeploying such a Context once the leak had been fixed and the file could be deleted. (markt) 54044: Correct bug in timestamp cache used by logging (including the access log valve) that meant entries could be made with an earlier timestamp than the true timestamp. (markt) 54054: Do not share shell environment variables between multiple instances of the CGI servlet. (markt) 54060: Use a simple parser rather than a regular expression to parse HTTP Digest authentication headers so the header is correctly parsed. The new approach is also faster and generates less garbage. (markt) 54068: Rewrite the web fragment ordering algorithm to resolve multiple issues that resulted in incorrect ordering or failure to find a correct, valid order. (markt) The HTTP header parser added to address 52811 has been removed and replaced with the light-weight HTTP header parser created to address 54060. The new parser includes a work-around for a bug in the Adobe Acrobat Reader 9.x plug-in for Microsoft Internet Explorer that was identified when the old parser was introduced (53814). 54076: Add an alternative work-around for clients that use SPNEGO authentication and expect the authenticated user to be cached per connection (Tomcat only does this if an HTTP session is available). (markt) 54087: Correctly handle (ignore) invalid If-Modified-Since header rather than throwing an exception. (markt) 54096: In web.xml, <env-entry> should accept any type that has a constructor that takes a single String or char. (markt) 54127: Add support for sending a WebSocket Ping. Patch provided by Sean Winterberger. (markt) In FormAuthenticator: If it is configured to change Session IDs, do the change before displaying the login form. (kkolinko) Ensure AsyncListener.timeout() and AsyncListener.complete() are called with the correct thread context class loader. (fhanik) 54123: If an asynchronous request times out without any AsyncListeners defined, a 500 error will be triggered. (markt) 54124: Correct provided value of request attribute javax.servlet.async.request_uri and add missing request attribute javax.servlet.async.path_info. (markt) Add denyStatus initialization parameter to CsrfPreventionFilter, allowing to customize the HTTP status code used for denied requests. (kkolinko) 54141: Increase the permitted number of nested Realm levels from 2 to 3 by default and make the limit configurable via a system property. (markt) Revert occasional API change in BaseDirContext class that was done in 7.0.32. Methods should not be final. (kkolinko) Prevent failures in the AccessLogValve when running under a SecurityManager and the first request received is an asynchronous one. (markt) Correct an issue that prevented WebSockets from being used over SSL when using the HTTP NIO connector. (markt) 54022: Ensure the Comet END event is triggered on client disconnect with APR/native on Windows Vista/2k8 or later. Patch provided by Douglas Beachy. (markt) 54067: Ensure responses with 1xx response codes are correctly marked as not containing an entity body. This caused an issue for some WebSocket clients when an Transfer-Encoding header was sent with the 101 (HTTP upgrade) response. (markt) 53867: Optimise the XML escaping provided by the PageContext implementation. Based on a patch by Sheldon Shao. (markt) 53896: Use an optimised CompositeELResolver for Jasper that skips resolvers that are known to be unable to resolve the value. Patch by Jarek Gawor. (markt) 53986: Correct a regression introduced by the fix for 53713. JSP comments that ended with the sequence ---%> (or any similar sequence with a odd number of - characters) was not correctly parsed. (markt) 54011: Fix a bug in the tag plug-in for <c:out> that triggered a JSP compilation error if the escapeXml attribute was used. Patch provided by Sheldon Shao. (markt) Follow up to 54011. Simplify generated code for <c:out>. Based on a patch by Sheldon Shao. (markt) 54012: Fix a bug in the tag plug-in infrastructure that meant the <c:set> triggered a JSP compilation error when used in a tag file. Based on a patch provided by Sheldon Shao. (markt) 54017: Simplify coercion of String instances to Object. (markt) 54144: Fix a bug in the tag plug-in for <c:out> that meant that if the value of the tag evaluated to a java.io.Reader object then it was not correctly handled. (markt) Add getSessionIdsFull operation to mbeans-descriptor. listSessionIdsFull no longer exist. (kfujino) 54086: Fix threading issue when stopping an NioReceiver. (markt) 54143: Add display of the memory pools usage (including PermGen) to the Status page of the Manager web application. (kkolinko) 54045: Make sure getMembers() returns available member when TcpFailureDetector works in static cluster. (kfujino)
    Revert multiple operation support for the JMXProxyServlet pending further discussion. (schultz) CVE-2012-4431: Fix bypass of CsrfPreventionFilter when there is no session. Improve session management in the filter. (kkolinko) Correct the couple of broken links in the Tomcat Javadoc. (markt) Update optional Checkstyle library to 5.6. (kkolinko)
    Add one library from JDK 7 to the value of jarsToSkip property in the catalina.properties file. (kkolinko) 52777: Add an option to automatically remove old, unused versions (ones where there are no longer any active sessions) of applications deployed using parallel deployment. (markt) 53828: Use correct status code when closing a WebSocket connection normally in response to a close frame from a client. (markt) JMXProxyServlet now allows multiple operation commands like invokeAndSet, invokeAndGet, etc. (schultz) Note: reverted in 7.0.32. 53843: request.isAsyncStarted() must continue to return true until the dispatch actually happens (which at the earliest isn't until the thread where startAsync() was called returns to the container). (markt) 53863: Ensure the the implicit servlets (JSP and default) are marked as override-able when using embedded mode. (markt) When the DefaultServlet is under heavy load, the HTTP header parser added to address 52811 generates large amounts of garbage and uses significant CPU time. A cache has been added that significantly reduces the overhead of this parser. (markt) 53854: Make directory listings work correctly when aliases are used. (markt) 53713: Performance improvement of up to four times faster parsing of JSP pages. Patch provided by Sheldon Shao. (markt) Make the cluster members and the cluster deployer associated with the cluster accessible via JMX. (markt) Fix a behavior of TcpPingInterceptor#useThread. If set to false, ping thread is never started. (kfujino) Improve the documentation web application to clarify the difference between the tag and version parameters when using text interface of the Manager web application. (markt) Make sessions saved in the Store associated with a Manager that extends PersistentManager optionally visible (via the showProxySessions Servlet initialisation parameter in web.xml) to the Manager web application. (markt)
    Automatically delete temporary files used by Servlet 3.0 file upload (for parts which size is greater than file-size-threshold option in web.xml) when request processing completes. (kkolinko) 53071: This additional fix for this issue improves the formatting of Jasper errors (or any exceptions that use a multi-line message) with the ErrorReportValve. (markt) 53469: If a URL passed to javax.servlet.http.HttpServletResponse.encodeURL() cannot be made absolute, never encode it and return it unchanged. Previously, the fix for 53062 meant than an IllegalArgumentException was thrown. (markt) 53481: Added support for SSLHonorCipherOrder to allow the server to impose its cipher order on the client. Based on a patch provided by Marcel Šebek. This feature requires Tomcat Native 1.1.25 or later. (schultz) 53498: Fix atomicity bugs in use of concurrent collections. Based on a patch by Yu Lin. (markt) Correct a regression in the previous fix for 53062 that did not always correctly normalize redirect URLs when the redirect URL included a query string or fragment component. (markt) Add missing getter and setter for roleSearchAsUser option on JNDI Realm. (markt) Add some HTTP status codes registered at IANA. (rjung) 53531: Fix ExpandWar.expand to check the return value of File.mkdir and File.mkdirs. (schultz) 53535: Reduce memory footprint when performing class scanning on Context start. Patch provided by Cedomir Igaly. (markt) 53541: Fix JAR scanning when WEB-INF/lib is provided via VirtualDirContext. Patch provided by Philip Zuev. (markt) 53574: Ensure Servlets defined using jsp-file are available when metadata-complete is true. (markt) 53584: Ignore path parameters when comparing URIs for FORM authentication. This prevents users being prompted twice for passwords when logging in when session IDs are being encoded as path parameters. (markt) 53623: When performing a asynchronous dispatch after series of forwards, ensure that the request properties are correct for the request at each stage. (markt) 53624: Ensure that HttpServletResponse.sendRedirect() works when called after a dispatch from an AsyncContext. (markt) 53641: Correct name of HTTP header used in WebSocket handshake for listing the preferred protocols. (markt) Document the constants that were added to the RequestDispatcher interface in Servlet 3.0. (kkolinko) Ensure custom error pages are not truncated if the page that triggered the error set a content length header. (markt) 53677: Ensure that a 500 response rather than no response is returned if the HTTP headers exceed the size limit. (markt) 53702: When merging web.xml fragments, allow for <jsp-property-group> elements having multiple <url-pattern> elements. (markt) Always make the resulting web.xml available even if metadata-complete is true. (markt) 53714: Provide separate system properties to control which JARs are excluded from which scans when using the JarScanner. This allows JARs to be excluded from all scans or only from TLD scanning and/or Servlet 3.0 pluggability scanning. (markt) Add several JDK libraries to the value of jarsToSkip property in the catalina.properties file. (markt, kkolinko) Fix typos etc. in the code that logs merged web.xml (as enabled by logEffectiveWebXml option on Context). (kkolinko) 53758: When adding filters via FilterRegistration.Dynamic the filters were added at the wrong point because the isMatchAfter logic was inverted. (markt) 53783: Correctly handle JARs generated by tools that do not create specific entries for directories. Patch provided by Violeta Georgieva. (markt) Improvements to DIGEST authenticator including the disabling caching of authenticated user in session by default, tracking server rather than client nonces and better handling of stale nonce values. (markt) Improve performance of DIGEST authenticator for concurrent requests. (markt) CVE-2012-3546: Fix bypass of security constraint checks with FORM authentication. Remove unneeded processing in RealmBase. (kkolinko) 53800: FileDirContext.list() did not provide correct paths for subdirectories. Patch provided by Kevin Wooten. (kkolinko) 53801: Overlapping URL patterns were sometimes merged incorrectly in security constraints leading to incorrect 401 responses. Note: it was possible for access to be denied when it should have been granted but it was not possible for access to be granted when it should have been denied. (markt) Remove the socket.soTrafficClass from the BIO and NIO HTTP and AJP connectors because any use of the option is either ignored or in some cases (Java 7 with NIO) throws an Exception. (mark) Prevent possible NPE when processing Comet requests during Connector shutdown. (markt) 42181: Better handling of edge conditions in chunk header processing. (kkolinko) 53697: Correct a regression in the fix for 51881 that mean that in some circumstances the comet flag was not reset on HttpAprProcessor instances. This caused problems when the Processor was re-used for a new connection that would trigger a NullPointerException and could result in a JVM crash. (markt) 53725: Fix possible corruption of GZIP'd output. (markt/kkolinko) Better parsing of line-terminators for requests using chunked encoding. (markt) Further improvements to handling of Comet END events when the connector is stopped. (markt) 53545: Ensure buffered data is cleared when using a jsp:forward action inside a classic custom tag. (markt) 53654: Support file:// URLs for JSP dependencies. Patch provided by Viola Lu. (markt) 53792: Support MethodExpressions that include a method invocation that is not at the end of the expression. (markt) Fix an issue when running under Java 7 which throws exceptions when trying to set an invalid option whereas Java 6 silently swallowed them. The option using the problem was soTrafficClass. Investigations showed that this option had no effect for Cluster Channel Receivers so it was removed. (markt) 53513: Fix race condition between the processing of session sync message and transfer complete message. (kfujino) Update JSTL version information in the JNDI section of the documentation web application. (markt) 53524: Correct a typo in the cluster how-to section of the documentation web application. Also fix a handful of spelling errors. (markt) 53601: Clarify in documentation that building Apache Tomcat 7 from sources requires a Java 6 JDK. (kkolinko) 53653: Allow for wrapped source code example in config/context.html. Patch provided by Terence Bandoian. (schultz) 53793: Change links on the list of applications in the Manager to point to '/appname/' instead of '/appname'. (kkolinko) Avoid potential NPE identified by Find Bugs in org.apache.catalina.tribes.io.ReplicationStream. (markt) 53606: Fix potential NPE in TcpPingInterceptor. Based on a patch by F. Arnoud. (markt) 53607: To avoid NPE, set TCP PING data to ChannelMessage. Patch provided by F.Arnoud (kfujino) 53701: Javadoc fixes. Patch provided by sebb. (markt) Remove some unused code from Tomcat's package renamed, cut-down copy of Commons BCEL used for annotation scanning. (markt) 53735: Add support for Java 7 byte code to Tomcat's package renamed, cut-down copy of Commons BCEL used for annotation scanning. (markt)
    Add support for searching for roles in JNDI/LDAP using another value than the actual DN or username specified. Rather it will use a value from the users directory entry. The new attribute introduced to the JNDIRealm is userRoleAttribute (fhanik) Fix checking of recommended tcnative library version when using the APR connector. (rjung) 50306: Improve StuckThreadDetectionValve: add stuckThreadNames property as a pair for the stuckThreadIds one, add thread ids to the log messages. (kkolinko) 52135: Add support for a default error page to be defined in web.xml by defining an error page with just a nested location element. It appears this feature was intended to be included in the Servlet 3.0 specification but was accidently left out. (markt) 53450: Correct regression in fix for 52999 that could easily trigger a deadlock when deploying a ROOT web application. (markt) As per section 1.6.2 of the Servlet 3.0 specification and clarification from the Servlet Expert Group, the servlet specification version declared in web.xml no longer controls if Tomcat scans for annotations. Annotation scanning is now always performed - regardless of the version declared in web.xml - unless metadata complete is set to true. (markt) 53619: As per clarification from the Servlet Expert Group, JARs will always be scanned for ServletContainerInitializers regardless of the setting of metadata complete. However, if an absolute ordering is specified and a JAR is excluded from that ordering it will not be scanned for ServletContainerInitializers nor will it be scanned for matches to any HandleTypes annotations. (markt) 53465: Populate mapped-name property for resources defined in web.xml. Based on a patch by Violeta Georgieva. (markt) Make the request available when establishing a WebSocket connection. (markt) 53467: Correct a regression in the fix for 53257 that introduced problems for JSPs that used characters that must be encoded if used in a URI. (markt) 53430: Avoid a JVM crash when a connector that requires the APR/native library is explicitly specified and the library, or a recent enough version of it, is not available. (markt) 53421: Provide a more helpful error message if a getter or setter cannot be found for a bean property when using expression language. (markt) 53460: Allow container to handle errors if the creation of the PageContext fails rather than swallowing the error. (markt) Update the WebSocket examples in the examples web application so that they work with secure connections (wss) as well as non-secure (ws) connections. (markt) 53456: Minor corrections and improvements to the HTTP connector configuration reference. Patch provided by sebb. (markt) 53459: Correction and clarifications to the SSL Connector configuration examples in the SSL how-to. (markt) 53464: Correct reference to sample init.d script for use with jsvc in the documentation web application. (markt) 53473: Correct the allowed values for the SSI option isVirtualWebappRelative which are true or false. (markt) Document roleNested property of JNDIRealm in Configuration Reference. (kkolinko) 53445 (1354173): Allow configurable name for SlowQueryReportJmx (fhanik) 53416 (1354641): Multiple pools with the same name should register under JMX (fhanik) Fix cleanup of temporary files in TestNamingContext test. (kkolinko) Remove a few files from the source distribution that are not required since they are copied / generated during the build. (markt) Add manifest files to the set of files for which the line-ending is changed to match the OS defaults in the source distributions. (markt) Align Jk Ant tasks definitions between antlib.xml and catalina.tasks files, introducing jkupdate as synonym for jkstatus. The latter one is deprecated. Simplify bin/catalina-tasks.xml, replacing taskdef with typedef and adding Ant condition implementations used with JMX to jmxaccessor.tasks file. (kkolinko) 53454: Return correct content-length header for HEAD requests when content length is greater than 2GB. (markt)
    52055: An additional fix to ensure that the ChunkedInputFilter is correctly recycled. (markt) 52954: Make DIGEST authentication tolerant of clients (mainly older Android implementations) that do not follow RFC 2617 exactly. (markt) 52955: Implement custom thread factory for container start-stop thread pool. It allows to use daemon threads and give them more distinct names. (kfujino) 52999: Remove synchronization bottleneck from the firing of Container events. (markt) 53008: Additional test cases for BASIC authentication and RFC2617 compliance. Patch provided by Brian Burch. (markt) 53021: Correct WebSocket protocol version detection. (pero) Add new attributes of allow and deny to UserConfig. (kfujino) 53024: Fix context reloading so requests received during the reload are paused and processed when reloading completes rather than receiving 404 responses. (markt) Improve the handling of watched resources so that changes trigger a reload rather than a stop followed by a start which allows requests received to be paused and processed when reloading completes rather than receiving 404 responses. (markt) Remove potential bottleneck on creation of new WebSocket connections. (markt) 53047: If a JDBC Realm or DataSource Realm is configured for an all roles mode that only requires authorization (and no roles) and no role table or column is defined, don't populate the Principal's roles. (markt) 53056: Add APR version number to tcnative version INFO log message. (schultz) 53057: Add OpenSSL version number INFO log message when initializing. (schultz) Save a bit of memory in annotations cache in DefaultInstanceManager by trimming annotation lists to their size. (kkolinko) Correctly configure the parser used to process server.xml so that external entities may be used to include the content of external files into server.xml. (markt) Make sure ContextMBean#findFilterDefs returns correct filter definitions. (kfujino) Ensure that maxParameterCount applies to multi-part requests handled via the Servlet 3 file upload API. (markt) 53062: When constructing absolute URLs for redirects from relative URLs ensure that the resulting URLs are normalized. (markt) 53067: Ensure the WebSocket Servlet continues to work when requests are wrapped. (markt) Enable host's xmlBase attribute in ContextConfig. (kfujino) 53071: Use the message from the throwable (if there is one) when generating the report in the ErrorReportValve and no message has been specified via sendError(). (markt) 53074: Switch to an infinite socket timeout by default for WebSocket connections. (markt) 53081: Do not always cache resources loaded by the web application class loader since they may be very large which in turn could trigger a memory leak. Calls to the web application class loader's getResourceAsStream() method will now access the resource directly rather than via the cache in most cases. (markt) 53090: Include superclasses when considering injection targets. Patch provided by Borislav Kapukaranov. (markt) 53161: Provide a better error message if a ClassFormatException occurs during annotation scanning and do not prevent the web application from starting in this case. (markt) 53180: Improve check for setter method when processing annotations. Patch provided by Violeta Georgieva. (markt) 53225: Fix an IllegalStateException due to the JAR file being closed when accessing static resources in a JAR file when urlCacheProtection="false" in the JreMemoryLeakPreventionListener. (markt) 53230: Changed ManagerBase to throw TooManyActiveSessionsException instead of IllegalStateException when the maximum number of sessions has been exceeded and a new session will not be created. (schultz) 53257: Ensure that resources, including JSP files, that have names that include characters with special meanings in URLs (such as ampersand, semicolon, plus, hash and percent) are correctly handled. This bug is partially a regression caused by the original fix for 51584 and partially an existing issue that had not previously been identified. This fix reverts the original fix for 51584, correctly fixes that issue and fixes the additional issues identified by the test cases that were also added as part of this fix. (markt/kkolinko) 53266: If a class specified in a @HandlesTypes annotation on a ServletContainerInitializer is missing log a more helpful message and do not prevent the web application from starting. (markt) 53267: Ensure that using the GC Daemon Protection feature of the JreMemoryLeakPreventionListener does not trigger a full GC every hour. (markt) 53285: Do not require security-role-ref elements to contain a role-link element. (markt) 53301: Prevent double initialization of pre-created Servlet instances when used in embedded mode. (markt) 53322: When processing resource injection, correctly infer property name from its setter method if the name starts with several uppercase characters. (kkolinko) 53333: When processing JNDI resources, take account of the types of any specified injection targets to ensure that the resource definition and the injection target types are consistent. Based on a patch provided by Violeta Georgieva. (markt) 53337: Forwarding via a RequestDispatcher to an asynchronous Servlet always failed. Includes a test case based on code by Rossen Stoyanchev. (markt) 53339: Ensure WebSocket call backs (onOpen etc.) are called using the web application's class loader. (markt) 53342: To avoid BindException, make startStopThreads into a demon thread. (kfujino) 53353: Make the internal HTTP header parser more tolerant of Content-Type values that contain invalid parameters by ignoring the invalid parameters. It is a followup to bug 52811. (markt) 53354: Correctly handle @WebFilter annotations that do not include a mapping. (markt) 53356: Add support for servlets mapped explicitly to the context root of a web application. (markt) 53366: Ensure new HTTP header parser works correctly when running Tomcat under a security manager. (markt/kkolinko) 53368: Configure the default security policy to allow web applications to use WebSocket when running under a security manager. (markt/kkolinko) 53373: Allow whitespace around delimiters in <Context> aliases for readability. (schultz) 52858, CVE-2012-4534: Correct fix for high CPU load. (fhanik) 53138: Broken Sendfile on SSL introduced in 7.0.27 (fhanik) 52055: Additional fix required to ensure that InputFilters are recycled between requests. (markt) 53061: Fix a problem in the NIO connector whereby if the poller was under low but consistent load (>1 request/per second and always less than 1 second between requests) timeouts never took place. (markt) 53063: When using an Executor with BIO, use the executor's maxThreads as the default for maxConnections. (markt) 53119: Prevent buffer overflow errors being reported when a client disconnects before the response has been fully written from an AJP connection using the APR/native connector. (markt) 53169: Allow developers to avoid chunked encoding for a response of unknown length by setting the Connection: close header. Based on a patch suggested by Philippe Marschall. (markt) 53173: Properly count down maxConnections (fhanik) Update default value of pollerThreadCount for the NIO connector. The new default value will never go above 2 regardless of available processors. (fhanik) Allow to retrieve the current connectionCount via getter from the endpoint and as JMX attribute of the ThreadPool mbean. (rjung) Correct an edge case where Comet END events were not send to connected clients when the Tomcat connector was stopped. (markt) 53406: Fix possible stack overflow on connection close when using Comet. (fhanik) Improve InternalNioInputBuffer.parseHeaders(). (kkolinko) Implement maxHeaderCount attribute on Connector. It is equivalent of LimitRequestFields directive of Apache HTTPD. Default value is 100. (kkolinko) 48097#c7, 53366#c1: If JSP page unexpectedly fails to initialize PageContext instance, write exception to the logs instead of silent swallowing. (kkolinko) 53032: Modify JspC so it extends org.apache.tools.ant.Task enabling it to work with features such as namespaces within build.xml files. (markt) Avoid NPE when reload if a state of a BackupManager is FAILED. (kfujino) 53087: In order to avoid that a backup node expire a session, replicate session access time in BackupManager. (kfujino) Add support for SecureRandom to cluster manager template. (kfujino) Remove obsolete bug warning from Windows service documentation page. (rjung) 50182: Various improvements to the Compression Filter. Patch provided by David Becker. (markt) 52853: Clarify how Jar Scanner handles directories. (markt) 53158: Fix documented defaults for DBCP. Patch provided by ph.dezanneau at gmail.com. (rjung) 53203: Correct documentation for the default value of connectionTimeout attribute for AJP protocol connectors. (kkolinko) 53289: Clarify ResourceLink example that uses DataSource.getConnection(username, password) method. Not all data source implementations support it. (kkolinko) Fix several HTML markup errors in servlets of examples web application. (kkolinko) 53398: Correct spelling of "received" in the Manager application's XML output. (markt) 53403: Update a reference to the Servlet specification in the first web applciation section of the documentation web application to include newer versions of the specificarion. (markt) 50864 (1311844): JMX enable most pool properties (fhanik) 53254 (1340160): Add in the ability to purge connections from the pool (fhanik) 53367 (1346691): Prevent pool from hanging during database failure (fhanik) When a connection is reconnected due to failed validation make sure the ConnectionState is reset or it will assume incorrect values (fhanik) 53374 (1348056): Add support for the following properties in DataSourceFactory: commitOnReturn, rollbackOnReturn, useDisposableConnectionFacade, logValidationErrors and propagateInterruptState. Based on patch proposed by Suresh Avadhanula. (kkolinko) Update to Eclipse JDT Compiler 3.7.2 at maven tomcat-jasper.pom. (pero) Update the native component of the Tomcat APR/native connector to 1.1.24. (markt) Add missing dependencies in pom files. (markt) 53034: Add project.url and project.licenses sections to the POMs for the Maven artifacts. (markt) Properly mention jsp_2_2.xsd in the main LICENSE and INSTALLLICENSE files. (kkolinko) 53115: Fix using the command "catalina.bat run" when the value of %TEMP% contains spaces. (kkolinko) Add dependencies and description to "validate" target in build.xml, so that it could be run separately. Improve BUILDING.txt and RUNNING.txt. (kkolinko)
    Explicitly ignore empty path values in virtualClasspath attribute of VirtualWebappLoader class. Document that whitespace around the values is trimmed. Reformat documentation examples to make them more readable. (kkolinko) Further improve fix for 51197 to allow an error reporting Valve to write a response body if sendError() is called during an asynchronous request on a container thread. (markt) Correct fix for 51741 (1307600): If VirtualDirContext class is configured with non-empty value of extraResourcePaths option (a feature added in 7.0.24), do not implicitly set allowLinking option to the value of true. If it is really needed, it should be set explicitly. (kkolinko) 52500: Added configurable mechanism to retrieve user names from X509 client certificates. Based on a patch provided by Michael Furman. (schultz) 52719: Fix a theoretical resource leak in the JAR validation that checks for non-permitted classes in web application JARs. (markt) Code clean-up identified by 52723, 52724, 52726, 52727, 52729, 52731 and 52732. (markt) 52792: Improve error message when a JNDI resource can not be found. (markt) 52811: Fix parsing of Content-Type header in HttpServletResponse.setContentType(). Introduces a new HTTP header parser that follows RFC2616. (markt/kkolinko) 52830: Correct JNDI lookups when using javax.naming.Name to identify the resource rather than a java.lang.String. (markt) 52833: Handle the case where the parent class loader for the Catalina object does not have the system class loader in its hierarchy. This may happen when embedding. Patch provided by olamy. (markt) 52839: Add a unit test for DigestAuthenticator and SingleSignOn. Patch provide by Brian Burch. (markt) 52846: Make sure NonLoginAuthenticator registers not MemoryUser but GenericPrincipal into a session when UserDatabaseRealm is used. (kfujino) 52850: Extend memory leak prevention and detection code to work with IBM as well as Oracle JVMs. Extend unit tests to check direct and indirect ThreadLocal memory leak detection. Based on a patch provided by Rohit Kelapure. (markt) Add support for the WebSocket protocol (RFC6455). Both streaming and message based APIs are provided and the implementation currently fully passes the Autobahn test suite. Also included are several examples. A significant contribution to this new functionality was provided by Johno Crawford — particularly the examples. Contributions were also provided by Petr Praus, Jonathan Drake & Slávka. (markt) When stopping a Context, ensure that any Servlets registered with JMX are unregistered. (markt) Make the implementation of Catalina.getParentClassLoader consistent with similar methods across the code base and have it return the system class loader if no parent class loader is set. (markt) 52953: Ensure users can authenticate when using DIGEST authentication with digested passwords if the digested password is stored using upper case hexadecimal characters since DIGEST authentication expects digests to use lower case characters. Based on a patch provided by Neale Rudd. (markt) 52957: Ensure that a Valve implements Lifecycle before calling any Lifecycle methods on that Valve. (markt) 52958: Fix MBean descriptors for org.apache.catalina.realm package. (markt) 52974: Fix NameNotFoundException when field/method is annotated with @Resource annotation. Patch provided by Violet Agg. (markt) Add support for multi-thread deployment in UserConfig. (kfujino) Correctly register NIO sockets with poller after processing Comet events to ensure that no read events are missed. This fixes an intermittent issue observed in the unit tests. (fhanik/markt) 52770: Fix a bug in the highly unlikely circumstance that an infinite timeout was specified for writing data to a client when using NIO. (markt) 52858: Fix high CPU load with SSL, NIO and sendfile when client breaks the connection before reading all the requested data. (markt) 52926: Avoid NPE when an NIO Comet connection times out on one thread at the same time as it is closed on another thread. (markt) Include port number when known in connector name when logging messages from connectors that use automatic free port allocation. (markt) Don't try an unlock the acceptor thread if it is not locked. This is unlikely to impact normal usage but it does fix some unit test issues. (markt) When using the APR connector ensure that any connections in a keep-alive state are closed when the connector is stopped rather than when the connector is destroyed. This is important when stop() followed by start() is called on the connector. (markt) 52725: Use configurable package name for tags rather than hard-coded value so configuration actually works. (markt) 52758: Implement additional interface methods in Eclipse JDT integration required for Jasper to correctly with the latest Eclipse development code. (markt) 52772: Ensure uriRoot is fully validated before it is used. Patch based on a suggestion by Eugene Chung. (markt) 52776: Refactor the code so JspFragment.invoke cleans up after itself. Patch provided by Karl von Randow. (markt) 52970: Take account of coercion rules when invoking methods via EL. (markt) 52998: Partial fix. Remove static references to the EL expression factory and use per web application references instead. (markt) 52998: Remainder of fix. Cache the class to use for the EL expression factory per class loader. (kkolinko) 53001: Revert the fix for 46915 since the use case described in the bug is invalid since it breaks the EL specification. (markt) Replicate principal in ClusterSingleSignOn. (kfujino) 52760: Fix expires filter mime type in javascript examples. (rjung) 52842: Exception in MBeanDumper when dumping MBean for StandardThreadExecutor. (rjung) Bring built-in mime types for embedded Tomcat more in line with the ones defined in the default web.xml configuration file. (rjung) Add support to the JMXProxyServlet which is part of the Manager application for fetching a specific key from a CompositeData value. Updated documentation, so that the entire 'get' command for the JMX proxy servlet is documented, including the new optional 'key' parameter. (schultz/markt) Pool cleaner thread should be created using the classloader that loaded the pool, not the context loader (fhanik) 52804: Make pool properties serializable and cloneable. (fhanik) 51237 (1302902): Slow Query Report should log using WARN level when queries are slow and within the threshold of caching it. (fhanik) 52002 (1302948): Add in configuration option to disallow connection reuse. (1305862): useDisposableConnectionFacade is by default enabled (fhanik) 52493 (1302969): Java 7 DataSource method addition. (fhanik) 51893 (1302990): Throw an error and notification when pool is exhausted. (fhanik) 50860 (1303031): Add in option to configure logging for validation errors. (fhanik) 52066 (1305931): Add in configuration option, progagateInterruptState, to allow threads to retain the interrupt state. (fhanik) 52750: Fix the way how daemon.sh parses command options so that more then one can be provided. (mturk) Rearrange validate-eoln target in build.xml so that it could be run ahead of compilation. (kkolinko) Update Apache Commons Daemon to 1.0.10. (mturk) Update the native component of the Tomcat APR/native connector to 1.1.23 and take advantage of the simplified distribution. (mturk) Update to Eclipse JDT Compiler 3.7.2. (markt)
    Provide constants for commonly used Charset objects and use these constants where appropriate. (markt) Refactor the fix for 52184 to correct two issues (a missing class and incorrect class/method names) when using the extras logging packages. (markt) 52444: Only load classes during HandlesTypes processing if the class is a match. Previously, every class in the web application was loaded regardless of whether it was a match or not. (markt) 52488: Correct typo: exipre -> expire. (markt) Add a unit test for SSO authentication. Patch provided by Brian Burch. (markt) 52511: Correct regression in the fix for 51741 that caused a harmless exception to be logged when scanning for annotations and WEB-INF/classes did not exist. (markt) Refactor to remove a circular dependency between org.apache.catalina and org.apache.naming. (markt) Remove some initialisation code from the standard start process (i.e. via the scripts) that was intended for embedding but is not required when performing a standard start.(markt) Add new method to MBeanFactory that allows any Valve to be created and deprecate the methods to create specific Valves. (markt) Partial sync of MIME type mapping with mime.types from the Apache web server. (rjung) 52577: Fix a regression in the fix for 52328. Prevent output truncation when reset() is called on a response. (mark) 52586: Remove an old and now unnecessary hack that modified the path info reported via the javax.servlet.forward.path_info request attribute when forwarding to an error page. (markt) 52587: Ensure that if it is necessary to fall back to the default NullRealm, the NullRealm instance is created early enough for it to be correctly initialised. (markt) Fix millisecond output in AccessLogValve when using a SimpleDateFormat based time pattern. (rjung) 52591: When dumping MBean data, skip attributes where getters throw UnsupportedOperationException. (markt) 52607: Ensure that the extension validator checks the JARs in the shared and common class loaders for extensions. (markt) Correct a threading issue in the generation of the list of standard authenticators during Context initialization that could lead to a web application failing to start if Contexts were started in parallel. (markt) 52669: Correct regression that broke annotation processing in /WEB-INF/classes for web applications deployed as WARs, packageless classes and some embedding scenarios. The regression was introduced by the invalid assumptions made in the fix for 51741. (markt) 52671: When dumping MBean data, skip attributes where getters throw NullPointerException. (markt) 51543: Provide a meaningful error message when writing more response headers than permitted. (markt) 52547: Ensure that bytes written (which is used by the access log) is correctly reset after an HTTP 1.0 request has been processed. (markt) Minor refactoring to reduce code duplication in the HTTP connectors. (markt) 52606: Ensure that POST bodies are available for reply after FORM authentication when using the AJP connectors. (markt) 52474: Ensure that leading and trailing white space is removed from listener class names when parsing TLD files. (markt) 52480: When converting class path entries from URLs to files/directories, ensure that any URL encoded characters are converted. Fixes JSP compilation with javac when Tomcat is installed at a path that includes spaces. (markt) 52666: Correct coercion order in EL when processing the equality and inequality operators. (markt) Improve BUILDING.txt. Update instructions for building. Add instructions for using Checkstyle and running the tests. (kkolinko) 38216: Improve handling of null return values in the JMX proxy servlet which is part of the Manager application. (kkolinko) 52515: Make it clear in the Realm how-to in the documentation web application that digested password storage when using DIGEST authentication requires that MD5 digests are used. (markt) 52634: Fix typos in JSP examples. Patch provided by Felix Schumacher. (rjung) 52641: Remove mentioning of ldap.jar from docs. Patch provided by Felix Schumacher. (rjung) Fix code style issues and enable Checkstyle checks for jdbc-pool when it is built within Tomcat. (kkolinko) 51582 Correct set and reset the query cache to avoid NPE (fhanik) Update Commons Daemon to 1.0.9 to resolve 52548 which meant that services created with service.bat did not set the catalina.home and catalina.base system properties. (markt) Implement check for correct end-of-line characters in the source files. It is run as separate target in build.xml. (kkolinko)
    Restore format of the first line of error message for JMX proxy servlet in case scripts were depending on it. (markt) When building a Windows installer do not copy whole "res" folder to output/dist, but only the files that we need. Apply fixcrlf filter only after the files are copied, so that INSTALLLICENSE file had correct line ends. (kkolinko) Remove res/License.rtf. The file that is actually shown by the Windows installer is res/INSTALLLICENSE. (kkolinko) Automate the OpenPGP signature generation for the release process. (markt) Don't exclude directories named target from the build process. (rjung)
    52184: Provide greater control over the logging of errors triggered by invalid input data (i.e. data over which Tomcat has no control). (markt/kkolinko) 52225: Fix ClassCastException in an Alias added to existing host through JMX. (kkolinko) Do not throw IllegalArgumentException from parseParameters() call when chunked POST request is too large, but treat it like an IO error. The FailedRequestFilter filter can be used to detect this condition. (kkolinko) 52245: Don't allow web applications to package classes from the javax.el package. Patch provided by pid. (markt) 52259: Fix regression caused by the addition of the threaded component start (46264) that triggered a deadlock on startup if no Realm was configured. (markt) 52293: Correctly handle the case when antiResourceLocking is enabled at the Context level when unpackWARs is disabled at the Host level. Based on a patch by Justin Miller. (markt) In ExtendedAccessLogValve when printing %-encoded value of a parameter, use UTF-8 encoding to convert parameter value to bytes instead of platform default encoding. (markt/kkolinko) 52303: Allow web applications that do not have a login configuration to participate in a SSO session. Patch provided by Brian Burch. (markt) 52316: When using sendfile, use the number of bytes requested to be written to the response in the access log valve for bytes written rather than recording a value of zero. (markt) 52326: Reduce log level for class loading errors during @HandlesTypes processing to debug. (markt) 52328: Improve performance when large numbers of single characters and/or small strings are written to the response via a Writer. (markt) 52384: Do not fail with parameter parsing when debug logging is enabled. (kkolinko) Do not flag extra '&' characters in parameters as parse errors. (kkolinko) Reduce log level for the message about hitting maxParameterCount limit from WARN to INFO. (kkolinko) 52387: Ensure that the correct host is used when configuring logging when Tomcat is embedded. Patch provided by David Calavera. (markt) 52405: Align the Servlet 3.0 implementation with the changes defined in the first maintenance release (also know as Rev. A). See the JCP documentation for a detailed list of changes (markt) Improve JMX names for objects related to Connectors that have the address attribute set. (markt) Remove some stale attributes from MBeans. (rjung) Move destruction of ContainerBase objects to ContainerBase to ensure that they are destroyed. (markt) 52443: Change the behaviour of the default Realm in the embedded use case so it is set once on the Engine rather than on every Context thereby avoiding the Lifecycle issues with having the same Realm set on multiple Contexts. (markt) Provide a new Realm implementation, the NullRealm, that does not contain any users and is used as the default Realm implementation (rather than the JAAS Realm which was used prior to this change) if no Realm is specified. (markt) 52461: Don't assume file based URLs when checking last modified times for global and host level web.xml files. Patch provided by violetagg. (markt) Add test cases for the BASIC and NonLogin Authenticators when not using SSO. Patch provided by Brian Burch. (markt) 52028: Add support for automatic binding to a free port by a connector if the special value of zero is used for the port. This is mainly useful in embedded and testing scenarios. (markt) Remove obsolete emptySessionPath JMX attribute. (rjung) Correct error in fix for 49683. (markt) Ensure that the process of unlocking the acceptor thread does not trigger processing of the connection as if it were a valid request. (markt) 52450: Add setter for entityResolver in ParserUtils. This is mainly useful when jasper and dtds are in different class loaders. (mturk) 52321: Ensure that the order of multiple prelude/coda values for JSP pages is respected. (markt) 52335: Only handle <\% and not \% as escaped in template text. (markt) 52440: Ensure that when using ValueExpression.getValueReference() if the expression is an EL variable that the value returned is the ValueReference for the ValueExpression associated with the EL variable. (markt) 52445: Don't assume that EL method expressions have exactly three components (identifier, method name, paramaters). (markt) 38216: Add the ability to invoke MBean operations to the JMX proxy sevrlet in the Manager application. Based on a patch by Christopher Hlubek. (markt) Further clarify the relation between values used by RemoteIpValve and RemoteIpFilter and their use by AccessLogValve. (kkolinko) 52243: Improve windows service documentation to clarify how to include # and/or ; in the value of an environment variable that is passed to the service. (markt) 52366: Fix typo in VirtualWebappLoader documentation (configuration example). (rjung) Replace Bugzilla search link on ROOT/index.jsp page with one pointing to the bug reporting page of Tomcat site. (kkolinko) Move MBean dump code from JMXProxyServlet into a utility class. (rjung) 52208: Fix threading issue that may lead to harmless NPE during shutdown that has occasionally been observed when running the unit tests. (markt) 52213, 52354, 52355 and 52356: Fix some potential concurrency issues in FastQueue. (markt) 1207712: Pool cleaner should be a global thread, not spawn one thread per connection pool. (fhanik) Update Apache Commons Daemon to 1.0.8. (mturk) Update Apache Commons Pool to 1.5.7. (kkolinko) Fix line ends in .gitignore files contained in source distributions. (rjung) Run Mapper performance test twice if the first run took too long, to ignore occasional failures. (kkolinko) Align .gitignore and build.xml exclude patterns with svn:ignore. (kkolinko) Configure defaultexcludes for Ant 1.8.1/1.8.2. The .git and .gitignore patterns are in since Ant 1.8.2, but we include .gitignore in src distributions. (kkolinko) 52237: Allow JUnit logs to be generated in formats other than plain text. Patch provided by M Hasko. (markt/kkolinko) Fix build condition for tomcat-dbcp to always rebuild whan a new version of commons-pool or commons-dbcp is downloaded. (kkolinko) Add example of configuration for SetCharacterEncodingFilter to the default web.xml file. (kkolinko) Switch unit tests to bind Connectors to localhost rather than all available IP addresses. (markt) Update to Eclipse JDT Compiler 3.7.1. (markt) Add Netbeans nbproject folder to svn:ignore and .gitignore. (rjung) Align .gitignore with trunk. (rjung)
    46264: Add the ability to start and stop containers (primarily Contexts) using a thread pool rather than a single thread. This can significantly improve start and stop time. Based on patches by Joe Kislo and Felix Schumacher. (markt) 50570: Enable FIPS mode to be set in AprLifecycleListener. Based upon a patch from Chris Beckey. (schultz/kkolinko) 51744: Throw the correct exception if an application attempts to modify the associated JNDI context. (markt) 51744: Add an option to the StandardContext that allows exception throwing when an application attempts to modify the associated JNDI context to be disabled. (markt) 51910: Prevent NPE on connector stop if Comet applications are being used without the CometConnectionManagerValve. (markt) 51940: Do not limit saving of request bodies during FORM authentication to POST requests since any HTTP method may include a request body. Based on a patch by Nicholas Sushkin. (markt/kkolinko) 51956: RemoteAddrFilter used getRemoteHost instead of getRemoteAddr when filtering Comet events. (schultz) 51952: Make the inclusion of a response body with a redirect response introduced to address 41718 optional and disabled by default due to the side-effects of including a body with the response in this case. (markt) 51972: Correctly handle protocol relative URLs when used with sendRedirect(). (markt) Simplify the deployment code and use full paths in log messages to remove any ambiguity in where a context is being deployed from. (markt) 52009: Fix a NPE during access log entry recording when an error occurred during the processing of a Comet request. (markt) In OneLineFormatter log formatter in JULI always use the US locale to format the date (esp. the month names). (rjung) Cache the results of parsing the global and host level web.xml files to improve web application start time. (markt) 52042: Correct threading issue in annotation caching that could lead to an NPE if multiple threads were processing the same class hierarchy for annotations. (markt) Correct additional threading and premature clearance issues with the annotation cache. (markt) Correct a regression in the fix for 49779 that parameters POSTed by an unauthenticated user to a page that required FORM authentication were lost during the authentication process. (markt) 52055: Ensure that the input and output buffers are correctly reset between keep-alive requests when using Servlet 3.0 asynchronous request processing. (markt) Ensure changes to the configuration of the RemoteHostValve and the RemoteAddrValve via JMX are thread-safe. (markt) Ensure the the memory leak protection for the HttpClient keep-alive always operates even if the thread has already stopped. (markt) Remove the Java 1.2 specific error handling around the adding of the shutdown hook. (markt) Correct errors in i18n resources and resource usage that meant some messages were either not used or were incorrectly formatted. (markt) Replace the use of deprecated auth method names from authenticator.Constants with the auth method names from HttpServletRequest. (kkolinko) Make configuration issues for security related Valves and Filters result in the failure of the valve or filter rather than just a warning message. (markt) Improve performance of parameter processing for GET and POST requests. Also add an option to limit the maximum number of parameters processed per request. This defaults to 10000. Excessive parameters are ignored. Note that FailedRequestFilter can be used to reject the request if some parameters were ignored. (markt/kkolinko) 52091: Address performance issues related to lock contention in StandardWrapper. Patch provided by Taiki Sugawara. (markt) Switch to using Collections.enumeration() rather than custom code that does the same thing. (markt) 52113: Don't assume presence of context.xml file with JMX deployment. (markt) In RequestFilterValve (RemoteAddrValve, RemoteHostValve): refactor value matching logic into separate method and expose this new method isAllowed through JMX. (kkolinko) 52156: Ensure that getServletContext().getResource(path) returns the correct resource when path contains /../ sequences or any other sequences that require normalization. (markt) Report existence of HTTP request parameter parsing errors via new special ServletRequest attribute, org.apache.catalina.parameter_parse_failed. (kkolinko) New filter FailedRequestFilter that will reject a request if there were errors during HTTP parameter parsing. (kkolinko) Improve special attributes handling in Request object by using hash table lookup instead of series of string comparisons. (kkolinko) Deprecate unused methods in IntrospectionUtils class. (kkolinko) Improve processing of errors that are wrapped in InvocationTargetException. Rethrow fatal errors that must be rethrown. (kkolinko) Improve handling of failed web application deployments during automatic deployment. Once deployment of a web application fails in one form (e.g. WAR), no further attempt (e.g. directory) will be made to deploy that web application. The base Lifecycle implementation has been improved to allow failed web applications to be started once the configuration issues have been resolved. Any changes to a context.xml file (global, per host or web application specific) will now result in a redeploy of the affected web application(s) that ensures that any changes are correctly applied rather than a reload which ignores changes in context.xml files. (markt/kkolinko) 52173: Improve Javadoc for delegate attribute of WebappClassLoader. Based on a patch by bmargulies. (markt) Add denyStatus attribute to RequestFilterValve (RemoteAddrValve, RemoteHostValve valves) and RequestFilter (RemoteAddrFilter, RemoteHostFilter filters). It allows to use different HTTP response code when rejecting denied request. E.g. 404 instead of 403. (kkolinko) Slightly improve performance of UDecoder.convert(). Align %2f handling between implementations. (kkolinko) 51881: Correctly complete Comet requests when the Comet END event is triggered asynchronously. (markt) 51905: Fix infinite loop in AprEndpoint shutdown if acceptor unlock fails. Reduce timeout before forcefully closing the socket from 30s to 10s. (kkolinko) 51912: Fix HTTP header processing in NIO HTTP connector. (kkolinko) Improve MimeHeaders.toString(). (kkolinko) Fix threading issue in NIO connectors during shutdown that meant Comet connections were not always shut down cleanly. (markt) In HTTP connectors: self-guard against using a non-recycled input buffer. Requests will be rejected with response status 400. (kkolinko) 52121: Fix possible output corruption when compression is enabled for a connector and the response is flushed. Includes a test case provided by David Marcks. (kkolinko/markt) Improve multi-byte character handling in Coyote output for HTTP and AJP. (rjung) Refactor acceptor unlock code to reduce waiting time during connector pause and stop. (markt) Correct possible (but very small) memory leak when using maxLoadedJsps to limit the number of JSPs loaded at any one time. (markt) 52051: Better handling of missing resource problems with non-standard Servlet mappings so that a 404 response is returned to the client rather than a 500 response. (markt) 52091: Address performance issues related to log creation in TagHandlerPool. Patch provided by Taiki Sugawara. (markt) Switch to using Collections.enumeration() rather than custom code that does the same thing. (markt) Avoid an unnecessary session ID change notice. Notice of changed session ID by JvmRouteBinderValve is unnecessary to BackupManager. In BackupManager, change of session ID is replicated by the call of a setId() method. (kfujino) Fix duplicate resetDeltaRequest() call in DeltaSession.setId(String). (kkolinko) Work around a known JVM bug that is fixed in 1.7.0_01 but still present in 1.6.0_29 and was triggering intermittent unit test failure for org.apache.catalina.tribes.group. TestGroupChannelMemberArrival.testMemberArrival. The bug affects any components that use NIO although it was more likely to be observed in the clustering module than the HTTP or AJP NIO connector. (markt) When Context manager does not exist, no context manager message is replied in order to avoid timeout (default 60sec) of GET_ALL_SESSIONS sync phase. (kfujino) Fix setting maxInactiveInterval, sessionIdLength and processExpiresFrequency for cluster managers. Use setter when setting maxActiveSessions. (rjung) 50923: Use distinct background color for code tag in Tomcat documentation, for better readability. (kkolinko) 51630: Fix bug in async0 example that triggered an IllegalStateException in the application log. (markt) 52025: Add additional information regarding DriverManager, the service provider mechanism and memory leaks. (markt) 52049: Improve setup instructions for running as a Windows service: remove references to specific Windows operating systems - it easily becomes dated; correct information on how a JRE is identified and selected. (markt) 52172: Clarify Tomcat build instructions. Patch provided by bmargulies. (kkolinko) 52015: In jdbc-pool: JdbcInterceptor passes not 'this' but 'proxy' to getNext().invoke. (kfujino) In jdbc-pool: Improve handling of Errors that originate from methods invoked through reflection. In TrapException interceptor: rethrow Error as is, without wrapping it in a RuntimeException. (kkolinko) In jdbc-pool: Unwrap InvocationTargetException if it is caught in ResultSetProxy, like we do it elsewhere. (kkolinko) When building jdbc-pool from within Tomcat, use Tomcat's output directory location. This allows to move all build output away from the source tree. (kkolinko) Update the package re-named copy of Commons BCEL (formerly Jakarta BCEL) to the latest code from Commons BCEL trunk. (markt) Remove some unused code from the packaged renamed Commons BCEL. (markt) 52059: In Windows uninstaller: Do not forget to remove Tomcat keys from 32-bit registry on deinstallation. (kkolinko) Start the process of deprecating unused and unnecessary code that will be removed in the next major release (8.0.x). (markt) Ignore .git directory when building the source distributive. (markt) Remove trailing whitespace from the default configuration files. (kkolinko) Improve RUNNING.txt. (kkolinko) Update optional Checkstyle library to 5.5. (kkolinko) In test suite: add LoggingBaseTest class to allow use of Tomcat logging configuration in tests that do not start Tomcat. (kkolinko) In test suite: speed up TestGroupChannelSenderConnections. Remove 48 seconds worth of waits. (kkolinko) 52148: Add tomcat-coyote.jar to catalina-tasks.xml as this JAR is now required by the Ant tasks. Patch provided by Volker Krebs. (markt) Add sample Apache Commons Daemon JSVC wrapper script bin/daemon.sh that can be used with /etc/init.d. (mturk)
    51550: An additional change that ensures any exceptions thrown by an Authenticator (or any other Valve configured for the Context) will be handled by the custom error pages for the Context if an appropriate error page is configured. (markt) 51580: Added a nicer error message when a WAR file contains filenames not properly encoded in UTF-8. (schultz) 51687: Added (optional) protection against sun.java2d.Disposer thread pinning a WebappClassLoader into memory in the JreMemoryLeakPreventionListener. (schultz) 51741: Fixes a problem with Eclipse WTP "Serve modules without publishing" feature where applications failed to access resources when using getResource() on the classloader. (slaurent) 51744: Prevent application code from closing the associated JNDI context while the application is running. (markt) Correct a regression with the fix for 51653 that broke custom error pages for 4xx responses from the Authenticators. Error handling and request listeners are now handled in the StandardHostValve to ensure they wrap all Context level activity. (markt) 51758: The digester (used for processing XML files) used the logger name org.apache.commons.digester.Digester rather than the expected org.apache.tomcat.util.digester.Digester. The digester has been changed to use the expected logger name. (markt/kkolinko) 51774: Fix incorrect cached method signature that prevented session tracking modes from being defined in web.xml when running under a security manager. (markt) Add an annotation cache to the DefaultInstanceManager that improves performance for applications that make use of a lot of non-poolable objects (e.g. tag files) that need to be scanned for annotations when created. (markt) Use the specification compliant request attribute of javax.servlet.request.ssl_session_id to access the SSL session ID and deprecated the Tomcat specific request attribute. (markt) Allow to overwrite the check for distributability of session attributes by session implementations. (rjung) Add Java 7 sunec.jar and zipfs.jar to the list of JARs to skip when scanning for TLDs and web fragments. (rjung) 51862: Added a classesToInitialize attribute to JreMemoryLeakPreventionListener to allow pre-loading of configurable classes to avoid some classloader leaks. (slaurent) Reduce visibility of static field ManagerBase.name and make it final. (kkolinko) Add thread name to juli OneLineFormatter. (rjung) Ensure Servlets that implement ContainerServlet always get treated as restricted. (markt) 51872: Ensure that the access log always uses the correct value for the remote IP address associated with the request and that requests with multiple errors do not result in multiple entries in the access log. (markt) Remove unused and undocumented socketCloseDelay attribute from NIO connector. (markt) 49683: Support separate connection and keep-alive timeouts for the APR/native connector HTTP and AJP connectors. (markt) Further re-factoring of the HTTP connectors to align the BIO, NIO and APR implementations. (markt) 51794: Fix race condition in NioEndpoint. (fhanik) 51811: Correct SSL configuration property name from sslImplemenationName to sslImplementationName. (rjung) Fix a timing issue in NIO connector that meant that stopping a connector did not trigger a Comet END event if the associated processor was processing a READ event when the connector was stopped. (markt) Replace unneeded call that iterated events queue in NioEndpoint.Poller. (kkolinko) 51860: Fix issues if using NIO with a custom SSLImplementation. Based on a suggestion by Roman Tsirulnikov. (markt) Allow the BIO HTTP connector to be used with SSL when running under Java 7. (markt) Don't send AJP CPONG if endpoint is already paused. (rjung) Align APR AJP connector with NIO one. Send 503 if endpoint is paused. (rjung) Accept AJP request even if endpoint is paused, if CPING was successful. (rjung) When unloading JSPs due to configuration of the maxLoadedJsps initialisation parameter, the unloading code was retaining a reference to the to the unloaded JSP preventing the associated class from being unloaded until the JSP that replaced it was itself unloaded. (markt) 51852: Correct two problems in the handling of varargs methods with the BeanELResolver. The first meant the wrong method was sometimes called and the second that an ArrayIndexOutOfBoundsExceptions could be thrown. Patch (including a test case) provided by Matt Benson. (markt) Refactor cluster manager configuration: move handling of common attributes to base class. (kfujino, rjung) New cluster manager attribute sessionAttributeFilter allows to filter which session attributes are replicated using a regular expression applied to the attribute name. (rjung) Correct the documentation for connectionLinger attribute for the AJP and HTTP connectors. (markt) Document caveat of using RemoteAddrValve with IPv6 addresses. (kkolinko) In jdbc-pool: Avoid IllegalArgumentException when setting maxActive less than or equal to 0. ArrayBlockingQueue doesn't allow capacity of 0 or less. (kfujino) 48392 (1169796): Fix typo in StatementDecoratorInterceptor. (fhanik) 51139: In jdbc-pool: validatorClassName and suspectTimeout are ignored. In order to support them correctly, validatorClassName and suspectTimeout are added to a property list. (kfujino) 51786: In jdbc-pool: Discarded connection is not active in a pool any longer. It removes from the active connection list. (kfujino) 51871: Fix dependency in Maven POM file of tomcat-jbdc. (kkolinko) Update the "test" target in the default build file to report a test failure only after all available connector variants (bio, nio, apr) have been tested. Do not stop after first connector that fails. (kkolinko) 51887: When running the unit tests, use a fast but insecure random number source for session ID generation to reduce the delays caused by waiting for entropy. (kkolinko/markt) Code clean-up to further reduce the number of warnings reported by Eclipse, FindBugs and CheckStyle. (markt/kkolinko)
    41718: Include a response body when sending a redirect. (markt) 51640: Improve the memory leak prevention for leaks triggered by java.sql.DriverManager. (markt) 51644: Fix annotation scanning for contexts with a multi-level context path such as /a/b. (markt) Unregisters MBean of DataSource when web application stops. (kfujino) 51650: Code clean-up. Patch provided by Felix Schumacher. (markt) 51653: Move application level error page handling from the Host to the Context. This ensures that application error page handling is completed before the requestDestroyed event of any ServletRequestListener is fired. (markt) 51654: Improve handling of invalid appBase settings for Host elements. (markt) 51658: Fix possible NPE when logging a failed request. Based on a suggestion by Felix Schumacher. (markt) 51688: JreMemoryLeakPreventionListener now protects against AWT thread creation. (schultz) 51712: Ensure cache control headers are sent when appropriate even if the request is secure. Patch provided by Michael Zampani. (markt) 51713: Improve message that is logged if there is an error in the value of protocol in a Connector. (kkolinko) 51739: When using a landing page with FORM authentication ensure that the request has a valid HTTP method. (markt) 51641: Use correct key when removing processor instances from the connections map during clean-up. Patch provided by zhh. (mark) More changes to align the code between the different HTTP connectors. (markt) Ensure AjpMessage headers are correct for the direction of the message. (markt) Code clean-up and re-factoring to reduce duplicate code in the AJP processor implementations. (markt) Detect incomplete AJP messages and reject the associated request if one is found. (markt) 51698: Fix CVE-2011-3190. Prevent AJP message injection. (markt) 41673: Use platform line-endings when reporting compilation errors. (markt) 51736: Make rpcTimeout configurable in BackupManager. (kfujino) 51649: Update the documentation web application to include the ThreadLocal leak prevention listener. (markt) 51583 (1157874, 1162102): Fix shutdown delay in jdbc-pool. (fhanik/kkolinko) 51558: Don't force the use of StandardManager when using any of the Tomcat#addWebapp() methods. (markt) 51704: Make use of File#mkdirs() more robust. (markt)
    Corrected missing comma in the value of jarsToSkip property in conf/catalina.properties file, which caused tomcat-jdbc.jar and commons-beanutils*.jar to be not ignored when scanning jars for tag libraries. (kkolinko) 41709: Provide exception messages where no message is provided currently for IllegalStateExcpetions triggered by calling HttpServletResponse methods when the reponse is committed. (markt) 51509: Fix potential concurrency issue in CSRF prevention filter that may lead to some requests failing that should not. (markt) 51518: Correct error in web.xml parsing rules for the <others/> tag when using absolute ordering. (markt) Move the SetCharacterEncoding filter from the examples web application to the org.apache.catalina.filters package so it is available for all web applications. (markt) 51550: Internal errors in Tomcat components that process requests before they are passed to a web application, such as Authenticators, now return a 500 response rather than a 200 response. (markt) 51555: Allow destroy() to be called on Lifecycle components that are in the initialized state. (markt) Add x-threadname pattern format token to ExtendedAccessLogValve to log the current request thread name. Based on a patch from Felix Schumacher. (timw) 51584: Ensure file paths are encoded/decoded when translated to/from URLs when working with resources from a Context so special characters don't cause issues. (markt) 51586: Expand error handling to cover anything that is recoverable (or might be recoverable) when loading classes during HandlesTypes processing. (markt) 51588: Make it easier to extend the AccessLogValve to add support for custom elements. (markt) Ensure that calls to StandardWrapper methods() that may trigger creation of a Servlet instance always do so in way that correctly instantiates a Servlet instance. (markt) In JDBCStore: Committing connection if autoCommit is false. Make sure committed connection is returned to the pool if datasource is enabled. (kfujino) Split condition attribute of AccessLogValve into two, conditionIf and conditionUnless. Implement conditional logging that logs only if a request attribute is present. (kkolinko) Allow to have several AccessLogValve instances in the same scope (e.g. in the same Context). (kkolinko) 51610: If an unchecked exception occurs during a lifecycle transition (e.g. web application start) ensure that the component is put into the failed state. (markt) 51614: Avoid calling store.load() and session.expire() twice in PersistentManager when expiring sessions. (kfujino) Prevent spurious log warnings on container stop if a child component has previously failed. (markt) Add missing getter and setter for the alwaysUseSession attribute of the authenticators. (markt) 49595: Prevent JVM crash with the AJP APR connector when flushing a closed socket. (jfclere) 50394: Return -1 instead of throwing an exception when encountering an EOF while processing an input stream with the HTTP APR connector. (jfclere) Correctly handle a connectionTimeout value of -1 (no timeout) for the HTTP NIO and AJP NIO connectors. (markt) 51503: Add additional validation that prevents a connector from starting if it does not have a port > 0. (markt) 51557: Ignore HTTP headers that do not comply with RFC 2616 and use header names that are not tokens. (markt) Improve error handling for HTTP APR if an error occurs while using sendfile. (markt) Ensure that when using sendfile, HTTP APR sockets are not added to multiple pollers. This may cause errors during shutdown. (markt) Set reuse flag of final AJP END_RESPONSE packet to 0 if we plan to close the connection. (rjung) Correctly indicate if socket is closing when calling recycle for the AJP NIO processor. Note since the flag is unused in this case there were no bugs triggered by the re-factoring error. (rjung) 51532: JSP files with dependencies in JARs were recompiled on every access leading to poor performance. (markt) 51544: Correctly resolve bean methods in EL so accessible methods that are overridden by inaccessible methods do not cause an IllegalAccessException. (markt) 41498: Add the allRolesMode attribute to the Realm configuration page in the documentation web application. (markt) 48997: Fixed some typos and correct cross-referencing to the HTTP Connector documentation with the SSL How-To page of the documentation web application. (markt) 49122: Improvements and fixes for index page for ROOT web application. Based on a patch provided by pidster. (markt) 51516: Correct documentation web application to show correct system property name for changing the name of the SSO session cookie. (markt) Configure the Manager and Host Manager web applications with the Set Character Encoding Filter to make the default request character encoding UTF-8 to improve i18n support. Note that best results will be obtained if the connector is also configured with URIEncoding="UTF-8".(markt) Update the documentation web application to be even more explicit about the implications of setting the path attribute on a Context element in server.xml. (markt) 51561: Update the Realm page within the documentation web application to recommend the use of digest.[bat|sh] to generate digests rather than calling RealmBase directly. (markt) 51567: Update the class loading page of the documentation web application to include information on the search order for the common class loader when separate values are used for $CATALINA_HOME and $CATALINA_BASE. (markt) Improve class loading documentation and logging documentation. (kkolinko) Add information to the security page of the the documentation web application for the ciphers attribute of the Connector element. (markt) 51503: Add additional validation to Windows installer that ensure that the shutdown port, HTTP port and AJP port are all specified during the install process. (markt) 51531: Update sample Eclipse classpath file to reflect updated ECJ jar. Patch provided by Ian Brandt. (markt) Convert Tomcat unit tests to JUnit 4. (kkolinko) Update optional CheckStyle library to 5.4. (kkolinko) Remove resolveHosts attribute from AccessLogValve configuration in the default server.xml. It was documented in 7.0.19 that it has no effect. (kkolinko) Simplify mapping for jsp servlet in the default web.xml. (kkolinko) Correctly handle uninstall with the Windows installer if the service is installed with a name that contains a '-' character. (markt) 51598: Prevent direct invocation of the Windows uninstaller without a service name from executing since the uninstall will not be complete. (markt) Use Tomcat icon (cat) instead of Apache Commons Daemon (feather) one in the list of uninstallable programs on Windows. (kkolinko) Update to Apache Commons Daemon 1.0.7. (markt) 51621: Add additional required JARs to the deployer distribution. (markt) Fix a small number of warnings reported by FindBugs. (markt) Update to version 1.1.22 of the native component for the AJP APR/native and HTTP APR/native connectors. (markt)
    Add option to activate access log for unit tests. (rjung) Fix regression in year number formatting for AccessLogValve. (rjung) 46252: Allow to specify character set to be used to write the access log in AccessLogValve. (kkolinko) 51494: Prevent an NPE when a long running request completes if the associated web application was destroyed while the request was processing. (markt) Allow choosing a locale for timestamp formatting in AccessLogValve. (rjung) When generating access logs for errors, log at the Context/Host level if a Context or Host can be identified for the failed request. (markt) Create a directory for access log or error log (in AccessLogValve and in JULI FileHandler) automatically when it is specified as a part of the file name, e.g. in the prefix attribute. Earlier this happened only if it was specified with the directory attribute. (kkolinko) Log a failure if access log file cannot be opened. (kkolinko) Use en_US as locale for timestamps in ExtendedAccessLogValve. (rjung) Use en_US as locale for creationdate in WebdavServlet. (rjung) 51477: Support all SSL protocol combinations in the APR/native connector. This only works when using the native library version 1.1.21 or later, which is not yet released. (rjung) Various refactorings to reduce code duplication and unnecessary code in the connectors. (markt) Correct regression introduced in 7.0.17 that triggered 400 entries in the AccessLog when using the AJP/BIO connector. (markt) Fix regression producing invalid MBean names when using IPV6 addresses for connectors. (rjung) Add missing thread name in RequestProcessor when Servlet 3 Async is used. Fixes null thread name in access log and JMX MBean. (rjung) Fix CVE-2011-2526. Protect against infinite loops (HTTP NIO) and crashes (HTTP APR) if sendfile is configured to send more data than is available in the file. (markt) Prevent NPEs when a socket is closed in non-error conditions after sendfile processing when using the HTTP NIO connector. (markt) Remove unnecessary server.xml parsing code for old cluster implementation that does not ship as part of Tomcat 7. (markt) Add additional information to the documentation web application on the benefits and remaining risks when running under a security manager. (markt) 51490: Correct broken HTML in JSP tag plugin examples and improve the <c:if> example to make failures more obvious. Based on suggestions by Charles. (markt) Document ExtendedAccessLogValve. (rjung) Correct default value of enableLookups for connectors and mention, that resolveHosts for the AccessLogValve is replaced by enableLookups. (rjung) Include jdbc-pool into Tomcat release. (fhanik) Update to Apache Commons Daemon 1.0.6. (markt) Update to Eclipse JDT Compiler 3.7. (markt)
    Correct regression introduced in 7.0.17 that triggered an NPE if a CrawlerSessionManagerValve was used without setting crawlerUserAgents. (markt) 51466: Correct comment typos in HostManagerServlet. Patch provided by Felix Schumacher. (markt) 51467: Invoke Thread.start() rather than Thread.run() so that listeners and filters are stopped in a separate thread rather than the current thread. Patch provided by Felix Schumacher. (markt) 51473: Fix concatenation of values in SecurityConfig.setSecurityProperty(). (kkolinko) Fix response.encodeURL() for the special case of an absolute URL with no path segment (http://name). (rjung) Correct regression caused by connector re-factoring that made AJP APR/native connector very unstable on Windows platforms. (markt) Correct regression caused by connector re-factoring that meant that sendfile data was not reset between pipe-lined HTTP requests. (markt) Re-factor tests to align packages for tests with the classes under test. Start to convert non-JUnit tests to JUnit. Remove unnecessary code. (markt) Add synchronization to receiver socket binding to prevent test failures on Linux. (markt) More code clean-up to remove unused code and reduce IDE warnings. (markt/kkolinko) Further improvements to the Windows installer. (markt/kkolinko)
    48956: Add regular expression support for SSI. (markt) 49165: Allow any time stamp formats supported by SimpleDateFormat in AccessLogValve. Support logging begin and/or end of request. (rjung) 50677: Allow system property variables to be used in the values of "common.loader" and other "*.loader" properties in the catalina.properties file. (kkolinko) 51376: When adding a Servlet via ServletContext#addServlet(String, Servlet), the Servlet was not initialized when the web application started and a load on startup value was set. (markt) 51386: Correct code for processing @HandlesTypes annotations so only types of interest are reported to a ServletContainerInitializer. (markt) Add the Tomcat extras, ant-junit and Java Help Jars to the list of JARs to skip when scanning for TLDs and web fragments. (rjung) The fix for bug 51310 caused a regression that re-introduced bug 49957 and deleted the contents of the work directory when Tomcat was shutdown. This fix ensures that that work directory for an application is not deleted when Tomcat is shutdown. (markt) Correct issues with JULI's OneLineFormatter including: correctly re-using formatted timestamps when possible; thread-safety issues in timestamp formatting; correcting the output of any milliseconds to include leading zeros and formatting any parameters present. (kkolinko/markt/rjung) 51395: Fix memory leak triggered when an application that includes a SAXParserFactory is the first web application to be loaded. (markt) 51396: Correctly handle jsp-file entries in web.xml when the JSP servlet has been configured via code when embedding Tomcat. (markt) 51400: Avoid known bottleneck in JVM when converting between Strings and bytes by always providing a Charset rather than an encoding name. Based on a patch by Dave Engberg. (markt) 51401: Correctly initialise shared WebRuleSet instance used by the digesters that parse web.xml and prevent incorrect warnings about multiple occurrences of elements that are only allowed to appear once in web.xml and web-fragment.xml. (kfujino) 51403: Avoid NPE in JULI FileHandler if formatter is misconfigured. (kkolinko) Previous improvements in JAR scanning performance introduced a start-up performance penalty for some use cases. This fix addresses those performance penalties while retaining the original improvements. (markt) 51418: Provide more control over Context creation when embedding Tomcat. Based on a patch by Benson Margulies. (markt/kkolinko) Remove redundant copy of catalina.properties from o.a.c.startup. Generate this copy for inclusion in bin and src jars during the ant "compile" task. (rjung) Use system properties loaded from catalina.properties via the class path in unit tests. (rjung) Improve JMX unit test. (rjung) Fix IllegalStateException for JavaScript files when switching from Writer to OutputStream. The special handling of this case in the DefaultServlet was broken due to a MIME type change for JavaScript. (funkman) Fix CVE-2011-2204. Prevent user passwords appearing in log files if a runtime exception (e.g. OOME) occurs while creating a new user for a MemoryUserDatabase via JMX. (markt) Fix an issue with the CrawlerSessionManagerValve that meant sessions were not always correctly tracked. (markt) 51436: Send 100 (Continue) response earlier to enable ServletRequestListener implementations to read the request body. Based on a patch by Simon Olofsson. (markt) Ensure an access log entry is made if an error occurs during asynchronous request processing and the socket is immediately closed. (markt) Ensure that if asyncDispatch() is called during an onTimeout event and the target Servlet does not call startAsync() or complete() that Tomcat calls complete() once the target Servlet exits. (markt) Improve the handling for Servlets that implement the deprecated SingleThreadModel when embedding Tomcat. (markt) 51445: Correctly initialise all instances of Servlets that implement SingleThreadModel. Based on a patch by Felix Schumacher. (markt) 51453: Fix a regression in the preemptive authentication support (enhancement 12428) that could trigger authentication even if preemptive authentication was disabled. (markt) Prevent possible NPE when serving Servlets that implement the SingleThreadModel interface. (markt) In launcher for embedded Tomcat: do not change catalina.home system property if it had a value. (kkolinko) When using Servlets that implement the SingleThreadModel interface, add the single instance created to the pool when it is determined that a pool of servlets is required rather than throwing it away. (markt) Fix unit test for bindOnInit which was failing for APR on some platforms. (rjung) Remove superfluous quotes from thread names for connection pools. (rjung) Fix crash observed during pausing the connector when using APR. Only add socket to poller if we are sure we don't close it later. (rjung) Various refactorings to reduce code duplication and unnecessary code in the connectors. (markt) Correct a regression introduced in Apache Tomcat 7.0.11 that broke certificate revocation list handling. (markt) Improve the message printed by TldLocationsCache and add configuration example to the logging.properties file. (kkolinko) 33453: Recompile JSPs if last modified time of the source or any of its dependencies changes either forwards or backwards. Note that this introduces an incompatible change to the code generated for JSPs. Tomcat will automatically re-compile any JSPs and tag files found in the work directory when upgrading from 7.0.16 or earlier to 7.0.17 or later. If you later downgrade from 7.0.17 or later to 7.0.16 or earlier, you must empty the work directory as part of the downgrade process. (markt) 36362: Handle the case where tag file attributes (which can use any valid XML name) have a name which is not a Java identifier. (markt/kkolinko) Broaden the exception handling in the EL Parser so that more failures to parse an expression include the failed expression in the exception message. Hopefully, this will help track down the cause of 51088. (markt) 51306: Avoid NPE when handleSESSION_EXPIRED is processed while handleSESSION_CREATED is being processed. (kfujino) Notifications of changes in session ID to other nodes in the cluster should be controlled by notifySessionListenersOnReplication rather than notifyListenersOnReplication. (markt) The change in session ID is notified to the container event listener on the backup node in cluster. This notification is controlled by notifyContainerListenersOnReplication.(kfujino) Update Maven repository information in the documentation to reflect current usage. (markt) 43538: Add host name and IP address to the HTML Manager application. Patch by Dennis Lundberg. (markt) Add session="false" directive to the index page of the ROOT web application. (kkolinko) 51443: Document the notifySessionListenersOnReplication attribute for the DeltaManager. (markt) 51447: Viewing a back up session in the HTML Manager web application no longer changes the session to a primary session. Based on a patch provided by Eiji Takahashi. (markt) 33262: Install monitor to auto-start for current user only rather than all users to be consistent with menu item creation. (markt) 40510: Provide an option to install shortcuts for the current user or all users. Also ensure registry is correctly cleaned on uninstall for 64-bit platforms. (markt) 50949: Provide the ability to specify the AJP port and service name when installing Tomcat using the Windows installer. This permits multiple instances of the same Tomcat version to be installed side-by-side. (markt) Clean up shell and batch scripts (improve consistency, clarify comments, add configtest command support for Windows). (rjung) 51206: Make CATALINA_BASE visible for setenv.sh. (rjung) Remove unnecessary variable BASEDIR from scripts. (rjung) 51425, 51450: Update Spanish translations. Based on patches provided by Jesus Marin. (markt)
    51249: Further improve system property replacement code in ClassLoaderLogManager of Tomcat JULI to cover some corner cases. (kkolinko) 51264: Improve the previous fix for this issue by returning the connection to the pool when not in use so it does not appear to be an abandoned connection. Patch provided by Felix Schumacher. (markt) 51324: Improve handling of exceptions when flushing the response buffer to ensure that the doFlush flag does not get stuck in the enabled state. Patch provided by Jeremy Norris. (markt) Correct a regression in the fix for 51278 that prevented any web application from being marked as distributable. (kfujino/markt) Correct a regression in the fix for 51278 that prevented a web application from overriding the default welcome files. (markt) Enable remaining valves for Servlet 3 asynchronous processing support. (markt) Avoid possible NPE when logging requests received during embedded Tomcat shutdown. (markt) 51340: Fix thread-safety issue when parsing multiple web.xml files in parallel. Apache Tomcat does not do this but products that embed it may. (markt) 51344: Fix problem with Lifecycle re-factoring for deprecated embedded class that prevented events being triggered. (markt) 51348: Prevent possible NPE when processing WebDAV locks. (markt) When parsing the port in the HTTP host header, restrict the value to be base 10 integer digits rather than hexadecimal ones. (rjung/markt/kkolinko) Various refactorings to reduce code duplication and unnecessary code in the connectors. (markt) Change JAR scanning log messages where no TLDs are found to DEBUG level and replace the multiple messages with a single INFO level message that indicates that at least one JAR was scanned needlessly and how to obtain more info. (markt) Enable Servlet 3 asynchronous processing support when using clustering. (markt) Correct the log4j configuration settings when defining conversion patterns in the documentation web application. (markt)
    27122: Remove a workaround for a very old and since fixed Mozilla bug and change the default value of the securePagesWithPragma attribute of the Authenticator Valves to false. These changes should reduce the likelihood of issues when downloading files with IE. (markt) 35054: Check that a file is not specified for a Host's appBase and log an error if it is. (markt) 51197: Fix possible dropped connection when sendError or sendRedirect are used during async processing. (markt) 51221: Correct Spanish translation of text used in a 302 response. Patch provided by Paco Soberón. (markt) 51249: Correct ClassLoaderLogManager system property replacement code so properties of the form "}${...}" can be used without error. (markt) 51264: Allow the JDBC persistent session store to use a JNDI datasource to define the database in which sessions are persisted. Patch provided by Felix Schumacher. (markt) 51274: Add missing i18n strings in PersistentManagerBase. Patch provided by Eiji Takahashi. (markt) 51276: Provide an abstraction for accessing content in JARs so the most efficient method can be selected depending on the type of URL used to identify the JAR. This improves startup time when JARs are located in $CATALINA_BASE/lib. (markt) 51277: Improve error message if an application is deployed with an incomplete FORM authentication configuration. (markt) 51278: Allow ServletContainerInitializers to override settings in the global default web.xml and the host web.xml. (markt) 51310: When stopping the Server object on shutdown call destroy() after calling stop(). (markt) 51145: Add an AJP-NIO connector. (markt/rjung) 51220: Add a system property to enable tag pooling with JSPs that use a custom base class. Based on a patch by Dan Mikusa. (markt) Include a comment header in generated java files that indicates when the file was generated and which version of Tomcat generated it. (markt) 51240: Ensure that maxConnections limit is enforced when multiple acceptor threads are configured. (markt) 51230: Add missing attributes to JMX for ReplicationValve and JvmRouteBinderValve. Patch provided by Eiji Takahashi. (markt) Add documentation for AJP-NIO connector. (markt/rjung) 51182: Document JAAS supported added in 51119. Patch provided by Neil Laurance. (markt) 51225: Fix broken documentation links for non-English locales in the HTML Manager application. Patch provided by Eiji Takahashi. (markt) 51229: Fix bugs in the Servlet 3.0 asynchronous examples. Patch provided by Eiji Takahashi. (markt) 51251: Add web application version support to the Ant tasks. Based on a patch provided by Eiji Takahashi. (markt) 51294: Clarify behaviour of unpackWAR attribute of StandardContext components. (markt) 46451: Configure svn:bugtraq properties for Tomcat trunk. Based on a patch provided by Marc Guillemot. (markt) 51309: Correct logic in catalina.sh stop when using a PID file to ensure the correct message is shown. Patch provided by Caio Cezar. (markt)
    Stylistic improvements to MIME type sync script. Based on a patch provided by Felix Schumacher. (rjung) Ensure that the SSLValve provides the SSL key size as an Integer rather than a String. (markt) Ensure that the RemoteIpValve works correctly with Servlet 3.0 asynchronous requests. (markt) Use safe equality test when determining event type in the MapperListener. (markt) Use correct class loader when loading Servlet classes in StandardWrapper. (markt) Provide additional configuration options for the RemoteIpValve and RemoteIpFilter to allow greater control over the values returned by ServletRequest#getServerPort() and ServletRequest#getLocalPort() when Tomcat is behind a reverse proxy. (markt) Ensure session cookie paths end in / so that session cookies created for a context with a path of /foo do not get returned with requests mapped to a context with a path of /foobar. (markt) 51177: Ensure Tomcat's MapElResolver always returns Object.class for getType() as required by the EL specification. (markt)
    Correct mix-up in Realm Javadoc. (markt) Fix display of response headers in AccessLogValve. (kkolinko) Implement display of multiple request headers in AccessLogValve: print not just the value of the first header, but of the all of them, separated by commas. (kkolinko) 50306: New StuckThreadDetectionValve to detect requests that take a long time to process, which might indicate that their processing threads are stuck. Based on a patch provided by TomLu. (slaurent) 51038: Ensure that asynchronous requests are included in access logs. (markt) 51042: Don't trigger session creation listeners when a session ID is changed as part of the authentication process. (markt) 51050: Add additional common but non-standard file extension to MIME type mappings for MPEG 4 files. Based on a patch by Cédrik Lime. (markt) Add some additional common JARs that do not contain TLDs or web fragments to the list of JARs to skip when scanning for TLDs and web fragments. (markt) While scanning JARs for TLDs and fragments, avoid using JarFile and use JarInputStream as in most circumstances where JARs are scanned, JarFile will create a temporary copy of the JAR rather than using the resource directly. This change significantly improves startup performance for applications with lots of JARs to be scanned. (markt) Ensure response is committed when AsyncContext#complete() is called. (markt) Add a container event that is fired when a session's ID is changed, e.g. on authentication. (markt) 51099: Correctly implement non-default login configurations (configured via the loginConfigName attribute) for the the SPNEGO authenticator. (fhanik/markt) 51119: Add JAAS authentication support to the JMXRemoteLifecycleListener. Patch provided by Neil Laurance. (markt) 51136: Provide methods that enable the name of a Context on Context creation when using Tomcat in an embedded scenario. Based on a patch provided by David Calavera. (markt) 51137: Add additional Microsoft Office MIME type mappings. (rjung) Partial sync of MIME type mapping with mime.types from the Apache web server. About 600 MIME types added, some changed. (rjung) Make access logging more robust when logging requests that generate 400 responses since the request object is unlikely to be fully/correctly populated in that case. (markt) 50957: Fix regression in HTTP BIO connector that triggered errors when processing pipe-lined requests. (markt) 50158: Ensure the asynchronous requests never timeout if the timeout is set to zero or less. Based on a patch provided by Chris. (markt) 51073: Throw an exception and do not start the APR connector if it is configured for SSL and an invalid value is provided for SSLProtocol. (markt) Align all the connector implementations with the documented default setting for processorCache of 200. This changes the default from -1 (unlimited) for the AJP-BIO, AJP-APR and HTTP-APR connectors. Additional information was also added to the documentation on how to select an appropriate value. Take account of time spent waiting for a processing thread when calculating connection and keep-alive timeouts for the HTTP BIO connector. (markt) 51095: Don't trigger a NullPointerException when the SSL handshake fails with the HTTP-APR connector. Patch provided by Mike Glazer. (markt) Improve handling in AJP connectors of the case where too large a AJP packet is received. (markt) Restore the automatic disabling of HTTP keep-alive with the BIO connector once 75% of the processing threads are in use and make the threshold configurable. (markt) Make pollerSize and maxConnections synonyms for the APR connectors since they perform the same function. (markt) Use maxThreads rather than 10000 as the default maxConnections for the BIO connectors. (markt) 47371: Correctly coerce the empty string to zero when used as an operand in EL arithmetic. Patch provided by gbt. (markt) Label JSP/tag file line and column numbers when reporting errors since it may not be immediately obvious what the numbers represent. (markt) Correct a regression in the fix for 49916 that resulted in JSPs being compiled twice rather than just once. (markt) Log JARs that are scanned for TLDs where no TLD is found so that users can easily identify JARs that can be added to the list of JARs to skip. (markt) Use a single TLD location cache for a web application rather than one per JSP compilation to speed up JSP compilation. (markt) 51124: Refactor BodyContentImpl to assist in determining the root cause of this bug. Based on a patch by Ramiro. (markt) 50950: Correct possible NotSerializableException for an authenticated session when running with a security manager. (markt) Configure Security Manager How-To to include a copy of the actual conf/catalina.policy file when the documentation is built, rather than maintaining a copy of its content. (kkolinko) Fix broken stylesheet URL in XML based manager status output. (rjung) 51156: Ensure session expiration option is available in Manager application was running web applications that were defined in server.xml. (markt) Clarify error messages in *.sh files to mention that if a script is not found it might be because execute permission is needed. (kkolinko) Update Apache Commons Pool to 1.5.6. (markt) 51135: Fix auto-detection of JAVA_HOME for 64-bit Windows platforms that only have a 32-bit JVM installed. (markt) 51154: Remove duplicate @deprecated tags in ServletContext Javadoc. Patch provided by sebb. (markt) 51155: Add comments to @deprecated tags that have none. Patch provided by sebb. (markt)
    Automatically correct invalid paths when specified for Context elements inside server.xml and log a warning that the configuration has been corrected. (markt) Don't unpack WAR files if they are not located in the Host's appBase. (markt) Don't log to standard out in SSLValve. (markt) Handle the case where a web crawler provides an invalid session ID in the CrawlerSessionManagerValve. (markt) Update pattern used in CrawlerSessionManagerValve to that used by the ASF infrastructure team. (markt) Remove unnecessary whitespace from MIME mapping entries in global web.xml file. (markt) When using parallel deployment, correctly handle the scenario when the client sends multiple JSESSIONID cookies. (markt) 12428: Add support (disabled by default) for preemptive authentication. This can be configured per context. Based on a patch suggested by Werner Donn. (markt) Make the CSRF nonce cache serializable so that it can be replicated across a cluster and/or persisted across Tomcat restarts. (markt) Resolve some refactoring TODOs in the implementation of the new Context attribute "swallowAbortedUploads". (markt) Include the seed time when calculating the time taken to create SecureRandom instances for session ID generation, report excessive times (greater than 100ms) at INFO level and provide a value for the message key so a meaningful message appears in the logs. (markt) Don't register Contexts that fail to start with the Mapper. (markt) 48685: Add initial support for SPNEGO/Kerberos authentication also referred to as integrated Windows authentication. This includes user authentication, authorisation via the directory using the user's delegated credentials and exposing the user's delegated credentials via a request attribute so applications can make use of them to impersonate the current user when accessing third-party systems that use a compatible authentication mechanism. Based on a patch provided by Michael Osipov. (markt) HTTP range requests cannot be reliably served when a Writer is in use so prevent the DefaultServlet from attempting to do so. (kkolinko) Protect the DefaultServlet from Valves, Filters and Wrappers that write content to the response. Prevent partial responses to partial GET requests in this case since the range cannot be reliably determined. Also prevent the DefaultServlet from setting a content length header since this too cannot be reliably determined. (markt) 50929: When wrapping an exception, include the root cause. Patch provided by sebb. (markt) 50991: Fix regression in fix for 25060 that called close on a JNDI resource while it was still available to the application. (markt) Provide a configuration option that lets the close method to be used for a JNDI Resource to be defined by the user. This change also disables using the close method unless one is explicitly defined for the resource and limits it to singleton resources. (markt) Correctly track changes to context.xml files and trigger redeployment when copyXML is set to false. (markt) 50997: Relax the requirement that directories must have a name ending in .jar to be treated as an expanded JAR file by the default JarScanner. Based on patch by Rodion Zhitomirsky. (markt) Don't append the jvmRoute to a session ID if the jvmRoute is a zero length string. (markt) Don't register non-singelton DataSource resources with JMX. (markt) CVE-2011-1184: Provide additional configuration options for the DIGEST authenticator. (markt) Provide a workaround for Tomcat hanging during shutdown when running the unit tests. (markt) 50887: Add support for configuring the JSSE provider used to convert client certificates. Based on a patch by pknopp. (markt) 50903: When a connector is stopped, ensure that requests that are currently in a keep-alive state and waiting for client data are not processed. Requests where processing has started will continue to completion. (markt) 50927: Improve error message when SSLCertificateFile is not specified when using APR with SSL. Based on a patch provided by sebb. (markt) 50928: Don't ignore keyPass attribute for HTTP BIO and NIO connectors. Based on a patch provided by sebb. (markt) Securely seed the SecureRandom instance used for UUID generation and report excessive creation time (greater than 100ms) at INFO level. (markt) 50924: Clean-up HTTP connector comparison table. (markt) Slightly expanded the documentation of the Host element to clarify the relationship between host name and DNS name. (markt) 50925: Update SSL how-to to take account of keyPass connector attribute. (markt) Improve Tomcat Logging documentation. (kkolinko) Align the authenticator documentation and MBean descriptors with the implementation. (markt) Prevent the custom error pages for the Manager and Host Manager applications from being accessed directly. (markt) 50984: When using the Manager application ensure that undeployment fails if a file cannot be deleted. (markt) Update Eclipse JDT complier to 3.6.2. (markt) Update WSDL4J library to 1.6.2 (used by JSR 109 support in the extras package). (markt) Update optional CheckStyle library to 5.3. (markt) 50911: Reduce noise generated during the build of the Windows installer so warnings are more obvious. Patch provided by sebb. (markt) Further work to reduce compiler and validation warnings across the code base. (markt)
    CVE-2011-1088: Completed fix. Don't ignore @ServletSecurity annotations. (markt) 25060: Close Apache Commons DBCP datasources when the associated JNDI naming context is stopped (e.g. for a non-global DataSource resource on web application reload) to close remaining database connections immediately rather than waiting for garbage collection. (markt) 26701: Provide a mechanism for users to register their own URLStreamHandlerFactory objects. (markt) 50855: Fix NPE on HttpServletRequest.logout() when debug logging is enabled. (markt) New context attribute "swallowAbortedUploads" allows to make request data swallowing configurable for requests that are too large. (rjung) 50854: Add additional permissions required by the Manager application when running under a security Manager and support a shared Manager installation when $CATALINA_HOME != CATALINA_BASE. (markt) 50893: Add additional information to the download README for the extras components. (markt) Calling stop() and then destroy() on a connector incorrectly triggered an exception. (markt) 48208: Allow the configuration of a custom trust manager for use in CLIENT-CERT authentication. (markt) Fix issues that prevented asynchronous servlets from working when used with the HTTP APR connector on platforms that support TCP_DEFER_ACCEPT. (markt) Correct possible threading issue in JSP compilation when development mode is used. (markt) 50895: Don't initialize classes created during the compilation stage. (markt)
    CVE-2011-1088: Partial fix. Don't ignore @ServletSecurity annotations. (markt) 27988: Improve reporting of missing files. (markt) 28852: Add URL encoding where missing to parameters in URLs presented by Ant tasks to the Manager application. Based on a patch by Stephane Bailliez. (markt) Improve handling of SSL renegotiation by failing earlier when the request body contains more bytes than maxSavePostSize. (markt) Improve shut down speed by not renewing threads during shut down when the ThreadLocalLeakPreventionListener is enabled. (markt) 49284: Add SSL re-negotiation support to the HTTP NIO connector and extend test cases to cover CLIENT-CERT authentication. (fhanik/markt)
    19444: Add an option to the JNDI realm to allow role searches to be performed by the authenticated user. (markt) 21669: Add the ability to specify the roleBase for the JNDI Realm as relative to the users DN. Based on a patch by Art W. (markt) 22405: Add a new Lifecycle listener, org.apache.catalina.security.SecurityListener that prevents Tomcat from starting insecurely. It requires that Tomcat is not started as root and that a umask at least as restrictive as 0007 is used. This new listener is not enabled by default. (markt) 48863: Better logging when specifying an invalid directory for a class loader. Based on a patch by Ralf Hauser. (markt/kkolinko) 48870: Refactor to remove use of parallel arrays. (markt) Enhance the RemoteIpFilter and RemoteIpValve so that the modified remote address, remote host, protocol and server port may be used in an access log if desired. (markt) Restore access to Environments, Resources and ResourceLinks via JMX which was lost in early 7.0.x re-factoring. (markt) Remove ServerLifecycleListener. This was already removed from server.xml and with the Lifecycle re-factoring is no longer required. (markt) Add additional checks to ensure that sub-classes of org.apache.catalina.util.LifecycleBase correctly implement the expected state transitions. (markt) 50189: Once the application has finished writing to the response, prevent further reads from the request since this causes various problems in the connectors which do not expect this. (markt) 50700: Ensure that the override attribute of context parameters is correctly followed. (markt) 50721: Correctly handle URL decoding where the URL ends in %nn. Patch provided by Christof Marti. (markt) 50737: Add additional information when an invalid WAR file is detected. (markt) 50748: Allow the content length header to be set up to the point the response is committed when a writer is being used. (markt) 50751: When authenticating with the JNDI Realm, only attempt to read user attributes from the directory if attributes are required. (markt) 50752: Fix typo in debug message in deprecated Embedded class. (markt) 50789: Provide an option to enable ServletRequestListeners for forwards as required by some CDI frameworks. (markt) 50793: When processing Servlet 3.0 async requests, ensure that the requestInitialized and requestDestroyed events are only fired once per request at the correct times. (markt) 50802: Ensure that ServletContext.getResourcePaths() includes static resources packaged in JAR files in its output. (markt) Web crawlers can trigger the creation of many thousands of sessions as they crawl a site which may result in significant memory consumption. The new Crawler Session Manager Valve ensures that crawlers are associated with a single session - just like normal users - regardless of whether or not they provide a session token with their requests. (markt) Don't attempt to start NamingResources for Contexts multiple times. (markt) 50826: Avoid IllegalArgumentException if an embedded Tomcat instance that includes at least one Context is destroyed without ever being started. (markt) Ensure a web application is taken out of service if the web.xml file is not valid. (kkolinko/markt) Ensure Servlet 2.2 jspFile elements are correctly converted to use a leading '/' if missing. (markt) 50836: Better documentation of the meaning of Lifecycle.isAvailable() and correct a couple of cases where this could incorrectly return true. (markt) 50780: Fix memory leak in APR implementation of AJP connector introduced by the refactoring for 49884. (markt) If server configuration errors and/or faulty applications caused the ulimit for open files to be reached, the acceptor threads for all connectors could enter a tight loop. This loop consumed CPU and also logged an error message for every iteration of the loop which lead to large log files being generated. The acceptors have been enhanced to better handle this situation. (markt) 50720: Ensure that the use of non-ISO-8859-1 character sets for web.xml does not trigger an error when Jasper parses the web.xml file. (markt) 50726: Ensure that the use of the genStringAsCharArray does not result in String constants that are too long for valid Java code. (markt) 50790: Improve method resolution in EL expressions. (markt) 50771: Ensure HttpServletRequest#getAuthType() returns the name of the authentication scheme if request has already been authenticated. (kfujino) 50713: Remove roles command from the Manager application. (markt) 50667 (1068549): Allow RPC callers to get confirmation when sending a reply. (fhanik) 50743: Cache CheckStyle results between builds to speed up validation. Patch provided by Oliver. (markt)
    Fix NPE in CoyoteAdapter when postParseRequest() call fails. (kkolinko) 50709: Make ApplicationContextFacade non-final to enable extension. (markt) When running under a security manager, user requests may fail with a security exception. (markt) Reduce level of log message for invalid URL parameters from WARNING to INFO. (markt) Fix hanging Servlet 3 asynchronous requests when using the APR based AJP connector. (markt) Align server.xml installed by the Windows installer with the one bundled in zip/tar.gz files. The differences are LockOutRealm being used and AccessLogValve being enabled by default. (kkolinko)
    18462: Don't merge stdout and stderr internally so users retain the option to treat them separately. (markt) 18797: Provide protection against null or zero length names being provided for users, roles and groups in the MemoryRealm and UserDatabaseRealm. (markt) Improve fix for 50205 to trigger an error earlier if invalid configuration is used. (markt) Provide additional control over component class loaders, primarily for use when embedding. (markt) Fix NPE in RemoteAddrFilter, RemoteHostFilter. (kkolinko) 49711: HttpServletRequest#getParts will work in a filter or servlet without an @MultipartConfig annotation or MultipartConfigElement if the new "allowCasualMultipartParsing" context attribute is set to "true". (schultz) 49978: Correct another instance where deployment incorrectly failed if a directory in the work area already existed. (markt) 50582: Refactor access logging so chunked encoding is not forced for all requests if bytes sent is logged. (markt) 50597: Don't instantiate a new instance of a Filter if an instance was provided via the ServletContext.addFilter(String, Filter) method. Patch provided by Ismael Juma. (markt) 50598: Correct URL for Manager text interface. (markt) 50620: Stop exceptions that occur during Session.endAccess() from preventing the normal completion of Request.recycle(). (markt) 50629: Make StandardContext.bindThread() and StandardContext.unbindThread() protected to allow use by sub-classes. (markt) Use getName() instead of logName() in error messages in StandardContext. (kkolinko) 50642: Move the sun.net.www.http.HttpClient keep-alive thread memory leak protection from the JreMemoryLeakPreventionListener to the WebappClassLoader since the thread that triggers the memory leak is created on demand. (markt) 50673: Improve Catalina shutdown when running as a service. Do not call System.exit(). (kkolinko) 50683: Ensure annotations are scanned when unpackWARs is set to false in the Host where a web application is deployed. (markt) Improve HTTP specification compliance in support of Accept-Language header. This protects from known exploit of the Oracle JVM bug that triggers a DoS, CVE-2010-4476. (kkolinko) Prevent possible thread exhaustion if a Comet timeout event takes a while to complete. (markt) Prvent multiple Comet END events if the CometServlet calls event.close() during an END event. (markt) 50325: When the JVM indicates support for RFC 5746, disable Tomcat's allowUnsafeLegacyRenegotiation configuration attribute and use the JVM configuration to control renegotiation. (markt) 50405: Fix occassional NPE when using NIO connector and Comet. (markt) Ensure correct recycling of NIO input filters when processing Comet events. (markt) 50627: Correct interaction of NIO socket and Poller when processing Comet events. (markt) Correct interaction of APR socket and Poller when processing Comet events. (markt) 50631: InternalNioInputBuffer should honor maxHttpHeadSize. (kkolinko) Improve special case handling of javax.servlet.jsp.el.ScopedAttributeELResolver in javax.el.CompositeELResolver to handle sub-classes. (markt) 15688: Use fully-qualified class names in generated jsp files to avoid naming conflicts with user imports. (markt) 46819: Remove redundant object instantiations in JspRuntimeLibrary. Patch provided by Anthony Whitford. (markt) Improve error message when EL identifiers are not valid Java identifiers and use i18n for the error message. (markt) 50680: Prevent an NPE when using tag files from an exploded JAR file, e.g. from within an IDE. Patch provided by Larry Isaacs. (markt) 50591: Fix NPE in ReplicationValve. (kkolinko) Internationalise the log messages for the FarmWarDeployer. (markt) 50600: Prevent a ConcurrentModificationException when removing a WAR file via the FarmWarDeployer. (markt) Be consistent with locks on sessionCreationTiming, sessionExpirationTiming in DeltaManager.resetStatistics(). (kkolinko) 50648: Correctly set the interrupt status if a thread using RpcChannel is interrupted waiting for a message reply. Based on a patch by Olivier Costet. (markt) 50646: Ensure larger Tribes messages are fully read. Patch provided by Olivier Costet. (markt) 50679: Update the FarmWarDeployer to support parallel deployment. (markt) 22278: Add a commented out RemoteAddrValve that limits access to the Manager and Host Manager applications to localhost. Based on a patch by Yann Cébron. (markt) Correct a handful of Javadoc warnings. (markt) Provide additional detail about how web application version order is determined when using parallel deployment. (markt) Correct the documentation for the recoveryCount count attribute of the the default cluster membership. (markt) 50441: Clarify when it is valid to set the docBase attribute in a Context element. (markt) 50526: Provide additional documetation on configuring JavaMail resources. (markt) 50599: Use correct names of roles required to access the Manager application. (markt) Extend the Checkstyle tests to check for license headers. (markt) Modify the build script so a release build always rebuilds the dependencies to ensure that the correct Tomcat version appears in the manifest. (markt) Code clean-up to remove unused code and reduce IDE warnings. (markt) 50601: Code clean-up. Patch provided by sebb. (markt) 50606: Improve CGIServlet: Provide support for specifying empty value for the executable init-param. Provide support for explicit additional arguments for the executable. Those were broken when implementing fix for bug 49657. (kkolinko)
    Update to Apache Commons Daemon 1.0.5. (mturk) 8705: org.apache.catalina.SessionListener now extends java.util.EventListener. (markt) 10526: Add an option to the Authenticators to force the creation of a session on authentication which may offer some performance benefits. (markt) 10972: Improve error message if the className attribute is missing on an element in server.xml where it is required. (markt) 48692: Provide option to parse application/x-www-form-urlencoded PUT requests. (schultz) 48822: Include context name in case of error while stopping or starting a context during its reload. Patch provided by Marc Guillemot. (slaurent) 48837: Extend thread local memory leak detection to include classes loaded by subordinate class loaders to the web application's class loader such as the Jasper class loader. Based on a patch by Sylvain Laurent. (markt) 48973: Avoid creating a SESSIONS.ser file when stopping an application if there's no session. Patch provided by Marc Guillemot. (slaurent) 49000: No longer accept specification invalid name only cookies by default. This behaviour can be restored using a system property. (markt) 49159: Improve memory leak protection by renewing threads of the pool when a web application is stopped. (slaurent) 49372: Re-fix after connector re-factoring. If connector initialisation fails (e.g. if a port is alreasy in use) do not trigger an LifecycleException for an invalid state transition. (markt) 49543: Allow Tomcat to use shared data sources with per application credentials. (fhanik) 49650: Remove unnecessary entries package.access property defined in catalina.properties. Patch provided by Owen Farrell. (markt) 50106: Correct several MBean descriptors. Patch provided by Eiji Takahashi. (markt) Further performance improvements to session ID generation. Remove legacy configuration options that are no longer required. Provide additional options to control the SecureRandom instances used to generate session IDs. (markt) 50201: Update the access log reference in StandardEngine when the ROOT web application is redeployed, started, stopped or defaultHost is changed. (markt/kkolinko) 50282: Load javax.security.auth.login.Configuration with JreMemoryLeakPreventionListener to avoid memory leak when stopping a web application that would use JAAS. (slaurent) 50351: Fix the regression that broke BeanFactory resources caused by the previous fix for 50159. (markt) 50352: Ensure that AsyncListener.onComplete() is fired when AsyncContext.complete() is called. (markt) 50358: Set the correct LifecycleState when stopping instances of the deprecated Embedded class. (markt) Further Lifecycle refactoring for Connectors and associated components. (markt) Correct handling of versioned web applications in deployer. (markt) Correct removal of LifeCycleListeners from Containers via JMX. (markt) Don't use nulls to construct log messages. (markt) Code clean-up. Replace use of inefficient constructors with more efficient alternatives. (markt) 50411: Ensure sessions are removed from the Store associated with a PersistentManager. (markt) 50413: Ensure 304 responses are not returned when using static files as error pages. (markt/kkolinko) 50448: Fix possible IllegalStateException caused by recent session management refactoring. (markt) Ensure aliases settings for a context are retained after a context is reloaded. (markt) Log a warning if context.xml files define values for properties that do not exist (e.g. if there is a typo in a property name). (markt) 50453: Correctly handle multiple X-Forwarded-For headers in the RemoteIpFilter and RemoteIpValve. Patch provided by Jim Riggs. (markt) 50541: Add support for setting the size limit and time limit for LDAP seaches when using the JNDI Realm with userSearch. (markt) All configuration options that use regular expression now require a single regular expression (using java.util.regex) rather than a list of comma-separated or semi-colon-separated expressions. (markt) 50496: Bytes sent in the access log are now counted after compression, chunking etc rather than before. (markt) 50550: When a new directory is created (e.g. via WebDAV) ensure that a subsequent request for that directory does not result in a 404 response. (markt) 50554: Code clean up. (markt) 50556: Improve JreMemoryLeakPreventionListener to prevent a potential class loader leak caused by a thread spawned when the class com.sun.jndi.ldap.LdapPoolManager is initialized and the system property com.sun.jndi.ldap.connect.pool.timeout is set to a value greater than 0. (slaurent) 47319: Return the client's IP address rather than null for calls to getRemoteHost() when the APR connector is used with enableLookups="true" but the IP address is not resolveable. (markt) 50108: Add get/set methods for Connector property minSpareThreads. Patch provided by Eiji Takahashi. (markt) 50360: Provide an option to control when the socket associated with a connector is bound. By default, the socket is bound on Connector.init() and released on Connector.destroy() as per the current behaviour but this can be changed so that the socket is bound on Connector.start() and released on Connector.stop(). This fix also includes further Lifecycle refactoring for Connectors and associated components. (markt) Remove a huge memory leak in the NIO connector introduced by the fix for 49884. (markt) 50467: Protected against NPE triggered by a race condition that causes the NIO poller to fail, preventing the processing of further requests. (markt) 13731: Make variables in _jspService() method final where possible. (markt) 50408: Fix NoSuchMethodException when using scoped variables with EL method invocation. (markt) 50460: Avoid a memory leak caused by using a cached exception instance in JspDocumentParser and ProxyDirContext. (kkolinko) 50500: Use correct coercions (as per the EL spec) for arithmetic operations involving string values containing '.', 'e' or 'E'. Based on a patch by Brian Weisleder. (markt) 50185: Add additional trace level logging to Tribes to assist with fault diagnosis. Based on a patch by Ariel. (markt) Don't try and obtain session data from the cluster if the current node is the only node in the cluster. Log requesting session data as INFO rather than WARNING. (markt) 50503: When web application has a version, Engine level Clustering works correctly. (kfujino) 50547: Add time stamp for CHANGE_SESSION_ID message and SESSION_EXPIRED message. (kfujino) 21157: Ensure cookies are written before the response is commited in the Cookie example. Patch provided by Stefan Radzom. (markt) 50294: Add more information to documentation regarding format of configuration files. Patch provided by Luke Meyer. (markt) Correctly validate provided context path so sessions for the ROOT web application can be viewed through the HTML Manager. (markt) Improve documentation of database connection factory. (rjung) 50488: Update classpath required when using jsvc and add a note regarding server VMs. (markt) Further filtering of Manager display output. (kkolinko) Don't configure Windows installer to use PID file since it is not removed when the service stops which prevents the service from starting. (markt) 14416: Make TagLibraryInfo.getTag() more robust at handling nulls. (markt) 50552: Avoid NPE that hides error message when using Ant tasks. (schultz) Provide two alternative locations for the libraries downloaded from the ASF web site at build time. Use the main distribution site as default and the archive one as fallback. (kkolinko)
    Update to Apache Commons Daemon 1.0.4. (mturk) 3839: Provide a mechanism to gracefully handle the case where users book-mark the form login page or otherwise misuse the FORM authentication process. Based on a suggestion by Mark Morris. (markt) 49180: Add option to disable log rotation in juli FileHandler. Patch provided by Pid (pidster at apache). (funkman) 49991: Ensure servlet request listeners are fired for the login and error pages during FORM authentication. (markt) 50107: When removing a Host via JMX, do not attempt to destroy the host's pipeline twice. Patch provided by Eiji Takahashi. (markt) 50138: Fix threading issues in org.apache.catalina.security.SecurityUtil. (markt) 50157: Ensure MapperListener is only added to a container object once. (markt) 50159: Add a new attribute for <Resource> elements, singleton, that controls whether or not a new object is created every time a JNDI lookup is performed to obtain the resource. The default value is true, which will return the same instance of the resource in every JNDI lookup. (markt) 50168: Separate the Lifecycle.DESTROY_EVENT into Lifecycle.BEFORE_DESTROY_EVENT and Lifecycle.AFTER_DESTROY_EVENT. Use the additional state to ensure that Context objects are only destroyed once. (markt) 50169: Ensure that when a Container is started that it doesn't try and register with the mapper unless its parent has already started. Patch provided by Eiji Takahashi. (markt) 50222: Modify memory leak prevention code so it pins the system class loader in memory rather than than the common class loader, which is better for embedded systems. Patch provided by Christopher Schultz. (markt) Improve debug logging for MapperListener registration. (markt) Expose names of LifecycleListeners and ContainerListeners for StandardContext via JMX. (markt) Add a new option, resourceOnlyServlets, to Context elements that provides a mechanism for working around the issues caused by new requirements for welcome file mapping introduced in Servlet 3.0. By default, the existing Tomcat 6.0.x welcome file handling is used. (markt) Make Tomcat more tolerant of null when generating JMX names for Valves. (markt) Make AccessLogValve attribute enabled changeable via JMX. (pero) Correct infinite loop if ServletRequest.startAsync(ServletRequest, ServletResponse) was called. (markt) 50232: Remove dependency between StoreBase and PersistentManager and associated code clean-up. Patch provided by Tiago Batista. (markt) 50252: Prevent ClassCastException when using a <ResourceLink>. Patch provided by Eiji Takahashi. (markt) Reduce synchronization in session managers to improve performance of session creation. (markt) If starting children automatically when adding them to a container (e.g. when adding a Context to a Host) don't lock the parent's set of children whilst the new child is being started since this can block other threads and cause issues such as lost cluster messages. (markt) Implement support for parallel deployment. This allows multiple versions of the same web application to be deployed to the same context path at the same time. Users without a current session will be mapped to the latest version of the web application. Users with a current session will continue to use the version of the web application with which the session is associated until the session expires. (markt) 50308: Allow asynchronous request processing to call AsyncContext.dispatch() once the asynchronous request has timed out. (markt) Make memory leak prevention code that clears ThreadLocal instances more robust against objects with toString() methods that throw exceptions. (markt) 49860: Complete support for handling trailing headers in chunked HTTP requests. (markt) Impose a limit on the length of the trailing headers. The limit is configurable with a system property and is 8192 by default. (kkolinko) 50207: Ensure Comet timeout events are triggered. This bug was a regression triggered by the fix for 49884. (markt) 49297: Enforce the rules in the JSP specification for parsing the attributes of custom and standard actions that require that the attribute names are unique within an element and that there is whitespace before the attribute name. The whitespace test can be disabled by setting the system property org.apache.jasper.compiler.Parser.STRICT_WHITESPACE to false. Attributes of the page directive have slightly different rules. The implementation of that part of the fix is based on a patch by genspring. (markt) 50105: When processing composite EL expressions use Enum.name() rather than Enum.toString() as required by the EL specification. (markt) Fix minor thread-safety and performance issues in the implementation of maxLoadedJsps. (rjung) Add support for unloading JSPs that have not been requested for a long time using the new parameter jspIdleTimeout. (rjung) Add logging and JMX support to JSP unloading. (rjung) 50192: Improve performance for EL when running under a security manager. Based on a patch by Robert Goff. (markt) 50228: Improve recycling of BodyContentImpl. This avoids keeping a cached reference to a webapp-provided Writer used in JspFragment.invoke() calls. (kkolinko) 50273: Provide a workaround for an HP-UX issue that can result in large numbers of SEVERE log messages appearing in the logs as a result of normal operation. (markt) 50293: Increase the size of internal ELResolver array from 2 to 8 since in typical usage there are at least 5 resolvers. Based on a patch by Robert Goff. (markt) Add support for maxActiveSessions attribute to BackupManager. (kfujino) Improve sending an access message in DeltaManager. maxInactiveInterval of not Manager but the session is used. If maxInactiveInterval is negative, an access message is not sending. (kfujino) 50183: BIO sender was not scheduling tasks to the executor during normal operation. Patch provided by Ariel. (markt) 50184: Add an option to the RpcChannel to enable the Channel send options to be set for the reply message. Based on a patch by Ariel. (markt) Ensure that a new Context waiting for session data from other nodes in the cluster does not block the processing of clustering messages for other Contexts. (markt) 49426: Localize messages in the Manager application based on the Locale of the user rather than the default Locale of the server. (markt) Localize messages in the Host Manager application based on the Locale of the user rather than the default Locale of the server. (markt) 50242: Provide a sample log4j configuration that more closely matches the default JULI configuration. Patch provided by Christopher Schultz. (markt) Restore the ability to edit the contents of /WEB-INF and /META-INF via WebDAV via the provision of a new configuration option, allowSpecialPaths. (markt) Correct broken links for on-line JavaDocs. (markt) 50230: Add new DistributedManager interface that is implemented by the Backup Manager to remove circular dependency between tomcat-catalina-ha and tomcat-catalina modules. Also allows third-party distributed Manager implementations to report full session information through the HTML Manager. (markt) Improve Tomcat Logging documentation. (kkolinko) 50303: Update JNDI how-to to reflect the new JavaMail download location and that JAF is now included in Java SE 6. (markt) Fix ordering functionality on sessions page for the HTML Manager application. (markt) Fix primary sessions not always being treated as such in the HTML Manager application. (markt) Fix message not being displayed after session attribute removal in the HTML Manager application. (markt) 50310: Fix display of Servlet information in the Manager application. (markt) CVE-2010-4172: Multiple XSS in the Manager application. (markt/kkolinko) 50316: Fix display of negative values in the Manager application. (kkolinko) 50318: Avoid NPE when trying to view session detail for an expired session in the Manager application. (markt) Correct a handful of Javadoc warnings. (markt) 22965: Fix some typos and formatting issues in the global web.xml file. Based on a patch by Yann Cébron. (markt) Extend Checkstyle validation checks to check for unused imports. (markt) General code clean-up to reduce (not eliminate) the number of warnings reported by IDEs. (markt) 50140: Don't ignore a user specified installation directory when performing a silent install with the Windows installer on 64-bit platforms. (markt) Reimplemented Windows installer dialogs, using modern libraries (nsDialogs, MUI2). (kkolinko) When installing with the Windows installer on 64-bit platforms, allow the user to select either a 32-bit JDK or a 64-bit JDK. If a 32-bit JDK is selected, the 32-bit service wrapper and the 32-bit native DLL will be installed. If a 64-bit JDK is selected, the 64-bit service wrapper and the 64-bit native DLL will be installed. (markt/kkolinko) Create Windows shortcuts for the Manager and Host Manager webapps. (kkolinko) Support /? command line option in the Windows Installer. (kkolinko) Display and allow to change roles for the Tomcat admin user in the Windows installer. (kkolinko) In the Windows installer: do not leave stale server.xml and tomcat-users.xml fragments in the $TEMP folder. (kkolinko) 49819: Redesign of home page by Pid (pidster at apache). (timw)
    49428: Re-implement the fix for bug 49428 – namespace issues for some Microsoft WebDAV clients. (kkolinko) 49669: Fix memory leak triggered by using the deprecated javax.security.auth.Policy class. (markt) 49922: Don't add filter twice to filter chain if the filter matches more than one URL pattern and/or Servlet name. Patch provided by heyoulin. (markt) 49937: Use an InstanceManager when creating an AsyncListener through the AsyncContext to ensure annotations are processed. Based on a patch by David Jencks. (markt) To avoid NoSuchMethodException, xmlValidation and xmlNamespaceAware are removed from the createStandardHost definition of mbeans-descriptors.xml. (kfujino) 49945: Continue improvements to JMX. Fix a handful of attributes that were showing as Unavailable in JConsole. Patch provided by Chamith Buddhika. (markt) 49952: Allow ServletContainerInitializers to add listeners to a web application. Patch provided by David Jencks. (markt) 49956: Handle case when @Resource annotation uses the full JNDI name for a resource. Based on a patch by Gurkan Erdogdu. (markt) 49557: Correct regression due to Lifecycle refactoring that cleared all work directories (with compiled JSPs and persisted sessions) when Tomcat was stopped. (markt) 49978: Correctly handle the case when a directory expected to be created during web application start is already present. Rather than throwing an exception and failing to start, allow the web application to start normally. (markt) 49987: Fix thread safety issue with population of servlet context initialization parameters. (markt) 49994: As per the Java EE 6 specification, return a new object instance for each JNDI look up of a resource reference. (markt) 50015: Re-factor dynamic servlet security implementation to make extensions, such as JACC implementations, simpler. Patch provided by David Jencks. (markt) 50016: Re-factor isUserInRole() and login()/logout() methods to support JACC implementations and to improve encapsulation. Patch provided by David Jencks. (markt) 50017: Code clean-up. No functional change. Patch provided by sebb. (markt) 50027: Avoid NPE on start when a Context is defined in server.xml with one or more JNDI resources. (markt) 50059: JARs should always be searched for static resources even if the web application is marked as meta-data complete. (markt) 50063: Correct regression in fix for 50059 that causes applications marked as meta-data complete to return 404s for all requests. Patch provided by heyoulin. (markt) 50087: Catch ClassFormatErrors when scanning for annotations. (markt) 49923: Avoid using negative timeouts during acceptor unlock to ensure APR connector shuts down properly. (mturk) 49972: Fix potential thread safe issue when formatting dates for use in HTTP headers. (markt) 50003: Set not maxThreads but minSpareThreads to corePoolSize, if AbstractEndpoint.setMinSpareThreads is called. (kfujino) 50044: Fix issue when using comet where socket remained in long poll after the comet request has ended. (markt) 50054: Correctly handle the setting of minSpareThreads in AJP connector. (kfujino) 50072: Fix issues when using a non-blocking read for the request line with the NIO connector that could result in the request line being mis-read. (markt) 49986: Fix thread safety issue for JSP reload. (timw) 49998: Make jsp:root detection work with single quoted attributes as well. (timw) Correctly handle the setting of primitive bean values via expression language. (markt) Don't swallow exceptions when processing TLD files and handle the case when there is no web.xml file. (markt) 50066: Fix building of recursive tag files when the file depends on a JAR file. Patch provided by Sylvain Laurent. (markt) 50078: Fix threading problem in EL caches. Patch provided by Takayoshi Kimura. (markt) Make EL cache sizes configurable. (markt) Apply filters to default home page so copyright year is correctly displayed. (markt) 48716: Do not call reset if the default LogManager is in use. (markt) 50013: Correctly package classes from org.apache.tomcat.util.file and add the tomcat-util.jar to the class path for the Ant tasks. Based on a patch provided by Sylvain Laurent. (markt)
    48644: Review all instances of catching Throwable and re-throw where appropriate. (markt) Allow glob patterns in the jarsToSkip configuration and add some debug logging to the jar scanner. (rjung) 48738: Workaround a couple of long standing JDK bugs to enable GZIP compressed output streams to be flushed. Based on a patch provided by Jiong Wang. (markt) 48967: Replace strings "catalina.base" and "catalina.home" by globally defined constants. Patch provided by Marc Guillemot. (rjung) 49195: Don't report an error when shutting down a Windows service for a Tomcat instance that has a disabled shutdown port. (markt) 49209: Prevent possible AccessControlException during undeployment when running with a security manager. Patch provided by Sylvain Laurent. (markt) 49657: Handle CGI executables with spaces in the path. (markt) 49667: Ensure that using the JDBC driver memory leak prevention code does not cause a one of the memory leaks it is meant to avoid. (markt) 49670: Restore SSO functionality that was broken by Lifecycle refactoring. (markt) 49698: Allow a listener to complete an asynchronous request if it times out. (markt) 49714: The annotation process of Jar doesn't influence distributable element of web.xml. (kfujino) 49721: Alls JAR in a web application should be searched for resources, not just those with a web-fragment.xml that is going to be processed. (markt) 49728: Improve PID file handling when another process is managing the PID file and Tomcat does not have write access. (markt) 49730: Fix a race condition in StandardThreadExector that can cause requests to experience large delays. Patch provided by Sylvain Laurent. (markt) 49749: Single sign on cookies should have httpOnly flag set using same rules as session cookies. (markt) 49750: Align WebappClassLoader.validate() implementation with Javadoc and ensure that javax.servlet.* classes can not be loaded by a WebappClassLoader instance. Patch provided by pid. (markt) 49757: Correct some generics warnings. Based on a patch provided by Gábor. (markt) 49779: Improve handling of POST requests and FORM authentication, particularly when the user agent responds to the 302 response by repeating the POST request including a request body. Any request body provided at this point is now swallowed. (markt) CSRF prevention filter did not correctly handle URLs that used anchors. (markt) Fix memory leak on web application stopped caused by failed to de-register the web application's Servlets with the MBean server. (markt) More tweaks to the Lifecycle refactoring to ensure that when a component is being destroyed, the destroy method is only called once on each child component. (markt) Keep the MBean names for web applications consistent between Tomcat 6 and Tomcat 7. (markt) 49856: Add an executorName attribute to Connectors so it is possible to trace ThreadPool to Connector to Executor via the JMX interface. (markt) 49865: Tomcat failed to start if catalina.properties was not present. (markt) 49876: Fix the generics warnings in the copied Apache Jakarta BCEL code. Based on a patch by Gábor. (markt) 49883: Ensure that the CombinedRealm and LockOutRealm return a name for use in log messages rather than throwing an UnsupportedOperationException. (markt) 49884: Fix occassional NullPointerException on async complete(). This resulted in a major refactoring of the async implementation to address a number of threading issues. (markt) Update the version numbers in ServerInfo defaults to Tomcat 7.0.x. (markt) 49892: Correct JNDI name for method resource injections. Based on a patch by Gurkan Erdogdu. (markt) Ensure that Context elements defined in server.xml use any configClass setting specified in the parent Host element. (markt) GSOC 2010. Enable the creation of Services, Engines, Connectors, Hosts and Contexts via JMX from a minimal server.xml that contains only a Server element. Based on a patch by Chamith Buddhika. (markt) 49909: Fix a regression introduced with the fix for 47950 that prevented JSTL classes being loaded. (markt) 49915: Make error more obvious, particularly when accessed via JConsole, if StandardServer.storeConfig() is called when there is no StoreConfig implementation present. (markt) 50018: Fix some minor Javadoc errors in Jasper source. Based on a patch by sebb. (timw) 50021: Correct a regression in the fix for 46844 that may have caused additional problems during a failure at start up. (markt) 50026: Prevent serving of resources from WEB-INF and META-INF directories when DefaultServlet or WebdavServlet is mapped to a sub-path of the context. This changes DefaultServlet to always serve resources with paths relative to the root of the context regardless of where it is mapped, which is a breaking change for current servlet-mappings that map the default servlet to a subpath. (timw) 50689: Provide 100 Continue responses at appropriate points during FORM authentication if client indicates that they are expected. (markt) Wait for the connectors to exit before closing them down. (mturk) Follow up to 48545. Make JSSE connectors more tolerant of a incorrect trust store password. (markt) Fix some edge cases in the NIO connector when handling requests that are not received all at the same time and the socket needs to be returned to the poller. (markt) Further work to reduce the code duplication in the HTTP connectors. (markt) Make sure acceptor threads are stopped when the connector is stopped. (markt) Make sure async timeout thread is stopped when the connector is stopped. (markt) 49625: Ensure Vary header is set if response may be compressed rather than only setting it if it is compressed. (markt) 49802: Re-factor connector pause, stop and destroy methods so that calling any of those methods has the expected results. (markt) Various refactorings to reduce code duplication and unnecessary code in the connectors. (markt) 49860: Add partial support for trailing headers in chunked HTTP requests. (markt) 49665: Provide better information including JSP file name and location when a missing file is detected during TLD handling. Patch provided by Ted Leung. (markt) 49726: Specifying a default content type via a JSP property group should not prevent a page from setting some other content type. (markt) 49799: The new omit attribute for jsp:attribute elements now supports the use of expressions and expression language. (markt) 49916: Switch to using an initialisation parameter to pass JSP file information from Catalina to Jasper. This simplifies the Catalina code as well as making it easier for Geronimo and others to integrate Jasper. Patch provided by David Jencks. (markt) 49985: Fix thread safety issue in EL parser. (markt) Remove domainReplication attribute from ClusterManager. If you send session to only same domain, use DomainFilterInterceptor. (kfujino) Add Null check when CHANGE_SESSION_ID message received. (kfujino) Add support for LAST_ACCESS_AT_START system property to DeltaSession. (kfujino) Avoid a NPE in the DeltaManager when a parallel request invalidates the session before the current request has a chance to send the replication message. (markt) 49905: Prevent memory leak when using asynchronous session replication. (markt) 49924: When non-primary node changes into a primary node, make sure isPrimarySession is changed to true. (kfujino) Correct the class name of the default JAR scanner in the documentation web application. (rjung) 49585: Update JSVC documentation to reflect new packaging of Commons Daemon. (markt) Update the Servlet, JSP and EL Javadoc links to link to the specifications and the relevant part of the Java EE 6 Javadoc. (markt) Update a few places in the docs where the Manager documentation referred to the old role name of manager rather than than the new manager-script. (markt) 49861: Don't log RMI ports formatted with commas for the JMX remote listener. (markt) Correct the user names created by the Windows installer for the Manager and Host Manager applications. (mturk) Correct the Eclipse compiler dependency in the Jasper POM. (markt) Extend Checkstyle validation checks to check import order. (markt) 49758: Fix generics warnings exposed by a fix in Eclipse 3.6. Patch provided by sebb. (markt) Update Apache Commons Pool to 1.5.5. (markt) 49955: Improvement and correction of Building Tomcat guide. Based on a patch from Wesley Acheson. (timw)
    Fix regression that prevented running with a security manager enabled. (markt) Correct Javadoc errors. (markt) Provide Javadoc for Servlet 3.0 API, JSP 2.2 API and EL 2.2 API. (markt) Remove second copy of RUNNING.txt from the full-docs distribution. Some unpacking utilities can't handle multiple copies of a file with the same name in a directory. (markt) Extend Checkstyle validation checks to check for tabs in nearly all text files. (markt) Update Apache Commons Daemon from 1.0.2 to 1.0.3. (markt) Update Eclipse JDT Core Batch Compiler (ecj.jar) from 3.5.1 to 3.6. (markt)
    GSOC 2010. Continue work to align MBean descriptors with reality. Patch provided by Chamith Buddhika. (markt) When running under a security manager, enforce package access and package definition restrictions defined in the catalina.properties file. (markt) When using a Loader configured with searchExternalFirst="true" failure to find the class in an external repository should not prevent searching of the local repositories. (markt) Add entryPoint support to the CSRF prevention filter. (markt) 48297: Correctly initialise handler chain for web services resources. (markt) 48960: Add a new option to the SSI Servlet and SSI Filter to allow the disabling of the exec command. This is now disabled by default. Based on a patch by Yair Lenga. (markt) 48998, 49617: Add the ExpiresFilter, a port of the httpd mod_expires module. Patch provided by Cyrille Le Clerc. (markt) 49030: When initializing/starting/stopping connectors and one of them fails, do not ignore the others. (markt/kkolinko) 49128: Don't swallow exceptions unnecessarily in WebappClassLoader.start(). (markt) 49182: Align comments in setclasspath.[sh|bat] with behaviour. Based on a patch provided by sebb. (markt) 49230: Enhance JRE leak prevention listener with protection for the keep-alive thread started by sun.net.www.http.HttpClient. Based on a patch provided by Rob Kooper. (markt) 49414: When reporting threads that may have triggered a memory leak on web application stop, attempt to differentiate between request processing threads and threads started by the application. (markt) 49428: Add a work-around for the known namespace issues for some Microsoft WebDAV clients. Patch provided by Panagiotis Astithas. (markt) Add support for *.jar pattern in VirtualWebappLoader. (kkolinko) Use a LockOutRealm in the default configuration to prevent attempts to guess user passwords by brute-force. (markt) 49478: Add support for user specified character sets to the AddDefaultCharsetFilter. Based on a patch by Felix Schumacher. (markt) 49503: Make sure connectors bind to their associated ports sufficiently early to allow jsvc and the org.apache.catalina.startup.EXIT_ON_INIT_FAILURE system property to operate correctly. (markt) 49525: Ensure cookies for the ROOT context have a path of / rather than an empty string. (markt) 49528, 49567: Ensure that AsyncContext.isAsyncStarted() returns the correct value after AsyncContext.start() and that if AsyncContext.complete() is called on a separate thread that it is handled correctly. (markt) 49530: Contexts and Servlets not stopped when Tomcat is shut down. (markt) 49536: If no ROOT context is deployed, ensure a 404 rather than a 200 is returned for requests that don't map to any other context. (markt) Additional debug logging in StandardContext to provide information on Manager selection. (markt) 49550: Supress deprecation warning where deprecated code is required to be used. No functional change. Patch provided by Sebb. (markt) 49551: Allow default context.xml location to be specified using an absolute path. (markt) Improve logging of unhandled exceptions in servlets by including the path of the context where the error occurred. (markt) Include session ID in error message logged when trying to set an attribute on an invalid session. (markt) Improve the CSRF protection filter by using SecureRandom rather than Random to generate nonces. Also make the implementation class used user configurable. (markt) Avoid NullPointerException, when copyXML=true and META-INF/context.xml does not exist. (kfujino) 49598: When session is changed and the session cookie is replaced, ensure that the new Set-Cookie header overwrites the old Set-Cookie header. (markt) Create a thread to trigger asynchronous timeouts when using the BIO connector, change the default timeout to 10s (was infinite) and make the default timeout configurable using the asyncTimeout attribute on the connector. (pero/markt) 49600: Make exceptions returned by the ProxyDirContext consistent for resources that weren't found by checking the DirContext or the cache. Test case based on a patch provided by Marc Guillemot. (markt) 49613: Improve performance when using SSL for applications that make multiple class to Request.getAttributeNames(). Patch provided by Sampo Savolainen. (markt) Handle the edge cases where resources packaged in JARs have names that start with a single quote character or a double quote character. (markt) Correct copy and paste typo in web.xml parsing rules that mixed up local-ejb-ref and resource-env-ref. (markt) Refactor session managers to remove unused code and to reduce code duplication. Also, all session managers used for session replication now extend org.apache.catalina.ha.session.ClusterManagerBase. (markt) Remove references to Jikes since it does not support Java 6. (markt) Correct over zealous type checking for EL in attributes that broke the use of JSF converters. (markt) Correct algorithm used to identify correct method to use when a MethodExpressions is used in EL. (markt) 49217: Ensure that identifiers used in EL meet the requirements of the Java Language Specification. (markt) Improve logging of JSP exceptions by including JSP snippet (if enabled) rather than just the root cause in the host log. (markt) 49555: Correctly handled Tag Libraries where functions are defined in static inner classes. (markt) 49127: Don't swallow exceptions unnecessarily in SimpleTcpReplicationManager.startInternal(). (markt) 49407: Change the BackupManager so it is consistent with DeltaManager and reports both primary and backup sessions when active sessions are requested. (markt) 49445: When session ID is changed after authentication, ensure the DeltaManager replicates the change in ID to the other nodes in the cluster. (kfujino) 49112: Update the ROOT web application's index page. Patch provided by pid. (markt) 49213: Add the permissions necessary to enable the Manager application to operate currently when running with a security manager. (markt) 49436: Correct documented default for readonly attribute of the UserDatabase component. (markt) 49475: Use new role name for manager application access on the ROOT web application's index page. (markt) 49476: CSRF protection was preventing access to the session expiration features. Also switch the manager application to the generic CSRF protection filter. (markt) Better handle failure to create directories required for new hosts in the Host Manager application. (markt) Switch the Host Manager application to the generic CSRF protection for the HTML interface and prevent started hosts from being started and stopped hosts from being stopped. (markt) 49518: Fix typo in extras documentation. (markt) 49522: Fix regression due to change of name for MBeans for naming resources that broke the complete server status page in the manager application. Note these MBeans now have a new name. (markt) 49570: When using the example compression filter, set the Vary header on compressed responses. (markt) Add redirects for the root of the manager and host-manager web applications that redirect users to the html interface rather than returning a 404. (markt) Provide the HTML Manager application with the ability to differentiate between primary, backup and proxy sessions. Note that proxy sessions are only shown if enabled in web.xml. (markt) 49130: Better describe the core package in the Windows installer, making it clear that the service will be installed. Patch provided by sebb. (markt) Re-factor unit tests to enable them to be run once with each of the HTTP connector implementations (BIO, NIO and APR/native). (markt) 49268: Add the necessary plumbing to include CheckStyle in the build process. Start with no checks. Additional checks will be added as they are agreed. (markt) Updated to Ant 1.8.1. The build now requires a minimum of Ant 1.8.x. (markt) Update the re-packaged version of commons-fileupload from 1.2.1 to 1.2.2. The layout of re-packaged version was also restored to the original commons-fileupload layout to make merging of future updates easier. (markt) Update the re-packaged version of Jakarta BCEL from trunk revision 880760 to trunk revision 978831. (markt)
    Update Servlet support to the Servlet 3.0 specification. (all) Improve and document VirtualWebappLoader. (rjung) 43642: Add prestartminSpareThreads attribute for Executor. (jfclere) Switch from AnnotationProcessor to InstanceManager. Patch provided by David Jecks with modifications by Remy. (remm/fhanik) 620845 and 669119. Make shutdown address configurable. (jfclere) 651977 Add some missing control checks to ThreadWithAttributes. (markt) 677640 Add a startup class that does not require any configuration files. (costin) 700532 Log if temporary file operations within the CGI servlet fail. Make sure header Reader is closed on failure. (markt) 708541 Delete references to DefaultContext which was removed in 6.0.x. (markt) 709018 Initial implementation of an asynchronous file handler for JULI. (fhanik) Give session thisAccessedTime and lastAccessedTime clear semantics. (rjung) Expose thisAccessedTime via Session interface. (rjung) Provide a log format for JULI that provides the same information as the default but on a single line. (markt) 723889 Provide the ability to configure the Executor job queue size and a timeout for adding jobs to the queue. (fhanik) Add support for aliases to StandardContext. This allows content from other directories and/or WAR files to be mapped to paths within the context. (markt) Provide clearer definition of Lifecycle interface, particularly start and stop, and align components that implement Lifecycle with this definition. (markt) 48662: Provide a new option to control the copying of context XML descriptors from web applications to the host's xmlBase. Copying of XML descriptors is now disabled by default. (markt) Move comet classes from the org.apache.catalina package to the org.apache.catalina.comet package to allow comet to work under a security manager. (markt) Port SSLInsecureRenegotiation from mod_ssl. This requires to use tomcat-native 1.2.21 that have option to detect this support from OpenSSL library. (mturk) Allow bigger AJP packets also for request bodies and responses using the packetSize attribute of the Connector. (rjung) 703017 Make Java socket options consistent between NIO and JIO connector. Expose all the socket options available on java.net.Socket (fhanik) 46051: The writer returned by getWriter() now conforms to the PrintWriter specification and uses platform dependent line endings rather than always using \r\n. (markt) Use tc-native 1.2.x which is based on APR 1.3.3+ (mturk) 724239 NIO connector now always uses an Executor. (fhanik) 724393 Implement keepAliveCount for NIO connector in a thread safe manner. (fhanik) 724849 Implement keep alive timeout for NIO connector. (fhanik) Update JSP support to the JSP 2.2 specification. (markt) Update EL support to the EL 2.2 specification. (markt) 787978 Use "1.6" as the default value for compilerSourceVM and compilerTargetVM options of Jasper. (kkolinko) 48358: Add support for limiting the number of JSPs that are loaded at any one time. Based on a patch by Isabel Drost. (markt) 48689: Access TLD files through a new JarResource interface to make extending Jasper simpler, particularly in OSGi environments. Patch provided by Jarek Gawor. (markt) Add support for UDP and secure communication to tribes. (fhanik) Add versioning to the tribes communication protocol to support future developments. (fhanik) Add a demo on how to use the payload. (fhanik) Started to add JMX support to the cluster implementation. (markt) 609778 Minor fixes to the throughput interceptor and the NIO receiver. (fhanik) 630234 Additional checks for the NIO receiver. (fhanik) 671650 Improve error message when multicast is not enabled. (fhanik) 631321 Update changelog to support the <rev> element in the documentation. (fhanik) A number of additional roles were added to the Manager and Host Manager applications to separate out permissions for the HTML interface, the text interface and the JMX proxy. (markt) CSRF protection was added to the Manager and Host Manager applications. (markt) List array elements in the JMX proxy output of the Manager application. (rjung) A new JmxRemoteLifecycleListener that can be used to fix the ports used for remote JMX connections, eg when using JConsole. (markt) Numerous code clean-up changes including the use of generics and removing unused imports, fields, parameters and methods. (markt) All deprecated internal code has been removed. Warning: If you have custom components for a previous Tomcat version that extend internal Tomcat classes and override deprecated methods it is highly likely that they will no longer work. (markt) Parameterize version number throughout build scripts and source. (rjung)
    tomcat7-7.0.52/webapps/docs/elapi/0000755000175100017510000000000012301126373016624 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/elapi/index.html0000644000175100017510000000242611656646736020653 0ustar locutuslocutus API docs The EL Javadoc is not installed by default. Download and install the "fulldocs" package to get it. You can also access the javadoc online in the Tomcat documentation bundle. tomcat7-7.0.52/webapps/docs/appdev/0000755000175100017510000000000012301126373017011 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/web.xml.txt0000644000175100017510000001415712271304167021143 0ustar locutuslocutus My Web Application This is version X.X of an application to perform a wild and wonderful task, based on servlets and JSP pages. It was written by Dave Developer (dave@mycompany.com), who should be contacted for more information. webmaster myaddress@mycompany.com The EMAIL address of the administrator to whom questions and comments about this application should be addressed. controller This servlet plays the "controller" role in the MVC architecture used in this application. It is generally mapped to the ".do" filename extension with a servlet-mapping element, and all form submits in the app will be submitted to a request URI like "saveCustomer.do", which will therefore be mapped to this servlet. The initialization parameter names for this servlet are the "servlet path" that will be received by this servlet (after the filename extension is removed). The corresponding value is the name of the action class that will be used to process this request. com.mycompany.mypackage.ControllerServlet listOrders com.mycompany.myactions.ListOrdersAction saveCustomer com.mycompany.myactions.SaveCustomerAction 5 graph This servlet produces GIF images that are dynamically generated graphs, based on the input parameters included on the request. It is generally mapped to a specific request URI like "/graph". controller *.do graph /graph 30 tomcat7-7.0.52/webapps/docs/appdev/installation.xml0000644000175100017510000000740612271304167022250 0ustar locutuslocutus ]> &project; Craig R. McClanahan Yoav Shapira Installation

    In order to use Tomcat for developing web applications, you must first install it (and the software it depends on). The required steps are outlined in the following subsections.

    Tomcat 7.0 was designed to run on Java SE 6.

    Compatible JDKs for many platforms (or links to where they can be found) are available at http://www.oracle.com/technetwork/java/javase/downloads/index.html.

    Binary downloads of the Tomcat server are available from http://tomcat.apache.org/. This manual assumes you are using the most recent release of Tomcat 7. Detailed instructions for downloading and installing Tomcat are available here.

    In the remainder of this manual, example shell scripts assume that you have set an environment variable CATALINA_HOME that contains the pathname to the directory in which Tomcat has been installed. Optionally, if Tomcat has been configured for multiple instances, each instance will have its own CATALINA_BASE configured.

    Binary downloads of the Ant build tool are available from http://ant.apache.org/. This manual assumes you are using Ant 1.8 or later. The instructions may also be compatible with other versions, but this has not been tested.

    Download and install Ant. Then, add the bin directory of the Ant distribution to your PATH environment variable, following the standard practices for your operating system platform. Once you have done this, you will be able to execute the ant shell command directly.

    Besides the required tools described above, you are strongly encouraged to download and install a source code control system, such as the Concurrent Version System (CVS), to maintain historical versions of the source files that make up your web application. Besides the server, you will also need appropriate client tools to check out source code files, and check in modified versions.

    Detailed instructions for installing and using source code control applications is beyond the scope of this manual. However, CVS server and client tools for many platforms (along with documentation) can be downloaded from http://www.cvshome.org/.

    tomcat7-7.0.52/webapps/docs/appdev/deployment.xml0000644000175100017510000002770012271304167021726 0ustar locutuslocutus ]> &project; Craig R. McClanahan Deployment

    Before describing how to organize your source code directories, it is useful to examine the runtime organization of a web application. Prior to the Servlet API Specification, version 2.2, there was little consistency between server platforms. However, servers that conform to the 2.2 (or later) specification are required to accept a Web Application Archive in a standard format, which is discussed further below.

    A web application is defined as a hierarchy of directories and files in a standard layout. Such a hierarchy can be accessed in its "unpacked" form, where each directory and file exists in the filesystem separately, or in a "packed" form known as a Web ARchive, or WAR file. The former format is more useful during development, while the latter is used when you distribute your application to be installed.

    The top-level directory of your web application hierarchy is also the document root of your application. Here, you will place the HTML files and JSP pages that comprise your application's user interface. When the system administrator deploys your application into a particular server, he or she assigns a context path to your application (a later section of this manual describes deployment on Tomcat). Thus, if the system administrator assigns your application to the context path /catalog, then a request URI referring to /catalog/index.html will retrieve the index.html file from your document root.

    To facilitate creation of a Web Application Archive file in the required format, it is convenient to arrange the "executable" files of your web application (that is, the files that Tomcat actually uses when executing your app) in the same organization as required by the WAR format itself. To do this, you will end up with the following contents in your application's "document root" directory:

    • *.html, *.jsp, etc. - The HTML and JSP pages, along with other files that must be visible to the client browser (such as JavaScript, stylesheet files, and images) for your application. In larger applications you may choose to divide these files into a subdirectory hierarchy, but for smaller apps, it is generally much simpler to maintain only a single directory for these files.

    • /WEB-INF/web.xml - The Web Application Deployment Descriptor for your application. This is an XML file describing the servlets and other components that make up your application, along with any initialization parameters and container-managed security constraints that you want the server to enforce for you. This file is discussed in more detail in the following subsection.

    • /WEB-INF/classes/ - This directory contains any Java class files (and associated resources) required for your application, including both servlet and non-servlet classes, that are not combined into JAR files. If your classes are organized into Java packages, you must reflect this in the directory hierarchy under /WEB-INF/classes/. For example, a Java class named com.mycompany.mypackage.MyServlet would need to be stored in a file named /WEB-INF/classes/com/mycompany/mypackage/MyServlet.class.

    • /WEB-INF/lib/ - This directory contains JAR files that contain Java class files (and associated resources) required for your application, such as third party class libraries or JDBC drivers.

    When you install an application into Tomcat (or any other 2.2 or later Servlet container), the classes in the WEB-INF/classes/ directory, as well as all classes in JAR files found in the WEB-INF/lib/ directory, are made visible to other classes within your particular web application. Thus, if you include all of the required library classes in one of these places (be sure to check licenses for redistribution rights for any third party libraries you utilize), you will simplify the installation of your web application -- no adjustment to the system class path (or installation of global library files in your server) will be necessary.

    Much of this information was extracted from Chapter 9 of the Servlet API Specification, version 2.3, which you should consult for more details.

    Like most servlet containers, Tomcat also supports mechanisms to install library JAR files (or unpacked classes) once, and make them visible to all installed web applications (without having to be included inside the web application itself). The details of how Tomcat locates and shares such classes are described in the Class Loader HOW-TO documentation. The location commonly used within a Tomcat installation for shared code is $CATALINA_HOME/lib. JAR files placed here are visible both to web applications and internal Tomcat code. This is a good place to put JDBC drivers that are required for both your application or internal Tomcat use (such as for a JDBCRealm).

    Out of the box, a standard Tomcat installation includes a variety of pre-installed shared library files, including:

    • The Servlet 3.0 and JSP 2.2 APIs that are fundamental to writing servlets and JavaServer Pages.

    As mentioned above, the /WEB-INF/web.xml file contains the Web Application Deployment Descriptor for your application. As the filename extension implies, this file is an XML document, and defines everything about your application that a server needs to know (except the context path, which is assigned by the system administrator when the application is deployed).

    The complete syntax and semantics for the deployment descriptor is defined in Chapter 13 of the Servlet API Specification, version 2.3. Over time, it is expected that development tools will be provided that create and edit the deployment descriptor for you. In the meantime, to provide a starting point, a basic web.xml file is provided. This file includes comments that describe the purpose of each included element.

    NOTE - The Servlet Specification includes a Document Type Descriptor (DTD) for the web application deployment descriptor, and Tomcat enforces the rules defined here when processing your application's /WEB-INF/web.xml file. In particular, you must enter your descriptor elements (such as <filter>, <servlet>, and <servlet-mapping> in the order defined by the DTD (see Section 13.3).

    A /META-INF/context.xml file can be used to define Tomcat specific configuration options, such as an access log, data sources, session manager configuration and more. This XML file must contain one Context element, which will be considered as if it was the child of the Host element corresponding to the Host to which the web application is being deployed. The Tomcat configuration documentation contains information on the Context element.

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    In order to be executed, a web application must be deployed on a servlet container. This is true even during development. We will describe using Tomcat to provide the execution environment. A web application can be deployed in Tomcat by one of the following approaches:

    • Copy unpacked directory hierarchy into a subdirectory in directory $CATALINA_BASE/webapps/. Tomcat will assign a context path to your application based on the subdirectory name you choose. We will use this technique in the build.xml file that we construct, because it is the quickest and easiest approach during development. Be sure to restart Tomcat after installing or updating your application.

    • Copy the web application archive file into directory $CATALINA_BASE/webapps/. When Tomcat is started, it will automatically expand the web application archive file into its unpacked form, and execute the application that way. This approach would typically be used to install an additional application, provided by a third party vendor or by your internal development staff, into an existing Tomcat installation. NOTE - If you use this approach, and wish to update your application later, you must both replace the web application archive file AND delete the expanded directory that Tomcat created, and then restart Tomcat, in order to reflect your changes.

    • Use the Tomcat "Manager" web application to deploy and undeploy web applications. Tomcat includes a web application, deployed by default on context path /manager, that allows you to deploy and undeploy applications on a running Tomcat server without restarting it. See Manager App HOW-TO for more information on using the Manager web application.

    • Use "Manager" Ant Tasks In Your Build Script. Tomcat includes a set of custom task definitions for the Ant build tool that allow you to automate the execution of commands to the "Manager" web application. These tasks are used in the Tomcat deployer.

    • Use the Tomcat Deployer. Tomcat includes a packaged tool bundling the Ant tasks, and can be used to automatically precompile JSPs which are part of the web application before deployment to the server.

    Deploying your app on other servlet containers will be specific to each container, but all containers compatible with the Servlet API Specification (version 2.2 or later) are required to accept a web application archive file. Note that other containers are NOT required to accept an unpacked directory structure (as Tomcat does), or to provide mechanisms for shared library files, but these features are commonly available.

    tomcat7-7.0.52/webapps/docs/appdev/source.xml0000644000175100017510000003740412271304167021050 0ustar locutuslocutus ]> &project; Craig R. McClanahan Source Organization

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    A key recommendation of this manual is to separate the directory hierarchy containing your source code (described in this section) from the directory hierarchy containing your deployable application (described in the preceding section). Maintaining this separation has the following advantages:

    • The contents of the source directories can be more easily administered, moved, and backed up if the "executable" version of the application is not intermixed.

    • Source code control is easier to manage on directories that contain only source files.

    • The files that make up an installable distribution of your application are much easier to select when the deployment hierarchy is separate.

    As we will see, the ant development tool makes the creation and processing of such directory hierarchies nearly painless.

    The actual directory and file hierarchy used to contain the source code of an application can be pretty much anything you like. However, the following organization has proven to be quite generally applicable, and is expected by the example build.xml configuration file that is discussed below. All of these components exist under a top level project source directory for your application:

    • docs/ - Documentation for your application, in whatever format your development team is using.

    • src/ - Java source files that generate the servlets, beans, and other Java classes that are unique to your application. If your source code is organized in packages (highly recommended), the package hierarchy should be reflected as a directory structure underneath this directory.

    • web/ - The static content of your web site (HTML pages, JSP pages, JavaScript files, CSS stylesheet files, and images) that will be accessible to application clients. This directory will be the document root of your web application, and any subdirectory structure found here will be reflected in the request URIs required to access those files.

    • web/WEB-INF/ - The special configuration files required for your application, including the web application deployment descriptor (web.xml, defined in the Servlet Specification), tag library descriptors for custom tag libraries you have created, and other resource files you wish to include within your web application. Even though this directory appears to be a subdirectory of your document root, the Servlet Specification prohibits serving the contents of this directory (or any file it contains) directly to a client request. Therefore, this is a good place to store configuration information that is sensitive (such as database connection usernames and passwords), but is required for your application to operate successfully.

    During the development process, two additional directories will be created on a temporary basis:

    • build/ - When you execute a default build (ant), this directory will contain an exact image of the files in the web application archive for this application. Tomcat allows you to deploy an application in an unpacked directory like this, either by copying it to the $CATALINA_BASE/webapps directory, or by installing it via the "Manager" web application. The latter approach is very useful during development, and will be illustrated below.

    • dist/ - When you execute the ant dist target, this directory will be created. It will create an exact image of the binary distribution for your web application, including an license information, documentation, and README files that you have prepared.

    Note that these two directories should NOT be archived in your source code control system, because they are deleted and recreated (from scratch) as needed during development. For that reason, you should not edit any source files in these directories if you want to maintain a permanent record of the changes, because the changes will be lost the next time that a build is performed.

    What do you do if your application requires JAR files (or other resources) from external projects or packages? A common example is that you need to include a JDBC driver in your web application, in order to operate.

    Different developers take different approaches to this problem. Some will encourage checking a copy of the JAR files you depend on into the source code control archives for every application that requires those JAR files. However, this can cause significant management issues when you use the same JAR in many applications - particular when faced with a need to upgrade to a different version of that JAR file.

    Therefore, this manual recommends that you NOT store a copy of the packages you depend on inside the source control archives of your applications. Instead, the external dependencies should be integrated as part of the process of building your application. In that way, you can always pick up the appropriate version of the JAR files from wherever your development system administrator has installed them, without having to worry about updating your application every time the version of the dependent JAR file is changed.

    In the example Ant build.xml file, we will demonstrate how to define build properties that let you configure the locations of the files to be copied, without having to modify build.xml when these files change. The build properties used by a particular developer can be customized on a per-application basis, or defaulted to "standard" build properties stored in the developer's home directory.

    In many cases, your development system administrator will have already installed the required JAR files into the lib directory of Tomcat. If this has been done, you need to take no actions at all - the example build.xml file automatically constructs a compile classpath that includes these files.

    As mentioned earlier, it is highly recommended that you place all of the source files that comprise your application under the management of a source code control system like the Concurrent Version System (CVS). If you elect to do this, every directory and file in the source hierarchy should be registered and saved -- but none of the generated files. If you register binary format files (such as images or JAR libraries), be sure to indicate this to your source code control system.

    We recommended (in the previous section) that you should not store the contents of the build/ and dist/ directories created by your development process in the source code control system. An easy way to tell CVS to ignore these directories is to create a file named .cvsignore (note the leading period) in your top-level source directory, with the following contents:

    build dist build.properties

    The reason for mentioning build.properties here will be explained in the Processes section.

    Detailed instructions for your source code control environment are beyond the scope of this manual. However, the following steps are followed when using a command-line CVS client:

    • To refresh the state of your source code to that stored in the the source repository, go to your project source directory, and execute cvs update -dP.

    • When you create a new subdirectory in the source code hierarchy, register it in CVS with a command like cvs add {subdirname}.

    • When you first create a new source code file, navigate to the directory that contains it, and register the new file with a command like cvs add {filename}.

    • If you no longer need a particular source code file, navigate to the containing directory and remove the file. Then, deregister it in CVS with a command like cvs remove {filename}.

    • While you are creating, modifying, and deleting source files, changes are not yet reflected in the server repository. To save your changes in their current state, go to the project source directory and execute cvs commit. You will be asked to write a brief description of the changes you have just completed, which will be stored with the new version of any updated source file.

    CVS, like other source code control systems, has many additional features (such as the ability to tag the files that made up a particular release, and support for multiple development branches that can later be merged). See the links and references in the Introduction for more information.

    We will be using the ant tool to manage the compilation of our Java source code files, and creation of the deployment hierarchy. Ant operates under the control of a build file, normally called build.xml, that defines the processing steps required. This file is stored in the top-level directory of your source code hierarchy, and should be checked in to your source code control system.

    Like a Makefile, the build.xml file provides several "targets" that support optional development activities (such as creating the associated Javadoc documentation, erasing the deployment home directory so you can build your project from scratch, or creating the web application archive file so you can distribute your application. A well-constructed build.xml file will contain internal documentation describing the targets that are designed for use by the developer, versus those targets used internally. To ask Ant to display the project documentation, change to the directory containing the build.xml file and type:

    ant -projecthelp

    To give you a head start, a basic build.xml file is provided that you can customize and install in the project source directory for your application. This file includes comments that describe the various targets that can be executed. Briefly, the following targets are generally provided:

    • clean - This target deletes any existing build and dist directories, so that they can be reconstructed from scratch. This allows you to guarantee that you have not made source code modifications that will result in problems at runtime due to not recompiling all affected classes.

    • compile - This target is used to compile any source code that has been changed since the last time compilation took place. The resulting class files are created in the WEB-INF/classes subdirectory of your build directory, exactly where the structure of a web application requires them to be. Because this command is executed so often during development, it is normally made the "default" target so that a simple ant command will execute it.

    • all - This target is a short cut for running the clean target, followed by the compile target. Thus, it guarantees that you will recompile the entire application, to ensure that you have not unknowingly introduced any incompatible changes.

    • javadoc - This target creates Javadoc API documentation for the Java classes in this web application. The example build.xml file assumes you want to include the API documentation with your app distribution, so it generates the docs in a subdirectory of the dist directory. Because you normally do not need to generate the Javadocs on every compilation, this target is usually a dependency of the dist target, but not of the compile target.

    • dist - This target creates a distribution directory for your application, including any required documentation, the Javadocs for your Java classes, and a web application archive (WAR) file that will be delivered to system administrators who wish to install your application. Because this target also depends on the deploy target, the web application archive will have also picked up any external dependencies that were included at deployment time.

    For interactive development and testing of your web application using Tomcat, the following additional targets are defined:

    • install - Tell the currently running Tomcat to make the application you are developing immediately available for execution and testing. This action does not require Tomcat to be restarted, but it is also not remembered after Tomcat is restarted the next time.

    • reload - Once the application is installed, you can continue to make changes and recompile using the compile target. Tomcat will automatically recognize changes made to JSP pages, but not to servlet or JavaBean classes - this command will tell Tomcat to restart the currently installed application so that such changes are recognized.

    • remove - When you have completed your development and testing activities, you can optionally tell Tomcat to remove this application from service.

    Using the development and testing targets requires some additional one-time setup that is described on the next page.

    tomcat7-7.0.52/webapps/docs/appdev/sample/0000755000175100017510000000000012301126373020272 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/sample/index.html0000644000175100017510000000341712271304167022301 0ustar locutuslocutus Sample Application

    Sample Application

    The example app has been packaged as a war file and can be downloaded here (Note: make sure your browser doesn't change file extension or append a new one).

    The easiest way to run this application is simply to move the war file to your CATALINA_HOME/webapps directory. Tomcat will automatically expand and deploy the application for you. You can view it with the following URL (assuming that you're running tomcat on port 8080 as is the default):
    http://localhost:8080/sample

    If you just want to browse the contents, you can unpack the war file with the jar command.

            jar -xvf sample.war
          
    tomcat7-7.0.52/webapps/docs/appdev/sample/src/0000755000175100017510000000000012301126373021061 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/sample/src/mypackage/0000755000175100017510000000000012301126373023022 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/sample/src/mypackage/Hello.java0000644000175100017510000000552712271304167024746 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 mypackage; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Simple servlet to validate that the Hello, World example can * execute servlets. In the web application deployment descriptor, * this servlet must be mapped to correspond to the link in the * "index.html" file. * * @author Craig R. McClanahan */ public final class Hello extends HttpServlet { private static final long serialVersionUID = 1L; /** * Respond to a GET request for the content produced by * this servlet. * * @param request The servlet request we are processing * @param response The servlet response we are producing * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter writer = response.getWriter(); writer.println(""); writer.println(""); writer.println("Sample Application Servlet Page"); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println("
    "); writer.println(""); writer.println(""); writer.println("

    Sample Application Servlet

    "); writer.println("This is the output of a servlet that is part of"); writer.println("the Hello, World application."); writer.println("
    "); writer.println(""); writer.println(""); } } tomcat7-7.0.52/webapps/docs/appdev/sample/docs/0000755000175100017510000000000012301126373021222 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/sample/docs/README.txt0000644000175100017510000000151012271304167022722 0ustar locutuslocutus Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. This is a dummy README file for the sample web application. tomcat7-7.0.52/webapps/docs/appdev/sample/sample.war0000644000175100017510000001077610653474335022315 0ustar locutuslocutusPK F6 META-INF/PK E6^jMETA-INF/MANIFEST.MFMLK-. K-*ϳR03rCq,HLHU%LyRKRSt*AM t L4K|3+KRs<4yxPK N6WEB-INF/PK O6WEB-INF/classes/PK O6WEB-INF/classes/mypackage/PK N6 WEB-INF/lib/PK N6images/PK O6ڪ)!%WEB-INF/classes/mypackage/Hello.classTRA= !x]"wBIU>l1Yd݉B$>~e*4:9=s3_}`G6h业5\qm;SQqc> lsi3t;^S%ѱ Y }e%V͊݊OL, =NȔjxrs+pܺCWM.d}nڑB {`-&m?ݢ@"QU8a?OgarÿKJrD:1jE1\65PK N6~ex-WEB-INF/web.xmlK0x6ttAPA0Ao5&!/[Ym,ޗ{.W%zR֌'F\8>g  gpb8)Bp#R0Z&mɣ !br؃ţm*V0|TXT mԈjJj?>ogxm46j+rZ|F8E1<[srN){e(ʭ tT( U:9@Jbڅ  j?19P xh%ok\BZ4֪~1]3Q2gZMO'䇘#ӻXcoxvY2n(2-Nj?0:]\ PK N6n8x hello.jsp}Pj1 /?@ %nﻁJO-];W!%A3hi&Q՟{}Z0$ᜒw.h$;pJV<߭ W1\JY<7 r ;MG֭傁=op)q6'ת}ł×u;V8 h \ s*C{OM٫qdדf gͳh*OBd޿PK N6images/tomcat.gif^GIF89adG'%siTYvnXδgNKBuҤ!,dGI8_s,Fh8A 8N߸ttPCMv| aIC%X-.}+aIKfˀ{S t,`);t sv~M,    j=h@; fs8; QlK lY4E@I  Ʋ S9s4s7+,𡠅!-<]2 #T+k A 2x ! @Mj-# \10d6226g&'4H +| 0{%<9+PvvCNWu%̠ P9TFZqWB0aa@!KMj# =J( ;kkH5[=y(vbIztg*AvrE)ǓK17l(B8;2UvsL-= ~P2@,_'d6s q 4g] !\܇߂(3zLT`^ѱG۱bQ]b +ztȠ۴m]G e@z3\T\ d@5tmo{D<` E 6n CB8ˁTW6&rL\ t6!bAYl JNQчf@ M$IU&*C\щm# W/PxB& $ ;҉$^;PK N60_| index.htmlRMK@\FA$TI&ٱLݴ]zY5l]^UMzo!ou<̳*3PpwfhٱNB|QCEt&xiwf@_d;PeF';o<,aVY29 &`dWi:lX3%W694$YhjIzKp4MGpx#:Qn<<-{2WV6s: 6cNN, yL.:>J={N1F9{Z8*V6sQ_SUiآ(G +r w PK F6 AMETA-INF/PK E6^j+META-INF/MANIFEST.MFPK N6AWEB-INF/PK O6AWEB-INF/classes/PK O6AWEB-INF/classes/mypackage/PK N6 AGWEB-INF/lib/PK N6Aqimages/PK O6ڪ)!%WEB-INF/classes/mypackage/Hello.classPK N6~ex-WEB-INF/web.xmlPK N6n8x hello.jspPK N6images/tomcat.gifPK N60_| { index.htmlPK tomcat7-7.0.52/webapps/docs/appdev/sample/web/0000755000175100017510000000000012301126373021047 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/sample/web/images/0000755000175100017510000000000012301126373022314 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/sample/web/images/tomcat.gif0000644000175100017510000000264110457676032024311 0ustar locutuslocutusGIF89adG'%siTYvnXδgNKBuҤ!,dGI8_s,Fh8A 8N߸ttPCMv| aIC%X-.}+aIKfˀ{S t,`);t sv~M,    j=h@; fs8; QlK lY4E@I  Ʋ S9s4s7+,𡠅!-<]2 #T+k A 2x ! @Mj-# \10d6226g&'4H +| 0{%<9+PvvCNWu%̠ P9TFZqWB0aa@!KMj# =J( ;kkH5[=y(vbIztg*AvrE)ǓK17l(B8;2UvsL-= ~P2@,_'d6s q 4g] !\܇߂(3zLT`^ѱG۱bQ]b +ztȠ۴m]G e@z3\T\ d@5tmo{D<` E 6n CB8ˁTW6&rL\ t6!bAYl JNQчf@ M$IU&*C\щm# W/PxB& $ ;҉$^;tomcat7-7.0.52/webapps/docs/appdev/sample/web/WEB-INF/0000755000175100017510000000000012301126373022076 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/appdev/sample/web/WEB-INF/web.xml0000644000175100017510000000307012271304167023402 0ustar locutuslocutus Hello, World Application This is a simple web application with a source code organization based on the recommendations of the Application Developer's Guide. HelloServlet mypackage.Hello HelloServlet /hello tomcat7-7.0.52/webapps/docs/appdev/sample/web/index.html0000644000175100017510000000260212271304167023051 0ustar locutuslocutus Sample "Hello, World" Application

    Sample "Hello, World" Application

    This is the home page for a sample application used to illustrate the source directory organization of a web application utilizing the principles outlined in the Application Developer's Guide.

    To prove that they work, you can execute either of the following links:

    tomcat7-7.0.52/webapps/docs/appdev/sample/web/hello.jsp0000644000175100017510000000216512271304167022701 0ustar locutuslocutus Sample Application JSP Page

    Sample Application JSP Page

    This is the output of a JSP page that is part of the Hello, World application.
    <%= new String("Hello!") %> tomcat7-7.0.52/webapps/docs/appdev/project.xml0000644000175100017510000000361012271304167021206 0ustar locutuslocutus Application Developer's Guide The Apache Tomcat Servlet/JSP Container tomcat7-7.0.52/webapps/docs/appdev/build.xml.txt0000644000175100017510000004043412275241511021457 0ustar locutuslocutus tomcat7-7.0.52/webapps/docs/appdev/processes.xml0000644000175100017510000003054712271304167021557 0ustar locutuslocutus ]> &project; Craig R. McClanahan Development Processes

    Although application development can take many forms, this manual proposes a fairly generic process for creating web applications using Tomcat. The following sections highlight the commands and tasks that you, as the developer of the code, will perform. The same basic approach works when you have multiple programmers involved, as long as you have an appropriate source code control system and internal team rules about who is working on what parts of the application at any given time.

    The task descriptions below assume that you will be using CVS for source code control, and that you have already configured access to the appropriate CVS repository. Instructions for doing this are beyond the scope of this manual. If you are using a different source code control environment, you will need to figure out the corresponding commands for your system.

    In order to take advantage of the special Ant tasks that interact with the Manager web application, you need to perform the following tasks once (no matter how many web applications you plan to develop).

    • Configure the Ant custom tasks. The implementation code for the Ant custom tasks is in a JAR file named $CATALINA_HOME/lib/catalina-ant.jar, which must be copied in to the lib directory of your Ant installation.

    • Define one or more Tomcat users. The Manager web application runs under a security constraint that requires a user to be logged in, and have the security role manager-script assigned to him or her. How such users are defined depends on which Realm you have configured in Tomcat's conf/server.xml file -- see the Realm Configuration HOW-TO for more information. You may define any number of users (with any username and password that you like) with the manager-script role.

    The first step is to create a new project source directory, and customize the build.xml and build.properties files you will be using. The directory structure is described in the previous section, or you can use the sample application as a starting point.

    Create your project source directory, and define it within your CVS repository. This might be done by a series of commands like this, where {project} is the name under which your project should be stored in the CVS repository, and {username} is your login username:

    cd {my home directory} mkdir myapp <-- Assumed "project source directory" cd myapp mkdir docs mkdir src mkdir web mkdir web/WEB-INF cvs import -m "Initial Project Creation" {project} \ {username} start

    Now, to verify that it was created correctly in CVS, we will perform a checkout of the new project:

    cd .. mv myapp myapp.bu cvs checkout {project}

    Next, you will need to create and check in an initial version of the build.xml script to be used for development. For getting started quickly and easily, base your build.xml on the basic build.xml file, included with this manual, or code it from scratch.

    cd {my home directory} cd myapp emacs build.xml <-- if you want a real editor :-) cvs add build.xml cvs commit

    Until you perform the CVS commit, your changes are local to your own development directory. Committing makes those changes visible to other developers on your team that are sharing the same CVS repository.

    The next step is to customize the Ant properties that are named in the build.xml script. This is done by creating a file named build.properties in your project's top-level directory. The supported properties are listed in the comments inside the sample build.xml script. At a minimum, you will generally need to define the catalina.home property defining where Tomcat is installed, and the manager application username and password. You might end up with something like this:

    # Context path to install this application on app.path=/hello # Tomcat 7 installation directory catalina.home=/usr/local/apache-tomcat-7.0 # Manager webapp username and password manager.username=myusername manager.password=mypassword

    In general, you will not want to check the build.properties file in to the CVS repository, because it is unique to each developer's environment.

    Now, create the initial version of the web application deployment descriptor. You can base web.xml on the basic web.xml file, or code it from scratch.

    cd {my home directory} cd myapp/web/WEB-INF emacs web.xml cvs add web.xml cvs commit Note that this is only an example web.xml file. The full definition of the deployment descriptor file is in the Servlet Specification.

    The edit/build/test tasks will generally be your most common activities during development and maintenance. The following general principles apply. As described in Source Organization, newly created source files should be located in the appropriate subdirectory, under your project source directory.

    Whenever you wish to refresh your development directory to reflect the work performed by other developers, you will ask CVS to do it for you:

    cd {my home directory} cd myapp cvs update -dP

    To create a new file, go to the appropriate directory, create the file, and register it with CVS. When you are satisfied with it's contents (after building and testing is successful), commit the new file to the repository. For example, to create a new JSP page:

    cd {my home directory} cd myapp/web <-- Ultimate destination is document root emacs mypage.jsp cvs add mypage.jsp ... build and test the application ... cvs commit

    Java source code that is defined in packages must be organized in a directory hierarchy (under the src/ subdirectory) that matches the package names. For example, a Java class named com.mycompany.mypackage.MyClass.java should be stored in file src/com/mycompany/mypackage/MyClass.java. Whenever you create a new subdirectory, don't forget to register it with CVS.

    To edit an existing source file, you will generally just start editing and testing, then commit the changed file when everything works. Although CVS can be configured to required you to "check out" or "lock" a file you are going to be modifying, this is generally not used.

    When you are ready to compile the application, issue the following commands (generally, you will want a shell window open that is set to the project source directory, so that only the last command is needed):

    cd {my home directory} cd myapp <-- Normally leave a window open here ant

    The Ant tool will be execute the default "compile" target in your build.xml file, which will compile any new or updated Java code. If this is the first time you compile after a "build clean", it will cause everything to be recompiled.

    To force the recompilation of your entire application, do this instead:

    cd {my home directory} cd myapp ant all

    This is a very good habit immediately before checking in changes, to make sure that you have not introduced any subtle problems that Javac's conditional checking did not catch.

    To test your application, you will want to install it under Tomcat. The quickest way to do that is to use the custom Ant tasks that are included in the sample build.xml script. Using these commands might follow a pattern like this:

    • Start Tomcat if needed. If Tomcat is not already running, you will need to start it in the usual way.

    • Compile your application. Use the ant compile command (or just ant, since this is the default). Make sure that there are no compilation errors.

    • Install the application. Use the ant install command. This tells Tomcat to immediately start running your app on the context path defined in the app.path build property. Tomcat does NOT have to be restarted for this to take effect.

    • Test the application. Using your browser or other testing tools, test the functionality of your application.

    • Modify and rebuild as needed. As you discover that changes are required, make those changes in the original source files, not in the output build directory, and re-issue the ant compile command. This ensures that your changes will be available to be saved (via cvs commit) later on -- the output build directory is deleted and recreated as necessary.

    • Reload the application. Tomcat will recognize changes in JSP pages automatically, but it will continue to use the old versions of any servlet or JavaBean classes until the application is reloaded. You can trigger this by executing the ant reload command.

    • Remove the application when you re done. When you are through working on this application, you can remove it from live execution by running the ant remove command.

    Do not forget to commit your changes to the source code repository when you have completed your testing!

    When you are through adding new functionality, and you've tested everything (you DO test, don't you :-), it is time to create the distributable version of your web application that can be deployed on the production server. The following general steps are required:

    • Issue the command ant all from the project source directory, to rebuild everything from scratch one last time.

    • Use the cvs tag command to create an identifier for all of the source files utilized to create this release. This allows you to reliably reconstruct a release (from sources) at a later time.
    • Issue the command ant dist to create a distributable web application archive (WAR) file, as well as a JAR file containing the corresponding source code.

    • Package the contents of the dist directory using the tar or zip utility, according to the standard release procedures used by your organization.
    tomcat7-7.0.52/webapps/docs/appdev/introduction.xml0000644000175100017510000000767112271304167022274 0ustar locutuslocutus ]> &project; Craig R. McClanahan Introduction

    Congratulations! You've decided to (or been told to) learn how to build web applications using servlets and JSP pages, and picked the Tomcat server to use for your learning and development. But now what do you do?

    This manual is a primer covering the basic steps of using Tomcat to set up a development environment, organize your source code, and then build and test your application. It does not discuss architectures or recommended coding practices for web application development, or provide in depth instructions on operating the development tools that are discussed. References to sources of additional information are included in the following subsections.

    The discussion in this manual is aimed at developers who will be using a text editor along with command line tools to develop and debug their applications. As such, the recommendations are fairly generic -- but you should easily be able to apply them in either a Windows-based or Unix-based development environment. If you are utilizing an Integrated Development Environment (IDE) tool, you will need to adapt the advice given here to the details of your particular environment.

    The following links provide access to selected sources of online information, documentation, and software that is useful in developing web applications with Tomcat.

    • http://jcp.org/aboutJava/communityprocess/mrel/jsr245/ - JavaServer Pages (JSP) Specification, Version 2.2. Describes the programming environment provided by standard implementations of the JavaServer Pages (JSP) technology. In conjunction with the Servlet API Specification (see below), this document describes what a portable API page is allowed to contain. Specific information on scripting (Chapter 9), tag extensions (Chapter 7), and packaging JSP pages (Appendix A) is useful. The Javadoc API Documentation is included in the specification, and with the Tomcat download.

    • http://jcp.org/aboutJava/communityprocess/mrel/jsr315/ - Servlet API Specification, Version 3.0. Describes the programming environment that must be provided by all servlet containers conforming to this specification. In particular, you will need this document to understand the web application directory structure and deployment file (Chapter 10), methods of mapping request URIs to servlets (Chapter 12), container managed security (Chapter 13), and the syntax of the web.xml Web Application Deployment Descriptor (Chapter 14). The Javadoc API Documentation is included in the specification, and with the Tomcat download.

    tomcat7-7.0.52/webapps/docs/appdev/index.xml0000644000175100017510000000571112271304167020653 0ustar locutuslocutus ]> &project; Craig R. McClanahan Table of Contents

    This manual includes contributions from many members of the Tomcat Project developer community. The following authors have provided significant content:

    The information presented is divided into the following sections:

    • Introduction - Briefly describes the information covered here, with links and references to other sources of information.
    • Installation - Covers acquiring and installing the required software components to use Tomcat for web application development.
    • Deployment Organization - Discusses the standard directory layout for a web application (defined in the Servlet API Specification), the Web Application Deployment Descriptor, and options for integration with Tomcat in your development environment.
    • Source Organization - Describes a useful approach to organizing the source code directories for your project, and introduces the build.xml used by Ant to manage compilation.
    • Development Processes - Provides brief descriptions of typical development processes utilizing the recommended deployment and source organizations.
    • Example Application - This directory contains a very simple, but functionally complete, "Hello, World" application built according to the principles described in this manual. You can use this application to practice using the described techniques.
    tomcat7-7.0.52/webapps/docs/security-manager-howto.xml0000644000175100017510000002542712271304167022710 0ustar locutuslocutus ]> &project; Glenn Nielsen Jean-Francois Arcand Security Manager HOW-TO

    The Java SecurityManager is what allows a web browser to run an applet in its own sandbox to prevent untrusted code from accessing files on the local file system, connecting to a host other than the one the applet was loaded from, and so on. In the same way the SecurityManager protects you from an untrusted applet running in your browser, use of a SecurityManager while running Tomcat can protect your server from trojan servlets, JSPs, JSP beans, and tag libraries. Or even inadvertent mistakes.

    Imagine if someone who is authorized to publish JSPs on your site inadvertently included the following in their JSP:

    <% System.exit(1); %>

    Every time this JSP was executed by Tomcat, Tomcat would exit. Using the Java SecurityManager is just one more line of defense a system administrator can use to keep the server secure and reliable.

    WARNING - A security audit have been conducted using the Tomcat codebase. Most of the critical package have been protected and a new security package protection mechanism has been implemented. Still, make sure that you are satisfied with your SecurityManager configuration before allowing untrusted users to publish web applications, JSPs, servlets, beans, or tag libraries. However, running with a SecurityManager is definitely better than running without one.

    Permission classes are used to define what Permissions a class loaded by Tomcat will have. There are a number of Permission classes that are a standard part of the JDK, and you can create your own Permission class for use in your own web applications. Both techniques are used in Tomcat.

    This is just a short summary of the standard system SecurityManager Permission classes applicable to Tomcat. See http://java.sun.com/security/ for more information.

    • java.util.PropertyPermission - Controls read/write access to JVM properties such as java.home.
    • java.lang.RuntimePermission - Controls use of some System/Runtime functions like exit() and exec(). Also control the package access/definition.
    • java.io.FilePermission - Controls read/write/execute access to files and directories.
    • java.net.SocketPermission - Controls use of network sockets.
    • java.net.NetPermission - Controls use of multicast network connections.
    • java.lang.reflect.ReflectPermission - Controls use of reflection to do class introspection.
    • java.security.SecurityPermission - Controls access to Security methods.
    • java.security.AllPermission - Allows access to all permissions, just as if you were running Tomcat without a SecurityManager.

    Tomcat utilizes a custom permission class called org.apache.naming.JndiPermission. This permission controls read access to JNDI named file based resources. The permission name is the JNDI name and there are no actions. A trailing "*" can be used to do wild card matching for a JNDI named file resource when granting permission. For example, you might include the following in your policy file:

    permission org.apache.naming.JndiPermission "jndi://localhost/examples/*";

    A Permission entry like this is generated dynamically for each web application that is deployed, to allow it to read its own static resources but disallow it from using file access to read any other files (unless permissions for those files are explicitly granted).

    Also, Tomcat always dynamically creates the following file permissions:

    permission java.io.FilePermission "** your application context**", "read"; permission java.io.FilePermission "** application working directory**", "read,write"; permission java.io.FilePermission "** application working directory**/-", "read,write,delete";

    Where **your application context** equals the folder (or WAR file) under which your application has been deployed and **application working directory** is the temporary directory provided to your application as required by the Servlet Specification.

    Policy File Format

    The security policies implemented by the Java SecurityManager are configured in the $CATALINA_BASE/conf/catalina.policy file. This file completely replaces the java.policy file present in your JDK system directories. The catalina.policy file can be edited by hand, or you can use the policytool application that comes with Java 1.2 or later.

    Entries in the catalina.policy file use the standard java.policy file format, as follows:

    // Example policy file entry grant [signedBy <signer>,] [codeBase <code source>] { permission <class> [<name> [, <action list>]]; };

    The signedBy and codeBase entries are optional when granting permissions. Comment lines begin with "//" and end at the end of the current line. The codeBase is in the form of a URL, and for a file URL can use the ${java.home} and ${catalina.home} properties (which are expanded out to the directory paths defined for them by the JAVA_HOME, CATALINA_HOME and CATALINA_BASE environment variables).

    The Default Policy File

    The default $CATALINA_BASE/conf/catalina.policy file looks like this:

    &defaultpolicy;

    Starting Tomcat With A SecurityManager

    Once you have configured the catalina.policy file for use with a SecurityManager, Tomcat can be started with a SecurityManager in place by using the "-security" option:

    $CATALINA_HOME/bin/catalina.sh start -security (Unix) %CATALINA_HOME%\bin\catalina start -security (Windows)

    Starting with Tomcat 5, it is now possible to configure which Tomcat internal package are protected againts package definition and access. See http://java.sun.com/security/seccodeguide.html for more information.

    WARNING: Be aware that removing the default package protection could possibly open a security hole

    The Default Properties File

    The default $CATALINA_BASE/conf/catalina.properties file looks like this:

    # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when # passed to checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat., org.apache.jasper. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when # passed to checkPackageDefinition unless the # corresponding RuntimePermission ("defineClassInPackage."+package) has # been granted. # # by default, no packages are restricted for definition, and none of # the class loaders supplied with the JDK call checkPackageDefinition. # package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote., org.apache.tomcat.,org.apache.jasper.

    Once you have configured the catalina.properties file for use with a SecurityManager, remember to re-start Tomcat.

    If your web application attempts to execute an operation that is prohibited by lack of a required Permission, it will throw an AccessControLException or a SecurityException when the SecurityManager detects the violation. Debugging the permission that is missing can be challenging, and one option is to turn on debug output of all security decisions that are made during execution. This is done by setting a system property before starting Tomcat. The easiest way to do this is via the CATALINA_OPTS environment variable. Execute this command:

    export CATALINA_OPTS=-Djava.security.debug=all (Unix) set CATALINA_OPTS=-Djava.security.debug=all (Windows)

    before starting Tomcat.

    WARNING - This will generate many megabytes of output! However, it can help you track down problems by searching for the word "FAILED" and determining which permission was being checked for. See the Java security documentation for more options that you can specify here as well.

    tomcat7-7.0.52/webapps/docs/balancer-howto.xml0000644000175100017510000000325212271304167021170 0ustar locutuslocutus ]> &project; Yoav Shapira Remy Maucherat Andy Oliver Load Balancer HOW-TO
    Please refer to the JK 1.2.x documentation.
    Please refer to the mod_proxy documentation for Apache HTTP Server 2.2. This supports either HTTP or AJP load balancing. This new version of mod_proxy is also usable with Apache HTTP Server 2.0, but mod_proxy will have to be compiled separately using the code from Apache HTTP Server 2.2.
    tomcat7-7.0.52/webapps/docs/building.xml0000644000175100017510000002067412271304167020067 0ustar locutuslocutus ]> &project; Remy Maucherat, Tim Whittington Building Tomcat

    Building Apache Tomcat from source is very easy, and is the first step to contributing to Tomcat. The following is a step by step guide.

    Building Apache Tomcat requires a JDK (version 6) to be installed. You can download one from
    http://www.oracle.com/technetwork/java/javase/downloads/index.html
    or from another JDK vendor.

    IMPORTANT: Set an environment variable JAVA_HOME to the pathname of the directory into which you installed the JDK release.

    Download a binary distribution of Ant 1.8.1 or later from here.

    Unpack the binary distribution into a convenient location so that the Ant release resides in its own directory (conventionally named apache-ant-1.8.x). For the remainder of this guide, the symbolic name ${ant.home} is used to refer to the full pathname of the Ant installation directory directory.

    IMPORTANT: Create an ANT_HOME environment variable to point the directory ${ant.home}, and modify the PATH environment variable to include directory ${ant.home}/bin in its list. This makes the ant command line script available, which will be used to actually perform the build.

    Tomcat 7.0 SVN repository URL: http://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk/

    Tomcat source packages: http://tomcat.apache.org/download-70.cgi.

    Checkout the source using SVN, selecting a tag for released version or trunk for the current development code, or download and unpack a source package. For the remainder of this guide, the symbolic name ${tomcat.source} is used to refer to the location where the source has been placed.

    Use the following commands to build Tomcat:

    cd ${tomcat.source}
    ant

    WARNING: Running this command will download libraries required to build Tomcat to the /usr/share/java directory by default. On a typical Linux or MacOX system, an ordinary user will not have access to write to this directory, and, even if you do, it is likely not appropriate for you to write there. On Windows this usually corresponds to the C:\usr\share\java directory, unless Cygwin is used. Read below to learn how to customize the directory used to download the binaries.

    NOTE: Users accessing the Internet through a proxy must use a properties file to indicate to Ant the proxy configuration. Read below for details.

    The build can be controlled by creating a ${tomcat.source}/build.properties file and adding the following content to it:

    # ----- Proxy setup -----
    # Uncomment if using a proxy server.
    #proxy.host=proxy.domain
    #proxy.port=8080
    #proxy.use=on

    # ----- Default Base Path for Dependent Packages -----
    # Replace this path with the directory path where
    # dependencies binaries should be downloaded.
    base.path=/home/me/some-place-to-download-to

    Once the build has completed successfully, a usable Tomcat installation will have been produced in the ${tomcat.source}/output/build directory, and can be started and stopped with the usual scripts.

    IMPORTANT: This is not a supported means of building Tomcat; this information is provided without warranty :-). The only supported means of building Tomcat is with the Ant build described above. However, some developers like to work on Java code with a Java IDE, and the following steps have been used by some developers.

    NOTE: This will not let you build everything under Eclipse; the build process requires use of Ant for the many stages that aren't simple Java compilations. However, it will allow you to view and edit the Java code, get warnings, reformat code, perform refactorings, run Tomcat under the IDE, and so on.

    WARNING: Do not forget to create and configure ${tomcat.source}/build.properties file as described above before running any Ant targets.

    Sample Eclipse project files and launch targets are provided in the res/ide-support/eclipse directory of the source tree. The instructions below will automatically copy these into the required locations.

    An Ant target is provided as a convenience to download all binary dependencies, and to create the Eclipse project and classpath files in the root of the source tree.

    cd ${tomcat.source}
    ant ide-eclipse

    Start Eclipse and create a new Workspace.

    Open the Preferences dialog and then select Java->Build Path->Classpath Variables to add two new Classpath Variables:

    TOMCAT_LIBS_BASEThe same location as the base.path setting in build.properties, where the binary dependencies have been downloaded
    ANT_HOMEthe base path of Ant 1.8.1 or later

    Use File->Import and choose Existing Projects into Workspace. From there choose the root directory of the Tomcat source tree (${tomcat.source}) and import the Tomcat project located there.

    start-tomcat and stop-tomcat launch configurations are provided in res/ide-support/eclipse and will be available in the Run->Run Configurations dialog. Use these to start and stop Tomcat from Eclipse.
    If you want to configure these yourself (or are using a different IDE) then use org.apache.catalina.startup.Bootstrap as the main class, start/stop etc. as program arguments, and specify -Dcatalina.home=... (with the name of your build directory) as VM arguments.

    Tweaking a few formatting preferences will make it much easier to keep consistent with Tomcat coding conventions (and have your contributions accepted):

    Java -> Code Style -> Formatter -> Edit... Tab policy: Spaces only
    Tab and Indentation size: 4
    General -> Editors -> Text Editors Displayed tab width: 2
    Insert spaces for tabs
    Show whitespace characters (optional)
    XML -> XML Files -> EditorIndent using spaces
    Indentation size: 2
    Ant -> Editor -> FormatterTab size: 2
    Use tab character instead of spaces: unchecked

    The same general approach should work for most IDEs; it has been reported to work in IntelliJ IDEA, for example.

    tomcat7-7.0.52/webapps/docs/api/0000755000175100017510000000000012301126373016303 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/api/index.html0000644000175100017510000000244112271304167020306 0ustar locutuslocutus API docs Tomcat's internal javadoc is not installed by default. Download and install the "fulldocs" package to get it. You can also access the javadoc online in the Tomcat documentation bundle. tomcat7-7.0.52/webapps/docs/virtual-hosting-howto.xml0000644000175100017510000001141611656650057022571 0ustar locutuslocutus ]> &project; Virtual Hosting and Tomcat

    For the sake of this how-to, assume you have a development host with two host names, ren and stimpy. Let's also assume one instance of Tomcat running, so $CATALINA_HOME refers to wherever it's installed, perhaps /usr/local/tomcat.

    Also, this how-to uses Unix-style path separators and commands; if you're on Windows modify accordingly.

    At the simplest, edit the Engine portion of your server.xml file to look like this:

    <Engine name="Catalina" defaultHost="ren"> <Host name="ren" appBase="renapps"/> <Host name="stimpy" appBase="stimpyapps"/> </Engine>

    Note that the directory structures under the appBase for each host should not overlap each other.

    Consult the configuration documentation for other attributes of the Engine and Host elements.

    Create directories for each of the virtual hosts:

    mkdir $CATALINA_HOME/renapps mkdir $CATALINA_HOME/stimpyapps

    Contexts are normally located underneath the appBase directory. For example, to deploy the foobar context as a war file in the ren host, use $CATALINA_HOME/renapps/foobar.war. Note that the default or ROOT context for ren would be deployed as $CATALINA_HOME/renapps/ROOT.war (WAR) or $CATALINA_HOME/renapps/ROOT (directory).

    NOTE: The docBase for a context should never be the same as the appBase for a host.

    Within your Context, create a META-INF directory and then place your Context definition in it in a file named context.xml. i.e. $CATALINA_HOME/renapps/ROOT/META-INF/context.xml This makes deployment easier, particularly if you're distributing a WAR file.

    Create a structure under $CATALINA_HOME/conf/Catalina corresponding to your virtual hosts, e.g.:

    mkdir $CATALINA_HOME/conf/Catalina/ren mkdir $CATALINA_HOME/conf/Catalina/stimpy

    Note that the ending directory name "Catalina" represents the name attribute of the Engine element as shown above.

    Now, for your default webapps, add:

    $CATALINA_HOME/conf/Catalina/ren/ROOT.xml $CATALINA_HOME/conf/Catalina/stimpy/ROOT.xml

    If you want to use the Tomcat manager webapp for each host, you'll also need to add it here:

    cd $CATALINA_HOME/conf/Catalina cp localhost/manager.xml ren/ cp localhost/manager.xml stimpy/

    Consult the configuration documentation for other attributes of the Context element.

    tomcat7-7.0.52/webapps/docs/jndi-resources-howto.xml0000644000175100017510000012306512271304167022362 0ustar locutuslocutus ]> &project; Craig R. McClanahan Yoav Shapira JNDI Resources HOW-TO

    Tomcat provides a JNDI InitialContext implementation instance for each web application running under it, in a manner that is compatible with those provided by a Java Enterprise Edition application server. The Java EE standard provides a standard set of elements in the /WEB-INF/web.xml file to reference/define resources.

    See the following Specifications for more information about programming APIs for JNDI, and for the features supported by Java Enterprise Edition (Java EE) servers, which Tomcat emulates for the services that it provides:

    The following elements may be used in the web application deployment descriptor (/WEB-INF/web.xml) of your web application to define resources:

    • <env-entry> - Environment entry, a single-value parameter that can be used to configure how the application will operate.
    • <resource-ref> - Resource reference, which is typically to an object factory for resources such as a JDBC DataSource, a JavaMail Session, or custom object factories configured into Tomcat.
    • <resource-env-ref> - Resource environment reference, a new variation of resource-ref added in Servlet 2.4 that is simpler to configure for resources that do not require authentication information.

    Providing that Tomcat is able to identify an appropriate resource factory to use to create the resource and that no further configuration information is required, Tomcat will use the information in /WEB-INF/web.xml to create the resource.

    Tomcat provides a number of Tomcat specific options for JNDI resources that cannot be specified in web.xml. These include closeMethod that enables faster cleaning-up of JNDI resources when a web application stops and singleton that controls whether or not a new instance of the resource is created for every JNDI lookup. To use these configuration options the resource must be specified in a web application's <Context> element or in the <GlobalNamingResources> element of $CATALINA_BASE/conf/server.xml.

    If Tomcat is unable to identify the appropriate resource factory and/or additional configuration information is required, additional Tomcat specific configuration must be specified before Tomcat can create the resource. Tomcat specific resource configuration is entered in the <Context> elements that can be specified in either $CATALINA_BASE/conf/server.xml or, preferably, the per-web-application context XML file (META-INF/context.xml).

    Tomcat specific resource configuration is performed using the following elements in the <Context> element:

    • <Environment> - Configure names and values for scalar environment entries that will be exposed to the web application through the JNDI InitialContext (equivalent to the inclusion of an <env-entry> element in the web application deployment descriptor).
    • <Resource> - Configure the name and data type of a resource made available to the application (equivalent to the inclusion of a <resource-ref> element in the web application deployment descriptor).
    • <ResourceLink> - Add a link to a resource defined in the global JNDI context. Use resource links to give a web application access to a resource defined in the <GlobalNamingResources> child element of the <Server> element.
    • <Transaction> - Add a resource factory for instantiating the UserTransaction object instance that is available at java:comp/UserTransaction.

    Any number of these elements may be nested inside a <Context> element and will be associated only with that particular web application.

    If a resource has been defined in a <Context> element it is not necessary for that resource to be defined in /WEB-INF/web.xml. However, it is recommended to keep the entry in /WEB-INF/web.xml to document the resource requirements for the web application.

    Where the same resource name has been defined for a <env-entry> element included in the web application deployment descriptor (/WEB-INF/web.xml) and in an <Environment> element as part of the <Context> element for the web application, the values in the deployment descriptor will take precedence only if allowed by the corresponding <Environment> element (by setting the override attribute to "true").

    Tomcat maintains a separate namespace of global resources for the entire server. These are configured in the <GlobalNamingResources> element of $CATALINA_BASE/conf/server.xml. You may expose these resources to web applications by using a <ResourceLink> to include it in the per-web-application context.

    If a resource has been defined using a <ResourceLink>, it is not necessary for that resource to be defined in /WEB-INF/web.xml. However, it is recommended to keep the entry in /WEB-INF/web.xml to document the resource requirements for the web application.

    The InitialContext is configured as a web application is initially deployed, and is made available to web application components (for read-only access). All configured entries and resources are placed in the java:comp/env portion of the JNDI namespace, so a typical access to a resource - in this case, to a JDBC DataSource - would look something like this:

    // Obtain our environment naming context Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); // Look up our data source DataSource ds = (DataSource) envCtx.lookup("jdbc/EmployeeDB"); // Allocate and use a connection from the pool Connection conn = ds.getConnection(); ... use this connection to access the database ... conn.close();

    Tomcat includes a series of standard resource factories that can provide services to your web applications, but give you configuration flexibility (via the <Context> element) without modifying the web application or the deployment descriptor. Each subsection below details the configuration and usage of the standard resource factories.

    See Adding Custom Resource Factories for information about how to create, install, configure, and use your own custom resource factory classes with Tomcat.

    NOTE - Of the standard resource factories, only the "JDBC Data Source" and "User Transaction" factories are mandated to be available on other platforms, and then they are required only if the platform implements the Java Enterprise Edition (Java EE) specs. All other standard resource factories, plus custom resource factories that you write yourself, are specific to Tomcat and cannot be assumed to be available on other containers.

    0. Introduction

    This resource factory can be used to create objects of any Java class that conforms to standard JavaBeans naming conventions (i.e. it has a zero-arguments constructor, and has property setters that conform to the setFoo() naming pattern. The resource factory will only create a new instance of the appropriate bean class every time a lookup() for this entry is made if the singleton attribute of the factory is set to false.

    The steps required to use this facility are described below.

    1. Create Your JavaBean Class

    Create the JavaBean class which will be instantiated each time that the resource factory is looked up. For this example, assume you create a class com.mycompany.MyBean, which looks like this:

    package com.mycompany; public class MyBean { private String foo = "Default Foo"; public String getFoo() { return (this.foo); } public void setFoo(String foo) { this.foo = foo; } private int bar = 0; public int getBar() { return (this.bar); } public void setBar(int bar) { this.bar = bar; } }

    2. Declare Your Resource Requirements

    Next, modify your web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will request new instances of this bean. The simplest approach is to use a <resource-env-ref> element, like this:

    <resource-env-ref> <description> Object factory for MyBean instances. </description> <resource-env-ref-name> bean/MyBeanFactory </resource-env-ref-name> <resource-env-ref-type> com.mycompany.MyBean </resource-env-ref-type> </resource-env-ref>

    WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

    3. Code Your Application's Use Of This Resource

    A typical use of this resource environment reference might look like this:

    Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory"); writer.println("foo = " + bean.getFoo() + ", bar = " + bean.getBar());

    4. Configure Tomcat's Resource Factory

    To configure Tomcat's resource factory, add an element like this to the <Context> element for this web application.

    <Context ...> ... <Resource name="bean/MyBeanFactory" auth="Container" type="com.mycompany.MyBean" factory="org.apache.naming.factory.BeanFactory" bar="23"/> ... </Context>

    Note that the resource name (here, bean/MyBeanFactory must match the value specified in the web application deployment descriptor. We are also initializing the value of the bar property, which will cause setBar(23) to be called before the new bean is returned. Because we are not initializing the foo property (although we could have), the bean will contain whatever default value is set up by its constructor.

    0. Introduction

    UserDatabase resources are typically configured as global resources for use by a UserDatabase realm. Tomcat includes a UserDatabaseFactoory that creates UserDatabase resources backed by an XML file - usually tomcat-users.xml

    The steps required to set up a global UserDatabase resource are described below.

    1. Create/edit the XML file

    The XML file is typically located at $CATALINA_BASE/conf/tomcat-users.xml however, you are free to locate the file anywhere on the file system. It is recommended that the XML files are placed in $CATALINA_BASE/conf. A typical XML would look like:

    <?xml version='1.0' encoding='utf-8'?> <tomcat-users> <role rolename="tomcat"/> <role rolename="role1"/> <user username="tomcat" password="tomcat" roles="tomcat"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="role1" password="tomcat" roles="role1"/> </tomcat-users>

    2. Declare Your Resource

    Next, modify $CATALINA_BASE/conf/server.xml to create the UserDatabase resource based on your XML file. It should look something like this:

    <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" readonly="false" />

    The pathname attribute can be absolute or relative. If relative, it is relative to $CATALINA_BASE.

    The readonly attribute is optional and defaults to true if not supplied. If the XML is writeable then it will be written to when Tomcat starts. WARNING: When the file is written it will inherit the default file permissions for the user Tomcat is running as. Ensure that these are appropriate to maintain the security of your installation.

    3. Configure the Realm

    Configure a UserDatabase Realm to use this resource as described in the Realm configuration documentation.

    0. Introduction

    In many web applications, sending electronic mail messages is a required part of the system's functionality. The Java Mail API makes this process relatively straightforward, but requires many configuration details that the client application must be aware of (including the name of the SMTP host to be used for message sending).

    Tomcat includes a standard resource factory that will create javax.mail.Session session instances for you, already configured to connect to an SMTP server. In this way, the application is totally insulated from changes in the email server configuration environment - it simply asks for, and receives, a preconfigured session whenever needed.

    The steps required for this are outlined below.

    1. Declare Your Resource Requirements

    The first thing you should do is modify the web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will look up preconfigured sessions. By convention, all such names should resolve to the mail subcontext (relative to the standard java:comp/env naming context that is the root of all provided resource factories. A typical web.xml entry might look like this:

    <resource-ref> <description> Resource reference to a factory for javax.mail.Session instances that may be used for sending electronic mail messages, preconfigured to connect to the appropriate SMTP server. </description> <res-ref-name> mail/Session </res-ref-name> <res-type> javax.mail.Session </res-type> <res-auth> Container </res-auth> </resource-ref>

    WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

    2. Code Your Application's Use Of This Resource

    A typical use of this resource reference might look like this:

    Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); Session session = (Session) envCtx.lookup("mail/Session"); Message message = new MimeMessage(session); message.setFrom(new InternetAddress(request.getParameter("from"))); InternetAddress to[] = new InternetAddress[1]; to[0] = new InternetAddress(request.getParameter("to")); message.setRecipients(Message.RecipientType.TO, to); message.setSubject(request.getParameter("subject")); message.setContent(request.getParameter("content"), "text/plain"); Transport.send(message);

    Note that the application uses the same resource reference name that was declared in the web application deployment descriptor. This is matched up against the resource factory that is configured in the <Context> element for the web application as described below.

    3. Configure Tomcat's Resource Factory

    To configure Tomcat's resource factory, add an elements like this to the <Context> element for this web application.

    <Context ...> ... <Resource name="mail/Session" auth="Container" type="javax.mail.Session" mail.smtp.host="localhost"/> ... </Context>

    Note that the resource name (here, mail/Session) must match the value specified in the web application deployment descriptor. Customize the value of the mail.smtp.host parameter to point at the server that provides SMTP service for your network.

    Additional resource attributes and values will be converted to properties and values and passed to javax.mail.Session.getInstance(java.util.Properties) as part of the java.util.Properties collection. In addition to the properties defined in Annex A of the JavaMail specification, individual providers may also support additional properties.

    If the resource is configured with a password attribute and either a mail.smtp.user or mail.user attribute then Tomcat's resource factory will configure and add a javax.mail.Authenticator to the mail session.

    4. Install the JavaMail libraries

    Download the JavaMail API.

    Unpackage the distribution and place mail.jar into $CATALINA_HOME/lib so that it is available to Tomcat during the initialization of the mail Session Resource. Note: placing this jar in both $CATALINA_HOME/lib and a web application's lib folder will cause an error, so ensure you have it in the $CATALINA_HOME/lib location only.

    5. Restart Tomcat

    For the additional JAR to be visible to Tomcat, it is necessary for the Tomcat instance to be restarted.

    Example Application

    The /examples application included with Tomcat contains an example of utilizing this resource factory. It is accessed via the "JSP Examples" link. The source code for the servlet that actually sends the mail message is in /WEB-INF/classes/SendMailServlet.java.

    WARNING - The default configuration assumes that there is an SMTP server listing on port 25 on localhost. If this is not the case, edit the <Context> element for this web application and modify the parameter value for the mail.smtp.host parameter to be the host name of an SMTP server on your network.

    0. Introduction

    Many web applications need to access a database via a JDBC driver, to support the functionality required by that application. The Java EE Platform Specification requires Java EE Application Servers to make available a DataSource implementation (that is, a connection pool for JDBC connections) for this purpose. Tomcat offers exactly the same support, so that database-based applications you develop on Tomcat using this service will run unchanged on any Java EE server.

    For information about JDBC, you should consult the following:

    NOTE - The default data source support in Tomcat is based on the DBCP connection pool from the Commons project. However, it is possible to use any other connection pool that implements javax.sql.DataSource, by writing your own custom resource factory, as described below.

    1. Install Your JDBC Driver

    Use of the JDBC Data Sources JNDI Resource Factory requires that you make an appropriate JDBC driver available to both Tomcat internal classes and to your web application. This is most easily accomplished by installing the driver's JAR file(s) into the $CATALINA_HOME/lib directory, which makes the driver available both to the resource factory and to your application.

    2. Declare Your Resource Requirements

    Next, modify the web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will look up preconfigured data source. By convention, all such names should resolve to the jdbc subcontext (relative to the standard java:comp/env naming context that is the root of all provided resource factories. A typical web.xml entry might look like this:

    <resource-ref> <description> Resource reference to a factory for java.sql.Connection instances that may be used for talking to a particular database that is configured in the <Context> configurartion for the web application. </description> <res-ref-name> jdbc/EmployeeDB </res-ref-name> <res-type> javax.sql.DataSource </res-type> <res-auth> Container </res-auth> </resource-ref>

    WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

    3. Code Your Application's Use Of This Resource

    A typical use of this resource reference might look like this:

    Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); DataSource ds = (DataSource) envCtx.lookup("jdbc/EmployeeDB"); Connection conn = ds.getConnection(); ... use this connection to access the database ... conn.close();

    Note that the application uses the same resource reference name that was declared in the web application deployment descriptor. This is matched up against the resource factory that is configured in the <Context> element for the web application as described below.

    4. Configure Tomcat's Resource Factory

    To configure Tomcat's resource factory, add an element like this to the <Context> element for the web application.

    <Context ...> ... <Resource name="jdbc/EmployeeDB" auth="Container" type="javax.sql.DataSource" username="dbusername" password="dbpassword" driverClassName="org.hsql.jdbcDriver" url="jdbc:HypersonicSQL:database" maxActive="8" maxIdle="4"/> ... </Context>

    Note that the resource name (here, jdbc/EmployeeDB) must match the value specified in the web application deployment descriptor.

    This example assumes that you are using the HypersonicSQL database JDBC driver. Customize the driverClassName and driverName parameters to match your actual database's JDBC driver and connection URL.

    The configuration properties for Tomcat's standard data source resource factory (org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory) are as follows:

    • driverClassName - Fully qualified Java class name of the JDBC driver to be used.
    • username - Database username to be passed to our JDBC driver.
    • password - Database password to be passed to our JDBC driver.
    • url - Connection URL to be passed to our JDBC driver. (For backwards compatibility, the property driverName is also recognized.)
    • initialSize - The initial number of connections that will be created in the pool during pool initialization. Default: 0
    • maxActive - The maximum number of connections that can be allocated from this pool at the same time. Default: 8
    • minIdle - The minimum number of connections that will sit idle in this pool at the same time. Default: 0
    • maxIdle - The maximum number of connections that can sit idle in this pool at the same time. Default: 8
    • maxWait - The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception. Default: -1 (infinite)

    Some additional properties handle connection validation:

    • validationQuery - SQL query that can be used by the pool to validate connections before they are returned to the application. If specified, this query MUST be an SQL SELECT statement that returns at least one row.
    • validationQueryTimeout - Timeout in seconds for the validation query to return. Default: -1 (infinite)
    • testOnBorrow - true or false: whether a connection should be validated using the validation query each time it is borrowed from the pool. Default: true
    • testOnReturn - true or false: whether a connection should be validated using the validation query each time it is returned to the pool. Default: false

    The optional evictor thread is responsible for shrinking the pool by removing any conections which are idle for a long time. The evictor does not respect minIdle. Note that you do not need to activate the evictor thread if you only want the pool to shrink according to the configured maxIdle property.

    The evictor is disabled by default and can be configured using the following properties:

    • timeBetweenEvictionRunsMillis - The number of milliseconds between consecutive runs of the evictor. Default: -1 (disabled)
    • numTestsPerEvictionRun - The number of connections that will be checked for idleness by the evitor during each run of the evictor. Default: 3
    • minEvictableIdleTimeMillis - The idle time in milliseconds after which a connection can be removed from the pool by the evictor. Default: 30*60*1000 (30 minutes)
    • testWhileIdle - true or false: whether a connection should be validated by the evictor thread using the validation query while sitting idle in the pool. Default: false

    Another optional feature is the removal of abandoned connections. A connection is called abandoned if the application does not return it to the pool for a long time. The pool can close such connections automatically and remove them from the pool. This is a workaround for applications leaking connections.

    The abandoning feature is disabled by default and can be configured using the following properties:

    • removeAbandoned - true or false: whether to remove abandoned connections from the pool. Default: false
    • removeAbandonedTimeout - The number of seconds after which a borrowed connection is assumed to be abandoned. Default: 300
    • logAbandoned - true or false: whether to log stack traces for application code which abandoned a statement or connection. This adds serious overhead. Default: false

    Finally there are various properties that allow further fine tuning of the pool behaviour:

    • defaultAutoCommit - true or false: default auto-commit state of the connections created by this pool. Default: true
    • defaultReadOnly - true or false: default read-only state of the connections created by this pool. Default: false
    • defaultTransactionIsolation - This sets the default transaction isolation level. Can be one of NONE, READ_COMMITTED, READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE. Default: no default set
    • poolPreparedStatements - true or false: whether to pool PreparedStatements and CallableStatements. Default: false
    • maxOpenPreparedStatements - The maximum number of open statements that can be allocated from the statement pool at the same time. Default: -1 (unlimited)
    • defaultCatalog - The name of the default catalog. Default: not set
    • connectionInitSqls - A list of SQL statements run once after a Connection is created. Separate multiple statements by semicolons (;). Default: no statement
    • connectionProperties - A list of driver specific properties passed to the driver for creating connections. Each property is given as name=value, multiple properties are separated by semicolons (;). Default: no properties
    • accessToUnderlyingConnectionAllowed - true or false: whether accessing the underlying connections is allowed. Default: false

    For more details, please refer to the commons-dbcp documentation.

    If none of the standard resource factories meet your needs, you can write your own factory and integrate it into Tomcat, and then configure the use of this factory in the <Context> element for the web application. In the example below, we will create a factory that only knows how to create com.mycompany.MyBean beans from the Generic JavaBean Resources example above.

    1. Write A Resource Factory Class

    You must write a class that implements the JNDI service provider javax.naming.spi.ObjectFactory inteface. Every time your web application calls lookup() on a context entry that is bound to this factory (assuming that the factory is configured with singleton="false"), the getObjectInstance() method is called, with the following arguments:

    • Object obj - The (possibly null) object containing location or reference information that can be used in creating an object. For Tomcat, this will always be an object of type javax.naming.Reference, which contains the class name of this factory class, as well as the configuration properties (from the <Context> for the web application) to use in creating objects to be returned.
    • Name name - The name to which this factory is bound relative to nameCtx, or null if no name is specified.
    • Context nameCtx - The context relative to which the name parameter is specified, or null if name is relative to the default initial context.
    • Hashtable environment - The (possibly null) environment that is used in creating this object. This is generally ignored in Tomcat object factories.

    To create a resource factory that knows how to produce MyBean instances, you might create a class like this:

    package com.mycompany; import java.util.Enumeration; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; public class MyBeanFactory implements ObjectFactory { public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws NamingException { // Acquire an instance of our specified bean class MyBean bean = new MyBean(); // Customize the bean properties from our attributes Reference ref = (Reference) obj; Enumeration addrs = ref.getAll(); while (addrs.hasMoreElements()) { RefAddr addr = (RefAddr) addrs.nextElement(); String name = addr.getType(); String value = (String) addr.getContent(); if (name.equals("foo")) { bean.setFoo(value); } else if (name.equals("bar")) { try { bean.setBar(Integer.parseInt(value)); } catch (NumberFormatException e) { throw new NamingException("Invalid 'bar' value " + value); } } } // Return the customized instance return (bean); } }

    In this example, we are unconditionally creating a new instance of the com.mycompany.MyBean class, and populating its properties based on the parameters included in the <ResourceParams> element that configures this factory (see below). You should note that any parameter named factory should be skipped - that parameter is used to specify the name of the factory class itself (in this case, com.mycompany.MyBeanFactory) rather than a property of the bean being configured.

    For more information about ObjectFactory, see the JNDI 1.2 Service Provider Interface (SPI) Specification.

    You will need to compile this class against a class path that includes all of the JAR files in the $CATALINA_HOME/lib directory. When you are through, place the factory class (and the corresponding bean class) unpacked under $CATALINA_HOME/lib, or in a JAR file inside $CATALINA_HOME/lib. In this way, the required class files are visible to both Catalina internal resources and your web application.

    2. Declare Your Resource Requirements

    Next, modify your web application deployment descriptor (/WEB-INF/web.xml) to declare the JNDI name under which you will request new instances of this bean. The simplest approach is to use a <resource-env-ref> element, like this:

    <resource-env-ref> <description> Object factory for MyBean instances. </description> <resource-env-ref-name> bean/MyBeanFactory </resource-env-ref-name> <resource-env-ref-type> com.mycompany.MyBean </resource-env-ref-type> <resource-env-ref>

    WARNING - Be sure you respect the element ordering that is required by the DTD for web application deployment descriptors! See the Servlet Specification for details.

    3. Code Your Application's Use Of This Resource

    A typical use of this resource environment reference might look like this:

    Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory"); writer.println("foo = " + bean.getFoo() + ", bar = " + bean.getBar());

    4. Configure Tomcat's Resource Factory

    To configure Tomcat's resource factory, add an elements like this to the <Context> element for this web application.

    <Context ...> ... <Resource name="bean/MyBeanFactory" auth="Container" type="com.mycompany.MyBean" factory="com.mycompany.MyBeanFactory" singleton="false" bar="23"/> ... </Context>

    Note that the resource name (here, bean/MyBeanFactory must match the value specified in the web application deployment descriptor. We are also initializing the value of the bar property, which will cause setBar(23) to be called before the new bean is returned. Because we are not initializing the foo property (although we could have), the bean will contain whatever default value is set up by its constructor.

    You will also note that, from the application developer's perspective, the declaration of the resource environment reference, and the programming used to request new instances, is identical to the approach used for the Generic JavaBean Resources example. This illustrates one of the advantages of using JNDI resources to encapsulate functionality - you can change the underlying implementation without necessarily having to modify applications using the resources, as long as you maintain compatible APIs.

    tomcat7-7.0.52/webapps/docs/security-howto.xml0000644000175100017510000005671712274431005021301 0ustar locutuslocutus ]> &project; Security Considerations

    Tomcat is configured to be reasonably secure for most use cases by default. Some environments may require more, or less, secure configurations. This page is to provide a single point of reference for configuration options that may impact security and to offer some commentary on the expected impact of changing those options. The intention is to provide a list of configuration options that should be considered when assessing the security of a Tomcat installation.

    Note: Reading this page is not a substitute for reading and understanding the detailed configuration documentation. Fuller descriptions of these attributes may be found in the relevant documentation pages.

    Tomcat configuration should not be the only line of defense. The other components in the system (operating system, network, database, etc.) should also be secured.

    Tomcat should not be run under the root user. Create a dedicated user for the Tomcat process and provide that user with the minimum necessary permissions for the operating system. For example, it should not be possible to log on remotely using the Tomcat user.

    File permissions should also be suitable restricted. Taking the Tomcat instances at the ASF as an example (where auto-deployment is disabled and web applications are deployed as exploded directories), the standard configuration is to have all Tomcat files owned by root with group Tomcat and whilst owner has read/write priviliges, group only has read and world has no permissions. The exceptions are the logs, temp and work directory that are owned by the Tomcat user rather than root. This means that even if an attacker compromises the Tomcat process, they can't change the Tomcat configuration, deploy new web applications or modify existing web applications. The Tomcat process runs with a umask of 007 to maintain these permissions.

    At the network level, consider using a firewall to limit both incoming and outgoing connections to only those connections you expect to be present.

    Tomcat ships with a number of web applications that are enabled by default. Vulnerabilities have been discovered in these applications in the past. Applications that are not required should be removed so the system will not be at risk if another vulnerability is discovered.

    The ROOT web application presents a very low security risk but it does include the version of Tomcat that is being used. The ROOT web application should normally be removed from a publicly accessible Tomcat instance, not for security reasons, but so that a more appropriate default page is shown to users.

    The documentation web application presents a very low security risk but it does identify the version of Tomcat that is being used. It should normally be removed from a publicly accessible Tomcat instance.

    The examples web application should always be removed from any security sensitive installation. While the examples web application does not contain any known vulnerabilities, it is known to contain features (particularly the cookie examples that display the contents of all received and allow new cookies to be set) that may be used by an attacker in conjunction with a vulnerability in another application deployed on the Tomcat instance to obtain additional information that would otherwise be unavailable.

    The Manager application allows the remote deployment of web applications and is frequently targeted by attackers due to the widespread use of weak passwords and publicly accessible Tomcat instances with the Manager application enabled. The Manager application is not accessible by default as no users are configured with the necessary access. If the Manager application is enabled then guidance in the section Securing Management Applications section should be followed.

    The Host Manager application allows the creation and management of virtual hosts - including the enabling of the Manager application for a virtual host. The Host Manager application is not accessible by default as no users are configured with the necessary access. If the Host Manager application is enabled then guidance in the section Securing Management Applications section should be followed.

    When deploying a web application that provides management functions for the Tomcat instance, the following guidelines should be followed:

        Ensure that any users permitted to access the management application have strong passwords.
        Do not remove the use of the LockOutRealm which prevents brute force attacks against user passwords.
        Uncomment the RemoteAddrValve in /META-INF/context.xml which limits access to localhost. If remote access is required, limit it to specific IP addresses using this valve.

    Enabling the security manager causes web applications to be run in a sandbox, significantly limiting a web application's ability to perform malicious actions such as calling System.exit(), establishing network connections or accessing the file system outside of the web application's root and temporary directories. However, it should be noted that there are some malicious actions, such as triggering high CPU consumption via an infinite loop, that the security manager cannot prevent.

    Enabling the security manager is usually done to limit the potential impact, should an attacker find a way to compromise a trusted web application . A security manager may also be used to reduce the risks of running untrusted web applications (e.g. in hosting environments) but it should be noted that the security manager only reduces the risks of running untrusted web applications, it does not eliminate them. If running multiple untrusted web applications, it is recommended that each web application is deployed to a separate Tomcat instance (and ideally separate hosts) to reduce the ability of a malicious web application impacting the availability of other applications.

    Tomcat is tested with the security manager enabled; but the majority of Tomcat users do not run with a security manager, so Tomcat is not as well user-tested in this configuration. There have been, and continue to be, bugs reported that are triggered by running under a security manager.

    The restrictions imposed by a security manager are likely to break most applications if the security manager is enabled. The security manager should not be used without extensive testing. Ideally, the use of a security manager should be introduced at the start of the development cycle as it can be time-consuming to track down and fix issues caused by enabling a security manager for a mature application.

    Enabling the security manager changes the defaults for the following settings:

    • The default value for the deployXML attribute of the Host element is changed to false.

    The default server.xml contains a large number of comments, including some example component definitions that are commented out. Removing these comments makes it considerably easier to read and comprehend server.xml.

    If a component type is not listed, then there are no settings for that type that directly impact security.

    Setting the port attribute to -1 disables the shutdown port.

    If the shutdown port is not disabled, a strong password should be configured for shutdown.

    The APR Lifecycle Listener is not stable if compiled on Solaris using gcc. If using the APR/native connector on Solaris, compile it with the Sun Studio compiler.

    The Security Listener should be enabled and configured as appropriate.

    By default, an HTTP and an AJP connector are configured. Connectors that will not be used should be removed from server.xml.

    The address attribute may be used to control which IP address the connector listens on for connections. By default, the connector listens on all configured IP addresses.

    The allowTrace attribute may be used to enable TRACE requests which can be useful for debugging. Due to the way some browsers handle the response from a TRACE request (which exposes the browser to an XSS attack), support for TRACE requests is disabled by default.

    The maxPostSize attribute controls the maximum size of a POST request that will be parsed for parameters. The parameters are cached for the duration of the request so this is limited to 2MB by default to reduce exposure to a DOS attack.

    The maxSavePostSize attribute controls the saving of POST requests during FORM and CLIENT-CERT authentication. The parameters are cached for the duration of the authentication (which may be many minutes) so this is limited to 4KB by default to reduce exposure to a DOS attack.

    The maxParameterCount attribute controls the maximum number of parameter and value pairs (GET plus POST) that can be parsed and stored in the request. Excessive parameters are ignored. If you want to reject such requests, configure a FailedRequestFilter.

    The xpoweredBy attribute controls whether or not the X-Powered-By HTTP header is sent with each request. If sent, the value of the header contains the Servlet and JSP specification versions, the full Tomcat version (e.g. Apache Tomcat/7.0.0), the name of the JVM vendor and the version of the JVM. This header is disabled by default. This header can provide useful information to both legitimate clients and attackers.

    The server attribute controls the value of the Server HTTP header. The default value of this header for Tomcat 4.1.x, 5.0.x, 5.5.x, 6.0.x and 7.0.x is Apache-Coyote/1.1. This header can provide limited information to both legitimate clients and attackers.

    The SSLEnabled, scheme and secure attributes may all be independently set. These are normally used when Tomcat is located behind a reverse proxy and the proxy is connecting to Tomcat via HTTP or HTTPS. They allow Tomcat to see the SSL attributes of the connections between the client and the proxy rather than the proxy and Tomcat. For example, the client may connect to the proxy over HTTPS but the proxy connects to Tomcat using HTTP. If it is necessary for Tomcat to be able to distinguish between secure and non-secure connections received by a proxy, the proxy must use separate connectors to pass secure and non-secure requests to Tomcat. If the proxy uses AJP then the SSL attributes of the client connection are passed via the AJP protocol and separate connectors are not needed.

    The ciphers attribute controls the ciphers used for SSL connections. By default, the default ciphers for the JVM will be used. This usually means that the weak export grade ciphers will be included in the list of available ciphers. Secure environments will normally want to configure a more limited set of ciphers.

    The tomcatAuthentication attribute is used with the AJP connectors to determine if Tomcat should authenticate the user or if authentication can be delegated to the reverse proxy that will then pass the authenticated username to Tomcat as part of the AJP protocol.

    The allowUnsafeLegacyRenegotiation attribute provides a workaround for CVE-2009-3555, a TLS man in the middle attack. This workaround applies to the BIO connector. It is only necessary if the underlying SSL implementation is vulnerable to CVE-2009-3555. For more information on the current state of this vulnerability and the work-arounds available see the Tomcat 7 security page.

    The requiredSecret attribute in AJP connectors configures shared secret between Tomcat and reverse proxy in front of Tomcat. It is used to prevent unauthorized connections over AJP protocol.

    The host element controls deployment. Automatic deployment allows for simpler management but also makes it easier for an attacker to deploy a malicious application. Automatic deployment is controlled by the autoDeploy and deployOnStartup attributes. If both are false, only Contexts defined in server.xml will be deployed and any changes will require a Tomcat restart.

    In a hosted environment where web applications may not be trusted, set the deployXML attribute to false to ignore any context.xml packaged with the web application that may try to assign increased privileges to the web application. Note that if the security manager is enabled that the deployXML attribute will default to false.

    This applies to Context elements in all places where they can be defined: server.xml file, default context.xml file, per-host context.xml.default file, web application context file in per-host configuration directory or inside the web application.

    The crossContext attribute controls if a context is allowed to access the resources of another context. It is false by default and should only be changed for trusted web applications.

    The privileged attribute controls if a context is allowed to use container provided servlets like the Manager servlet. It is false by default and should only be changed for trusted web applications.

    The allowLinking attribute controls if a context is allowed to use linked files. If enabled and the context is undeployed, the links will be followed when deleting the context resources. To avoid this behaviour, use the aliases attribute. Changing this setting from the default of false on case insensitive operating systems (this includes Windows) will disable a number of security measures and allow, among other things, direct access to the WEB-INF directory.

    It is strongly recommended that an AccessLogValve is configured. The default Tomcat configuration includes an AccessLogValve. These are normally configured per host but may also be configured per engine or per context as required.

    Any administrative application should be protected by a RemoteAddrValve. (Note that this Valve is also available as a Filter.) The allow attribute should be used to limit access to a set of known trusted hosts.

    The default ErrorReportValve includes the Tomcat version number in the response sent to clients. To avoid this, custom error handling can be configured within each web application. Alternatively, the version number can be changed by creating the file CATALINA_BASE/lib/org/apache/catalina/util/ServerInfo.properties with content as follows:

    server.info=Apache Tomcat/7.0.x

    Modify the values as required. Note that this will also change the version number reported in some of the management tools and may make it harder to determine the real version installed. The CATALINA_HOME/bin/version.bat|sh script will still report the version number.

    The default ErrorReportValve can display stack traces and/or JSP source code to clients when an error occurs. To avoid this, custom error handling can be configured within each web application.

    The MemoryRealm is not intended for production use as any changes to tomcat-users.xml require a restart of Tomcat to take effect.

    The JDBCRealm is not recommended for production use as it is single threaded for all authentication and authorization options. Use the DataSourceRealm instead.

    The UserDatabaseRealm is not intended for large-scale installations. It is intended for small-scale, relatively static environments.

    The JAASRealm is not widely used and therefore the code is not as mature as the other realms. Additional testing is recommended before using this realm.

    By default, the realms do not implement any form of account lock-out. This means that brute force attacks can be successful. To prevent a brute force attack, the chosen realm should be wrapped in a LockOutRealm.

    The manager component is used to generate session IDs.

    The default entropy value has been shown to generate predictable values under certain conditions. For more secure session generation, this should be set to a long string. This is done automatically if the APR/native library is installed; a random value will be obtained from the APR/native library.

    The class used to generate random session IDs may be changed with the randomClass attribute.

    The length of the session ID may be changed with the sessionIdLength attribute.

    Setting org.apache.catalina.connector.RECYCLE_FACADES system property to true will cause a new facade object to be created for each request. This reduces the chances of a bug in an application exposing data from one request to another.

    The org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH and org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH system properties allow non-standard parsing of the request URI. Using these options when behind a reverse proxy may enable an attacker to bypass any security constraints enforced by the proxy.

    The org.apache.catalina.connector.Response.ENFORCE_ENCODING_IN_GET_WRITER system property has security implications if disabled. Many user agents, in breach of RFC2616, try to guess the character encoding of text media types when the specification-mandated default of ISO-8859-1 should be used. Some browsers will interpret as UTF-7 a response containing characters that are safe for ISO-8859-1 but trigger an XSS vulnerability if interpreted as UTF-7.

    This applies to the default conf/web.xml file and WEB-INF/web.xml files in web applications if they define the components mentioned here.

    The DefaultServlet is configured with readonly set to true. Changing this to false allows clients to delete or modify static resources on the server and to upload new resources. This should not normally be changed without requiring authentication.

    The DefaultServlet is configured with listings set to false. This isn't because allowing directory listings is considered unsafe but because generating listings of directories with thousands of files can consume significant CPU leading to a DOS attack.

    FailedRequestFilter can be configured and used to reject requests that had errors during request parameter parsing. Without the filter the default behaviour is to ignore invalid or excessive parameters.

    BASIC and FORM authentication pass user names and passwords in clear text. Web applications using these authentication mechanisms with clients connecting over untrusted networks should use SSL.

    The session cookie for a session with an authenticated user are nearly as useful as the user's password to an attacker and in nearly all circumstances should be afforded the same level of protection as the password itself. This usually means authenticating over SSL and continuing to use SSL until the session ends.

    tomcat7-7.0.52/webapps/docs/manager-howto.xml0000644000175100017510000015477712271304167021056 0ustar locutuslocutus ]> &project; Craig R. McClanahan Manager App HOW-TO

    In many production environments, it is very useful to have the capability to deploy a new web application, or undeploy an existing one, without having to shut down and restart the entire container. In addition, you can request an existing application to reload itself, even if you have not declared it to be reloadable in the Tomcat server configuration file.

    To support these capabilities, Tomcat includes a web application (installed by default on context path /manager) that supports the following functions:

    • Deploy a new web application from the uploaded contents of a WAR file.
    • Deploy a new web application, on a specified context path, from the server file system.
    • List the currently deployed web applications, as well as the sessions that are currently active for those web apps.
    • Reload an existing web application, to reflect changes in the contents of /WEB-INF/classes or /WEB-INF/lib.
    • List the OS and JVM property values.
    • List the available global JNDI resources, for use in deployment tools that are preparing <ResourceLink> elements nested in a <Context> deployment description.
    • Start a stopped application (thus making it available again).
    • Stop an existing application (so that it becomes unavailable), but do not undeploy it.
    • Undeploy a deployed web application and delete its document base directory (unless it was deployed from file system).

    A default Tomcat installation includes the Manager. To add an instance of the Manager web application Context to a new host install the manager.xml context configuration file in the $CATALINA_BASE/conf/[enginename]/[hostname] folder. Here is an example:

    <Context privileged="true" antiResourceLocking="false"
             docBase="${catalina.home}/webapps/manager">
      <Valve className="org.apache.catalina.valves.RemoteAddrValve"
             allow="127\.0\.0\.1" />
    </Context>
    

    If you have Tomcat configured to support multiple virtual hosts (websites) you would need to configure a Manager for each.

    There are three ways to use the Manager web application.

    • As an application with a user interface you use in your browser. Here is an example URL where you can replace localhost with your website host name: http://localhost/manager/html/ .
    • A minimal version using HTTP requests only which is suitable for use by scripts setup by system administrators. Commands are given as part of the request URI, and responses are in the form of simple text that can be easily parsed and processed. See Supported Manager Commands for more information.
    • A convenient set of task definitions for the Ant (version 1.4 or later) build tool. See Executing Manager Commands With Ant for more information.

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    It would be quite unsafe to ship Tomcat with default settings that allowed anyone on the Internet to execute the Manager application on your server. Therefore, the Manager application is shipped with the requirement that anyone who attempts to use it must authenticate themselves, using a username and password that have one of manager-** roles associated with them (the role name depends on what functionality is required). Further, there is no username in the default users file ($CATALINA_BASE/conf/tomcat-users.xml) that is assigned to those roles. Therefore, access to the Manager application is completely disabled by default.

    You can find the role names in the web.xml file of the Manager web application. The available roles are:

    • manager-gui — Access to the HTML interface.
    • manager-status — Access to the "Server Status" page only.
    • manager-script — Access to the tools-friendly plain text interface that is described in this document, and to the "Server Status" page.
    • manager-jmx — Access to JMX proxy interface and to the "Server Status" page.

    The HTML interface is protected against CSRF (Cross-Site Request Forgery) attacks, but the text and JMX interfaces cannot be protected. To maintain the CSRF protection:

    • Users with the manager-gui role should not be granted the manager-script or manager-jmx roles.
    • If you use web browser to access the Manager application using a user that has either manager-script or manager-jmx roles (for example for testing the plain text or JMX interfaces), then all windows of the browser MUST be closed afterwards to terminate the session.

    Note that JMX proxy interface is effectively low-level root-like administrative interface of Tomcat. One can do a lot, if he knows what commands to call. You should be cautious when enabling the manager-jmx role.

    To enable access to the Manager web application, you must either create a new username/password combination and associate one of the manager-** roles with it, or add a manager-** role to some existing username/password combination. As the majority of this document describes the commands of plain textual interface, let the role name for further example to be manager-script. Exactly how the usernames/passwords are configured depends on which Realm implementation you are using:

    • MemoryRealm — This one is configured in the default $CATALINA_BASE/conf/server.xml. If you have not configured it differently, or replaced it with a different Realm implementation, this realm reads an XML-format file stored at $CATALINA_BASE/conf/tomcat-users.xml, which can be edited with any text editor. This file contains an XML <user> for each individual user, which might look something like this: <user name="craigmcc" password="secret" roles="standard,manager-script" /> which defines the username and password used by this individual to log on, and the role names he or she is associated with. You can add the manager-script role to the comma-delimited roles attribute for one or more existing users, and/or create new users with that assigned role.
    • JDBCRealm — Your user and role information is stored in a database accessed via JDBC. Add the manager-script role to one or more existing users, and/or create one or more new users with this role assigned, following the standard procedures for your environment.
    • JNDIRealm — Your user and role information is stored in a directory server accessed via LDAP. Add the manager-script role to one or more existing users, and/or create one or more new users with this role assigned, following the standard procedures for your environment.

    The first time you attempt to issue one of the Manager commands described in the next section, you will be challenged to log on using BASIC authentication. The username and password you enter do not matter, as long as they identify a valid user in the users database who possesses the role manager-script.

    In addition to the password restrictions the Manager web application could be restricted by the remote IP address or host by adding a RemoteAddrValve or RemoteHostValve. See valves documentation for details. Here is an example of restricting access to the localhost by IP address:

    <Context privileged="true">
             <Valve className="org.apache.catalina.valves.RemoteAddrValve"
                    allow="127\.0\.0\.1"/>
    </Context>
    

    All commands that the Manager application knows how to process are specified in a single request URI like this:

    http://{host}:{port}/manager/text/{command}?{parameters}

    where {host} and {port} represent the hostname and port number on which Tomcat is running, {command} represents the Manager command you wish to execute, and {parameters} represents the query parameters that are specific to that command. In the illustrations below, customize the host and port appropriately for your installation.

    Most commands accept one or more of the following query parameters:

    • path - The context path (including the leading slash) of the web application you are dealing with. To select the ROOT web application, specify "/". NOTE - It is not possible to perform administrative commands on the Manager application itself.
    • version - The version of this web application as used by the parallel deployment feature,
    • war - URL of a web application archive (WAR) file, pathname of a directory which contains the web application, or a Context configuration ".xml" file. You can use URLs in any of the following formats:
      • file:/absolute/path/to/a/directory - The absolute path of a directory that contains the unpacked version of a web application. This directory will be attached to the context path you specify without any changes.
      • file:/absolute/path/to/a/webapp.war - The absolute path of a web application archive (WAR) file. This is valid only for the /deploy command, and is the only acceptable format to that command.
      • jar:file:/absolute/path/to/a/warfile.war!/ - The URL to a local web application archive (WAR) file. You can use any syntax that is valid for the JarURLConnection class for reference to an entire JAR file.
      • file:/absolute/path/to/a/context.xml - The absolute path of a web application Context configuration ".xml" file which contains the Context configuration element.
      • directory - The directory name for the web application context in the Host's application base directory.
      • webapp.war - The name of a web application war file located in the Host's application base directory.

    Each command will return a response in text/plain format (i.e. plain ASCII with no HTML markup), making it easy for both humans and programs to read). The first line of the response will begin with either OK or FAIL, indicating whether the requested command was successful or not. In the case of failure, the rest of the first line will contain a description of the problem that was encountered. Some commands include additional lines of information as described below.

    Internationalization Note - The Manager application looks up its message strings in resource bundles, so it is possible that the strings have been translated for your platform. The examples below show the English version of the messages.

    http://localhost:8080/manager/text/deploy?path=/foo

    Upload the web application archive (WAR) file that is specified as the request data in this HTTP PUT request, install it into the appBase directory of our corresponding virtual host, and start , using the directory name or the war file name without the .war extension as the path. The application can later be undeployed (and the corresponding application directory removed) by use of the /undeploy command.

    The .WAR file may include Tomcat specific deployment configuration, by including a Context configuration XML file in /META-INF/context.xml.

    URL parameters include:

    • update: When set to true, any existing update will be undeployed first. The default value is set to false.
    • tag: Specifying a tag name, this allows associating the deployed webapp with a tag or label. If the web application is undeployed, it can be later redeployed when needed using only the tag.

    NOTE - This command is the logical opposite of the /undeploy command.

    If installation and startup is successful, you will receive a response like this:

    OK - Deployed application at context path /foo

    Otherwise, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Application already exists at path /foo

      The context paths for all currently running web applications must be unique. Therefore, you must undeploy the existing web application using this context path, or choose a different context path for the new one. The update parameter may be specified as a parameter on the URL, with a value of true to avoid this error. In that case, an undeploy will be performed on an existing application before performing the deployment.

    • Encountered exception

      An exception was encountered trying to start the new web application. Check the Tomcat logs for the details, but likely explanations include problems parsing your /WEB-INF/web.xml file, or missing classes encountered when initializing application event listeners and filters.

    Deploy and start a new web application, attached to the specified context path (which must not be in use by any other web application). This command is the logical opposite of the /undeploy command.

    There are a number of different ways the deploy command can be used.

    Deploy a previously deployed webapp

    This can be used to deploy a previously deployed web application, which has been deployed using the tag attribute. Note that the work directory for the Manager webapp will contain the previously deployed WARs; removing it would make the deployment fail.

    http://localhost:8080/manager/text/deploy?path=/footoo&tag=footag

    Deploy a Directory or WAR by URL

    Deploy a web application directory or ".war" file located on the Tomcat server. If no path is specified, the directory name or the war file name without the ".war" extension is used as the path. The war parameter specifies a URL (including the file: scheme) for either a directory or a web application archive (WAR) file. The supported syntax for a URL referring to a WAR file is described on the Javadocs page for the java.net.JarURLConnection class. Use only URLs that refer to the entire WAR file.

    In this example the web application located in the directory /path/to/foo on the Tomcat server is deployed as the web application context named /footoo.

    http://localhost:8080/manager/text/deploy?path=/footoo&war=file:/path/to/foo

    In this example the ".war" file /path/to/bar.war on the Tomcat server is deployed as the web application context named /bar. Notice that there is no path parameter so the context path defaults to the name of the web application archive file without the ".war" extension.

    http://localhost:8080/manager/text/deploy?war=jar:file:/path/to/bar.war!/

    Deploy a Directory or War from the Host appBase

    Deploy a web application directory or ".war" file located in your Host appBase directory. The directory name or the war file name without the ".war" extension is used as the path.

    In this example the web application located in a sub directory named foo in the Host appBase directory of the Tomcat server is deployed as the web application context named /foo. Notice that the context path used is the name of the web application directory.

    http://localhost:8080/manager/text/deploy?war=foo

    In this example the ".war" file bar.war located in your Host appBase directory on the Tomcat server is deployed as the web application context named /bar.

    http://localhost:8080/manager/text/deploy?war=bar.war

    Deploy using a Context configuration ".xml" file

    If the Host deployXML flag is set to true you can deploy a web application using a Context configuration ".xml" file and an optional ".war" file or web application directory. The context path is not used when deploying a web application using a context ".xml" configuration file.

    A Context configuration ".xml" file can contain valid XML for a web application Context just as if it were configured in your Tomcat server.xml configuration file. Here is an example:

    <Context path="/foobar" docBase="/path/to/application/foobar"> </Context>

    When the optional war parameter is set to the URL for a web application ".war" file or directory it overrides any docBase configured in the context configuration ".xml" file.

    Here is an example of deploying an application using a Context configuration ".xml" file.

    http://localhost:8080/manager/text/deploy?config=file:/path/context.xml

    Here is an example of deploying an application using a Context configuration ".xml" file and a web application ".war" file located on the server.

    http://localhost:8080/manager/text/deploy ?config=file:/path/context.xml&war=jar:file:/path/bar.war!/

    Deployment Notes

    If the Host is configured with unpackWARs=true and you deploy a war file, the war will be unpacked into a directory in your Host appBase directory.

    If the application war or directory is installed in your Host appBase directory and either the Host is configured with autoDeploy=true or the Context path must match the directory name or war file name without the ".war" extension.

    For security when untrusted users can manage web applications, the Host deployXML flag can be set to false. This prevents untrusted users from deploying web applications using a configuration XML file and also prevents them from deploying application directories or ".war" files located outside of their Host appBase.

    Deploy Response

    If installation and startup is successful, you will receive a response like this:

    OK - Deployed application at context path /foo

    Otherwise, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Application already exists at path /foo

      The context paths for all currently running web applications must be unique. Therefore, you must undeploy the existing web application using this context path, or choose a different context path for the new one. The update parameter may be specified as a parameter on the URL, with a value of true to avoid this error. In that case, an undeploy will be performed on an existing application before performing the deployment.

    • Document base does not exist or is not a readable directory

      The URL specified by the war parameter must identify a directory on this server that contains the "unpacked" version of a web application, or the absolute URL of a web application archive (WAR) file that contains this application. Correct the value specified by the war parameter.

    • Encountered exception

      An exception was encountered trying to start the new web application. Check the Tomcat logs for the details, but likely explanations include problems parsing your /WEB-INF/web.xml file, or missing classes encountered when initializing application event listeners and filters.

    • Invalid application URL was specified

      The URL for the directory or web application that you specified was not valid. Such URLs must start with file:, and URLs for a WAR file must end in ".war".

    • Invalid context path was specified

      The context path must start with a slash character. To reference the ROOT web application use "/".

    • Context path must match the directory or WAR file name:
      If the application war or directory is installed in your Host appBase directory and either the Host is configured with autoDeploy=true the Context path must match the directory name or war file name without the ".war" extension.
    • Only web applications in the Host web application directory can be installed
      If the Host deployXML flag is set to false this error will happen if an attempt is made to deploy a web application directory or ".war" file outside of the Host appBase directory.
    http://localhost:8080/manager/text/list

    List the context paths, current status (running or stopped), and number of active sessions for all currently deployed web applications. A typical response immediately after starting Tomcat might look like this:

    OK - Listed applications for virtual host localhost /webdav:running:0 /examples:running:0 /manager:running:0 /:running:0
    http://localhost:8080/manager/text/reload?path=/examples

    Signal an existing application to shut itself down and reload. This can be useful when the web application context is not reloadable and you have updated classes or property files in the /WEB-INF/classes directory or when you have added or updated jar files in the /WEB-INF/lib directory.

    NOTE: The /WEB-INF/web.xml web application configuration file is not reread on a reload. If you have made changes to your web.xml file you must stop then start the web application.

    If this command succeeds, you will see a response like this:

    OK - Reloaded application at context path /examples

    Otherwise, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to restart the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character. To reference the ROOT web application use "/".

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.
    • Reload not supported on WAR deployed at path /foo
      Currently, application reloading (to pick up changes to the classes or web.xml file) is not supported when a web application is deployed directly from a WAR file. It only works when the web application is deployed from an unpacked directory. If you are using a WAR file, you should undeploy and then deploy or deploy with the update parameter the application again to pick up your changes.
    http://localhost:8080/manager/text/serverinfo

    Lists information about the Tomcat version, OS, and JVM properties.

    If an error occurs, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to enumerate the system properties. Check the Tomcat logs for the details.

    http://localhost:8080/manager/text/resources[?type=xxxxx]

    List the global JNDI resources that are available for use in resource links for context configuration files. If you specify the type request parameter, the value must be the fully qualified Java class name of the resource type you are interested in (for example, you would specify javax.sql.DataSource to acquire the names of all available JDBC data sources). If you do not specify the type request parameter, resources of all types will be returned.

    Depending on whether the type request parameter is specified or not, the first line of a normal response will be:

      OK - Listed global resources of all types
    

    or

      OK - Listed global resources of type xxxxx
    

    followed by one line for each resource. Each line is composed of fields delimited by colon characters (":"), as follows:

    • Global Resource Name - The name of this global JNDI resource, which would be used in the global attribute of a <ResourceLink> element.
    • Global Resource Type - The fully qualified Java class name of this global JNDI resource.

    If an error occurs, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to enumerate the global JNDI resources. Check the Tomcat logs for the details.

    • No global JNDI resources are available

      The Tomcat server you are running has been configured without global JNDI resources.

    http://localhost:8080/manager/text/sessions?path=/examples

    Display the default session timeout for a web application, and the number of currently active sessions that fall within ten-minute ranges of their actual timeout times. For example, after restarting Tomcat and then executing one of the JSP samples in the /examples web app, you might get something like this:

    OK - Session information for application at context path /examples Default maximum session inactive interval 30 minutes 30 - <40 minutes:1 sessions
    http://localhost:8080/manager/text/start?path=/examples

    Signal a stopped application to restart, and make itself available again. Stopping and starting is useful, for example, if the database required by your application becomes temporarily unavailable. It is usually better to stop the web application that relies on this database rather than letting users continuously encounter database exceptions.

    If this command succeeds, you will see a response like this:

    OK - Started application at context path /examples

    Otherwise, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to start the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character. To reference the ROOT web application use "/".

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.
    http://localhost:8080/manager/text/stop?path=/examples

    Signal an existing application to make itself unavailable, but leave it deployed. Any request that comes in while an application is stopped will see an HTTP error 404, and this application will show as "stopped" on a list applications command.

    If this command succeeds, you will see a response like this:

    OK - Stopped application at context path /examples

    Otherwise, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to stop the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character. To reference the ROOT web application use "/".

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.
    http://localhost:8080/manager/text/undeploy?path=/examples

    WARNING - This command will delete any web application artifacts that exist within appBase directory (typically "webapps") for this virtual host. This will delete the the application .WAR, if present, the application directory resulting either from a deploy in unpacked form or from .WAR expansion as well as the XML Context definition from $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. If you simply want to take an application out of service, you should use the /stop command instead.

    Signal an existing application to gracefully shut itself down, and remove it from Tomcat (which also makes this context path available for reuse later). In addition, the document root directory is removed, if it exists in the appBase directory (typically "webapps") for this virtual host. This command is the logical opposite of the /deploy command.

    If this command succeeds, you will see a response like this:

    OK - Undeployed application at context path /examples

    Otherwise, the response will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to undeploy the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character. To reference the ROOT web application use "/".

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.
    http://localhost:8080/manager/text/findleaks[?statusLine=[true|false]]

    The find leaks diagnostic triggers a full garbage collection. It should be used with extreme caution on production systems.

    The find leaks diagnostic attempts to identify web applications that have caused memory leaks when they were stopped, reloaded or undeployed. Results should always be confirmed with a profiler. The diagnostic uses additional functionality provided by the StandardHost implementation. It will not work if a custom host is used that does not extend StandardHost.

    Explicitly triggering a full garbage collection from Java code is documented to be unreliable. Furthermore, depending on the JVM used, there are options to disable explicit GC triggering, like -XX:+DisableExplicitGC. If you want to make sure, that the diagnostics were successfully running a full GC, you will need to check using tools like GC logging, JConsole or similar.

    If this command succeeds, you will see a response like this:

    /leaking-webapp

    If you wish to see a status line included in the response then include the statusLine query parameter in the request with a value of true.

    Each context path for a web application that was stopped, reloaded or undeployed, but which classes from the previous runs are still loaded in memory, thus causing a memory leak, will be listed on a new line. If an application has been reloaded several times, it may be listed several times.

    If the command does not succeed, the response will start with FAIL and include an error message.

    From this link , you can view information about the server.

    First, you have the server and JVM version number, JVM provider, OS name and number followed by the architecture type.

    Second, there is several information about the memory usage of the JVM (available, total and max memory).

    Then, there is information about the Tomcat AJP and HTTP connectors. The same information is available for both of them :

    • Threads information : Max threads, min and max spare threads, current thread count and current thread busy.

    • Request information : Max processing time and processing time, request and error count, bytes received and sent.

    • A table showing Stage, Time, Bytes Sent, Bytes Receive, Client, VHost and Request. All existing threads are listed in the table. Here is the list of the possible thread stages :

      • "Parse and Prepare Request" : The request headers are being parsed or the necessary preparation to read the request body (if a transfer encoding has been specified) is taking place.

      • "Service" : The thread is processing a request and generating the response. This stage follows the "Parse and Prepare Request" stage and precedes the "Finishing" stage. There is always at least one thread in this stage (the server-status page).

      • "Finishing" : The end of the request processing. Any remainder of the response still in the output buffers is sent to the client. This stage is followed by "Keep-Alive" if it is appropriate to keep the connection alive or "Ready" if "Keep-Alive" is not appropriate.

      • "Keep-Alive" : The thread keeps the connection open to the client in case the client sends another request. If another request is received, the next stage will br "Parse and Prepare Requst". If no request is received before the keep alive times out, the connection will be closed and the next stage will be "Ready".

      • "Ready" : The thread is at rest and ready to be used.

    In addition to the ability to execute Manager commands via HTTP requests, as documented above, Tomcat includes a convenient set of Task definitions for the Ant (version 1.4 or later) build tool. In order to use these commands, you must perform the following setup operations:

    • Download the binary distribution of Ant from http://ant.apache.org. You must use version 1.4 or later.
    • Install the Ant distribution in a convenient directory (called ANT_HOME in the remainder of these instructions).
    • Copy the file server/lib/catalina-ant.jar from your Tomcat installation into Ant's library directory ($ANT_HOME/lib).
    • Add the $ANT_HOME/bin directory to your PATH environment variable.
    • Configure at least one username/password combination in your Tomcat user database that includes the manager-script role.

    To use custom tasks within Ant, you must declare them first with a <taskdef> element. Therefore, your build.xml file might look something like this:

    <project name="My Application" default="compile" basedir=".">
    
      <!-- Configure the directory into which the web application is built -->
      <property name="build"    value="${basedir}/build"/>
    
      <!-- Configure the context path for this application -->
      <property name="path"     value="/myapp"/>
    
      <!-- Configure properties to access the Manager application -->
      <property name="url"      value="http://localhost:8080/manager/text"/>
      <property name="username" value="myusername"/>
      <property name="password" value="mypassword"/>
    
      <!-- Configure the custom Ant tasks for the Manager application -->
      <taskdef name="deploy"    classname="org.apache.catalina.ant.DeployTask"/>
      <taskdef name="list"      classname="org.apache.catalina.ant.ListTask"/>
      <taskdef name="reload"    classname="org.apache.catalina.ant.ReloadTask"/>
      <taskdef name="findleaks" classname="org.apache.catalina.ant.FindLeaksTask"/>
      <taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask"/>
      <taskdef name="start"     classname="org.apache.catalina.ant.StartTask"/>
      <taskdef name="stop"      classname="org.apache.catalina.ant.StopTask"/>
      <taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask"/>
    
      <!-- Executable Targets -->
      <target name="compile" description="Compile web application">
        <!-- ... construct web application in ${build} subdirectory, and
                generated a ${path}.war ... -->
      </target>
    
      <target name="deploy" description="Install web application"
              depends="compile">
        <deploy url="${url}" username="${username}" password="${password}"
                path="${path}" war="file:${build}${path}.war"/>
      </target>
    
      <target name="reload" description="Reload web application"
              depends="compile">
        <reload  url="${url}" username="${username}" password="${password}"
                path="${path}"/>
      </target>
    
      <target name="undeploy" description="Remove web application">
        <undeploy url="${url}" username="${username}" password="${password}"
                path="${path}"/>
      </target>
    
    </project>
    

    Note: The definition of the resources task above will override the resources datatype added in Ant 1.7. If you wish to use the resources datatype you will need to use Ant's namespace support to assign the Tomcat tasks to their own namespace.

    Now, you can execute commands like ant deploy to deploy the application to a running instance of Tomcat, or ant reload to tell Tomcat to reload it. Note also that most of the interesting values in this build.xml file are defined as replaceable properties, so you can override their values from the command line. For example, you might consider it a security risk to include the real manager password in your build.xml file's source code. To avoid this, omit the password property, and specify it from the command line:

      ant -Dpassword=secret deploy
    

    Using Ant version 1.6.2 or later, the Catalina tasks offer the option to capture their output in properties or external files. They support directly the following subset of the <redirector> type attributes:

    Attribute Description Required
    output Name of a file to which to write the output. If the error stream is not also redirected to a file or property, it will appear in this output. No
    error The file to which the standard error of the command should be redirected. No
    logError This attribute is used when you wish to see error output in Ant's log and you are redirecting output to a file/property. The error output will not be included in the output file/property. If you redirect error with the error or errorProperty attributes, this will have no effect. No
    append Whether output and error files should be appended to or overwritten. Defaults to false. No
    createemptyfiles Whether output and error files should be created even when empty. Defaults to true. No
    outputproperty The name of a property in which the output of the command should be stored. Unless the error stream is redirected to a separate file or stream, this property will include the error output. No
    errorproperty The name of a property in which the standard error of the command should be stored. No

    A couple of additional attributes can also be specified:

    Attribute Description Required
    alwaysLog This attribute is used when you wish to see the output you are capturing, appearing also in the Ant's log. It must not be used unless you are capturing task output. Defaults to false. This attribute will be supported directly by <redirector> in Ant 1.6.3 No
    failonerror This attribute is used when you wish to avoid that any manager command processing error terminates the ant execution. Defaults to true. It must be set to false, if you want to capture error output, otherwise execution will terminate before anything can be captured.

    This attribute acts only on manager command execution, any wrong or missing command attribute will still cause Ant execution termination.
    No

    They also support the embedded <redirector> element in which you can specify its full set of attributes, but input, inputstring and inputencoding that, even if accepted, are not used because they have no meaning in this context. Refer to ant manual for details on <redirector> element attributes.

    Here is a sample build file extract that shows how this output redirection support can be used:

        <target name="manager.deploy"
            depends="context.status"
            if="context.notInstalled">
            <deploy url="${mgr.url}"
                username="${mgr.username}"
                password="${mgr.password}"
                path="${mgr.context.path}"
                config="${mgr.context.descriptor}"/>
        </target>
    
        <target name="manager.deploy.war"
            depends="context.status"
            if="context.deployable">
            <deploy url="${mgr.url}"
                username="${mgr.username}"
                password="${mgr.password}"
                update="${mgr.update}"
                path="${mgr.context.path}"
                war="${mgr.war.file}"/>
        </target>
    
        <target name="context.status">
            <property name="running" value="${mgr.context.path}:running"/>
            <property name="stopped" value="${mgr.context.path}:stopped"/>
    
            <list url="${mgr.url}"
                outputproperty="ctx.status"
                username="${mgr.username}"
                password="${mgr.password}">
            </list>
    
            <condition property="context.running">
                <contains string="${ctx.status}" substring="${running}"/>
            </condition>
            <condition property="context.stopped">
                <contains string="${ctx.status}" substring="${stopped}"/>
            </condition>
            <condition property="context.notInstalled">
                <and>
                    <isfalse value="${context.running}"/>
                    <isfalse value="${context.stopped}"/>
                </and>
            </condition>
            <condition property="context.deployable">
                <or>
                    <istrue value="${context.notInstalled}"/>
                    <and>
                        <istrue value="${context.running}"/>
                        <istrue value="${mgr.update}"/>
                    </and>
                    <and>
                        <istrue value="${context.stopped}"/>
                        <istrue value="${mgr.update}"/>
                    </and>
                </or>
            </condition>
            <condition property="context.undeployable">
                <or>
                    <istrue value="${context.running}"/>
                    <istrue value="${context.stopped}"/>
                </or>
            </condition>
        </target>
    

    WARNING: even if it doesn't make many sense, and is always a bad idea, calling a Catalina task more than once, badly set Ant tasks depends chains may cause that a task be called more than once in the same Ant run, even if not intended to. A bit of caution should be exercised when you are capturing output from that task, because this could lead to something unexpected:

    • when capturing in a property you will find in it only the output from the first call, because Ant properties are immutable and once set they cannot be changed,
    • when capturing in a file, each run will overwrite it and you will find in it only the last call output, unless you are using the append="true" attribute, in which case you will see the output of each task call appended to the file.
    The JMX Proxy Servlet is a lightweight proxy to get and set the tomcat internals. (Or any class that has been exposed via an MBean) Its usage is not very user friendly but the UI is extremely help for integrating command line scripts for monitoring and changing the internals of tomcat. You can do two things with the proxy: get information and set information. For you to really understand the JMX Proxy Servlet, you should have a general understanding of JMX. If you don't know what JMX is, then prepare to be confused. This takes the form: http://webserver/manager/jmxproxy/?qry=STUFF Where STUFF is the JMX query you wish to perform. For example, here are some queries you might wish to run:
    • qry=*%3Atype%3DRequestProcessor%2C* --> type=RequestProcessor which will locate all workers which can process requests and report their state.
    • qry=*%3Aj2eeType=Servlet%2c* --> j2eeType=Servlet which return all loaded servlets.
    • qry=Catalina%3Atype%3DEnvironment%2Cresourcetype%3DGlobal%2Cname%3DsimpleValue --> Catalina:type=Environment,resourcetype=Global,name=simpleValue which look for a specific MBean by the given name.
    You'll need to experiment with this to really understand its capabilites. If you provide no qry parameter, then all of the MBeans will be displayed. We really recommend looking at the tomcat source code and understand the JMX spec to get a better understanding of all the queries you may run.
    The JXMProxyServlet also supports a "get" command that you can use to fetch the value of a specific MBean's attribute. The general form of the get command is: http://webserver/manager/jmxproxy/?get=BEANNAME&att=MYATTRIBUTE&key=MYKEY You must provide the following parameters:
    1. get: The full bean name
    2. att: The attribute you wish to fetch
    3. key: (optional) The key into a CompositeData MBean attribute
    If all goes well, then it will say OK, otherwise an error message will be shown. For example, let's say we wish to fetch the current heap memory data: http://webserver/manager/jmxproxy/?get=java.lang:type=Memory&att=HeapMemoryUsage Or, if you only want the "used" key: http://webserver/manager/jmxproxy/ ?get=java.lang:type=Memory&att=HeapMemoryUsage&key=used
    Now that you can query an MBean, its time to muck with Tomcat's internals! The general form of the set command is : http://webserver/manager/jmxproxy/?set=BEANNAME&att=MYATTRIBUTE&val=NEWVALUE So you need to provide 3 request parameters:
    1. set: The full bean name
    2. att: The attribute you wish to alter
    3. val: The new value
    If all goes ok, then it will say OK, otherwise an error message will be shown. For example, lets say we wish to turn up debugging on the fly for the ErrorReportValve. The following will set debugging to 10. http://localhost:8080/manager/jmxproxy/ ?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost &att=debug&val=10 and my result is (YMMV): Result: ok Here is what I see if I pass in a bad value. Here is the URL I used, I try set debugging equal to 'cow': http://localhost:8080/manager/jmxproxy/ ?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost &att=debug&val=cow When I try that, my result is Error: java.lang.NumberFormatException: For input string: "cow"

    The invoke command enables methods to be called on MBeans. The general form of the command is:

    http://webserver/manager/jmxproxy/ ?invoke=BEANNAME&op=METHODNAME&ps=COMMASEPARATEDPARAMETERS

    For example, to call the findConnectors() method of the Service use:

    http://localhost:8080/manager/jmxproxy/ ?invoke=Catalina%3Atype%3DService&op=findConnectors&ps=
    tomcat7-7.0.52/webapps/docs/html-manager-howto.xml0000644000175100017510000005405212271304167022001 0ustar locutuslocutus ]> &project; Glenn L. Nielsen Tomcat Web Application Manager How To

    In many production environments it is very useful to have the capability to manage your web applications without having to shut down and restart Tomcat. This document is for the HTML web interface to the web application manager.

    The interface is divided into six sections:

    • Message - Displays success and failure messages.
    • Manager - General manager operations like list and help.
    • Applications - List of web applications and commands.
    • Deploy - Deploying web applications.
    • Diagnostics - Identifying potential problems.
    • Server Information - Information about the Tomcat server.

    Displays information about the success or failure of the last web application manager command you performed. If it succeeded OK is displayed and may be followed by a success message. If it failed FAIL is displayed followed by an error message. Common failure messages are documented below for each command. The complete list of failure messages for each command can be found in the manager web application documentation.

    The Manager section has three links:

    • List Applications - Redisplay a list of web applications.
    • HTML Manager Help - A link to this document.
    • Manager Help - A link to the comprehensive Manager App HOW TO.

    The Applications section lists information about all the installed web applications and provides links for managing them. For each web application the following is displayed:

    • Path - The web application context path.
    • Display Name - The display name for the web application if it has one configured in its "web.xml" file.
    • Running - Whether the web application is running and available (true), or not running and unavailable (false).
    • Sessions - The number of active sessions for remote users of this web application. The number of sessions is a link which when submitted displays more details about session usage by the web application in the Message box.
    • Commands - Lists all commands which can be performed on the web application. Only those commands which can be performed will be listed as a link which can be submitted. No commands can be performed on the manager web application itself. The following commands can be performed:
      • Start - Start a web application which had been stopped.
      • Stop - Stop a web application which is currently running and make it unavailable.
      • Reload - Reload the web application so that new ".jar" files in /WEB-INF/lib/ or new classes in /WEB-INF/classes/ can be used.
      • Undeploy - Stop and then remove this web application from the server.

    Signal a stopped application to restart, and make itself available again. Stopping and starting is useful, for example, if the database required by your application becomes temporarily unavailable. It is usually better to stop the web application that relies on this database rather than letting users continuously encounter database exceptions.

    If this command succeeds, you will see a Message like this:

    OK - Started application at context path /examples

    Otherwise, the Message will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to start the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character, unless you are referencing the ROOT web application -- in which case the context path must be a zero-length string.

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.

    Signal an existing application to make itself unavailable, but leave it deployed. Any request that comes in while an application is stopped will see an HTTP error 404, and this application will show as "stopped" on a list applications command.

    If this command succeeds, you will see a Message like this:

    OK - Stopped application at context path /examples

    Otherwise, the Message will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to stop the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character, unless you are referencing the ROOT web application -- in which case the context path must be a zero-length string.

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.

    Signal an existing application to shut itself down and reload. This can be useful when the web application context is not reloadable and you have updated classes or property files in the /WEB-INF/classes directory or when you have added or updated jar files in the /WEB-INF/lib directory.

    NOTE: The /WEB-INF/web.xml web application configuration file is not checked on a reload; the previous web.xml configuration is used. If you have made changes to your web.xml file you must stop then start the web application.

    If this command succeeds, you will see a Message like this:

    OK - Reloaded application at context path /examples

    Otherwise, the Message will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to restart the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character, unless you are referencing the ROOT web application -- in which case the context path must be a zero-length string.

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.
    • Reload not supported on WAR deployed at path /foo
      Currently, application reloading (to pick up changes to the classes or web.xml file) is not supported when a web application is installed directly from a WAR file, which happens when the host is configured to not unpack WAR files. As it only works when the web application is installed from an unpacked directory, if you are using a WAR file, you should undeploy and then deploy the application again to pick up your changes.

    WARNING - This command will delete the contents of the web application directory and/or ".war" file if it exists within the appBase directory (typically "webapps") for this virtual host . The web application temporary work directory is also deleted. If you simply want to take an application out of service, you should use the /stop command instead.

    Signal an existing application to gracefully shut itself down, and then remove it from Tomcat (which also makes this context path available for reuse later). This command is the logical opposite of the /deploy Ant command, and the related deploy features available in the HTML manager.

    If this command succeeds, you will see a Message like this:

    OK - Undeployed application at context path /examples

    Otherwise, the Message will start with FAIL and include an error message. Possible causes for problems include:

    • Encountered exception

      An exception was encountered trying to undeploy the web application. Check the Tomcat logs for the details.

    • Invalid context path was specified

      The context path must start with a slash character, unless you are referencing the ROOT web application -- in which case the context path must be a zero-length string.

    • No context exists for path /foo

      There is no deployed application on the context path that you specified.

    • No context path was specified
      The path parameter is required.

    Web applications can be deployed using files or directories located on the Tomcat server or you can upload a web application archive (WAR) file to the server.

    To install an application, fill in the appropriate fields for the type of install you want to do and then submit it using the Install button.

    Deploy and start a new web application, attached to the specified Context Path: (which must not be in use by any other web application). This command is the logical opposite of the Undeploy command.

    There are a number of different ways the deploy command can be used.

    Deploy a Directory or WAR by URL

    Install a web application directory or ".war" file located on the Tomcat server. If no Context Path is specified, the directory name or the war file name without the ".war" extension is used as the path. The WAR or Directory URL specifies a URL (including the file: scheme) for either a directory or a web application archive (WAR) file. The supported syntax for a URL referring to a WAR file is described on the Javadocs page for the java.net.JarURLConnection class. Use only URLs that refer to the entire WAR file.

    In this example the web application located in the directory C:\path\to\foo on the Tomcat server (running on Windows) is deployed as the web application context named /footoo.

    Context Path: /footoo WAR or Directory URL: file:C:/path/to/foo

    In this example the ".war" file /path/to/bar.war on the Tomcat server (running on Unix) is deployed as the web application context named /bar. Notice that there is no path parameter so the context path defaults to the name of the web application archive file without the ".war" extension.

    WAR or Directory URL: jar:file:/path/to/bar.war!/

    Deploy a Directory or War from the Host appBase

    Install a web application directory or ".war" file located in your Host appBase directory. If no Context Path is specified the directory name or the war file name without the ".war" extension is used as the path.

    In this example the web application located in a subdirectory named foo in the Host appBase directory of the Tomcat server is deployed as the web application context named /foo. Notice that there is no path parameter so the context path defaults to the name of the web application directory.

    WAR or Directory URL: foo

    In this example the ".war" file bar.war located in your Host appBase directory on the Tomcat server is deployed as the web application context named /bartoo.

    Context Path: /bartoo WAR or Directory URL: bar.war

    Deploy using a Context configuration ".xml" file

    If the Host deployXML flag is set to true, you can install a web application using a Context configuration ".xml" file and an optional ".war" file or web application directory. The Context Path is not used when installing a web application using a context ".xml" configuration file.

    A Context configuration ".xml" file can contain valid XML for a web application Context just as if it were configured in your Tomcat server.xml configuration file. Here is an example for Tomcat running on Windows:

    <Context path="/foobar" docBase="C:\path\to\application\foobar"> </Context>

    Use of the WAR or Directory URL is optional. When used to select a web application ".war" file or directory it overrides any docBase configured in the context configuration ".xml" file.

    Here is an example of installing an application using a Context configuration ".xml" file for Tomcat running on Windows.

    XML Configuration file URL: file:C:/path/to/context.xml

    Here is an example of installing an application using a Context configuration ".xml" file and a web application ".war" file located on the server (Tomcat running on Unix).

    XML Configuration file URL: file:/path/to/context.xml WAR or Directory URL: jar:file:/path/to/bar.war!/

    Upload a WAR file from your local system and install it into the appBase for your Host. The name of the WAR file without the ".war" extension is used as the context path name.

    Use the Browse button to select a WAR file to upload to the server from your local desktop system.

    The .WAR file may include Tomcat specific deployment configuration, by including a Context configuration XML file in /META-INF/context.xml.

    Upload of a WAR file could fail for the following reasons:

    • File uploaded must be a .war

      The upload install will only accept files which have the filename extension of ".war".

    • War file already exists on server

      If a war file of the same name already exists in your Host's appBase the upload will fail. Either undeploy the existing war file from your Host's appBase or upload the new war file using a different name.

    • File upload failed, no file

      The file upload failed, no file was received by the server.

    • Install Upload Failed, Exception:

      The war file upload or install failed with a Java Exception. The exception message will be listed.

    If the Host is configured with unpackWARs=true and you install a war file, the war will be unpacked into a directory in your Host appBase directory.

    If the application war or directory is deployed in your Host appBase directory and either the Host is configured with autoDeploy=true the Context path must match the directory name or war file name without the ".war" extension.

    For security when untrusted users can manage web applications, the Host deployXML flag can be set to false. This prevents untrusted users from installing web applications using a configuration XML file and also prevents them from installing application directories or ".war" files located outside of their Host appBase.

    If deployment and startup is successful, you will receive a Message like this:

    OK - Deployed application at context path /foo

    Otherwise, the Message will start with FAIL and include an error message. Possible causes for problems include:

    • Application already exists at path /foo

      The context paths for all currently running web applications must be unique. Therefore, you must either undeploy the existing web application using this context path, or choose a different context path for the new one.

    • Document base does not exist or is not a readable directory

      The URL specified by the WAR or Directory URL: field must identify a directory on this server that contains the "unpacked" version of a web application, or the absolute URL of a web application archive (WAR) file that contains this application. Correct the value entered for the WAR or Directory URL: field.

    • Encountered exception

      An exception was encountered trying to start the new web application. Check the Tomcat logs for the details, but likely explanations include problems parsing your /WEB-INF/web.xml file, or missing classes encountered when initializing application event listeners and filters.

    • Invalid application URL was specified

      The URL for the WAR or Directory URL: field that you specified was not valid. Such URLs must start with file:, and URLs for a WAR file must end in ".war".

    • Invalid context path was specified

      The context path must start with a slash character, unless you are referencing the ROOT web application -- in which case the context path must be a "/" string.

    • Context path must match the directory or WAR file name:
      If the application war or directory is deployed in your Host appBase directory and either the Host is configured with autoDeploy=true the Context path must match the directory name or war file name without the ".war" extension.
    • Only web applications in the Host web application directory can be deployed
      If the Host deployXML flag is set to false this error will happen if an attempt is made to install a web application directory or ".war" file outside of the Host appBase directory.

    The find leaks diagnostic triggers a full garbage collection. It should be used with extreme caution on production systems.

    The find leaks diagnostic attempts to identify web applications that have caused memory leaks when they were stopped, reloaded or undeployed. Results should always be confirmed with a profiler. The diagnostic uses additional functionality provided by the StandardHost implementation. It will not work if a custom host is used that does not extend StandardHost.

    This diagnostic will list context paths for the web applications that were stopped, reloaded or undeployed, but which classes from the previous runs are still present in memory, thus being a memory leak. If an application has been reloaded several times, it may be listed several times.

    Explicitly triggering a full garbage collection from Java code is documented to be unreliable. Furthermore, depending on the JVM used, there are options to disable explicit GC triggering, like -XX:+DisableExplicitGC. If you want to make sure, that the diagnostics were successfully running a full GC, you will need to check using tools like GC logging, JConsole or similar.

    This section displays information about Tomcat, the operating system of the server Tomcat is hosted on, and the Java Virtual Machine Tomcat is running in.

    tomcat7-7.0.52/webapps/docs/cluster-howto.xml0000644000175100017510000011203612271304167021103 0ustar locutuslocutus ]> &project; Filip Hanik Peter Rossbach Clustering/Session Replication HOW-TO

    You can also check the configuration reference documentation.

    Simply add <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> to your <Engine> or your <Host> element to enable clustering.

    Using the above configuration will enable all-to-all session replication using the DeltaManager to replicate session deltas. By all-to-all we mean that the session gets replicated to all the other nodes in the cluster. This works great for smaller cluster but we don't recommend it for larger clusters(a lot of Tomcat nodes). Also when using the delta manager it will replicate to all nodes, even nodes that don't have the application deployed.
    To get around this problem, you'll want to use the BackupManager. This manager only replicates the session data to one backup node, and only to nodes that have the application deployed. Downside of the BackupManager: not quite as battle tested as the delta manager.
    Here are some of the important default values:
    1. Multicast address is 228.0.0.4
    2. Multicast port is 45564 (the port and the address together determine cluster membership.
    3. The IP broadcasted is java.net.InetAddress.getLocalHost().getHostAddress() (make sure you don't broadcast 127.0.0.1, this is a common error)
    4. The TCP port listening for replication messages is the first available server socket in range 4000-4100
    5. Two listeners are configured ClusterSessionListener and JvmRouteSessionIDBinderListener
    6. Two interceptors are configured TcpFailureDetector and MessageDispatch15Interceptor
    The following is the default cluster configuration:
    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8"> <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="4000" autoBind="100" selectorTimeout="5000" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/> <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>

    Will cover this section in more detail later in this document.

    To run session replication in your Tomcat 7.0 container, the following steps should be completed:

    • All your session attributes must implement java.io.Serializable
    • Uncomment the Cluster element in server.xml
    • If you have defined custom cluster valves, make sure you have the ReplicationValve defined as well under the Cluster element in server.xml
    • If your Tomcat instances are running on the same machine, make sure the tcpListenPort attribute is unique for each instance, in most cases Tomcat is smart enough to resolve this on it's own by autodetecting available ports in the range 4000-4100
    • Make sure your web.xml has the <distributable/> element
    • If you are using mod_jk, make sure that jvmRoute attribute is set at your Engine <Engine name="Catalina" jvmRoute="node01" > and that the jvmRoute attribute value matches your worker name in workers.properties
    • Make sure that all nodes have the same time and sync with NTP service!
    • Make sure that your loadbalancer is configured for sticky session mode.

    Load balancing can be achieved through many techniques, as seen in the Load Balancing chapter.

    Note: Remember that your session state is tracked by a cookie, so your URL must look the same from the out side otherwise, a new session will be created.

    Note: Clustering support currently requires the JDK version 1.5 or later.

    The Cluster module uses the Tomcat JULI logging framework, so you can configure logging through the regular logging.properties file. To track messages, you can enable logging on the key:org.apache.catalina.tribes.MESSAGES

    To enable session replication in Tomcat, three different paths can be followed to achieve the exact same thing:

    1. Using session persistence, and saving the session to a shared file system (PersistenceManager + FileStore)
    2. Using session persistence, and saving the session to a shared database (PersistenceManager + JDBCStore)
    3. Using in-memory-replication, using the SimpleTcpCluster that ships with Tomcat (lib/catalina-tribes.jar + lib/catalina-ha.jar)

    In this release of session replication, Tomcat can perform an all-to-all replication of session state using the DeltaManager or perform backup replication to only one node using the BackupManager. The all-to-all replication is an algorithm that is only efficient when the clusters are small. For larger clusters, to use a primary-secondary session replication where the session will only be stored at one backup server simply setup the BackupManager.
    Currently you can use the domain worker attribute (mod_jk > 1.2.8) to build cluster partitions with the potential of having a more scalable cluster solution with the DeltaManager(you'll need to configure the domain interceptor for this). In order to keep the network traffic down in an all-to-all environment, you can split your cluster into smaller groups. This can be easily achieved by using different multicast addresses for the different groups. A very simple setup would look like this:

    DNS Round Robin | Load Balancer / \ Cluster1 Cluster2 / \ / \ Tomcat1 Tomcat2 Tomcat3 Tomcat4

    What is important to mention here, is that session replication is only the beginning of clustering. Another popular concept used to implement clusters is farming, i.e., you deploy your apps only to one server, and the cluster will distribute the deployments across the entire cluster. This is all capabilities that can go into with the FarmWarDeployer (s. cluster example at server.xml)

    In the next section will go deeper into how session replication works and how to configure it.

    Membership is established using multicast heartbeats. Hence, if you wish to subdivide your clusters, you can do this by changing the multicast IP address or port in the <Membership> element.

    The heartbeat contains the IP address of the Tomcat node and the TCP port that Tomcat listens to for replication traffic. All data communication happens over TCP.

    The ReplicationValve is used to find out when the request has been completed and initiate the replication, if any. Data is only replicated if the session has changed (by calling setAttribute or removeAttribute on the session).

    One of the most important performance considerations is the synchronous versus asynchronous replication. In a synchronous replication mode the request doesn't return until the replicated session has been sent over the wire and reinstantiated on all the other cluster nodes. Synchronous vs. asynchronous is configured using the channelSendOptions flag and is an integer value. The default value for the SimpleTcpCluster/DeltaManager combo is 8, which is asynchronous. You can read more on the send flag(overview) or the send flag(javadoc). During async replication, the request is returned before the data has been replicated. async replication yields shorter request times, and synchronous replication guarantees the session to be replicated before the request returns.

    If you are using mod_jk and not using sticky sessions or for some reasons sticky session don't work, or you are simply failing over, the session id will need to be modified as it previously contained the worker id of the previous tomcat (as defined by jvmRoute in the Engine element). To solve this, we will use the JvmRouteBinderValve.

    The JvmRouteBinderValve rewrites the session id to ensure that the next request will remain sticky (and not fall back to go to random nodes since the worker is no longer available) after a fail over. The valve rewrites the JSESSIONID value in the cookie with the same name. Not having this valve in place, will make it harder to ensure stickiness in case of a failure for the mod_jk module.

    By default, if no valves are configured, the JvmRouteBinderValve is added on. The cluster message listener called JvmRouteSessionIDBinderListener is also defined by default and is used to actually rewrite the session id on the other nodes in the cluster once a fail over has occurred. Remember, if you are adding your own valves or cluster listeners in server.xml then the defaults are no longer valid, make sure that you add in all the appropriate valves and listeners as defined by the default.

    Hint:
    With attribute sessionIdAttribute you can change the request attribute name that included the old session id. Default attribute name is org.apache.catalina.ha.session.JvmRouteOrignalSessionID.

    Trick:
    You can enable this mod_jk turnover mode via JMX before you drop a node to all backup nodes! Set enable true on all JvmRouteBinderValve backups, disable worker at mod_jk and then drop node and restart it! Then enable mod_jk Worker and disable JvmRouteBinderValves again. This use case means that only requested session are migrated.

    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6"> <Manager className="org.apache.catalina.ha.session.BackupManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" mapSendOptions="6"/> <!-- <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> --> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="5000" selectorTimeout="100" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/> <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>

    Break it down!!

    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6">

    The main element, inside this element all cluster details can be configured. The channelSendOptions is the flag that is attached to each message sent by the SimpleTcpCluster class or any objects that are invoking the SimpleTcpCluster.send method. The description of the send flags is available at our javadoc site The DeltaManager sends information using the SimpleTcpCluster.send method, while the backup manager sends it itself directly through the channel.
    For more info, Please visit the reference documentation

    <Manager className="org.apache.catalina.ha.session.BackupManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true" mapSendOptions="6"/> <!-- <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> -->

    This is a template for the manager configuration that will be used if no manager is defined in the <Context> element. In Tomcat 5.x each webapp marked distributable had to use the same manager, this is no longer the case since Tomcat you can define a manager class for each webapp, so that you can mix managers in your cluster. Obviously the managers on one node's application has to correspond with the same manager on the same application on the other node. If no manager has been specified for the webapp, and the webapp is marked <distributable/> Tomcat will take this manager configuration and create a manager instance cloning this configuration.
    For more info, Please visit the reference documentation

    <Channel className="org.apache.catalina.tribes.group.GroupChannel">

    The channel element is Tribes, the group communication framework used inside Tomcat. This element encapsulates everything that has to do with communication and membership logic.
    For more info, Please visit the reference documentation

    <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/>

    Membership is done using multicasting. Please note that Tribes also supports static memberships using the StaticMembershipInterceptor if you want to extend your membership to points beyond multicasting. The address attribute is the multicast address used and the port is the multicast port. These two together create the cluster separation. If you want a QA cluster and a production cluster, the easiest config is to have the QA cluster be on a separate multicast address/port combination than the production cluster.
    The membership component broadcasts TCP address/port of itself to the other nodes so that communication between nodes can be done over TCP. Please note that the address being broadcasted is the one of the Receiver.address attribute.
    For more info, Please visit the reference documentation

    <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="5000" selectorTimeout="100" maxThreads="6"/>

    In tribes the logic of sending and receiving data has been broken into two functional components. The Receiver, as the name suggests is responsible for receiving messages. Since the Tribes stack is thread less, (a popular improvement now adopted by other frameworks as well), there is a thread pool in this component that has a maxThreads and minThreads setting.
    The address attribute is the host address that will be broadcasted by the membership component to the other nodes.
    For more info, Please visit the reference documentation

    <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender>

    The sender component, as the name indicates is responsible for sending messages to other nodes. The sender has a shell component, the ReplicationTransmitter but the real stuff done is done in the sub component, Transport. Tribes support having a pool of senders, so that messages can be sent in parallel and if using the NIO sender, you can send messages concurrently as well.
    Concurrently means one message to multiple senders at the same time and Parallel means multiple messages to multiple senders at the same time.
    For more info, Please visit the reference documentation

    <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/> </Channel>

    Tribes uses a stack to send messages through. Each element in the stack is called an interceptor, and works much like the valves do in the Tomcat servlet container. Using interceptors, logic can be broken into more manageable pieces of code. The interceptors configured above are:
    TcpFailureDetector - verifies crashed members through TCP, if multicast packets get dropped, this interceptor protects against false positives, ie the node marked as crashed even though it still is alive and running.
    MessageDispatch15Interceptor - dispatches messages to a thread (thread pool) to send message asynchrously.
    ThroughputInterceptor - prints out simple stats on message traffic.
    Please note that the order of interceptors is important. the way they are defined in server.xml is the way they are represented in the channel stack. Think of it as a linked list, with the head being the first most interceptor and the tail the last.
    For more info, Please visit the reference documentation

    <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt"/>

    The cluster uses valves to track requests to web applications, we've mentioned the ReplicationValve and the JvmRouteBinderValve above. The <Cluster> element itself is not part of the pipeline in Tomcat, instead the cluster adds the valve to its parent container. If the <Cluster> elements is configured in the <Engine> element, the valves get added to the engine and so on.
    For more info, Please visit the reference documentation

    <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer" tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/" watchDir="/tmp/war-listen/" watchEnabled="false"/>

    The default tomcat cluster supports farmed deployment, ie, the cluster can deploy and undeploy applications on the other nodes. The state of this component is currently in flux but will be addressed soon. There was a change in the deployment algorithm between Tomcat 5.0 and 5.5 and at that point, the logic of this component changed to where the deploy dir has to match the webapps directory.
    For more info, Please visit the reference documentation

    <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>

    Since the SimpleTcpCluster itself is a sender and receiver of the Channel object, components can register themselves as listeners to the SimpleTcpCluster. The listener above ClusterSessionListener listens for DeltaManager replication messages and applies the deltas to the manager that in turn applies it to the session.
    For more info, Please visit the reference documentation

    Component Levels: Server | Service | Engine | \ | --- Cluster --* | Host | ------ / \ Cluster Context(1-N) | \ | -- Manager | \ | -- DeltaManager | -- BackupManager | --------------------------- | \ Channel \ ----------------------------- \ | \ Interceptor_1 .. \ | \ Interceptor_N \ ----------------------------- \ | | | \ Receiver Sender Membership \ -- Valve | \ | -- ReplicationValve | -- JvmRouteBinderValve | -- LifecycleListener | -- ClusterListener | \ | -- ClusterSessionListener | -- JvmRouteSessionIDBinderListener | -- Deployer \ -- FarmWarDeployer

    To make it easy to understand how clustering works, We are gonna take you through a series of scenarios. In the scenario we only plan to use two tomcat instances TomcatA and TomcatB. We will cover the following sequence of events:

    1. TomcatA starts up
    2. TomcatB starts up (Wait that TomcatA start is complete)
    3. TomcatA receives a request, a session S1 is created.
    4. TomcatA crashes
    5. TomcatB receives a request for session S1
    6. TomcatA starts up
    7. TomcatA receives a request, invalidate is called on the session (S1)
    8. TomcatB receives a request, for a new session (S2)
    9. TomcatA The session S2 expires due to inactivity.

    Ok, now that we have a good sequence, we will take you through exactly what happens in the session repliction code

    1. TomcatA starts up

      Tomcat starts up using the standard start up sequence. When the Host object is created, a cluster object is associated with it. When the contexts are parsed, if the distributable element is in place in web.xml Tomcat asks the Cluster class (in this case SimpleTcpCluster) to create a manager for the replicated context. So with clustering enabled, distributable set in web.xml Tomcat will create a DeltaManager for that context instead of a StandardManager. The cluster class will start up a membership service (multicast) and a replication service (tcp unicast). More on the architecture further down in this document.

    2. TomcatB starts up

      When TomcatB starts up, it follows the same sequence as TomcatA did with one exception. The cluster is started and will establish a membership (TomcatA,TomcatB). TomcatB will now request the session state from a server that already exists in the cluster, in this case TomcatA. TomcatA responds to the request, and before TomcatB starts listening for HTTP requests, the state has been transferred from TomcatA to TomcatB. In case TomcatA doesn't respond, TomcatB will time out after 60 seconds, and issue a log entry. The session state gets transferred for each web application that has distributable in its web.xml. Note: To use session replication efficiently, all your tomcat instances should be configured the same.

    3. TomcatA receives a request, a session S1 is created.

      The request coming in to TomcatA is treated exactly the same way as without session replication. The action happens when the request is completed, the ReplicationValve will intercept the request before the response is returned to the user. At this point it finds that the session has been modified, and it uses TCP to replicata the session to TomcatB. Once the serialized data has been handed off to the operating systems TCP logic, the request returns to the user, back through the valve pipeline. For each request the entire session is replicated, this allows code that modifies attributes in the session without calling setAttribute or removeAttribute to be replicated. a useDirtyFlag configuration parameter can be used to optimize the number of times a session is replicated.

    4. TomcatA crashes

      When TomcatA crashes, TomcatB receives a notification that TomcatA has dropped out of the cluster. TomcatB removes TomcatA from its membership list, and TomcatA will no longer be notified of any changes that occurs in TomcatB. The load balancer will redirect the requests from TomcatA to TomcatB and all the sessions are current.

    5. TomcatB receives a request for session S1

      Nothing exciting, TomcatB will process the request as any other request.

    6. TomcatA starts up

      Upon start up, before TomcatA starts taking new request and making itself available to it will follow the start up sequence described above 1) 2). It will join the cluster, contact TomcatB for the current state of all the sessions. And once it receives the session state, it finishes loading and opens its HTTP/mod_jk ports. So no requests will make it to TomcatA until it has received the session state from TomcatB.

    7. TomcatA receives a request, invalidate is called on the session (S1)

      The invalidate call is intercepted, and the session is queued with invalidated sessions. When the request is complete, instead of sending out the session that has changed, it sends out an "expire" message to TomcatB and TomcatB will invalidate the session as well.

    8. TomcatB receives a request, for a new session (S2)

      Same scenario as in step 3)

    9. TomcatA The session S2 expires due to inactivity.

      The invalidate call is intercepted the same was as when a session is invalidated by the user, and the session is queued with invalidated sessions. At this point, the invalidated session will not be replicated across until another request comes through the system and checks the invalid queue.

    Phuuuhh! :)

    Membership Clustering membership is established using very simple multicast pings. Each Tomcat instance will periodically send out a multicast ping, in the ping message the instance will broad cast its IP and TCP listen port for replication. If an instance has not received such a ping within a given timeframe, the member is considered dead. Very simple, and very effective! Of course, you need to enable multicasting on your system.

    TCP Replication Once a multicast ping has been received, the member is added to the cluster Upon the next replication request, the sending instance will use the host and port info and establish a TCP socket. Using this socket it sends over the serialized data. The reason I choose TCP sockets is because it has built in flow control and guaranteed delivery. So I know, when I send some data, it will make it there :)

    Distributed locking and pages using frames Tomcat does not keep session instances in sync across the cluster. The implementation of such logic would be to much overhead and cause all kinds of problems. If your client accesses the same session simultanously using multiple requests, then the last request will override the other sessions in the cluster.

    Monitoring is a very important question when you use a cluster. Some of the cluster objects are JMX MBeans

    Add the following parameter to your startup script with Java 5: set CATALINA_OPTS=\ -Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.port=%my.jmx.port% \ -Dcom.sun.management.jmxremote.ssl=false \ -Dcom.sun.management.jmxremote.authenticate=false

    List of Cluster Mbeans
    Name Description MBean ObjectName - Engine MBean ObjectName - Host
    Cluster The complete cluster element type=Cluster type=Cluster,host=${HOST}
    DeltaManager This manager control the sessions and handle session replication type=Manager,context=${APP.CONTEXT.PATH}, host=${HOST} type=Manager,context=${APP.CONTEXT.PATH}, host=${HOST}
    FarmWarDeployer Manages the process of deploying an application to all nodes in the cluster Not supported type=Cluster, host=${HOST}, component=deployer
    Member Represents a node in the cluster type=Cluster, component=member, name=${NODE_NAME} type=Cluster, host=${HOST}, component=member, name=${NODE_NAME}
    ReplicationValve This valve control the replication to the backup nodes type=Valve,name=ReplicationValve type=Valve,name=ReplicationValve,host=${HOST}
    JvmRouteBinderValve This is a cluster fallback valve to change the Session ID to the current tomcat jvmroute. type=Valve,name=JvmRouteBinderValve, context=${APP.CONTEXT.PATH} type=Valve,name=JvmRouteBinderValve,host=${HOST}, context=${APP.CONTEXT.PATH}

    Please see the clustering section of the FAQ.

    tomcat7-7.0.52/webapps/docs/maven-jars.xml0000644000175100017510000000374711656647746020362 0ustar locutuslocutus ]> &project; Filip Hanik Apache Tomcat - Using Tomcat libraries with Maven
    Tomcat snapshots are located in the Apache Snapshot Repository. The official URL is http://people.apache.org/repo/m2-snapshot-repository/org/apache/tomcat/ Snapshots are done periodically, not on a regular basis, but when changes happen and the Tomcat team deems a new snapshot might useful. Stable releases are published to the Central Maven Repositories. The URL for this is http://repo2.maven.org/maven2/org/apache/tomcat/
    tomcat7-7.0.52/webapps/docs/project.xml0000644000175100017510000001170212271304167017730 0ustar locutuslocutus Apache Tomcat 7 The Apache Tomcat Servlet/JSP Container tomcat7-7.0.52/webapps/docs/jndi-datasource-examples-howto.xml0000644000175100017510000006300612271304167024314 0ustar locutuslocutus ]> &project; Les Hughes David Haraburda Glenn Nielsen Yoav Shapira JNDI Datasource HOW-TO

    JNDI Datasource configuration is covered extensively in the JNDI-Resources-HOWTO. However, feedback from tomcat-user has shown that specifics for individual configurations can be rather tricky.

    Here then are some example configurations that have been posted to tomcat-user for popular databases and some general tips for db usage.

    You should be aware that since these notes are derived from configuration and/or feedback posted to tomcat-user YMMV :-). Please let us know if you have any other tested configurations that you feel may be of use to the wider audience, or if you feel we can improve this section in anyway.

    Please note that JNDI resource configuration changed somewhat between Tomcat 5.0.x and Tomcat 5.5.x. You will most likely need to modify older JNDI resource configurations to match the syntax in the example below in order to make them work in Tomcat 7.x.x.

    Also, please note that JNDI DataSource configuration in general, and this tutorial in particular, assumes that you have read and understood the Context and Host configuration references, including the section about Automatic Application Deployment in the latter reference.

    java.sql.DriverManager supports the service provider mechanism. This feature is that all the available JDBC drivers that announce themselves by providing a META-INF/services/java.sql.Driver file are automatically discovered, loaded and registered, relieving you from the need to load the database driver explicitly before you create a JDBC connection. However, the implementation is fundamentally broken in all Java versions for a servlet container environment. The problem is that java.sql.DriverManager will scan for the drivers only once.

    The JRE Memory Leak Prevention Listener that is included with Apache Tomcat solves this by triggering the drivers scan during Tomcat startup. This is enabled by default. It means that only libraries visible to the listener such as the ones in $CATALINA_BASE/lib will be scanned for database drivers. If you are considering disabling this feature, note that the scan would be triggered by the first web application that is using JDBC, leading to failures when this web application is reloaded and for other web applications that rely on this feature.

    Thus, the web applications that have database drivers in their WEB-INF/lib directory cannot rely on the service provider mechanism and should register the drivers explicitly.

    The list of drivers in java.sql.DriverManager is also a known source of memory leaks. Any Drivers registered by a web application must be deregistered when the web application stops. Tomcat will attempt to automatically discover and deregister any JDBC drivers loaded by the web application class loader when the web application stops. However, it is expected that applications do this for themselves via a ServletContextListener.

    The default database connection pool implementation in Apache Tomcat relies on the libraries from the Apache Commons project. The following libraries are used:

    • Commons DBCP
    • Commons Pool

    These libraries are located in a single JAR at $CATALINA_HOME/lib/tomcat-dbcp.jar. However, only the classes needed for connection pooling have been included, and the packages have been renamed to avoid interfering with applications.

    DBCP 1.4 provides support for JDBC 4.0.

    See the DBCP documentation for a complete list of configuration parameters.

    A database connection pool creates and manages a pool of connections to a database. Recycling and reusing already existing connections to a database is more efficient than opening a new connection.

    There is one problem with connection pooling. A web application has to explicitly close ResultSet's, Statement's, and Connection's. Failure of a web application to close these resources can result in them never being available again for reuse, a database connection pool "leak". This can eventually result in your web application database connections failing if there are no more available connections.

    There is a solution to this problem. The Apache Commons DBCP can be configured to track and recover these abandoned database connections. Not only can it recover them, but also generate a stack trace for the code which opened these resources and never closed them.

    To configure a DBCP DataSource so that abandoned database connections are removed and recycled add the following attribute to the Resource configuration for your DBCP DataSource:

    removeAbandoned="true"

    When available database connections run low DBCP will recover and recycle any abandoned database connections it finds. The default is false.

    Use the removeAbandonedTimeout attribute to set the number of seconds a database connection has been idle before it is considered abandoned.

    removeAbandonedTimeout="60"

    The default timeout for removing abandoned connections is 300 seconds.

    The logAbandoned attribute can be set to true if you want DBCP to log a stack trace of the code which abandoned the database connection resources.

    logAbandoned="true"

    The default is false.

    0. Introduction

    Versions of MySQL and JDBC drivers that have been reported to work:

    • MySQL 3.23.47, MySQL 3.23.47 using InnoDB,, MySQL 3.23.58, MySQL 4.0.1alpha
    • Connector/J 3.0.11-stable (the official JDBC Driver)
    • mm.mysql 2.0.14 (an old 3rd party JDBC Driver)

    Before you proceed, don't forget to copy the JDBC Driver's jar into $CATALINA_HOME/lib.

    1. MySQL configuration

    Ensure that you follow these instructions as variations can cause problems.

    Create a new test user, a new database and a single test table. Your MySQL user must have a password assigned. The driver will fail if you try to connect with an empty password.

    mysql> GRANT ALL PRIVILEGES ON *.* TO javauser@localhost -> IDENTIFIED BY 'javadude' WITH GRANT OPTION; mysql> create database javatest; mysql> use javatest; mysql> create table testdata ( -> id int not null auto_increment primary key, -> foo varchar(25), -> bar int);
    Note: the above user should be removed once testing is complete!

    Next insert some test data into the testdata table.

    mysql> insert into testdata values(null, 'hello', 12345); Query OK, 1 row affected (0.00 sec) mysql> select * from testdata; +----+-------+-------+ | ID | FOO | BAR | +----+-------+-------+ | 1 | hello | 12345 | +----+-------+-------+ 1 row in set (0.00 sec) mysql>

    2. Context configuration

    Configure the JNDI DataSource in Tomcat by adding a declaration for your resource to your Context.

    For example:

    <Context> <!-- maxActive: Maximum number of database connections in pool. Make sure you configure your mysqld max_connections large enough to handle all of your db connections. Set to -1 for no limit. --> <!-- maxIdle: Maximum number of idle database connections to retain in pool. Set to -1 for no limit. See also the DBCP documentation on this and the minEvictableIdleTimeMillis configuration parameter. --> <!-- maxWait: Maximum time to wait for a database connection to become available in ms, in this example 10 seconds. An Exception is thrown if this timeout is exceeded. Set to -1 to wait indefinitely. --> <!-- username and password: MySQL username and password for database connections --> <!-- driverClassName: Class name for the old mm.mysql JDBC driver is org.gjt.mm.mysql.Driver - we recommend using Connector/J though. Class name for the official MySQL Connector/J driver is com.mysql.jdbc.Driver. --> <!-- url: The JDBC connection url for connecting to your MySQL database. --> <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/javatest"/> </Context>

    3. web.xml configuration

    Now create a WEB-INF/web.xml for this test application.

    <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <description>MySQL Test App</description> <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/TestDB</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>

    4. Test code

    Now create a simple test.jsp page for use later. <%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <sql:query var="rs" dataSource="jdbc/TestDB"> select id, foo, bar from testdata </sql:query> <html> <head> <title>DB Test</title> </head> <body> <h2>Results</h2> <c:forEach var="row" items="${rs.rows}"> Foo ${row.foo}<br/> Bar ${row.bar}<br/> </c:forEach> </body> </html>

    That JSP page makes use of JSTL's SQL and Core taglibs. You can get it from Apache Tomcat Taglibs - Standard Tag Library project — just make sure you get a 1.1.x or later release. Once you have JSTL, copy jstl.jar and standard.jar to your web app's WEB-INF/lib directory.

    Finally deploy your web app into $CATALINA_BASE/webapps either as a warfile called DBTest.war or into a sub-directory called DBTest

    Once deployed, point a browser at http://localhost:8080/DBTest/test.jsp to view the fruits of your hard work.

    0. Introduction

    Oracle requires minimal changes from the MySQL configuration except for the usual gotchas :-)

    Drivers for older Oracle versions may be distributed as *.zip files rather than *.jar files. Tomcat will only use *.jar files installed in $CATALINA_HOME/lib. Therefore classes111.zip or classes12.zip will need to be renamed with a .jar extension. Since jarfiles are zipfiles, there is no need to unzip and jar these files - a simple rename will suffice.

    For Oracle 9i onwards you should use oracle.jdbc.OracleDriver rather than oracle.jdbc.driver.OracleDriver as Oracle have stated that oracle.jdbc.driver.OracleDriver is deprecated and support for this driver class will be discontinued in the next major release.

    1. Context configuration

    In a similar manner to the mysql config above, you will need to define your Datasource in your Context. Here we define a Datasource called myoracle using the thin driver to connect as user scott, password tiger to the sid called mysid. (Note: with the thin driver this sid is not the same as the tnsname). The schema used will be the default schema for the user scott.

    Use of the OCI driver should simply involve a changing thin to oci in the URL string.

    <Resource name="jdbc/myoracle" auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@127.0.0.1:1521:mysid" username="scott" password="tiger" maxActive="20" maxIdle="10" maxWait="-1"/>

    2. web.xml configuration

    You should ensure that you respect the element ordering defined by the DTD when you create you applications web.xml file.

    <resource-ref> <description>Oracle Datasource example</description> <res-ref-name>jdbc/myoracle</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>

    3. Code example

    You can use the same example application as above (asuming you create the required DB instance, tables etc.) replacing the Datasource code with something like

    Context initContext = new InitialContext(); Context envContext = (Context)initContext.lookup("java:/comp/env"); DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle"); Connection conn = ds.getConnection(); //etc.

    0. Introduction

    PostgreSQL is configured in a similar manner to Oracle.

    1. Required files

    Copy the Postgres JDBC jar to $CATALINA_HOME/lib. As with Oracle, the jars need to be in this directory in order for DBCP's Classloader to find them. This has to be done regardless of which configuration step you take next.

    2. Resource configuration

    You have two choices here: define a datasource that is shared across all Tomcat applications, or define a datasource specifically for one application.

    2a. Shared resource configuration

    Use this option if you wish to define a datasource that is shared across multiple Tomcat applications, or if you just prefer defining your datasource in this file.

    This author has not had success here, although others have reported so. Clarification would be appreciated here.

    <Resource name="jdbc/postgres" auth="Container" type="javax.sql.DataSource" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://127.0.0.1:5432/mydb" username="myuser" password="mypasswd" maxActive="20" maxIdle="10" maxWait="-1"/>

    2b. Application-specific resource configuration

    Use this option if you wish to define a datasource specific to your application, not visible to other Tomcat applications. This method is less invasive to your Tomcat installation.

    Create a resource definition for your Context. The Context element should look something like the following.

    <Context> <Resource name="jdbc/postgres" auth="Container" type="javax.sql.DataSource" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://127.0.0.1:5432/mydb" username="myuser" password="mypasswd" maxActive="20" maxIdle="10" maxWait="-1"/> </Context>

    3. web.xml configuration

    <resource-ref> <description>postgreSQL Datasource example</description> <res-ref-name>jdbc/postgres</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>

    4. Accessing the datasource

    When accessing the datasource programmatically, remember to prepend java:/comp/env to your JNDI lookup, as in the following snippet of code. Note also that "jdbc/postgres" can be replaced with any value you prefer, provided you change it in the above resource definition file as well.

    InitialContext cxt = new InitialContext(); if ( cxt == null ) { throw new Exception("Uh oh -- no context!"); } DataSource ds = (DataSource) cxt.lookup( "java:/comp/env/jdbc/postgres" ); if ( ds == null ) { throw new Exception("Data source not found!"); }

    These solutions either utilise a single connection to the database (not recommended for anything other than testing!) or some other pooling technology.

    Whilst not strictly addressing the creation of a JNDI DataSource using the OCI client, these notes can be combined with the Oracle and DBCP solution above.

    In order to use OCI driver, you should have an Oracle client installed. You should have installed Oracle8i(8.1.7) client from cd, and download the suitable JDBC/OCI driver(Oracle8i 8.1.7.1 JDBC/OCI Driver) from otn.oracle.com.

    After renaming classes12.zip file to classes12.jar for Tomcat, copy it into $CATALINA_HOME/lib. You may also have to remove the javax.sql.* classes from this file depending upon the version of Tomcat and JDK you are using.

    Ensure that you have the ocijdbc8.dll or .so in your $PATH or LD_LIBRARY_PATH (possibly in $ORAHOME\bin) and also confirm that the native library can be loaded by a simple test program using System.loadLibrary("ocijdbc8");

    You should next create a simple test servlet or jsp that has these critical lines:

    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); conn = DriverManager.getConnection("jdbc:oracle:oci8:@database","username","password");

    where database is of the form host:port:SID Now if you try to access the URL of your test servlet/jsp and what you get is a ServletException with a root cause of java.lang.UnsatisfiedLinkError:get_env_handle.

    First, the UnsatisfiedLinkError indicates that you have

    • a mismatch between your JDBC classes file and your Oracle client version. The giveaway here is the message stating that a needed library file cannot be found. For example, you may be using a classes12.zip file from Oracle Version 8.1.6 with a Version 8.1.5 Oracle client. The classeXXXs.zip file and Oracle client software versions must match.
    • A $PATH, LD_LIBRARY_PATH problem.
    • It has been reported that ignoring the driver you have downloded from otn and using the classes12.zip file from the directory $ORAHOME\jdbc\lib will also work.

    Next you may experience the error ORA-06401 NETCMN: invalid driver designator

    The Oracle documentation says : "Cause: The login (connect) string contains an invalid driver designator. Action: Correct the string and re-submit." Change the database connect string (of the form host:port:SID) with this one: (description=(address=(host=myhost)(protocol=tcp)(port=1521))(connect_data=(sid=orcl)))

    Ed. Hmm, I don't think this is really needed if you sort out your TNSNames - but I'm not an Oracle DBA :-)

    Here are some common problems encountered with a web application which uses a database and tips for how to solve them.

    Tomcat runs within a JVM. The JVM periodically performs garbage collection (GC) to remove java objects which are no longer being used. When the JVM performs GC execution of code within Tomcat freezes. If the maximum time configured for establishment of a database connection is less than the amount of time garbage collection took you can get a database connection failure.

    To collect data on how long garbage collection is taking add the -verbose:gc argument to your CATALINA_OPTS environment variable when starting Tomcat. When verbose gc is enabled your $CATALINA_BASE/logs/catalina.out log file will include data for every garbage collection including how long it took.

    When your JVM is tuned correctly 99% of the time a GC will take less than one second. The remainder will only take a few seconds. Rarely, if ever should a GC take more than 10 seconds.

    Make sure that the db connection timeout is set to 10-15 seconds. For the DBCP you set this using the parameter maxWait.

    These can occur when one request gets a db connection from the connection pool and closes it twice. When using a connection pool, closing the connection just returns it to the pool for reuse by another request, it doesn't close the connection. And Tomcat uses multiple threads to handle concurrent requests. Here is an example of the sequence of events which could cause this error in Tomcat:

      Request 1 running in Thread 1 gets a db connection.
    
      Request 1 closes the db connection.
    
      The JVM switches the running thread to Thread 2
    
      Request 2 running in Thread 2 gets a db connection
      (the same db connection just closed by Request 1).
    
      The JVM switches the running thread back to Thread 1
    
      Request 1 closes the db connection a second time in a finally block.
    
      The JVM switches the running thread back to Thread 2
    
      Request 2 Thread 2 tries to use the db connection but fails
      because Request 1 closed it.
    

    Here is an example of properly written code to use a database connection obtained from a connection pool:

      Connection conn = null;
      Statement stmt = null;  // Or PreparedStatement if needed
      ResultSet rs = null;
      try {
        conn = ... get connection from connection pool ...
        stmt = conn.createStatement("select ...");
        rs = stmt.executeQuery();
        ... iterate through the result set ...
        rs.close();
        rs = null;
        stmt.close();
        stmt = null;
        conn.close(); // Return to connection pool
        conn = null;  // Make sure we don't close it twice
      } catch (SQLException e) {
        ... deal with errors ...
      } finally {
        // Always make sure result sets and statements are closed,
        // and the connection is returned to the pool
        if (rs != null) {
          try { rs.close(); } catch (SQLException e) { ; }
          rs = null;
        }
        if (stmt != null) {
          try { stmt.close(); } catch (SQLException e) { ; }
          stmt = null;
        }
        if (conn != null) {
          try { conn.close(); } catch (SQLException e) { ; }
          conn = null;
        }
      }
    

    Please note that although the above instructions place the JNDI declarations in a Context element, it is possible and sometimes desirable to place these declarations in the GlobalNamingResources section of the server configuration file. A resource placed in the GlobalNamingResources section will be shared among the Contexts of the server.

    In order to get Realms to work, the realm must refer to the datasource as defined in the <GlobalNamingResources> or <Context> section, not a datasource as renamed using <ResourceLink>.

    tomcat7-7.0.52/webapps/docs/servletapi/0000755000175100017510000000000012301126373017710 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/servletapi/index.html0000644000175100017510000000243311656646736021735 0ustar locutuslocutus API docs The Servlet Javadoc is not installed by default. Download and install the "fulldocs" package to get it. You can also access the javadoc online in the Tomcat documentation bundle. tomcat7-7.0.52/webapps/docs/setup.xml0000644000175100017510000001566212271304167017433 0ustar locutuslocutus ]> &project; Remy Maucherat Tomcat Setup

    There are several ways to set up Tomcat for running on different platforms. The main documentation for this is a file called RUNNING.txt. We encourage you to refer to that file if the information below does not answer some of your questions.

    Installing Tomcat on Windows can be done easily using the Windows installer. Its interface and functionality is similar to other wizard based installers, with only a few items of interest.

    • Installation as a service: Tomcat will be installed as a Windows service no matter what setting is selected. Using the checkbox on the component page sets the service as "auto" startup, so that Tomcat is automatically started when Windows starts. For optimal security, the service should be run as a separate user, with reduced permissions (see the Windows Services administration tool and its documentation).
    • Java location: The installer will provide a default JRE to use to run the service. The installer uses the registry to determine the base path of a Java 6 or later JRE, including the JRE installed as part of the full JDK. When running on a 64-bit operating system, the installer will first look for a 64-bit JRE and only look for a 32-bit JRE if a 64-bit JRE is not found. It is not mandatory to use the default JRE detected by the installer. Any installed Java 6 or later JRE (32-bit or 64-bit) may be used.
    • Tray icon: When Tomcat is run as a service, there will not be any tray icon present when Tomcat is running. Note that when choosing to run Tomcat at the end of installation, the tray icon will be used even if Tomcat was installed as a service.
    • Refer to the Windows Service HOW-TO for information on how to manage Tomcat as a Windows service.

    The installer will create shortcuts allowing starting and configuring Tomcat. It is important to note that the Tomcat administration web application can only be used when Tomcat is running.

    Tomcat can be run as a daemon using the jsvc tool from the commons-daemon project. Source tarballs for jsvc are included with the Tomcat binaries, and need to be compiled. Building jsvc requires a C ANSI compiler (such as GCC), GNU Autoconf, and a JDK.

    Before running the script, the JAVA_HOME environment variable should be set to the base path of the JDK. Alternately, when calling the ./configure script, the path of the JDK may be specified using the --with-java parameter, such as ./configure --with-java=/usr/java.

    Using the following commands should result in a compiled jsvc binary, located in the $CATALINA_HOME/bin folder. This assumes that GNU TAR is used, and that CATALINA_HOME is an environment variable pointing to the base path of the Tomcat installation.

    Please note that you should use the GNU make (gmake) instead of the native BSD make on FreeBSD systems.

    cd $CATALINA_HOME/bin tar xvfz commons-daemon-native.tar.gz cd commons-daemon-1.0.x-native-src/unix ./configure make cp jsvc ../.. cd ../..

    Tomcat can then be run as a daemon using the following commands.

    CATALINA_BASE=$CATALINA_HOME cd $CATALINA_HOME ./bin/jsvc \ -classpath $CATALINA_HOME/bin/bootstrap.jar:$CATALINA_HOME/bin/tomcat-juli.jar \ -outfile $CATALINA_BASE/logs/catalina.out \ -errfile $CATALINA_BASE/logs/catalina.err \ -Dcatalina.home=$CATALINA_HOME \ -Dcatalina.base=$CATALINA_BASE \ -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager \ -Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties \ org.apache.catalina.startup.Bootstrap

    You may also need to specify -jvm server if the JVM defaults to using a server VM rather than a client VM. This has been observed on OSX.

    jsvc has other useful parameters, such as -user which causes it to switch to another user after the daemon initialization is complete. This allows, for example, running Tomcat as a non privileged user while still being able to use privileged ports. Note that if you use this option and start Tomcat as root, you'll need to disable the org.apache.catalina.security.SecurityListener check that prevents Tomcat starting when running as root.

    jsvc --help will return the full jsvc usage information. In particular, the -debug option is useful to debug issues running jsvc.

    The file $CATALINA_HOME/bin/daemon.sh can be used as a template for starting Tomcat automatically at boot time from /etc/init.d with jsvc.

    Note that the Commons-Daemon JAR file must be on your runtime classpath to run Tomcat in this manner. The Commons-Daemon JAR file is in the Class-Path entry of the bootstrap.jar manifest, but if you get a ClassNotFoundException or a NoClassDefFoundError for a Commons-Daemon class, add the Commons-Daemon JAR to the -cp argument when launching jsvc.

    tomcat7-7.0.52/webapps/docs/apr.xml0000644000175100017510000001521312271304167017045 0ustar locutuslocutus ]> &project; Apache Portable Runtime (APR) based Native library for Tomcat Remy Maucherat

    Tomcat can use the Apache Portable Runtime to provide superior scalability, performance, and better integration with native server technologies. The Apache Portable Runtime is a highly portable library that is at the heart of Apache HTTP Server 2.x. APR has many uses, including access to advanced IO functionality (such as sendfile, epoll and OpenSSL), OS level functionality (random number generation, system status, etc), and native process handling (shared memory, NT pipes and Unix sockets).

    These features allows making Tomcat a general purpose webserver, will enable much better integration with other native web technologies, and overall make Java much more viable as a full fledged webserver platform rather than simply a backend focused technology.

    APR support requires three main native components to be installed:

    • APR library
    • JNI wrappers for APR used by Tomcat (libtcnative)
    • OpenSSL libraries

    Windows binaries are provided for tcnative-1, which is a statically compiled .dll which includes OpenSSL and APR. It can be downloaded from here as 32bit or AMD x86-64 binaries. In security conscious production environments, it is recommended to use separate shared dlls for OpenSSL, APR, and libtcnative-1, and update them as needed according to security bulletins. Windows OpenSSL binaries are linked from the Official OpenSSL website (see related/binaries).

    Most Linux distributions will ship packages for APR and OpenSSL. The JNI wrapper (libtcnative) will then have to be compiled. It depends on APR, OpenSSL, and the Java headers.

    Requirements:

    • APR 1.2+ development headers (libapr1-dev package)
    • OpenSSL 0.9.7+ development headers (libssl-dev package)
    • JNI headers from Java compatible JDK 1.4+
    • GNU development environment (gcc, make)

    The wrapper library sources are located in the Tomcat binary bundle, in the bin/tomcat-native.tar.gz archive. Once the build environment is installed and the source archive is extracted, the wrapper library can be compiled using (from the folder containing the configure script): ./configure && make && make install

    Once the libraries are properly installed and available to Java (if loading fails, the library path will be displayed), the Tomcat connectors will automatically use APR. Configuration of the connectors is similar to the regular connectors, but have a few extra attributes which are used to configure APR components. Note that the defaults should be well tuned for most use cases, and additional tweaking shouldn't be required.

    When APR is enabled, the following features are also enabled in Tomcat:

    • Secure session ID generation by default on all platforms (platforms other than Linux required random number generation using a configured entropy)
    • OS level statistics on memory usage and CPU usage by the Tomcat process are displayed by the status servlet

    Name of the SSLEngine to use. off: Do not use SSL, on: Use SSL but no specific ENGINE. The default value is on. This initializes the native SSL engine, then enable the use of this engine in the connector using the SSLEnabled attribute. Example: <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

    See the Official OpenSSL website for more details on SSL hardware engines and manufacturers.

    For HTTP configuration, see the HTTP connector configuration documentation.

    For HTTPS configuration, see the HTTPS connector configuration documentation.

    An example SSL Connector declaration is: <Connector port="443" maxHttpHeaderSize="8192" maxThreads="150" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" SSLEnabled="true" SSLCertificateFile="${catalina.base}/conf/localhost.crt" SSLCertificateKeyFile="${catalina.base}/conf/localhost.key" />

    For AJP configuration, see the AJP connector configuration documentation.

    tomcat7-7.0.52/webapps/docs/introduction.xml0000644000175100017510000001354512271304167021012 0ustar locutuslocutus ]> &project; Robert Slifka Introduction

    For administrators and web developers alike, there are some important bits of information you should familiarize yourself with before starting out. This document serves as a brief introduction to some of the concepts and terminology behind the Tomcat container. As well, where to go when you need help.

    In the course of reading these documents, you will run across a number of terms; some specific to Tomcat, and others defined by the Servlet and JSP specifications.

    • Context - In a nutshell, a Context is a web application.
    • Term2 - This is it.
    • Term3 - This is it!

    Throughout the docs, you'll notice there are numerous references to $CATALINA_HOME. This represents the root of your Tomcat installation. When we say, "This information can be found in your $CATALINA_HOME/README.txt file" we mean to look at the README.txt file at the root of your Tomcat install. Optionally, Tomcat may be configured for multiple instances by defining $CATALINA_BASE for each instance. If multiple instances are not configured, $CATALINA_BASE is the same as $CATALINA_HOME.

    These are some of the key tomcat directories:

    • /bin - Startup, shutdown, and other scripts. The *.sh files (for Unix systems) are functional duplicates of the *.bat files (for Windows systems). Since the Win32 command-line lacks certain functionality, there are some additional files in here.
    • /conf - Configuration files and related DTDs. The most important file in here is server.xml. It is the main configuration file for the container.
    • /logs - Log files are here by default.
    • /webapps - This is where your webapps go.

    This section will acquaint you with the basic information used during the configuration of the container.

    All of the information in the configuration files is read at startup, meaning that any change to the files necessitates a restart of the container.

    While we've done our best to ensure that these documents are clearly written and easy to understand, we may have missed something. Provided below are various web sites and mailing lists in case you get stuck.

    As Tomcat 7 is a new release of Tomcat, keep in mind that some of the issues and solutions vary between the major versions of Tomcat (6.x versus 7.x). As you search around the web, there will be some documentation that is not relevant to Tomcat 7, but 6.x, 5.x or earlier versions. Doing 3.x or 4.x things to 7 will probably not work in most cases as the server.xml files are very different.

    • Current document - most documents will list potential hangups. Be sure to fully read the relevant documentation as it will save you much time and effort. There's nothing like scouring the web only to find out that the answer was right in front of you all along!
    • Tomcat FAQ
    • Tomcat WIKI
    • Tomcat FAQ at jGuru
    • Tomcat mailing list archives - numerous sites archive the Tomcat mailing lists. Since the links change over time, clicking here will search Google.
    • The TOMCAT-USER mailing list, which you can subscribe to here. If you don't get a reply, then there's a good chance that your question was probably answered in the list archives or one of the FAQs. Although questions about web application development in general are sometimes asked and answered, please focus your questions on Tomcat-specific issues.
    • The TOMCAT-DEV mailing list, which you can subscribe to here. This list is reserved for discussions about the development of Tomcat itself. Questions about Tomcat configuration, and the problems you run into while developing and running applications, will normally be more appropriate on the TOMCAT-USER list instead.

    And, if you think something should be in the docs, by all means let us know on the TOMCAT-DEV list.

    tomcat7-7.0.52/webapps/docs/architecture/0000755000175100017510000000000012301126373020214 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/architecture/startup.xml0000644000175100017510000000363512271304167022454 0ustar locutuslocutus ]> &project; Yoav Shapira Startup

    This page describes how the Tomcat server starts up. There are several different ways to start tomcat, including:

    • From the command line.
    • From a Java program as an embedded server.
    • Automatically as a Windows service.

    A text description of the startup procedure is available here.

    A UML sequence diagram of the startup procedure is available here.

    The startup process can be customized in many ways, both by modifying Tomcat code and by implementing your own LifecycleListeners which are then registered in the server.xml configuration file.

    tomcat7-7.0.52/webapps/docs/architecture/project.xml0000644000175100017510000000330712271304167022414 0ustar locutuslocutus Apache Tomcat 7 Architecture The Apache Tomcat Servlet/JSP Container tomcat7-7.0.52/webapps/docs/architecture/startup/0000755000175100017510000000000012301126373021716 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/architecture/startup/serverStartup.txt0000644000175100017510000002060312271304167025356 0ustar locutuslocutus Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. Tomcat 5 Startup Sequence Sequence 1. Start from Command Line Class: org.apache.catalina.startup.Bootstrap What it does: a) Set up classloaders commonLoader (common)-> System Loader sharedLoader (shared)-> commonLoader -> System Loader catalinaLoader(server) -> commonLoader -> System Loader b) Load startup class (reflection) org.apache.catalina.startup.Catalina setParentClassloader -> sharedLoader Thread.contextClassloader -> catalinaLoader c) Bootstrap.daemon.init() complete Sequence 2. Process command line argument (start, startd, stop, stopd) Class: org.apache.catalina.startup.Bootstrap (assume command->start) What it does: a) Catalina.setAwait(true); b) Catalina.load() b1) initDirs() -> set properties like catalina.home catalina.base == catalina.home (most cases) b2) initNaming setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, org.apache.naming.java.javaURLContextFactory ->default) b3) createStartDigester() Configures a digester for the main server.xml elements like org.apache.catalina.core.StandardServer (can change of course :) org.apache.catalina.deploy.NamingResources Stores naming resources in the J2EE JNDI tree org.apache.catalina.LifecycleListener implements events for start/stop of major components org.apache.catalina.core.StandardService The single entry for a set of connectors, so that a container can listen to multiple connectors ie, single entry org.apache.coyote.tomcat5.CoyoteConnector Connectors to listen for incoming requests only It also adds the following rulesets to the digester NamingRuleSet EngineRuleSet HostRuleSet ContextRuleSet b4) Load the server.xml and parse it using the digester Parsing the server.xml using the digester is an automatic XML-object mapping tool, that will create the objects defined in server.xml Startup of the actual container has not started yet. b5) Assigns System.out and System.err to the SystemLogHandler class b6) Calls initialize on all components, this makes each object register itself with the JMX agent. During the process call the Connectors also initialize the adapters. The adapters are the components that do the request pre-processing. Typical adapters are HTTP1.1 (default if no protocol is specified, org.apache.coyote.http11.Http11Protocol) AJP1.3 for mod_jk etc. c) Catalina.start() c1) Starts the NamingContext and binds all JNDI references into it c2) Starts the services under which are: StandardService -> starts Engine (ContainerBase ->Logger,Loader,Realm,Cluster etc) c3) StandardHost (started by the service) Configures a ErrorReportValvem to do proper HTML output for different HTTP errors codes Starts the Valves in the pipeline (at least the ErrorReportValve) Configures the StandardHostValve, this valves ties the Webapp Class loader to the thread context it also finds the session for the request and invokes the context pipeline Starts the HostConfig component This component deploys all the webapps (webapps & conf/Catalina/localhost/*.xml) Webapps are installed using the deployer (StandardHostDeployer) The deployer will create a Digester for your context, this digester will then invoke ContextConfig.start() The ContextConfig.start() will process the default web.xml (conf/web.xml) and then process the applications web.xml (WEB-INF/web.xml) c4) During the lifetime of the container (StandardEngine) there is a background thread that keeps checking if the context has changed. If a context changes (timestamp of war file, context xml file, web.xml) then a reload is issued (stop/remove/deploy/start) d) Tomcat receives a request on an HTTP port d1) The request is received by a separate thread which is waiting in the PoolTcpEndPoint class. It is waiting for a request in a regular ServerSocket.accept() method. When a request is received, this thread wakes up. d2) The PoolTcpEndPoint assigns the a TcpConnection to handle the request. It also supplies a JMX object name to the catalina container (not used I believe) d3) The processor to handle the request in this case is Coyote Http11Processor, and the process method is invoked. This same processor is also continuing to check the input stream of the socket until the keep alive point is reached or the connection is disconnected. d4) The HTTP request is parsed using an internal buffer class (Coyote Http11 Internal Buffer) The buffer class parses the request line, the headers, etc and store the result in a Coyote request (not an HTTP request) This request contains all the HTTP info, such as servername, port, scheme, etc. d5) The processor contains a reference to an Adapter, in this case it is the Coyote Tomcat 5 Adapter. Once the request has been parsed, the Http11 processor invokes service() on the adapter. In the service method, the Request contains a CoyoteRequest and CoyoteRespons (null for the first time) The CoyoteRequest(Response) implements HttpRequest(Response) and HttpServletRequest(Response) The adapter parses and associates everything with the request, cookies, the context through a Mapper, etc d6) When the parsing is finished, the CoyoteAdapter invokes its container (StandardEngine) and invokes the invoke(request,response) method. This initiates the HTTP request into the Catalina container starting at the engine level d7) The StandardEngine.invoke() simply invokes the container pipeline.invoke() d8) By default the engine only has one valve the StandardEngineValve, this valve simply invokes the invoke() method on the Host pipeline (StandardHost.getPipeLine()) d9) the StandardHost has two valves by default, the StandardHostValve and the ErrorReportValve d10) The standard host valve associates the correct class loader with the current thread It also retrieves the Manager and the session associated with the request (if there is one) If there is a session access() is called to keep the session alive d11) After that the StandardHostValve invokes the pipeline on the context associated with the request. d12) The first valve that gets invoked by the Context pipeline is the FormAuthenticator valve. Then the StandardContextValve gets invoke. The StandardContextValve invokes any context listeners associated with the context. Next it invokes the pipeline on the Wrapper component (StandardWrapperValve) d13) During the invocation of the StandardWrapperValve, the JSP wrapper (Jasper) gets invoked This results in the actual compilation of the JSP. And then invokes the actual servlet. e) Invocation of the servlet class tomcat7-7.0.52/webapps/docs/architecture/startup/serverStartup.pdf0000644000175100017510000013213710453561304025314 0ustar locutuslocutus%PDF-1.4 % 1 0 obj << /Type /Page /Parent 24 0 R /Resources 2 0 R /Contents 3 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 2 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 32 0 R >> /ExtGState << /GS1 36 0 R >> /ColorSpace << /Cs6 33 0 R >> >> endobj 3 0 obj << /Length 1620 /Filter /FlateDecode >> stream HWnF}W dzsoA\ڗ1hI$&F=(`[3;s]\vvLl]6n)Õaq_.=m}r]M& ֓Qij,=A*CZXɌG$Kul!eK!xkۗb%ytv%wdGs;ZҖ'TO<~hmzβML(ܩUыy)낎-XdNe%Ngg')l7fY=PV(ntݮ^}:Hc]"dloC@\ǁ]@,Jkpl/kNߗDh&Pф OLZ]w*.y0ML_m9DHm Bn)K"D̝U $^UDTVID pyUB*ͪB9gwzvVt@X˝KqaiU"ϣU9Mփ&XPU8Һjc7SOߓT =j;XԢ]ĞPȱa &FUB[rmTj9."tIN"@[.-b('[9p2Jr {F\#:wBstR")vVyҶ,PMV$x(ǝsv XaN`^Q-ڷM;TmUDj@;GBC%. 'A7Rm2;KG1qNf"[J=^LGJReH:`U.j 7Ӟ#VZr$oO:*IحM=3`($QFt qE /-(i?*UTjIJGB "sd^2d}:'kPZ( SZn%9v!.{b>7> L.m(3T;=7`Բoz˺D(W7(I[HyO SkMAxL G(Z)T2NF(XI?U8 &4ᦂ<]\dp$?P}jAb;LzXTU)z'w4LsF^/Sϼߪɶ`ekWyEP\NOs9RLnQ;٨ 2 3&j: o-r݁ {M(TŭֹuLz:̾uczi-w|mm0KwͧtY͒}k/~h-onf=O=g7,]KLL n~g)Y$wtr+Ŧmf7wYd5.C!L'BT?8ߋ]1٬-\$S$w)SU endstream endobj 4 0 obj << /Type /Page /Parent 24 0 R /Resources 5 0 R /Contents 6 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 5 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 32 0 R >> /ExtGState << /GS1 36 0 R >> /ColorSpace << /Cs6 33 0 R >> >> endobj 6 0 obj << /Length 2860 /Filter /FlateDecode >> stream HWnG}W4/J~-ɻXDIdqV !G #&=5r4 mְXU}tWg&fdw \a^ȥblr;y;N |Gkq9GZX29yl׳L\L'mJur6j@z{r$vZ֋lG H`<ۋ%,HZ[X-W$[nH݁`xlBoy, c Gi1ۍ}B"Cy 舜]O|Ǿ0)%[ :S}$y*)Ul+G2jh*mc+Eq|8CX%qF kR݄h>,N #u4v @II:-S\Jh[Q3ϵF1u+4ոfPY|@;mmCAM.!E Q.ԹCTPӭa$=^RKn/\kJ8 _՚M=8zU(hR١XRA_1ȣCe r^q+CR~/gft˥뻴5miB˒\ePl\ eYMls6(Ipdԡl< 4Xn%D6 l ٸdCgmcu_՚M=8zUh0NscFM<:7.bMc܏ӊHk'fe1l#SوpEQ.ٔCvݍ FY/(ᡆ}ĺ{ߊ VwW35e_@n-eK_.TS*0МyܰtP u4j\Z]`Mk:aB|'*], #$BEj[f`O;LZA7z{srM×SRtt44`%uhN8YQN SwKc53T[735 ]iw ;h)aa);/eѾvξ_f?yvGo/釋/~] qԦ<54КFH$R^@ тFδMy /mk  C^ϱIAV-Dr @` @ӴjSА^ & 0#bXDp^wh(lKNE*SZL i̊TAR )Ev%f44+Rݼ5^EwVIc)A5JGh2 ((-C(m$Ѝ5a*Yzhb M̈́L $Mn{99x`T-8cڂ˃ T AӘPC yyH=xjWLNRv9^>~G8 8~)g5Xpc*H@}NHwhJ󇻻l͏ԁt@>6%k[mM#^IԞ:}o*uðu lAl xk!bʔo<;mLc_I!57bc  MhjQ6pP4vpL)BfӘWARD/Ki\4c-g-:[􆝒 ;HE410 ädr\^VAL+!ε܇#(GQS(Hj(Tk'䥡&UǤ"HY5p!i[ӣ\ bp$i&vZ֋/K|%no&cĂ9gIF\5t-|*0K]@Ry UDȀyH-EnU&@h7 G|!]w]n#|(V0 :mtGdfQiCP^g[6AUpGP2-rng뛛{*(u.Ww7jٮgۇ5ܲon"g_ gKv;ٚIà:9[3vA ! jp*J̵ROLŃ&.o}Po`o#p;,3\A_XO!SA0Q0 c)Tr!x#4sp.(: endstream endobj 10 0 obj << /Type /Page /Parent 24 0 R /Resources 11 0 R /Contents 12 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 11 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 32 0 R >> /ExtGState << /GS1 36 0 R >> /ColorSpace << /Cs6 33 0 R >> >> endobj 12 0 obj << /Length 2156 /Filter /FlateDecode >> stream HWkoV_q}?-XA7R`$P+1I{Ӣ)ǥ r4{y],>:9D]%yoW4r6Knt=Mi&)1lJDl:_Iv.n[z4Tܺ~LJ ܆>'db]P‘c~s~mMuݧe6I2pd?).MW]8YhJ./g"#ER^L!-t +W:SgWZ#"(٩< pOKH~w[>j]`.J/+ xc7TSE*=妥t+v.V2`#G` u(gFrf<;5^|OoؕG@PpeksJ*EbP\H/-Z@FjX>@(JuaA$Hcy* Jy ҕt+ h|h|XK݂wuxeL#gnr[>%I|ʢb׼K!wPlynk]!a*zWf9;>Nۨ6*ɈM;{v" 9(n5ԟ蠚;@51va#f 2<0x4UQb1 X!+hqߧ<b]S*Q]BЈFDMBӘLv^l7.v7U5*R'(J0Ե:a勴P\c3.O˱0$-`+z+jpC=; EOKR9\ F2qBsT\DmۢtT-sw`|yhx#z\㑨Ik/P"ŐX6}1p&0JZL4J._hŤZ9n};Z5hHj]Xi\k)yu?62R=Cŀl6T?ȸ_Dܼ""=b+zDc."-7Վ!]@Zw6>->ڟIj.Cۥ;~|J(r1[CeXEteEum"X9c=E8b*[e=g 9Zb˷iB-o,oWojdž?]z~]fl12~`Jo)[2vHEjzl9{[%!O#?qԨA=8E1٬,7EAt?wۿ}R endstream endobj 13 0 obj << /Type /Page /Parent 24 0 R /Resources 14 0 R /Contents 15 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 14 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 32 0 R >> /ExtGState << /GS1 36 0 R >> /ColorSpace << /Cs6 33 0 R >> >> endobj 15 0 obj << /Length 1915 /Filter /FlateDecode >> stream HWr6}W`/N'qNogZINi)%S'߳xDSN[Ws'+Ǧ+&j:t%j Wy'\*Fd'TilV]EˀFejh5 c|QeMkO:\K$daUd8%\읦4X eR9 FāU@Zd { ԇ1/vƬF9Dߦ5]`#|qВT=t>  4DSetH|>"(:gZd^vπ tċ5KZu)Vjyá;#$YME$Ӵ!cQR/CUgsx[IR::g[b|"{ :@ +j;dHH]LH6lxP [Y+eO fYq6= 'HB*K.Д :,(qQϸwaoTCck7חr9Ȧ:[2cEvWٿ2VvweHg!xLBYL z`}>\d3 endstream endobj 16 1 obj << /Type /Metadata /Subtype /XML /Length 1381 >> stream 2002-12-16T20:05:37Z 2002-12-16T15:06:25-05:00 Acrobat Distiller 5.0 (Windows) Administrator PScript5.dll Version 5.2 Rational Rose - Tomcat_5_UML.md 2002-12-16T20:05:37Z 2002-12-16T15:06:25-05:00 Administrator 2002-12-16T15:06:25-05:00 Rational Rose - Tomcat_5_UML.md Administrator Rational Rose - Tomcat_5_UML.md endstream endobj 19 0 obj << /Type /Page /Parent 24 0 R /Resources 20 0 R /Contents 21 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 20 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 32 0 R >> /ExtGState << /GS1 36 0 R >> /ColorSpace << /Cs6 33 0 R >> >> endobj 21 0 obj << /Length 3021 /Filter /FlateDecode >> stream HWnG}Wc_cB66zX )RL2Q9s%9a$v!8tU:]uֱٖFv%v Wymdn2Q܌9ˋ$z| K.O!vt/+vu6_sI>,|m !ӑ.;!B|6[\p;:,c:@ "L8iyCԧ,o鼠J>Y i@O)(%N1]?D|hѠҹ IMI3.Ȃ9<0JN]'2.9W:_@2xE\krK#; { L{::]壍v}åjíJx*&HBIJP"4tpdu.).6!qdel.ak/Gꕞ?Q.86&^ ӨAtj#P+ڛfʀ>hLҷѰËDֆTP4]E@!9rZ'QgM2 <UERe26bkDd7t˛/ߑ͘* NNfr^M hd T)S/ #'+QhRU֊l2d|Ƨ<M}F2^#'+1"pI%HD&'CA+4m09_OR(WQP"C3UZ¿Q"oQǠO9'Eb7$Ll%1XJMR( YJ-z0I\tk-g4 iNrmV֠t*M!Vu=gX4}_t_ٔ]g_S!6?ؗ7}XlnH&_2)p3P\:xD-b4DZ9n(Pa~;<ݝ+<It9*{Lj%cbeP+> endobj 25 0 obj << /CreationDate (D:20021216200537Z) /ModDate (D:20021216150625-05'00') /Producer (Acrobat Distiller 5.0 \(Windows\)) /Author (Administrator) /Creator (PScript5.dll Version 5.2) /Title (Rational Rose - Tomcat_5_UML.md) >> endobj 28 0 obj << /Type /Catalog /Pages 24 0 R /Metadata 16 1 R /AcroForm 40 0 R >> endobj 29 0 obj << /Type /Page /Parent 24 0 R /Resources 30 0 R /Contents 34 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 30 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 32 0 R >> /ExtGState << /GS1 36 0 R >> /ColorSpace << /Cs6 33 0 R >> >> endobj 31 0 obj << /Type /FontDescriptor /Ascent 905 /CapHeight 718 /Descent -211 /Flags 32 /FontBBox [ -665 -325 2028 1037 ] /FontName /NNEOBB+Arial /ItalicAngle 0 /StemV 94 /XHeight 515 /FontFile2 35 0 R >> endobj 32 0 obj << /Type /Font /Subtype /TrueType /FirstChar 32 /LastChar 122 /Widths [ 278 0 0 556 0 0 0 0 333 333 389 0 278 0 278 278 556 556 556 556 556 556 556 556 556 0 278 0 0 0 0 0 0 667 667 722 722 667 611 778 722 278 500 0 556 833 722 778 667 0 722 667 611 722 667 944 667 0 0 278 278 278 0 556 0 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 ] /Encoding /WinAnsiEncoding /BaseFont /NNEOBB+Arial /FontDescriptor 31 0 R >> endobj 33 0 obj [ /ICCBased 37 0 R ] endobj 34 0 obj << /Length 1951 /Filter /FlateDecode >> stream HWmo6 _!`_ҢU.9ߚVlHbK3n}w#% hÒ>HemH^|ywCHM!*bysd[$2y\ ^''up \%+bF9]l6z;X~I~^&wZԴ}g;*-ʇ=Zj.켋bO*{^WeM)ؔT qj4nUY{QoyQ)J zr q7f-w/7a?>n~2eUzDd' 77\1r8q[8* bx8:7kF9$Zэk1ț9QAphL<(:Jnke1=qX*H4(n#}D4a܍bk깃Py )(OwDHR!DwTI=`0E5<7'<ϐpyO0~ΠuƀєwI.}F<'fObxPn?yVZ=+uc{§ vAvOSki ^RJ;<)%ǎ)̷"lt4}fR@ 8$[Hp %U'#Vދ&jp 4)7mD%Ra mEP.RЃ ]#Mx3j(f}xz~_SL0Ŭg`LΩ^N9ћZB;6}v9uڸxؐ?0+R+" X9sp2W x "紕` OB~#c9󋔴a'O)e͇aF qEh5{(ŽVpF)e&\HɜʎdPj m`ixDJhDDZx~_k#KS+㶦V_ʪ8'緷MTl}Gnv,7ef̊nvY]Usϥ%f}}EE^>[X4^  ?PndQf,!i\$gluN6eUd}?.aCh'D/2?ϲx"o$p2Dxl endstream endobj 35 0 obj << /Filter /FlateDecode /Length 22223 /Length1 36588 >> stream H\T xMWMxP>թgֽa9k^{9$Y]TZRЖ Ϲż`8SZFܥj {M6kfe,Ze#`;>e DZls+4djOsWԞ gO傅7?}7v|G=h~c}VWk}_|֭^'Al!D LeɯǤ| Eݜn,qt(+j[f{c rPz4a.*0 ՚.s|{qLgAbPf~~b~$؊H; Բ拘rBf#g`AAH`%JQT#0b2qB]ffm1vVħdS;̗D#Op=8CJhFLecTxgIEjS4iCD`&stK,gZ!Q2̱c\qbhM'EQ)v∃Qxoc(h{mˣKfH^xBRг}. "(sV7W*PE]i8/jFg#&9,U2)_YRר,|.[nr?bWv 8tWH cNTOFO,]_tn 0YDat1_,[NtV|+-#eo Y +9:E^Vbvd%Q=vXlgO{߹owl^F7>FR8{7l>TddfljF9A{ts=9?.b"SDTMbhUβtY"ʥA}wyE~/b2`[Sq eK\U/- K֡Tk5:ݺzaP!whQ<%R:e 6J8#p?@ܩ֊e,ՖQbeCc/(E(Š,ʫKQuv=W[l\ܰp Fp̷@%AƧ"YLt]9'T܉CE8y:Z}M\D4!E6w09VaůX) \+|+,ngQx# FPjr8EhWqAodҡQ߀eX*s%.BғU.tɊ+xLvoqcdKs2/&Tw| O3hL(UÈa gnFσ:=6KlD#=s2 ѮfI+΋|2ڱ!U>F>FͿrw 3 |U~SMfpk3{Q0̹kU&6:)F>l'8Ą{۵^=ڳGLtTdnt9,)jQ)N=P3 %N?>ɿ,p? (44e/jlyo;@=%6&O7xXL9zHRVp r[w ?ui 6uw?WkpUW^}νP@PPB BB"ry@B^TJ [ie#\(L &$&8\ i#u 1T->ȌmK;3rs`k^{I'(14qM[(䚰[^Hn&~{c~ Ήj?N}^Aj^~$yNL6oI7ɩSh#IW%=ɐʥ,4,ԫZ|~Dhɹф))wةž½$̌.ͼ>[DzwC9S%%)ɳT_:Q eQ)[$U.Gg\$H$7597RYbW&'FNs siOJVWtSWҬv+;!GrܟR*5~g$n>{FWBw\藩ʽ|1.ޑY(6ob-s>s<&<ءQfףLيbm~# W<vX~@ 0J?JS/ҋ Y7Fyͱ5~eӭpl̋%O;lƒyF6@JWI1;`OU; f2@b}CZ*MFXdL?(J͈ pc]*ZǁE@zbc /a`-ۃ3ZQ}m2$sLrTdGjo`2P2 XP`@0 s5d"f86e| 66ɘupPsfX/;6)e|sk:9b':~AAĖ|`3z!U!+8f>/k'8ƭ5SAbe1^M0f9oCZ!lc433z6wb?޵Ep ׮1[&O%]3&]f,^hN3#&&=ݶ|&|Z&2'0pV/Z|`]֋ A$Z?y 7QM;EG-Lax.U0x|8sXrٍW/sW15 l]PxGc#O4gI lwվtˍOO{ⳏ7.,wŽ9?ryq#z#Rz|:b۶r#V` ,{SN-}:ڽK=ޣf6S7ҏ=Z$eu;rVAv2|Ua8K'r/{DcwQ5Uo}/S1l?/uSYgSIYV^:{c@hghhW+}#2.o9^?o% цǫ}4@쏷cZZ,YH8Cu0Y8sjѯmA!C|U"7U"琌}hz6!F>j0|X.>[89v {bEcS5t&$VLݝ?Lm;-o>/ %Za iS0.q<ÿ~F/4=xR~Jʁ%8 gkzqSb ="(OEJYhxbY$(\oK_XBb*W72hGzg~q2?ĸ 2p}9bK_.<6y|)r7{akN'i*}Hs+_&V2w$u~Ns%qOОƉ _o  c>&2Cw~Ń纝>fu0Cj`x1D1 O3= =#c,<ɞ]LC5xn8vKL bs%,#+ie4P[6i Jzp Hɔ֔ieL'"meT-{޳1iw}y}uI4F0JDaźH$cB! F;Tbp&4&Dɍr(څƑ1z0 `p~D>wu `p00p~P V`0` ~@{d"n~R;DKV/`uV_ VcVX݂(VE`!o*Y+w(>h@XDwdfRdܥrUo#>V(7d^ǹs⥚K~3&nd11.d2 ±qymIfg|adq!dya$bija1n٬V y].of3CZs+Bs}NA1 B K'?//K9zco?xa K&47Z}2/58V,Ǜ7SZ&:XX1Aw `M/_0?zO{Ͼ{O_k2o,g.Ǐ3=$w$; Z^kNy,;V0̯>g0DG*d_lW PT>}{, D`:M% j0DE_6Jl M֙֘ v.Ҥ{9d\6[Toڌ%`ӝ-n{.$2I&F^j#SX GM^_ KNFlnI|#gfm[Ra)|wvOOǯI#a5VwFX换,[8Vi hJ2N]Zd$ *Q̳Wzep֪IqYr"JFCt"@# ol,Q;X,2?ݔ|KfC5ԮY0{vEkԝSL[JV\+ӥkU4xd76O bB1*Dlp)*GըAqhG"#CpS1DmSpF8X=Xzn,Rh$2cBtF'@ǦHz/IrBg"jZ&k_ 0Sp[0C9EB0!t ء+-Y p6-E.z*ea.SPwwNp[6|fVa1rQڊ]?WږDPE]z֒ZȗWь$GQK d12FblIE3~Ah-x `p*A íּvh3lϞgt-vQkwmoo___!3ON^M$u;%~}Uw^hs9tQ4ɒ.@  瓱[!+-2daƷ`?1q =oA(`WJ.C ,,DzYmjzݣo\A|>˜g{K^qq8+Mu:ez}s-('E$qenun$#NZ0ݒOe/Fz53&"_x|^ 4]DI5i 4! zk,{!VZ4 YA)3dŽ) gEpʼn`> MJrbr4m>qLݦǃ{G::fV\Xe6+~zcщc[{\0z!4Mb$4Gj9Z}\V_֪Rs\?AL4u4;d$.Qr mehdZS&@$i.t 8"`/EDDӡ@@,HxU]Iȸ~GOӟ(\Еm8u칪U5VCJM-[Wů:7~SWd+6ow_\YY~0wn?oBn`z$4Y+bxIdRs_ҔD^8$O`ThJBD^d֦/cdᵔ>59܆\LtIL"ݦޑD nIKDG,n cnKW 5,F/kBvJ蔔BP.d?*jBX0/,jqZ8i9--ʂɞfr>JOiu'47Z)){7+gQq)c%\)6̪IQMf )&gLmLf͆m6dzLA ^-@\]2-I:1rNl[p.2V`qA|z ##`"8 !EIU'WEOL`;`$T`9:v,1}'4~t ذ?yGtO&j&}|qwu6s : 4ll|* UJjK-FeAwe4]ٖI>M'' N-,rW~5iǣ f=Of-/Ckܽ{ɲ.\^*/ ;c%jMPWQF+LDѠ#$&%1 uFL2mh3L֌Mgq{޽?kᏪz4e96A$NFrK0'+-{nSI_h.^Z Z6:0ƒ1wj(^&p.Ow_wx3>څß:Dr \t=T8ك3=<[\^/K:ܤwp[MeegOqɺ Æ 0e ҼHI&vLM34ECBjvlCEG+E:]hCJx]m Vؽj/d,q& KT7Xz5?o{c;M l#$y~QEϞlTpSc86>HCkG} ;e etI}~v`m_{*n Ur\Ypa6[dW|1¿b=2gi,;ZVVf&JkK)fGo_cn7]$j40bp ŭԶ(^ļIܚ@+Vā3 O=#6Ty1\ÅsZ0p8py~הoPpOX-^$QDc 5ɚI"Y$.un!&GW/'mTp#qByKG-|_W㨥E lHdTʊEK@ރNLpvSfSf#^IWYu ?$WT㥒;hj* 8HٱY)HC%zz5}Ss:N cP YQI)"'`R/91 CJ` ]N]q|Z'#.;\49@.lZQ )fWb'pntVZmo)K/_‘u=o64W<2u@2y3.z9IdS颉xBAE!lb'A t tV[,\q7; K\{%&!0 ͅ=ga>D/#'+@h *0݉'ƂIqBn|ȌC9uη<`u@G-A% ޡ6w*VK: jl*創_ 3L ‘oBUԕNXG V ۾PllLaN;CJgsb;N&TÍa 4fL ŜQ-6Z_unҌĞ?&S,G!#$yr8d %H׀=S]6QWߙݽ۽^{ٮc`)L n@b($VT-*`Nm(BPZڨrЊ[8gۙ{{jOƒ)ʣh glwc"͋ ]$NzQ$8\ZjB n;Ї!^Ya%ǕǑ PqO$IUq>c}AaW{,}"lqQKj-OEj8g= KY<42];2 ;^i) fsZkvͳ0Z.%?$(ljFqT(VBPt:щ^y{_',`K\i] yr43^-XvGV@DϧGw['P!3# T&gi4gͺ4&1.o2״W6;#E`FfL?18/H)[iA4|lgk')!{ +P #DFe !(DmVÝl'ߡ.V 6W;"GѴxʂ#0<EQ%E|*FBFB8Hu WU0FM֟錼uCB7^Ek/g8uFPy*br2W[kBc`1)HyF6Fqs y18k`O1VҊ?H7weD4 $MjTftM+VGSF,~ wb;?Q_7tlǡ%wjѶGE%~TY7o<[;tO~ rk5$t|ܒ9et;QHR ˓MJCٜܙ+e˓oKk'^sEڢlU7$;i#|tH9%$q`04dE#/.Udvԃ䁓4#>EUp]b#s>UFUgo}U[}ڊg7n2 xQ&/fK,{=,g XϤ Y:Fsl]57l|7:ENDXɻ.8J(Ҡm_Jd:w8&@ lYmT~~xE kY|.F g :.éTe&ԕ xP\hҘO8W?p]wrv{_B ޙ~"2yPVXL}b# -Qv3Pk@f YaZP/ꅊt;#dKخHe:Ƙh z?"To0l n ,ʓqRm>tkOg%X %Y]9GyƨG%h9 ܉}61.(ʻ4oϩRZ2T֛:NTsL3x/'"/Ɋ"EMӟlf)"kW:((;= (帘4~Sy>5QQ,U3TUy3XҦps6u](. Շy(~h6Ţ# hfCs@p(g.;)OD! gt>jJKV/]K˥ Fh$N~Xl}pIlYlv'@q8g1K@Y)#ph@BH+BWZ޲ͱі AnKGJ(p7ﱤ>y`nFS#x6ʭ6TFȰ(%ልAs Hחq>ͬ8yQݙSh"2W0y0)rNɌ*P$BP)GedQ.TrJNlxVatu?AWnZ0UpQ1,?@U+83}P'/CT} Գv9)[m6jORjʗ~{xI s8=$Iq$IpɊa#yMŠUAbAI7ϓ$"wTe2bOApzf,dv2[+kC5ܸ1du{WnCXm1!E[m;\;X# Nq=yvJwwrż71|'rHbBPP@ص$vZAp Kh1܏uY1.MHG/5z 4S cM"q@>@ ص:Ka) Ù5LC-Bge_0xTIM)͒+]"j`0!ԾLæMp?QD6^u_D h4!<)˪VESB*(4D&l'x/8U\!/U'*jGŞ7/͘,."J* ՉAoqB\q8,һ6HFx5!F؉.P;~ܐ"9 0.NX H= P}E.m6l+.U!R0n}}&iV B4FAMLg_.GLc"b ۫I#´d" \D&53JW,C%SnYA3/m_+9DEnXp }yܢ+Mz,Ko6<<~ۛ'sTPS4ٓA@uPDdgVD]JOJu=W+~w %MfzgRcg@)asweC{?UaݟC9JAtO=Q$^ Y3D:!3:n#Gq W QBc܁:tTf#L/id44hrwڂ>L[D: І)T"r#$pv5Bи_nm}ym+v̵ٚ7'o?!kP}8mLwHצ(SԹ\NSw]^io ~7t3Z(qeI1wsst"SU8j:bU3.ס:ຬqO8͉!17 EP]M4OA:S`8+iU욪U[L@hhfЪ+Q$3 )XTb:L~}@OM|7nݿ獯.Vo{;kS~uMi ,XL B\xHKݥ<}=W[k圿Os_S,yu=0eW05Ȍ!a x0]-` }[hP9 "9_ "]|I:Bpչ6(3r\`ldcⵣªIA]4anwe&uLj̐ 47~BErZ׾s˷ٍms&c4,O| >lKuBdN9s zK$[XkdmD~:D[o[﹁o$‹zjΝ K a ρZjX] HP~8nFYu{Kc{\6YR:YP%4hȮ&3zݻ/=Vj%$-MRUjU^1+&4LHeiR$c܎2ŝ4Hܱ4kӦnHwW0{?Zssf3β"۶MCRŰpКz? ;;Jkrlӗx.Y`Ó272й ء0=<5Ѕ]7S@C'oۥ${G/@lur|ۜy rQCx6c$QkI8I%/og\Ľ(Fčp'@|a0oa%SgIꚋ"@R4ٝ\ԙL9pGXۙBǦWCFCo Gg['`饋 ٶ9^]JG }+04MA#U*ŪWt*B8RVebARHq̢EbYlreqZ4tFqMxUW?|V͝ Tk~5>4bYe4 +ⲺB}׵sW ::zz%weߒWҿ+)[vCo# 7m.ݒd%(VeLj (T4DH; }}dp R#p;rؚ#mmi1/8E <Wcof;p7IL8$>IDB8"xD9TJ<xIfҪZ֪9D6Tyx1wWtb-n9 %MŲCEM)B%B2&˺b?M^rIGI-X˦֦dHgdi0JMCp\.C aBp"Z.υЯ)u.~rg(Bє*t^k_N:qD'OtKK^҃qS|ZN-։U&L%ڄÈYL㳃'k!6{bǜFvk%l!~Y(. yY&o>FCO EdnHȄܝw7=c;v4qH>^@RFHX4 ,R^AІv(hJJA ).ZUhlt@jQhՔGY=gjͲG^-qѨ˻jRT)z͆OQ(\,Feei5=a]s &w]X))ϺWלy>^ :wcaWM+ ZySU쪃La#6@BLB K^ʵ"lÃ! ԢJcU55-#G ͪLE&s8e*PԸT=n;Ǻ֞mο2wαG̑+>D5sC?<`GiԠzQe F'x0e/K}-u ۗ=R"b Ub#jCĿx>w}i|7!+9;6')p;ʁE2TdSneVRuy;<:ć;Yڿ?V_ŎC#7=޺!f,mGw}3yʕ>~cMH%l3kPaaͰl+ڰ*`K%О+@prHX:ץjAys:uy=-#vG"jŋe/2mZg1X69rٱI'[&6T:<#0<cGwJ~H'ԗts>! OЄHIlڅvNbt:~:!'Dxb,//KvEbݱ} qor'!'$O/]jL-X($Dz^Z`YqհFXm6ؐ@oP@s@I&D . *Ak;]jjҦ x_jy7f'c}j S2x"i)/Cٲ2T@c #',5lJXCsrߑ*=ԙj|ygq;iԜuGRЌ cHaIqt :HTbj LliBJizm qmvkoo/l-8ٿsQOQ٬sj7&C陛Vx5ͫ:O['Jq7> M4n~s*6( p)8-*]V" %Hc~_w{xs??ځN<ٚoC Z*0 PP.[v+.r[WQg RLѪOd7);!j՝#fxl]s8x0u(2e55g&ØDUzP*s =Ǜk{bx5ރ1/|X(0$9clz.2XN+Bd QV @=+$yxJREuRX D"(wLr0d7XrA͝g>P9sށ(,B@ܥ pə ZEn*LUF7v‡WğM,̀$].ݧfo4tbqR*LPK…h [QІ7p=(lIA/1/;W/9 \ɧ |NaRBG}C;hBhFlpghF4tTd'Lթ]*ZCӭn(am"m>lh Xq~gPVħ#*j1l>]Usiwiöo_c80aB(EUi՟eH0jZ;(I$9UDp8A^cYQ h( [idy_`F3IHZ`V_Pj [r<`nnP٧_=ac:9;?ۉꘄ8$mR<HIh@iVt1*˺VU.Vm4 P ZƘԎcݨ:)Fi}6N &M=}?{߻r,YO]}3|AO5 b_O #uf ͰH] _H3$(_/ͽpp-Osqi3ז3j$4ÙI]8]ax1狝lD$Rgxm("𭘥q'O;L #5j'SGC]{o#> z<3cZČ"GӅv5ik;&sgʦo׃4ϒTzw^GdLSghB{G}8 ]V,K$DYI襚4AeA" A鲈զ"9 ʻɌ#vEAL/9FXE#](hg$fb v^㡥?@a'iJipoI<[ZSZ?Yl3~3)~Dm 7TdaqZ֥ ZJ8Xey(<#XbZVEZ^*d ki hOo  [R[YY&y}CJG&cђyώlxg%szl8E[eN;2d);#QNrt&w d-]+ll lv/dJ IT!ϥsͽwk)F :e&Y%xst ETt+ &9DN%#1f6>6m"dH< )dۊMLc5.Yn9Lb2f==qmhCd3H\I;>uHIڦSKmٲ_' 8_oS" #b?qo&G~癹_eΠZ\C#ףY +|(c=@4w-x0 w!>(1@ ŷE!lCd0 ^¸ l(+ D[؞FLQ=B?PR*@q?[{4op,Cy[Xk!r!r!r!r!@ "DgҳTMűpla= Rw[7 6g@ÚdwᗡEܢ.9( eiYڅ׳pggkWKKŲFC'~Ѕl )B |H n[>JǰjM0 Q2H.xf JUSXA;K|S*a,U:h:7O")=vtbn kVa9d endstream endobj 36 0 obj << /Type /ExtGState /SA false /SM 0.02 /TR2 /Default >> endobj 37 0 obj << /N 3 /Alternate /DeviceRGB /Length 2575 /Filter /FlateDecode >> stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 40 0 obj << /Fields [ ] /DR << /Font << /ZaDb 41 0 R /Helv 42 0 R >> /Encoding << /PDFDocEncoding 43 0 R >> >> /DA (/Helv 0 Tf 0 g ) >> endobj 41 0 obj << /Type /Font /Name /ZaDb /BaseFont /ZapfDingbats /Subtype /Type1 >> endobj 42 0 obj << /Type /Font /Name /Helv /BaseFont /Helvetica /Subtype /Type1 /Encoding 43 0 R >> endobj 43 0 obj << /Type /Encoding /Differences [ 24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde 39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright /minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 160 /Euro 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot /.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine 188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] >> endobj xref 0 44 0000000007 65535 f 0000000016 00000 n 0000000167 00000 n 0000000301 00000 n 0000001995 00000 n 0000002146 00000 n 0000002280 00000 n 0000000008 00001 f 0000000009 00001 f 0000000017 00001 f 0000005214 00000 n 0000005368 00000 n 0000005503 00000 n 0000007734 00000 n 0000007888 00000 n 0000008023 00000 n 0000010013 00001 n 0000000018 00001 f 0000000022 00001 f 0000011479 00000 n 0000011633 00000 n 0000011768 00000 n 0000000023 00001 f 0000000026 00001 f 0000014864 00000 n 0000014963 00000 n 0000000027 00001 f 0000000038 00001 f 0000015203 00000 n 0000015294 00000 n 0000015448 00000 n 0000015583 00000 n 0000015805 00000 n 0000016308 00000 n 0000016347 00000 n 0000018373 00000 n 0000040687 00000 n 0000040765 00000 n 0000000039 00001 f 0000000000 00001 f 0000043442 00000 n 0000043589 00000 n 0000043681 00000 n 0000043788 00000 n trailer << /Size 44 /Info 25 0 R /Root 28 0 R /ID[<6d115667785bf532af1e7e60c1e4b949>] >> startxref 45137 %%EOF tomcat7-7.0.52/webapps/docs/architecture/requestProcess/0000755000175100017510000000000012301126373023243 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/architecture/requestProcess/roseModel.mdl0000644000175100017510000124317012271304167025707 0ustar locutuslocutus (object Petal version 45 _written "Rose 7.6.0109.2314" charSet 0) (object Design "Logical View" is_unit TRUE is_loaded TRUE quid "3DFDF6CE0337" defaults (object defaults rightMargin 0.250000 leftMargin 0.250000 topMargin 0.250000 bottomMargin 0.500000 pageOverlap 0.250000 clipIconLabels TRUE autoResize TRUE snapToGrid TRUE gridX 16 gridY 16 defaultFont (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) showMessageNum 1 showClassOfObject TRUE notation "Unified") root_usecase_package (object Class_Category "Use Case View" quid "3DFDF6CE0369" exportControl "Public" global TRUE logical_models (list unit_reference_list) logical_presentations (list unit_reference_list (object UseCaseDiagram "Main" quid "3DFDF6D201FE" title "Main" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list)))) root_category (object Class_Category "Logical View" quid "3DFDF6CE0338" exportControl "Public" global TRUE subsystem "Component View" quidu "3DFDF6CE036A" logical_models (list unit_reference_list (object Class_Category "org.apache.catalina" quid "3E42DE8D0082" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E42DEF601EB" supplier "Logical View::org.apache.tomcat.util" quidu "3E42DEDF01F2") (object Visibility_Relationship quid "3E42DF700060" supplier "Logical View::org.apache.coyote" quidu "3E42DE9F0132") (object Visibility_Relationship quid "3E43D165039C" supplier "Logical View::org.apache.naming" quidu "3E43D1580339")) exportControl "Public" logical_models (list unit_reference_list (object Class_Category "ant" quid "3E42DFBB037F" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43CFF7020F" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "authenticator" quid "3E42DFC702B4" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D03C0395" supplier "Logical View::org.apache.catalina::deploy" quidu "3E42DFDC0340") (object Visibility_Relationship quid "3E43D03F01C2" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184") (object Visibility_Relationship quid "3E43D043024A" supplier "Logical View::org.apache.catalina::valves" quidu "3E42E02D035B")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "connector" quid "3E42DFCF036A" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D07E017D" supplier "Logical View::org.apache.catalina::session" quidu "3E42E00C026D")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "core" quid "3E42DFD603BA" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D19E01A9" supplier "Logical View::org.apache.catalina::deploy" quidu "3E42DFDC0340") (object Visibility_Relationship quid "3E43D1A10185" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184") (object Visibility_Relationship quid "3E43D1CE007C" supplier "Logical View::org.apache.catalina::connector" quidu "3E42DFCF036A") (object Visibility_Relationship quid "3E43D1D800D0" supplier "Logical View::org.apache.catalina::security" quidu "3E42E00100D7") (object Visibility_Relationship quid "3E43D25C031F" supplier "Logical View::org.apache.catalina::mbean" quidu "3E42DFF10188") (object Visibility_Relationship quid "3E43D260028E" supplier "Logical View::org.apache.catalina::startup" quidu "3E42E01E00EC") (object Visibility_Relationship quid "3E43D26A015C" supplier "Logical View::org.apache.catalina::session" quidu "3E42E00C026D") (object Visibility_Relationship quid "3E43D2830271" supplier "Logical View::org.apache.catalina::valves" quidu "3E42E02D035B") (object Visibility_Relationship quid "3E43D2C80248" supplier "Logical View::org.apache.catalina::net" quidu "3E42DFF70227") (object Visibility_Relationship quid "3E43D2D6002B" supplier "Logical View::org.apache.catalina::loader" quidu "3E43D2D002D6") (object Visibility_Relationship quid "3E43D3D300F7" supplier "Logical View::org.apache.naming" quidu "3E43D1580339")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "deploy" quid "3E42DFDC0340" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D32001B8" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "launcher" quid "3E42DFE2033F" exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "logger" quid "3E42DFEC0285" exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "mbean" quid "3E42DFF10188" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D49101A5" supplier "Logical View::org.apache.catalina::deploy" quidu "3E42DFDC0340") (object Visibility_Relationship quid "3E43D4C6027D" supplier "Logical View::org.apache.catalina::core" quidu "3E42DFD603BA") (object Visibility_Relationship quid "3E43D4FB008F" supplier "Logical View::org.apache.catalina::session" quidu "3E42E00C026D") (object Visibility_Relationship quid "3E43D50000BE" supplier "Logical View::org.apache.catalina::valves" quidu "3E42E02D035B") (object Visibility_Relationship quid "3E43D5080278" supplier "Logical View::org.apache.catalina::realm" quidu "3E42DFFA00AE") (object Visibility_Relationship quid "3E43D55A0258" supplier "Logical View::org.apache.catalina::logger" quidu "3E42DFEC0285") (object Visibility_Relationship quid "3E43D56000D0" supplier "Logical View::org.apache.catalina::authenticator" quidu "3E42DFC702B4")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "net" quid "3E42DFF70227" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D6390371" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "realm" quid "3E42DFFA00AE" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D69F0133" supplier "Logical View::org.apache.catalina::core" quidu "3E42DFD603BA") (object Visibility_Relationship quid "3E43D6A10353" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184") (object Visibility_Relationship quid "3E43D70E00E2" supplier "Logical View::org.apache.naming" quidu "3E43D1580339") (object Visibility_Relationship quid "3E43D72302D7" supplier "Logical View::org.apache.catalina::deploy" quidu "3E42DFDC0340")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "security" quid "3E42E00100D7" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D74D007F" supplier "Logical View::org.apache.catalina::startup" quidu "3E42E01E00EC") (object Visibility_Relationship quid "3E43D76B0371" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "servlets" quid "3E42E00502DB" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D82702E5" supplier "Logical View::org.apache.tomcat.util" quidu "3E42DEDF01F2") (object Visibility_Relationship quid "3E43D82A02CC" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184") (object Visibility_Relationship quid "3E43D82D0244" supplier "Logical View::org.apache.naming" quidu "3E43D1580339")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "session" quid "3E42E00C026D" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D8770344" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "ssi" quid "3E42E01002C3" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D8F902B5" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "startup" quid "3E42E01E00EC" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D9150251" supplier "Logical View::org.apache.catalina::logger" quidu "3E42DFEC0285") (object Visibility_Relationship quid "3E43D919018F" supplier "Logical View::org.apache.catalina::security" quidu "3E42E00100D7") (object Visibility_Relationship quid "3E43D946000D" supplier "Logical View::org.apache.catalina::core" quidu "3E42DFD603BA") (object Visibility_Relationship quid "3E43D95E012A" supplier "Logical View::org.apache.catalina::loader" quidu "3E43D2D002D6") (object Visibility_Relationship quid "3E43D9960315" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184") (object Visibility_Relationship quid "3E43D99902BF" supplier "Logical View::org.apache.catalina::valves" quidu "3E42E02D035B") (object Visibility_Relationship quid "3E43D99C0147" supplier "Logical View::org.apache.catalina::deploy" quidu "3E42DFDC0340") (object Visibility_Relationship quid "3E43D9DA0114" supplier "Logical View::org.apache.catalina::net" quidu "3E42DFF70227") (object Visibility_Relationship quid "3E43D9F402F2" supplier "Logical View::org.apache.catalina::realm" quidu "3E42DFFA00AE")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "user" quid "3E42E0220174" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43DB240227" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184") (object Visibility_Relationship quid "3E43DB31009F" supplier "Logical View::org.apache.naming" quidu "3E43D1580339")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "util" quid "3E42E0260184" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43DB85017C" supplier "Logical View::org.apache.catalina::core" quidu "3E42DFD603BA") (object Visibility_Relationship quid "3E43DB88016C" supplier "Logical View::org.apache.naming" quidu "3E43D1580339")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "valves" quid "3E42E02D035B" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43DC2B0257" supplier "Logical View::org.apache.catalina::util" quidu "3E42E0260184") (object Visibility_Relationship quid "3E43DD3E0271" supplier "Logical View::org.apache.catalina::deploy" quidu "3E42DFDC0340") (object Visibility_Relationship quid "3E43DD4102CF" supplier "Logical View::org.apache.catalina::connector" quidu "3E42DFCF036A") (object Visibility_Relationship quid "3E43DDDE00B8" supplier "Logical View::org.apache.catalina::core" quidu "3E42DFD603BA")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "loader" quid "3E43D2D002D6" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E43D3CF00F2" supplier "Logical View::org.apache.naming" quidu "3E43D1580339")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list))) logical_presentations (list unit_reference_list (object ClassDiagram "Main" quid "3E42DFB6010B" title "Main" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list (object CategoryView "Logical View::org.apache.catalina::ant" @1 location (2208, 1504) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @1 location (2064, 1420) fill_color 13434879 nlines 2 max_width 288 justify 0 label "ant") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFBB037F" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::authenticator" @2 location (192, 2000) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @2 location (48, 1916) fill_color 13434879 nlines 2 max_width 288 justify 0 label "authenticator") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFC702B4" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::connector" @3 location (464, 1328) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @3 location (320, 1244) fill_color 13434879 nlines 2 max_width 288 justify 0 label "connector") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFCF036A" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::core" @4 location (2224, 800) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @4 location (2080, 716) fill_color 13434879 nlines 2 max_width 288 justify 0 label "core") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFD603BA" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::deploy" @5 location (240, 160) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @5 location (96, 76) fill_color 13434879 nlines 2 max_width 288 justify 0 label "deploy") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFDC0340" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::launcher" @6 location (1776, 2480) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @6 location (1632, 2396) fill_color 13434879 nlines 2 max_width 288 justify 0 label "launcher") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFE2033F" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::logger" @7 location (752, 128) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @7 location (608, 44) fill_color 13434879 nlines 2 max_width 288 justify 0 label "logger") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFEC0285" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::mbean" @8 location (2208, 1216) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @8 location (2064, 1132) fill_color 13434879 nlines 2 max_width 288 justify 0 label "mbean") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFF10188" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::net" @9 location (1056, 2496) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @9 location (912, 2412) fill_color 13434879 nlines 2 max_width 288 justify 0 label "net") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFF70227" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::realm" @10 location (1248, 112) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @10 location (1104, 28) fill_color 13434879 nlines 2 max_width 288 justify 0 label "realm") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DFFA00AE" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::security" @11 location (304, 2496) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @11 location (160, 2412) fill_color 13434879 nlines 2 max_width 288 justify 0 label "security") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E00100D7" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::servlets" @12 location (2096, 1888) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @12 location (1952, 1804) fill_color 13434879 nlines 2 max_width 288 justify 0 label "servlets") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E00502DB" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::session" @13 location (432, 1696) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @13 location (288, 1612) fill_color 13434879 nlines 2 max_width 288 justify 0 label "session") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E00C026D" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::ssi" @14 location (672, 2480) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @14 location (528, 2393) fill_color 13434879 nlines 2 max_width 288 justify 0 label "ssi") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E01002C3" width 301 height 187) (object CategoryView "Logical View::org.apache.catalina::startup" @15 location (1088, 832) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @15 location (944, 748) fill_color 13434879 nlines 2 max_width 288 justify 0 label "startup") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E01E00EC" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::user" @16 location (1424, 2496) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @16 location (1280, 2412) fill_color 13434879 nlines 2 max_width 288 justify 0 label "user") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E0220174" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::util" @17 location (1312, 1872) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @17 location (1168, 1788) fill_color 13434879 nlines 2 max_width 288 justify 0 label "util") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E0260184" width 300 height 180) (object CategoryView "Logical View::org.apache.catalina::valves" @18 location (304, 704) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @18 location (160, 620) fill_color 13434879 nlines 2 max_width 288 justify 0 label "valves") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42E02D035B" width 300 height 180) (object ImportView "" @19 stereotype TRUE line_color 3342489 quidu "3E43CFF7020F" client @1 supplier @17 line_style 0) (object ImportView "" @20 stereotype TRUE line_color 3342489 quidu "3E43D07E017D" client @3 supplier @13 line_style 0) (object CategoryView "Logical View::org.apache.catalina::loader" @21 location (2240, 416) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @21 location (2096, 332) fill_color 13434879 nlines 2 max_width 288 justify 0 label "loader") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E43D2D002D6" width 300 height 180) (object ImportView "" @22 stereotype TRUE line_color 3342489 quidu "3E43D32001B8" client @5 supplier @17 line_style 0) (object CategoryView "Logical View::org.apache.naming" @23 location (1872, 96) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @23 location (1699, 12) fill_color 13434879 nlines 2 max_width 346 justify 0 label "org.apache.naming") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E43D1580339" width 358 height 180) (object ImportView "" @24 stereotype TRUE line_color 3342489 quidu "3E43D3CF00F2" client @21 supplier @23 line_style 0) (object ImportView "" @25 stereotype TRUE line_color 3342489 quidu "3E43D6390371" client @9 supplier @17 line_style 0) (object ImportView "" @26 stereotype TRUE line_color 3342489 quidu "3E43D69F0133" client @10 supplier @4 line_style 0) (object ImportView "" @27 stereotype TRUE line_color 3342489 quidu "3E43D6A10353" client @10 supplier @17 line_style 0) (object ImportView "" @28 stereotype TRUE line_color 3342489 quidu "3E43D70E00E2" client @10 supplier @23 line_style 0) (object ImportView "" @29 stereotype TRUE line_color 3342489 quidu "3E43D72302D7" client @10 supplier @5 line_style 0) (object ImportView "" @30 stereotype TRUE line_color 3342489 quidu "3E43D69F0133" client @10 supplier @4 line_style 0) (object ImportView "" @31 stereotype TRUE line_color 3342489 quidu "3E43D74D007F" client @11 supplier @15 line_style 0) (object ImportView "" @32 stereotype TRUE line_color 3342489 quidu "3E43D76B0371" client @11 supplier @17 line_style 0) (object CategoryView "Logical View::org.apache.tomcat.util" @33 location (2096, 2224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @33 location (1923, 2140) fill_color 13434879 nlines 2 max_width 346 justify 0 label "org.apache.tomcat.util") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DEDF01F2" width 358 height 180) (object ImportView "" @34 stereotype TRUE line_color 3342489 quidu "3E43D8770344" client @13 supplier @17 line_style 0) (object ImportView "" @35 stereotype TRUE line_color 3342489 quidu "3E43D8F902B5" client @14 supplier @17 line_style 0) (object ImportView "" @36 stereotype TRUE line_color 3342489 quidu "3E43DB240227" client @16 supplier @17 line_style 0) (object ImportView "" @37 stereotype TRUE line_color 3342489 quidu "3E43DB31009F" client @16 supplier @23 line_style 0) (object ImportView "" @38 stereotype TRUE line_color 3342489 quidu "3E43DB85017C" client @17 supplier @4 line_style 0) (object ImportView "" @39 stereotype TRUE line_color 3342489 quidu "3E43DB88016C" client @17 supplier @23 line_style 0) (object ImportView "" @40 stereotype TRUE line_color 3342489 quidu "3E43D82702E5" client @12 supplier @33 line_style 0) (object ImportView "" @41 stereotype TRUE line_color 3342489 quidu "3E43D82A02CC" client @12 supplier @17 line_style 0) (object ImportView "" @42 stereotype TRUE line_color 3342489 quidu "3E43D82D0244" client @12 supplier @23 vertices (list Points (2060, 1743) (1746, 447) (1838, 186)) line_style 0) (object ImportView "" @43 stereotype TRUE line_color 3342489 quidu "3E43D919018F" client @15 supplier @11 line_style 0) (object ImportView "" @44 stereotype TRUE line_color 3342489 quidu "3E43D946000D" client @15 supplier @4 line_style 0) (object ImportView "" @45 stereotype TRUE line_color 3342489 quidu "3E43D95E012A" client @15 supplier @21 line_style 0) (object ImportView "" @46 stereotype TRUE line_color 3342489 quidu "3E43D95E012A" client @15 supplier @21 line_style 0) (object ImportView "" @47 stereotype TRUE line_color 3342489 quidu "3E43D9960315" client @15 supplier @17 line_style 0) (object ImportView "" @48 stereotype TRUE line_color 3342489 quidu "3E43D99902BF" client @15 supplier @18 line_style 0) (object ImportView "" @49 stereotype TRUE line_color 3342489 quidu "3E43D99C0147" client @15 supplier @5 line_style 0) (object ImportView "" @50 stereotype TRUE line_color 3342489 quidu "3E43D946000D" client @15 supplier @4 line_style 0) (object ImportView "" @51 stereotype TRUE line_color 3342489 quidu "3E43D9150251" client @15 supplier @7 line_style 0) (object ImportView "" @52 stereotype TRUE line_color 3342489 quidu "3E43D9DA0114" client @15 supplier @9 line_style 0) (object ImportView "" @53 stereotype TRUE line_color 3342489 quidu "3E43D9F402F2" client @15 supplier @10 line_style 0) (object ImportView "" @54 stereotype TRUE line_color 3342489 quidu "3E43D9960315" client @15 supplier @17 line_style 0) (object ImportView "" @55 stereotype TRUE line_color 3342489 quidu "3E43D946000D" client @15 supplier @4 line_style 0) (object ImportView "" @56 stereotype TRUE line_color 3342489 quidu "3E43D99C0147" client @15 supplier @5 line_style 0) (object ImportView "" @57 stereotype TRUE line_color 3342489 quidu "3E43D49101A5" client @8 supplier @5 line_style 0) (object ImportView "" @58 stereotype TRUE line_color 3342489 quidu "3E43D4C6027D" client @8 supplier @4 line_style 0) (object ImportView "" @59 stereotype TRUE line_color 3342489 quidu "3E43D4FB008F" client @8 supplier @13 line_style 0) (object ImportView "" @60 stereotype TRUE line_color 3342489 quidu "3E43D50000BE" client @8 supplier @18 vertices (list Points (2057, 1216) (1278, 1216) (454, 783)) line_style 0) (object ImportView "" @61 stereotype TRUE line_color 3342489 quidu "3E43D5080278" client @8 supplier @10 line_style 0) (object ImportView "" @62 stereotype TRUE line_color 3342489 quidu "3E43D55A0258" client @8 supplier @7 line_style 0) (object ImportView "" @63 stereotype TRUE line_color 3342489 quidu "3E43D56000D0" client @8 supplier @2 line_style 0) (object ImportView "" @64 stereotype TRUE line_color 3342489 quidu "3E43D19E01A9" client @4 supplier @5 line_style 0) (object ImportView "" @65 stereotype TRUE line_color 3342489 quidu "3E43D1A10185" client @4 supplier @17 line_style 0) (object ImportView "" @66 stereotype TRUE line_color 3342489 quidu "3E43D1CE007C" client @4 supplier @3 line_style 0) (object ImportView "" @67 stereotype TRUE line_color 3342489 quidu "3E43D1D800D0" client @4 supplier @11 vertices (list Points (2081, 890) (959, 1616) (409, 2351)) line_style 0) (object ImportView "" @68 stereotype TRUE line_color 3342489 quidu "3E43D25C031F" client @4 supplier @8 line_style 0) (object ImportView "" @69 stereotype TRUE line_color 3342489 quidu "3E43D260028E" client @4 supplier @15 line_style 0) (object ImportView "" @70 stereotype TRUE line_color 3342489 quidu "3E43D26A015C" client @4 supplier @13 line_style 0) (object ImportView "" @71 stereotype TRUE line_color 3342489 quidu "3E43D2830271" client @4 supplier @18 line_style 0) (object ImportView "" @72 stereotype TRUE line_color 3342489 quidu "3E43D2C80248" client @4 supplier @9 line_style 0) (object ImportView "" @73 stereotype TRUE line_color 3342489 quidu "3E43D2D6002B" client @4 supplier @21 line_style 0) (object ImportView "" @74 stereotype TRUE line_color 3342489 quidu "3E43D3D300F7" client @4 supplier @23 line_style 0) (object ImportView "" @75 stereotype TRUE line_color 3342489 quidu "3E43D03C0395" client @2 supplier @5 vertices (list Points (171, 1855) (16, 766) (205, 250)) line_style 0) (object ImportView "" @76 stereotype TRUE line_color 3342489 quidu "3E43D03F01C2" client @2 supplier @17 line_style 0) (object ImportView "" @77 stereotype TRUE line_color 3342489 quidu "3E43D043024A" client @2 supplier @18 line_style 0) (object ImportView "" @78 stereotype TRUE line_color 3342489 quidu "3E43DC2B0257" client @18 supplier @17 line_style 0) (object ImportView "" @79 stereotype TRUE line_color 3342489 quidu "3E43DD3E0271" client @18 supplier @5 line_style 0) (object ImportView "" @80 stereotype TRUE line_color 3342489 quidu "3E43DD4102CF" client @18 supplier @3 line_style 0) (object ImportView "" @81 stereotype TRUE line_color 3342489 quidu "3E43DDDE00B8" client @18 supplier @4 vertices (list Points (454, 654) (1293, 381) (2073, 731)) line_style 0))))) (object Class_Category "org.apache.coyote" quid "3E42DE9F0132" visible_categories (list visibility_relationship_list (object Visibility_Relationship quid "3E42DEFC00B3" supplier "Logical View::org.apache.tomcat.util" quidu "3E42DEDF01F2")) exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "org.apache.tomcat.util" quid "3E42DEDF01F2" exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "org.apache.jasper" quid "3E42DEFF0270" exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Class_Category "org.apache.naming" quid "3E43D1580339" exportControl "Public" logical_models (list unit_reference_list) logical_presentations (list unit_reference_list)) (object Mechanism @82 logical_models (list unit_reference_list (object Object "Bootstrap" quid "3DFDF8FD0345" collaborators (list link_list (object Link quid "3DFDF9210008" supplier "Bootstrap" quidu "3DFDF8FD0345" messages (list Messages (object Message "initClassLoaders()" quid "3DFDF9210009" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE))) (object Link quid "3DFDF91A010C" supplier "Catalina" quidu "3DFDF90A0330" messages (list Messages (object Message "newInstance()" quid "3DFDF91A010D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 1 quidu "000000000000" creation FALSE) (object Message "setParentClassLoader()" quid "3DFDF97900C2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3" ordinal 2 quidu "000000000000" creation FALSE) (object Message "load()" quid "3DFDFA3402F2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "4" ordinal 3 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "Digester" quid "3DFDFAF201A1" collaborators (list link_list (object Link quid "3DFDFB8400A6" supplier "ServerLifecycleListener" quidu "3DFDFB4B0217" messages (list Messages (object Message "newInstance()" quid "3DFDFB8400A7" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "9.1" ordinal 9 quidu "000000000000" creation FALSE))) (object Link quid "3DFDFB920147" supplier "GlobalResourcesLifecycleListener" quidu "3DFDFB7A02AB" messages (list Messages (object Message "newInstance()" quid "3DFDFB920148" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "9.2" ordinal 10 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "ServerLifecycleListener" quid "3DFDFB4B0217" persistence "Transient" creationObj FALSE multi FALSE) (object Object "GlobalResourcesLifecycleListener" quid "3DFDFB7A02AB" persistence "Transient" creationObj FALSE multi FALSE) (object Object "SecurityConfig" quid "3DFDFBD802BA" persistence "Transient" creationObj FALSE multi FALSE) (object Object "Catalina" quid "3DFDF90A0330" collaborators (list link_list (object Link quid "3DFDFA8001D9" supplier "Catalina" quidu "3DFDF90A0330" messages (list Messages (object Message "initDirs()" quid "3DFDFA8001DA" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "5" ordinal 4 quidu "000000000000" creation FALSE) (object Message "initNaming()" quid "3DFDFA8B0347" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "6" ordinal 5 quidu "000000000000" creation FALSE) (object Message "initialize()" quid "3DFDFAAD01AC" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "7" ordinal 6 quidu "000000000000" creation FALSE))) (object Link quid "3DFDFAF800C3" supplier "Digester" quidu "3DFDFAF201A1" messages (list Messages (object Message "createDigester()" quid "3DFDFAF800C4" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8" ordinal 7 quidu "000000000000" creation FALSE) (object Message "parse()" quid "3DFDFB0100B2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "9" ordinal 8 quidu "000000000000" creation FALSE))) (object Link quid "3DFDFBEA00C1" supplier "SecurityConfig" quidu "3DFDFBD802BA" messages (list Messages (object Message "newInstance()" quid "3DFDFBEA00C2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "10" ordinal 11 quidu "000000000000" creation FALSE) (object Message "setPackageDefinition()" quid "3DFDFBF401F2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "11" ordinal 12 Operation "setPackageDefinition" quidu "000000000000" creation FALSE) (object Message "setPackageAccess()" quid "3DFDFC1203C2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "12" ordinal 13 Operation "setPackageAccess" quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @83 logical_models (list unit_reference_list (object Object "Catalina" quid "3DFDFC8F015F" collaborators (list link_list (object Link quid "3DFDFD1F0075" supplier "StandardServer" quidu "3DFDFCCB006B" messages (list Messages (object Message "initialize()" quid "3DFDFD1F0076" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardServer" quid "3DFDFCCB006B" collaborators (list link_list (object Link quid "3DFDFD3D01C3" supplier "StandardService" quidu "3DFDFD370020" messages (list Messages (object Message "initialize()" quid "3DFDFD3D01C4" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 1 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardService" quid "3DFDFD370020" collaborators (list link_list (object Link quid "3DFDFE990304" supplier "CoyoteConnector" quidu "3DFDFE810313" messages (list Messages (object Message "initialize()" quid "3DFDFE990305" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.1" ordinal 2 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "CoyoteConnector" quid "3DFDFE810313" collaborators (list link_list (object Link quid "3DFE013D0216" supplier "CoyoteAdapter" quidu "3DFDFFA00226" messages (list Messages (object Message "new()" quid "3DFE013D0217" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.1.1" ordinal 3 quidu "000000000000" creation FALSE))) (object Link quid "3DFE0183032F" supplier "Http11Protocol" quidu "3DFE016601A6" messages (list Messages (object Message "new()" quid "3DFE01830330" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.1.2" ordinal 4 quidu "000000000000" creation FALSE) (object Message "init()" quid "3DFE0188032C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.1.3" ordinal 5 quidu "000000000000" creation FALSE))) (object Link quid "3DFE01BC038B" supplier "JkCoyoteAdapter" quidu "3DFE01AD01A8" messages (list Messages (object Message "new()" quid "3DFE01BC038C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.1.4" ordinal 6 quidu "000000000000" creation FALSE) (object Message "init()" quid "3DFE01C30164" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.1.5" ordinal 7 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "CoyoteAdapter" quid "3DFDFFA00226" persistence "Transient" creationObj FALSE multi FALSE) (object Object "Http11Protocol" quid "3DFE016601A6" persistence "Transient" creationObj FALSE multi FALSE) (object Object "JkCoyoteAdapter" quid "3DFE01AD01A8" persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @84 logical_models (list unit_reference_list (object Object "Bootstrap" quid "3DFE027700F5" collaborators (list link_list (object Link quid "3DFE02830373" supplier "Catalina" quidu "3DFE027D0067" messages (list Messages (object Message "start()" quid "3DFE02830374" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "Catalina" quid "3DFE027D0067" collaborators (list link_list (object Link quid "3DFE02BA0187" supplier "StandardServer" quidu "3DFE02B30015" messages (list Messages (object Message "start()" quid "3DFE02BA0188" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1" ordinal 1 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardServer" quid "3DFE02B30015" collaborators (list link_list (object Link quid "3DFE02D3006B" supplier "StandardServer" quidu "3DFE02B30015" messages (list Messages (object Message "fireLifecycleEvent(BEFORE_START_EVENT)" quid "3DFE02D3006C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.1" ordinal 2 quidu "000000000000" creation FALSE) (object Message "fireLifecycleEvent(START_EVENT)" quid "3DFE02DF02DF" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.2" ordinal 3 quidu "000000000000" creation FALSE))) (object Link quid "3DFE030C02B2" supplier "StandardService" quidu "3DFE030400E3" messages (list Messages (object Message "start()" quid "3DFE030C02B3" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.3" ordinal 4 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardService" quid "3DFE030400E3" collaborators (list link_list (object Link quid "3DFE031D0021" supplier "StandardService" quidu "3DFE030400E3" messages (list Messages (object Message "fireLifecycleEvent(BEFORE_START_EVENT)" quid "3DFE031D0022" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.3.1" ordinal 5 quidu "000000000000" creation FALSE) (object Message "fireLifecycleEvent(START_EVENT)" quid "3DFE0330019B" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.3.2" ordinal 6 quidu "000000000000" creation FALSE))) (object Link quid "3DFE03700189" supplier "StandardEngine" quidu "3DFE034700C2" messages (list Messages (object Message "start()" quid "3DFE0370018A" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.3.3" ordinal 7 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardEngine" quid "3DFE034700C2" collaborators (list link_list (object Link quid "3DFE03750050" supplier "StandardEngine" quidu "3DFE034700C2" messages (list Messages (object Message "fireLifecycleEvent(BEFORE_START_EVENT)" quid "3DFE03750051" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 8 quidu "000000000000" creation FALSE) (object Message "addDefaultMapper()" quid "3DFE0389001C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3" ordinal 9 quidu "000000000000" creation FALSE) (object Message "logger.start()" quid "3DFE03980281" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "4" ordinal 10 quidu "000000000000" creation FALSE) (object Message "realm.start()" quid "3DFE03A80107" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "5" ordinal 11 quidu "000000000000" creation FALSE) (object Message "findMappers()" quid "3DFE03BD000D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "6" ordinal 12 quidu "000000000000" creation FALSE) (object Message "findChildren()" quid "3DFE03E000A4" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "7" ordinal 13 quidu "000000000000" creation FALSE))) (object Link quid "3DFE03FB0279" supplier "StandardHost" quidu "3DFE03F2035D" messages (list Messages (object Message "start()" quid "3DFE03FB027A" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8" ordinal 14 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardHost" quid "3DFE03F2035D" collaborators (list link_list (object Link quid "3DFE043B02AD" supplier "StandardHost" quidu "3DFE03F2035D" messages (list Messages (object Message "fireLifecycleEvent(BEFORE_START_EVENT)" quid "3DFE043B02AE" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.1" ordinal 15 quidu "000000000000" creation FALSE) (object Message "addDefaultMapper()" quid "3DFE045C021F" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.2" ordinal 16 quidu "000000000000" creation FALSE) (object Message "logger.start()" quid "3DFE049B000C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.3" ordinal 17 quidu "000000000000" creation FALSE) (object Message "findMapper()" quid "3DFE04A303BB" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.4" ordinal 18 quidu "000000000000" creation FALSE) (object Message "findChildren()" quid "3DFE04A90342" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.5" ordinal 19 Operation "findChildren" quidu "000000000000" creation FALSE))) (object Link quid "3DFE048E00B8" supplier "StandardPipeline" quidu "3DFE047D006D" messages (list Messages (object Message "start()" quid "3DFE048E00B9" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.6" ordinal 20 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardPipeline" quid "3DFE047D006D" collaborators (list link_list (object Link quid "3DFE05780137" supplier "StandardPipeline" quidu "3DFE047D006D" messages (list Messages (object Message "fireLifecycleEvent(BEFORE_START_EVENT)" quid "3DFE05780138" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.6.1" ordinal 21 Operation "fireLifecycleEvent(AFTER_START_EVENT)" quidu "000000000000" creation FALSE) (object Message "fireLifecycleEvent(START_EVENT)" quid "3DFE05A80398" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.6.2" ordinal 22 Operation "fireLifecycleEvent(BEFORE_START_EVENT)" quidu "000000000000" creation FALSE) (object Message "fireLifecycleEvent(AFTER_EVENT)" quid "3DFE05BA0196" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "8.6.3" ordinal 23 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @85 logical_models (list unit_reference_list (object Object "StandardHost" quid "3DFE0538017B" collaborators (list link_list (object Link quid "3DFE066C0340" supplier "StandardHost" quidu "3DFE0538017B" messages (list Messages (object Message "fireLifecycleEvent(START_EVENT)" quid "3DFE066C0341" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE))) (object Link quid "3DFE06D20293" supplier "HostConfig" quidu "3DFE06A60131" messages (list Messages (object Message "interested[i].lifecycleEvent()" quid "3DFE06D20294" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 1 quidu "000000000000" creation FALSE) (object Message "install()" quid "3DFE078B03BB" frequency "Aperiodic" synchronization "Simple" dir "ToClientFromSupplier" sequence "2.6" ordinal 7 quidu "000000000000" creation FALSE) (object Message "install()" quid "3DFE132D0309" frequency "Aperiodic" synchronization "Simple" dir "ToClientFromSupplier" sequence "5" ordinal 13 quidu "000000000000" creation FALSE))) (object Link quid "3DFE07B100BD" supplier "StandardHostDeployer" quidu "3DFE079A0055" messages (list Messages (object Message "install()" quid "3DFE07B100BE" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3" ordinal 8 quidu "000000000000" creation FALSE) (object Message "install() // same as above" quid "3DFE133A036C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "6" ordinal 17 Operation "install()" quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "HostConfig" quid "3DFE06A60131" collaborators (list link_list (object Link quid "3DFE06E9028C" supplier "HostConfig" quidu "3DFE06A60131" messages (list Messages (object Message "setDeployXML()" quid "3DFE06E9028D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.1" ordinal 2 quidu "000000000000" creation FALSE) (object Message "setLiveDeploy()" quid "3DFE06F300FF" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.2" ordinal 3 quidu "000000000000" creation FALSE) (object Message "setUnpacksWar()" quid "3DFE06FB00D9" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.3" ordinal 4 quidu "000000000000" creation FALSE) (object Message "setXMLValidation()" quid "3DFE070C0015" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.4" ordinal 5 quidu "000000000000" creation FALSE) (object Message "deployDescriptors()" quid "3DFE073B0031" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2.5" ordinal 6 quidu "000000000000" creation FALSE) (object Message "deployApps()" quid "3DFE131F0327" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "4" ordinal 12 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardHostDeployer" quid "3DFE079A0055" collaborators (list link_list (object Link quid "3DFE07D200EC" supplier "Digester" quidu "3DFE07C9034C" messages (list Messages (object Message "create()" quid "3DFE07D200ED" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1" ordinal 9 quidu "000000000000" creation FALSE) (object Message "parse()" quid "3DFE07D603D7" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.6" ordinal 16 quidu "000000000000" creation FALSE) (object Message "add(ContextRuleSet)" quid "3DFE08FA003D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.3" ordinal 11 quidu "000000000000" creation FALSE))) (object Link quid "3DFE087D01E2" supplier "StandardHostDeployer" quidu "3DFE079A0055") (object Link quid "3DFE08DA029A" supplier "ContextRuleSet" quidu "3DFE0834016F" messages (list Messages (object Message "new()" quid "3DFE08DA029B" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.2" ordinal 10 quidu "000000000000" creation FALSE) (object Message "add(NamingRuleSet())" quid "3DFE0907015F" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.5" ordinal 15 quidu "000000000000" creation FALSE))) (object Link quid "3DFE08E00090" supplier "NamingRuleSet" quidu "3DFE08D00173" messages (list Messages (object Message "new()" quid "3DFE08E00091" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.4" ordinal 14 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "Digester" quid "3DFE07C9034C" persistence "Transient" creationObj FALSE multi FALSE) (object Object "ContextRuleSet" quid "3DFE0834016F" persistence "Transient" creationObj FALSE multi FALSE) (object Object "NamingRuleSet" quid "3DFE08D00173" persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @86 logical_models (list unit_reference_list (object Object "Digester" quid "3DFE095A0371" collaborators (list link_list (object Link quid "3DFE0E7801DA" supplier "Digester" quidu "3DFE095A0371" messages (list Messages (object Message "parse" quid "3DFE0E7801DB" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE) (object Message "startElement()" quid "3DFE0F2F03D2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 1 quidu "000000000000" creation FALSE))) (object Link quid "3DFE0F400213" supplier "Rule" quidu "3DFE0E7400D0" messages (list Messages (object Message "begin()" quid "3DFE0F400214" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3" ordinal 2 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "Rule" quid "3DFE0E7400D0" collaborators (list link_list (object Link quid "3DFE0FD30265" supplier "StandardContext" quidu "3DFE0FC502A1" messages (list Messages (object Message "newInstance()" quid "3DFE0FD30266" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1" ordinal 3 quidu "000000000000" creation FALSE))) (object Link quid "3DFE102002E8" supplier "SetPropertiesRule" quidu "3DFE100303A4" messages (list Messages (object Message "begin()" quid "3DFE102002E9" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.2" ordinal 6 quidu "000000000000" creation FALSE))) (object Link quid "3DFE127F0024" supplier "Rule" quidu "3DFE0E7400D0") (object Link quid "3DFE128501C7" supplier "SetNextRule" quidu "3DFE12690267" messages (list Messages (object Message "end()" quid "3DFE128501C8" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.3" ordinal 8 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardContext" quid "3DFE0FC502A1" collaborators (list link_list (object Link quid "3DFE114A0192" supplier "StandardPipeline" quidu "3DFE112F003F" messages (list Messages (object Message "setBasic(StandardContextValve)" quid "3DFE114A0193" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.2" ordinal 5 Operation "setBasic" quidu "000000000000" creation FALSE))) (object Link quid "3DFE115E001E" supplier "StandardContextValve" quidu "3DFE110D0375" messages (list Messages (object Message "new()" quid "3DFE115E001F" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1" ordinal 4 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "SetPropertiesRule" quid "3DFE100303A4" collaborators (list link_list (object Link quid "3DFE11D50390" supplier "StandardContext" quidu "3DFE0FC502A1" messages (list Messages (object Message "//Using BeanUtil, set the object properties (from ex: admin.xml)" quid "3DFE11D50391" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.2.1" ordinal 7 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardContextValve" quid "3DFE110D0375" persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardPipeline" quid "3DFE112F003F" persistence "Transient" creationObj FALSE multi FALSE) (object Object "SetNextRule" quid "3DFE12690267" persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @87 logical_models (list unit_reference_list (object Object "StandardContext" quid "3DFE196D00D9" collaborators (list link_list (object Link quid "3DFE200603BD" supplier "WebappLoader" quidu "3DFE1FFA0347" messages (list Messages (object Message "new" quid "3DFE200603BE" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.1" ordinal 5 quidu "000000000000" creation FALSE))) (object Link quid "3DFE200C0299" supplier "StandardContext" quidu "3DFE196D00D9" messages (list Messages (object Message "setLoader" quid "3DFE200C029A" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.2" ordinal 6 quidu "000000000000" creation FALSE) (object Message "setManager" quid "3DFE2032001C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.4" ordinal 8 quidu "000000000000" creation FALSE) (object Message "fireLifecycleEvent(START_EVENT)" quid "3DFE205B01A2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.5" ordinal 9 quidu "000000000000" creation FALSE))) (object Link quid "3DFE202C024F" supplier "StandardManager" quidu "3DFE201F0105" messages (list Messages (object Message "new" quid "3DFE202C0250" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.3" ordinal 7 quidu "000000000000" creation FALSE) (object Message "start()" quid "3DFE20B600E5" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.7" ordinal 12 quidu "000000000000" creation FALSE))) (object Link quid "3DFE20960002" supplier "ContextConfig" quidu "3DFE2087028C" messages (list Messages (object Message " // Notify interested LifecycleListeners" quid "3DFE20960003" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6" ordinal 10 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardHostDeployer" quid "3DFE1D8A02DC" collaborators (list link_list (object Link quid "3DFE1FAF0014" supplier "StandardHost" quidu "3DFE1DF20141" messages (list Messages (object Message "addChild" quid "3DFE1FB60277" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1" ordinal 3 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardHost" quid "3DFE1DF20141" collaborators (list link_list (object Link quid "3DFE1FC40227" supplier "StandardContext" quidu "3DFE196D00D9" messages (list Messages (object Message "start()" quid "3DFE1FC40228" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1" ordinal 4 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "WebappLoader" quid "3DFE1FFA0347" persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardManager" quid "3DFE201F0105" persistence "Transient" creationObj FALSE multi FALSE) (object Object "ContextConfig" quid "3DFE2087028C" collaborators (list link_list (object Link quid "3DFE20CF018B" supplier "ContextConfig" quidu "3DFE2087028C" messages (list Messages (object Message "start()" quid "3DFE20CF018C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.1" ordinal 11 quidu "000000000000" creation FALSE) (object Message "defaultConfig()" quid "3DFE20E303E2" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.2" ordinal 13 quidu "000000000000" creation FALSE) (object Message "applicationConfig()" quid "3DFE211D01A1" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.3" ordinal 14 Operation "applicationConfig" quidu "000000000000" creation FALSE))) (object Link quid "3DFE21B60287" supplier "Digester" quidu "3DFE13960364" messages (list Messages (object Message "create()" quid "3DFE21B60288" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.3.1" ordinal 15 quidu "000000000000" creation FALSE) (object Message "createWarpper() // Invoked by a WebWrapperRule (not Directly by the Digester)" quid "3DFE228B03BA" frequency "Aperiodic" synchronization "Simple" dir "ToClientFromSupplier" sequence "3.1.1.6.3.1.2" ordinal 17 Operation "createWarpper() // Invoked by a Rule (not Directly by the Digester)" quidu "000000000000" creation FALSE))) (object Link quid "3DFE22560061" supplier "StandardWrapper" quidu "3DFE220C0122" messages (list Messages (object Message "new" quid "3DFE229A0004" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.3.1.2.1" ordinal 18 quidu "000000000000" creation FALSE) (object Message "addInstanceListener()" quid "3DFE22A700C1" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.3.2" ordinal 19 Operation "addInstanceListener" quidu "000000000000" creation FALSE) (object Message "addLifecycleListener()" quid "3DFE22C701CC" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.3.3" ordinal 20 quidu "000000000000" creation FALSE) (object Message "addContainerListener()" quid "3DFE22E80364" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.3.4" ordinal 21 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj TRUE multi FALSE) (object Object "Digester" quid "3DFE13960364" collaborators (list link_list (object Link quid "3DFE19AE0064" supplier "Digester" quidu "3DFE13960364" messages (list Messages (object Message "parse" quid "3DFE19AE0065" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE) (object Message "startElement()" quid "3DFE19B102E9" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 1 quidu "000000000000" creation FALSE) (object Message "// Process web.xml * tld.xml" quid "3DFE21BE021B" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1.1.6.3.1.1" ordinal 16 quidu "000000000000" creation FALSE))) (object Link quid "3DFE1DFB0021" supplier "StandardHostDeployer" quidu "3DFE1D8A02DC" messages (list Messages (object Message "addChild" quid "3DFE1DFB0022" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3" ordinal 2 quidu "000000000000" creation FALSE))) (object Link quid "3DFE22190225" supplier "StandardWrapper" quidu "3DFE220C0122")) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardWrapper" quid "3DFE220C0122" persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @88 logical_models (list unit_reference_list (object Object "ThreadPool" quid "3DFE402B02C5" collaborators (list link_list (object Link quid "3DFE40E701AD" supplier "TcpWorkerThread" quidu "3DFE403200F8" messages (list Messages (object Message "runIt()" quid "3DFE40E701AE" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "TcpWorkerThread" quid "3DFE403200F8" collaborators (list link_list (object Link quid "3DFE40FC010D" supplier "Http11Protocol" quidu "3DFE40750177" messages (list Messages (object Message "processConnection" quid "3DFE40FC010E" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1" ordinal 1 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "Http11Protocol" quid "3DFE40750177" collaborators (list link_list (object Link quid "3DFE4111029E" supplier "Http11Protocol" quidu "3DFE40750177" messages (list Messages (object Message "process()" quid "3DFE4111029F" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.1" ordinal 2 quidu "000000000000" creation FALSE) (object Message "parseHeaders()" quid "3DFE415C0151" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 3 quidu "000000000000" creation FALSE) (object Message "prepareRequest()" quid "3DFE41A60161" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3" ordinal 4 quidu "000000000000" creation FALSE))) (object Link quid "3DFE41D60106" supplier "CoyoteAdapter" quidu "3DFE410600DF" messages (list Messages (object Message "service()" quid "3DFE41D60107" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "4" ordinal 5 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "CoyoteAdapter" quid "3DFE410600DF" collaborators (list link_list (object Link quid "3DFE422C01F0" supplier "CoyoteAdapter" quidu "3DFE410600DF" messages (list Messages (object Message "postParseRequest()" quid "3DFE422C01F1" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "5" ordinal 6 quidu "000000000000" creation FALSE))) (object Link quid "3DFE42800237" supplier "StandardEngine" quidu "3DFE424B0349" messages (list Messages (object Message "invoke()" quid "3DFE42800238" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "6" ordinal 7 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardEngine" quid "3DFE424B0349" collaborators (list link_list (object Link quid "3DFE429A002C" supplier "StandardPipeline" quidu "3DFE42900045" messages (list Messages (object Message "invoke()" quid "3DFE429A002D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "6.1" ordinal 8 Operation "invoke" quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardPipeline" quid "3DFE42900045" collaborators (list link_list (object Link quid "3DFE42CE022F" supplier "StandardValveContext" quidu "3DFE42C002B1" messages (list Messages (object Message "invoke()" quid "3DFE42CE0230" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "6.1.1" ordinal 9 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardValveContext" quid "3DFE42C002B1" persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @89 logical_models (list unit_reference_list (object Object "StandardContextValve" quid "3DFE4307001E" collaborators (list link_list (object Link quid "3DFE434C019A" supplier "StandardEngineValve" quidu "3DFE432801F3" messages (list Messages (object Message "invoke()" quid "3DFE434C019B" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE))) (object Link quid "3DFE43C203A3" supplier "ErrorReportValve" quidu "3DFE438C028D" messages (list Messages (object Message "invoke()" quid "3DFE43C203A4" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3" ordinal 4 quidu "000000000000" creation FALSE) (object Message "invokeNext()" quid "3DFE46330293" frequency "Aperiodic" synchronization "Simple" dir "ToClientFromSupplier" sequence "3.2" ordinal 6 quidu "000000000000" creation FALSE))) (object Link quid "3DFE46E70025" supplier "ErrorDispatcherValve" quidu "3DFE451F01EC" messages (list Messages (object Message "invoke()" quid "3DFE46E70026" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "4" ordinal 7 quidu "000000000000" creation FALSE) (object Message "invokeNext" quid "3DFE475D03A0" frequency "Aperiodic" synchronization "Simple" dir "ToClientFromSupplier" sequence "4.1" ordinal 8 quidu "000000000000" creation FALSE))) (object Link quid "3DFE476503C9" supplier "StandardHostValve" quidu "3DFE47310130" messages (list Messages (object Message "invoke()" quid "3DFE476503CA" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "5" ordinal 9 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardEngineValve" quid "3DFE432801F3" collaborators (list link_list (object Link quid "3DFE436C009C" supplier "StandardHost" quidu "3DFE436503BD" messages (list Messages (object Message "map()" quid "3DFE436C009D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1" ordinal 1 quidu "000000000000" creation FALSE) (object Message "invoke()" quid "3DFE43830063" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2" ordinal 2 quidu "000000000000" creation FALSE))) (object Link quid "3DFE437F0143" supplier "StandardEngineValve" quidu "3DFE432801F3")) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardHost" quid "3DFE436503BD" collaborators (list link_list (object Link quid "3DFE43B903BE" supplier "StandardContextValve" quidu "3DFE4307001E" messages (list Messages (object Message "invoke()" quid "3DFE43B903BF" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "2" ordinal 3 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "ErrorReportValve" quid "3DFE438C028D" collaborators (list link_list (object Link quid "3DFE442501B0" supplier "ErrorReportValve" quidu "3DFE438C028D" messages (list Messages (object Message "report()" quid "3DFE442501B1" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "3.1" ordinal 5 quidu "000000000000" creation FALSE))) (object Link quid "3DFE452A00F7" supplier "ErrorDispatcherValve" quidu "3DFE451F01EC")) persistence "Transient" creationObj FALSE multi FALSE) (object Object "ErrorDispatcherValve" quid "3DFE451F01EC" collaborators (list link_list (object Link quid "3DFE47500148" supplier "StandardHostValve" quidu "3DFE47310130") (object Link quid "3DFE47580335" supplier "ErrorDispatcherValve" quidu "3DFE451F01EC")) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardHostValve" quid "3DFE47310130" collaborators (list link_list (object Link quid "3DFE47CD0166" supplier "StandardHostValve" quidu "3DFE47310130" messages (list Messages (object Message "map() //Context" quid "3DFE47CD0167" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "5.1" ordinal 10 quidu "000000000000" creation FALSE))) (object Link quid "3DFE47D500B3" supplier "StandardContext" quidu "3DFE47C100F1" messages (list Messages (object Message "invoke()" quid "3DFE47D500B4" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "5.2" ordinal 11 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardContext" quid "3DFE47C100F1" persistence "Transient" creationObj FALSE multi FALSE))) (object Mechanism @90 logical_models (list unit_reference_list (object Object "StandardContext" quid "3DFE48B001D1" collaborators (list link_list (object Link quid "3DFE48BE0267" supplier "StandardPipeline" quidu "3DFE48B80088" messages (list Messages (object Message "invoke()" quid "3DFE48BE0268" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1" ordinal 0 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardPipeline" quid "3DFE48B80088" collaborators (list link_list (object Link quid "3DFE48EA0039" supplier "StandardValveContext" quidu "3DFE48D000DC" messages (list Messages (object Message "invoke()" quid "3DFE48EA003A" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1" ordinal 1 quidu "000000000000" creation FALSE) (object Message "invoke()" quid "3DFE4976015D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2" ordinal 6 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardValveContext" quid "3DFE48D000DC" collaborators (list link_list (object Link quid "3DFE491102D5" supplier "StandardContextValve" quidu "3DFE490303A7" messages (list Messages (object Message "invoke()" quid "3DFE491102D6" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.1" ordinal 2 quidu "000000000000" creation FALSE))) (object Link quid "3DFE4993023B" supplier "StandardWrapperValve" quidu "3DFE49890056" messages (list Messages (object Message "invoke()" quid "3DFE4993023C" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2.1" ordinal 7 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardContextValve" quid "3DFE490303A7" collaborators (list link_list (object Link quid "3DFE492F033C" supplier "StandardContextValve" quidu "3DFE490303A7" messages (list Messages (object Message "map //return Wrapper" quid "3DFE492F033D" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.1.1" ordinal 3 quidu "000000000000" creation FALSE))) (object Link quid "3DFE494A0150" supplier "StandardWrapper" quidu "3DFE49370351" messages (list Messages (object Message "invoke()" quid "3DFE494A0151" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.1.2" ordinal 4 Operation "invoke" quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardWrapper" quid "3DFE49370351" collaborators (list link_list (object Link quid "3DFE495F0287" supplier "StandardPipeline" quidu "3DFE48B80088" messages (list Messages (object Message "invoke()" quid "3DFE495F0288" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.1.1.2.1" ordinal 5 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "StandardWrapperValve" quid "3DFE49890056" collaborators (list link_list (object Link quid "3DFE49DB018A" supplier "StandardWrapperValve" quidu "3DFE49890056") (object Link quid "3DFE49EC004E" supplier "StandardWrapper" quidu "3DFE49370351" messages (list Messages (object Message "allocate()" quid "3DFE49EC004F" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2.1.1" ordinal 8 quidu "000000000000" creation FALSE) (object Message "return servlet" quid "3DFE4A200067" frequency "Aperiodic" synchronization "Return" dir "ToClientFromSupplier" sequence "1.2.1.1.1" ordinal 9 quidu "000000000000" creation FALSE))) (object Link quid "3DFE4A29027D" supplier "ApplicationFilterChain" quidu "3DFE4A1500B2" messages (list Messages (object Message "createFilterChain()" quid "3DFE4A29027E" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2.1.1.1.1" ordinal 10 quidu "000000000000" creation FALSE) (object Message "doFilter()" quid "3DFE4A490283" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2.1.2" ordinal 11 Operation "doFilter" quidu "000000000000" creation FALSE) (object Message "return" quid "3DFE4CB4025B" frequency "Aperiodic" synchronization "Return" dir "ToClientFromSupplier" sequence "1.2.1.2.3" ordinal 14 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "ApplicationFilterChain" quid "3DFE4A1500B2" collaborators (list link_list (object Link quid "3DFE4C2701C2" supplier "ApplicationFilterChain" quidu "3DFE4A1500B2" messages (list Messages (object Message "internalDoFilter()" quid "3DFE4C2701C3" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2.1.2.1" ordinal 12 quidu "000000000000" creation FALSE))) (object Link quid "3DFE4CA502BE" supplier "$UNNAMED$0" quidu "3DFE4BAE0056" messages (list Messages (object Message "service()" quid "3DFE4CA502BF" frequency "Aperiodic" synchronization "Simple" dir "FromClientToSupplier" sequence "1.2.1.2.2" ordinal 13 quidu "000000000000" creation FALSE)))) persistence "Transient" creationObj FALSE multi FALSE) (object Object "$UNNAMED$0" quid "3DFE4BAE0056" stereotype "Servlet" persistence "Transient" creationObj TRUE multi FALSE)))) logical_presentations (list unit_reference_list (object ClassDiagram "Main" quid "3DFDF6D2021B" title "Main" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list)) (object ClassDiagram "high level packaging" quid "3E42DE75004B" title "high level packaging" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list (object CategoryView "Logical View::org.apache.catalina" @91 location (1024, 752) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @91 location (780, 668) fill_color 13434879 nlines 2 max_width 488 justify 0 label "org.apache.catalina") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DE8D0082" width 500 height 181) (object CategoryView "Logical View::org.apache.coyote" @92 location (512, 1184) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @92 location (237, 1090) fill_color 13434879 nlines 2 max_width 550 justify 0 label "org.apache.coyote") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DE9F0132" width 563 height 200) (object CategoryView "Logical View::org.apache.tomcat.util" @93 location (1920, 1104) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @93 location (1670, 1020) fill_color 13434879 nlines 2 max_width 500 justify 0 label "org.apache.tomcat.util") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DEDF01F2" width 512 height 181) (object ImportView "" @94 stereotype TRUE line_color 3342489 quidu "3E42DEF601EB" client @91 supplier @93 line_style 0) (object ImportView "" @95 stereotype TRUE line_color 3342489 quidu "3E42DEFC00B3" client @92 supplier @93 line_style 0) (object CategoryView "Logical View::org.apache.jasper" @96 location (1728, 624) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @96 location (1437, 540) fill_color 13434879 nlines 2 max_width 582 justify 0 label "org.apache.jasper") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E42DEFF0270" width 594 height 181) (object ImportView "" @97 stereotype TRUE line_color 3342489 quidu "3E42DF700060" client @91 supplier @92 line_style 0) (object NoteView @98 location (1200, 208) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @98 location (847, 143) fill_color 13434879 nlines 2 max_width 671 label "High Level package dependencies") line_color 3342489 fill_color 13434879 width 731 height 143) (object CategoryView "Logical View::org.apache.naming" @99 location (352, 304) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @99 location (83, 220) fill_color 13434879 nlines 2 max_width 538 justify 0 label "org.apache.naming") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3E43D1580339" width 550 height 181) (object ImportView "" @100 stereotype TRUE line_color 3342489 quidu "3E43D165039C" client @91 supplier @99 line_style 0))) (object InteractionDiagram "1. catalina_load" mechanism_ref @82 quid "3DFDF8EE0267" title "1. catalina_load" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 519 items (list diagram_item_list (object InterObjView "Bootstrap" @101 location (224, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @101 location (224, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Bootstrap") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDF8FD0345" width 300 height 1972 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @102 location (224, 368) line_color 3342489 InterObjView @101 height 1738 y_coord 1678 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @103 location (224, 368) line_color 3342489 InterObjView @101 height 60 y_coord 0 Nested TRUE)) (object InterObjView "Digester" @104 location (896, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @104 location (896, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Digester") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFAF201A1" width 300 height 1972 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @105 location (896, 1232) line_color 3342489 InterObjView @104 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @106 location (896, 1312) line_color 3342489 InterObjView @104 height 264 y_coord 204 Nested FALSE)) (object InterObjView "ServerLifecycleListener" @107 location (1232, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @107 location (1232, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "ServerLifecycleListener") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFB4B0217" width 300 height 1972 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @108 location (1232, 1328) line_color 3342489 InterObjView @107 height 60 y_coord 0 Nested FALSE)) (object InterObjView "GlobalResourcesLifecycleListener" @109 location (1568, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @109 location (1568, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 322 justify 0 label "GlobalResourcesLifecycleListener") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFB7A02AB" width 340 height 1972 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @110 location (1568, 1456) line_color 3342489 InterObjView @109 height 60 y_coord 0 Nested FALSE)) (object InterObjView "SecurityConfig" @111 location (1920, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @111 location (1920, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "SecurityConfig") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFBD802BA" width 300 height 1972 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @112 location (1920, 1600) line_color 3342489 InterObjView @111 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @113 location (1920, 1680) line_color 3342489 InterObjView @111 height 146 y_coord 86 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @114 location (1920, 1760) line_color 3342489 InterObjView @111 height 60 y_coord 0 Nested TRUE)) (object SelfMessView "" @115 location (16, 368) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @116 Parent_View @115 location (315, 324) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDF9210009" anchor_loc 1 nlines 1 max_width 340 justify 0 label "initClassLoaders()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @101 supplier @101 Focus_Src @102 Focus_Entry @103 origin (240, 368) terminus (390, 368) ordinal 0) (object NoteView @117 location (1152, 1072) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @117 location (1014, 1012) fill_color 13434879 nlines 2 max_width 240 label "parse server.xml") line_color 3342489 fill_color 13434879 width 300 height 132) (object NoteView @118 location (1376, 80) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @118 location (1238, 20) fill_color 13434879 nlines 2 max_width 240 label "MBeans") line_color 3342489 fill_color 13434879 width 300 height 132) (object AttachView "" @119 stereotype TRUE line_color 3342489 client @118 supplier @107 line_style 0) (object AttachView "" @120 stereotype TRUE line_color 3342489 client @109 supplier @118 line_style 0) (object NoteView @121 location (2160, 2176) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @121 location (1947, 2113) fill_color 13434879 nlines 2 max_width 390 label "#1Catalina.load()") line_color 3342489 fill_color 13434879 width 450 height 138) (object InterObjView "Catalina" @122 location (560, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @122 location (560, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Catalina") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDF90A0330" width 300 height 1972 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @123 location (560, 464) line_color 3342489 InterObjView @122 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @124 location (560, 608) line_color 3342489 InterObjView @122 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @125 location (560, 720) line_color 3342489 InterObjView @122 height 1326 y_coord 1266 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @126 location (560, 896) line_color 3342489 InterObjView @122 height 194 y_coord 134 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @127 location (560, 896) InterObjView @122 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @128 location (560, 1024) line_color 3342489 InterObjView @122 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @129 location (560, 1024) InterObjView @122 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @130 location (560, 1152) line_color 3342489 InterObjView @122 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @131 location (560, 1152) InterObjView @122 height 60 y_coord 0 Nested TRUE)) (object SelfMessView "" @132 location (16, 896) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @133 Parent_View @132 location (651, 852) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFA8001DA" anchor_loc 1 nlines 1 max_width 160 justify 0 label "initDirs()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @122 supplier @122 Focus_Src @127 Focus_Entry @126 origin (576, 896) terminus (726, 896) ordinal 4) (object SelfMessView "" @134 location (16, 1024) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @135 Parent_View @134 location (701, 981) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFA8B0347" anchor_loc 1 nlines 1 max_width 228 justify 0 label "initNaming()" pctDist 0.840000 height 44 orientation 0) line_color 3342489 client @122 supplier @122 Focus_Src @129 Focus_Entry @128 origin (576, 1024) terminus (726, 1024) ordinal 5) (object SelfMessView "" @136 location (16, 1152) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @137 Parent_View @136 location (686, 1109) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFAAD01AC" anchor_loc 1 nlines 1 max_width 180 justify 0 label "initialize()" pctDist 0.733333 height 44 orientation 0) line_color 3342489 client @122 supplier @122 Focus_Src @131 Focus_Entry @130 origin (576, 1152) terminus (726, 1152) ordinal 6) (object InterMessView "" @138 location (16, 464) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @139 Parent_View @138 location (389, 437) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDF91A010D" anchor_loc 1 nlines 1 max_width 265 justify 0 label "newInstance()" pctDist 0.495082 height 28 orientation 0) line_color 3342489 client @101 supplier @122 Focus_Src @102 Focus_Entry @123 origin (239, 464) terminus (544, 464) ordinal 1) (object InterMessView "" @140 location (16, 608) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @141 Parent_View @140 location (456, 565) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDF97900C2" anchor_loc 1 nlines 1 max_width 445 justify 0 label "setParentClassLoader()" pctDist 0.711475 height 44 orientation 0) line_color 3342489 client @101 supplier @122 Focus_Src @102 Focus_Entry @124 origin (239, 608) terminus (544, 608) ordinal 2) (object InterMessView "" @142 location (16, 720) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @143 Parent_View @142 location (391, 676) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFA3402F2" anchor_loc 1 nlines 1 max_width 108 justify 0 label "load()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @101 supplier @122 Focus_Src @102 Focus_Entry @125 origin (239, 720) terminus (544, 720) ordinal 3) (object InterMessView "" @144 location (16, 1232) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @145 Parent_View @144 location (727, 1188) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFAF800C4" anchor_loc 1 nlines 1 max_width 302 justify 0 label "createDigester()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @122 supplier @104 Focus_Src @125 Focus_Entry @105 origin (575, 1232) terminus (880, 1232) ordinal 7) (object InterMessView "" @146 location (16, 1312) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @147 Parent_View @146 location (727, 1268) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFB0100B2" anchor_loc 1 nlines 1 max_width 136 justify 0 label "parse()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @122 supplier @104 Focus_Src @125 Focus_Entry @106 origin (575, 1312) terminus (880, 1312) ordinal 8) (object AttachView "" @148 stereotype TRUE line_color 3342489 client @147 supplier @117 line_style 0) (object InterMessView "" @149 location (16, 1328) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @150 Parent_View @149 location (1063, 1284) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFB8400A7" anchor_loc 1 nlines 1 max_width 265 justify 0 label "newInstance()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @104 supplier @107 Focus_Src @106 Focus_Entry @108 origin (911, 1328) terminus (1216, 1328) ordinal 9) (object InterMessView "" @151 location (16, 1456) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @152 Parent_View @151 location (1231, 1412) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFB920148" anchor_loc 1 nlines 1 max_width 265 justify 0 label "newInstance()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @104 supplier @109 Focus_Src @106 Focus_Entry @110 origin (911, 1456) terminus (1552, 1456) ordinal 10) (object InterMessView "" @153 location (16, 1600) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @154 Parent_View @153 location (1239, 1556) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFBEA00C2" anchor_loc 1 nlines 1 max_width 265 justify 0 label "newInstance()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @122 supplier @111 Focus_Src @125 Focus_Entry @112 origin (575, 1600) terminus (1904, 1600) ordinal 11) (object InterMessView "" @155 location (16, 1680) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @156 Parent_View @155 location (1239, 1636) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFBF401F2" anchor_loc 1 nlines 1 max_width 425 justify 0 label "setPackageDefinition()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @122 supplier @111 Focus_Src @125 Focus_Entry @113 origin (575, 1680) terminus (1904, 1680) ordinal 12) (object InterMessView "" @157 location (16, 1760) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @158 Parent_View @157 location (1239, 1716) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFC1203C2" anchor_loc 1 nlines 1 max_width 386 justify 0 label "setPackageAccess()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @122 supplier @111 Focus_Src @125 Focus_Entry @114 origin (575, 1760) terminus (1904, 1760) ordinal 13))) (object InteractionDiagram "2. catalina_initliaze" mechanism_ref @83 quid "3DFDFC44002A" title "2. catalina_initliaze" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 87 items (list diagram_item_list (object InterObjView "Catalina" @159 location (176, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @159 location (176, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Catalina") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFC8F015F" width 300 height 1180 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @160 location (176, 400) line_color 3342489 InterObjView @159 height 914 y_coord 854 Nested FALSE)) (object InterObjView "StandardServer" @161 location (496, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @161 location (496, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardServer") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFCCB006B" width 300 height 1180 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @162 location (496, 400) line_color 3342489 InterObjView @161 height 854 y_coord 794 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @163 location (496, 480) line_color 3342489 InterObjView @161 height 768 y_coord 708 Nested TRUE)) (object InterObjView "StandardService" @164 location (832, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @164 location (832, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardService") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFD370020" width 300 height 1180 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @165 location (832, 480) line_color 3342489 InterObjView @164 height 708 y_coord 648 Nested FALSE)) (object InterObjView "CoyoteConnector" @166 location (1168, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @166 location (1168, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "CoyoteConnector") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFE810313" width 300 height 1180 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @167 location (1168, 528) line_color 3342489 InterObjView @166 height 600 y_coord 540 Nested FALSE)) (object InterObjView "CoyoteAdapter" @168 location (1504, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @168 location (1504, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "CoyoteAdapter") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFDFFA00226" width 300 height 1180 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @169 location (1504, 576) line_color 3342489 InterObjView @168 height 60 y_coord 0 Nested FALSE)) (object InterObjView "Http11Protocol" @170 location (1808, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @170 location (1808, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Http11Protocol") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE016601A6" width 300 height 1180 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @171 location (1808, 704) line_color 3342489 InterObjView @170 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @172 location (1808, 832) line_color 3342489 InterObjView @170 height 60 y_coord 0 Nested FALSE)) (object InterObjView "JkCoyoteAdapter" @173 location (2144, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @173 location (2144, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "JkCoyoteAdapter") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE01AD01A8" width 300 height 1180 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @174 location (2144, 928) line_color 3342489 InterObjView @173 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @175 location (2144, 1008) line_color 3342489 InterObjView @173 height 60 y_coord 0 Nested FALSE)) (object InterMessView "" @176 location (16, 400) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @177 Parent_View @176 location (335, 356) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFD1F0076" anchor_loc 1 nlines 1 max_width 180 justify 0 label "initialize()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @159 supplier @161 Focus_Src @160 Focus_Entry @162 origin (191, 400) terminus (480, 400) ordinal 0) (object InterMessView "" @178 location (16, 480) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @179 Parent_View @178 location (663, 436) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFD3D01C4" anchor_loc 1 nlines 1 max_width 180 justify 0 label "initialize()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @161 supplier @164 Focus_Src @163 Focus_Entry @165 origin (511, 480) terminus (816, 480) ordinal 1) (object InterMessView "" @180 location (16, 528) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @181 Parent_View @180 location (999, 484) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFDFE990305" anchor_loc 1 nlines 1 max_width 180 justify 0 label "initialize()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @164 supplier @166 Focus_Src @165 Focus_Entry @167 origin (847, 528) terminus (1152, 528) ordinal 2) (object InterMessView "" @182 location (16, 576) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @183 Parent_View @182 location (1335, 532) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE013D0217" anchor_loc 1 nlines 1 max_width 106 justify 0 label "new()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @166 supplier @168 Focus_Src @167 Focus_Entry @169 origin (1183, 576) terminus (1488, 576) ordinal 3) (object InterMessView "" @184 location (1504, 704) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @185 Parent_View @184 location (1487, 660) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE01830330" anchor_loc 1 nlines 1 max_width 106 justify 0 label "new()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @166 supplier @170 Focus_Src @167 Focus_Entry @171 origin (1183, 704) terminus (1792, 704) ordinal 4) (object InterMessView "" @186 location (1504, 832) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @187 Parent_View @186 location (1487, 788) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0188032C" anchor_loc 1 nlines 1 max_width 80 justify 0 label "init()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @166 supplier @170 Focus_Src @167 Focus_Entry @172 origin (1183, 832) terminus (1792, 832) ordinal 5) (object InterMessView "" @188 location (16, 928) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @189 Parent_View @188 location (1655, 884) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE01BC038C" anchor_loc 1 nlines 1 max_width 106 justify 0 label "new()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @166 supplier @173 Focus_Src @167 Focus_Entry @174 origin (1183, 928) terminus (2128, 928) ordinal 6) (object InterMessView "" @190 location (16, 1008) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @191 Parent_View @190 location (1655, 964) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE01C30164" anchor_loc 1 nlines 1 max_width 80 justify 0 label "init()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @166 supplier @173 Focus_Src @167 Focus_Entry @175 origin (1183, 1008) terminus (2128, 1008) ordinal 7) (object NoteView @192 location (2144, 2016) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @192 location (1947, 1957) fill_color 13434879 nlines 2 max_width 359 label "#2 Catalina.initialize()") line_color 3342489 fill_color 13434879 width 419 height 131))) (object InteractionDiagram "3. catalina_start" mechanism_ref @84 quid "3DFE026D02D1" title "3. catalina_start" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 2481 items (list diagram_item_list (object InterObjView "Bootstrap" @193 location (192, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @193 location (192, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Bootstrap") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE027700F5" width 300 height 2912 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @194 location (192, 384) line_color 3342489 InterObjView @193 height 2662 y_coord 2602 Nested FALSE)) (object InterObjView "Catalina" @195 location (480, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @195 location (480, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Catalina") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE027D0067" width 300 height 2912 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @196 location (480, 384) line_color 3342489 InterObjView @195 height 2602 y_coord 2542 Nested FALSE)) (object InterObjView "StandardServer" @197 location (784, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @197 location (784, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardServer") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE02B30015" width 300 height 2912 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @198 location (784, 416) line_color 3342489 InterObjView @197 height 2510 y_coord 2450 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @199 location (784, 480) line_color 3342489 InterObjView @197 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @200 location (784, 592) line_color 3342489 InterObjView @197 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardService" @201 location (1088, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @201 location (1088, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardService") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE030400E3" width 300 height 2912 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @202 location (1088, 704) line_color 3342489 InterObjView @201 height 2162 y_coord 2102 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @203 location (1088, 752) line_color 3342489 InterObjView @201 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @204 location (1088, 864) line_color 3342489 InterObjView @201 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardEngine" @205 location (1424, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @205 location (1424, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 332 justify 0 label "StandardEngine") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE034700C2" width 350 height 2912 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @206 location (1424, 976) line_color 3342489 InterObjView @205 height 1830 y_coord 1770 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @207 location (1424, 1056) line_color 3342489 InterObjView @205 height 1744 y_coord 1684 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @208 location (1424, 1056) line_color 3342489 InterObjView @205 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @209 location (1424, 1168) line_color 3342489 InterObjView @205 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @210 location (1424, 1296) line_color 3342489 InterObjView @205 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @211 location (1424, 1408) line_color 3342489 InterObjView @205 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @212 location (1424, 1536) line_color 3342489 InterObjView @205 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @213 location (1424, 1648) line_color 3342489 InterObjView @205 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardHost" @214 location (1760, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @214 location (1760, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardHost") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE03F2035D" width 300 height 2912 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @215 location (1760, 1760) line_color 3342489 InterObjView @214 height 980 y_coord 920 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @216 location (1760, 1808) line_color 3342489 InterObjView @214 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @217 location (1760, 1920) line_color 3342489 InterObjView @214 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @218 location (1760, 2032) line_color 3342489 InterObjView @214 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @219 location (1760, 2144) line_color 3342489 InterObjView @214 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @220 location (1760, 2256) line_color 3342489 InterObjView @214 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardPipeline" @221 location (2080, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @221 location (2080, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 326 justify 0 label "StandardPipeline") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE047D006D" width 344 height 2912 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @222 location (2080, 2368) line_color 3342489 InterObjView @221 height 312 y_coord 252 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @223 location (2080, 2416) line_color 3342489 InterObjView @221 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @224 location (2080, 2480) line_color 3342489 InterObjView @221 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @225 location (2080, 2560) line_color 3342489 InterObjView @221 height 60 y_coord 0 Nested TRUE)) (object InterMessView "" @226 location (16, 384) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @227 Parent_View @226 location (335, 340) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE02830374" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @193 supplier @195 Focus_Src @194 Focus_Entry @196 origin (207, 384) terminus (464, 384) ordinal 0) (object InterMessView "" @228 location (16, 416) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @229 Parent_View @228 location (631, 372) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE02BA0188" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @195 supplier @197 Focus_Src @196 Focus_Entry @198 origin (495, 416) terminus (768, 416) ordinal 1) (object SelfMessView "" @230 location (16, 480) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @231 Parent_View @230 location (1244, 437) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE02D3006C" anchor_loc 1 nlines 1 max_width 854 justify 0 label "fireLifecycleEvent(BEFORE_START_EVENT)" pctDist 2.960000 height 44 orientation 0) line_color 3342489 client @197 supplier @197 Focus_Src @198 Focus_Entry @199 origin (800, 480) terminus (950, 480) ordinal 2) (object SelfMessView "" @232 location (16, 592) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @233 Parent_View @232 location (1146, 549) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE02DF02DF" anchor_loc 1 nlines 1 max_width 658 justify 0 label "fireLifecycleEvent(START_EVENT)" pctDist 2.313333 height 44 orientation 0) line_color 3342489 client @197 supplier @197 Focus_Src @198 Focus_Entry @200 origin (800, 592) terminus (950, 592) ordinal 3) (object InterMessView "" @234 location (16, 704) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @235 Parent_View @234 location (935, 660) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE030C02B3" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @197 supplier @201 Focus_Src @198 Focus_Entry @202 origin (799, 704) terminus (1072, 704) ordinal 4) (object SelfMessView "" @236 location (16, 752) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @237 Parent_View @236 location (1531, 708) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE031D0022" anchor_loc 1 nlines 1 max_width 854 justify 0 label "fireLifecycleEvent(BEFORE_START_EVENT)" pctDist 2.853333 height 45 orientation 0) line_color 3342489 client @201 supplier @201 Focus_Src @202 Focus_Entry @203 origin (1104, 752) terminus (1254, 752) ordinal 5) (object SelfMessView "" @238 location (16, 864) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @239 Parent_View @238 location (1449, 821) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0330019B" anchor_loc 1 nlines 1 max_width 658 justify 0 label "fireLifecycleEvent(START_EVENT)" pctDist 2.306667 height 44 orientation 0) line_color 3342489 client @201 supplier @201 Focus_Src @202 Focus_Entry @204 origin (1104, 864) terminus (1254, 864) ordinal 6) (object InterMessView "" @240 location (16, 976) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @241 Parent_View @240 location (1255, 932) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0370018A" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @201 supplier @205 Focus_Src @202 Focus_Entry @206 origin (1103, 976) terminus (1408, 976) ordinal 7) (object SelfMessView "" @242 location (16, 1056) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @243 Parent_View @242 location (1865, 1014) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE03750051" anchor_loc 1 nlines 1 max_width 854 justify 0 label "fireLifecycleEvent(BEFORE_START_EVENT)" pctDist 2.840000 height 43 orientation 0) line_color 3342489 client @205 supplier @205 Focus_Src @207 Focus_Entry @208 origin (1440, 1056) terminus (1590, 1056) ordinal 8) (object SelfMessView "" @244 location (16, 1168) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @245 Parent_View @244 location (1639, 1141) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0389001C" anchor_loc 1 nlines 1 max_width 373 justify 0 label "addDefaultMapper()" pctDist 1.326667 height 28 orientation 0) line_color 3342489 client @205 supplier @205 Focus_Src @207 Focus_Entry @209 origin (1440, 1168) terminus (1590, 1168) ordinal 9) (object SelfMessView "" @246 location (16, 1296) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @247 Parent_View @246 location (1592, 1268) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE03980281" anchor_loc 1 nlines 1 max_width 238 justify 0 label "logger.start()" pctDist 1.020000 height 29 orientation 0) line_color 3342489 client @205 supplier @205 Focus_Src @207 Focus_Entry @210 origin (1440, 1296) terminus (1590, 1296) ordinal 10) (object SelfMessView "" @248 location (16, 1408) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @249 Parent_View @248 location (1593, 1380) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE03A80107" anchor_loc 1 nlines 1 max_width 226 justify 0 label "realm.start()" pctDist 1.026667 height 29 orientation 0) line_color 3342489 client @205 supplier @205 Focus_Src @207 Focus_Entry @211 origin (1440, 1408) terminus (1590, 1408) ordinal 11) (object SelfMessView "" @250 location (16, 1536) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @251 Parent_View @250 location (1608, 1508) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE03BD000D" anchor_loc 1 nlines 1 max_width 259 justify 0 label "findMappers()" pctDist 1.120000 height 29 orientation 0) line_color 3342489 client @205 supplier @205 Focus_Src @207 Focus_Entry @212 origin (1440, 1536) terminus (1590, 1536) ordinal 12) (object SelfMessView "" @252 location (16, 1648) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @253 Parent_View @252 location (1515, 1604) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE03E000A4" anchor_loc 1 nlines 1 max_width 251 justify 0 label "findChildren()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @205 supplier @205 Focus_Src @207 Focus_Entry @213 origin (1440, 1648) terminus (1590, 1648) ordinal 13) (object InterMessView "" @254 location (1664, 1760) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @255 Parent_View @254 location (1591, 1716) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE03FB027A" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @205 supplier @214 Focus_Src @207 Focus_Entry @215 origin (1439, 1760) terminus (1744, 1760) ordinal 14) (object SelfMessView "" @256 location (16, 1808) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @257 Parent_View @256 location (1606, 1784) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE043B02AE" anchor_loc 1 nlines 1 max_width 854 justify 0 label "fireLifecycleEvent(BEFORE_START_EVENT)" pctDist -1.133333 height 24 orientation 0) line_color 3342489 client @214 supplier @214 Focus_Src @215 Focus_Entry @216 origin (1776, 1808) terminus (1926, 1808) ordinal 15) (object SelfMessView "" @258 location (16, 1920) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @259 Parent_View @258 location (1963, 1877) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE045C021F" anchor_loc 1 nlines 1 max_width 373 justify 0 label "addDefaultMapper()" pctDist 1.253333 height 44 orientation 0) line_color 3342489 client @214 supplier @214 Focus_Src @215 Focus_Entry @217 origin (1776, 1920) terminus (1926, 1920) ordinal 16) (object InterMessView "" @260 location (2000, 2368) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @261 Parent_View @260 location (1919, 2324) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE048E00B9" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @214 supplier @221 Focus_Src @215 Focus_Entry @222 origin (1775, 2368) terminus (2064, 2368) ordinal 20) (object SelfMessView "" @262 location (16, 2032) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @263 Parent_View @262 location (1916, 2004) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE049B000C" anchor_loc 1 nlines 1 max_width 238 justify 0 label "logger.start()" pctDist 0.933333 height 29 orientation 0) line_color 3342489 client @214 supplier @214 Focus_Src @215 Focus_Entry @218 origin (1776, 2032) terminus (1926, 2032) ordinal 17) (object SelfMessView "" @264 location (16, 2144) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @265 Parent_View @264 location (1916, 2117) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE04A303BB" anchor_loc 1 nlines 1 max_width 238 justify 0 label "findMapper()" pctDist 0.933333 height 28 orientation 0) line_color 3342489 client @214 supplier @214 Focus_Src @215 Focus_Entry @219 origin (1776, 2144) terminus (1926, 2144) ordinal 18) (object SelfMessView "" @266 location (16, 2256) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @267 Parent_View @266 location (1916, 2228) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE04A90342" anchor_loc 1 nlines 1 max_width 251 justify 0 label "findChildren()" pctDist 0.933333 height 29 orientation 0) line_color 3342489 client @214 supplier @214 Focus_Src @215 Focus_Entry @220 origin (1776, 2256) terminus (1926, 2256) ordinal 19) (object NoteView @268 location (2128, 1488) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @268 location (1915, 1422) fill_color 13434879 nlines 2 max_width 390 label "#1 Catalina.start()") line_color 3342489 fill_color 13434879 width 450 height 144) (object SelfMessView "" @269 location (16, 2416) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @270 Parent_View @269 location (1644, 2498) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE05780138" anchor_loc 1 nlines 1 max_width 854 justify 0 label "fireLifecycleEvent(BEFORE_START_EVENT)" pctDist -3.020000 height 45 orientation 0) line_color 3342489 client @221 supplier @221 Focus_Src @222 Focus_Entry @223 origin (2096, 2416) terminus (2246, 2416) ordinal 21) (object SelfMessView "" @271 location (16, 2480) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @272 Parent_View @271 location (1705, 2582) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE05A80398" anchor_loc 1 nlines 1 max_width 658 justify 0 label "fireLifecycleEvent(START_EVENT)" pctDist -2.613333 height 45 orientation 0) line_color 3342489 client @221 supplier @221 Focus_Src @222 Focus_Entry @224 origin (2096, 2480) terminus (2246, 2480) ordinal 22) (object SelfMessView "" @273 location (16, 2560) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @274 Parent_View @273 location (1737, 2423) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE05BA0196" anchor_loc 1 nlines 1 max_width 658 justify 0 label "fireLifecycleEvent(AFTER_EVENT)" pctDist -2.393333 height 138 orientation 0) line_color 3342489 client @221 supplier @221 Focus_Src @222 Focus_Entry @225 origin (2096, 2560) terminus (2246, 2560) ordinal 23) (object NoteView @275 location (960, 1680) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @275 location (635, 1571) fill_color 13434879 nlines 4 max_width 615 label "All StandardX will fire these events.") line_color 3342489 fill_color 13434879 width 675 height 231) (object AttachView "" @276 stereotype TRUE line_color 3342489 client @275 supplier @272 line_style 0) (object AttachView "" @277 stereotype TRUE line_color 3342489 client @275 supplier @270 line_style 0) (object AttachView "" @278 stereotype TRUE line_color 3342489 client @275 supplier @274 line_style 0))) (object InteractionDiagram "4. catalina_start_2" mechanism_ref @85 quid "3DFE050900BF" title "4. catalina_start_2" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 1087 items (list diagram_item_list (object InterObjView "StandardHost" @279 location (208, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @279 location (208, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardHost") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE0538017B" width 300 height 2114 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @280 location (208, 384) line_color 3342489 InterObjView @279 height 1864 y_coord 1804 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @281 location (208, 384) line_color 3342489 InterObjView @279 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @282 location (208, 1088) line_color 3342489 InterObjView @279 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @283 location (208, 1616) line_color 3342489 InterObjView @279 height 60 y_coord 0 Nested TRUE)) (object InterObjView "HostConfig" @284 location (544, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @284 location (544, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "HostConfig") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE06A60131" width 300 height 2114 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @285 location (544, 512) line_color 3342489 InterObjView @284 height 696 y_coord 636 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @286 location (544, 576) line_color 3342489 InterObjView @284 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @287 location (544, 688) line_color 3342489 InterObjView @284 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @288 location (544, 784) line_color 3342489 InterObjView @284 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @289 location (544, 896) line_color 3342489 InterObjView @284 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @290 location (544, 1008) line_color 3342489 InterObjView @284 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @291 location (544, 1536) line_color 3342489 InterObjView @284 height 200 y_coord 140 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @292 location (544, 1536) line_color 3342489 InterObjView @284 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardHostDeployer" @293 location (944, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @293 location (944, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 426 justify 0 label "StandardHostDeployer") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE079A0055" width 444 height 2114 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @294 location (944, 1280) line_color 3342489 InterObjView @293 height 824 y_coord 764 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @295 location (944, 2128) line_color 3342489 InterObjView @293 height 60 y_coord 0 Nested FALSE)) (object InterObjView "Digester" @296 location (1328, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @296 location (1328, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Digester") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE07C9034C" width 300 height 2114 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @297 location (1328, 1280) line_color 3342489 InterObjView @296 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @298 location (1328, 1488) line_color 3342489 InterObjView @296 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @299 location (1328, 1984) line_color 3342489 InterObjView @296 height 60 y_coord 0 Nested FALSE)) (object InterObjView "ContextRuleSet" @300 location (1648, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @300 location (1648, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "ContextRuleSet") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE0834016F" width 300 height 2114 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @301 location (1648, 1408) line_color 3342489 InterObjView @300 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @302 location (1648, 1888) line_color 3342489 InterObjView @300 height 60 y_coord 0 Nested FALSE)) (object InterObjView "NamingRuleSet" @303 location (1968, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @303 location (1968, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "NamingRuleSet") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE08D00173" width 300 height 2114 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @304 location (1968, 1792) line_color 3342489 InterObjView @303 height 60 y_coord 0 Nested FALSE)) (object SelfMessView "" @305 location (0, 384) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @306 Parent_View @305 location (555, 342) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE066C0341" anchor_loc 1 nlines 1 max_width 651 justify 0 label "fireLifecycleEvent(START_EVENT)" pctDist 2.206667 height 43 orientation 0) line_color 3342489 client @279 supplier @279 Focus_Src @280 Focus_Entry @281 origin (224, 384) terminus (374, 384) ordinal 0) (object InterMessView "" @307 location (384, 512) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @308 Parent_View @307 location (486, 468) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE06D20294" anchor_loc 1 nlines 1 max_width 507 justify 0 label "interested[i].lifecycleEvent()" pctDist 0.865574 height 45 orientation 0) line_color 3342489 client @279 supplier @284 Focus_Src @280 Focus_Entry @285 origin (223, 512) terminus (528, 512) ordinal 1) (object SelfMessView "" @309 location (16, 576) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @310 Parent_View @309 location (713, 537) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE06E9028D" anchor_loc 1 nlines 1 max_width 297 justify 0 label "setDeployXML()" pctDist 1.026667 height 40 orientation 0) line_color 3342489 client @284 supplier @284 Focus_Src @285 Focus_Entry @286 origin (560, 576) terminus (710, 576) ordinal 2) (object SelfMessView "" @311 location (16, 688) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @312 Parent_View @311 location (714, 645) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE06F300FF" anchor_loc 1 nlines 1 max_width 288 justify 0 label "setLiveDeploy()" pctDist 1.033333 height 44 orientation 0) line_color 3342489 client @284 supplier @284 Focus_Src @285 Focus_Entry @287 origin (560, 688) terminus (710, 688) ordinal 3) (object SelfMessView "" @313 location (16, 784) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @314 Parent_View @313 location (732, 756) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE06FB00D9" anchor_loc 1 nlines 1 max_width 326 justify 0 label "setUnpacksWar()" pctDist 1.153333 height 29 orientation 0) line_color 3342489 client @284 supplier @284 Focus_Src @285 Focus_Entry @288 origin (560, 784) terminus (710, 784) ordinal 4) (object SelfMessView "" @315 location (16, 896) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @316 Parent_View @315 location (747, 868) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE070C0015" anchor_loc 1 nlines 1 max_width 350 justify 0 label "setXMLValidation()" pctDist 1.246667 height 29 orientation 0) line_color 3342489 client @284 supplier @284 Focus_Src @285 Focus_Entry @289 origin (560, 896) terminus (710, 896) ordinal 5) (object SelfMessView "" @317 location (16, 1008) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @318 Parent_View @317 location (762, 980) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE073B0031" anchor_loc 1 nlines 1 max_width 359 justify 0 label "deployDescriptors()" pctDist 1.346667 height 29 orientation 0) line_color 3342489 client @284 supplier @284 Focus_Src @285 Focus_Entry @290 origin (560, 1008) terminus (710, 1008) ordinal 6) (object InterMessView "" @319 location (16, 1088) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @320 Parent_View @319 location (376, 1044) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE078B03BB" anchor_loc 1 nlines 1 max_width 136 justify 0 label "install()" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @284 supplier @279 Focus_Src @285 Focus_Entry @282 origin (528, 1088) terminus (224, 1088) ordinal 7) (object InterMessView "" @321 location (576, 1280) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @322 Parent_View @321 location (575, 1236) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE07B100BE" anchor_loc 1 nlines 1 max_width 136 justify 0 label "install()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @279 supplier @293 Focus_Src @280 Focus_Entry @294 origin (223, 1280) terminus (928, 1280) ordinal 8) (object InterMessView "" @323 location (1152, 1280) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @324 Parent_View @323 location (1135, 1236) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE07D200ED" anchor_loc 1 nlines 1 max_width 144 justify 0 label "create()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @293 supplier @296 Focus_Src @294 Focus_Entry @297 origin (959, 1280) terminus (1312, 1280) ordinal 9) (object InterMessView "" @325 location (1136, 1984) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @326 Parent_View @325 location (1135, 1940) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE07D603D7" anchor_loc 1 nlines 1 max_width 136 justify 0 label "parse()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @293 supplier @296 Focus_Src @294 Focus_Entry @299 origin (959, 1984) terminus (1312, 1984) ordinal 16) (object InterMessView "" @327 location (1296, 1408) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @328 Parent_View @327 location (1295, 1364) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE08DA029B" anchor_loc 1 nlines 1 max_width 106 justify 0 label "new()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @293 supplier @300 Focus_Src @294 Focus_Entry @301 origin (959, 1408) terminus (1632, 1408) ordinal 10) (object InterMessView "" @329 location (1456, 1792) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @330 Parent_View @329 location (1455, 1748) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE08E00091" anchor_loc 1 nlines 1 max_width 106 justify 0 label "new()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @293 supplier @303 Focus_Src @294 Focus_Entry @304 origin (959, 1792) terminus (1952, 1792) ordinal 14) (object InterMessView "" @331 location (16, 1488) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @332 Parent_View @331 location (1182, 1445) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE08FA003D" anchor_loc 1 nlines 1 max_width 387 justify 0 label "add(ContextRuleSet)" pctDist 0.631728 height 44 orientation 0) line_color 3342489 client @293 supplier @296 Focus_Src @294 Focus_Entry @298 origin (959, 1488) terminus (1312, 1488) ordinal 11) (object InterMessView "" @333 location (1296, 1888) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @334 Parent_View @333 location (1295, 1844) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0907015F" anchor_loc 1 nlines 1 max_width 416 justify 0 label "add(NamingRuleSet())" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @293 supplier @300 Focus_Src @294 Focus_Entry @302 origin (959, 1888) terminus (1632, 1888) ordinal 15) (object NoteView @335 location (2096, 2384) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @335 location (1893, 2315) fill_color 13434879 nlines 2 max_width 371 label "#2 Catalina.start()") line_color 3342489 fill_color 13434879 width 431 height 150) (object SelfMessView "" @336 location (16, 1536) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @337 Parent_View @336 location (697, 1493) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE131F0327" anchor_loc 1 nlines 1 max_width 244 justify 0 label "deployApps()" pctDist 0.913333 height 43 orientation 0) line_color 3342489 client @284 supplier @284 Focus_Src @291 Focus_Entry @292 origin (560, 1536) terminus (710, 1536) ordinal 12) (object InterMessView "" @338 location (16, 1616) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @339 Parent_View @338 location (376, 1572) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE132D0309" anchor_loc 1 nlines 1 max_width 136 justify 0 label "install()" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @284 supplier @279 Focus_Src @291 Focus_Entry @283 origin (528, 1616) terminus (224, 1616) ordinal 13) (object InterMessView "" @340 location (576, 2128) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @341 Parent_View @340 location (575, 2084) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE133A036C" anchor_loc 1 nlines 1 max_width 463 justify 0 label "install() // same as above" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @279 supplier @293 Focus_Src @280 Focus_Entry @295 origin (223, 2128) terminus (928, 2128) ordinal 17))) (object InteractionDiagram "5. catalina_start_3" mechanism_ref @86 quid "3DFE094A0346" title "5. catalina_start_3" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list (object InterObjView "Digester" @342 location (176, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @342 location (176, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Digester") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE095A0371" width 300 height 1214 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @343 location (176, 352) line_color 3342489 InterObjView @342 height 996 y_coord 936 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @344 location (176, 352) line_color 3342489 InterObjView @342 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @345 location (176, 448) line_color 3342489 InterObjView @342 height 60 y_coord 0 Nested TRUE)) (object InterObjView "Rule" @346 location (480, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @346 location (480, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Rule") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE0E7400D0" width 300 height 1214 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @347 location (480, 560) line_color 3342489 InterObjView @346 height 728 y_coord 668 Nested FALSE)) (object InterObjView "StandardContext" @348 location (816, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @348 location (816, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 332 justify 0 label "StandardContext") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE0FC502A1" width 350 height 1214 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @349 location (816, 592) line_color 3342489 InterObjView @348 height 264 y_coord 204 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @350 location (816, 1008) line_color 3342489 InterObjView @348 height 60 y_coord 0 Nested FALSE)) (object InterObjView "StandardPipeline" @351 location (1184, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @351 location (1184, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 363 justify 0 label "StandardPipeline") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE112F003F" width 381 height 1214 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @352 location (1184, 736) line_color 3342489 InterObjView @351 height 60 y_coord 0 Nested FALSE)) (object InterObjView "StandardContextValve" @353 location (1552, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @353 location (1552, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 300 justify 0 label "StandardContextValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE110D0375" width 318 height 1214 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @354 location (1552, 624) line_color 3342489 InterObjView @353 height 60 y_coord 0 Nested FALSE)) (object InterObjView "SetPropertiesRule" @355 location (1920, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @355 location (1920, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 363 justify 0 label "SetPropertiesRule") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE100303A4" width 381 height 1214 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @356 location (1920, 928) line_color 3342489 InterObjView @355 height 200 y_coord 140 Nested FALSE)) (object InterObjView "SetNextRule" @357 location (2272, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @357 location (2272, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "SetNextRule") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE12690267" width 300 height 1214 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @358 location (2272, 1168) line_color 3342489 InterObjView @357 height 60 y_coord 0 Nested FALSE)) (object SelfMessView "" @359 location (0, 352) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @360 Parent_View @359 location (267, 308) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0E7801DB" anchor_loc 1 nlines 1 max_width 108 justify 0 label "parse" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @342 supplier @342 Focus_Src @343 Focus_Entry @344 origin (192, 352) terminus (342, 352) ordinal 0) (object SelfMessView "" @361 location (16, 448) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @362 Parent_View @361 location (345, 420) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0F2F03D2" anchor_loc 1 nlines 1 max_width 267 justify 0 label "startElement()" pctDist 1.020000 height 28 orientation 0) line_color 3342489 client @342 supplier @342 Focus_Src @343 Focus_Entry @345 origin (192, 448) terminus (342, 448) ordinal 1) (object InterMessView "" @363 location (336, 560) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @364 Parent_View @363 location (327, 516) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0F400214" anchor_loc 1 nlines 1 max_width 132 justify 0 label "begin()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @342 supplier @346 Focus_Src @343 Focus_Entry @347 origin (191, 560) terminus (464, 560) ordinal 2) (object InterMessView "" @365 location (16, 592) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @366 Parent_View @365 location (647, 548) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE0FD30266" anchor_loc 1 nlines 1 max_width 265 justify 0 label "newInstance()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @346 supplier @348 Focus_Src @347 Focus_Entry @349 origin (495, 592) terminus (800, 592) ordinal 3) (object InterMessView "" @367 location (864, 928) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @368 Parent_View @367 location (1199, 884) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE102002E9" anchor_loc 1 nlines 1 max_width 132 justify 0 label "begin()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @346 supplier @355 Focus_Src @347 Focus_Entry @356 origin (495, 928) terminus (1904, 928) ordinal 6) (object InterMessView "" @369 location (1008, 736) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @370 Parent_View @369 location (1139, 693) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE114A0193" anchor_loc 1 nlines 1 max_width 610 justify 0 label "setBasic(StandardContextValve)" pctDist 0.915014 height 44 orientation 0) line_color 3342489 client @348 supplier @351 Focus_Src @349 Focus_Entry @352 origin (831, 736) terminus (1168, 736) ordinal 5) (object InterMessView "" @371 location (16, 624) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @372 Parent_View @371 location (1183, 580) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE115E001F" anchor_loc 1 nlines 1 max_width 106 justify 0 label "new()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @348 supplier @353 Focus_Src @349 Focus_Entry @354 origin (831, 624) terminus (1536, 624) ordinal 4) (object InterMessView "" @373 location (1440, 1008) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @374 Parent_View @373 location (1368, 964) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE11D50391" anchor_loc 1 nlines 1 max_width 1190 justify 0 label "//Using BeanUtil, set the object properties (from ex: admin.xml)" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @355 supplier @348 Focus_Src @356 Focus_Entry @350 origin (1904, 1008) terminus (832, 1008) ordinal 7) (object InterMessView "" @375 location (1392, 1168) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @376 Parent_View @375 location (1375, 1124) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE128501C8" anchor_loc 1 nlines 1 max_width 99 justify 0 label "end()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @346 supplier @357 Focus_Src @347 Focus_Entry @358 origin (495, 1168) terminus (2256, 1168) ordinal 8) (object NoteView @377 location (1216, 80) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @377 location (900, 15) fill_color 13434879 nlines 2 max_width 596 label "HostConfig.deployDescriptor()") line_color 3342489 fill_color 13434879 width 656 height 143) (object NoteView @378 location (2128, 1888) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @378 location (1947, 1822) fill_color 13434879 nlines 2 max_width 327 label "#3 Catalina.start()") line_color 3342489 fill_color 13434879 width 387 height 144))) (object InteractionDiagram "6. catalina_start_4" mechanism_ref @87 quid "3DFE13890008" title "6. catalina_start_4" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 1818 items (list diagram_item_list (object InterObjView "Digester" @379 location (176, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @379 location (176, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Digester") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE13960364" width 300 height 2446 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @380 location (176, 336) line_color 3342489 InterObjView @379 height 1228 y_coord 1168 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @381 location (176, 336) line_color 3342489 InterObjView @379 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @382 location (176, 480) line_color 3342489 InterObjView @379 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @383 location (176, 1616) line_color 3342489 InterObjView @379 height 580 y_coord 520 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @384 location (176, 1728) line_color 3342489 InterObjView @379 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardHostDeployer" @385 location (480, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @385 location (480, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 301 justify 0 label "StandardHostDeployer") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE1D8A02DC" width 319 height 2446 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @386 location (480, 576) line_color 3342489 InterObjView @385 height 928 y_coord 868 Nested FALSE)) (object InterObjView "StandardHost" @387 location (800, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @387 location (800, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardHost") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE1DF20141" width 300 height 2446 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @388 location (800, 592) line_color 3342489 InterObjView @387 height 852 y_coord 792 Nested FALSE)) (object InterObjView "StandardContext" @389 location (1120, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @389 location (1120, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 295 justify 0 label "StandardContext") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE196D00D9" width 313 height 2446 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @390 location (1120, 624) line_color 3342489 InterObjView @389 height 760 y_coord 700 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @391 location (1120, 800) line_color 3342489 InterObjView @389 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @392 location (1120, 976) line_color 3342489 InterObjView @389 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @393 location (1120, 1072) line_color 3342489 InterObjView @389 height 60 y_coord 0 Nested TRUE)) (object InterObjView "WebappLoader" @394 location (1440, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @394 location (1440, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 295 justify 0 label "WebappLoader") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE1FFA0347" width 313 height 2446 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @395 location (1440, 640) line_color 3342489 InterObjView @394 height 60 y_coord 0 Nested FALSE)) (object InterObjView "StandardManager" @396 location (1760, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @396 location (1760, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 301 justify 0 label "StandardManager") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE201F0105" width 319 height 2446 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @397 location (1760, 832) line_color 3342489 InterObjView @396 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @398 location (1760, 1264) line_color 3342489 InterObjView @396 height 60 y_coord 0 Nested FALSE)) (object InterObjView "ContextConfig" @399 location (1952, 352) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @399 location (1952, 352) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "ContextConfig") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE2087028C" width 300 height 2318 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @400 location (1952, 412) InterObjView @399 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @401 location (1952, 1136) line_color 3342489 InterObjView @399 height 1444 y_coord 1384 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @402 location (1952, 1264) line_color 3342489 InterObjView @399 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @403 location (1952, 1456) line_color 3342489 InterObjView @399 height 1070 y_coord 1010 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @404 location (1952, 1568) line_color 3342489 InterObjView @399 height 952 y_coord 892 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @405 location (1952, 1984) line_color 3342489 InterObjView @399 height 152 y_coord 92 Nested TRUE)) (object SelfMessView "" @406 location (16, 336) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @407 Parent_View @406 location (267, 292) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE19AE0065" anchor_loc 1 nlines 1 max_width 108 justify 0 label "parse" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @379 supplier @379 Focus_Src @380 Focus_Entry @381 origin (192, 336) terminus (342, 336) ordinal 0) (object SelfMessView "" @408 location (16, 480) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @409 Parent_View @408 location (328, 437) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE19B102E9" anchor_loc 1 nlines 1 max_width 267 justify 0 label "startElement()" pctDist 0.906667 height 44 orientation 0) line_color 3342489 client @379 supplier @379 Focus_Src @380 Focus_Entry @382 origin (192, 480) terminus (342, 480) ordinal 1) (object InterMessView "" @410 location (16, 576) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @411 Parent_View @410 location (327, 552) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE1DFB0022" anchor_loc 1 nlines 1 max_width 165 justify 0 label "addChild" pctDist 0.498645 height 25 orientation 0) line_color 3342489 client @379 supplier @385 Focus_Src @380 Focus_Entry @386 origin (191, 576) terminus (464, 576) ordinal 2) (object InterMessView "" @412 location (16, 592) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @413 Parent_View @412 location (639, 548) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE1FB60277" anchor_loc 1 nlines 1 max_width 165 justify 0 label "addChild" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @385 supplier @387 Focus_Src @386 Focus_Entry @388 origin (495, 592) terminus (784, 592) ordinal 3) (object InterMessView "" @414 location (16, 624) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @415 Parent_View @414 location (959, 580) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE1FC40228" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @387 supplier @389 Focus_Src @388 Focus_Entry @390 origin (815, 624) terminus (1104, 624) ordinal 4) (object InterMessView "" @416 location (16, 640) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @417 Parent_View @416 location (1279, 596) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE200603BE" anchor_loc 1 nlines 1 max_width 82 justify 0 label "new" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @389 supplier @394 Focus_Src @390 Focus_Entry @395 origin (1135, 640) terminus (1424, 640) ordinal 5) (object SelfMessView "" @418 location (16, 800) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @419 Parent_View @418 location (1224, 756) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE200C029A" anchor_loc 1 nlines 1 max_width 186 justify 0 label "setLoader" pctDist 0.593333 height 45 orientation 0) line_color 3342489 client @389 supplier @389 Focus_Src @390 Focus_Entry @391 origin (1136, 800) terminus (1286, 800) ordinal 6) (object InterMessView "" @420 location (16, 832) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @421 Parent_View @420 location (1439, 788) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE202C0250" anchor_loc 1 nlines 1 max_width 82 justify 0 label "new" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @389 supplier @396 Focus_Src @390 Focus_Entry @397 origin (1135, 832) terminus (1744, 832) ordinal 7) (object SelfMessView "" @422 location (16, 976) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @423 Parent_View @422 location (1260, 933) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE2032001C" anchor_loc 1 nlines 1 max_width 221 justify 0 label "setManager" pctDist 0.833333 height 44 orientation 0) line_color 3342489 client @389 supplier @389 Focus_Src @390 Focus_Entry @392 origin (1136, 976) terminus (1286, 976) ordinal 8) (object SelfMessView "" @424 location (16, 1072) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @425 Parent_View @424 location (1481, 1043) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE205B01A2" anchor_loc 1 nlines 1 max_width 658 justify 0 label "fireLifecycleEvent(START_EVENT)" pctDist 2.306667 height 30 orientation 0) line_color 3342489 client @389 supplier @389 Focus_Src @390 Focus_Entry @393 origin (1136, 1072) terminus (1286, 1072) ordinal 9) (object InterMessView "" @426 location (16, 1136) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @427 Parent_View @426 location (1535, 1092) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE20960003" anchor_loc 1 nlines 1 max_width 745 justify 0 label " // Notify interested LifecycleListeners" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @389 supplier @399 Focus_Src @390 Focus_Entry @401 origin (1135, 1136) terminus (1936, 1136) ordinal 10) (object SelfMessView "" @428 location (16, 1264) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @429 Parent_View @428 location (2043, 1220) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE20CF018C" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @399 supplier @399 Focus_Src @401 Focus_Entry @402 origin (1968, 1264) terminus (2118, 1264) ordinal 11) (object SelfMessView "" @430 location (16, 1456) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @431 Parent_View @430 location (2027, 1413) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE20E303E2" anchor_loc 1 nlines 1 max_width 275 justify 0 label "defaultConfig()" pctDist 0.393333 height 44 orientation 0) line_color 3342489 client @399 supplier @399 Focus_Src @401 Focus_Entry @403 origin (1968, 1456) terminus (2118, 1456) ordinal 13) (object SelfMessView "" @432 location (16, 1568) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @433 Parent_View @432 location (2043, 1524) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE211D01A1" anchor_loc 1 nlines 1 max_width 349 justify 0 label "applicationConfig()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @399 supplier @399 Focus_Src @401 Focus_Entry @404 origin (1968, 1568) terminus (2118, 1568) ordinal 14) (object InterMessView "" @434 location (1664, 1264) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @435 Parent_View @434 location (1439, 1220) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE20B600E5" anchor_loc 1 nlines 1 max_width 110 justify 0 label "start()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @389 supplier @396 Focus_Src @390 Focus_Entry @398 origin (1135, 1264) terminus (1744, 1264) ordinal 12) (object InterMessView "" @436 location (16, 1616) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @437 Parent_View @436 location (1064, 1572) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE21B60288" anchor_loc 1 nlines 1 max_width 145 justify 0 label "create()" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @399 supplier @379 Focus_Src @404 Focus_Entry @383 origin (1936, 1616) terminus (192, 1616) ordinal 15) (object SelfMessView "" @438 location (16, 1728) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @439 Parent_View @438 location (457, 1701) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE21BE021B" anchor_loc 1 nlines 1 max_width 530 justify 0 label "// Process web.xml * tld.xml" pctDist 1.773333 height 28 orientation 0) line_color 3342489 client @379 supplier @379 Focus_Src @383 Focus_Entry @384 origin (192, 1728) terminus (342, 1728) ordinal 16) (object InterObjView "StandardWrapper" @440 location (2208, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @440 location (2208, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardWrapper") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE220C0122" width 300 height 2446 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @441 location (2208, 2016) line_color 3342489 InterObjView @440 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @442 location (2208, 2176) line_color 3342489 InterObjView @440 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @443 location (2208, 2288) line_color 3342489 InterObjView @440 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @444 location (2208, 2400) line_color 3342489 InterObjView @440 height 60 y_coord 0 Nested FALSE)) (object InterMessView "" @445 location (16, 1984) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @446 Parent_View @445 location (1063, 1940) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE228B03BA" anchor_loc 1 nlines 1 max_width 1478 justify 0 label "createWarpper() // Invoked by a WebWrapperRule (not Directly by the Digester)" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @379 supplier @399 Focus_Src @383 Focus_Entry @405 origin (191, 1984) terminus (1936, 1984) ordinal 17) (object InterMessView "" @447 location (16, 2016) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @448 Parent_View @447 location (2079, 1972) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE229A0004" anchor_loc 1 nlines 1 max_width 82 justify 0 label "new" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @399 supplier @440 Focus_Src @405 Focus_Entry @441 origin (1967, 2016) terminus (2192, 2016) ordinal 18) (object InterMessView "" @449 location (16, 2176) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @450 Parent_View @449 location (2116, 2134) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE22A700C1" anchor_loc 1 nlines 1 max_width 405 justify 0 label "addInstanceListener()" pctDist 0.662295 height 43 orientation 0) line_color 3342489 client @399 supplier @440 Focus_Src @404 Focus_Entry @442 origin (1967, 2176) terminus (2192, 2176) ordinal 19) (object InterMessView "" @451 location (2496, 2288) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @452 Parent_View @451 location (2116, 2245) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE22C701CC" anchor_loc 1 nlines 1 max_width 410 justify 0 label "addLifecycleListener()" pctDist 0.662295 height 44 orientation 0) line_color 3342489 client @399 supplier @440 Focus_Src @404 Focus_Entry @443 origin (1967, 2288) terminus (2192, 2288) ordinal 20) (object InterMessView "" @453 location (16, 2400) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @454 Parent_View @453 location (2124, 2357) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE22E80364" anchor_loc 1 nlines 1 max_width 428 justify 0 label "addContainerListener()" pctDist 0.701639 height 44 orientation 0) line_color 3342489 client @399 supplier @440 Focus_Src @404 Focus_Entry @444 origin (1967, 2400) terminus (2192, 2400) ordinal 21) (object NoteView @455 location (1216, 80) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @455 location (825, 14) fill_color 13434879 nlines 2 max_width 746 label "Deploy App.") line_color 3342489 fill_color 13434879 width 806 height 144) (object NoteView @456 location (2144, 2704) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @456 location (1953, 2641) fill_color 13434879 nlines 2 max_width 347 label "#4 Catalina.start()") line_color 3342489 fill_color 13434879 width 407 height 138))) (object InteractionDiagram "1. catalina_request" mechanism_ref @88 quid "3DFE3B5001C3" title "1. catalina_request" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list (object InterObjView "ThreadPool" @457 location (176, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @457 location (176, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "ThreadPool") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE402B02C5" width 300 height 1276 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @458 location (176, 384) line_color 3342489 InterObjView @457 height 304 y_coord 244 Nested FALSE)) (object InterObjView "TcpWorkerThread" @459 location (512, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @459 location (512, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 332 justify 0 label "TcpWorkerThread") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE403200F8" width 350 height 1276 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @460 location (512, 384) line_color 3342489 InterObjView @459 height 244 y_coord 184 Nested FALSE)) (object InterObjView "Http11Protocol" @461 location (848, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @461 location (848, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "Http11Protocol") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE40750177" width 300 height 1276 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @462 location (848, 400) line_color 3342489 InterObjView @461 height 168 y_coord 108 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @463 location (848, 448) line_color 3342489 InterObjView @461 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @464 location (848, 592) line_color 3342489 InterObjView @461 height 120 y_coord 60 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @465 location (848, 592) line_color 3342489 InterObjView @461 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @466 location (848, 736) line_color 3342489 InterObjView @461 height 674 y_coord 614 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @467 location (848, 736) line_color 3342489 InterObjView @461 height 60 y_coord 0 Nested TRUE)) (object InterObjView "CoyoteAdapter" @468 location (1168, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @468 location (1168, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "CoyoteAdapter") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE410600DF" width 300 height 1276 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @469 location (1168, 848) line_color 3342489 InterObjView @468 height 502 y_coord 442 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @470 location (1168, 944) line_color 3342489 InterObjView @468 height 352 y_coord 292 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @471 location (1168, 944) line_color 3342489 InterObjView @468 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardEngine" @472 location (1520, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @472 location (1520, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 363 justify 0 label "StandardEngine") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE424B0349" width 381 height 1276 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @473 location (1520, 1008) line_color 3342489 InterObjView @472 height 228 y_coord 168 Nested FALSE)) (object InterObjView "StandardPipeline" @474 location (1872, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @474 location (1872, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardPipeline") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE42900045" width 300 height 1276 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @475 location (1872, 1040) line_color 3342489 InterObjView @474 height 136 y_coord 76 Nested FALSE)) (object InterObjView "StandardValveContext" @476 location (2192, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @476 location (2192, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardValveContext") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE42C002B1" width 300 height 1276 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @477 location (2192, 1056) line_color 3342489 InterObjView @476 height 60 y_coord 0 Nested FALSE)) (object InterMessView "" @478 location (16, 384) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @479 Parent_View @478 location (343, 340) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE40E701AE" anchor_loc 1 nlines 1 max_width 112 justify 0 label "runIt()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @457 supplier @459 Focus_Src @458 Focus_Entry @460 origin (191, 384) terminus (496, 384) ordinal 0) (object InterMessView "" @480 location (16, 400) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @481 Parent_View @480 location (679, 356) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE40FC010E" anchor_loc 1 nlines 1 max_width 359 justify 0 label "processConnection" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @459 supplier @461 Focus_Src @460 Focus_Entry @462 origin (527, 400) terminus (832, 400) ordinal 1) (object SelfMessView "" @482 location (16, 448) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @483 Parent_View @482 location (969, 405) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4111029F" anchor_loc 1 nlines 1 max_width 175 justify 0 label "process()" pctDist 0.706667 height 44 orientation 0) line_color 3342489 client @461 supplier @461 Focus_Src @462 Focus_Entry @463 origin (864, 448) terminus (1014, 448) ordinal 2) (object SelfMessView "" @484 location (16, 592) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @485 Parent_View @484 location (1048, 549) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE415C0151" anchor_loc 1 nlines 1 max_width 291 justify 0 label "parseHeaders()" pctDist 1.226667 height 44 orientation 0) line_color 3342489 client @461 supplier @461 Focus_Src @464 Focus_Entry @465 origin (864, 592) terminus (1014, 592) ordinal 3) (object SelfMessView "" @486 location (16, 736) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @487 Parent_View @486 location (1052, 692) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE41A60161" anchor_loc 1 nlines 1 max_width 328 justify 0 label "prepareRequest()" pctDist 1.253333 height 44 orientation 0) line_color 3342489 client @461 supplier @461 Focus_Src @466 Focus_Entry @467 origin (864, 736) terminus (1014, 736) ordinal 4) (object InterMessView "" @488 location (992, 848) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @489 Parent_View @488 location (1007, 804) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE41D60107" anchor_loc 1 nlines 1 max_width 162 justify 0 label "service()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @461 supplier @468 Focus_Src @466 Focus_Entry @469 origin (863, 848) terminus (1152, 848) ordinal 5) (object SelfMessView "" @490 location (16, 944) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @491 Parent_View @490 location (1372, 916) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE422C01F1" anchor_loc 1 nlines 1 max_width 373 justify 0 label "postParseRequest()" pctDist 1.253333 height 28 orientation 0) line_color 3342489 client @468 supplier @468 Focus_Src @470 Focus_Entry @471 origin (1184, 944) terminus (1334, 944) ordinal 6) (object InterMessView "" @492 location (1344, 1008) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @493 Parent_View @492 location (1343, 964) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE42800238" anchor_loc 1 nlines 1 max_width 149 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @468 supplier @472 Focus_Src @470 Focus_Entry @473 origin (1183, 1008) terminus (1504, 1008) ordinal 7) (object InterMessView "" @494 location (16, 1040) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @495 Parent_View @494 location (1695, 996) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE429A002D" anchor_loc 1 nlines 1 max_width 149 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @472 supplier @474 Focus_Src @473 Focus_Entry @475 origin (1535, 1040) terminus (1856, 1040) ordinal 8) (object InterMessView "" @496 location (16, 1056) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @497 Parent_View @496 location (2031, 1012) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE42CE0230" anchor_loc 1 nlines 1 max_width 149 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @474 supplier @476 Focus_Src @475 Focus_Entry @477 origin (1887, 1056) terminus (2176, 1056) ordinal 9) (object NoteView @498 location (2000, 2016) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @498 location (1862, 1956) fill_color 13434879 nlines 2 max_width 240 label "See next diagram") line_color 3342489 fill_color 13434879 width 300 height 132) (object AttachView "" @499 stereotype TRUE line_color 3342489 client @498 supplier @476 line_style 0))) (object InteractionDiagram "2. catalina_request_2" mechanism_ref @89 quid "3DFE42F7024C" title "2. catalina_request_2" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list (object InterObjView "StandardContextValve" @500 location (224, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @500 location (224, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 401 justify 0 label "StandardContextValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE4307001E" width 419 height 1678 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @501 location (224, 384) line_color 3342489 InterObjView @500 height 386 y_coord 326 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @502 location (224, 704) line_color 3342489 InterObjView @500 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @503 location (224, 896) line_color 3342489 InterObjView @500 height 916 y_coord 856 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @504 location (224, 1024) line_color 3342489 InterObjView @500 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @505 location (224, 1280) line_color 3342489 InterObjView @500 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardEngineValve" @506 location (592, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @506 location (592, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardEngineValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE432801F3" width 300 height 1678 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @507 location (592, 384) line_color 3342489 InterObjView @506 height 264 y_coord 204 Nested FALSE)) (object InterObjView "StandardHost" @508 location (912, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @508 location (912, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardHost") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE436503BD" width 300 height 1678 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @509 location (912, 416) line_color 3342489 InterObjView @508 height 431 y_coord 371 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @510 location (912, 528) line_color 3342489 InterObjView @508 height 60 y_coord 0 Nested TRUE) Focus_Of_Control (object Focus_Of_Control "" @511 location (912, 704) line_color 3342489 InterObjView @508 height 120 y_coord 60 Nested TRUE)) (object InterObjView "ErrorReportValve" @512 location (1264, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @512 location (1264, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 294 justify 0 label "ErrorReportValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE438C028D" width 312 height 1678 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @513 location (1264, 896) line_color 3342489 InterObjView @512 height 248 y_coord 188 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @514 location (1264, 944) line_color 3342489 InterObjView @512 height 60 y_coord 0 Nested TRUE)) (object InterObjView "ErrorDispatcherValve" @515 location (1584, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @515 location (1584, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 295 justify 0 label "ErrorDispatcherValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE451F01EC" width 313 height 1678 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @516 location (1584, 1168) line_color 3342489 InterObjView @515 height 232 y_coord 172 Nested FALSE)) (object InterObjView "StandardHostValve" @517 location (1904, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @517 location (1904, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 295 justify 0 label "StandardHostValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE47310130" width 313 height 1678 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @518 location (1904, 1472) line_color 3342489 InterObjView @517 height 280 y_coord 220 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @519 location (1904, 1536) line_color 3342489 InterObjView @517 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardContext" @520 location (2224, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @520 location (2224, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardContext") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE47C100F1" width 300 height 1678 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @521 location (2224, 1632) line_color 3342489 InterObjView @520 height 60 y_coord 0 Nested FALSE)) (object InterMessView "" @522 location (16, 384) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @523 Parent_View @522 location (407, 340) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE434C019B" anchor_loc 1 nlines 1 max_width 146 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @500 supplier @506 Focus_Src @501 Focus_Entry @507 origin (239, 384) terminus (576, 384) ordinal 0) (object InterMessView "" @524 location (16, 416) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @525 Parent_View @524 location (751, 372) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE436C009D" anchor_loc 1 nlines 1 max_width 107 justify 0 label "map()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @506 supplier @508 Focus_Src @507 Focus_Entry @509 origin (607, 416) terminus (896, 416) ordinal 1) (object InterMessView "" @526 location (800, 528) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @527 Parent_View @526 location (751, 484) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE43830063" anchor_loc 1 nlines 1 max_width 146 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @506 supplier @508 Focus_Src @507 Focus_Entry @510 origin (607, 528) terminus (896, 528) ordinal 2) (object InterMessView "" @528 location (608, 704) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @529 Parent_View @528 location (568, 660) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE43B903BF" anchor_loc 1 nlines 1 max_width 146 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @508 supplier @500 Focus_Src @511 Focus_Entry @502 origin (896, 704) terminus (240, 704) ordinal 3) (object InterMessView "" @530 location (752, 896) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @531 Parent_View @530 location (743, 852) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE43C203A4" anchor_loc 1 nlines 1 max_width 146 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @500 supplier @512 Focus_Src @503 Focus_Entry @513 origin (239, 896) terminus (1248, 896) ordinal 4) (object SelfMessView "" @532 location (16, 944) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @533 Parent_View @532 location (1355, 900) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE442501B1" anchor_loc 1 nlines 1 max_width 135 justify 0 label "report()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @512 supplier @512 Focus_Src @513 Focus_Entry @514 origin (1280, 944) terminus (1430, 944) ordinal 5) (object InterMessView "" @534 location (16, 1024) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @535 Parent_View @534 location (744, 980) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE46330293" anchor_loc 1 nlines 1 max_width 230 justify 0 label "invokeNext()" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @512 supplier @500 Focus_Src @513 Focus_Entry @504 origin (1248, 1024) terminus (240, 1024) ordinal 6) (object InterMessView "" @536 location (944, 1168) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @537 Parent_View @536 location (903, 1124) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE46E70026" anchor_loc 1 nlines 1 max_width 146 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @500 supplier @515 Focus_Src @503 Focus_Entry @516 origin (239, 1168) terminus (1568, 1168) ordinal 7) (object InterMessView "" @538 location (16, 1280) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @539 Parent_View @538 location (904, 1236) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE475D03A0" anchor_loc 1 nlines 1 max_width 206 justify 0 label "invokeNext" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @515 supplier @500 Focus_Src @516 Focus_Entry @505 origin (1568, 1280) terminus (240, 1280) ordinal 8) (object InterMessView "" @540 location (1184, 1472) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @541 Parent_View @540 location (1063, 1428) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE476503CA" anchor_loc 1 nlines 1 max_width 146 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @500 supplier @517 Focus_Src @503 Focus_Entry @518 origin (239, 1472) terminus (1888, 1472) ordinal 9) (object SelfMessView "" @542 location (16, 1536) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @543 Parent_View @542 location (1995, 1492) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE47CD0167" anchor_loc 1 nlines 1 max_width 295 justify 0 label "map() //Context" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @517 supplier @517 Focus_Src @518 Focus_Entry @519 origin (1920, 1536) terminus (2070, 1536) ordinal 10) (object InterMessView "" @544 location (16, 1632) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @545 Parent_View @544 location (2063, 1588) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE47D500B4" anchor_loc 1 nlines 1 max_width 146 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @517 supplier @520 Focus_Src @518 Focus_Entry @521 origin (1919, 1632) terminus (2208, 1632) ordinal 11))) (object InteractionDiagram "3. catalina_request_3" mechanism_ref @90 quid "3DFE48A202AD" title "3. catalina_request_3" zoom 100 max_height 28350 max_width 21600 origin_x 612 origin_y 938 items (list diagram_item_list (object InterObjView "StandardContext" @546 location (160, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @546 location (160, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardContext") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE48B001D1" width 300 height 2226 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @547 location (160, 400) line_color 3342489 InterObjView @546 height 1960 y_coord 1900 Nested FALSE)) (object InterObjView "StandardPipeline" @548 location (480, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @548 location (480, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardPipeline") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE48B80088" width 300 height 2226 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @549 location (480, 400) line_color 3342489 InterObjView @548 height 1900 y_coord 1840 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @550 location (480, 1088) line_color 3342489 InterObjView @548 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardValveContext" @551 location (800, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @551 location (800, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardValveContext") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE48D000DC" width 300 height 2226 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @552 location (800, 736) line_color 3342489 InterObjView @551 height 1510 y_coord 1450 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @553 location (800, 1168) line_color 3342489 InterObjView @551 height 1072 y_coord 1012 Nested TRUE)) (object InterObjView "StandardContextValve" @554 location (1104, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @554 location (1104, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardContextValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE490303A7" width 300 height 2226 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @555 location (1104, 800) line_color 3342489 InterObjView @554 height 468 y_coord 408 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @556 location (1104, 848) line_color 3342489 InterObjView @554 height 60 y_coord 0 Nested TRUE)) (object InterObjView "StandardWrapper" @557 location (1424, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @557 location (1424, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 288 justify 0 label "StandardWrapper") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE49370351" width 306 height 2226 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @558 location (1424, 944) line_color 3342489 InterObjView @557 height 264 y_coord 204 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @559 location (1424, 1520) line_color 3342489 InterObjView @557 height 340 y_coord 280 Nested FALSE)) (object InterObjView "StandardWrapperValve" @560 location (1744, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @560 location (1744, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "StandardWrapperValve") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE49890056" width 300 height 2226 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @561 location (1744, 1440) line_color 3342489 InterObjView @560 height 740 y_coord 680 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @562 location (1744, 1616) line_color 3342489 InterObjView @560 height 184 y_coord 124 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @563 location (1744, 2000) line_color 3342489 InterObjView @560 height 60 y_coord 0 Nested TRUE)) (object InterObjView "ApplicationFilterChain" @564 location (2064, 224) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @564 location (2064, 224) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "ApplicationFilterChain") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE4A1500B2" width 300 height 2226 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @565 location (2064, 1680) line_color 3342489 InterObjView @564 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @566 location (2064, 1808) line_color 3342489 InterObjView @564 height 312 y_coord 252 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @567 location (2064, 1872) line_color 3342489 InterObjView @564 height 60 y_coord 0 Nested TRUE)) (object InterMessView "" @568 location (336, 400) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @569 Parent_View @568 location (319, 356) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE48BE0268" anchor_loc 1 nlines 1 max_width 147 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @546 supplier @548 Focus_Src @547 Focus_Entry @549 origin (175, 400) terminus (464, 400) ordinal 0) (object InterMessView "" @570 location (16, 736) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @571 Parent_View @570 location (639, 692) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE48EA003A" anchor_loc 1 nlines 1 max_width 147 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @548 supplier @551 Focus_Src @549 Focus_Entry @552 origin (495, 736) terminus (784, 736) ordinal 1) (object InterMessView "" @572 location (16, 800) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @573 Parent_View @572 location (951, 756) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE491102D6" anchor_loc 1 nlines 1 max_width 147 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @551 supplier @554 Focus_Src @552 Focus_Entry @555 origin (815, 800) terminus (1088, 800) ordinal 2) (object SelfMessView "" @574 location (16, 848) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @575 Parent_View @574 location (1322, 821) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE492F033D" anchor_loc 1 nlines 1 max_width 437 justify 0 label "map //return Wrapper" pctDist 1.346667 height 28 orientation 0) line_color 3342489 client @554 supplier @554 Focus_Src @555 Focus_Entry @556 origin (1120, 848) terminus (1270, 848) ordinal 3) (object InterMessView "" @576 location (1264, 944) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @577 Parent_View @576 location (1262, 901) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE494A0151" anchor_loc 1 nlines 1 max_width 147 justify 0 label "invoke()" pctDist 0.498270 height 44 orientation 0) line_color 3342489 client @554 supplier @557 Focus_Src @555 Focus_Entry @558 origin (1119, 944) terminus (1408, 944) ordinal 4) (object InterMessView "" @578 location (960, 1088) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @579 Parent_View @578 location (952, 1044) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE495F0288" anchor_loc 1 nlines 1 max_width 147 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @557 supplier @548 Focus_Src @558 Focus_Entry @550 origin (1408, 1088) terminus (496, 1088) ordinal 5) (object InterMessView "" @580 location (16, 1168) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @581 Parent_View @580 location (639, 1124) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4976015D" anchor_loc 1 nlines 1 max_width 147 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @548 supplier @551 Focus_Src @549 Focus_Entry @553 origin (495, 1168) terminus (784, 1168) ordinal 6) (object InterMessView "" @582 location (1296, 1440) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @583 Parent_View @582 location (1271, 1396) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4993023C" anchor_loc 1 nlines 1 max_width 147 justify 0 label "invoke()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @551 supplier @560 Focus_Src @553 Focus_Entry @561 origin (815, 1440) terminus (1728, 1440) ordinal 7) (object InterMessView "" @584 location (1616, 1520) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @585 Parent_View @584 location (1584, 1476) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE49EC004F" anchor_loc 1 nlines 1 max_width 175 justify 0 label "allocate()" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @560 supplier @557 Focus_Src @561 Focus_Entry @559 origin (1728, 1520) terminus (1440, 1520) ordinal 8) (object InterMessView "" @586 location (1616, 1616) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @587 Parent_View @586 location (1583, 1572) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4A200067" anchor_loc 1 nlines 1 max_width 242 justify 0 label "return servlet" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @557 supplier @560 Focus_Src @559 Focus_Entry @562 origin (1439, 1616) terminus (1728, 1616) ordinal 9) (object InterMessView "" @588 location (1936, 1680) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @589 Parent_View @588 location (1937, 1636) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4A29027E" anchor_loc 1 nlines 1 max_width 343 justify 0 label "createFilterChain()" pctDist 0.619377 height 45 orientation 0) line_color 3342489 client @560 supplier @564 Focus_Src @562 Focus_Entry @565 origin (1759, 1680) terminus (2048, 1680) ordinal 10) (object InterMessView "" @590 location (16, 1808) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @591 Parent_View @590 location (1902, 1764) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4A490283" anchor_loc 1 nlines 1 max_width 170 justify 0 label "doFilter()" pctDist 0.498270 height 45 orientation 0) line_color 3342489 client @560 supplier @564 Focus_Src @561 Focus_Entry @566 origin (1759, 1808) terminus (2048, 1808) ordinal 11) (object InterObjView "$UNNAMED$0" @592 location (2240, 368) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline TRUE strike FALSE color 0 default_color TRUE) label (object ItemLabel Parent_View @592 location (2240, 368) fill_color 13434879 anchor_loc 1 nlines 2 max_width 282 justify 0 label "") stereotype (object ItemLabel Parent_View @592 location (2240, 368) fill_color 13434879 anchor 10 anchor_loc 1 nlines 1 max_width 222 justify 0 label "<>") icon_style "Icon" line_color 3342489 fill_color 13434879 quidu "3DFE4BAE0056" width 300 height 2082 icon_height 0 icon_width 0 icon_y_offset 0 annotation 1 Focus_Of_Control (object Focus_Of_Control "" @593 location (2240, 428) InterObjView @592 height 60 y_coord 0 Nested FALSE) Focus_Of_Control (object Focus_Of_Control "" @594 location (2240, 1984) line_color 3342489 InterObjView @592 height 60 y_coord 0 Nested FALSE)) (object SelfMessView "" @595 location (16, 1872) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @596 Parent_View @595 location (2155, 1828) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4C2701C3" anchor_loc 1 nlines 1 max_width 308 justify 0 label "internalDoFilter()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @564 supplier @564 Focus_Src @566 Focus_Entry @567 origin (2080, 1872) terminus (2230, 1872) ordinal 12) (object InterMessView "" @597 location (2144, 1984) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @598 Parent_View @597 location (2151, 1940) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4CA502BF" anchor_loc 1 nlines 1 max_width 162 justify 0 label "service()" pctDist 0.500000 height 45 orientation 0) line_color 3342489 client @564 supplier @592 Focus_Src @566 Focus_Entry @594 origin (2079, 1984) terminus (2224, 1984) ordinal 13) (object InterMessView "" @599 location (16, 2000) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) label (object SegLabel @600 Parent_View @599 location (1904, 1956) font (object Font size 10 face "Arial" bold FALSE italics FALSE underline FALSE strike FALSE color 0 default_color TRUE) quidu "3DFE4CB4025B" anchor_loc 1 nlines 1 max_width 113 justify 0 label "return" pctDist 0.500000 height 45 orientation 1) line_color 3342489 client @564 supplier @560 Focus_Src @566 Focus_Entry @563 origin (2048, 2000) terminus (1760, 2000) ordinal 14))))) root_subsystem (object SubSystem "Component View" quid "3DFDF6CE036A" physical_models (list unit_reference_list) physical_presentations (list unit_reference_list (object Module_Diagram "Main" quid "3DFDF6D201FD" title "Main" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list)))) process_structure (object Processes quid "3DFDF6CE0373" ProcsNDevs (list (object Process_Diagram "Deployment View" quid "3DFDF6CE0387" title "Deployment View" zoom 100 max_height 28350 max_width 21600 origin_x 0 origin_y 0 items (list diagram_item_list)))) properties (object Properties attributes (list Attribute_Set (object Attribute tool "Data Modeler" name "propertyId" value "809135966") (object Attribute tool "Data Modeler" name "default__Project" value (list Attribute_Set (object Attribute tool "Data Modeler" name "project" value "") (object Attribute tool "Data Modeler" name "TableCounter" value 0) (object Attribute tool "Data Modeler" name "ViewCounter" value 0) (object Attribute tool "Data Modeler" name "DomainCounter" value 0) (object Attribute tool "Data Modeler" name "SPPackageCounter" value 0) (object Attribute tool "Data Modeler" name "TriggerCounter" value 0) (object Attribute tool "Data Modeler" name "IndexCounter" value 0) (object Attribute tool "Data Modeler" name "ConstraintCounter" value 0) (object Attribute tool "Data Modeler" name "StoreProcedureCounter" value 0) (object Attribute tool "Data Modeler" name "PrimaryKeyCounter" value 0) (object Attribute tool "Data Modeler" name "ForeignKeyCounter" value 0) (object Attribute tool "Data Modeler" name "JoinCounter" value 0) (object Attribute tool "Data Modeler" name "TableSpaceCounter" value 0) (object Attribute tool "Data Modeler" name "cONTAINERCounter" value 0) (object Attribute tool "Data Modeler" name "TablePrefix" value "") (object Attribute tool "Data Modeler" name "ViewPrefix" value "") (object Attribute tool "Data Modeler" name "DomainPrefix" value "") (object Attribute tool "Data Modeler" name "TriggerPrefix" value "") (object Attribute tool "Data Modeler" name "IndexPrefix" value "") (object Attribute tool "Data Modeler" name "ConstraintPrefix" value "") (object Attribute tool "Data Modeler" name "StoreProcedurePrefix" value "") (object Attribute tool "Data Modeler" name "PrimaryKeyPrefix" value "") (object Attribute tool "Data Modeler" name "ForeignKeyPrefix" value "") (object Attribute tool "Data Modeler" name "TableSpacePrefix" value ""))) (object Attribute tool "Data Modeler" name "default__Module-Spec" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "IsDatabase" value FALSE) (object Attribute tool "Data Modeler" name "TargetDatabase" value "") (object Attribute tool "Data Modeler" name "Location" value "") (object Attribute tool "Data Modeler" name "IsTableSpace" value FALSE) (object Attribute tool "Data Modeler" name "TableSpaceType" value "") (object Attribute tool "Data Modeler" name "IsDeault" value FALSE) (object Attribute tool "Data Modeler" name "BufferPool" value "") (object Attribute tool "Data Modeler" name "ExtentSize" value 1) (object Attribute tool "Data Modeler" name "PrefetchSize" value 1) (object Attribute tool "Data Modeler" name "PageSize" value 4) (object Attribute tool "Data Modeler" name "ManagedBy" value "") (object Attribute tool "Data Modeler" name "ContainerList" value ""))) (object Attribute tool "Data Modeler" name "default__Category" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "dmSchema" value "") (object Attribute tool "Data Modeler" name "dmDomainPackage" value "") (object Attribute tool "Data Modeler" name "IsSchema" value FALSE) (object Attribute tool "Data Modeler" name "IsDomainPackage" value FALSE) (object Attribute tool "Data Modeler" name "IsRootSchema" value FALSE) (object Attribute tool "Data Modeler" name "IsRootDomainPackage" value FALSE) (object Attribute tool "Data Modeler" name "IsSchemaPackage" value FALSE) (object Attribute tool "Data Modeler" name "DatabaseID" value "") (object Attribute tool "Data Modeler" name "DBMS" value ""))) (object Attribute tool "Data Modeler" name "default__Class" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "IsTable" value FALSE) (object Attribute tool "Data Modeler" name "IsView" value FALSE) (object Attribute tool "Data Modeler" name "IsDomain" value FALSE) (object Attribute tool "Data Modeler" name "IsSPPackage" value FALSE) (object Attribute tool "Data Modeler" name "Synonymns" value "") (object Attribute tool "Data Modeler" name "TableSpaceID" value "") (object Attribute tool "Data Modeler" name "SourceId" value "") (object Attribute tool "Data Modeler" name "SourceType" value "") (object Attribute tool "Data Modeler" name "CorrelationName" value "") (object Attribute tool "Data Modeler" name "SelectClause" value "") (object Attribute tool "Data Modeler" name "IsUpdateable" value TRUE) (object Attribute tool "Data Modeler" name "CheckOption" value "None") (object Attribute tool "Data Modeler" name "IsSnapShot" value FALSE) (object Attribute tool "Data Modeler" name "IsDistinct" value FALSE) (object Attribute tool "Data Modeler" name "PersistToServer" value "") (object Attribute tool "Data Modeler" name "IsPackage" value FALSE))) (object Attribute tool "Data Modeler" name "default__Attribute" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "Ordinal" value 0) (object Attribute tool "Data Modeler" name "IsIdentity" value FALSE) (object Attribute tool "Data Modeler" name "IsUnique" value FALSE) (object Attribute tool "Data Modeler" name "NullsAllowed" value FALSE) (object Attribute tool "Data Modeler" name "Length" value 0) (object Attribute tool "Data Modeler" name "Scale" value 0) (object Attribute tool "Data Modeler" name "ColumnType" value "Native") (object Attribute tool "Data Modeler" name "ForBitData" value FALSE) (object Attribute tool "Data Modeler" name "DefaultValueType" value "") (object Attribute tool "Data Modeler" name "DefaultValue" value "") (object Attribute tool "Data Modeler" name "SourceId" value "") (object Attribute tool "Data Modeler" name "SourceType" value "") (object Attribute tool "Data Modeler" name "OID" value FALSE))) (object Attribute tool "Data Modeler" name "default__Association" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "IsRelationship" value FALSE) (object Attribute tool "Data Modeler" name "SourceId" value "") (object Attribute tool "Data Modeler" name "SourceType" value "") (object Attribute tool "Data Modeler" name "RIMethod" value "") (object Attribute tool "Data Modeler" name "ParentUpdateRule" value "") (object Attribute tool "Data Modeler" name "ParentUpdateRuleName" value "") (object Attribute tool "Data Modeler" name "ParentDeleteRule" value "") (object Attribute tool "Data Modeler" name "ParentDeleteRuleName" value "") (object Attribute tool "Data Modeler" name "ChildInsertRestrict" value FALSE) (object Attribute tool "Data Modeler" name "ChildInsertRestrictName" value "") (object Attribute tool "Data Modeler" name "ChildMultiplicity" value FALSE) (object Attribute tool "Data Modeler" name "ChildMultiplicityName" value ""))) (object Attribute tool "Data Modeler" name "default__Role" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "ConstraintName" value ""))) (object Attribute tool "Data Modeler" name "default__Operation" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "IsConstraint" value FALSE) (object Attribute tool "Data Modeler" name "ConstraintType" value "") (object Attribute tool "Data Modeler" name "IsIndex" value FALSE) (object Attribute tool "Data Modeler" name "IsTrigger" value FALSE) (object Attribute tool "Data Modeler" name "IsStoredProcedure" value FALSE) (object Attribute tool "Data Modeler" name "IsCluster" value FALSE) (object Attribute tool "Data Modeler" name "TableSpace" value "") (object Attribute tool "Data Modeler" name "FillFactor" value 0) (object Attribute tool "Data Modeler" name "KeyList" value "") (object Attribute tool "Data Modeler" name "CheckPredicate" value "") (object Attribute tool "Data Modeler" name "IsUnique" value FALSE) (object Attribute tool "Data Modeler" name "DeferalMode" value "") (object Attribute tool "Data Modeler" name "InitialCheckTime" value "") (object Attribute tool "Data Modeler" name "TriggerType" value "") (object Attribute tool "Data Modeler" name "IsInsertEvent" value FALSE) (object Attribute tool "Data Modeler" name "IsUpdateEvent" value FALSE) (object Attribute tool "Data Modeler" name "IsDeleteEvent" value FALSE) (object Attribute tool "Data Modeler" name "RefOldTable" value "") (object Attribute tool "Data Modeler" name "RefNewTable" value "") (object Attribute tool "Data Modeler" name "RefOldRow" value "") (object Attribute tool "Data Modeler" name "RefNewRow" value "") (object Attribute tool "Data Modeler" name "IsRow" value FALSE) (object Attribute tool "Data Modeler" name "WhenClause" value "") (object Attribute tool "Data Modeler" name "Language" value "SQL") (object Attribute tool "Data Modeler" name "ProcType" value "Procedure") (object Attribute tool "Data Modeler" name "IsDeterministic" value FALSE) (object Attribute tool "Data Modeler" name "ParameterStyle" value "") (object Attribute tool "Data Modeler" name "ReturnedNull" value FALSE) (object Attribute tool "Data Modeler" name "ExternalName" value "") (object Attribute tool "Data Modeler" name "Length" value "") (object Attribute tool "Data Modeler" name "Scale" value "") (object Attribute tool "Data Modeler" name "ForBitData" value FALSE) (object Attribute tool "Data Modeler" name "DefaultValue" value "") (object Attribute tool "Data Modeler" name "DefaultValueType" value ""))) (object Attribute tool "Data Modeler" name "default__Parameter" value (list Attribute_Set (object Attribute tool "Data Modeler" name "dmItem" value FALSE) (object Attribute tool "Data Modeler" name "DMName" value "") (object Attribute tool "Data Modeler" name "IsInParameter" value TRUE) (object Attribute tool "Data Modeler" name "IsOutParameter" value FALSE) (object Attribute tool "Data Modeler" name "Ordinal" value "") (object Attribute tool "Data Modeler" name "Length" value "") (object Attribute tool "Data Modeler" name "Scale" value "") (object Attribute tool "Data Modeler" name "ForBitData" value FALSE) (object Attribute tool "Data Modeler" name "DefaultValueType" value "") (object Attribute tool "Data Modeler" name "DefaultValue" value "") (object Attribute tool "Data Modeler" name "OperationID" value ""))) (object Attribute tool "Data Modeler" name "HiddenTool" value FALSE) (object Attribute tool "Data Modeler Communicator" name "HiddenTool" value FALSE) (object Attribute tool "Deploy" name "HiddenTool" value FALSE) (object Attribute tool "Rose Model Integrator" name "HiddenTool" value FALSE) (object Attribute tool "Rose Web Publisher" name "HiddenTool" value FALSE) (object Attribute tool "Web Modeler" name "HiddenTool" value FALSE)) quid "3DFDF6CE0374")) tomcat7-7.0.52/webapps/docs/architecture/requestProcess/requestProcess.pdf0000644000175100017510000007725010453561304027003 0ustar locutuslocutus%PDF-1.3 % 12 0 obj << /Linearized 1 /O 14 /H [ 698 195 ] /L 32424 /E 25872 /N 3 /T 32066 >> endobj xref 12 13 0000000016 00000 n 0000000607 00000 n 0000000893 00000 n 0000001046 00000 n 0000001181 00000 n 0000001403 00000 n 0000001880 00000 n 0000001919 00000 n 0000003694 00000 n 0000022967 00000 n 0000023045 00000 n 0000000698 00000 n 0000000873 00000 n trailer << /Size 25 /Info 10 0 R /Root 13 0 R /Prev 32056 /ID[] >> startxref 0 %%EOF 13 0 obj << /Type /Catalog /Pages 9 0 R /Metadata 11 0 R /PageLabels 8 0 R >> endobj 23 0 obj << /S 50 /L 93 /Filter /FlateDecode /Length 24 0 R >> stream Hb```f``@l(GÆ5 \*+ĜPTut&Չ "s e@ = 7 endstream endobj 24 0 obj 85 endobj 14 0 obj << /Type /Page /Parent 9 0 R /Resources 15 0 R /Contents 19 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 15 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 17 0 R >> /ExtGState << /GS1 21 0 R >> /ColorSpace << /Cs6 18 0 R >> >> endobj 16 0 obj << /Type /FontDescriptor /Ascent 905 /CapHeight 718 /Descent -211 /Flags 32 /FontBBox [ -665 -325 2028 1037 ] /FontName /EHPFDM+Arial /ItalicAngle 0 /StemV 94 /XHeight 515 /FontFile2 20 0 R >> endobj 17 0 obj << /Type /Font /Subtype /TrueType /FirstChar 32 /LastChar 121 /Widths [ 278 0 0 0 0 0 0 0 333 333 0 0 278 0 278 278 556 556 556 556 0 556 556 556 0 0 278 0 584 0 584 0 0 667 0 722 722 667 611 0 722 278 0 0 556 833 722 0 667 0 722 667 611 722 667 944 0 0 0 0 278 0 0 556 0 556 556 500 556 556 0 556 556 222 0 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 ] /Encoding /WinAnsiEncoding /BaseFont /EHPFDM+Arial /FontDescriptor 16 0 R >> endobj 18 0 obj [ /ICCBased 22 0 R ] endobj 19 0 obj << /Length 1700 /Filter /FlateDecode >> stream HWr6}W$0iNju2ĸJ(ѥ@LF]`w^qytld2.'=,peXO{byz8ϥwL7}98"0bx\ g/7Z}4Z\vW.?kQG];zܪ~zkׯm.EE+2|7*i97*VJ5l,3 V6&{"pm]$߰C}ݡxj@ڵd D0Y }\^Z2$c]M(&ͬZlYTx0904t N{t\#0}l*CJȪ7^{#%wBR,sZVy|u2r\-ߢ>> stream H\T |Lgw&I@45؀zX0%C k6s>ʺP#J1XCZHph9p^YR4W͗-!LHa،dp:|ENV,3 9(A+I)jd&{a;4RIfيn~dj1|F6|lG,8ӌSt\o-cTF7N%^8M:)*UfO! 0Ŗi|O6G qY@"QKOޢRl1Q6&w({><&sͦgcBd)yqInPv+gnIT`uAO%P=J.Ɖ5U2P,Q+,WN;o2s?,7bWvm8tH0`NZZEFM4]tn 0YD7a=t1KVtZ|'#eO$4Y$+9z逼)m8 jG}Kmجφ ;n%:l^D>8F8{7t>!8JtLTEՌsvsGGO.s~T #X'Ekz,>?I e(GɲTΑ d4IyI f2PSIPeM\V''ԯ, 2K_Ǭbw#+5fꙥ)h c69#Z6Qt:$IqzÈճ2.1򝎬nv{QJATcRP0%ӰhjBkJ>[$[^4(S22Kv9Yn7sĔkW/;ݵEEmE|˗͡W2 5&9 Z!@%nW;t蠏=.>8qq shqNn 7EWOZ;)Mnc )nt]d)87kS>+j[%|"FL/rH@7H]]w~%;K|u@m57@X3L9z@JH [wѐ> 8- .y{_5 s>^(H ^(d( ! !!WR  ![*a2.V&J.T ̴:}d6ڙB[s90 Vc~ZkO2H:A1QkZݚ@!ׄݚXTDr3C6K8guNT_w RC%s"eʷyKINX*EgI*IEP.5fOTgɠ^#*FK΍&uNIN-%f7ef4gLwn0`ޒP$һ[B͙p"D<-)IIB4ZɌҤh. J&r)8:"E"ɹ;"59!5rJ?lSN}zWR4Zҵf%еc] 9r̾R=_w"*vPHo'P (6B>}Ѿ+0((`9P2ڞc#y#hYd|{6z8rx)!;#&qk5R Pu(/ELUƷqv4D~k)Řp.6*6`;XV<lCt!RQQ^g`κ6Zk +ncc^<0/T}g3) .|UZ'JA짿*ZYf3cX Ѿ!Pq&{^_r? nfl81.a-٢Cv s}y u11Hؗ0swk ھ6K9&Xi*o2գM57l g { ,`(0r x 2^32>f|d:k8(93uj,':J )<&Yrnj29xS1t? be>w^*l5 S֚) JU^CZRKsŷv!Wh1ƙa=h;iZ"xk֘XgN§pѮfIyIJoa/V_?KfrfnXn>N-Hv@?Fk-BJEr M؟<tƨN}Z~<~*<>xC\u9o,ƫ9竘p.(1'3$~@;j_y: Ƨ'N=^w {NaNw9ql|K}awm[n0 VLֽ)v]>ޥrQ3֩|vH-f:9P[ E|G聥Dww~滨*7^_ө:ܩ̬3,Q\Jxxl1 Ox3 Po>ܷ·|مh>AqHB[}1-Nz,b:_B5`Wȶy_q**sHȾn4a=# 5f>,k-ϏHrX{="b ͱʩjyn+o&N6as7_|)xT8?ltb`)?P@RzR5Ѹ qw)Ee?~B~LBE U,iwь%/_\C!1+bm4#~Ok38b\m E8[Q>v1C̥t/Vr5fkmqяۈ4Ⱦ 9ܕWSPf Z: ?'hOz؂Xcz؆ςOwCI;qsN3S]o0牘oŧf 1OxdOO.R`\dfu7G}`7I*]"pmb@N\SXc4Џ>BxM꽲w_{t8na7mehxeyʰ^BKH}>i"ܙ>}1"2meT͐gЛF~7׉W)qŻ?/(.!(\r,UNd%67ͳqۏW6\e8G$pwt#>y*n |yh up{wo%ʏBEժw`~xN&vX(|\V92ȏ/B(Aip<H^Gn?fY ;O~C1{5M-q+;~7[xE}>eÃ0} "`9X Ț1` hkfIq#.}H'K^yN/9q39iYa}Zg 4o_Wklzwmcb;c^C0؆xag]hVullhR 塢 jQJRn~TMHxkTNƍCP*G"P"`o;@iԽss̝;3l$w)[LKG|ah$DNTu,gK%| "G+-(< dv `C|zb '='W5{= kL"x ,.+#8"peXB~",!"𽝰l~ vXB‚H_ll|ԈBvJP]wn~=;kf+d&52:C^2Bd'C#K 0H2"#NFr2P)'yiUjToDWKV0RT˺) e i>.Yqal@XFd @;p ;1tAVax ح\8ۚqkbI7#>6%WA/|Kx}yNw<AV q(&n(Iz58D+gêrEx )t5cЕ :ts%s[KW$y{BQB <I'<$A ߻HykĢEhB#Tw t8]@{7*zc)az%f-}y6gcVR`s͎FBGcԡ8JŎ);󝓜9N99 7TV`#|X̅5rr3'KQ]SGQ&ݨ7ב鉲:sM:R͠5MO6k$mNRJeȽbg{)cE;EaRwͷ":2R+z.1G4oJaJbQk~NhkBŚtaKKchY<5bYتQAd`uosdw$}2˲]Xv4=|MGh.+䛡 Ö@̟W.uC`[dwT=f8wd}%z 6M)Ie]Nh_$YR%IzEc1 #Q Uv>\235&V 7b> eBf2Αy r$3p+_ozgЪ N^ҴKf;ز*@?W&㫔GlAٓԤH qN9b9xIB̾ȱY֍KӝW1m7.c!R?jAՔc…ѦT,FGB` O"JJ\/"M(=qfFf g8n`ttz53)u.QPÓsZPD\꒎b'bˌ_F%_1[no=5Wk{F~WTQӦP&e'R_Yb\:8}}.{ݻOvj ypM5ib*4P53J_QlF#d5I4<L)LXR::4Mhm&-Фo9!C^k.l!ϑ ,_Ovw(A0:\sg]HZd]j_ZRj{ص,i3o4n1Cg74>d9Ҡ'g02bh`DP˺W5Ch =qLPE*EqP °%+caYȘeV_{kc'~@ǩSU="}??[ L/7߈ ^˿~6zlP1lf~(gYl@Q5ᝧo/Y,z+HZ2eeuNҠ[xJzUʿ?2HgȠ%"_m[As>5B1x[gq!] )2]d;ҐstܞGJRMXI&hBASH,/:0[^`G+ g9ph${r dee΄KrmXa($N}7'=-57vo빳"ڑk75?#wYLE}Nvs:k^bޘ,tVme f[۶+m9jNFIVXe S@:Yvǐ3$:;q"vc}ɖmF2F5@ ?sFpNwC(iwXE<0MEAr9f;hEđ 8N; & W;rs62RW^[[w^^QV|mQۛ䥗Kkw{W{o_w_w,@tl.Qר~U3N։SugfS&|Ӣ Ktټ(0a(rSi\"cךlOf1MW׶5]wʩ}5==ǚZ۳Kch@ Ev9n㚣[iaL(-ezq/~0 Ѷɚ_KZ5OrLdٖJ(;%q)> $GIjiUU0-\=!/$qMbu"![SstԘ"L EDZP 0i?9 X 2T#j̣Vg…@f_\6 [;~l쯔O|eywtK'?:]ysK..N Օp502 ,` ɕ C-!nXi'%0ypZad1 U?.PM-fEՐl ,%{9Ӿ7e`jbo{0f=lp Ľa,< >" !BQq̣T´7ͅt+ VX ㏇Nh-^F<*֥L /gDubȐ-@ ,)g;Hw\iQx9iAclؾh($nj.ga0`F+DFFS[8̍Ep7Ώ~"3d[ފp5 .:}ziW; G[T"W Ix^/ݗ+VbeVa e틼 HY%&H6@Fc%83| HLH'6"EЯfa{2 ,f#[-1 w$\HP#5S_Gvv(rѼ 5Qj5OwMRPenӣsgPFxTkbD\m^W]3Ɍ5 Ld\':37Ox2csH1>Ա=#_rzQD_VJʽr)d6& ɽ'h{kV,^L姘z O˅%B*.jcib&I|4E"(3<εszwvg m(n1!S I T FHRF8R0m,T4n$HC*mI+R hh١ٚ4ky̛}?|Z!lq UTT 1y97a-6RI!*$ eN6 cdyl,)Ij֢qM7^U$)L2ż=k8fMX5X}اW|6.Z5'{lw A-S>[ͤQfG H5NtI;fm4kL(ol/K#x`C"""b4[Qx0᱙3Rذ`|& (yƀnX+5_QDrHN0M)Ӣ)yĺRYgJjil՝ u( bȳQ{[Ԋ`->e_v{ 5'`Flܤ5ڵv##T 8o!͜܇3_Nm5Y㜒F= Oy޶[[/s(=bUˇW_2h掗2hz7B4TK V ȃOj?*,pQ  'u_d!47 k畍6eu|RQo(P56{w \9e˘z$jT,z.7/<`vh!uQdDZSX[X%@^-n6ɛDS!T_Ӷ_J~$Wd/9CcJ w^.[:U!Nԅv#tDi$lTK$5M UF^>I[,+ǁ:Ԡoq43BQF2xQ2YSM:Y]ϲC/3Ɠ^~ṟ-l騷V}٧_c_GRџ[{7MuX[ڒ{fy:xW(hK6gMC9ݿ,0eG<@b\,#!i#λ hD|9VNΓ2$d(>SC αN+&Qp8=3>j+ʿ3:):jo` qʹ)|Kⴡ#Coqޥ.' Y~R'%[샢8^wo_ػ;8T@ G|A"z$R41htai4X5&!Ǝ0y:V턉6`4J.ivq;}N[[L .$2SCpPwrA$,ՋGc^J߹שNKڳ[}&ó[ѝ<Qʶ1Lμβ`a`O-^3-x -B[0{f\O3^ilaScI4K&#xCno;>^f3X<]xܽ6d!Ay"bix81zT9Z |c[IY̑xéֽ\bՙˍYi!:1\/G!"+PP!˳,a8K淚r2MP+a,)EN,;Kh${>,FHt,9X,^q^^x^-YvМhCS2qLeQd\̂k1pwE4=@?8wU8)q'i'^}8Im4PSj ; ~zpAkh o5lNz 50E#ɟc4an?]yù,eϒK>M~crIa$J冏$o{a#o}dIBS>!`\[A@; )"Q>bvcr cC/F45,RlaѠ479-M{ |)" ʴtWQ^UoA>&VBϟfP Ӣ-%f=\6&wMXmɮ}ǹͳuv ut s\ ':RЈ`8b0L1<'!̼|ea;6ykt$]Kr<{}}}Noo)]\d_)oń&XG+-w?egQ>'iAD 5=+鈐qe˙y3FKXP cK==v&mԃIN&u8zտ9Z"r#z@9SFXN3PU/M)ZܵNZi%g׭W[\Υό~aiϘiMǗm]2r__Ĩ{KTM{zϡk( ]4"zMTJLݬǥ8K]E\ <ݕv03n0X&0o:f ` lB:0|aKq5;|QZ'nkT# z(̣ (PdhMƣbV7紐%lK[ɋogOF=t`U25=e.εlaw>O(rHbL4OZH̒CB@^ Εs¿\)P٭W/) KspkkrC͡4VZ3XAл),65&NJ5 +O4Uw#qW]oC5)#m [mh' |Ǡz4X0Ϟ^ 7z I39Ac:Ow>8sc 9't 1wv}^Պ:np3;j{ڛ{+RhkWL؇oFh/6|vmf޳}.5j(c#}tk8)eN[0ӓd=an ([*ɢ`H^A8^F\q ʈB)mJPB#R*w[Ի $}0HA@wӦ+Yً,&QA H(  q[w6{ů0豟VG[v-==pl/4G5EV{~(>#c/d0EXi,6܁{ &x~8¸4-B= q߫?-y.V?r g=GgEIrgly.sÐFN:P}''}\1u0Na_T*d8@tQ,jfbjRo~)_ͮ1SHP.c^Sc?< )jyK-]ehߍ]~},}t~%^ЕȯS72 :|t/Hu}33 *wwiFuoɷ)҇A_§pP q4/VHhcQ QVOf$!"T 3sh`=)^819ǛLqɴnlZ|~omVx7vkwd7-,=f].a/Jދ =YA;̤U)󴦷ag[>9 ϻƹ[ޜ~p'̟R=tos+C-smC"@B7eu[(=ؐdتm6l?! &CmF8W0NB=n\}~1hF6(GS~;/{n%;'2N$aa</q=/UqwNw{w }CeIpl_>2\pB(m 0!fJcIm:$$4ml I;H fJR&ϴ}WOvv]gGB{,#AjK V]iZɁ/ߕ T\v3ȼ>p؁I*D$Wmu6.zEb$6uL^㿿]>p^XTǖ% Keߗ,N-ݿ5e҂B,li>i IG]#AnJ\L:+.@Ϥ)U aFQvd &y%$yT%C`cVӬ[ * O}-~7Т4JB;|PA3F %ieP-[:4)i+n%۔mt/ڃ}^un|D:A_f"{>/=4*r$9q9/r@(20Yey)eH ৐c,Ɍ fiX*〯%tOGS6 Nf','n͗s^.uα9lK/-5Psn[ j)y'}_ޭHA=T$J wHسs{rB8wԷ4(w ~,ݠw; ?\.좌)1Ӳ|5Z2%+ٲK\iZ[ #/LG,"e[T Ksb`뚦(jۍM.Ka|aFwgadC-z"辶 oAfm] lhgY7ya_W@Bۼ$g^z׬#ZjPScʈS#H땫pndMCOͪ^9a(7 2<5vN+Cs^|z?7Ϛ"bxAŮ T exZ'5*NCdX@{pQ)mIdR,I% p[@:6 T $̼.Sb!E DcL&0JH(D2eƷ$za@$CuKaI]fuD[ZO͉ϲ_eǚat+9kh8( yw 3*50E +ɘfb328?.4*٬ٝٙt65Nk`&1I4mӴ(m*(ZB@`BDobWb})}o;3{[.6jP|jbG) #2oX?]OV~g˼}w`;;Z7LO:bGJk?'99+hzP?gL2hԨoCB\8f9l(UyD OxIu2fT|ZyK=RBMX9B Q<QZt! 0y~ErzD.l~Ygy킨γMM6evP,y IeP_4h:kNM ٬X0 VL)Ŧsr^DdE @PrlE%PQD hjNLmڀtvuʠgw/S>$l JGZ$)x{чC8A&r9j6IlGZ'A/0Fso/qD7G{H )X,ԛ樼9Kz+ݹ'~|dh^]d>`' A:NY(Y!*W-I=GDB?xG yHW92i-Ӝm`'|czUs߾fPl+kfwxmyfeXjҥmɑN endstream endobj 21 0 obj << /Type /ExtGState /SA false /SM 0.02 /TR2 /Default >> endobj 22 0 obj << /N 3 /Alternate /DeviceRGB /Length 2575 /Filter /FlateDecode >> stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 1 0 obj << /Type /Page /Parent 9 0 R /Resources 2 0 R /Contents 3 0 R /MediaBox [ 0 0 612 792 ] /CropBox [ 0 0 612 792 ] /Rotate 0 >> endobj 2 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 17 0 R >> /ExtGState << /GS1 21 0 R >> /ColorSpace << /Cs6 18 0 R >> >> endobj 3 0 obj << /Length 1857 /Filter /FlateDecode >> stream HWrG}+N/z%'r"<͂ 9={aeQ)+fg{{9}vvlf2]O%[yo[džVhp6)|0z?Xv -jŵa9^ނdq;Y^,d%{>0x5lcpR^EpW*jq7[d8IIŃvr9t4}qS,jjZ~ch'/]Z.w~ҫ z'[UGV׿\}r4~6s{$V\rʻU+c2K_eJ.d4Oaޢ/!l4jdW쯿 bAI)Py.s`)`}H~˟8 ITP-)iNU W,=W%S^ObX^>*'vl>.aNYy H0 \kdHl55=:[P9R@[POUtr88CC{aC"蓃H-(%C{hXD"Ś6vx"W@ ) URϭsڶb Բ6x.nI,0˫BP?W%\NxmVMHaliXM"4谾A ܵ/)G<M]^QQ⿤NT %VV)rsJ\ϭW4uq(\\:- @LJ'uv**/%xTwHmmA,41bqy&Ys;'m 6РB4Cc4б֠6T(˒ڪ(W9wvzWyӶ=jB-LjZ<܇I`wZ1\PB5GkAl=5IDj-[y=mZ*G_* ʇv)\*TAZ9OJy]<‹WqG 7&BQ$0tZYh %`Zs0"f/ˏ4VUt[X*cT[ tVEN}/]F$J"iM@8A\h&JR0muwpj6tڄ zШmpە2;d¼0plUEY .Usە@NE/x1.# '@IȍCD̓vExb+u]-tф?oHJlgӨaM=aJ\X> endobj 5 0 obj << /ProcSet [ /PDF /Text ] /Font << /TT2 17 0 R >> /ExtGState << /GS1 21 0 R >> /ColorSpace << /Cs6 18 0 R >> >> endobj 6 0 obj << /Length 2187 /Filter /FlateDecode >> stream HWko_1"y ADj q@L* ZLPHn}ϝ}pEw)y#6wܙsn\V݄"O"IMb[L>L~N.S$J d"x/t5Q%t}f/f)Hv}P+wzl[<ź8q'XouT\o'zf^gx] i?Car)b!&V)ξUZ*w]׳!dt?<>.~Ye냻?&J`BRQs'Q2s}ga_?[/>#L[)qω;=3%O.IKϒWv< M ]ct#fG@V$e&xd[{՗/yzmuF:Gd"<*F+VVQV^frLJMFɃceL3;3.5%Mf5QNa*q{iQy[P& KEfDC)5DFi\"j1zt'OjqeZLi1nG9~Xq^3U>w2:d: ]’Uk^GNPc4M‡5d3fMRX&i qXzyYݤ6LU]@X%XUs]9BƎE2!( X=#vlN,4˲`TVXT]4h:ZdN^ҡk F.6ᙝڐ=j&jÒ] va?F53xNr6<Ts)LǐؘE!HǬ' [y >3| 0>xp3A8>X1SĸK0%d\.YKg n"ZU7L=_n{sMt_Jڄ˶,Q0+#@u%(ZV^>4!FAj|ExDCeG,k-p^+I1aEks|U}L]+* F%"UObN=l,gyNz(ahip=M|8zM}8X9})Ao E0˙l".-,꥗bڲ%E-(YN2@Q2I9AJImg \y0W]a2R:Zc%Ac>7KC+p̺|*2mTZq2( rW=`.5ȌzP4 s6hKek[1bk-}uk9ɣg&NbƗ{ki G eHM 6cso͡C$sP޳dkK+7)~p~WNy/f!IƳ_#CPm C9@Hw=~Fx¾zU?aPz-&oŕ?~'f{q[bf b~xw7ݬ ޻I+EW*wo~oM1/V.Bo)Elw[X q=s:jzLf+a1-DHumca,4:h>,.--jox7{(|. endstream endobj 7 0 obj << /S /D >> endobj 8 0 obj << /Nums [ 0 7 0 R ] >> endobj 9 0 obj << /Type /Pages /Kids [ 14 0 R 1 0 R 4 0 R ] /Count 3 >> endobj 10 0 obj << /CreationDate (D:20021216170206-05'00') /ModDate (D:20021216170206-05'00') /Producer (Acrobat Distiller 5.0 \(Windows\)) /Author (Administrator) /Creator (PScript5.dll Version 5.2) /Title (Rational Rose - Tomcat_5_UML.md) >> endobj 11 0 obj << /Type /Metadata /Subtype /XML /Length 1095 >> stream Rational Rose - Tomcat_5_UML.md endstream endobj xref 0 12 0000000000 65535 f 0000025722 00000 n 0000025872 00000 n 0000026006 00000 n 0000027937 00000 n 0000028087 00000 n 0000028221 00000 n 0000030482 00000 n 0000030512 00000 n 0000030554 00000 n 0000030631 00000 n 0000030877 00000 n trailer << /Size 12 /ID[] >> startxref 173 %%EOF tomcat7-7.0.52/webapps/docs/architecture/requestProcess.xml0000644000175100017510000000346112271304167023776 0ustar locutuslocutus ]> &project; Yoav Shapira Request Process Flow

    This page describes the process used by Tomcat to handle an incoming request. This process is largely defined by the Servlet Specification, which outlines the order of events that must take place.

    TODO

    A UML sequence diagram of the request process is available here.

    The Servlet Specification provides many opportunities for listening in (using Listeners) or modifying (using Filters) the request handling process even before the request arrives at the servlet that will handle it.

    tomcat7-7.0.52/webapps/docs/architecture/index.xml0000644000175100017510000000416512271304167022060 0ustar locutuslocutus ]> &project; Yoav Shapira Table of Contents

    This section of the Tomcat documentation attempts to explain the architecture and design of the Tomcat server. It includes significant contributions from several tomcat developers:

    The information presented is divided into the following sections:

    • Overview - An overview of the Tomcat server architecture with key terms and concepts.
    • Server Startup - A detailed description, with sequence diagrams, of how the Tomcat server starts up.
    • Request Process Flow - A detailed description of how Tomcat handles a request.
    tomcat7-7.0.52/webapps/docs/architecture/overview.xml0000644000175100017510000001151012271304167022607 0ustar locutuslocutus ]> &project; Yoav Shapira Architecture Overview

    This page provides an overview of the Tomcat server architecture.

    In the Tomcat world, a Server represents the whole container. Tomcat provides a default implementation of the Server interface which is rarely customized by users.

    A Service is an intermediate component which lives inside a Server and ties one or more Connectors to exactly one Engine. The Service element is rarely customized by users, as the default implementation is simple and sufficient: Service interface.

    An Engine represents request processing pipeline for a specific Service. As a Service may have multiple Connectors, the Engine receives and processes all requests from these connectors, handing the response back to the appropriate connector for transmission to the client. The Engine interface may be implemented to supply custom Engines, though this is uncommon.

    Note that the Engine may be used for Tomcat server clustering via the jvmRoute parameter. Read the Clustering documentation for more information.

    A Host is an association of a network name, e.g. www.yourcompany.com, to the Tomcat server. An Engine may contain multiple hosts, and the Host element also supports network aliases such as yourcompany.com and abc.yourcompany.com. Users rarely create custom Hosts because the StandardHost implementation provides significant additional functionality.

    A Connector handles communications with the client. There are multiple connectors available with Tomcat. These include the HTTP connector which is used for most HTTP traffic, especially when running Tomcat as a standalone server, and the AJP connector which implements the AJP procotol used when connecting Tomcat to a web server such as Apache HTTPD server. Creating a customized connector is a significant effort.

    A Context represents a web application. A Host may contain multiple contexts, each with a unique path. The Context interface may be implemented to create custom Contexts, but this is rarely the case because the StandardContext provides significant additional functionality.

    Tomcat is designed to be a fast and efficient implementation of the Servlet Specification. Tomcat came about as the reference implementation of this specification, and has remained rigorous in adhering to the specification. At the same time, significant attention has been paid to Tomcat's performance and it is now on par with other servlet containers, including commercial ones.

    In recent releases of Tomcat, mostly starting with Tomcat 5, we have begun efforts to make more aspects of Tomcat manageable via JMX. In addition, the Manager and Admin webapps have been greatly enhanced and improved. Manageability is a primary area of concern for us as the product matures and the specification becomes more stable.

    tomcat7-7.0.52/webapps/docs/windows-service-howto.xml0000644000175100017510000003214212271304167022551 0ustar locutuslocutus ]> &project; Mladen Turk Windows service HOW-TO

    Tomcat7 is a service application for running Tomcat7 as NT service.

    Tomcat7w is a GUI application for monitoring and configuring Tomcat services.

    The available command line options are:

    //ES// Edit service configuration This is the default operation. It is called if the no option is provided but the executable is renamed to servicenameW.exe
    //MS// Monitor service Put the icon in the system tray

    Each command line directive is in the form of //XX//ServiceName

    The available command line options are:

    //TS// Run the service as console application This is the default operation. It is called if the no option is provided. The ServiceName is the name of the executable without exe suffix, meaning Tomcat7
    //RS// Run the service Called only from ServiceManager
    //SS// Stop the service
    //US// Update service parameters
    //IS// Install service
    //DS// Delete service Stops the service if running

    Each command parameter is prefixed with --. If the command line is prefixed with ++ then it's value will be appended to the existing option. If the environment variable with the same name as command line parameter but prefixed with PR_ exists it will take precedence. For example: set PR_CLASSPATH=xx.jar

    is equivalent to providing --Classpath=xx.jar

    as command line parameter.

    ParameterName Default Description
    --Description Service name description (maximum 1024 characters)
    --DisplayName ServiceName Service display name
    --Install procrun.exe //RS//ServiceName Install image
    --Startup manual Service startup mode can be either auto or manual
    --DependsOn List of services that this service depend on. Dependent services are separated using either # or ; characters
    --Environment List of environment variables that will be provided to the service in the form key=value. They are separated using either # or ; characters. If you need to use either the # or ; character within a value then the entire value must be enclosed inside single quotes.
    --User User account used for running executable. It is used only for StartMode java or exe and enables running applications as service under account without LogonAsService privilege.
    --Password Password for user account set by --User parameter
    --JavaHome JAVA_HOME Set a different JAVA_HOME than defined by JAVA_HOME environment variable
    --Jvm auto Use either auto or specify the full path to the jvm.dll. You can use the environment variable expansion here.
    --JvmOptions -Xrs List of options in the form of -D or -X that will be passed to the JVM. The options are separated using either # or ; characters.
    --Classpath Set the Java classpath
    --JvmMs Initial memory pool size in MB
    --JvmMx Maximum memory pool size in MB
    --JvmSs Thread stack size in KB
    --StartImage Executable that will be run.
    --StartPath Working path for the start image executable.
    --StartClass Class that will be used for startup.
    --StartParams List of parameters that will be passed to either StartImage or StartClass. Parameters are separated using either # or ; character.
    --StartMethod Main Method name if differs then main
    --StartMode executable Can one of jvm java or exe
    --StopImage Executable that will be run on Stop service signal.
    --StopPath Working path for the stop image executable.
    --StopClass Class that will be used on Stop service signal.
    --StopParams List of parameters that will be passed to either StopImage or StopClass. Parameters are separated using either # or ; character.
    --StopMethod Main Method name if differs then main
    --StopMode executable Can one of jvm java or exe
    --StopTimeout No Timeout Defines the timeout in seconds that procrun waits for service to exit gracefully.
    --LogPath working path Defines the path for logging
    --LogPrefix jakarta_service Defines the service log filename
    --LogLevel INFO Defines the logging level and can be either error, info, warn or debug
    --StdOutput Redirected stdout filename
    --StdError Redirected stderr filename

    The safest way to manually install the service is to use the provided service.bat script. Administrator privileges are required to run this script. If necessary, you can use the /user switch to specify a user to use for the installation of the service.

    NOTE: On Windows Vista or any other operating system with User Account Control (UAC) you must either disable UAC or right-click on cmd.exe and select "Run as administrator" in order to run this script. If UAC is enabled neither being logged on with an Administrator account, nor using the /user switch is sufficient.

    Install the service named 'Tomcat7' C:\> service.bat install

    There is a 2nd optional parameter that lets you specify the name of the service, as displayed in Windows services.

    Install the service named 'MyService' C:\> service.bat install MyService

    If using tomcat7.exe, you need to use the //IS// parameter.

    Install the service named 'Tomcat7' C:\> tomcat7 //IS//Tomcat7 --DisplayName="Apache Tomcat 7" \ C:\> --Install="C:\Program Files\Tomcat\bin\tomcat7.exe" --Jvm=auto \ C:\> --StartMode=jvm --StopMode=jvm \ C:\> --StartClass=org.apache.catalina.startup.Bootstrap --StartParams=start \ C:\> --StopClass=org.apache.catalina.startup.Bootstrap --StopParams=stop

    To update the service parameters, you need to use the //US// parameter.

    Update the service named 'Tomcat7' C:\> tomcat7 //US//Tomcat7 --Description="Apache Tomcat Server - http://tomcat.apache.org/ " \ C:\> --Startup=auto --Classpath=%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\bin\bootstrap.jar

    If you gave the service an optional name, you need to specify it like this:

    Update the service named 'MyService' C:\> tomcat7 //US//MyService --Description="Apache Tomcat Server - http://tomcat.apache.org/ " \ C:\> --Startup=auto --Classpath=%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\bin\bootstrap.jar

    To remove the service, you need to use the //DS// parameter.
    If the service is running it will be stopped and then deleted.

    Remove the service named 'Tomcat7' C:\> tomcat7 //DS//Tomcat7

    If you gave the service an optional name, you need to specify it like this:

    Remove the service named 'MyService' C:\> tomcat7 //DS//MyService

    To run the service in console mode, you need to use the //TS// parameter. The service shutdown can be initiated by pressing CTRL+C or CTRL+BREAK. If you rename the tomcat7.exe to testservice.exe then you can just execute the testservice.exe and this command mode will be executed by default.

    Run the service named 'Tomcat7' in console mode C:\> tomcat7 //TS//Tomcat7 [additional arguments] Or simply execute: C:\> tomcat7

    Tomcat supports installation of multiple instances. You can have a single installation of Tomcat with multiple instances running on different IP/port combinations, or multiple Tomcat versions, each running one or more instances on different IP/ports.

    Each instance folder will need the following structure:

    • conf
    • logs
    • temp
    • webapps
    • work

    At a minimum, conf should contain a copy of the following files from CATALINA_HOME\conf\. Any files not copied and edited, will be picked up by default from CATALINA_HOME\conf, i.e. CATALINA_BASE\conf files override defaults from CATALINA_HOME\conf.

    • server.xml
    • web.xml

    You must edit CATALINA_BASE\conf\server.xml to specify a unique IP/port for the instance to listen on. Find the line that contains

    <Connector port="8080" ...
    and add an address attribute and/or update the port number so as to specify a unique IP/port combination.

    To install an instance, first set the CATALINA_HOME environment variable to the name of the Tomcat installation directory. Then create a second environment variable CATALINA_BASE and point this to the instance folder. Then run "service install" command specifying a service name.

    set CATALINA_HOME=c:\tomcat_7 set CATALINA_BASE=c:\tomcat_7\instances\instance1 service install instance1

    To modify the service settings, you can run tomcat7w //ES//instance1.

    For additional instances, create additional instance folder, update the CATALINA_BASE environment variable, and run the service install again.

    set CATALINA_BASE=c:\tomcat_7\instances\instance2 service install instance2

    tomcat7-7.0.52/webapps/docs/websocketapi/0000755000175100017510000000000012301126373020212 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/websocketapi/index.html0000644000175100017510000000222112233231243022201 0ustar locutuslocutus API docs The WebSocket Javadoc is not installed by default. Download and install the "fulldocs" package to get it. You can also access the javadoc online in the Tomcat documentation bundle. tomcat7-7.0.52/webapps/docs/config/0000755000175100017510000000000012301126373016777 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/config/host.xml0000644000175100017510000007160312271304167020512 0ustar locutuslocutus ]> &project; Craig R. McClanahan Remy Maucherat Yoav Shapira The Host Container

    The Host element represents a virtual host, which is an association of a network name for a server (such as "www.mycompany.com" with the particular server on which Tomcat is running. For clients to be able to connect to a Tomcat server using its network name, this name must be registered in the Domain Name Service (DNS) server that manages the Internet domain you belong to - contact your Network Administrator for more information.

    In many cases, System Administrators wish to associate more than one network name (such as www.mycompany.com and company.com) with the same virtual host and applications. This can be accomplished using the Host Name Aliases feature discussed below.

    One or more Host elements are nested inside an Engine element. Inside the Host element, you can nest Context elements for the web applications associated with this virtual host. Exactly one of the Hosts associated with each Engine MUST have a name matching the defaultHost attribute of that Engine.

    Clients normally use host names to identify the server they wish to connect to. This host name is also included in the HTTP request headers. Tomcat extracts the host name from the HTTP headers and looks for a Host with a matching name. If no match is found, the request is routed to the default host. The name of the default host does not have to match a DNS name (although it can) since any request where the DNS name does not match the name of a Host element will be routed to the default host.

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    All implementations of Host support the following attributes:

    The Application Base directory for this virtual host. This is the pathname of a directory that may contain web applications to be deployed on this virtual host. You may specify an absolute pathname, or a pathname that is relative to the $CATALINA_BASE directory. See Automatic Application Deployment for more information on automatic recognition and deployment of web applications. If not specified, the default of webapps will be used.

    The XML Base directory for this virtual host. This is the pathname of a directory that may contain context XML descriptors to be deployed on this virtual host. You may specify an absolute pathname for this directory, or a pathname that is relative to the $CATALINA_BASE directory. See Automatic Application Deployment for more information on automatic recognition and deployment of web applications. If not specified the default of conf/<engine_name>/<host_name> will be used.

    If set to true, Tomcat will attempt to create the directories defined by the attributes appBase and xmlBase during the startup phase. The default value is true. If set to true, and directory creation fails, an error message will be printed out but will not halt the startup sequence.

    This flag value indicates if Tomcat should check periodically for new or updated web applications while Tomcat is running. If true, Tomcat periodically checks the appBase and xmlBase directories and deploys any new web applications or context XML descriptors found. Updated web applications or context XML descriptors will trigger a reload of the web application. The flag's value defaults to true. See Automatic Application Deployment for more information.

    This value represents the delay in seconds between the invocation of the backgroundProcess method on this host and its child containers, including all contexts. Child containers will not be invoked if their delay value is not negative (which would mean they are using their own processing thread). Setting this to a positive value will cause a thread to be spawn. After waiting the specified amount of time, the thread will invoke the backgroundProcess method on this host and all its child containers. A host will use background processing to perform live web application deployment related tasks. If not specified, the default value for this attribute is -1, which means the host will rely on the background processing thread of its parent engine.

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Host interface. If not specified, the standard value (defined below) will be used.

    A regular expression defining paths to ignore when autoDeploy and deployOnStartup are set. This allows you to keep your configuration in a version control system, for example, and not deploy a .svn or CVS folder that happens to be in the appBase.

    This regular expression is relative to appBase. It is also anchored, meaning the match is performed against the entire file/directory name. So, foo matches only a file or directory named foo but not foo.war, foobar, or myfooapp. To match anything with "foo", you could use .*foo.*.

    See Automatic Application Deployment for more information.

    This flag value indicates if web applications from this host should be automatically deployed when Tomcat starts. The flag's value defaults to true. See Automatic Application Deployment for more information.

    Usually the network name of this virtual host, as registered in your Domain Name Service server. Regardless of the case used to specify the host name, Tomcat will convert it to lower case internally. One of the Hosts nested within an Engine MUST have a name that matches the defaultHost setting for that Engine. See Host Name Aliases for information on how to assign more than one network name to the same virtual host.

    The number of threads this Host will use to start child Context elements in parallel. The same thread pool will be used to deploy new Contexts if automatic deployment is being used. The special value of 0 will result in the value of Runtime.getRuntime().availableProcessors() being used. Negative values will result in Runtime.getRuntime().availableProcessors() + value being used unless this is less than 1 in which case 1 thread will be used. If not specified, the default value of 1 will be used.

    This flag determines if Tomcat, as part of the auto deployment process, will check for old, unused versions of web applications deployed using parallel deployment and, if any are found, remove them. This flag only applies if autoDeploy is true. If not specified the default value of false will be used.

    The standard implementation of Host is org.apache.catalina.core.StandardHost. It supports the following additional attributes (in addition to the common attributes listed above):

    Set to true if you want a context XML descriptor embedded inside the application (located at /META-INF/context.xml) to be copied to xmlBase when the application is deployed. On subsequent starts, the copied context XML descriptor will be used in preference to any context XML descriptor embedded inside the application even if the descriptor embedded inside the application is more recent. The flag's value defaults to false. Note if deployXML is false, this attribute will have no effect.

    Set to false if you want to disable parsing the context XML descriptor embedded inside the application (located at /META-INF/context.xml). Security conscious environments should set this to false to prevent applications from interacting with the container's configuration. The administrator will then be responsible for providing an external context configuration file, and putting it in the location defined by the xmlBase attribute. If this flag is false, a descriptor is located at /META-INF/context.xml and no descriptor is present in xmlBase then the context will fail to start in case the descriptor contains necessary configuration for secure deployment (such as a RemoteAddrValve) which should not be ignored. The flag's value defaults to true unless a security manager is enabled when the default is false.

    Java class name of the error reporting valve which will be used by this Host. The responsibility of this valve is to output error reports. Setting this property allows to customize the look of the error pages which will be generated by Tomcat. This class must implement the org.apache.catalina.Valve interface. If none is specified, the value org.apache.catalina.valves.ErrorReportValve will be used by default.

    Set to true if you want web applications that are placed in the appBase directory as web application archive (WAR) files to be unpacked into a corresponding disk directory structure, false to run such web applications directly from a WAR file. WAR files located outside of the Host's appBase will not be expanded. See Automatic Application Deployment for more information.

    Pathname to a scratch directory to be used by applications for this Host. Each application will have its own sub directory with temporary read-write use. Configuring a Context workDir will override use of the Host workDir configuration. This directory will be made visible to servlets in the web application by a servlet context attribute (of type java.io.File) named javax.servlet.context.tempdir as described in the Servlet Specification. If not specified, a suitable directory underneath $CATALINA_BASE/work will be provided.

    You can nest one or more Context elements inside this Host element, each representing a different web application associated with this virtual host.

    You can nest at most one instance of the following utility components by nesting a corresponding element inside your Host element:

    • Realm - Configure a realm that will allow its database of users, and their associated roles, to be shared across all Contexts nested inside this Host (unless overridden by a Realm configuration at a lower level).

    A host is associated with the org.apache.catalina.core.ContainerBase.[engine_name].[host_name] log category. Note that the brackets are part of the name, don't omit them.

    When you run a web server, one of the output files normally generated is an access log, which generates one line of information for each request processed by the server, in a standard format. Catalina includes an optional Valve implementation that can create access logs in the same standard format created by web servers, or in any number of custom formats.

    You can ask Catalina to create an access log for all requests processed by an Engine, Host, or Context by nesting a Valve element like this:

    <Host name="localhost" ...> ... <Valve className="org.apache.catalina.valves.AccessLogValve" prefix="localhost_access_log." suffix=".txt" pattern="common"/> ... </Host>

    See Access Log Valve for more information on the configuration attributes that are supported.

    If you are using the standard Host implementation with default settings then applications in the appBase or with context files in the configBase are automatically deployed when Tomcat starts (the deployOnStartup property defaults to true) and reloaded or redeployed (as appropriate) when a change is detected while Tomcat is running (the autoDeploy attribute also defaults to true).

    deployOnStartup and autoDeploy trigger execution of exactly the same code so the behaviour is very similar. However, there is one key difference. When Tomcat starts it has no knowledge of which files are the same, which have been changed and which are new. It therefore treats all files as new. While Tomcat is running, it can differentiate between unchanged, modified and new files. This leads to some differences in behaviour between files being modified while Tomcat is running and files being modified while Tomcat is stopped.

    When you use automatic deployment, related files (a web application may have a context.xml file, a WAR and a directory) that exist in the Host's appBase and/or configBase must conform to the expected naming convention. In short, this means files for the same web application must share the same base name.

    The automatic deployment process identifies new and/or modified web applications using the following search order:

    1. Web applications with a context.xml file located in the Host's configBase.
    2. Web applications with a WAR file located in the Host's appBase that have not already been identified during the scan for context.xml files.
    3. Web applications with a directory located in the Host's appBase that have not already been identified during the scans for context.xml and/or WAR files.

    When autoDeploy is true, the automatic deployment process will monitor the deployed web applications for changes. Depending on exactly what changes, the web application will either be re-deployed or reloaded. Re-deployment involves the creation of a new web application and, if using the standard session manager, user sessions will not be retained. Reloading uses the existing web application but re-parses the web.xml and reloads any classes. If using the standard session manager, user sessions will be persisted.

    Users may add to the files that the automatic deployment process monitors for reloading (i.e. any change to one of these files triggers a reload of the web application) by adding a WatchedResources element to the context.xml file. See the Context documentation for further details.

    When using automatic deployment, the docBase defined by an XML Context file should be outside of the appBase directory. If this is not the case, difficulties may be experienced deploying the web application or the application may be deployed twice. The deployIgnore attribute can be used to avoid this situation.

    Note that if you are defining contexts explicitly in server.xml, you should probably turn off automatic application deployment or specify deployIgnore carefully. Otherwise, the web applications will each be deployed twice, and that may cause problems for the applications.

    There are many possible combinations of settings, new files, changed files and deleted files. A separate page describes the expected behaviour of the automatic deployment process in many of these scenarios.

    In many server environments, Network Administrators have configured more than one network name (in the Domain Name Service (DNS) server), that resolve to the IP address of the same server. Normally, each such network name would be configured as a separate Host element in conf/server.xml, each with its own set of web applications.

    However, in some circumstances, it is desirable that two or more network names should resolve to the same virtual host, running the same set of applications. A common use case for this scenario is a corporate web site, where it is desirable that users be able to utilize either www.mycompany.com or company.com to access exactly the same content and applications.

    This is accomplished by utilizing one or more Alias elements nested inside your Host element. For example:

    <Host name="www.mycompany.com" ...> ... <Alias>mycompany.com</Alias> ... </Host>

    In order for this strategy to be effective, all of the network names involved must be registered in your DNS server to resolve to the same computer that is running this instance of Catalina.

    If you have implemented a Java object that needs to know when this Host is started or stopped, you can declare it by nesting a Listener element inside this element. The class name you specify must implement the org.apache.catalina.LifecycleListener interface, and it will be notified about the occurrence of the corresponding lifecycle events. Configuration of such a listener looks like this:

    <Host name="localhost" ...> ... <Listener className="com.mycompany.mypackage.MyListener" ... > ... </Host>

    Note that a Listener can have any number of additional properties that may be configured from this element. Attribute names are matched to corresponding JavaBean property names using the standard property method naming patterns.

    You can ask Catalina to check the IP address, or host name, on every incoming request directed to the surrounding Engine, Host, or Context element. The remote address or name will be checked against configured "accept" and/or "deny" filters, which are defined using java.util.regex Regular Expression syntax. Requests that come from locations that are not accepted will be rejected with an HTTP "Forbidden" error. Example filter declarations:

    <Host name="localhost" ...> ... <Valve className="org.apache.catalina.valves.RemoteHostValve" allow=".*\.mycompany\.com|www\.yourcompany\.com"/> <Valve className="org.apache.catalina.valves.RemoteAddrValve" deny="192\.168\.1\.\d+"/> ... </Host>

    See Remote Address Filter and Remote Host Filter for more information about the configuration options that are supported.

    In many environments, but particularly in portal environments, it is desireable to have a user challenged to authenticate themselves only once over a set of web applications deployed on a particular virtual host. This can be accomplished by nesting an element like this inside the Host element for this virtual host:

    <Host name="localhost" ...> ... <Valve className="org.apache.catalina.authenticator.SingleSignOn"/> ... </Host>

    The Single Sign On facility operates according to the following rules:

    • All web applications configured for this virtual host must share the same Realm. In practice, that means you can nest the Realm element inside this Host element (or the surrounding Engine element), but not inside a Context element for one of the involved web applications.
    • As long as the user accesses only unprotected resources in any of the web applications on this virtual host, they will not be challenged to authenticate themselves.
    • As soon as the user accesses a protected resource in any web application associated with this virtual host, the user will be challenged to authenticate himself or herself, using the login method defined for the web application currently being accessed.
    • Once authenticated, the roles associated with this user will be utilized for access control decisions across all of the associated web applications, without challenging the user to authenticate themselves to each application individually.
    • As soon as the user logs out of one web application (for example, by invalidating the corresponding session if form based login is used), the user's sessions in all web applications will be invalidated. Any subsequent attempt to access a protected resource in any application will require the user to authenticate himself or herself again.
    • The Single Sign On feature utilizes HTTP cookies to transmit a token that associates each request with the saved user identity, so it can only be utilized in client environments that support cookies.

    Many web servers can automatically map a request URI starting with a tilde character ("~") and a username to a directory (commonly named public_html) in that user's home directory on the server. You can accomplish the same thing in Catalina by using a special Listener element like this (on a Unix system that uses the /etc/passwd file to identify valid users):

    <Host name="localhost" ...> ... <Listener className="org.apache.catalina.startup.UserConfig" directoryName="public_html" userClass="org.apache.catalina.startup.PasswdUserDatabase"/> ... </Host>

    On a server where /etc/passwd is not in use, you can request Catalina to consider all directories found in a specified base directory (such as c:\Homes in this example) to be considered "user home" directories for the purposes of this directive:

    <Host name="localhost" ...> ... <Listener className="org.apache.catalina.startup.UserConfig" directoryName="public_html" homeBase=c:\Homes" userClass="org.apache.catalina.startup.HomesUserDatabase"/> ... </Host>

    If a user home directory has been set up for a user named craigmcc, then its contents will be visible from a client browser by making a request to a URL like:

    http://www.mycompany.com:8080/~craigmcc

    Successful use of this feature requires recognition of the following considerations:

    • Each user web application will be deployed with characteristics established by the global and host level default context settings.
    • It is legal to include more than one instance of this Listener element. This would only be useful, however, in circumstances where you wanted to configure more than one "homeBase" directory.
    • The operating system username under which Catalina is executed MUST have read access to each user's web application directory, and all of its contents.
    tomcat7-7.0.52/webapps/docs/config/realm.xml0000644000175100017510000013766712271304167020652 0ustar locutuslocutus ]> &project; Craig R. McClanahan The Realm Component

    A Realm element represents a "database" of usernames, passwords, and roles (similar to Unix groups) assigned to those users. Different implementations of Realm allow Catalina to be integrated into environments where such authentication information is already being created and maintained, and then utilize that information to implement Container Managed Security as described in the Servlet Specification.

    A Catalina container (Engine, Host, or Context) may contain no more than one Realm element (although if supported by the Realm this one Realm may itself contain multiple nested Realms). In addition, the Realm associated with an Engine or a Host is automatically inherited by lower-level containers unless the lower level container explicitly defines its own Realm.

    For more in-depth information about container managed security in web applications, as well as more information on configuring and using the standard realm component implementations, please see the Container-Managed Security Guide.

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    All implementations of Realm support the following attributes:

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Realm interface.

    Unlike most Catalina components, there are several standard Realm implementations available. As a result, the className attribute MUST be used to select the implementation you wish to use.

    The JDBC Database Realm connects Tomcat to a relational database, accessed through an appropriate JDBC driver, to perform lookups of usernames, passwords, and their associated roles. Because the lookup is done each time that it is required, changes to the database will be immediately reflected in the information used to authenticate new logins.

    A rich set of additional attributes lets you configure the required connection to the underlying database, as well as the table and column names used to retrieve the required information:

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    When this attribute has the value of authOnly or strictAuthOnly, the roleNameCol and userRoleTable attributes become optional. If those two attributes are omitted, the user's roles will not be loaded by this Realm.

    The database username to use when establishing the JDBC connection.

    The database password to use when establishing the JDBC connection.

    The connection URL to be passed to the JDBC driver when establishing a database connection.

    The name of the MessageDigest algorithm used to encode user passwords stored in the database. If not specified, user passwords are assumed to be stored in clear-text.

    The charset for encoding digests. If not specified, the platform default will be used.

    Fully qualified Java class name of the JDBC driver to be used to connect to the authentication database.

    Name of the column, in the "user roles" table, which contains a role name assigned to the corresponding user.

    This attribute is required in majority of configurations. See allRolesMode attribute for a rare case when it can be omitted.

    When processing users authenticated via the GSS-API, this attribute controls if any "@..." is removed from the end of the user name. If not specified, the default is true.

    Name of the column, in the "users" table, which contains the user's credentials (i.e. password). If a value for the digest attribute is specified, this component will assume that the passwords have been encoded with the specified algorithm. Otherwise, they will be assumed to be in clear text.

    Name of the column, in the "users" and "user roles" table, that contains the user's username.

    Name of the "user roles" table, which must contain columns named by the userNameCol and roleNameCol attributes.

    This attribute is required in majority of configurations. See allRolesMode attribute for a rare case when it can be omitted.

    Name of the "users" table, which must contain columns named by the userNameCol and userCredCol attributes.

    When using X509 client certificates, this specifies the class name that will be used to retrieve the user name from the certificate. The class must implement the org.apache.catalina.realm.X509UsernameRetriever interface. The default is to use the certificate's SubjectDN as the username.

    See the Container-Managed Security Guide for more information on setting up container managed security using the JDBC Database Realm component.

    The DataSource Database Realm connects Tomcat to a relational database, accessed through a JNDI named JDBC DataSource to perform lookups of usernames, passwords, and their associated roles. Because the lookup is done each time that it is required, changes to the database will be immediately reflected in the information used to authenticate new logins.

    The JDBC Realm uses a single db connection. This requires that realm based authentication be synchronized, i.e. only one authentication can be done at a time. This could be a bottleneck for applications with high volumes of realm based authentications.

    The DataSource Database Realm supports simultaneous realm based authentications and allows the underlying JDBC DataSource to handle optimizations like database connection pooling.

    A rich set of additional attributes lets you configure the name of the JNDI JDBC DataSource, as well as the table and column names used to retrieve the required information:

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    When this attribute has the value of authOnly or strictAuthOnly, the roleNameCol and userRoleTable attributes become optional. If those two attributes are omitted, the user's roles will not be loaded by this Realm.

    The name of the JNDI JDBC DataSource for this Realm.

    The name of the MessageDigest algorithm used to encode user passwords stored in the database. If not specified, user passwords are assumed to be stored in clear-text.

    When the realm is nested inside a Context element, this allows the realm to use a DataSource defined for the Context rather than a global DataSource. If not specified, the default is false: use a global DataSource.

    Name of the column, in the "user roles" table, which contains a role name assigned to the corresponding user.

    This attribute is required in majority of configurations. See allRolesMode attribute for a rare case when it can be omitted.

    When processing users authenticated via the GSS-API, this attribute controls if any "@..." is removed from the end of the user name. If not specified, the default is true.

    Name of the column, in the "users" table, which contains the user's credentials (i.e. password). If a value for the digest attribute is specified, this component will assume that the passwords have been encoded with the specified algorithm. Otherwise, they will be assumed to be in clear text.

    Name of the column, in the "users" and "user roles" table, that contains the user's username.

    Name of the "user roles" table, which must contain columns named by the userNameCol and roleNameCol attributes.

    This attribute is required in majority of configurations. See allRolesMode attribute for a rare case when it can be omitted.

    Name of the "users" table, which must contain columns named by the userNameCol and userCredCol attributes.

    When using X509 client certificates, this specifies the class name that will be used to retrieve the user name from the certificate. The class must implement the org.apache.catalina.realm.X509UsernameRetriever interface. The default is to use the certificate's SubjectDN as the username.

    See the DataSource Realm HOW-TO for more information on setting up container managed security using the DataSource Database Realm component.

    The JNDI Directory Realm connects Tomcat to an LDAP Directory, accessed through an appropriate JNDI driver, that stores usernames, passwords, and their associated roles. Changes to the directory are immediately reflected in the information used to authenticate new logins.

    The directory realm supports a variety of approaches to using LDAP for authentication:

    • The realm can either use a pattern to determine the distinguished name (DN) of the user's directory entry, or search the directory to locate that entry.
    • The realm can authenticate the user either by binding to the directory with the DN of the user's entry and the password presented by the user, or by retrieving the password from the user's entry and performing a comparison locally.
    • Roles may be represented in the directory as explicit entries found by a directory search (e.g. group entries of which the user is a member), as the values of an attribute in the user's entry, or both.

    A rich set of additional attributes lets you configure the required behaviour as well as the connection to the underlying directory and the element and attribute names used to retrieve information from the directory:

    Microsoft Active Directory often returns referrals. When iterating over NamingEnumerations these lead to PartialResultExceptions. If you want us to ignore those exceptions, set this attribute to "true". Unfortunately there's no stable way to detect, if the Exceptions really come from an AD referral. The default value is "false".

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    If a socket connection can not be made to the provider at the connectionURL an attempt will be made to use the alternateURL.

    A string specifying the type of authentication to use. "none", "simple", "strong" or a provider specific definition can be used. If no value is given the providers default is used.

    A role name assigned to each successfully authenticated user in addition to the roles retrieved from LDAP. If not specified, only the roles retrieved via LDAP are used.

    The directory username to use when establishing a connection to the directory for LDAP search operations. If not specified an anonymous connection is made, which is often sufficient unless you specify the userPassword property.

    The directory password to use when establishing a connection to the directory for LDAP search operations. If not specified an anonymous connection is made, which is often sufficient unless you specify the userPassword property.

    The timeout in milliseconds to use when establishing the connection to the LDAP directory. If not specified, a value of 5000 (5 seconds) is used.

    The connection URL to be passed to the JNDI driver when establishing a connection to the directory.

    Fully qualified Java class name of the factory class used to acquire our JNDI InitialContext. By default, assumes that the standard JNDI LDAP provider will be utilized.

    A string specifying how aliases are to be dereferenced during search operations. The allowed values are "always", "never", "finding" and "searching". If not specified, "always" is used.

    The digest algorithm to apply to the plaintext password offered by the user before comparing it with the value retrieved from the directory. Valid values are those accepted for the algorithm name by the java.security.MessageDigest class. If not specified the plaintext password is assumed to be retrieved. Not required unless userPassword is specified

    A string specifying the security protocol to use. If not given the providers default is used.

    How do we handle JNDI referrals? Allowed values are "ignore", "follow", or "throw" (see javax.naming.Context.REFERRAL for more information). Microsoft Active Directory often returns referrals. If you need to follow them set referrals to "follow". Caution: if your DNS is not part of AD, the LDAP client lib might try to resolve your domain name in DNS to find another LDAP server.

    The base directory entry for performing role searches. If not specified the top-level element in the directory context will be used. If specified it may optionally include pattern replacements "{0}".."{n}" corresponding to the name parts of the user's distinguished name (as returned by javax.naming.Name.get()).

    The name of the attribute that contains role names in the directory entries found by a role search. In addition you can use the userRoleName property to specify the name of an attribute, in the user's entry, containing additional role names.

    If roleName is not specified a role search does not take place, and roles are taken only from the user's entry.

    Set to true if you want to nest roles into roles. When a role search is performed and the value of this property is true, the search will be repeated recursively to find all the roles that belong to the user either directly or indirectly. If not specified, the default value of false is used.

    The LDAP filter expression used for performing role searches.

    Use {0} to substitute the distinguished name (DN) of the user, and/or {1} to substitute the username, and/or {2} for the value of an attribute from the user's directory entry, of the authenticated user. The name of the attribute that provides the value for {2} is configured by the userRoleAttribute property.

    When roleNested property is true, this filter expression will be also used to recursively search for other roles, which indirectly belong to this user. To find the roles that match the newly found role, the following values are used: {0} is substituted by the distinguished name of the newly found role, and both {1} and {2} are substituted by the name of the role (see the roleName property). The userRoleAttribute property is not applicable to this search.

    If this property is not specified, a role search does not take place and roles are taken only from the attribute in the user's entry specified by the userRoleName property.

    When searching for user roles, should the search be performed as the user currently being authenticated? If false, connectionName and connectionPassword will be used if specified, else an anonymous. If not specified, the default value of false is used. Note that when accessing the directory using delegated credentials, this attribute is always ignored and the search is performed using the delegated credentials.

    Set to true if you want to search the entire subtree of the element specified by the roleBase property for role entries associated with the user. The default value of false causes only the top level to be searched.

    Specifies the maximum number of records to return when using the userSearch attribute. If not specified, the default of 0 is used which indicates no limit.

    When the JNDI Realm is used with the SPNEGO authenticator and useDelegatedCredential is true this attribute controls the QOP (Quality of Protection) that should be used for the connection to the LDAP server after authentication. This value is used to set the javax.security.sasl.qop environment property for the LDAP connection. This attribute should be a comma-separated list of values selected from auth-conf, auth-int and auth. See Java documentation for more details.

    The default value is auth-conf.

    When processing users authenticated via the GSS-API, this attribute controls if any "@..." is removed from the end of the user name. If not specified, the default is true.

    Specifies the time (in milliseconds) to wait for records to be returned when using the userSearch attribute. If not specified, the default of 0 is used which indicates no limit.

    When the JNDIRealm is used with the SPNEGO authenticator, delegated credentials for the user may be available. If such credentials are present, this attribute controls whether or not they are used to connect to the directory. If not specified, the default value of true is used.

    The base element for user searches performed using the userSearch expression. Not used if you are using the userPattern expression.

    Name of the attribute in the user's entry containing the user's password. If you specify this value, JNDIRealm will bind to the directory using the values specified by connectionName and connectionPassword properties, and retrieve the corresponding attribute for comparison to the value specified by the user being authenticated. If you do not specify this value, JNDIRealm will attempt a simple bind to the directory using the DN of the user's entry and the password presented by the user, with a successful bind being interpreted as an authenticated user.

    Pattern for the distinguished name (DN) of the user's directory entry, with {0} marking where the actual username should be inserted. You can use this property instead of userSearch, userSubtree and userBase when the distinguished name contains the username and is otherwise the same for all users. Note that when accessing the directory using delegated credentials, this attribute is always ignored and userSearch, userSubtree and userBase are always used instead.

    The name of an attribute in the user's directory entry containing zero or more values for the names of roles assigned to this user. In addition you can use the roleName property to specify the name of an attribute to be retrieved from individual role entries found by searching the directory. If userRoleName is not specified all the roles for a user derive from the role search.

    The name of an attribute in the user's directory entry containing the value that you wish to use when you search for roles. This is especially useful for RFC 2307 where the role memberUid can be the uid or the uidNumber of the user. This value will be marked as {2} in your role search filter expression. This value will NOT be available for nested role searches.

    The LDAP filter expression to use when searching for a user's directory entry, with {0} marking where the actual username should be inserted. Use this property (along with the userBase and userSubtree properties) instead of userPattern to search the directory for the user's entry.

    Set to true if you want to search the entire subtree of the element specified by the userBase property for the user's entry. The default value of false causes only the top level to be searched. Not used if you are using the userPattern expression.

    When using X509 client certificates, this specifies the class name that will be used to retrieve the user name from the certificate. The class must implement the org.apache.catalina.realm.X509UsernameRetriever interface. The default is to use the certificate's SubjectDN as the username.

    See the Container-Managed Security Guide for more information on setting up container managed security using the JNDI Directory Realm component.

    The UserDatabase Realm is a Realm implementation that is based on a UserDatabase resource made available through the global JNDI resources configured for this Tomcat instance.

    The UserDatabase Realm implementation supports the following additional attributes:

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    The name of the global UserDatabase resource that this realm will use for user, password and role information.

    When using X509 client certificates, this specifies the class name that will be used to retrieve the user name from the certificate. The class must implement the org.apache.catalina.realm.X509UsernameRetriever interface. The default is to use the certificate's SubjectDN as the username.

    See the Container-Managed Security Guide for more information on setting up container managed security using the UserDatabase Realm component and the JNDI resources how-to for more information on how to configure a UserDatabase resource.

    The Memory Based Realm is a simple Realm implementation that reads user information from an XML format, and represents it as a collection of Java objects in memory. This implementation is intended solely to get up and running with container managed security - it is NOT intended for production use. As such, there are no mechanisms for updating the in-memory collection of users when the content of the underlying data file is changed.

    The Memory Based Realm implementation supports the following additional attributes:

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    The digest algorithm used to store passwords in non-plaintext formats. Valid values are those accepted for the algorithm name by the java.security.MessageDigest class. If not specified, passwords are stored in clear text.

    Absolute or relative (to $CATALINA_BASE) pathname to the XML file containing our user information. See below for details on the XML element format required. If no pathname is specified, the default value is conf/tomcat-users.xml.

    When processing users authenticated via the GSS-API, this attribute controls if any "@..." is removed from the end of the user name. If not specified, the default is true.

    When using X509 client certificates, this specifies the class name that will be used to retrieve the user name from the certificate. The class must implement the org.apache.catalina.realm.X509UsernameRetriever interface. The default is to use the certificate's SubjectDN as the username.

    The XML document referenced by the pathname attribute must conform to the following requirements:

    • The root (outer) element must be <tomcat-users>.
    • Each authorized user must be represented by a single XML element <user>, nested inside the root element.
    • Each <user> element must have the following attributes:
      • name - Username of this user (must be unique within this file).
      • password - Password of this user (in clear text).
      • roles - Comma-delimited list of the role names assigned to this user.

    See the Container-Managed Security Guide for more information on setting up container managed security using the Memory Based Realm component.

    JAASRealm is an implementation of the Tomcat Realm interface that authenticates users through the Java Authentication & Authorization Service (JAAS) framework which is now provided as part of the standard J2SE API.

    Using JAASRealm gives the developer the ability to combine practically any conceivable security realm with Tomcat's CMA.

    JAASRealm is prototype for Tomcat of the JAAS-based J2EE authentication framework for J2EE v1.4, based on the JCP Specification Request 196 to enhance container-managed security and promote 'pluggable' authentication mechanisms whose implementations would be container-independent.

    Based on the JAAS login module and principal (see javax.security.auth.spi.LoginModule and javax.security.Principal), you can develop your own security mechanism or wrap another third-party mechanism for integration with the CMA as implemented by Tomcat.

    The JAAS Realm implementation supports the following additional attributes:

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    The name of the application as configured in your login configuration file (JAAS LoginConfig).

    A comma-separated list of the names of the classes that you have made for your user Principals.

    The name of a JAAS configuration file to use with this Realm. It will be searched for using ClassLoader#getResource(String) so it is possible for the configuration to be bundled within a web application. If not specified, the default JVM global JAAS configuration will be used.

    A comma-separated list of the names of the classes that you have made for your role Principals.

    When processing users authenticated via the GSS-API, this attribute controls if any "@..." is removed from the end of the user name. If not specified, the default is true.

    Instructs JAASRealm to use the context class loader for loading the user-specified LoginModule class and associated Principal classes. The default value is true, which is backwards-compatible with the way Tomcat 5 works. To load classes using the container's classloader, specify false.

    When using X509 client certificates, this specifies the class name that will be used to retrieve the user name from the certificate. The class must implement the org.apache.catalina.realm.X509UsernameRetriever interface. The default is to use the certificate's SubjectDN as the username.

    See the Container-Managed Security Guide for more information on setting up container managed security using the JAAS Realm component.

    CombinedRealm is an implementation of the Tomcat Realm interface that authenticates users through one or more sub-Realms.

    Using CombinedRealm gives the developer the ability to combine multiple Realms of the same or different types. This can be used to authenticate against different sources, provide fall back in case one Realm fails or for any other purpose that requires multiple Realms.

    Sub-realms are defined by nesting Realm elements inside the Realm element that defines the CombinedRealm. Authentication will be attempted against each Realm in the order they are listed. Authentication against any Realm will be sufficient to authenticate the user.

    See the Container-Managed Security Guide for more information on setting up container managed security using the CombinedRealm component.

    The CombinedRealm implementation supports the following additional attributes.

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    LockOutRealm is an implementation of the Tomcat Realm interface that extends the CombinedRealm to provide lock out functionality to provide a user lock out mechanism if there are too many failed authentication attempts in a given period of time.

    To ensure correct operation, there is a reasonable degree of synchronization in this Realm.

    This Realm does not require modification to the underlying Realms or the associated user storage mechanisms. It achieves this by recording all failed logins, including those for users that do not exist. To prevent a DOS by deliberating making requests with invalid users (and hence causing this cache to grow) the size of the list of users that have failed authentication is limited.

    Sub-realms are defined by nesting Realm elements inside the Realm element that defines the LockOutRealm. Authentication will be attempted against each Realm in the order they are listed. Authentication against any Realm will be sufficient to authenticate the user.

    The LockOutRealm implementation supports the following additional attributes.

    This attribute controls how the special role name * is handled when processing authorization constraints in web.xml. By default, the specification compliant value of strict is used which means that the user must be assigned one of the roles defined in web.xml. The alternative values are authOnly which means that the user must be authenticated but no check is made for assigned roles and strictAuthOnly which means that the user must be authenticated and no check will be made for assigned roles unless roles are defined in web.xml in which case the user must be assigned at least one of those roles.

    If a failed user is removed from the cache because the cache is too big before it has been in the cache for at least this period of time (in seconds) a warning message will be logged. Defaults to 3600 (1 hour).

    Number of users that have failed authentication to keep in cache. Over time the cache will grow to this size and may not shrink. Defaults to 1000.

    The number of times in a row a user has to fail authentication to be locked out. Defaults to 5.

    The time (in seconds) a user is locked out for after too many authentication failures. Defaults to 300 (5 minutes).

    See the Container-Managed Security Guide for more information on setting up container managed security using the LockOutRealm component.

    CombinedRealm Implementation

    If you are using the CombinedRealm Implementation or a Realm that extends the CombinedRealm, e.g. the LockOutRealm, <Realm> elements may be nested inside it.

    Other Realm Implementations

    No other Realm implementation supports nested components.

    See Single Sign On for information about configuring Single Sign On support for a virtual host.

    tomcat7-7.0.52/webapps/docs/config/cluster-manager.xml0000644000175100017510000002771512271304167022633 0ustar locutuslocutus ]> &project; Filip Hanik The ClusterManager object

    A cluster manager is an extension to Tomcat's session manager interface, org.apache.catalina.Manager. A cluster manager must implement the org.apache.catalina.ha.ClusterManager and is solely responsible for how the session is replicated.
    There are currently two different managers, the org.apache.catalina.ha.session.DeltaManager replicates deltas of session data to all members in the cluster. This implementation is proven and works very well, but has a limitation as it requires the cluster members to be homogeneous, all nodes must deploy the same applications and be exact replicas. The org.apache.catalina.ha.session.BackupManager also replicates deltas but only to one backup node. The location of the backup node is known to all nodes in the cluster. It also supports heterogeneous deployments, so the manager knows at what locations the web application is deployed.

    The <Manager> element defined inside the <Cluster> element is the template defined for all web applications that are marked <distributable/> in their web.xml file. However, you can still override the manager implementation on a per web application basis, by putting the <Manager> inside the <Context> element either in the context.xml file or the server.xml file.

    The name of this cluster manager, the name is used to identify a session manager on a node. The name might get modified by the Cluster element to make it unique in the container. Set to true if you wish to have session listeners notified when session attributes are being replicated or removed across Tomcat nodes in the cluster. When a web application is being shutdown, Tomcat issues an expire call to each session to notify all the listeners. If you wish for all sessions to expire on all nodes when a shutdown occurs on one node, set this value to true. Default value is false. A regular expression used to filter, which session attributes will be replicated. An attribute will only be replicated, if its name matches this pattern. If the pattern is not set (default), all attributes are eligible for replication. As an example, the value ^(userName|sessionHistory)$ will only replicate the two session attributes named userName and sessionHistory.

    The initial maximum time interval, in seconds, between client requests before a session is invalidated. A negative value will result in sessions never timing out. If the attribute is not provided, a default of 1800 seconds (30 minutes) is used.

    This attribute provides the initial value whenever a new session is created, but the interval may be dynamically varied by a servlet via the setMaxInactiveInterval method of the HttpSession object.

    The length of session ids created by this Manager, measured in bytes, excluding subsequent conversion to a hexadecimal string and excluding any JVM route information used for load balancing. The default is 16.

    Frequency of the session expiration, and related manager operations. Manager operations will be done once for the specified amount of backgroundProcess calls (i.e., the lower the amount, the more often the checks will occur). The minimum value is 1, and the default value is 6.

    Name of the Java class that extends java.security.SecureRandom to use to generate session IDs. If not specified, the default value is java.security.SecureRandom.

    Name of the provider to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the Manager will use the platform default provider and the default algorithm. If not specified, the platform default provider will be used.

    Name of the algorithm to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the Manager will use the platform default provider and the default algorithm. If not specified, the default algorithm of SHA1PRNG will be used. If the default algorithm is not supported, the platform default will be used. To specify that the platform default should be used, do not set the secureRandomProvider attribute and set this attribute to the empty string.

    When a web application is being shutdown, Tomcat issues an expire call to each session to notify all the listeners. If you wish for all sessions to expire on all nodes when a shutdown occurs on one node, set this value to true. Default value is false. The maximum number of active sessions that will be created by this Manager, or -1 (the default) for no limit. For this manager, all sessions are counted as active sessions irrespective if whether or not the current node is the primary node for the session. Set to true if you wish to have session listeners notified when sessions are created and expired across Tomcat nodes in the cluster. Set to true if you wish to have container listeners notified across Tomcat nodes in the cluster. The time in seconds to wait for a session state transfer to complete from another node when a node is starting up. Default value is 60 seconds. Flag whether send sessions as split blocks. If set to true, send all sessions as one big block. If set to false, send sessions as split blocks. Default value is true. The number of sessions in a session block message. This value is effective only when sendAllSessions is false. Default is 1000. Wait time between sending of session block messages. This value is effective only when sendAllSessions is false. Default is 2000 milliseconds. When this node sends a GET_ALL_SESSIONS message to other node, all session messages that are received as a response are queued. If this attribute is set to true, the received session messages (except any GET_ALL_SESSIONS sent by other nodes) are filtered by their timestamp. A message is dropped if it is not a GET_ALL_SESSIONS message and its timestamp is earlier than the timestamp of our GET_ALL_SESSIONS message. If set to false, all queued session messages are handled. Default is true. The backup manager uses a replicated map, this map is sending and receiving messages. You can setup the flag for how this map is sending messages, the default value is 6(synchronous).
    Note that if you use asynchronous messaging it is possible for update messages for a session to be processed by the receiving node in a different order to the order in which they were sent.
    The maximum number of active sessions that will be created by this Manager, or -1 (the default) for no limit. For this manager, only sessions where the current node is the primary node for the session are considered active sessions. Timeout for RPC message used for broadcast and transfer state from another map. Default value is 15000 milliseconds. Set to true if you wish to terminate replication map when replication map fails to start. If replication map is terminated, associated context will fail to start. If you set this attribute to false, replication map does not end. It will try to join the map membership in the heartbeat. Default value is false .
    tomcat7-7.0.52/webapps/docs/config/systemprops.xml0000644000175100017510000007361212271304167022147 0ustar locutuslocutus ]> &project; System Properties

    The following sections list the system properties that may be set to modify the default Tomcat behaviour.

    Set this to a fully qualified name of a class that implements org.apache.tomcat.util.IntrospectionUtils.PropertySource. Required to have a public constructor with no arguments.

    Use this to add a property source, that will be invoked when ${parameter} denoted parameters are found in the XML files that Tomcat parses.

    If true, the clustering module will attempt to use DNS to resolve any host names provided in the cluster configuration.

    If not specified, the default value of false will be used.

    The number of javax.el.BeanELResolver.BeanProperties objects that will be cached by the EL Parser.

    If not specified, the default of 1000 will be used.

    The number of parsed EL expressions that will be cached by the EL Parser.

    If not specified, the default of 5000 will be used.

    If true, when coercing expressions to numbers "" and null will be coerced to zero as required by the specification.

    If not specified, the default value of true will be used.

    If true, when parsing expressions, identifiers will not be checked to ensure that they conform to the Java Language Specification for Java identifiers.

    If not specified, the default value of false will be used.

    By default, JSPs that use their own base class via the extends attribute of the page directive, will have Tag pooling disabled since Jasper cannot guarantee that the necessary initialisation will have taken place. This can have a negative impact on performance. Providing the alternative base class calls _jspInit() from Servlet.init(), setting this property to true will enable pooling with an alternative base class. If the alternative base class does not call _jspInit() and this property is true, NPEs will occur when attempting to use tags.

    If not specified, the default value of false will be used.

    If true, the requirement to have the object referenced in jsp:getProperty action to be previously "introduced" to the JSP processor, as specified in the chapter JSP.5.3 of JSP 2.0 and later specifications, is enforced.

    If not specified, the specification compliant default of true will be used.

    The name of the variable to use for the expression language expression factory.

    If not specified, the default value of _el_expressionfactory will be used.

    The name of the variable to use for the instance manager factory.

    If not specified, the default value of _jsp_instancemanager will be used.

    If false the requirements for escaping quotes in JSP attributes will be relaxed so that an unescaped quote will not cause an error.

    If not specified, the specification compliant default of true will be used.

    If false the requirements for whitespace before an attribute name will be relaxed so that the lack of whitespace will not cause an error.

    If not specified, the specification compliant default of true will be used.

    If true, any tag buffer that expands beyond org.apache.jasper.Constants.DEFAULT_TAG_BUFFER_SIZE will be destroyed and a new buffer created of the default size.

    If not specified, the default value of false will be used.

    If true, a ThreadLocal PageContext pool will be used.

    If not specified, the default value of true will be used.

    The size of the ThreadLocal PageContext.

    If not specified, the default value of 8 will be used.

    The base class of the Servlets generated from the JSPs.

    If not specified, the default value of org.apache.jasper.runtime.HttpJspBase will be used.

    The name of the service method called by the base class.

    If not specified, the default value of _jspService will be used.

    The name of the ServletContext attribute that provides the classpath for the JSP.

    If not specified, the default value of org.apache.catalina.jsp_classpath will be used.

    The name of the request attribute for <jsp-file> element of a servlet definition. If present on a request, this overrides the value returned by request.getServletPath() to select the JSP page to be executed.

    If not specified, the default value of org.apache.catalina.jsp_file will be used.

    The name of the query parameter that causes the JSP engine to just pregenerate the servlet but not invoke it.

    If not specified, the default value of jsp_precompile will be used, as defined by JSP specification (JSP.11.4.2).

    The default package name for compiled jsp pages.

    If not specified, the default value of org.apache.jsp will be used.

    The default package name for tag handlers generated from tag files.

    If not specified, the default value of org.apache.jsp.tag will be used.

    The servlet context attribute under which the alternate deployment descriptor for this web application is stored.

    If not specified, the default value of org.apache.catalina.deploy.alt_dd will be used.

    Prefix to use for generated temporary variable names.

    If not specified, the default value of _jspx_temp will be used.

    If true, the instance manager is used to obtain tag handler instances.

    If not specified, the default value of false will be used.

    If this is true or if a security manager is in use a new facade object will be created for each request.

    If not specified, the default value of false will be used.

    If this is true the '\' character will be permitted as a path delimiter.

    If not specified, the default value of false will be used.

    If this is true '%2F' and '%5C' will be permitted as path delimiters.

    If not specified, the default value of false will be used.

    The default value of this system property is false.

    If this is true the default values will be changed for:

    • org.apache.catalina.core.
      ApplicationContext.GET_RESOURCE_REQUIRE_SLASH
    • org.apache.catalina.core.
      ApplicationDispatcher.WRAP_SAME_OBJECT
    • org.apache.catalina.core.
      StandardHostValve.ACCESS_SESSION
    • org.apache.catalina.session.
      StandardSession.ACTIVITY_CHECK
    • org.apache.catalina.session.
      StandardSession.LAST_ACCESS_AT_START
    • org.apache.tomcat.util.http.
      ServerCookie.ALWAYS_ADD_EXPIRES
    • org.apache.tomcat.util.http.
      ServerCookie.FWD_SLASH_IS_SEPARATOR
    • org.apache.tomcat.util.http.
      ServerCookie.STRICT_NAMING
    • The resourceOnlyServlets attribute of any Context element.
    • The tldValidation attribute of any Context element.
    • The xmlNamespaceAware attribute of any Context element.
    • The xmlValidation attribute of any Context element.

    Note that changing a number of the above defaults is likely to break the majority of systems as some browsers are unable to correctly handle the cookie headers that result from a strict adherence to the specifications. Defaults, regardless of whether or not they have been changed by setting org.apache.catalina.STRICT_SERVLET_COMPLIANCE can always be overridden by explicitly setting the appropriate system property or element attribute.

    If this is true then a call to Response.getWriter() if no character encoding has been specified will result in subsequent calls to Response.getCharacterEncoding() returning ISO-8859-1 and the Content-Type response header will include a charset=ISO-8859-1 component. (SRV.15.2.22.1)

    If not specified, the default specification compliant value of true will be used.

    If this is true then the path passed to ServletContext.getResource() or ServletContext.getResourceAsStream() must start with "/". If false, code like getResource("myfolder/myresource.txt") will work.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.

    If this is true then any wrapped request or response object passed to an application dispatcher will be checked to ensure that it has wrapped the original request or response.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.

    If this is true Tomcat will allow '=' characters when parsing unquoted cookie values. If false, cookie values containing '=' will be terminated when the '=' is encountered and the remainder of the cookie value will be dropped.

    If not specified, the default value specification compliant value of false will be used.

    If this is true Tomcat will allow HTTP separators in cookie names and values.

    If not specified, the default specification compliant value of false will be used.

    If this is true Tomcat will always add an expires parameter to a SetCookie header even for cookies with version greater than zero. This is to work around a known IE6 and IE7 bug that causes IE to ignore the Max-Age parameter in a SetCookie header.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be false, else the default value will be true.

    If this is true then the / (forward slash) character will be treated as a separator. Note that this character is frequently used in cookie path attributes and some browsers will fail to process a cookie if the path attribute is quoted as is required by a strict adherence to the specifications. This is highly likely to break session tracking using cookies.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.

    If this is true then the requirements of the Servlet specification that Cookie names must adhere to RFC2109 (no use of separators) will be enforced.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.

    If this is true then the requirements of the cookie specifications that cookies must have values will be enforced and cookies consisting only of a name but no value will be ignored.

    If not specified, the default specification compliant value of false will be used.

    An alternative name for the single sign on session cookie. Defaults to JSESSIONIDSSO.

    If this is true, every request that is associated with a session will cause the session's last accessed time to be updated regardless of whether or not the request explicitly accesses the session.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.

    If this is true, Tomcat will track the number of active requests for each session. When determining if a session is valid, any session with at least one active request will always be considered valid.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.

    If this is true, the last accessed time for sessions will be calculated from the beginning of the previous request. If false, the last accessed time for sessions will be calculated from the end of the previous request. This also affects how the idle time is calculated.

    If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.

    If no logging configuration file is specified and no logging configuration class is specified using the java.util.logging.config.class and java.util.logging.config.file properties the default logging framework org.apache.juli will use the default java.util.logging.SimpleFormatter for all console output. To simply override the console output formatter, one can use the described property. Example: -Dorg.apache.juli.formatter=org.apache.juli.OneLineFormatter

    When the memory limit of records has been reached the system needs to determine what action to take. Currently there are three actions that can be taken:

    • int OVERFLOW_DROP_LAST = 1 - the record that caused the overflow will be dropped and not logged
    • int OVERFLOW_DROP_FIRST = 2 - the record that is next in line to be logged will be dropped to make room for the latest record on the queue
    • int OVERFLOW_DROP_FLUSH = 3 - suspend the thread while the queue empties out and flushes the entries to the write buffer
    • int OVERFLOW_DROP_CURRENT = 4 - drop the current log entry

    The default value is 1 (OVERFLOW_DROP_LAST).

    The max number of log records that the async logger will keep in memory. When this limit is reached and a new record is being logged by the JULI framework the system will take an action based on the org.apache.juli.AsyncOverflowDropType setting.

    The default value is 10000 records. This number represents the global number of records, not on a per handler basis.

    The poll interval in milliseconds for the asynchronous logger thread in milliseconds. If the log queue is empty, the async thread will issue a poll(poll interval) in order to not wake up too often.

    The default value is 1000 milliseconds.

    The type of logging to use for errors generated by invalid input data. The options are: DEBUG_ALL, INFO_THEN_DEBUG, INFO_ALL and NONE. When INFO_THEN_DEBUG is used, the period for which errors are logged at DEBUG rather than INFO is controlled by the system property org.apache.juli.logging.UserDataHelper.SUPPRESSION_TIME.

    The default value is INFO_THEN_DEBUG.

    The errors currently logged using this system are:

    • invalid cookies;
    • invalid parameters;
    • too many headers, too many parameters (hitting maxHeaderCount or maxParameterCount limits of a connector).
    Other errors triggered by invalid input data may be added to this system in later versions.

    When using INFO_THEN_DEBUG for org.apache.juli.logging.UserDataHelper.CONFIG this system property controls how long messages are logged at DEBUG after a message has been logged at INFO. Once this period has elapsed, the next message will be logged at INFO followed by a new suppression period where messages are logged at DEBUG and so on. The value is measured in seconds.

    A value of 0 is equivalent to using INFO_ALL for org.apache.juli.logging.UserDataHelper.CONFIG.

    A negative value means an infinite suppression period.

    The default value is 86400 (24 hours).

    The comma-separated list of filenames of JARs that Tomcat will not scan for configuration information when using the JarScanner functionality. Note that there are additional system properties that enable JARs to be excluded from specific scans rather than all scans.

    The coded default is that no JARs are skipped however the system property is set in a default Tomcat installation via the $CATALINA_BASE/conf/catalina.properties file.

    The comma-separated list of additional filenames of JARs that Tomcat will not scan for Servlet 3.0 pluggability features.

    The coded default is that no JARs are skipped however the system property is set in a default Tomcat installation via the $CATALINA_BASE/conf/catalina.properties file.

    The comma-separated list of additional filenames of JARs that Tomcat will not scan for TLDs.

    The coded default is that no JARs are skipped however the system property is set in a default Tomcat installation via the $CATALINA_BASE/conf/catalina.properties file.

    If this is true, custom HTTP status messages will be used within HTTP headers. If a custom message is specified that is not valid for use in an HTTP header (as defined by RFC2616) then the custom message will be ignored and the default message used.

    If not specified, the default value of false will be used.

    If this is false it will override the useNaming attribute for all Context elements.

    The class name of the factory to use to create resources of type javax.sql.DataSource. If not specified the default of org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory is used which is a package renamed (to avoid conflictions) copy of Apache Commons DBCP.

    The class name of the factory to use to create resources of type javax.mail.Session. If not specified the default of org.apache.naming.factory.MailSessionFactory is used.

    Provides a default value for the jvmRoute attribute of the Engine element. It does not override the value configured on the Engine element.

    The URL for the catalina.properties configuration file.

    If true, the String cache is enabled for ByteChunk.

    If not specified, the default value of false will be used.

    If true, the String cache is enabled for CharChunk.

    If not specified, the default value of false will be used.

    The number of times toString() must be called before the cache is activated.

    If not specified, the default value of 20000 will be used.

    The size of the String cache.

    If not specified, the default value of 200 will be used.

    The maximum length of String that will be cached.

    If not specified, the default value of 128 will be used.

    The size of the cache to use parsed and formatted date value.

    If not specified, the default value of 1000 will be used.

    If true, use a shared selector for servlet write/read.

    If not specified, the default value of true will be used.

    If true, the server will exit if an exception happens during the server initialization phase.

    If not specified, the default value of false will be used.

    The CombinedRealm allows nested Realms. This property controls the maximum permitted number of levels of nesting.

    If not specified, the default value of 3 will be used.

    tomcat7-7.0.52/webapps/docs/config/cluster-membership.xml0000644000175100017510000001645612271304167023354 0ustar locutuslocutus ]> &project; Filip Hanik The Cluster Membership object

    The membership component in the Apache Tribes Channel is responsible for dynamic discovery of other members(nodes) in the cluster.

    The default implementation of the cluster group notification is built on top of multicast heartbeats sent using UDP packets to a multicast IP address. Cluster members are grouped together by using the same multicast address/port combination. Each member sends out a heartbeat with a given interval (frequency), and this heartbeat is used for dynamic discovery. In a similar fashion, if a heartbeat has not been received in a timeframe specified by dropTime ms. a member is considered suspect and the channel and any membership listener will be notified.

    The default value is org.apache.catalina.tribes.membership.McastService and is currently the only implementation. This implementation uses multicast heartbeats for member discovery.

    The multicast address that the membership will broadcast its presence and listen for other heartbeats on. The default value is 228.0.0.4 Make sure your network is enabled for multicast traffic.
    The multicast address, in conjunction with the port is what creates a cluster group. To divide up your farm into several different group, or to split up QA from production, change the port or the address
    Previously known as mcastAddr.

    The multicast port, the default value is 45564
    The multicast port, in conjunction with the address is what creates a cluster group. To divide up your farm into several different group, or to split up QA from production, change the port or the address

    The frequency in milliseconds in which heartbeats are sent out. The default value is 500 ms.
    In most cases the default value is sufficient. Changing this value, simply changes the interval in between heartbeats.

    The membership component will time out members and notify the Channel if a member fails to send a heartbeat within a give time. The default value is 3000 ms. This means, that if a heartbeat is not received from a member in that timeframe, the membership component will notify the cluster of this.
    On a high latency network you may wish to increase this value, to protect against false positives.
    Apache Tribes also provides a TcpFailureDetector that will verify a timeout using a TCP connection when a heartbeat timeout has occurred. This protects against false positives.

    Use this attribute if you wish to bind your multicast traffic to a specific network interface. By default, or when this attribute is unset, it tries to bind to 0.0.0.0 and sometimes on multihomed hosts this becomes a problem.

    The time-to-live setting for the multicast heartbeats. This setting should be a value between 0 and 255. The default value is VM implementation specific.

    Apache Tribes has the ability to logically group members into domains, by using this domain attribute. The org.apache.catalina.tribes.Member.getDomain() method returns the value specified here.

    The sending and receiving of heartbeats is done on a single thread, hence to avoid blocking this thread forever, you can control the SO_TIMEOUT value on this socket.
    If a value smaller or equal to 0 is presented, the code will default this value to frequency

    In case of a network failure, Java multicast socket don't transparently fail over, instead the socket will continuously throw IOException upon each receive request. When recoveryEnabled is set to true, this will close the multicast socket and open a new socket with the same properties as defined above.
    The default is true.

    When recoveryEnabled==true this value indicates how many times an error has to occur before recovery is attempted. The default is 10.

    When recoveryEnabled==true this value indicates how long time (in milliseconds) the system will sleep in between recovery attempts, until we either recovered successfully or we have reached the recoveryCounter limit. The default is 5000 (5 seconds).

    Membership uses multicast, it will call java.net.MulticastSocket.setLoopbackMode(localLoopbackDisabled). When localLoopbackDisabled==true multicast messages will not reach other nodes on the same local machine. The default is false.

    tomcat7-7.0.52/webapps/docs/config/jar-scanner.xml0000644000175100017510000001017512271304167021735 0ustar locutuslocutus ]> &project; The Jar Scanner Component

    The Jar Scanner element represents the component that is used to scan the web application for JAR files. It is typically used during web application start to identify configuration files such as TLDs or web-fragment.xml files that must be processed as part of the web application initialisation.

    A Jar Scanner element MAY be nested inside a Context component. If it is not included, a default Jar Scanner configuration will be created automatically, which is sufficient for most requirements.

    All implementations of Jar Scanner support the following attributes:

    Java class name of the implementation to use. This class must implement the org.apache.tomcat.JarScanner interface. If not specified, the standard value (defined below) will be used.

    The standard implementation of Jar Scanner is org.apache.tomcat.util.scan.StandardJarScanner. It supports the following additional attributes (in addition to the common attributes listed above):

    If true, any directories found on the classpath will be checked to see if are expanded Jar files. The default is false. Tomcat determines if directory is an expanded JAR file by looking for a META-INF sub-directory. Only if the META-INF sub-directory exists, is the directory to be an expanded JAR file.

    If true, any files found on the classpath will be checked to see if they are Jar files rather than relying on the file extension being .jar. The default is false

    If true, the full web application classpath, including the shared and common classloaders and the system classpath (but not the bootstrap classpath) will be scanned for Jar files in addition to the web application. The default is true.

    If scanClassPath is true and this is true the bootstrap classpath will also be scanned for Jar files. The default is false.

    No components may be nested inside a Jar Scanner element.

    No special features are associated with a Jar Scanner element.

    tomcat7-7.0.52/webapps/docs/config/filter.xml0000644000175100017510000016345212271304167021026 0ustar locutuslocutus ]> &project; Container Provided Filters

    Tomcat provides a number of Filters which may be configured for use with all web applications using $CATALINA_BASE/conf/web.xml or may be configured for individual web applications by configuring them in the application's WEB-INF/web.xml. Each filter is described below.

    This description uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    The HTTP specification is clear that if no character set is specified for media sub-types of the "text" media type, the ISO-8859-1 character set must be used. However, browsers may attempt to auto-detect the character set. This may be exploited by an attacker to perform an XSS attack. Internet Explorer has this behaviour by default. Other browsers have an option to enable it.

    This filter prevents the attack by explicitly setting a character set. Unless the provided character set is explicitly overridden by the user the browser will adhere to the explicitly set character set, thus preventing the XSS attack.

    The filter class name for the Add Default Character Set Filter is org.apache.catalina.filters.AddDefaultCharsetFilter .

    The Add Default Character Set Filter supports the following initialization parameters:

    Name of the character set which should be set, if no other character set was set explicitly by a Servlet. This parameter has two special values default and system. A value of system uses the JVM wide default character set, which is usually set by locale. A value of default will use ISO-8859-1.

    This filter is an implementation of W3C's CORS (Cross-Origin Resource Sharing) specification, which is a mechanism that enables cross-origin requests.

    The filter works by adding required Access-Control-* headers to HttpServletResponse object. The filter also protects against HTTP response splitting. If request is invalid, or is not permitted, then request is rejected with HTTP status code 403 (Forbidden). A flowchart that demonstrates request processing by this filter is available.

    The minimal configuration required to use this filter is:

    <filter> <filter-name>CorsFilter</filter-name> <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

    The filter class name for the CORS Filter is org.apache.catalina.filters.CorsFilter.

    The CORS Filter supports following initialisation parameters:

    A list of origins that are allowed to access the resource. A * can be specified to enable access to resource from any origin. Otherwise, a whitelist of comma separated origins can be provided. Eg: http://www.w3.org, https://www.apache.org. Defaults: * (Any origin is allowed to access the resource).

    A comma separated list of HTTP methods that can be used to access the resource, using cross-origin requests. These are the methods which will also be included as part of Access-Control-Allow-Methods header in pre-flight response. Eg: GET, POST. Defaults: GET, POST, HEAD, OPTIONS

    A comma separated list of request headers that can be used when making an actual request. These headers will also be returned as part of Access-Control-Allow-Headers header in a pre-flight response. Eg: Origin,Accept. Defaults: Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers

    A comma separated list of headers other than simple response headers that browsers are allowed to access. These are the headers which will also be included as part of Access-Control-Expose-Headers header in the pre-flight response. Eg: X-CUSTOM-HEADER-PING,X-CUSTOM-HEADER-PONG. Default: None. Non-simple headers are not exposed by default.

    The amount of seconds, browser is allowed to cache the result of the pre-flight request. This will be included as part of Access-Control-Max-Age header in the pre-flight response. A negative value will prevent CORS Filter from adding this response header to pre-flight response. Defaults: 1800

    A flag that indicates whether the resource supports user credentials. This flag is exposed as part of Access-Control-Allow-Credentials header in a pre-flight response. It helps browser determine whether or not an actual request can be made using credentials. Defaults: true

    A flag to control if CORS specific attributes should be added to HttpServletRequest object or not. Defaults: true

    Here's an example of a more advanced configuration, that overrides defaults:

    <filter> <filter-name>CorsFilter</filter-name> <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> <init-param> <param-name>cors.allowed.origins</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.allowed.methods</param-name> <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value> </init-param> <init-param> <param-name>cors.allowed.headers</param-name> <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value> </init-param> <init-param> <param-name>cors.exposed.headers</param-name> <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value> </init-param> <init-param> <param-name>cors.support.credentials</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>cors.preflight.maxage</param-name> <param-value>10</param-value> </init-param> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

    CORS Filter adds information about the request, in HttpServletRequest object, for consumption downstream. Following attributes are set, if cors.request.decorate initialisation parameter is true:

    • cors.isCorsRequest: Flag to determine if request is a CORS request.
    • cors.request.origin: The Origin URL, i.e. the URL of the page from where the request originated.
    • cors.request.type: Type of CORS request. Possible values:
      • SIMPLE: A request which is not preceded by a pre-flight request.
      • ACTUAL: A request which is preceded by a pre-flight request.
      • PRE_FLIGHT: A pre-flight request.
      • NOT_CORS: A normal same-origin request.
      • INVALID_CORS: A cross-origin request, which is invalid.
    • cors.request.headers: Request headers sent as Access-Control-Request-Headers header, for a pre-flight request.

    This filter provides basic CSRF protection for a web application. The filter assumes that it is mapped to /* and that all URLs returned to the client are encoded via a call to HttpServletResponse#encodeRedirectURL(String) or HttpServletResponse#encodeURL(String).

    This filter prevents CSRF by generating a nonce and storing it in the session. URLs are also encoded with the same nonce. When the next request is received the nonce in the request is compared to the nonce in the session and only if they are the same is the request allowed to continue.

    The filter class name for the CSRF Prevention Filter is org.apache.catalina.filters.CsrfPreventionFilter .

    The CSRF Prevention Filter supports the following initialisation parameters:

    HTTP response status code that is used when rejecting denied request. The default value is 403.

    A comma separated list of URLs that will not be tested for the presence of a valid nonce. They are used to provide a way to navigate back to a protected application after having navigated away from it. Entry points will be limited to HTTP GET requests and should not trigger any security sensitive actions.

    The number of previously issued nonces that will be cached on a LRU basis to support parallel requests, limited use of the refresh and back in the browser and similar behaviors that may result in the submission of a previous nonce rather than the current one. If not set, the default value of 5 will be used.

    The name of the class to use to generate nonces. The class must be an instance of java.util.Random. If not set, the default value of java.security.SecureRandom will be used.

    ExpiresFilter is a Java Servlet API port of Apache mod_expires. This filter controls the setting of the Expires HTTP header and the max-age directive of the Cache-Control HTTP header in server responses. The expiration date can set to be relative to either the time the source file was last modified, or to the time of the client access.

    These HTTP headers are an instruction to the client about the document's validity and persistence. If cached, the document may be fetched from the cache rather than from the source until this time has passed. After that, the cache copy is considered "expired" and invalid, and a new copy must be obtained from the source.

    To modify Cache-Control directives other than max-age (see RFC 2616 section 14.9), you can use other servlet filters or Apache Httpd mod_headers module.

    Basic configuration to add 'Expires' and 'Cache-Control: max-age=' headers to images, css and javascript.

    <filter> <filter-name>ExpiresFilter</filter-name> <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class> <init-param> <param-name>ExpiresByType image</param-name> <param-value>access plus 10 minutes</param-value> </init-param> <init-param> <param-name>ExpiresByType text/css</param-name> <param-value>access plus 10 minutes</param-value> </init-param> <init-param> <param-name>ExpiresByType application/javascript</param-name> <param-value>access plus 10 minutes</param-value> </init-param> </filter> ... <filter-mapping> <filter-name>ExpiresFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>

    The ExpiresDefault and ExpiresByType directives can also be defined in a more readable syntax of the form:

    <init-param> <param-name>ExpiresDefault</param-name> <param-value><base> [plus] {<num> <type>}*</param-value> </init-param> <init-param> <param-name>ExpiresByType type</param-name> <param-value><base> [plus] {<num> <type>}*</param-value> </init-param> <init-param> <param-name>ExpiresByType type;encoding</param-name> <param-value><base> [plus] {<num> <type>}*</param-value> </init-param>

    where <base> is one of:

    • access
    • now (equivalent to 'access')
    • modification

    The plus keyword is optional. <num> should be an integer value (acceptable to Integer.parseInt()), and <type> is one of:

    • years
    • months
    • weeks
    • days
    • hours
    • minutes
    • seconds
    For example, any of the following directives can be used to make documents expire 1 month after being accessed, by default:

    <init-param> <param-name>ExpiresDefault</param-name> <param-value>access plus 1 month</param-value> </init-param> <init-param> <param-name>ExpiresDefault</param-name> <param-value>access plus 4 weeks</param-value> </init-param> <init-param> <param-name>ExpiresDefault</param-name> <param-value>access plus 30 days</param-value> </init-param>

    The expiry time can be fine-tuned by adding several ' <num> <type>' clauses:

    <init-param> <param-name>ExpiresByType text/html</param-name> <param-value>access plus 1 month 15 days 2 hours</param-value> </init-param> <init-param> <param-name>ExpiresByType image/gif</param-name> <param-value>modification plus 5 hours 3 minutes</param-value> </init-param>

    Note that if you use a modification date based setting, the Expires header will not be added to content that does not come from a file on disk. This is due to the fact that there is no modification time for such content.

    A response is eligible to be enriched by ExpiresFilter if :

    1. no expiration header is defined (Expires header or the max-age directive of the Cache-Control header),
    2. the response status code is not excluded by the directive ExpiresExcludedResponseStatusCodes,
    3. the Content-Type of the response matches one of the types defined the in ExpiresByType directives or the ExpiresDefault directive is defined.

    Note : If Cache-Control header contains other directives than max-age, they are concatenated with the max-age directive that is added by the ExpiresFilter.

    The expiration configuration if elected according to the following algorithm:

    1. ExpiresByType matching the exact content-type returned by HttpServletResponse.getContentType() possibly including the charset (e.g. 'text/xml;charset=UTF-8'),
    2. ExpiresByType matching the content-type without the charset if HttpServletResponse.getContentType() contains a charset (e.g. ' text/xml;charset=UTF-8' -> 'text/xml'),
    3. ExpiresByType matching the major type (e.g. substring before '/') of HttpServletResponse.getContentType() (e.g. 'text/xml;charset=UTF-8' -> 'text '),
    4. ExpiresDefault

    The filter class name for the Expires Filter is org.apache.catalina.filters.ExpiresFilter .

    The Expires Filter supports the following initialisation parameters:

    This directive defines the http response status codes for which the ExpiresFilter will not generate expiration headers. By default, the 304 status code ("Not modified") is skipped. The value is a comma separated list of http status codes.

    This directive is useful to ease usage of ExpiresDefault directive. Indeed, the behavior of 304 Not modified (which does specify a Content-Type header) combined with Expires and Cache-Control:max-age= headers can be unnecessarily tricky to understand.

    See sample below the table

    This directive defines the value of the Expires header and the max-age directive of the Cache-Control header generated for documents of the specified type (e.g., text/html). The second argument sets the number of seconds that will be added to a base time to construct the expiration date. The Cache-Control: max-age is calculated by subtracting the request time from the expiration date and expressing the result in seconds.

    The base time is either the last modification time of the file, or the time of the client's access to the document. Which should be used is specified by the <code> field; M means that the file's last modification time should be used as the base time, and A means the client's access time should be used. The duration is expressed in seconds. A2592000 stands for access plus 30 days in alternate syntax.

    The difference in effect is subtle. If M (modification in alternate syntax) is used, all current copies of the document in all caches will expire at the same time, which can be good for something like a weekly notice that's always found at the same URL. If A ( access or now in alternate syntax) is used, the date of expiration is different for each client; this can be good for image files that don't change very often, particularly for a set of related documents that all refer to the same images (i.e., the images will be accessed repeatedly within a relatively short timespan).

    Note: When the content type includes a charset (e.g. 'ExpiresByType text/xml;charset=utf-8'), Tomcat removes blank chars between the ';' and the 'charset' keyword. Due to this, configuration of an expiration with a charset must not include such a space character.

    See sample below the table

    It overrides, for the specified MIME type only, any expiration date set by the ExpiresDefault directive.

    You can also specify the expiration time calculation using an alternate syntax, described earlier in this document.

    This directive sets the default algorithm for calculating the expiration time for all documents in the affected realm. It can be overridden on a type-by-type basis by the ExpiresByType directive. See the description of that directive for details about the syntax of the argument, and the "alternate syntax" description as well.

    Sample : exclude response status codes 302, 500 and 503

    <init-param> <param-name>ExpiresExcludedResponseStatusCodes</param-name> <param-value>302, 500, 503</param-value> </init-param>

    Sample for ExpiresByType initialization parameter

    <init-param> <param-name>ExpiresByType text/html</param-name> <param-value>access plus 1 month 15 days 2 hours</param-value> </init-param> <init-param> <!-- 2592000 seconds = 30 days --> <param-name>ExpiresByType image/gif</param-name> <param-value>A2592000</param-value> </init-param>

    To troubleshoot, enable logging on the org.apache.catalina.filters.ExpiresFilter.

    Extract of logging.properties

    org.apache.catalina.filters.ExpiresFilter.level = FINE

    Sample of initialization log message:

    Mar 26, 2010 2:01:41 PM org.apache.catalina.filters.ExpiresFilter init FINE: Filter initialized with configuration ExpiresFilter[ excludedResponseStatusCode=[304], default=null, byType={ image=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]], text/css=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]], text/javascript=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]]}]

    Sample of per-request log message where ExpiresFilter adds an expiration date is below. The message is on one line and is wrapped here for better readability.

    Mar 26, 2010 2:09:47 PM org.apache.catalina.filters.ExpiresFilter onBeforeWriteResponseBody FINE: Request "/tomcat.gif" with response status "200" content-type "image/gif", set expiration date 3/26/10 2:19 PM

    Sample of per-request log message where ExpiresFilter does not add an expiration date:

    Mar 26, 2010 2:10:27 PM org.apache.catalina.filters.ExpiresFilter onBeforeWriteResponseBody FINE: Request "/docs/config/manager.html" with response status "200" content-type "text/html", no expiration configured

    This filter triggers parameters parsing in a request and rejects the request if some parameters were skipped during parameter parsing because of parsing errors or request size limitations (such as maxParameterCount attribute in a Connector). This filter can be used to ensure that none parameter values submitted by client are lost.

    Note that parameter parsing may consume the body of an HTTP request, so caution is needed if the servlet protected by this filter uses request.getInputStream() or request.getReader() calls. In general the risk of breaking a web application by adding this filter is not so high, because parameter parsing does check content type of the request before consuming the request body.

    Note, that for the POST requests to be parsed correctly, a SetCharacterEncodingFilter filter must be configured above this one. See CharacterEncoding page in the FAQ for details.

    The request is rejected with HTTP status code 400 (Bad Request).

    The filter class name for the Failed Request Filter is org.apache.catalina.filters.FailedRequestFilter .

    The Failed Request Filter does not support any initialization parameters.

    The Remote Address Filter allows you to compare the IP address of the client that submitted this request against one or more regular expressions, and either allow the request to continue or refuse to process the request from this client.

    The syntax for regular expressions is different than that for 'standard' wildcard matching. Tomcat uses the java.util.regex package. Please consult the Java documentation for details of the expressions supported.

    Note: There is a caveat when using this filter with IPv6 addresses. Format of the IP address that this valve is processing depends on the API that was used to obtain it. If the address was obtained from Java socket using Inet6Address class, its format will be x:x:x:x:x:x:x:x. That is, the IP address for localhost will be 0:0:0:0:0:0:0:1 instead of the more widely used ::1. Consult your access logs for the actual value.

    See also: Remote Host Filter.

    The filter class name for the Remote Address Filter is org.apache.catalina.filters.RemoteAddrFilter .

    The Remote Address Filter supports the following initialisation parameters:

    A regular expression (using java.util.regex) that the remote client's IP address is compared to. If this attribute is specified, the remote address MUST match for this request to be accepted. If this attribute is not specified, all requests will be accepted UNLESS the remote address matches a deny pattern.

    A regular expression (using java.util.regex) that the remote client's IP address is compared to. If this attribute is specified, the remote address MUST NOT match for this request to be accepted. If this attribute is not specified, request acceptance is governed solely by the accept attribute.

    HTTP response status code that is used when rejecting denied request. The default value is 403. For example, it can be set to the value 404.

    To allow access only for the clients connecting from localhost:

    <filter> <filter-name>Remote Address Filter</filter-name> <filter-class>org.apache.catalina.filters.RemoteAddrFilter</filter-class> <init-param> <param-name>allow</param-name> <param-value>127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1</param-value> </init-param> </filter> <filter-mapping> <filter-name>Remote Address Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

    The Remote Host Filter allows you to compare the hostname of the client that submitted this request against one or more regular expressions, and either allow the request to continue or refuse to process the request from this client.

    The syntax for regular expressions is different than that for 'standard' wildcard matching. Tomcat uses the java.util.regex package. Please consult the Java documentation for details of the expressions supported.

    Note: This filter processes the value returned by method ServletRequest.getRemoteHost(). To allow the method to return proper host names, you have to enable "DNS lookups" feature on a Connector.

    See also: Remote Address Filter, HTTP Connector configuration.

    The filter class name for the Remote Address Filter is org.apache.catalina.filters.RemoteHostFilter .

    The Remote Host Filter supports the following initialisation parameters:

    A regular expression (using java.util.regex) that the remote client's hostname is compared to. If this attribute is specified, the remote hostname MUST match for this request to be accepted. If this attribute is not specified, all requests will be accepted UNLESS the remote hostname matches a deny pattern.

    A regular expression (using java.util.regex) that the remote client's hostname is compared to. If this attribute is specified, the remote hostname MUST NOT match for this request to be accepted. If this attribute is not specified, request acceptance is governed solely by the accept attribute.

    HTTP response status code that is used when rejecting denied request. The default value is 403. For example, it can be set to the value 404.

    Tomcat port of mod_remoteip, this filter replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. "X-Forwarded-For").

    Another feature of this filter is to replace the apparent scheme (http/https), server port and request.secure with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").

    If used in conjunction with Remote Address/Host filters then this filter should be defined first to ensure that the correct client IP address is presented to the Remote Address/Host filters.

    Note: By default this filter has no effect on the values that are written into access log. The original values are restored when request processing leaves the filter and that always happens earlier than access logging. To pass the remote address, remote host, server port and protocol values set by this filter to the access log, they are put into request attributes. Publishing these values here is enabled by default, but AccessLogValve should be explicitly configured to use them. See documentation for requestAttributesEnabled attribute of AccessLogValve.

    The names of request attributes that are set by this filter and can be used by access logging are the following:

    • org.apache.catalina.AccessLog.RemoteAddr
    • org.apache.catalina.AccessLog.RemoteHost
    • org.apache.catalina.AccessLog.Protocol
    • org.apache.catalina.AccessLog.ServerPort
    • org.apache.tomcat.remoteAddr

    The filter class name for the Remote IP Filter is org.apache.catalina.filters.RemoteIpFilter .

    The filter will process the x-forwarded-for http header.

    <filter> <filter-name>RemoteIpFilter</filter-name> <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class> </filter> <filter-mapping> <filter-name>RemoteIpFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>

    The filter will process x-forwarded-for and x-forwarded-proto http headers. Expected value for the x-forwarded-proto header in case of SSL connections is https (case insensitive).

    <filter> <filter-name>RemoteIpFilter</filter-name> <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class> <init-param> <param-name>protocolHeader</param-name> <param-value>x-forwarded-proto</param-value> </init-param> </filter> <filter-mapping> <filter-name>RemoteIpFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>

    RemoteIpFilter configuration:

    <filter> <filter-name>RemoteIpFilter</filter-name> <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name> <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIpHeader</param-name> <param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIpProxiesHeader</param-name> <param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>protocolHeader</param-name> <param-value>x-forwarded-proto</param-value> </init-param> </filter>

    Request values:
    Property Value Before RemoteIpFilter Value After RemoteIpFilter
    request.remoteAddr 192.168.0.10 140.211.11.130
    request.header['x-forwarded-for'] 140.211.11.130, 192.168.0.10 null
    request.header['x-forwarded-by'] null null
    request.header['x-forwarded-proto'] https https
    request.scheme http https
    request.secure false true
    request.serverPort 80 443

    Note : x-forwarded-by header is null because only internal proxies has been traversed by the request. x-forwarded-for is null because all the proxies are trusted or internal.

    RemoteIpFilter configuration:

    <filter> <filter-name>RemoteIpFilter</filter-name> <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name> <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIpHeader</param-name> <param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIpProxiesHeader</param-name> <param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>trustedProxies</param-name> <param-value>proxy1|proxy2</param-value> </init-param> </filter>

    Request values:
    Property Value Before RemoteIpFilter Value After RemoteIpFilter
    request.remoteAddr 192.168.0.10 140.211.11.130
    request.header['x-forwarded-for'] 140.211.11.130, proxy1, proxy2 null
    request.header['x-forwarded-by'] null proxy1, proxy2

    Note : proxy1 and proxy2 are both trusted proxies that come in x-forwarded-for header, they both are migrated in x-forwarded-by header. x-forwarded-for is null because all the proxies are trusted or internal.

    RemoteIpFilter configuration:

    <filter> <filter-name>RemoteIpFilter</filter-name> <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name> <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIpHeader</param-name> <param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIpProxiesHeader</param-name> <param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>trustedProxies</param-name> <param-value>proxy1|proxy2</param-value> </init-param> </filter>

    Request values:
    Property Value Before RemoteIpFilter Value After RemoteIpFilter
    request.remoteAddr 192.168.0.10 140.211.11.130
    request.header['x-forwarded-for'] 140.211.11.130, proxy1, proxy2, 192.168.0.10 null
    request.header['x-forwarded-by'] null proxy1, proxy2

    Note : proxy1 and proxy2 are both trusted proxies that come in x-forwarded-for header, they both are migrated in x-forwarded-by header. As 192.168.0.10 is an internal proxy, it does not appear in x-forwarded-by. x-forwarded-for is null because all the proxies are trusted or internal.

    RemoteIpFilter configuration:

    <filter> <filter-name>RemoteIpFilter</filter-name> <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class> <init-param> <param-name>allowedInternalProxies</param-name> <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value> </init-param> <init-param> <param-name>remoteIpHeader</param-name> <param-value>x-forwarded-for</param-value> </init-param> <init-param> <param-name>remoteIpProxiesHeader</param-name> <param-value>x-forwarded-by</param-value> </init-param> <init-param> <param-name>trustedProxies</param-name> <param-value>proxy1|proxy2</param-value> </init-param> </filter>

    Request values:
    Property Value Before RemoteIpFilter Value After RemoteIpFilter
    request.remoteAddr 192.168.0.10 untrusted-proxy
    request.header['x-forwarded-for'] 140.211.11.130, untrusted-proxy, proxy1 140.211.11.130
    request.header['x-forwarded-by'] null proxy1

    Note : x-forwarded-by holds the trusted proxy proxy1. x-forwarded-by holds 140.211.11.130 because untrusted-proxy is not trusted and thus, we can not trust that untrusted-proxy is the actual remote ip. request.remoteAddr is untrusted-proxy that is an IP verified by proxy1.

    The Remote IP Filter supports the following initialisation parameters:

    Name of the HTTP Header read by this valve that holds the list of traversed IP addresses starting from the requesting client. If not specified, the default of x-forwarded-for is used.

    Regular expression (using java.util.regex) that a proxy's IP address must match to be considered an internal proxy. Internal proxies that appear in the remoteIpHeader will be trusted and will not appear in the proxiesHeader value. If not specified the default value of 10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3} will be used.

    Name of the HTTP header created by this valve to hold the list of proxies that have been processed in the incoming remoteIpHeader. If not specified, the default of x-forwarded-by is used.

    Set to true to set the request attributes used by AccessLog implementations to override the values returned by the request for remote address, remote host, server port and protocol. Request attributes are also used to enable the forwarded remote address to be displayed on the status page of the Manager web application. If not set, the default value of true will be used.

    Regular expression (using java.util.regex) that a proxy's IP address must match to be considered an trusted proxy. Trusted proxies that appear in the remoteIpHeader will be trusted and will appear in the proxiesHeader value. If not specified, no proxies will be trusted.

    Name of the HTTP Header read by this valve that holds the protocol used by the client to connect to the proxy. If not specified, the default of null is used.

    Name of the HTTP Header read by this valve that holds the port used by the client to connect to the proxy. If not specified, the default of null is used.

    Value of the protocolHeader to indicate that it is an HTTPS request. If not specified, the default of https is used.

    Value returned by ServletRequest.getServerPort() when the protocolHeader indicates http protocol and no portHeader is present. If not specified, the default of 80 is used.

    Value returned by ServletRequest.getServerPort() when the protocolHeader indicates https protocol and no portHeader is present. If not specified, the default of 443 is used.

    If true, the value returned by ServletRequest.getLocalPort() and ServletRequest.getServerPort() is modified by the this filter. If not specified, the default of false is used.

    The Request Dumper Filter logs information from the request and response objects and is intended to be used for debugging purposes. When using this Filter, it is recommended that the org.apache.catalina.filter.RequestDumperFilter logger is directed to a dedicated file and that the org.apache.juli.VerbatimFormmater is used.

    WARNING: Using this filter has side-effects. The output from this filter includes any parameters included with the request. The parameters will be decoded using the default platform encoding. Any subsequent calls to request.setCharacterEncoding() within the web application will have no effect.

    The filter class name for the Request Dumper Filter is org.apache.catalina.filters.RequestDumperFilter .

    The Request Dumper Filter does not support any initialization parameters.

    The following entries in a web application's web.xml would enable the Request Dumper filter for all requests for that web application. If the entries were added to CATALINA_BASE/conf/web.xml, the Request Dumper Filter would be enabled for all web applications.

    <filter> <filter-name>requestdumper</filter-name> <filter-class> org.apache.catalina.filters.RequestDumperFilter </filter-class> </filter> <filter-mapping> <filter-name>requestdumper</filter-name> <url-pattern>*</url-pattern> </filter-mapping>

    The following entries in CATALINA_BASE/conf/logging.properties would create a separate log file for the Request Dumper Filter output.

    # To this configuration below, 1request-dumper.org.apache.juli.FileHandler # also needs to be added to the handlers property near the top of the file 1request-dumper.org.apache.juli.FileHandler.level = INFO 1request-dumper.org.apache.juli.FileHandler.directory = ${catalina.base}/logs 1request-dumper.org.apache.juli.FileHandler.prefix = request-dumper. 1request-dumper.org.apache.juli.FileHandler.formatter = org.apache.juli.VerbatimFormatter org.apache.catalina.filters.RequestDumperFilter.level = INFO org.apache.catalina.filters.RequestDumperFilter.handlers = \ 1request-dumper.org.apache.juli.FileHandler

    User agents don't always include character encoding information in requests. Depending on the how the request is processed, usually the default encoding of ISO-8859-1 is used. This is not always desirable. This filter provides options for setting that encoding or forcing it to a particular value. Essentially this filter calls ServletRequest.setCharacterEncoding() method.

    Effectively the value set by this filter is used when parsing parameters in a POST request, if parameter parsing occurs later than this filter. Thus the order of filter mappings is important. Note that the encoding for GET requests is not set here, but on a Connector. See CharacterEncoding page in the FAQ for details.

    The filter class name for the Set Character Encoding Filter is org.apache.catalina.filters.SetCharacterEncodingFilter .

    The Set Character Encoding Filter supports the following initialization parameters:

    Name of the character encoding which should be set.

    Determines if any character encoding specified by the user agent is ignored. If this attribute is true, any value provided by the user agent is ignored. If false, the encoding is only set if the user agent did not specify an encoding. The default value is false.

    Microsoft operating systems have two WebDAV clients. One is used with port 80, the other is used for all other ports. The implementation used with port 80 does not adhere to the WebDAV specification and fails when trying to communicate with the Tomcat WebDAV Servlet. This Filter provides a fix for this by forcing the use of the WebDAV implementation that works, even when connecting via port 80.

    The filter class name for the WebDAV Fix Filter is org.apache.catalina.filters.WebdavFixFilter .

    The WebDAV Fix Filter does not support any initialization parameters.

    tomcat7-7.0.52/webapps/docs/config/automatic-deployment.xml0000644000175100017510000004274412252427537023713 0ustar locutuslocutus ]> &project; Automatic Deployment - Use cases

    This page defines the expected behaviour of the automatic deployer in many typical use cases. This is a complex area of Tomcat's functionality. While any difference between this document and Tomcat's behaviour is a bug, the fix may be to change this document, Tomcat's behaviour or both.

    TermDescription
    XML An XML configuration file located in the Host's configBase. It must contain a single <Context> element and may contain optional nested elements. It does not define an explicit docBase attribute. It represents a single web application. It is often referred to as a context.xml file.
    XML+EW An XML configuration file located in the Host's configBase. It must contain a single <Context> element and may contain optional nested elements. If includes an explicit docBase attribute that points to an external WAR. It represents a single web application. It is often referred to as a context.xml file.
    XML+ED An XML configuration file located in the Host's configBase. It must contain a single <Context> element and may contain optional nested elements. If includes an explicit docBase attribute that points to an external WAR. It represents a single web application. It is often referred to as a context.xml file.
    WAR A WAR file located in the Host's appBase. The WAR does not include an embedded context.xml file.
    WAR+XML A WAR file located in the Host's appBase. The WAR does include an embedded context.xml file.
    DIR A directory located in the Host's appBase. The directory does not include an embedded context.xml file.
    DIR+XML A directory located in the Host's appBase. The director does include an embedded context.xml file.
    redeploy The Context object that represents the web application is destroyed and a new Context object created. If present and permitted by the configuration, this new Context object is created by parsing the context.xml file. The web.xml file is parsed during the application start process. Any sessions stored in the standard Manager in the default configuration will not be persisted. Any requests to the web application during the redeploy will be handled as if the web application is not deployed.
    reload The Context object that represents the web application is stopped and then started. The web.xml file is parsed during the application start process. Any sessions stored in the standard Manager in the default configuration will not be persisted. Any requests to the web application during the reload will be held until the reload completes at which point they will continue using the reloaded web application.

    This section describes Tomcat's behaviour when the automatic deployment process discovers a new web application.

    Starting artifact(s) Configuration Settings Result
    deployXMLcopyXMLunpackWARs XMLWARDIRNotes
    XML eithereithereither YNN1, 2, 3
    XML+EW eithereitherfalse YNN1
    XML+EW eithereithertrue YNY1
    XML+ED eithereithereither YNN1, 2
    WAR+XML falseeitherfalse NYN4
    WAR+XML falseeithertrue NYY4
    WAR+XML truefalsefalse NYN
    WAR+XML truefalsetrue NYY
    WAR+XML truetruefalse YYN
    WAR+XML truetruetrue YYY
    WAR eithereitherfalse NYN
    WAR eithereithertrue NYY
    DIR+XML falseeithereither NNY4
    DIR+XML truefalseeither NNY
    DIR+XML truetrueeither YNY
    DIR falseeithereither NNY

    This section describes Tomcat's behaviour when the automatic deployment process detects that a web application file has been deleted.

    When a file is deleted or modified any redeploy resources that are listed after the modified/deleted resource are themselves deleted (and possibly re-created). The order of redeploy resources is:

    1. WAR
    2. DIR
    3. XML
    4. global resources

    There are some exceptions to the deletion rule above:

    • global resources are never deleted
    • external resources are never deleted
    • if the WAR or DIR has been modified then the XML file is only deleted if copyXML is true and deployXML is true

    In the following table:

    • '-' means "unchanged from not present". i.e. the artifact wasn't present before the change and isn't present after it either. '-' rather than 'N' is used to focus attention on what changes.
    • 'R' means that the directory is re-created by expanding the WAR file. This will only happen if unpackWARs is true.
    • 'XW' means that the if the WAR contains a META-INF/context.xml file it will be extracted and placed in the Host's configBase. This only happens if copyXML is true and deployXML is true.
    • 'XD' means that the if the directory contains a META-INF/context.xml file it will be copied to the Host's configBase. This only happens if copyXML is true and deployXML is true.
    Artifacts present Artifact removed Artifacts remaining
    XMLWARDIR XMLWARDIRNotes
    NNY DIR --N
    NYN WAR -N-
    NYY DIR -YR
    NYY WAR -NN
    YNN XML N--
    YNY DIR N-N5
    YNY XML XD-Y
    YYN WAR NN-5
    YYN XML XWY-
    YYY DIR XWYR
    YYY WAR NNN
    YYY XML XWYY
    YY (external)N WAR YN-3
    YY (external)N XML NY (external)-6
    YNY (external) DIR Y-N3
    YNY (external) XML N-Y (external)6
    YY (external)Y DIR YY (external)R
    YY (external)Y WAR YNN3
    YY (external)Y XML NY (external)N6

    This section describes Tomcat's behaviour when the automatic deployment process detects that a web application file has been modified.

    In the following table:

    • '-' means "unchanged from not present". i.e. the artifact wasn't present before the change and isn't present after it either. '-' rather than 'N' is used to focus attention on what changes.
    • 'M' means that the artifact has been modified.
    • 'R' means that the directory is re-created by expanding the WAR file. This will only happen if unpackWARs is true.
    Artifacts present Artifact modified Artifacts remaining
    XMLWARDIR XMLWARDIRAction
    NNY DIR --MNone
    NYN WAR -M-Redeploy
    NYY DIR -YMNone
    NYY WAR -MRRedeploy
    YNN XML M--Redeploy
    YNY DIR Y-MNone
    YNY XML M-YRedeploy
    YYN WAR YM-Reload
    YYN XML MY-Redeploy
    YYY DIR YYMNone
    YYY WAR YMYReload
    YYY XML MYYRedeploy
    YY(external)N WAR YM(external)-Reload
    YY(external)N XML MY(external)-Redeploy
    YNY(external) DIR Y-M(external)None
    YNY(external) XML M-Y(external)Redeploy
    YY(external)Y DIR YY(external)MNone
    YY(external)Y WAR YM(external)RReload
    YY(external)Y XML MY(external)YRedeploy

    This is treated as if the added file has been modified with the following additional actions:

    • If a WAR is added, any DIR is removed and may be recreated depending on unpackWARs.
    • If an XML file is added that refers to an external docBase any WAR or DIR in the appBase will be removed. The DIR may be recreated if the external resource is a WAR and unpackWARs is true.
    • If a DIR is added when a WAR already exists and unpackWARs is false, the DIR will be ignored but a warning will be logged when the DIR is first detected. If the WAR is removed, the DIR will be left and may be deployed via automatic deployment.
    • If a WAR is added to the appBase when an external WAR already exists, the WAR in the appBase will be ignored but a warning will be logged when the WAR in the appBase is first detected. If the external WAR is removed, the WAR in the appBaase will be left and may be deployed via automatic deployment.
    • If an XML file is added to the META-INF directory of an application deployed from that DIR, the application will always be redeployed. The result will be the same as for a new deployment.
    1. deployXML and copyXML are ignored since an XML file was discovered in the configBase.
    2. unpackWARs is ignored since there is no WAR file.
    3. The context will fail to start because there is no content in the expected docBase.
    4. The web application fails to deploy because it contains an embedded META-INF/context.xml, deployXML is false and an XML has not been provided in the configBase.
    5. The XML file is only deleted if copyXML is true and deployXML is true.
    6. Although the external resource is still present, the web application is fully undeployed as Tomcat has no knowledge of the external resource.
    tomcat7-7.0.52/webapps/docs/config/cluster-channel.xml0000644000175100017510000001230312271304167022614 0ustar locutuslocutus ]> &project; Filip Hanik The Cluster Channel object
    The cluster channel is the main component of a small framework we've nicknamed Apache Tribes.
    The channel manages a set of sub components and together they create a group communication framework.
    This framework is then used internally by the components that need to send messages between different Tomcat instances.
    A few examples of these components would be the SimpleTcpCluster that does the messaging for the DeltaManager, or the BackupManager that uses a different replication strategy. The ReplicatedContext object does also use the channel object to communicate context attribute changes.

    Channel/Membership:
    The Membership component is responsible for auto discovering new nodes in the cluster and also to provide for notifications for any nodes that have not responded with a heartbeat. The default implementation uses multicast.
    In the membership component you configure how your nodes, aka. members, are to be discovered and/or divided up. You can always find out more about Apache Tribes

    Channel/Sender:
    The Sender component manages all outbound connections and data messages that are sent over the network from one node to another. This component allows messages to be sent in parallel. The default implementation uses TCP client sockets, and socket tuning for outgoing messages are configured here.
    You can always find out more about Apache Tribes

    Channel/Sender/Transport:
    The Transport component is the bottom IO layer for the sender component. The default implementation uses non-blocking TCP client sockets.
    You can always find out more about Apache Tribes

    Channel/Receiver:
    The receiver component listens for messages from other nodes. Here you will configure the cluster thread pool, as it will dispatch incoming messages to a thread pool for faster processing. The default implementation uses non-blocking TCP server sockets.
    You can always find out more about Apache Tribes

    Channel/Interceptor:
    The channel will send messages through an interceptor stack. Because of this, you have the ability to customize the way messages are sent and received, and even how membership is handled.
    You can always find out more about Apache Tribes

    The default value here is org.apache.catalina.tribes.group.GroupChannel and is currently the only implementation available. Flag whether the channel manages its own heartbeat. If set to true, the channel start a local thread for the heart beat. If set this flag to false, you must set SimpleTcpCluster#heartbeatBackgroundEnabled to true. default value is true. If heartbeat == true, specifies the interval of heartbeat thread in milliseconds. If set to true, the GroupChannel will check the option flags that each interceptor is using. Reports an error if two interceptor share the same flag.
    tomcat7-7.0.52/webapps/docs/config/resources.xml0000644000175100017510000001171312271304167021543 0ustar locutuslocutus ]> &project; Remy Maucherat The Resources Component

    The Resources element represents the web application static resources, from which classes will be loaded, HTML, JSP and the other static files will be served. This allows the webapp to reside on various mediums other than the filesystem, like compressed in a WAR file, in a JDBC database, or in a more advanced versioning repository.

    A unified caching engine is provided for all accesses to the webapp resources made by the servlet container and web applications which use the container provided mechanisms to access such resources, such as classloader access, access through the ServletContext interface, or native access through the DirectoryContext interface.

    Note: Running a webapp with non-filesystem based Resources implementations is only possible when the webapp does not rely on direct filesystem access to its own resources, and uses the methods in the ServletContext interface to access them.

    A Resources element MAY be nested inside a Context component. If it is not included, a default filesystem based Resources will be created automatically, which is sufficient for most requirements.

    All implementations of Resources support the following attributes:

    Java class name of the implementation to use. This class must implement the javax.naming.directory.DirContext interface. It is recommended for optimal functionality and performance, but not mandatory, that the class extend org.apache.naming.resources.BaseDirContext, as well as use the special object types provided in the org.apache.naming.resources for returned objects. If not specified, the standard value (defined below) will be used.

    The standard implementation of Resources is org.apache.naming.resources.FileDirContext, and is configured by its parent Context element.

    This implementation of Resources is org.apache.naming.resources.VirtualDirContext and is aimed to be used during development to deploy a webapp without copying files to a webapp compliant directory structure. It extends FileDirContext and supports the following additional attributes

    Allows to map a path of the filesystem to a path in the webapp. Multiple filesystem paths can be mapped to the same path in the webapp. Filesystem path and virtual path must be separated by an equal signe (=). Pairs of paths must be separated by a column.

    Example: /=/Users/jdoe/mywebapp/src/main/webapp,/=/Users/jdoe/mywebapp/src/main/webapp2,/pictures=/Users/jdoe/sharedpictures

    The path to the docBase (as declared in the Context) must not be added here.

    This attribute enhances the feature provided by the aliases attribute of the StandardContext.

    No components may be nested inside a Resources element.

    No special features are associated with a Resources element.

    tomcat7-7.0.52/webapps/docs/config/cluster-receiver.xml0000644000175100017510000002074312271304167023017 0ustar locutuslocutus ]> &project; Filip Hanik The Cluster Receiver object

    The receiver component is responsible for receiving cluster messages. As you might notice through the configuration, is that the receiving of messages and sending of messages are two different components, this is different from many other frameworks, but there is a good reason for it, to decouple the logic for how messages are sent from how messages are received.
    The receiver is very much like the Tomcat Connector, its the base of the thread pool for incoming cluster messages. The receiver is straight forward, but all the socket settings for incoming traffic are managed here.

    The receiver supports both a non blocking, org.apache.catalina.tribes.transport.nio.NioReceiver, and a blocking, org.apache.catalina.tribes.transport.bio.BioReceiver. It is preferred to use the non blocking receiver to be able to grow your cluster without running into thread starvation.
    Using the non blocking receiver allows you to with a very limited thread count to serve a large number of messages. Usually the rule is to use 1 thread per node in the cluster for small clusters, and then depending on your message frequency and your hardware, you'll find an optimal number of threads peak out at a certain number.

    The implementation of the receiver component. Two implementations available, org.apache.catalina.tribes.transport.nio.NioReceiver and org.apache.catalina.tribes.transport.bio.BioReceiver.
    The org.apache.catalina.tribes.transport.nio.NioReceiver is the preferred implementation
    The address (network interface) to listen for incoming traffic. Same as the bind address. The default value is auto and translates to java.net.InetAddress.getLocalHost().getHostAddress(). Possible values are true or false. Set to true if you want the receiver to use direct bytebuffers when reading data from the sockets. The listen port for incoming data. The default value is 4000. To avoid port conflicts the receiver will automatically bind to a free port within the range of port <= bindPort < port+autoBind So for example, if port is 4000, and autoBind is set to 10, then the receiver will open up a server socket on the first available port in the range 4000-4009. Default value is 100. Use this value if you wish to automatically avoid port conflicts the cluster receiver will try to open a server socket on the port attribute port, and then work up autoBind number of times. The secure listen port. This port is SSL enabled. If this attribute is omitted no SSL port is opened up. There default value is unset, meaning there is no SSL socket available. The UDP listen port. If this attribute is omitted no UDP port is opened up. There default value is unset, meaning there is no UDP listener available. The value in milliseconds for the polling timeout in the NioReceiver. On older versions of the JDK there have been bugs, that should all now be cleared out where the selector never woke up. The default value is a very high 5000 milliseconds. The maximum number of threads in the receiver thread pool. The default value is 6 Adjust this value relative to the number of nodes in the cluster, the number of messages being exchanged and the hardware you are running on. A higher value doesn't mean more efficiency, tune this value according to your own test results. Minimum number of threads to be created when the receiver is started up. Default value is 6 Boolean value for the socket OOBINLINE option. Possible values are true or false. The receiver buffer size on the receiving sockets. Value is in bytes, the default value is 43800 bytes. The sending buffer size on the receiving sockets. Value is in bytes, the default value is 25188 bytes. The receive buffer size on the datagram socket. Default value is 25188 bytes. The send buffer size on the datagram socket. Default value is 43800 bytes. Boolean value for the socket SO_KEEPALIVE option. Possible values are true or false. Boolean value to determine whether to use the SO_LINGER socket option. Possible values are true or false. Default value is true. Sets the SO_LINGER socket option time value. The value is in seconds. The default value is 3 seconds. Boolean value for the socket SO_REUSEADDR option. Possible values are true or false. Boolean value for the socket TCP_NODELAY option. Possible values are true or false. The default value is true Sets the SO_TIMEOUT option on the socket. The value is in milliseconds and the default value is 3000 milliseconds. Boolean value whether to use a shared buffer pool of cached org.apache.catalina.tribes.io.XByteBuffer objects. If set to true, the XByteBuffer that is used to pass a message up the channel, will be recycled at the end of the requests. This means that interceptors in the channel must not maintain a reference to the object after the org.apache.catalina.tribes.ChannelInterceptor#messageReceived method has exited.
    tomcat7-7.0.52/webapps/docs/config/executor.xml0000644000175100017510000001170112057557130021366 0ustar locutuslocutus ]> &project; Filip Hanik The Executor (thread pool)

    The Executor represents a thread pool that can be shared between components in Tomcat. Historically there has been a thread pool per connector created but this allows you to share a thread pool, between (primarly) connector but also other components when those get configured to support executors

    The executor has to implement the org.apache.catalina.Executor interface.

    The executor is a nested element to the Service element. And in order for it to be picked up by the connectors, the Executor element has to appear prior to the Connector element in server.xml

    All implementations of Executor support the following attributes:

    The class of the implementation. The implementation has to implement the org.apache.catalina.Executor interface. This interface ensures that the object can be referenced through its name attribute and that implements Lifecycle, so that it can be started and stopped with the container. The default value for the className is org.apache.catalina.core.StandardThreadExecutor

    The name used to reference this pool in other places in server.xml. The name is required and must be unique.

    The default implementation supports the following attributes:

    (int) The thread priority for threads in the executor, the default is 5 (the value of the Thread.NORM_PRIORITY constant)

    (boolean) Whether the threads should be daemon threads or not, the default is true

    (String) The name prefix for each thread created by the executor. The thread name for an individual thread will be namePrefix+threadNumber

    (int) The max number of active threads in this pool, default is 200

    (int) The minimum number of threads always kept alive, default is 25

    (int) The number of milliseconds before an idle thread shutsdown, unless the number of active threads are less or equal to minSpareThreads. Default value is 60000(1 minute)

    (int) The maximum number of runnable tasks that can queue up awaiting execution before we reject them. Default value is Integer.MAX_VALUE

    (boolean) Whether minSpareThreads should be started when starting the Executor or not, the default is false

    After a context is stopped, threads in the pool are renewed. To avoid renewing all threads at the same time, this delay is observed between 2 threads being renewed. Value is in ms, default value is 1000ms. If negative, threads are not renewed.

    tomcat7-7.0.52/webapps/docs/config/cluster-sender.xml0000644000175100017510000002245112271304167022471 0ustar locutuslocutus ]> &project; Filip Hanik The Cluster Sender object

    The channel sender component is responsible for delivering outgoing cluster messages over the network. In the default implementation, org.apache.catalina.tribes.transport.ReplicationTransmitter, the sender is a fairly empty shell with not much logic around a fairly complex <Transport> component the implements the actual delivery mechanism.

    In the default transport implementation, org.apache.catalina.tribes.transport.nio.PooledParallelSender, Apache Tribes implements what we like to call "Concurrent Parallel Delivery". This means that we can send a message to more than one destination at the same time(parallel), and deliver two messages to the same destination at the same time(concurrent). Combine these two and we have "Concurrent Parallel Delivery".

    When is this useful? The simplest example we can think of is when part of your code is sending a 10MB message, like a war file being deployed, and you need to push through a small 10KB message, say a session being replicated, you don't have to wait for the 10MB message to finish, as a separate thread will push in the small message transmission at the same time. Currently there is no interrupt, pause or priority mechanism available, but check back soon.

    The nested element <Transport> is is not required, by encouraged, as this is where you would set all the socket options for the outgoing messages. Please see its attributes below. There are two implementations, in a similar manner to the receiver, one is non-blocking based and the other is built using blocking IO.
    org.apache.catalina.tribes.transport.bio.PooledMultiSender is the blocking implementation and org.apache.catalina.tribes.transport.nio.PooledParallelSender. Parallel delivery is not available for the blocking implementation due to the fact that it is blocking a thread on sending data.

    Required, only available implementation is org.apache.catalina.tribes.transport.ReplicationTransmitter Required, an implementation of the org.apache.catalina.tribes.transport.MultiPointSender.
    Non-blocking implementation is org.apache.catalina.tribes.transport.nio.PooledParallelSender
    Blocking implementation is org.apache.catalina.tribes.transport.bio.PooledMultiSender
    The receive buffer size on the socket. Default value is 25188 bytes. The send buffer size on the socket. Default value is 43800 bytes. The receive buffer size on the datagram socket. Default value is 25188 bytes. The send buffer size on the datagram socket. Default value is 43800 bytes. Possible values are true or false. Set to true if you want the receiver to use direct bytebuffers when writing data to the sockets. Default value is false The number of requests that can go through the socket before the socket is closed, and reopened for the next request. The default value is -1, which is unlimited. The number of milliseconds a connection is kept open after its been opened. The default value is -1, which is unlimited. Sets the SO_TIMEOUT option on the socket. The value is in milliseconds and the default value is 3000 milliseconds.(3 seconds) This timeout starts when a message send attempt is starting, until the transfer has been completed. For the NIO sockets, this will mean, that the caller can guarantee that we will not attempt sending the message longer than this timeout value. For the blocking IO implementation, this translated directly to the soTimeout.
    A timeout will not spawn a retry attempt, in order to guarantee the return of the application thread.
    How many times do we retry a failed message, that received a IOException at the socket level. The default value is 1, meaning we will retry a message that has failed once. In other words, we will attempt a message send no more than twice. One is the original send, and one is the maxRetryAttempts. Boolean value for the socket OOBINLINE option. Possible values are true or false. Boolean value for the socket SO_KEEPALIVE option. Possible values are true or false. Boolean value to determine whether to use the SO_LINGER socket option. Possible values are true or false. Default value is true. Sets the SO_LINGER socket option time value. The value is in seconds. The default value is 3 seconds. Boolean value for the socket SO_REUSEADDR option. Possible values are true or false. Sets the traffic class level for the socket, the value is between 0 and 255. Default value is int soTrafficClass = 0x04 | 0x08 | 0x010; Different values are defined in java.net.Socket#setTrafficClass(int). Boolean value for the socket TCP_NODELAY option. Possible values are true or false. The default value is true Boolean value, default value is true. If set to true, the sender will throw a org.apache.catalina.tribes.RemoteProcessException when we receive a negative ack from the remote member. Set to false, and Tribes will treat a positive ack the same way as a negative ack, that the message was received.
    The maximum number of concurrent connections from A to B. The value is based on a per-destination count. The default value is 25 The maximum number of milliseconds that the senderPool will wait when there are no available senders. The default value is 3000 milliseconds.(3 seconds).
    tomcat7-7.0.52/webapps/docs/config/engine.xml0000644000175100017510000002330712271304167021000 0ustar locutuslocutus ]> &project; Craig R. McClanahan The Engine Container

    The Engine element represents the entire request processing machinery associated with a particular Catalina Service. It receives and processes all requests from one or more Connectors, and returns the completed response to the Connector for ultimate transmission back to the client.

    Exactly one Engine element MUST be nested inside a Service element, following all of the corresponding Connector elements associated with this Service.

    All implementations of Engine support the following attributes:

    This value represents the delay in seconds between the invocation of the backgroundProcess method on this engine and its child containers, including all hosts and contexts. Child containers will not be invoked if their delay value is not negative (which would mean they are using their own processing thread). Setting this to a positive value will cause a thread to be spawn. After waiting the specified amount of time, the thread will invoke the backgroundProcess method on this engine and all its child containers. If not specified, the default value for this attribute is 10, which represent a 10 seconds delay.

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Engine interface. If not specified, the standard value (defined below) will be used.

    The default host name, which identifies the Host that will process requests directed to host names on this server, but which are not configured in this configuration file. This name MUST match the name attributes of one of the Host elements nested immediately inside.

    Identifier which must be used in load balancing scenarios to enable session affinity. The identifier, which must be unique across all Tomcat servers which participate in the cluster, will be appended to the generated session identifier, therefore allowing the front end proxy to always forward a particular session to the same Tomcat instance.

    Logical name of this Engine, used in log and error messages. When using multiple Service elements in the same Server, each Engine MUST be assigned a unique name.

    The number of threads this Engine will use to start child Host elements in parallel. The special value of 0 will result in the value of Runtime.getRuntime().availableProcessors() being used. Negative values will result in Runtime.getRuntime().availableProcessors() + value being used unless this is less than 1 in which case 1 thread will be used. If not specified, the default value of 1 will be used.

    The standard implementation of Engine is org.apache.catalina.core.StandardEngine. It supports the following additional attributes (in addition to the common attributes listed above):

    You can nest one or more Host elements inside this Engine element, each representing a different virtual host associated with this server. At least one Host is required, and one of the nested Hosts MUST have a name that matches the name specified for the defaultHost attribute, listed above.

    You can nest at most one instance of the following utility components by nesting a corresponding element inside your Engine element:

    • Realm - Configure a realm that will allow its database of users, and their associated roles, to be shared across all Hosts and Contexts nested inside this Engine, unless overridden by a Realm configuration at a lower level.

    An engine is associated with the org.apache.catalina.core.ContainerBase.[enginename] log category. Note that the brackets are actually part of the name, don't omit them.

    When you run a web server, one of the output files normally generated is an access log, which generates one line of information for each request processed by the server, in a standard format. Catalina includes an optional Valve implementation that can create access logs in the same standard format created by web servers, or in any number of custom formats.

    You can ask Catalina to create an access log for all requests processed by an Engine, Host, or Context by nesting a Valve element like this:

    <Engine name="Standalone" ...> ... <Valve className="org.apache.catalina.valves.AccessLogValve" prefix="catalina_access_log." suffix=".txt" pattern="common"/> ... </Engine>

    See Access Log Valve for more information on the configuration attributes that are supported.

    If you have implemented a Java object that needs to know when this Engine is started or stopped, you can declare it by nesting a Listener element inside this element. The class name you specify must implement the org.apache.catalina.LifecycleListener interface, and it will be notified about the occurrence of the corresponding lifecycle events. Configuration of such a listener looks like this:

    <Engine name="Standalone" ...> ... <Listener className="com.mycompany.mypackage.MyListener" ... > ... </Engine>

    Note that a Listener can have any number of additional properties that may be configured from this element. Attribute names are matched to corresponding JavaBean property names using the standard property method naming patterns.

    You can ask Catalina to check the IP address, or host name, on every incoming request directed to the surrounding Engine, Host, or Context element. The remote address or name will be checked against configured "accept" and/or "deny" filters, which are defined using java.util.regex Regular Expression syntax. Requests that come from locations that are not accepted will be rejected with an HTTP "Forbidden" error. Example filter declarations:

    <Engine name="Standalone" ...> ... <Valve className="org.apache.catalina.valves.RemoteHostValve" allow=".*\.mycompany\.com|www\.yourcompany\.com"/> <Valve className="org.apache.catalina.valves.RemoteAddrValve" deny="192\.168\.1\.\d+"/> ... </Engine>

    See Remote Address Filter and Remote Host Filter for more information about the configuration options that are supported.

    tomcat7-7.0.52/webapps/docs/config/server.xml0000644000175100017510000000750612271304167021044 0ustar locutuslocutus ]> &project; Craig R. McClanahan The Server Component

    A Server element represents the entire Catalina servlet container. Therefore, it must be the single outermost element in the conf/server.xml configuration file. Its attributes represent the characteristics of the servlet container as a whole.

    All implementations of Server support the following attributes:

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Server interface. If no class name is specified, the standard implementation will be used.

    The TCP/IP address on which this server waits for a shutdown command. If no address is specified, localhost is used.

    The TCP/IP port number on which this server waits for a shutdown command. Set to -1 to disable the shutdown port.

    Note: Disabling the shutdown port works well when Tomcat is started using Apache Commons Daemon (running as a service on Windows or with jsvc on un*xes). It cannot be used when running Tomcat with the standard shell scripts though, as it will prevent shutdown.bat|.sh and catalina.bat|.sh from stopping it gracefully.

    The command string that must be received via a TCP/IP connection to the specified port number, in order to shut down Tomcat.

    The standard implementation of Server is org.apache.catalina.core.StandardServer. It supports the following additional attributes (in addition to the common attributes listed above):

    The following components may be nested inside a Server element:

    There are no special features associated with a Server.

    tomcat7-7.0.52/webapps/docs/config/loader.xml0000644000175100017510000001643612271304167021006 0ustar locutuslocutus ]> &project; Craig R. McClanahan The Loader Component

    The Loader element represents the web application class loader that will be used to load Java classes and resources for your web application. Such a class loader must follow the requirements of the Servlet Specification, and load classes from the following locations:

    • From the /WEB-INF/classes directory inside your web application.
    • From JAR files in the /WEB-INF/lib directory inside your web application.
    • From resources made available by Catalina to all web applications globally.

    A Loader element MAY be nested inside a Context component. If it is not included, a default Loader configuration will be created automatically, which is sufficient for most requirements.

    For a more in-depth description of the class loader hierarchy that is implemented by Catalina, see the ClassLoader HowTo.

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    All implementations of Loader support the following attributes:

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Loader interface. If not specified, the standard value (defined below) will be used.

    Set to true if you want the class loader to follow the standard Java2 delegation model, and attempt to load classes from parent class loaders before looking inside the web application. Set to false (the default) to have the class loader look inside the web application first, before asking parent class loaders to find requested classes or resources.

    Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. This feature is very useful during application development, but it requires significant runtime overhead and is not recommended for use on deployed production applications. You can use the Manager web application, however, to trigger reloads of deployed applications on demand.

    NOTE - The value for this property will be inherited from the reloadable attribute you set on the surrounding Context component, and any value you explicitly set here will be replaced.

    The standard implementation of Loader is org.apache.catalina.loader.WebappLoader. It supports the following additional attributes (in addition to the common attributes listed above):

    Java class name of the java.lang.ClassLoader implementation class to use. If not specified, the default value is org.apache.catalina.loader.WebappClassLoader. Custom loaderClass implementations must extend org.apache.catalina.loader.WebappClassLoader.

    Set to true if you want repositories outside of WEB-INF/classes and WEB-INF/lib to be searched first. Default value is false.

    This implementation of Loader is org.apache.catalina.loader.VirtualWebappLoader. It extends WebappLoader and supports the following additional attributes

    Additional repositories to search for resources. Multiple values can be joined using ; as a separator.

    Leading and trailing whitespaces in values are ignored. If a value does not point to an existing directory or *.jar file, it is silently skipped. Diagnostic messages can be seen if you enable debug logging for the VirtualWebappLoader class.

    Example: virtualClasspath="${catalina.base}/myapp_config"

    Set to true if you want the virtual class path to be searched before WEB-INF/classes and WEB-INF/lib. Default value is false.

    If searched before, resources located in the virtual class path take precendence over resources with the same name contained in the webapp.

    No components may be nested inside a Loader element.

    A loader is associated with the log category based on its classname.

    tomcat7-7.0.52/webapps/docs/config/cluster.xml0000644000175100017510000001771312275241511021215 0ustar locutuslocutus ]> &project; Filip Hanik The Cluster object

    The tomcat cluster implementation provides session replication, context attribute replication and cluster wide WAR file deployment. While the Cluster configuration is fairly complex, the default configuration will work for most people out of the box.

    The Tomcat Cluster implementation is very extensible, and hence we have exposed a myriad of options, making the configuration seem like a lot, but don't lose faith, instead you have a tremendous control over what is going on.

    You can place the <Cluster> element inside either the <Engine> container or the <Host> container.
    Placing it in the engine, means that you will support clustering in all virtual hosts of Tomcat, and share the messaging component. When you place the <Cluster> inside the <Engine> element, the cluster will append the host name of each session manager to the managers name so that two contexts with the same name but sitting inside two different hosts will be distinguishable.

    To configure context attribute replication, simply do this by swapping out the context implementation used for your application context. <Context className="org.apache.catalina.ha.context.ReplicatedContext"/> This context extends the Tomcat StandardContext so all the options from the base implementation are valid.

    Manager:
    The session manager element identifies what kind of session manager is used in this cluster implementation. This manager configuration is identical to the one you would use in a regular <Context> configuration.
    The default value is the org.apache.catalina.ha.session.DeltaManager that is closely coupled with the SimpleTcpCluster implementation. Other managers like the org.apache.catalina.ha.session.BackupManager are/could be loosely coupled and don't rely on the SimpleTcpCluster for its data replication.

    Channel:
    The Channel and its sub components are all part of the IO layer for the cluster group, and is a module in it's own that we have nick named "Tribes"
    Any configuring and tuning of the network layer, the messaging and the membership logic will be done in the channel and its nested components. You can always find out more about Apache Tribes

    Valve:
    The Tomcat Cluster implementation uses Tomcat Valves to track when requests enter and exit the servlet container. It uses these valves to be able to make intelligent decisions on when to replicate data, which is always at the end of a request.

    Deployer:
    The Deployer component is the Tomcat Farm Deployer. It allows you to deploy and undeploy applications cluster wide.

    ClusterListener:
    ClusterListener's are used to track messages sent and received using the SimpleTcpCluster. If you wish to track messages, you can add a listener here, or you can add a valve to the channel object.

    Deprecated settings: In the previous version of Tomcat you were able to control session manager settings using manager.<property>=value. This has been discontinued, as the way it was written interferes with the ability to support multiple different manager classes under one cluster implementation, as the same properties might have the different effect on different managers.

    The main cluster class, currently only one is available, org.apache.catalina.ha.tcp.SimpleTcpCluster

    The Tribes channel send options, default is 8.
    This option is used to set the flag that all messages sent through the SimpleTcpCluster uses. The flag decides how the messages are sent, and is a simple logical OR.
    int options= Channel.SEND_OPTIONS_ASYNCHRONOUS | Channel.SEND_OPTIONS_SYNCHRONIZED_ACK | Channel.SEND_OPTIONS_USE_ACK; Some of the values are:
    Channel.SEND_OPTIONS_SYNCHRONIZED_ACK = 0x0004
    Channel.SEND_OPTIONS_ASYNCHRONOUS = 0x0008
    Channel.SEND_OPTIONS_USE_ACK = 0x0002
    So to use ACK and ASYNC messaging, the flag would be 10 (8+2) or 0x000B
    Note that if you use ASYNC messaging it is possible for update messages for a session to be processed by the receiving nodes in a different order to the order in which they were sent.

    Sets the start and stop flags for the <Channel> object used by the cluster. The default is Channel.DEFAULT which starts all the channel services, such as sender, receiver, multicast sender and multicast receiver. The following flags are available today: Channel.DEFAULT = Channel.SND_RX_SEQ (1)| Channel.SND_TX_SEQ (2)| Channel.MBR_RX_SEQ (4)| Channel.MBR_TX_SEQ (8); To start a channel without multicasting, you would want to use the value Channel.SND_RX_SEQ | Channel.SND_TX_SEQ that equals to 3.

    Flag whether invoke channel heartbeat at container background thread. Default value is false. Enable this flag don't forget to disable the channel heartbeat thread.

    Flag whether notify LifecycleListeners if all ClusterListener couldn't accept channel message. Default value is false.

    tomcat7-7.0.52/webapps/docs/config/context.xml0000644000175100017510000020234612274431005021214 0ustar locutuslocutus ]> &project; Craig R. McClanahan The Context Container

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    The Context element represents a web application, which is run within a particular virtual host. Each web application is based on a Web Application Archive (WAR) file, or a corresponding directory containing the corresponding unpacked contents, as described in the Servlet Specification (version 2.2 or later). For more information about web application archives, you can download the Servlet Specification, and review the Tomcat Application Developer's Guide.

    The web application used to process each HTTP request is selected by Catalina based on matching the longest possible prefix of the Request URI against the context path of each defined Context. Once selected, that Context will select an appropriate servlet to process the incoming request, according to the servlet mappings defined by the web application deployment.

    You may define as many Context elements as you wish. Each such Context MUST have a unique context name within a virtual host. The context path does not need to be unique (see parallel deployment below). In addition, a Context must be present with a context path equal to a zero-length string. This Context becomes the default web application for this virtual host, and is used to process all requests that do not match any other Context's context path.

    You may deploy multiple versions of a web application with the same context path at the same time. The rules used to match requests to a context version are as follows:

    • If no session information is present in the request, use the latest version.
    • If session information is present in the request, check the session manager of each version for a matching session and if one is found, use that version.
    • If session information is present in the request but no matching session can be found, use the latest version.

    The Host may be configured (via the undeployOldVersions) to remove old versions deployed in this way once they are no longer in use.

    When autoDeploy or deployOnStartup operations are performed by a Host, the name and context path of the web application are derived from the name(s) of the file(s) that define(s) the web application. Consequently, the context path may not be defined in a META-INF/context.xml embedded in the application and there is a close relationship between the context name, context path, context version and the base file name (the name minus any .war or .xml extension) of the file.

    If no version is specified then the context name is always the same as the context path. If the context path is the empty string them the base name will be ROOT (always in upper case) otherwise the base name will be the context path with the leading '/' removed and any remaining '/' characters replaced with '#'.

    If a version is specified then the context path remains unchanged and both the context name and the base name have the string '##' appended to them followed by the version identifier.

    Some examples of these naming conventions are given below.

    Context Path Context Version Context Name Base File Name Example File Names (.xml, .war & directory)
    /foo None /foo foo foo.xml, foo.war, foo
    /foo/bar None /foo/bar foo#bar foo#bar.xml, foo#bar.war, foo#bar
    Empty String None Empty String ROOT ROOT.xml, ROOT.war, ROOT
    /foo 42 /foo##42 foo##42 foo##42.xml, foo##42.war, foo##42
    /foo/bar 42 /foo/bar##42 foo#bar##42 foo#bar##42.xml, foo#bar##42.war, foo#bar##42
    Empty String 42 ##42 ROOT##42 ROOT##42.xml, ROOT##42.war, ROOT##42

    The version component is treated as a String both for performance reasons and to allow flexibility in versioning schemes. String comparisons are used to determine version order. If version is not specified, it is treated as the empty string. Therefore, foo.war will be treated as an earlier version than foo##11.war and foo##11.war will be treated as an earlier version than foo##2.war. If using a purely numerical versioning scheme it is recommended that zero padding is used so that foo##002.war is treated as an earlier version than foo##011.war.

    If you want to deploy a WAR file or a directory using a context path that is not related to the base file name then one of the following options must be used to prevent double-deployment:

    • Disable autoDeploy and deployOnStartup and define all Contexts in server.xml
    • Locate the WAR and/or directory outside of the Host's appBase and use a context.xml file with a docBase attribute to define it.

    It is NOT recommended to place <Context> elements directly in the server.xml file. This is because it makes modifying the Context configuration more invasive since the main conf/server.xml file cannot be reloaded without restarting Tomcat.

    Individual Context elements may be explicitly defined:

    • In an individual file at /META-INF/context.xml inside the application files. Optionally (based on the Host's copyXML attribute) this may be copied to $CATALINA_BASE/conf/[enginename]/[hostname]/ and renamed to application's base file name plus a ".xml" extension.
    • In individual files (with a ".xml" extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The context path and version will be derived from the base name of the file (the file name less the .xml extension). This file will always take precedence over any context.xml file packaged in the web application's META-INF directory.
    • Inside a Host element in the main conf/server.xml.

    Default Context elements may be defined that apply to multiple web applications. Configuration for an individual web application will override anything configured in one of these defaults. Any nested elements, e.g. <Resource> elements, that are defined in a default Context will be created once for each Context to which the default applies. They will not be shared between Context elements.

    • In the $CATALINA_BASE/conf/context.xml file: the Context element information will be loaded by all web applications.
    • In the $CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default file: the Context element information will be loaded by all web applications of that host.

    With the exception of server.xml, files that define Context elements may only define a single Context element.

    In addition to explicitly specified Context elements, there are several techniques by which Context elements can be created automatically for you. See Automatic Application Deployment and User Web Applications for more information.

    To define multiple contexts that use a single WAR file or directory, use one of the options described in the Naming section above for creating a Context that has a path that is not related to the base file name.

    All implementations of Context support the following attributes:

    Set to true if Tomcat should automatically parse multipart/form-data request bodies when HttpServletRequest.getPart* or HttpServletRequest.getParameter* is called, even when the target servlet isn't marked with the @MultipartConfig annotation (See Servlet Specification 3.0, Section 3.2 for details). Note that any setting other than false causes Tomcat to behave in a way that is not technically spec-compliant. The default is false

    This value represents the delay in seconds between the invocation of the backgroundProcess method on this context and its child containers, including all wrappers. Child containers will not be invoked if their delay value is not negative (which would mean they are using their own processing thread). Setting this to a positive value will cause a thread to be spawn. After waiting the specified amount of time, the thread will invoke the backgroundProcess method on this host and all its child containers. A context will use background processing to perform session expiration and class monitoring for reloading. If not specified, the default value for this attribute is -1, which means the context will rely on the background processing thread of its parent host.

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Context interface. If not specified, the standard value (defined below) will be used.

    The regular expression that specifies which container provided SCIs should be filtered out and not used for this context. Matching uses java.util.regex.Matcher.find() so the regular expression only has to match a sub-string of the fully qualified class name of the container provided SCI for it to be filtered out. If not specified, no filtering will be applied.

    Set to true if you want cookies to be used for session identifier communication if supported by the client (this is the default). Set to false if you want to disable the use of cookies for session identifier communication, and rely only on URL rewriting by the application.

    Set to true if you want calls within this application to ServletContext.getContext() to successfully return a request dispatcher for other web applications running on this virtual host. Set to false (the default) in security conscious environments, to make getContext() always return null.

    The Document Base (also known as the Context Root) directory for this web application, or the pathname to the web application archive file (if this web application is being executed directly from the WAR file). You may specify an absolute pathname for this directory or WAR file, or a pathname that is relative to the appBase directory of the owning Host.

    The value of this field must not be set unless the Context element is defined in server.xml or the docBase is not located under the Host's appBase.

    If a symbolic link is used for docBase then changes to the symbolic link will only be effective after a Tomcat restart or by undeploying and redeploying the context. A context reload is not sufficient.

    Set to true to fire any configured ServletRequestListeners when Tomcat forwards a request. This is primarily of use to users of CDI frameworks that use ServletRequestListeners to configure the necessary environment for a request. If not specified, the default value of false is used.

    Set to true if you want the effective web.xml used for a web application to be logged (at INFO level) when the application starts. The effective web.xml is the result of combining the application's web.xml with any defaults configured by Tomcat and any web-fragment.xml files and annotations discovered. If not specified, the default value of false is used.

    Set to true to ignore any settings in both the global or Host default contexts. By default, settings from a default context will be used but may be overridden by a setting the same attribute explicitly for the Context.

    The context path of this web application, which is matched against the beginning of each request URI to select the appropriate web application for processing. All of the context paths within a particular Host must be unique. If you specify a context path of an empty string (""), you are defining the default web application for this Host, which will process all requests not assigned to other Contexts.

    This attribute must only be used when statically defining a Context in server.xml. In all other circumstances, the path will be inferred from the filenames used for either the .xml context file or the docBase.

    Even when statically defining a Context in server.xml, this attribute must not be set unless either the docBase is not located under the Host's appBase or both deployOnStartup and autoDeploy are false. If this rule is not followed, double deployment is likely to result.

    When set to true and the user presents credentials for a resource that is not protected by a security constraint, if the authenticator supports preemptive authentication (the standard authenticators provided with Tomcat do) then the user' credentials will be processed. If not specified, the default of falseis used.

    Set to true to allow this context to use container servlets, like the manager servlet. Use of the privileged attribute will change the context's parent class loader to be the Server class loader rather than the Shared class loader. Note that in a default installation, the Common class loader is used for both the Server and the Shared class loaders.

    Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. This feature is very useful during application development, but it requires significant runtime overhead and is not recommended for use on deployed production applications. That's why the default setting for this attribute is false. You can use the Manager web application, however, to trigger reloads of deployed applications on demand.

    Comma separated list of Servlet names (as used in /WEB-INF/web.xml) that expect a resource to be present. Ensures that welcome files associated with Servlets that expect a resource to be present (such as the JSP Servlet) are not used when there is no resource present. This prevents issues caused by the clarification of welcome file mapping in section 10.10 of the Servlet 3.0 specification. If the org.apache.catalina.STRICT_SERVLET_COMPLIANCE system property is set to true, the default value of this attribute will be the empty string, else the default value will be jsp.

    If true, redirect responses will include a short response body that includes details of the redirect as recommended by RFC 2616. This is disabled by default since including a response body may cause problems for some application component such as compression filters.

    The domain to be used for all session cookies created for this context. If set, this overrides any domain set by the web application. If not set, the value specified by the web application, if any, will be used.

    The name to be used for all session cookies created for this context. If set, this overrides any name set by the web application. If not set, the value specified by the web application, if any, will be used, or the name JSESSIONID if the web application does not explicitly set one.

    The path to be used for all session cookies created for this context. If set, this overrides any path set by the web application. If not set, the value specified by the web application will be used, or the context path used if the web application does not explicitly set one. To configure all web application to use an empty path (this can be useful for portlet specification implementations) set this attribute to / in the global CATALINA_BASE/conf/context.xml file.

    Note: Once one web application using sessionCookiePath="/" obtains a session, all subsequent sessions for any other web application in the same host also configured with sessionCookiePath="/" will always use the same session ID. This holds even if the session is invalidated and a new one created. This makes session fixation protection more difficult and requires custom, Tomcat specific code to change the session ID shared by the multiple applications.

    Some browsers, such as IE, will send a session cookie for a context with a path of /foo with a request to /foobar. To prevent this, Tomcat will add a trailing slash to the path associated with the session cookie so, in the above example, the cookie path becomes /foo/. However, with a cookie path of /foo/, IE will no longer send the cookie with a request to /foo. This should not be a problem unless there is a servlet mapped to /*. In this case this feature will need to be disabled. The default value for this attribute is true. To disable this feature, set the attribute to false.

    Set to false if Tomcat should not read any additional request body data for aborted uploads and instead abort the client connection. This setting is used in the following situations:

    • the size of the request body is larger than the maxPostSize configured in the connector
    • the size limit of a MultiPart upload is reached
    • the servlet sets the response status to 413 (Request Entity Too Large)

    Not reading the additional data will free the request processing thread more quickly. Unfortunately most HTTP clients will not read the response if they can not write the full request.

    The default is true, so additional data will be read.

    Note if an error occurs during the request processing that triggers a 5xx response, any unread request data will always be ignored and the client connection will be closed once the error response has been written.

    If the value of this flag is true, the bytes output to System.out and System.err by the web application will be redirected to the web application logger. If not specified, the default value of the flag is false.

    If the value of this flag is true, the TLD files will be XML validated on context startup. If the org.apache.catalina.STRICT_SERVLET_COMPLIANCE system property is set to true, the default value of this attribute will be true, else the default value will be false. Setting this attribute to true will incur a performance penalty.

    Should the HttpOnly flag be set on session cookies to prevent client side script from accessing the session ID? Defaults to true.

    Java class name of the org.apache.catalina.Wrapper implementation class that will be used for servlets managed by this Context. If not specified, a standard default value will be used.

    If the value of this flag is true, the parsing of web.xml, web-fragment.xml, *.tld, *.jspx, *.tagx and tagPlugins.xml files for this web application will not permit external entities to be loaded. If not specified, the default value of true will be used.

    If the value of this flag is true, the parsing of web.xml and web-fragment.xml files for this web application will be namespace-aware. Note that *.tld, *.jspx and *.tagx files are always parsed using a namespace-aware parser and that the tagPlugins.xml file (if any) is never parsed using a namespace-aware parser. Note also that if you turn this flag on, you should probably also turn xmlValidation on. If the org.apache.catalina.STRICT_SERVLET_COMPLIANCE system property is set to true, the default value of this attribute will be true, else the default value will be false. Setting this attribute to true will incur a performance penalty.

    If the value of this flag is true, the parsing of web.xml and web-fragment.xml files for this web application will use a validating parser. If the org.apache.catalina.STRICT_SERVLET_COMPLIANCE system property is set to true, the default value of this attribute will be true, else the default value will be false. Setting this attribute to true will incur a performance penalty.

    The standard implementation of Context is org.apache.catalina.core.StandardContext. It supports the following additional attributes (in addition to the common attributes listed above):

    This attribute controls if, in addition to static resources being served from META-INF/resources inside web application JAR files, static resources are also served from WEB-INF/classes/META-INF/resources. This only applies to web applications with a major version of 3 or higher. Since this is a proprietary extension to the Servlet 3 specification, it is disabled by default. To enable this feature, set the attribute to true.

    This attribute provides a list of external locations from which to load resources for this context. The list of aliases should be of the form "/aliasPath1=docBase1,/aliasPath2=docBase2" where aliasPathN must include a leading '/' and docBaseN must be an absolute path to either a .war file or a directory.

    Whitespace is permitted around both the , and = delimiters, and will be trimmed. Therefore, an aliases attribute with the value "/aliasPath1 = docBase1,
    /aliasPath2= docBase2"
    is equivalent to "/aliasPath1=docBase1,/aliasPath2=docBase2"

    A resource will be searched for in the first docBaseN for which aliasPathN is a leading path segment of the resource. If there is no such alias, then the resource will be searched in the usual way.

    Using '/' as an aliasPath is not allowed. Consider using docBase instead.

    These external locations will not be emptied if the context is un-deployed.

    A more powerful feature (for development only) is Virtual webapp.

    If the value of this flag is true, symlinks will be allowed inside the web application, pointing to resources outside the web application base path. If not specified, the default value of the flag is false.

    NOTE: This flag MUST NOT be set to true on the Windows platform (or any other OS which does not have a case sensitive filesystem), as it will disable case sensitivity checks, allowing JSP source code disclosure, among other security problems.

    If true, the Tomcat classloader will take extra measures to avoid JAR file locking when resources are accessed inside JARs through URLs. This will impact startup time of applications, but could prove to be useful on platforms or configurations where file locking can occur. If not specified, the default value is false.

    antiJARLocking is a subset of antiResourceLocking and therefore, to prevent duplicate work and possible issues, only one of these attributes should be set to true at any one time.

    If true, Tomcat will prevent any file locking. This will significantly impact startup time of applications, but allows full webapp hot deploy and undeploy on platforms or configurations where file locking can occur. If not specified, the default value is false.

    antiJARLocking is a subset of antiResourceLocking and therefore, to prevent duplicate work and possible issues, only one of these attributes should be set to true at any one time.

    Please note that setting this to true has some side effects, including the disabling of JSP reloading in a running server: see Bugzilla 37668.

    Please note that setting this flag to true in applications that are outside the appBase for the Host (the webapps directory by default) will cause the application to be deleted on Tomcat shutdown. You probably don't want to do this, so think twice before setting antiResourceLocking=true on a webapp that's outside the appBase for its Host.

    Maximum size of the static resource cache in kilobytes. If not specified, the default value is 10240 (10 megabytes).

    Maximum size of the static resource that will be placed in the cache. If not specified, the default value is 512 (512 kilobytes). If this value is greater than cacheMaxSize/20 it will be reduced to cacheMaxSize/20.

    Amount of time in milliseconds between cache entries revalidation. If not specified, the default value is 5000 (5 seconds).

    If the value of this flag is true, the cache for static resources will be used. If not specified, the default value of the flag is true.

    If true and an sun.net.www.http.HttpClient keep-alive timer thread has been started by this web application and is still running, Tomcat will change the context class loader for that thread from the current WebappClassLoader to WebappClassLoader#parent to prevent a memory leak. Note that the keep-alive timer thread will stop on its own once the keep-alives all expire however, on a busy system that might not happen for some time. If not specified, the default value of true will be used.

    If true, Tomcat attempts to null out any static or final fields from loaded classes when a web application is stopped as a work around for apparent garbage collection bugs and application coding errors. There have been some issues reported with log4j when this is true. Applications without memory leaks using recent JVMs should operate correctly with this attribute set to false. If not specified, the default value of false will be used.

    If true, Tomcat attempts to terminate threads that have been started by the web application. Stopping threads is performed via the deprecated (for good reason) Thread.stop() method and is likely to result in instability. As such, enabling this should be viewed as an option of last resort in a development environment and is not recommended in a production environment. If not specified, the default value of false will be used. If this feature is enabled, web applications may take up to two seconds longer to stop as executor threads are given up to two seconds to stop gracefully before Thread.stop() is called on any remaining threads.

    If true, Tomcat attempts to terminate java.util.Timer threads that have been started by the web application. Unlike standard threads, timer threads can be stopped safely although there may still be side-effects for the application. If not specified, the default value of false will be used.

    Set to true if you want a context XML descriptor embedded inside the application (located at /META-INF/context.xml) to be copied to the owning Host's xmlBase when the application is deployed. On subsequent starts, the copied context XML descriptor will be used in preference to any context XML descriptor embedded inside the application even if the descriptor embedded inside the application is more recent. The flag's value defaults to false. Note if the deployXML attribute of the owning Host is false or if the copyXML attribute of the owning Host is true, this attribute will have no effect.

    If true, any attempt by an application to modify the provided JNDI context with a call to bind(), unbind(), createSubContext(), destroySubContext() or close() will trigger a javax.naming.OperationNotSupportedException as required by section EE.5.3.4 of the Java EE specification. This exception can be disabled by setting this attribute to true in which case any calls to modify the JNDI context will return without making any changes and methods that return values will return null. If not specified, the specification compliant default of true will be used.

    Whether the context should process TLDs on startup. The default is true. The false setting is intended for special cases that know in advance TLDs are not part of the webapp.

    If true, when this context is stopped, Tomcat renews all the threads from the thread pool that was used to serve this context. This also requires that the ThreadLocalLeakPreventionListener be configured in server.xml and that the threadRenewalDelay property of the Executor be >=0. If not specified, the default value of true will be used.

    Number of ms that the container will wait for servlets to unload. If not specified, the default value is 2000 ms.

    If false, the unpackWARs attribute of the owning Host will be overridden and the WAR file will not be unpacked. If true, the value of the owning Host's unpackWARs attribute will determine if the WAR is unpacked. If not specified, the default value is true. Note that WAR files located outside of a Host's appBase are never unpacked.

    Set to true (the default) to have Catalina enable a JNDI InitialContext for this web application that is compatible with Java2 Enterprise Edition (J2EE) platform conventions.

    Pathname to a scratch directory to be provided by this Context for temporary read-write use by servlets within the associated web application. This directory will be made visible to servlets in the web application by a servlet context attribute (of type java.io.File) named javax.servlet.context.tempdir as described in the Servlet Specification. If not specified, a suitable directory underneath $CATALINA_BASE/work will be provided.

    You can nest at most one instance of the following utility components by nesting a corresponding element inside your Context element:

    • Loader - Configure the web application class loader that will be used to load servlet and bean classes for this web application. Normally, the default configuration of the class loader will be sufficient.
    • Manager - Configure the session manager that will be used to create, destroy, and persist HTTP sessions for this web application. Normally, the default configuration of the session manager will be sufficient.
    • Realm - Configure a realm that will allow its database of users, and their associated roles, to be utilized solely for this particular web application. If not specified, this web application will utilize the Realm associated with the owning Host or Engine.
    • Resources - Configure the resource manager that will be used to access the static resources associated with this web application. Normally, the default configuration of the resource manager will be sufficient.
    • WatchedResource - The auto deployer will monitor the specified static resource of the web application for updates, and will reload the web application if it is updated. The content of this element must be a string.

    A context is associated with the org.apache.catalina.core.ContainerBase.[enginename].[hostname].[path] log category. Note that the brackets are actually part of the name, don't omit them.

    When you run a web server, one of the output files normally generated is an access log, which generates one line of information for each request processed by the server, in a standard format. Catalina includes an optional Valve implementation that can create access logs in the same standard format created by web servers, or in any number of custom formats.

    You can ask Catalina to create an access log for all requests processed by an Engine, Host, or Context by nesting a Valve element like this:

    <Context> ... <Valve className="org.apache.catalina.valves.AccessLogValve" prefix="localhost_access_log." suffix=".txt" pattern="common"/> ... </Context>

    See Access Log Valve for more information on the configuration attributes that are supported.

    If you use the standard Context implementation, the following configuration steps occur automatically when Catalina is started, or whenever this web application is reloaded. No special configuration is required to enable this feature.

    • If you have not declared your own Loader element, a standard web application class loader will be configured.
    • If you have not declared your own Manager element, a standard session manager will be configured.
    • If you have not declared your own Resources element, a standard resources manager will be configured.
    • The web application properties listed in conf/web.xml will be processed as defaults for this web application. This is used to establish default mappings (such as mapping the *.jsp extension to the corresponding JSP servlet), and other standard features that apply to all web applications.
    • The web application properties listed in the /WEB-INF/web.xml resource for this web application will be processed (if this resource exists).
    • If your web application has specified security constraints that might require user authentication, an appropriate Authenticator that implements the login method you have selected will be configured.

    You can configure named values that will be made visible to the web application as servlet context initialization parameters by nesting <Parameter> elements inside this element. For example, you can create an initialization parameter like this:

    <Context> ... <Parameter name="companyName" value="My Company, Incorporated" override="false"/> ... </Context>

    This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):

    <context-param> <param-name>companyName</param-name> <param-value>My Company, Incorporated</param-value> </context-param>

    but does not require modification of the deployment descriptor to customize this value.

    The valid attributes for a <Parameter> element are as follows:

    Optional, human-readable description of this context initialization parameter.

    The name of the context initialization parameter to be created.

    Set this to false if you do not want a <context-param> for the same parameter name, found in the web application deployment descriptor, to override the value specified here. By default, overrides are allowed.

    The parameter value that will be presented to the application when requested by calling ServletContext.getInitParameter().

    You can configure named values that will be made visible to the web application as environment entry resources, by nesting <Environment> entries inside this element. For example, you can create an environment entry like this:

    <Context> ... <Environment name="maxExemptions" value="10" type="java.lang.Integer" override="false"/> ... </Context>

    This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):

    <env-entry> <env-entry-name>maxExemptions</env-entry-name> <env-entry-value>10</env-entry-value> <env-entry-type>java.lang.Integer</env-entry-type> </env-entry>

    but does not require modification of the deployment descriptor to customize this value.

    The valid attributes for an <Environment> element are as follows:

    Optional, human-readable description of this environment entry.

    The name of the environment entry to be created, relative to the java:comp/env context.

    Set this to false if you do not want an <env-entry> for the same environment entry name, found in the web application deployment descriptor, to override the value specified here. By default, overrides are allowed.

    The fully qualified Java class name expected by the web application for this environment entry. Must be a legal value for <env-entry-type> in the web application deployment descriptor.

    The parameter value that will be presented to the application when requested from the JNDI context. This value must be convertable to the Java type defined by the type attribute.

    If you have implemented a Java object that needs to know when this Context is started or stopped, you can declare it by nesting a Listener element inside this element. The class name you specify must implement the org.apache.catalina.LifecycleListener interface, and the class must be packaged in a jar and placed in the $CATALINA_HOME/lib directory. It will be notified about the occurrence of the corresponding lifecycle events. Configuration of such a listener looks like this:

    <Context> ... <Listener className="com.mycompany.mypackage.MyListener" ... > ... </Context>

    Note that a Listener can have any number of additional properties that may be configured from this element. Attribute names are matched to corresponding JavaBean property names using the standard property method naming patterns.

    You can ask Catalina to check the IP address, or host name, on every incoming request directed to the surrounding Engine, Host, or Context element. The remote address or name will be checked against configured "accept" and/or "deny" filters, which are defined using java.util.regex Regular Expression syntax. Requests that come from locations that are not accepted will be rejected with an HTTP "Forbidden" error. Example filter declarations:

    <Context> ... <Valve className="org.apache.catalina.valves.RemoteHostValve" allow=".*\.mycompany\.com|www\.yourcompany\.com"/> <Valve className="org.apache.catalina.valves.RemoteAddrValve" deny="192\.168\.1\.\d+"/> ... </Context>

    See Remote Address Filter and Remote Host Filter for more information about the configuration options that are supported.

    You can declare the characteristics of the resource to be returned for JNDI lookups of <resource-ref> and <resource-env-ref> elements in the web application deployment descriptor. You MUST also define the needed resource parameters as attributes of the Resource element, to configure the object factory to be used (if not known to Tomcat already), and the properties used to configure that object factory.

    For example, you can create a resource definition like this:

    <Context> ... <Resource name="jdbc/EmployeeDB" auth="Container" type="javax.sql.DataSource" description="Employees Database for HR Applications"/> ... </Context>

    This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):

    <resource-ref> <description>Employees Database for HR Applications</description> <res-ref-name>jdbc/EmployeeDB</res-ref-name> <res-ref-type>javax.sql.DataSource</res-ref-type> <res-auth>Container</res-auth> </resource-ref>

    but does not require modification of the deployment descriptor to customize this value.

    The valid attributes for a <Resource> element are as follows:

    Specify whether the web Application code signs on to the corresponding resource manager programatically, or whether the Container will sign on to the resource manager on behalf of the application. The value of this attribute must be Application or Container. This attribute is required if the web application will use a <resource-ref> element in the web application deployment descriptor, but is optional if the application uses a <resource-env-ref> instead.

    Name of the zero-argument method to call on a singleton resource when it is no longer required. This is intended to speed up clean-up of resources that would otherwise happen as part of garbage collection. This attribute is ignored if the singleton attribute is false. If not specificed, no default is defined and no close method will be called.

    For Apache Commons DBCP and Apache Tomcat JDBC connection pools you can use closeMethod="close".

    Optional, human-readable description of this resource.

    The name of the resource to be created, relative to the java:comp/env context.

    Specify whether connections obtained through this resource manager can be shared. The value of this attribute must be Shareable or Unshareable. By default, connections are assumed to be shareable.

    Specify whether this resource definition is for a singleton resource, i.e. one where there is only a single instance of the resource. If this attribute is true, multiple JNDI lookups for this resource will return the same object. If this attribute is false, multiple JNDI lookups for this resource will return different objects. This attribute must be true for javax.sql.DataSource resources to enable JMX registration of the DataSource. The value of this attribute must be true or false. By default, this attribute is true.

    The fully qualified Java class name expected by the web application when it performs a lookup for this resource.

    This element is used to create a link to a global JNDI resource. Doing a JNDI lookup on the link name will then return the linked global resource.

    For example, you can create a resource link like this:

    <Context> ... <ResourceLink name="linkToGlobalResource" global="simpleValue" type="java.lang.Integer" ... </Context>

    The valid attributes for a <ResourceLink> element are as follows:

    The name of the linked global resource in the global JNDI context.

    The name of the resource link to be created, relative to the java:comp/env context.

    The fully qualified Java class name expected by the web application when it performs a lookup for this resource link.

    The fully qualified Java class name for the class creating these objects. This class should implement the javax.naming.spi.ObjectFactory interface.

    When the attribute factory="org.apache.naming.factory.DataSourceLinkFactory" the resource link can be used with two additional attributes to allow a shared data source to be used with different credentials. When these two additional attributes are used in combination with the javax.sql.DataSource type, different contexts can share a global data source with different credentials. Under the hood, what happens is that a call to getConnection() is simply translated to a call getConnection(username, password) on the global data source. This is an easy way to get code to be transparent to what schemas are being used, yet be able to control connections (or pools) in the global configuration.

    username value for the getConnection(username, password) call on the linked global DataSource.

    password value for the getConnection(username, password) call on the linked global DataSource.

    Shared Data Source Example:

    Warning: This feature works only if the global DataSource supports getConnection(username, password) method. Apache Commons DBCP pool that Tomcat uses by default does not support it. See its Javadoc for BasicDataSource class. Apache Tomcat JDBC pool does support it, but by default this support is disabled and can be enabled by alternateUsernameAllowed attribute. See its documentation for details.

    <GlobalNamingResources> ... <Resource name="sharedDataSource" global="sharedDataSource" type="javax.sql.DataSource" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" alternateUsernameAllowed="true" username="bar" password="barpass" ... ... </GlobalNamingResources> <Context path="/foo"...> ... <ResourceLink name="appDataSource" global="sharedDataSource" type="javax.sql.DataSource" factory="org.apache.naming.factory.DataSourceLinkFactory" username="foo" password="foopass" ... </Context> <Context path="/bar"...> ... <ResourceLink name="appDataSource" global="sharedDataSource" type="javax.sql.DataSource" ... </Context>

    When a request for getConnection() is made in the /foo context, the request is translated into getConnection("foo","foopass"), while a request in the /bar gets passed straight through.

    You can declare the characteristics of the UserTransaction to be returned for JNDI lookup for java:comp/UserTransaction. You MUST define an object factory class to instantiate this object as well as the needed resource parameters as attributes of the Transaction element, and the properties used to configure that object factory.

    The valid attributes for the <Transaction> element are as follows:

    The class name for the JNDI object factory.

    During development it may be more productive to avoid copying files (static resources, JSPs, classes, jars...) and configure tomcat to use files from their source locations. To do that, several customisations of the context configuration are required:

    • The VirtualDirContext implementation of Resources
    • The VirtualWebappLoader implementation of Loader
    • scanAllDirectories="true" on the JarScanner

    To illustrate this feature, here is an example of a standard maven webapp source tree:

    mywebapp/ src/ main/ java/ resources/ webapp/ WEB-INF/ classes/ target/ classes/

    To deploy such an application (assuming it also uses the log4j maven artefact), the context configuration looks like:

    <Context path="/mywebapp" docBase="/Users/theuser/mywebapp/src/main/webapp" > <Resources className="org.apache.naming.resources.VirtualDirContext" extraResourcePaths= "/WEB-INF/classes=/Users/theuser/mywebapp/target/classes" /> <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="/Users/theuser/mywebapp/target/classes; /Users/theuser/.m2/repository/log4j/log4j/1.2.15/log4j-1.2.15.jar" /> <JarScanner scanAllDirectories="true" /> </Context>

    Here is another example where the webapp serves pictures under /pictures and movies under /movies and also depends on another maven project mylib that would normally produce a jar to be packaged in WEB-INF/lib:

    mylib/ src/ main/ java/ resources/ META-INF/ resources/ target/ classes/ mymovies/ mypictures/ mywebapp/ src/ main/ java/ resources/ webapp/ WEB-INF/ classes/ target/ classes/

    The configuration is:

    <Context path="/mywebapp" docBase="/Users/theuser/mywebapp/src/main/webapp" > <Resources className="org.apache.naming.resources.VirtualDirContext" extraResourcePaths="/WEB-INF/classes=/Users/theuser/mywebapp/target/classes,/pictures=/Users/theuser/mypictures,/movies=/Users/theuser/mymovies" /> <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="/Users/theuser/mywebapp/target/classes;/Users/theuser/mylib/target/classes;/Users/theuser/.m2/repository/log4j/log4j/1.2.15/log4j-1.2.15.jar" /> <JarScanner scanAllDirectories="true" /> </Context>

    Note that resources in mylib/target/classes/META-INF/resources/ are mapped to / as required by servlet 3 specification.

    tomcat7-7.0.52/webapps/docs/config/http.xml0000644000175100017510000017137712271304167020525 0ustar locutuslocutus ]> &project; Craig R. McClanahan Yoav Shapira The HTTP Connector

    The HTTP Connector element represents a Connector component that supports the HTTP/1.1 protocol. It enables Catalina to function as a stand-alone web server, in addition to its ability to execute servlets and JSP pages. A particular instance of this component listens for connections on a specific TCP port number on the server. One or more such Connectors can be configured as part of a single Service, each forwarding to the associated Engine to perform request processing and create the response.

    If you wish to configure the Connector that is used for connections to web servers using the AJP protocol (such as the mod_jk 1.2.x connector for Apache 1.3), please refer to the AJP Connector documentation.

    Each incoming request requires a thread for the duration of that request. If more simultaneous requests are received than can be handled by the currently available request processing threads, additional threads will be created up to the configured maximum (the value of the maxThreads attribute). If still more simultaneous requests are received, they are stacked up inside the server socket created by the Connector, up to the configured maximum (the value of the acceptCount attribute). Any further simultaneous requests will receive "connection refused" errors, until resources are available to process them.

    All implementations of Connector support the following attributes:

    A boolean value which can be used to enable or disable the TRACE HTTP method. If not specified, this attribute is set to false.

    The default timeout for asynchronous requests in milliseconds. If not specified, this attribute is set to 10000 (10 seconds).

    Set to true if you want calls to request.getRemoteHost() to perform DNS lookups in order to return the actual host name of the remote client. Set to false to skip the DNS lookup and return the IP address in String form instead (thereby improving performance). By default, DNS lookups are disabled.

    The maximum number of headers in a request that are allowed by the container. A request that contains more headers than the specified limit will be rejected. A value of less than 0 means no limit. If not specified, a default of 100 is used.

    The maximum number of parameter and value pairs (GET plus POST) which will be automatically parsed by the container. Parameter and value pairs beyond this limit will be ignored. A value of less than 0 means no limit. If not specified, a default of 10000 is used. Note that FailedRequestFilter filter can be used to reject requests that hit the limit.

    The maximum size in bytes of the POST which will be handled by the container FORM URL parameter parsing. The limit can be disabled by setting this attribute to a value less than or equal to 0. If not specified, this attribute is set to 2097152 (2 megabytes).

    The maximum size in bytes of the POST which will be saved/buffered by the container during FORM or CLIENT-CERT authentication. For both types of authentication, the POST will be saved/buffered before the user is authenticated. For CLIENT-CERT authentication, the POST is buffered for the duration of the SSL handshake and the buffer emptied when the request is processed. For FORM authentication the POST is saved whilst the user is re-directed to the login form and is retained until the user successfully authenticates or the session associated with the authentication request expires. The limit can be disabled by setting this attribute to -1. Setting the attribute to zero will disable the saving of POST data during authentication. If not specified, this attribute is set to 4096 (4 kilobytes).

    A comma-separated list of HTTP methods for which request bodies will be parsed for request parameters identically to POST. This is useful in RESTful applications that want to support POST-style semantics for PUT requests. Note that any setting other than POST causes Tomcat to behave in a way that goes against the intent of the servlet specification. The HTTP method TRACE is specifically forbidden here in accordance with the HTTP specification. The default is POST

    The TCP port number on which this Connector will create a server socket and await incoming connections. Your operating system will allow only one server application to listen to a particular port number on a particular IP address. If the special value of 0 (zero) is used, then Tomcat will select a free port at random to use for this connector. This is typically only useful in embedded and testing applications.

    Sets the protocol to handle incoming traffic. The default value is HTTP/1.1 which uses an auto-switching mechanism to select either a blocking Java based connector or an APR/native based connector. If the PATH (Windows) or LD_LIBRARY_PATH (on most unix systems) environment variables contain the Tomcat native library, the APR/native connector will be used. If the native library cannot be found, the blocking Java based connector will be used. Note that the APR/native connector has different settings for HTTPS than the Java connectors.
    To use an explicit protocol rather than rely on the auto-switching mechanism described above, the following values may be used:
    org.apache.coyote.http11.Http11Protocol - blocking Java connector
    org.apache.coyote.http11.Http11NioProtocol - non blocking Java connector
    org.apache.coyote.http11.Http11AprProtocol - the APR/native connector.
    Custom implementations may also be used.
    Take a look at our Connector Comparison chart. The configuration for both Java connectors is identical, for http and https.
    For more information on the APR connector and APR specific SSL settings please visit the APR documentation

    If this Connector is being used in a proxy configuration, configure this attribute to specify the server name to be returned for calls to request.getServerName(). See Proxy Support for more information.

    If this Connector is being used in a proxy configuration, configure this attribute to specify the server port to be returned for calls to request.getServerPort(). See Proxy Support for more information.

    If this Connector is supporting non-SSL requests, and a request is received for which a matching <security-constraint> requires SSL transport, Catalina will automatically redirect the request to the port number specified here.

    Set this attribute to the name of the protocol you wish to have returned by calls to request.getScheme(). For example, you would set this attribute to "https" for an SSL Connector. The default value is "http".

    Set this attribute to true if you wish to have calls to request.isSecure() to return true for requests received by this Connector. You would want this on an SSL Connector or a non SSL connector that is receiving data from a SSL accelerator, like a crypto card, a SSL appliance or even a webserver. The default value is false.

    This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.

    This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitly set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false.

    Set this attribute to true to cause Tomcat to use the IP address that the request was received on to determine the Host to send the request to. The default value is false.

    Set this attribute to true to cause Tomcat to advertise support for the Servlet specification using the header recommended in the specification. The default value is false.

    The standard HTTP connectors (BIO, NIO and APR/native) all support the following attributes in addition to the common Connector attributes listed above.

    The maximum queue length for incoming connection requests when all possible request processing threads are in use. Any requests received when the queue is full will be refused. The default value is 100.

    The number of threads to be used to accept connections. Increase this value on a multi CPU machine, although you would never really need more than 2. Also, with a lot of non keep alive connections, you might want to increase this value as well. Default value is 1.

    The priority of the acceptor threads. The threads used to accept new connections. The default value is 5 (the value of the java.lang.Thread.NORM_PRIORITY constant). See the JavaDoc for the java.lang.Thread class for more details on what this priority means.

    For servers with more than one IP address, this attribute specifies which address will be used for listening on the specified port. By default, this port will be used on all IP addresses associated with the server.

    Controls when the socket used by the connector is bound. By default it is bound when the connector is initiated and unbound when the connector is destroyed. If set to false, the socket will be bound when the connector is started and unbound when it is stopped.

    The value is a comma separated list of MIME types for which HTTP compression may be used. The default value is text/html,text/xml,text/plain.

    The Connector may use HTTP/1.1 GZIP compression in an attempt to save server bandwidth. The acceptable values for the parameter is "off" (disable compression), "on" (allow compression, which causes text data to be compressed), "force" (forces compression in all cases), or a numerical integer value (which is equivalent to "on", but specifies the minimum amount of data before the output is compressed). If the content-length is not known and compression is set to "on" or more aggressive, the output will also be compressed. If not specified, this attribute is set to "off".

    Note: There is a tradeoff between using compression (saving your bandwidth) and using the sendfile feature (saving your CPU cycles). If the connector supports the sendfile feature, e.g. the NIO connector, using sendfile will take precedence over compression. The symptoms will be that static files greater that 48 Kb will be sent uncompressed. You can turn off sendfile by setting useSendfile attribute of the connector, as documented below, or change the sendfile usage threshold in the configuration of the DefaultServlet in the default conf/web.xml or in the web.xml of your web application.

    If compression is set to "on" then this attribute may be used to specify the minimum amount of data before the output is compressed. If not specified, this attribute is defaults to "2048".

    The number of seconds during which the sockets used by this Connector will linger when they are closed. If not specified, the JVM default will be used.

    The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented. Use a value of -1 to indicate no (i.e. infinite) timeout. The default value is 60000 (i.e. 60 seconds) but note that the standard server.xml that ships with Tomcat sets this to 20000 (i.e. 20 seconds). Unless disableUploadTimeout is set to false, this timeout will also be used when reading the request body (if any).

    Specifies the timeout, in milliseconds, to use while a data upload is in progress. This only takes effect if disableUploadTimeout is set to false.

    This flag allows the servlet container to use a different, usually longer connection timeout during data upload. If not specified, this attribute is set to true which disables this longer timeout.

    A reference to the name in an Executor element. If this attribute is set, and the named executor exists, the connector will use the executor, and all the other thread attributes will be ignored. Note that if a shared executor is not specified for a connector then the connector will use a private, internal executor to provide the thread pool.

    The time that the private internal executor will wait for request processing threads to terminate before continuing with the process of stopping the connector. If not set, the default is 0 (zero) for the BIO connector and 5000 (5 seconds) for the NIO and APR/native connectors.

    The number of milliseconds this Connector will wait for another HTTP request before closing the connection. The default value is to use the value that has been set for the connectionTimeout attribute. Use a value of -1 to indicate no (i.e. infinite) timeout.

    The maximum number of connections that the server will accept and process at any given time. When this number has been reached, the server will accept, but not process, one further connection. This additional connection be blocked until the number of connections being processed falls below maxConnections at which point the server will start accepting and processing new connections again. Note that once the limit has been reached, the operating system may still accept connections based on the acceptCount setting. The default value varies by connector type. For BIO the default is the value of maxThreads unless an Executor is used in which case the default will be the value of maxThreads from the executor. For NIO the default is 10000. For APR/native, the default is 8192.

    Note that for APR/native on Windows, the configured value will be reduced to the highest multiple of 1024 that is less than or equal to maxConnections. This is done for performance reasons.
    If set to a value of -1, the maxConnections feature is disabled and connections are not counted.

    Limits the total length of chunk extensions in chunked HTTP requests. If the value is -1, no limit will be imposed. If not specified, the default value of 8192 will be used.

    The maximum size of the request and response HTTP header, specified in bytes. If not specified, this attribute is set to 8192 (8 KB).

    The maximum number of HTTP requests which can be pipelined until the connection is closed by the server. Setting this attribute to 1 will disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1 will allow an unlimited amount of pipelined or keep-alive HTTP requests. If not specified, this attribute is set to 100.

    The maximum number of request processing threads to be created by this Connector, which therefore determines the maximum number of simultaneous requests that can be handled. If not specified, this attribute is set to 200. If an executor is associated with this connector, this attribute is ignored as the connector will execute tasks using the executor rather than an internal thread pool.

    Limits the total length of trailing headers in the last chunk of a chunked HTTP request. If the value is -1, no limit will be imposed. If not specified, the default value of 8192 will be used.

    The minimum number of threads always kept running. If not specified, the default of 10 is used.

    The value is a regular expression (using java.util.regex) matching the user-agent header of HTTP clients for which compression should not be used, because these clients, although they do advertise support for the feature, have a broken implementation. The default value is an empty String (regexp matching disabled).

    The protocol handler caches Processor objects to speed up performance. This setting dictates how many of these objects get cached. -1 means unlimited, default is 200. If not using Servlet 3.0 asynchronous processing, a good default is to use the same as the maxThreads setting. If using Servlet 3.0 asynchronous processing, a good default is to use the larger of maxThreads and the maximum number of expected concurrent requests (synchronous and asynchronous).

    The value is a regular expression (using java.util.regex) matching the user-agent header of HTTP clients for which HTTP/1.1 or HTTP/1.0 keep alive should not be used, even if the clients advertise support for these features. The default value is an empty String (regexp matching disabled).

    Overrides the Server header for the http response. If set, the value for this attribute overrides the Tomcat default and any Server header set by a web application. If not set, any value specified by the application is used. If the application does not specify a value then Apache-Coyote/1.1 is used. Unless you are paranoid, you won't need this feature.

    The size (in bytes) of the buffer to be provided for socket output buffering. -1 can be specified to disable the use of a buffer. By default, a buffers of 9000 bytes will be used.

    Use this attribute to enable SSL traffic on a connector. To turn on SSL handshake/encryption/decryption on a connector set this value to true. The default value is false. When turning this value true you will want to set the scheme and the secure attributes as well to pass the correct request.getScheme() and request.isSecure() values to the servlets See SSL Support for more information.

    If set to true, the TCP_NO_DELAY option will be set on the server socket, which improves performance under most circumstances. This is set to true by default.

    The priority of the request processing threads within the JVM. The default value is 5 (the value of the java.lang.Thread.NORM_PRIORITY constant). See the JavaDoc for the java.lang.Thread class for more details on what this priority means.

    The BIO and NIO implementation support the following Java TCP socket attributes in addition to the common Connector and HTTP attributes listed above.

    (int)The socket receive buffer (SO_RCVBUF) size in bytes. JVM default used if not set.

    (int)The socket send buffer (SO_SNDBUF) size in bytes. JVM default used if not set.

    (bool)This is equivalent to standard attribute tcpNoDelay.

    (bool)Boolean value for the socket's keep alive setting (SO_KEEPALIVE). JVM default used if not set.

    (bool)Boolean value for the socket OOBINLINE setting. JVM default used if not set.

    (bool)Boolean value for the sockets reuse address option (SO_REUSEADDR). JVM default used if not set.

    (bool)Boolean value for the sockets so linger option (SO_LINGER). A value for the standard attribute connectionLinger that is >=0 is equivalent to setting this to true. A value for the standard attribute connectionLinger that is <0 is equivalent to setting this to false. Both this attribute and soLingerTime must be set else the JVM defaults will be used for both.

    (int)Value in seconds for the sockets so linger option (SO_LINGER). This is equivalent to standard attribute connectionLinger. Both this attribute and soLingerOn must be set else the JVM defaults will be used for both.

    This is equivalent to standard attribute connectionTimeout.

    (int)The first value for the performance settings. See Socket Performance Options All three performance attributes must be set else the JVM defaults will be used for all three.

    (int)The second value for the performance settings. See Socket Performance Options All three performance attributes must be set else the JVM defaults will be used for all three.

    (int)The third value for the performance settings. See Socket Performance Options All three performance attributes must be set else the JVM defaults will be used for all three.

    (int) The timeout for a socket unlock. When a connector is stopped, it will try to release the acceptor thread by opening a connector to itself. The default value is 250 and the value is in milliseconds

    The following attributes are specific to the BIO connector.

    The percentage of processing threads that have to be in use before HTTP keep-alives are disabled to improve scalability. Values less than 0 will be changed to 0 and values greater than 100 will be changed to 100. If not specified, the default value is 75.

    The following attributes are specific to the NIO connector.

    (int)The number of threads to be used to run for the polling events. Default value is 1 per processor up to and including version 7.0.27. Default value as of version 7.0.28 is 1 per processor but not more than 2.
    When accepting a socket, the operating system holds a global lock. So the benefit of going above 2 threads diminishes rapidly. Having more than one thread is for system that need to accept connections very rapidly. However usually just increasing acceptCount will solve that problem. Increasing this value may also be beneficial when a large amount of send file operations are going on.

    (int)The priority of the poller threads. The default value is 5 (the value of the java.lang.Thread.NORM_PRIORITY constant). See the JavaDoc for the java.lang.Thread class for more details on what this priority means.

    (int)The time in milliseconds to timeout on a select() for the poller. This value is important, since connection clean up is done on the same thread, so do not set this value to an extremely high one. The default value is 1000 milliseconds.

    (bool)Whether to allow comet servlets or not. Default value is true.

    (bool)Use this attribute to enable or disable sendfile capability. The default value is true.

    (bool)Boolean value, whether to use direct ByteBuffers or java mapped ByteBuffers. Default is false.
    When you are using direct buffers, make sure you allocate the appropriate amount of memory for the direct memory space. On Sun's JDK that would be something like -XX:MaxDirectMemorySize=256m.

    (int)Each connection that is opened up in Tomcat get associated with a read ByteBuffer. This attribute controls the size of this buffer. By default this read buffer is sized at 8192 bytes. For lower concurrency, you can increase this to buffer more data. For an extreme amount of keep alive connections, decrease this number or increase your heap size.

    (int)Each connection that is opened up in Tomcat get associated with a write ByteBuffer. This attribute controls the size of this buffer. By default this write buffer is sized at 8192 bytes. For low concurrency you can increase this to buffer more response data. For an extreme amount of keep alive connections, decrease this number or increase your heap size.
    The default value here is pretty low, you should up it if you are not dealing with tens of thousands concurrent connections.

    (int)The NIO connector uses a class called NioChannel that holds elements linked to a socket. To reduce garbage collection, the NIO connector caches these channel objects. This value specifies the size of this cache. The default value is 500, and represents that the cache will hold 500 NioChannel objects. Other values are -1 for unlimited cache and 0 for no cache.

    (int)The NioChannel pool can also be size based, not used object based. The size is calculated as follows:
    NioChannel buffer size = read buffer size + write buffer size
    SecureNioChannel buffer size = application read buffer size + application write buffer size + network read buffer size + network write buffer size
    The value is in bytes, the default value is 1024*1024*100 (100MB).

    (int)Tomcat will cache SocketProcessor objects to reduce garbage collection. The integer value specifies how many objects to keep in the cache at most. The default is 500. Other values are -1 for unlimited cache and 0 for no cache.

    (int)Tomcat will cache KeyAttachment objects to reduce garbage collection. The integer value specifies how many objects to keep in the cache at most. The default is 500. Other values are -1 for unlimited cache and 0 for no cache.

    (int)Tomcat will cache PollerEvent objects to reduce garbage collection. The integer value specifies how many objects to keep in the cache at most. The default is 500. Other values are -1 for unlimited cache and 0 for no cache.

    (int)The max selectors to be used in the pool, to reduce selector contention. Use this option when the command line org.apache.tomcat.util.net.NioSelectorShared value is set to false. Default value is 200.

    (int)The max spare selectors to be used in the pool, to reduce selector contention. When a selector is returned to the pool, the system can decide to keep it or let it be GC'd. Use this option when the command line org.apache.tomcat.util.net.NioSelectorShared value is set to false. Default value is -1 (unlimited).

    The following command line options are available for the NIO connector:
    -Dorg.apache.tomcat.util.net.NioSelectorShared=true|false - default is true. Set this value to false if you wish to use a selector for each thread. When you set it to false, you can control the size of the pool of selectors by using the selectorPool.maxSelectors attribute.

    (int)The NIO connector implements an OutOfMemoryError strategy called parachute. It holds a chunk of data as a byte array. In case of an OOM, this chunk of data is released and the error is reported. This will give the VM enough room to clean up. The oomParachute represents the size in bytes of the parachute(the byte array). The default value is 1024*1024(1MB). Please note, this only works for OOM errors regarding the Java Heap space, and there is absolutely no guarantee that you will be able to recover at all. If you have an OOM outside of the Java Heap, then this parachute trick will not help.

    The following attributes are specific to the APR/native connector.

    Sets the TCP_DEFER_ACCEPT flag on the listening socket for this connector. The default value is true where TCP_DEFER_ACCEPT is supported by the operating system, otherwise it is false.

    Amount of sockets that the poller responsible for polling kept alive connections can hold at a given time. Extra connections will be closed right away. The default value is 8192, corresponding to 8192 keep-alive connections. This is a synonym for maxConnections.

    Duration of a poll call in microseconds. Lowering this value will slightly decrease latency of connections being kept alive in some cases, but will use more CPU as more poll calls are being made. The default value is 2000 (2ms).

    Amount of sockets that the poller responsible for sending static files asynchronously can hold at a given time. Extra connections will be closed right away without any data being sent (resulting in a zero length file on the client side). Note that in most cases, sendfile is a call that will return right away (being taken care of "synchronously" by the kernel), and the sendfile poller will not be used, so the amount of static files which can be sent concurrently is much larger than the specified amount. The default value is 1024.

    (int)The priority of the acceptor and poller threads. The default value is 5 (the value of the java.lang.Thread.NORM_PRIORITY constant). See the JavaDoc for the java.lang.Thread class for more details on what this priority means.

    (bool)Whether to allow comet servlets or not. Default value is true.

    (bool)Use this attribute to enable or disable sendfile capability. The default value is true.

    None at this time.

    This Connector supports all of the required features of the HTTP/1.1 protocol, as described in RFC 2616, including persistent connections, pipelining, expectations and chunked encoding. If the client (typically a browser) supports only HTTP/1.0, the Connector will gracefully fall back to supporting this protocol as well. No special configuration is required to enable this support. The Connector also supports HTTP/1.0 keep-alive.

    RFC 2616 requires that HTTP servers always begin their responses with the highest HTTP version that they claim to support. Therefore, this Connector will always return HTTP/1.1 at the beginning of its responses.

    The proxyName and proxyPort attributes can be used when Tomcat is run behind a proxy server. These attributes modify the values returned to web applications that call the request.getServerName() and request.getServerPort() methods, which are often used to construct absolute URLs for redirects. Without configuring these attributes, the values returned would reflect the server name and port on which the connection from the proxy server was received, rather than the server name and port to whom the client directed the original request.

    For more information, see the Proxy Support HOW-TO.

    You can enable SSL support for a particular instance of this Connector by setting the SSLEnabled attribute to true.

    You will also need to set the scheme and secure attributes to the values https and true respectively, to pass correct information to the servlets.

    The BIO and NIO connectors use the JSSE SSL whereas the APR/native connector uses OpenSSL. Therefore, in addition to using different attributes to configure SSL, the APR/native connector also requires keys and certificates to be provided in a different format.

    For more information, see the SSL Configuration HOW-TO.

    The BIO and NIO connectors use the following attributes to configure SSL:

    The certificate encoding algorithm to be used. This defaults to KeyManagerFactory.getDefaultAlgorithm() which returns SunX509 for Sun JVMs. IBM JVMs return IbmX509. For other vendors, consult the JVM documentation for the default value.

    Is unsafe legacy TLS renegotiation allowed which is likely to expose users to CVE-2009-3555, a man-in-the-middle vulnerability in the TLS protocol that allows an attacker to inject arbitrary data into the user's request. If not specified, a default of false is used. This attribute only has an effect if the JVM does not support RFC 5746 as indicated by the presence of the pseudo-ciphersuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV. This is available JRE/JDK 6 update 22 onwards. Where RFC 5746 is supported the renegotiation - including support for unsafe legacy renegotiation - is controlled by the JVM configuration.

    The comma separated list of encryption ciphers to support for HTTPS connections. If specified, only the ciphers that are listed and supported by the SSL implementation will be used. By default, the default ciphers for the JVM will be used. Note that this usually means that the weak export grade ciphers will be included in the list of available ciphers. The ciphers are specified using the JSSE cipher naming convention. The special value of ALL will enable all supported ciphers. This will include many that are not secure. ALL is intended for testing purposes only.

    Set to true if you want the SSL stack to require a valid certificate chain from the client before accepting a connection. Set to want if you want the SSL stack to request a client Certificate, but not fail if one isn't presented. A false value (which is the default) will not require a certificate chain unless the client requests a resource protected by a security constraint that uses CLIENT-CERT authentication.

    When client certificate information is presented in a form other than instances of java.security.cert.X509Certificate it needs to be converted before it can be used and this property controls which JSSE provider is used to perform the conversion. For example it is used with the AJP connectors, the HTTP APR connector and with the org.apache.catalina.valves.SSLValve. If not specified, the default provider will be used.

    The certificate revocation list to be used to verify client certificates. If not defined, client certificates will not be checked against a certificate revocation list.

    The alias used to for the server certificate in the keystore. If not specified the first key read in the keystore will be used.

    The password used to access the server certificate from the specified keystore file. The default value is "changeit".

    The pathname of the keystore file where you have stored the server certificate to be loaded. By default, the pathname is the file ".keystore" in the operating system home directory of the user that is running Tomcat. If your keystoreType doesn't need a file use "" (empty string) for this parameter.

    The password used to access the specified keystore file. The default value is the value of the keyPass attribute.

    The name of the keystore provider to be used for the server certificate. If not specified, the list of registered providers is traversed in preference order and the first provider that supports the keystoreType is used.

    The type of keystore file to be used for the server certificate. If not specified, the default value is "JKS".

    The number of SSL sessions to maintain in the session cache. Use 0 to specify an unlimited cache size. If not specified, a default of 0 is used.

    The time, in seconds, after the creation of an SSL session that it will timeout. Use 0 to specify an unlimited timeout. If not specified, a default of 86400 (24 hours) is used.

    The comma separated list of SSL protocols to support for HTTPS connections. If specified, only the protocols that are listed and supported by the SSL implementation will be enabled. If not specified, the JVM default is used. The permitted values may be obtained from the JVM documentation for the allowed values for SSLSocket.setEnabledProtocols() e.g. Oracle Java 6 and Oracle Java 7. Note: There is overlap between this attribute and sslProtocol.

    The class name of the SSL implementation to use. If not specified, the default of org.apache.tomcat.util.net.jsse.JSSEImplementation will be used which wraps JVM's default JSSE provider. Note that the JVM can be configured to use a different JSSE provider as the default.

    The the SSL protocol(s) to use (a single value may enable multiple protocols - see the JVM documentation for details). If not specified, the default is TLS. The permitted values may be obtained from the JVM documentation for the allowed values for algorithm when creating an SSLContext instance e.g. Oracle Java 6 and Oracle Java 7. Note: There is overlap between this attribute and sslEnabledProtocols.

    The name of a custom trust manager class to use to validate client certificates. The class must have a zero argument constructor and must also implement javax.net.ssl.X509TrustManager. If this attribute is set, the trust store attributes may be ignored.

    The maximum number of intermediate certificates that will be allowed when validating client certificates. If not specified, the default value of 5 will be used.

    The algorithm to use for truststore. If not specified, the default value returned by javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm() is used.

    The trust store file to use to validate client certificates. The default is the value of the javax.net.ssl.trustStore system property. If neither this attribute nor the default system property is set, no trust store will be configured.

    The password to access the trust store. The default is the value of the javax.net.ssl.trustStorePassword system property. If that property is null, no trust store password will be configured. If an invalid trust store password is specified, a warning will be logged and an attempt will be made to access the trust store without a password which will skip validation of the trust store contents.

    The name of the truststore provider to be used for the server certificate. The default is the value of the javax.net.ssl.trustStoreProvider system property. If that property is null, the value of keystoreProvider is used as the default. If neither this attribute, the default system property nor keystoreProvideris set, the list of registered providers is traversed in preference order and the first provider that supports the truststoreType is used.

    The type of key store used for the trust store. The default is the value of the javax.net.ssl.trustStoreType system property. If that property is null, the value of keystoreType is used as the default.

    When APR/native is enabled, the HTTPS connector will use a socket poller for keep-alive, increasing scalability of the server. It also uses OpenSSL, which may be more optimized than JSSE depending on the processor being used, and can be complemented with many commercial accelerator components. Unlike the HTTP connector, the HTTPS connector cannot use sendfile to optimize static file processing.

    The HTTPS APR/native connector has the same attributes than the HTTP APR/native connector, but adds OpenSSL specific ones. For the full details on using OpenSSL, please refer to OpenSSL documentations and the many books available for it (see the Official OpenSSL website). The SSL specific attributes for the APR/native connector are:

    See the mod_ssl documentation.

    See the mod_ssl documentation.

    See the mod_ssl documentation.

    See the mod_ssl documentation.

    See the mod_ssl documentation.

    Name of the file that contains the concatenated certificates for the trusted certificate authorities. The format is PEM-encoded.

    Name of the directory that contains the certificates for the trusted certificate authorities. The format is PEM-encoded.

    Name of the file that contains the concatenated certificate revocation lists for the certificate authorities. The format is PEM-encoded.

    Name of the directory that contains the certificate revocation lists for the certificate authorities. The format is PEM-encoded.

    Name of the file that contains concatenated certifcates for the certificate authorities which form the certifcate chain for the server certificate. The format is PEM-encoded.

    Name of the file that contains the server certificate. The format is PEM-encoded.

    Name of the file that contains the server private key. The format is PEM-encoded. The default value is the value of "SSLCertificateFile" and in this case both certificate and private key have to be in this file (NOT RECOMMENDED).

    Ciphers which may be used for communicating with clients. The default is "ALL", with other acceptable values being a list of ciphers, with ":" used as the delimiter (see OpenSSL documentation for the list of ciphers supported).

    Disables compression if set to true and OpenSSL supports disabling compression. Default is false which inherits the default compression setting in OpenSSL.

    Set to true to enforce the server's cipher order (from the SSLCipherSuite setting) instead of allowing the client to choose the cipher (which is the default).

    Pass phrase for the encrypted private key. If "SSLPassword" is not provided, the callback function should prompt for the pass phrase.

    Protocol which may be used for communicating with clients. The default value is all, which is equivalent to SSLv3+TLSv1 with other acceptable values being SSLv2, SSLv3, TLSv1 and any combination of the three protocols concatenated with a plus sign. Note that the protocol SSLv2 is inherently unsafe.

    Ask client for certificate. The default is "none", meaning the client will not have the opportunity to submit a certificate. Other acceptable values include "optional", "require" and "optionalNoCA".

    Maximum verification depth for client certificates. The default is "10".

    Below is a small chart that shows how the connectors differentiate.

    Java Blocking Connector Java Non Blocking Connector APR/native Connector BIO NIO APR Classname Http11Protocol Http11NioProtocol Http11AprProtocol Tomcat Version 3.x onwards 6.x onwards 5.5.x onwards Support Polling NO YES YES Polling Size N/A maxConnections maxConnections Read HTTP Request Blocking Non Blocking Blocking Read HTTP Body Blocking Sim Blocking Blocking Write HTTP Response Blocking Sim Blocking Blocking Wait for next Request Blocking Non Blocking Non Blocking SSL Support Java SSL Java SSL OpenSSL SSL Handshake Blocking Non blocking Blocking Max Connections maxConnections maxConnections maxConnections
    tomcat7-7.0.52/webapps/docs/config/globalresources.xml0000644000175100017510000002465712271304167022737 0ustar locutuslocutus ]> &project; Remy Maucherat Yoav Shapira The GlobalNamingResources Component

    The GlobalNamingResources element defines the global JNDI resources for the Server.

    These resources are listed in the server's global JNDI resource context. This context is distinct from the per-web-application JNDI contexts described in the JNDI Resources HOW-TO. The resources defined in this element are not visible in the per-web-application contexts unless you explicitly link them with <ResourceLink> elements.

    You can configure named values that will be made visible to all web applications as environment entry resources by nesting <Environment> entries inside this element. For example, you can create an environment entry like this:

    <GlobalNamingResources ...> ... <Environment name="maxExemptions" value="10" type="java.lang.Integer" override="false"/> ... </GlobalNamingResources>

    This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):

    <env-entry> <env-entry-name>maxExemptions</env-entry-name> <env-entry-value>10</env-entry-value> <env-entry-type>java.lang.Integer</env-entry-type> </env-entry>

    but does not require modification of the deployment descriptor to customize this value.

    The valid attributes for an <Environment> element are as follows:

    Optional, human-readable description of this environment entry.

    The name of the environment entry to be created, relative to the java:comp/env context.

    Set this to false if you do not want an <env-entry> for the same environment entry name, found in the web application deployment descriptor, to override the value specified here. By default, overrides are allowed.

    The fully qualified Java class name expected by the web application for this environment entry. Must be a legal value for <env-entry-type> in the web application deployment descriptor.

    The parameter value that will be presented to the application when requested from the JNDI context. This value must be convertable to the Java type defined by the type attribute.

    You can declare the characteristics of resources to be returned for JNDI lookups of <resource-ref> and <resource-env-ref> elements in the web application deployment descriptor by defining them in this element and then linking them with <ResourceLink> elements in the <Context> element. You MUST also define any other needed parameters using attributes on the Resource element, to configure the object factory to be used (if not known to Tomcat already), and the properties used to configure that object factory.

    For example, you can create a resource definition like this:

    <GlobalNamingResources ...> ... <Resource name="jdbc/EmployeeDB" auth="Container" type="javax.sql.DataSource" description="Employees Database for HR Applications"/> ... </GlobalNamingResources>

    This is equivalent to the inclusion of the following element in the web application deployment descriptor (/WEB-INF/web.xml):

    <resource-ref> <description>Employees Database for HR Applications</description> <res-ref-name>jdbc/EmployeeDB</res-ref-name> <res-ref-type>javax.sql.DataSource</res-ref-type> <res-auth>Container</res-auth> </resource-ref>

    but does not require modification of the deployment descriptor to customize this value.

    The valid attributes for a <Resource> element are as follows:

    Specify whether the web Application code signs on to the corresponding resource manager programmatically, or whether the Container will sign on to the resource manager on behalf of the application. The value of this attribute must be Application or Container. This attribute is required if the web application will use a <resource-ref> element in the web application deployment descriptor, but is optional if the application uses a <resource-env-ref> instead.

    Name of the zero-argument method to call on a singleton resource when it is no longer required. This is intended to speed up clean-up of resources that would otherwise happen as part of garbage collection. This attribute is ignored if the singleton attribute is false. If not specificed, no default is defined and no close method will be called.

    For Apache Commons DBCP and Apache Tomcat JDBC connection pools you can use closeMethod="close".

    Optional, human-readable description of this resource.

    The name of the resource to be created, relative to the java:comp/env context.

    Specify whether connections obtained through this resource manager can be shared. The value of this attribute must be Shareable or Unshareable. By default, connections are assumed to be shareable.

    Specify whether this resource definition is for a singleton resource, i.e. one where there is only a single instance of the resource. If this attribute is true, multiple JNDI lookups for this resource will return the same object. If this attribute is false, multiple JNDI lookups for this resource will return different objects. This attribute must be true for javax.sql.DataSource resources to enable JMX registration of the DataSource. The value of this attribute must be true or false. By default, this attribute is true.

    The fully qualified Java class name expected by the web application when it performs a lookup for this resource.

    Use <ResourceLink> elements to link resources from the global context into per-web-application contexts. Here is an example of making a custom factory available to an application, based on the example definition in the JNDI Resource HOW-TO:

    ]]>

    You can declare the characteristics of the UserTransaction to be returned for JNDI lookup for java:comp/UserTransaction. You MUST define an object factory class to instantiate this object as well as the needed resource parameters as attributes of the Transaction element, and the properties used to configure that object factory.

    The valid attributes for the <Transaction> element are as follows:

    The class name for the JNDI object factory.

    tomcat7-7.0.52/webapps/docs/config/listeners.xml0000644000175100017510000005430512273753636021560 0ustar locutuslocutus ]> &project; The LifeCycle Listener Component

    A Listener element defines a component that performs actions when specific events occur, usually Tomcat starting or Tomcat stopping.

    Listeners may be nested inside a Server, Engine, Host or Context. Some Listeners are only intended to be nested inside specific elements. These constraints are noted in the documentation below.

    All implementations of Listener support the following attributes:

    Java class name of the implementation to use. This class must implement the org.apache.catalina.LifecycleListener interface.

    No element may be nested inside a Listener.

    Unlike most Catalina components, there are several standard Listener implementations available. As a result, the className attribute MUST be used to select the implementation you wish to use.

    The APR Lifecycle Listener checks for the presence of the APR/native library and loads the library if it is present. For more information see the APR/native guide.

    This listener must only be nested within Server elements.

    The following additional attributes are supported by the APR Lifecycle Listener:

    Name of the SSLEngine to use. off: do not use SSL, on: use SSL but no specific ENGINE.

    The default value is on. This initializes the native SSL engine, which must be enabled in the APR/native connector by the use of the SSLEnabled attribute.

    See the Official OpenSSL website for more details on supported SSL hardware engines and manufacturers.

    Entropy source used to seed the SSLEngine's PRNG. The default value is builtin. On development systems, you may want to set this to /dev/urandom to allow quicker start times.

    Set to on to instruct OpenSSL to go into FIPS mode. FIPS mode requires you to have a FIPS-capable OpenSSL library which you must build yourself. FIPS mode also requires Tomcat native library version 1.1.23 or later, which must be built against the FIPS-compatible OpenSSL library. If this attribute is "on", SSLEngine must be enabled as well. The default value is off.

    The Jasper Listener initializes the Jasper 2 JSP engine before any web applications that may use it are loaded. For more information on the Jasper 2 JSP engine see the Jasper How To.

    This listener must only be nested within Server elements.

    No additional attributes are supported by the Jasper Listener .

    The Global Resources Lifecycle Listener initializes the Global JNDI resources defined in server.xml as part of the Global Resources element. Without this listener, none of the Global Resources will be available.

    This listener must only be nested within Server elements.

    No additional attributes are supported by the Global Resources Lifecycle Listener.

    The JRE Memory Leak Prevention Listener provides work-arounds for known places where the Java Runtime environment uses the context class loader to load a singleton as this will cause a memory leak if a web application class loader happens to be the context class loader at the time. The work-around is to initialise these singletons when this listener starts as Tomcat's common class loader is the context class loader at that time. It also provides work-arounds for known issues that can result in locked JAR files.

    This listener must only be nested within Server elements.

    The following additional attributes are supported by the JRE Memory Leak Prevention Listener:

    Enables protection so that calls to sun.awt.AppContext.getAppContext() triggered by a web application do not result in a memory leak. Note that a call to this method will be triggered as part of the web application stop process when running on Java 6 and earlier. It is therefore strongly recommended that this protection is enabled when running on Java 6 and earlier. The default is true for Java 6 and earlier versions. The default is false for Java 7 and later versions.

    Enables protection so that calls to java.awt.Toolkit.getDefaultToolkit() triggered by a web application do not result in a memory leak. Defaults to false because an AWT thread is launched.

    List of comma-separated fully qualified class names to load and initialize during the startup of this Listener. This allows to pre-load classes that are known to provoke classloader leaks if they are loaded during a request processing. Non-JRE classes may be referenced, like oracle.jdbc.driver.OracleTimeoutThreadPerVM. The default value is empty, but specific JRE classes are loaded by other leak protection features managed by other attributes of this Listener.

    The first use of java.sql.DriverManager will trigger the loading of JDBC Driver in the the current class loader. The web application level memory leak protection can take care of this in most cases but triggering the loading here has fewer side-effects. The default is true.

    Enables protection so that calls to sun.misc.GC.requestLatency(long) triggered by a web application do not result in a memory leak. Use of RMI is likely to trigger a call to this method. A side effect of enabling this protection is the creation of a thread named "GC Daemon". The protection uses reflection to access internal Sun classes and may generate errors on startup on non-Sun JVMs. The default is true.

    Enables protection so that loading the sun.java2d.Disposer class by a web application does not result in a memory leak. Defaults to false because a thread is launched.

    Enables protection so that the PoolCleaner thread started by com.sun.jndi.ldap.LdapPoolManager does not result in a memory leak. The thread is started the first time the LdapPoolManager class is used if the system property com.sun.jndi.ldap.connect.pool.timeout is set to a value greater than 0. Without this protection, if a web application uses this class the PoolCleaner thread will be configured with the thread's context class loader set to the web application class loader which in turn will trigger a memory leak on reload. Defaults to true.

    Enables protection so that usage of the javax.security.auth.login.Configuration class by a web application does not provoke a memory leak. The first access of this class will trigger the initializer that will retain a static reference to the context class loader. The protection loads the class with the system class loader to ensure that the static initializer is not triggered by a web application. Defaults to true.

    Enables protection so that usage of the deprecated javax.security.auth.Policy class by a web application does not result in a memory leak. The first access of this class will trigger the static initializer that will retain a static reference to the context class loader. The protection calls the getPolicy() method of this class to ensure that the static initializer is not triggered by a web application. Defaults to true.

    Enables protection so that any token poller thread initialized by sun.security.pkcs11.SunPKCS11.initToken() does not result in a memory leak. The thread is started depending on various conditions as part of the initialization of the Java Cryptography Architecture. Without the protection this can happen during Webapp deployment when the MessageDigest for generating session IDs is initialized. As a result the thread has the Webapp class loader as its thread context class loader. Enabling the protection initializes JCA early during Tomcat startup. Defaults to true.

    Enables protection so that reading resources from JAR files using java.net.URLConnections does not result in the JAR file being locked. Note that enabling this protection disables caching by default for all resources obtained via java.net.URLConnections. Caching may be re-enabled on a case by case basis as required. Defaults to true.

    Enables protection so that parsing XML files within a web application does not result in a memory leak. Note that memory profilers may not display the GC root associated with this leak making it particularly hard to diagnose. Defaults to true.

    The Security Lifecycle Listener performs a number of security checks when Tomcat starts and prevents Tomcat from starting if they fail. The listener is not enabled by default. To enabled it uncomment the listener in $CATALINA_BASE/conf/server.xml. If the operating system supports umask then the line in $CATALINA_HOME/bin/catalina.sh that obtains the umask also needs to be uncommented.

    This listener must only be nested within Server elements.

    The following additional attributes are supported by the Security Lifecycle Listener:

    A comma separated list of OS users that must not be used to start Tomcat. If not specified, the default value of root is used. To disable this check, set the attribute to the empty string. Usernames are checked in a case-insensitive manner.

    The least restrictive umask that must be configured before Tomcat will start. If not specified, the default value of 0007 is used. To disable this check, set the attribute to the empty string. The check is not performed on Windows platforms.

    The ThreadLocal Leak Prevention Listener triggers the renewal of threads in Executor pools when a Context is being stopped to avoid thread-local related memory leaks. Active threads will be renewed one by one when they come back to the pool after executing their task.

    This listener must only be nested within Server elements.

    No additional attributes are supported by the ThreadLocal Leak Prevention Listener.

    The UserConfig provides feature of User Web Applications. User Web Applications map a request URI starting with a tilde character ("~") and a username to a directory (commonly named public_html) in that user's home directory on the server.

    See the User Web Applications special feature on the Host element for more information.

    The following additional attributes are supported by the UserConfig:

    The directory name to be searched for within each user home directory. The default is public_html.

    The class name of the user database class. There are currently two user database, the org.apache.catalina.startup.PasswdUserDatabase is used on a Unix system that uses the /etc/passwd file to identify valid users. The org.apache.catalina.startup.HomesUserDatabase is used on a server where /etc/passwd is not in use. HomesUserDatabase deploy all directories found in a specified base directory.

    The base directory containing user home directories.This is effective only when org.apache.catalina.startup.HomesUserDatabase is used.

    A regular expression defining user who deployment is allowed. If this attribute is specified, the user to deploy must match for this pattern. If this attribute is not specified, all users will be deployed unless the user matches a deny pattern.

    A regular expression defining user who deployment is denied. If this attribute is specified, the user to deploy must not match for this pattern. If this attribute is not specified, deployment of user will be governed by a allow attribute.

    This listener requires catalina-jmx-remote.jar to be placed in $CATALINA_HOME/lib. This jar may be found in the extras directory of the binary download area.

    The JMX Remote Lifecycle Listener fixes the ports used by the JMX/RMI Server making things much simpler if you need to connect jconsole or a similar tool to a remote Tomcat instance that is running behind a firewall. Only these ports are configured via the listener. The remainder of the configuration is via the standard system properties for configuring JMX. For further information on configuring JMX see Monitoring and Management Using JMX included with the Java SDK documentation.

    This listener must only be nested within a Server element.

    The following additional attributes are supported by the JMX Remote Lifecycle Listener:

    The port to be used by the JMX/RMI registry for the Platform MBeans. This replaces the use of the com.sun.management.jmxremote.port system property that should not be set when using this listener.

    The port to be used by the Platform JMX/RMI server.

    The address of the interface to be used by JMX/RMI server. This option is incompatible with setting the system property com.sun.management.jmxremote.ssl to true.

    Should any clients using these ports be forced to use local ports to connect to the the JMX/RMI server. This is useful when tunnelling connections over SSH or similar. Defaults to false.

    Using file-based Authentication and Authorisation

    If this listener was configured in server.xml as: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="10001" rmiServerPortPlatform="10002" /> with the following system properties set (e.g. in setenv.sh): -Dcom.sun.management.jmxremote.password.file=$CATALINA_BASE/conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=$CATALINA_BASE/conf/jmxremote.access -Dcom.sun.management.jmxremote.ssl=false $CATALINA_BASE/conf/jmxremote.password containing: admin letmein $CATALINA_BASE/conf/jmxremote.access containing: admin readwrite then opening ports 10001 (RMI Registry) and 10002 (JMX/RMI Server) in your firewall would enable jconsole to connect to a Tomcat instance running behind a firewall using a connection string of the form: service:jmx:rmi://<hostname>:10002/jndi/rmi://<hostname>:10001/jmxrmi with a user name of admin and a password of letmein.

    Using JAAS

    If we use the following system properties instead: -Dcom.sun.management.jmxremote.login.config=Tomcat -Djava.security.auth.login.config=$CATALINA_BASE/conf/login.config -Dcom.sun.management.jmxremote.access.file=$CATALINA_BASE/conf/jmxremote.access -Dcom.sun.management.jmxremote.ssl=false $CATALINA_BASE/conf/login.config containing your choice of JAAS LoginModule implementation, for example: Tomcat { /* should match to the com.sun.management.jmxremote.login.config property */ /* for illustration purposes only */ com.sun.security.auth.module.LdapLoginModule REQUIRED userProvider="ldap://ldap-svr/ou=people,dc=example,dc=com" userFilter="(&(uid={USERNAME})(objectClass=inetOrgPerson))" authzIdentity="admin" debug=true; }; $CATALINA_BASE/conf/jmxremote.access containing: admin readwrite then we would need to provide LDAP credentials instead.

    Note that the examples above do not use SSL. JMX access should be considered equivalent to administrative access and secured accordingly.

    tomcat7-7.0.52/webapps/docs/config/cluster-deployer.xml0000644000175100017510000001030612271304167023030 0ustar locutuslocutus ]> &project; Filip Hanik The Cluster Deployer object

    The Farm War Deployer can deploy and undeploy web applications on the other nodes in the cluster.

    Note: FarmWarDeployer can be configured at host level cluster only.

    The cluster deployer class, currently only one is available, org.apache.catalina.ha.deploy.FarmWarDeployer. Deployment directory. This is the pathname of a directory where deploy the web applications. You may specify an absolute pathname, or a pathname that is relative to the $CATALINA_BASE directory. In the current implementation, this attribute must be the same value as the Host's appBase. The temporaryDirectory to store binary data when downloading a war from the cluster. You may specify an absolute pathname, or a pathname that is relative to the $CATALINA_BASE directory. This is the pathname of a directory where watch for changes(add/modify/remove) of web applications. You may specify an absolute pathname, or a pathname that is relative to the $CATALINA_BASE directory. Note: if watchEnabled is false, this attribute will have no effect. Set to true if you want to watch for changes of web applications. Only when this attribute set to true, you can trigger a deploy/undeploy of web applications. The flag's value defaults to false. Frequency of the Farm watchDir check. Cluster wide deployment will be done once for the specified amount of backgrondProcess calls (ie, the lower the amount, the most often the checks will occur). The minimum value is 1, and the default value is 2. Note: if watchEnabled is false, this attribute will have no effect. The maximum valid time(in seconds) of FileMessageFactory. FileMessageFactory will be removed immediately after receiving the complete WAR file but when failing to receive a FileMessage which was sent dividing, FileMessageFactory will leak without being removed. FileMessageFactory that is leaking will be automatically removed after maxValidTime. If a negative value specified, FileMessageFactory will never be removed. If the attribute is not provided, a default of 300 seconds (5 minutes) is used.
    tomcat7-7.0.52/webapps/docs/config/cluster-listener.xml0000644000175100017510000000427312271304167023040 0ustar locutuslocutus ]> &project; Filip Hanik The ClusterListener object

    The org.apache.catalina.ha.ClusterListener base class lets you listen in on messages that are received by the Cluster component.

    When using the DeltaManager, the messages are received by the Cluster object and are propagated to the to the manager through this listener.

    Listens for session Id changes. This listener is only used if you are using mod_jk along with the jvmRoute attribute where the session Id can change. In the event of a change, the JvmRouteBinderValve will broadcast the session change and it will get picked up by this listener.

    tomcat7-7.0.52/webapps/docs/config/cluster-interceptor.xml0000644000175100017510000002756712271304167023564 0ustar locutuslocutus ]> &project; Filip Hanik The Channel Interceptor object

    Apache Tribes supports an interceptor architecture to intercept both messages and membership notifications. This architecture allows decoupling of logic and opens the way for some very kewl feature add ons.

    • org.apache.catalina.tribes.group.interceptors.TcpFailureDetector
    • org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor
    • org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor
    • org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor
    • org.apache.catalina.tribes.group.interceptors.NonBlockingCoordinator
    • org.apache.catalina.tribes.group.interceptors.OrderInterceptor
    • org.apache.catalina.tribes.group.interceptors.SimpleCoordinator
    • org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor
    • org.apache.catalina.tribes.group.interceptors.TwoPhaseCommitInterceptor
    • org.apache.catalina.tribes.group.interceptors.DomainFilterInterceptor
    • org.apache.catalina.tribes.group.interceptors.FragmentationInterceptor
    • org.apache.catalina.tribes.group.interceptors.GzipInterceptor
    • org.apache.catalina.tribes.group.interceptors.TcpPingInterceptor

    In addition to dynamic discovery, Apache Tribes also supports static membership, with membership verification. To achieve this add the org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor underneath the org.apache.catalina.tribes.group.interceptors.TcpFailureDetector interceptor. Inside the StaticMembershipInterceptor you can add the static members you wish to have. The TcpFailureDetector will do a health check on the static members,and also monitor them for crashes so they will have the same level of notification mechanism as the members that are automatically discovered. <Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor"> <Member className="org.apache.catalina.tribes.membership.StaticMember" port="5678" securePort="-1" host="tomcat01.mydomain.com" domain="staging-cluster" uniqueId="{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}"/> </Interceptor>

    Required, as there is no default If you want the interceptor to trigger on certain message depending on the message's option flag, you can setup the interceptors flag here. The default value is 0, meaning this interceptor will trigger on all messages. The logical cluster domain that this Interceptor accepts. Two different type of values are possible:
    1. Regular string values like "staging-domain" or "tomcat-cluster" will be converted into bytes using ISO-8859-1 encoding.
    2. byte array in string form, for example {216,123,12,3}
    Required, This dispatcher uses JDK 1.5 java.util.concurrent package The default and hard coded value is 8 (org.apache.catalina.tribes.Channel.SEND_OPTIONS_ASYNCHRONOUS). The dispatcher will trigger on this value only, as it is predefined by Tribes. The other attributes are inherited from its base class org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor. The maximum number of threads in this pool, default is 10. The number of threads to keep in the pool, default is 2. Maximum number of milliseconds of until Idle thread terminates. Default value is 5000(5 seconds). Required, Same implementation as MessageDispatch15Interceptor, but with JDK 1.4 compliance. The default and hard coded value is 8 (org.apache.catalina.tribes.Channel.SEND_OPTIONS_ASYNCHRONOUS). The dispatcher will trigger on this value only, as it is predefined by Tribes. What behavior should be executed when the dispatch queue is full. If true (default), then the message is is sent synchronously, if false an error is thrown. Size in bytes of the dispatch queue, the default value is 1024*1024*64 (64MB) sets the maximum queue size for the dispatch queue if the queue fills up, one can trigger the behavior, if alwaysSend is set to true, the message will be sent synchronously if the flag is false, an error is thrown Specifies the timeout, in milliseconds, to use when attempting a TCP connection to the suspect node. Default is 1000. If true is set, send a test message to the suspect node. Default is true. If true is set, read the response of the test message that sent. Default is false. Note: if performSendTest is false, this attribute will have no effect. Specifies the timeout, in milliseconds, to use when performing a read test to the suspicious node. Default is 5000. The maximum time(in seconds) for remove from removeSuspects. Member of removeSuspects will be automatically removed after removeSuspectsTimeout. If a negative value specified, the removeSuspects members never be removed until disappeared really. If the attribute is not provided, a default of 300 milliseconds (5 minutes) is used. If useThread == true, defines the interval of sending a ping message. default is 1000 ms. Flag of whether to start a thread for sending a ping message. If set to true, this interceptor will start a local thread for sending a ping message. if set to false, channel heartbeat will send a ping message. default is false. Defines the interval in number of messages when we are to report the throughput statistics. The report is logged to the org.apache.juli.logging.LogFactory.getLog(ThroughputInterceptor.class) logger under the INFO level. Default value is to report every 10000 messages. Only one implementation available:org.apache.catalina.tribes.membership.StaticMember The port that this static member listens to for cluster messages The secure port this static member listens to for encrypted cluster messages default value is -1, this value means the member is not listening on a secure port The host (or network interface) that this static member listens for cluster messages. Three different type of values are possible:
    1. IP address in the form of "216.123.1.23"
    2. Hostnames like "tomcat01.mydomain.com" or "tomcat01" as long as they resolve correctly
    3. byte array in string form, for example {216,123,12,3}
    The logical cluster domain for this this static member listens for cluster messages. Two different type of values are possible:
    1. Regular string values like "staging-domain" or "tomcat-cluster" will be converted into bytes using ISO-8859-1 encoding. 2. byte array in string form, for example {216,123,12,3}
    A universally uniqueId for this static member. The values must be 16 bytes in the following form:
    1. byte array in string form, for example {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
    tomcat7-7.0.52/webapps/docs/config/project.xml0000644000175100017510000000720212271304167021175 0ustar locutuslocutus Apache Tomcat 7 Configuration Reference The Apache Tomcat Servlet/JSP Container tomcat7-7.0.52/webapps/docs/config/valve.xml0000644000175100017510000020060612271304167020647 0ustar locutuslocutus ]> &project; Craig R. McClanahan The Valve Component

    A Valve element represents a component that will be inserted into the request processing pipeline for the associated Catalina container (Engine, Host, or Context). Individual Valves have distinct processing capabilities, and are described individually below.

    The description below uses the variable name $CATALINA_BASE to refer the base directory against which most relative paths are resolved. If you have not configured Tomcat for multiple instances by setting a CATALINA_BASE directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, the directory into which you have installed Tomcat.

    The Access Log Valve creates log files in the same format as those created by standard web servers. These logs can later be analyzed by standard log analysis tools to track page hit counts, user session activity, and so on. The files produces by this Valve are rolled over nightly at midnight. This Valve may be associated with any Catalina container (Context, Host, or Engine), and will record ALL requests processed by that container.

    Some requests may be handled by Tomcat before they are passed to a container. These include redirects from /foo to /foo/ and the rejection of invalid requests. Where Tomcat can identify the Context that would have handled the request, the request/response will be logged in the AccessLog(s) associated Context, Host and Engine. Where Tomcat cannot identify the Context that would have handled the request, e.g. in cases where the URL is invalid, Tomcat will look first in the Engine, then the default Host for the Engine and finally the ROOT (or default) Context for the default Host for an AccessLog implementation. Tomcat will use the first AccessLog implementation found to log those requests that are rejected before they are passed to a container.

    The output file will be placed in the directory given by the directory attribute. The name of the file is composed by concatenation of the configured prefix, timestamp and suffix. The format of the timestamp in the file name can be set using the fileDateFormat attribute. This timestamp will be omitted if the file rotation is switched off by setting rotatable to false.

    Warning: If multiple AccessLogValve instances are used, they should be configured to use different output files.

    If sendfile is used, the response bytes will be written asynchronously in a separate thread and the access log valve will not know how many bytes were actually written. In this case, the number of bytes that was passed to the sendfile thread for writing will be recorded in the access log valve.

    The Access Log Valve supports the following configuration attributes:

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.valves.AccessLogValve to use the default access log valve.

    Absolute or relative pathname of a directory in which log files created by this valve will be placed. If a relative path is specified, it is interpreted as relative to $CATALINA_BASE. If no directory attribute is specified, the default value is "logs" (relative to $CATALINA_BASE).

    The prefix added to the start of each log file's name. If not specified, the default value is "access_log.".

    The suffix added to the end of each log file's name. If not specified, the default value is "" (a zero-length string), meaning that no suffix will be added.

    Allows a customized timestamp in the access log file name. The file is rotated whenever the formatted timestamp changes. The default value is yyyy-MM-dd. If you wish to rotate every hour, then set this value to yyyy-MM-dd.HH. The date format will always be localized using the locale en_US.

    Flag to determine if log rotation should occur. If set to false, then this file is never rotated and fileDateFormat is ignored. Default value: true

    By default for a rotatable log the active access log file name will contain the current timestamp in fileDateFormat. During rotation the file is closed and a new file with the next timestamp in the name is created and used. When setting renameOnRotate to true, the timestamp is no longer part of the active log file name. Only during rotation the file is closed and then renamed to include the timestamp. This is similar to the behavior of most log frameworks when doing time based rotation. Default value: false

    A formatting layout identifying the various information fields from the request and response to be logged, or the word common or combined to select a standard format. See below for more information on configuring this attribute.

    Character set used to write the log file. An empty string means to use the system default character set. Default value: use the system default character set.

    The locale used to format timestamps in the access log lines. Any timestamps configured using an explicit SimpleDateFormat pattern (%{xxx}t) are formatted in this locale. By default the default locale of the Java process is used. Switching the locale after the AccessLogValve is initialized is not supported. Any timestamps using the common log format (CLF) are always formatted in the locale en_US.

    Set to true to check for the existence of request attributes (typically set by the RemoteIpValve and similar) that should be used to override the values returned by the request for remote address, remote host, server port and protocol. If the attributes are not set, or this attribute is set to false then the values from the request will be used. If not set, the default value of false will be used.

    Turns on conditional logging. If set, requests will be logged only if ServletRequest.getAttribute() is not null. For example, if this value is set to important, then a particular request will only be logged if ServletRequest.getAttribute("important") != null. The use of Filters is an easy way to set/unset the attribute in the ServletRequest on many different requests.

    Turns on conditional logging. If set, requests will be logged only if ServletRequest.getAttribute() is null. For example, if this value is set to junk, then a particular request will only be logged if ServletRequest.getAttribute("junk") == null. The use of Filters is an easy way to set/unset the attribute in the ServletRequest on many different requests.

    The same as conditionUnless. This attribute is provided for backwards compatibility.

    Flag to determine if logging will be buffered. If set to false, then access logging will be written after each request. Default value: true

    This attribute is no longer supported. Use the connector attribute enableLookups instead.

    If you have enableLookups on the connector set to true and want to ignore it, use %a instead of %h in the value of pattern.

    Values for the pattern attribute are made up of literal text strings, combined with pattern identifiers prefixed by the "%" character to cause replacement by the corresponding variable value from the current request and response. The following pattern codes are supported:

    • %a - Remote IP address
    • %A - Local IP address
    • %b - Bytes sent, excluding HTTP headers, or '-' if zero
    • %B - Bytes sent, excluding HTTP headers
    • %h - Remote host name (or IP address if enableLookups for the connector is false)
    • %H - Request protocol
    • %l - Remote logical username from identd (always returns '-')
    • %m - Request method (GET, POST, etc.)
    • %p - Local port on which this request was received
    • %q - Query string (prepended with a '?' if it exists)
    • %r - First line of the request (method and request URI)
    • %s - HTTP status code of the response
    • %S - User session ID
    • %t - Date and time, in Common Log Format
    • %u - Remote user that was authenticated (if any), else '-'
    • %U - Requested URL path
    • %v - Local server name
    • %D - Time taken to process the request, in millis
    • %T - Time taken to process the request, in seconds
    • %F - Time taken to commit the response, in millis
    • %I - Current request thread name (can compare later with stacktraces)

    There is also support to write information incoming or outgoing headers, cookies, session or request attributes and special timestamp formats. It is modeled after the Apache HTTP Server log configuration syntax:

    • %{xxx}i for incoming headers
    • %{xxx}o for outgoing response headers
    • %{xxx}c for a specific cookie
    • %{xxx}r xxx is an attribute in the ServletRequest
    • %{xxx}s xxx is an attribute in the HttpSession
    • %{xxx}t xxx is an enhanced SimpleDateFormat pattern

    All formats supported by SimpleDateFormat are allowed in %{xxx}t. In addition the following extensions have been added:

    • sec - number of seconds since the epoch
    • msec - number of milliseconds since the epoch
    • msec_frac - millisecond fraction

    These formats can not be mixed with SimpleDateFormat formats in the same format token.

    Furthermore one can define whether to log the timestamp for the request start time or the response finish time:

    • begin or prefix begin: chooses the request start time
    • end or prefix end: chooses the response finish time

    By adding multiple %{xxx}t tokens to the pattern, one can also log both timestamps.

    The shorthand pattern pattern="common" corresponds to the Common Log Format defined by '%h %l %u %t "%r" %s %b'.

    The shorthand pattern pattern="combined" appends the values of the Referer and User-Agent headers, each in double quotes, to the common pattern.

    The Extended Access Log Valve is a variant of the Access Log Valve. It is not a real extension of the standard Access Log valve, instead it supports the so-called Extended Log File Format defined by the W3C. The main difference to the standard AccessLogValve are the supported pattern values.

    The Extended Access Log Valve supports all configuration attributes of the standard Access Log Valve. Only the values used for className and pattern differ.

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.valves.ExtendedAccessLogValve to use the extended access log valve.

    A formatting layout identifying the various information fields from the request and response to be logged. See below for more information on configuring this attribute.

    Values for the pattern attribute are made up of format tokens. Some of the tokens need an additional prefix. Possible prefixes are c for "client", s for "server", cs for "client to server", sc for "server to client" or x for "application specific". Furthermore some tokens are completed by an additional selector. See the W3C specification for more information about the format.

    The following format tokens are supported:

    • bytes - Bytes sent, excluding HTTP headers, or '-' if zero
    • c-dns - Remote host name (or IP address if enableLookups for the connector is false)
    • c-ip - Remote IP address
    • cs-method - Request method (GET, POST, etc.)
    • cs-uri - Request URI
    • cs-uri-query - Query string (prepended with a '?' if it exists)
    • cs-uri-stem - Requested URL path
    • date - The date in yyyy-mm-dd format for GMT
    • s-dns - Local host name
    • s-ip - Local IP address
    • sc-status - HTTP status code of the response
    • time - Time the request was served in HH:mm:ss format for GMT
    • time-taken - Time (in seconds as floating point) taken to serve the request
    • x-threadname - Current request thread name (can compare later with stacktraces)

    For any of the x-H(XXX) the following method will be called from the HttpServletRequest object:

    • x-H(authType): getAuthType
    • x-H(characterEncoding): getCharacterEncoding
    • x-H(contentLength): getContentLength
    • x-H(locale): getLocale
    • x-H(protocol): getProtocol
    • x-H(remoteUser): getRemoteUser
    • x-H(requestedSessionId): getRequestedSessionId
    • x-H(requestedSessionIdFromCookie): isRequestedSessionIdFromCookie
    • x-H(requestedSessionIdValid): isRequestedSessionIdValid
    • x-H(scheme): getScheme
    • x-H(secure): isSecure

    There is also support to write information about headers cookies, context, request or session attributes and request parameters.

    • cs(XXX) for incoming request headers with name XXX
    • sc(XXX) for outgoing response headers with name XXX
    • x-A(XXX) for the servlet context attribute with name XXX
    • x-C(XXX) for the first cookie with name XXX
    • x-O(XXX) for a concatenation of all outgoing response headers with name XXX
    • x-P(XXX) for the URL encoded (using UTF-8) request parameter with name XXX
    • x-R(XXX) for the request attribute with name XXX
    • x-S(XXX) for the session attribute with name XXX

    The Remote Address Filter allows you to compare the IP address of the client that submitted this request against one or more regular expressions, and either allow the request to continue or refuse to process the request from this client. A Remote Address Filter can be associated with any Catalina container (Engine, Host, or Context), and must accept any request presented to this container for processing before it will be passed on.

    The syntax for regular expressions is different than that for 'standard' wildcard matching. Tomcat uses the java.util.regex package. Please consult the Java documentation for details of the expressions supported.

    Note: There is a caveat when using this valve with IPv6 addresses. Format of the IP address that this valve is processing depends on the API that was used to obtain it. If the address was obtained from Java socket using Inet6Address class, its format will be x:x:x:x:x:x:x:x. That is, the IP address for localhost will be 0:0:0:0:0:0:0:1 instead of the more widely used ::1. Consult your access logs for the actual value.

    See also: Remote Host Filter, Remote IP Valve.

    The Remote Address Filter supports the following configuration attributes:

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.valves.RemoteAddrValve.

    A regular expression (using java.util.regex) that the remote client's IP address is compared to. If this attribute is specified, the remote address MUST match for this request to be accepted. If this attribute is not specified, all requests will be accepted UNLESS the remote address matches a deny pattern.

    A regular expression (using java.util.regex) that the remote client's IP address is compared to. If this attribute is specified, the remote address MUST NOT match for this request to be accepted. If this attribute is not specified, request acceptance is governed solely by the accept attribute.

    HTTP response status code that is used when rejecting denied request. The default value is 403. For example, it can be set to the value 404.

    To allow access only for the clients connecting from localhost:

        <Valve className="org.apache.catalina.valves.RemoteAddrValve"
           allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1"/>
    

    The Remote Host Filter allows you to compare the hostname of the client that submitted this request against one or more regular expressions, and either allow the request to continue or refuse to process the request from this client. A Remote Host Filter can be associated with any Catalina container (Engine, Host, or Context), and must accept any request presented to this container for processing before it will be passed on.

    The syntax for regular expressions is different than that for 'standard' wildcard matching. Tomcat uses the java.util.regex package. Please consult the Java documentation for details of the expressions supported.

    Note: This filter processes the value returned by method ServletRequest.getRemoteHost(). To allow the method to return proper host names, you have to enable "DNS lookups" feature on a Connector.

    See also: Remote Address Filter, HTTP Connector configuration.

    The Remote Host Filter supports the following configuration attributes:

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.valves.RemoteHostValve.

    A regular expression (using java.util.regex) that the remote client's hostname is compared to. If this attribute is specified, the remote hostname MUST match for this request to be accepted. If this attribute is not specified, all requests will be accepted UNLESS the remote hostname matches a deny pattern.

    A regular expression (using java.util.regex) that the remote client's hostname is compared to. If this attribute is specified, the remote hostname MUST NOT match for this request to be accepted. If this attribute is not specified, request acceptance is governed solely by the accept attribute.

    HTTP response status code that is used when rejecting denied request. The default value is 403. For example, it can be set to the value 404.

    The Single Sign On Valve is utilized when you wish to give users the ability to sign on to any one of the web applications associated with your virtual host, and then have their identity recognized by all other web applications on the same virtual host.

    See the Single Sign On special feature on the Host element for more information.

    The Single Sign On Valve supports the following configuration attributes:

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.authenticator.SingleSignOn.

    Default false. Flag to determine whether each request needs to be reauthenticated to the security Realm. If "true", this Valve uses cached security credentials (username and password) to reauthenticate to the Realm each request associated with an SSO session. If "false", the Valve can itself authenticate requests based on the presence of a valid SSO cookie, without rechecking with the Realm.

    Sets the host domain to be used for sso cookies.

    The Basic Authenticator Valve is automatically added to any Context that is configured to use BASIC authentication.

    If any non-default settings are required, the valve may be configured within Context element with the required values.

    The Basic Authenticator Valve supports the following configuration attributes:

    Should a session always be used once a user is authenticated? This may offer some performance benefits since the session can then be used to cache the authenticated Principal, hence removing the need to authenticate the user via the Realm on every request. This may be of help for combinations such as BASIC authentication used with the JNDIRealm or DataSourceRealms. However there will also be the performance cost of creating and GC'ing the session. If not set, the default value of false will be used.

    Should we cache authenticated Principals if the request is part of an HTTP session? If not specified, the default value of true will be used.

    Controls if the session ID is changed if a session exists at the point where users are authenticated. This is to prevent session fixation attacks. If not set, the default value of true will be used.

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.authenticator.BasicAuthenticator.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers but will also cause secured pages to be cached by proxies which will almost certainly be a security issue. securePagesWithPragma offers an alternative, secure, workaround for browser caching issues. If not set, the default value of true will be used.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers by using Cache-Control: private rather than the default of Pragma: No-cache and Cache-control: No-cache. If not set, the default value of false will be used.

    Name of the algorithm to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the default algorithm of SHA1PRNG will be used. If the default algorithm is not supported, the platform default will be used. To specify that the platform default should be used, do not set the secureRandomProvider attribute and set this attribute to the empty string.

    Name of the Java class that extends java.security.SecureRandom to use to generate SSO session IDs. If not specified, the default value is java.security.SecureRandom.

    Name of the provider to use to create the java.security.SecureRandom instances that generate SSO session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the platform default provider will be used.

    The Digest Authenticator Valve is automatically added to any Context that is configured to use DIGEST authentication.

    If any non-default settings are required, the valve may be configured within Context element with the required values.

    The Digest Authenticator Valve supports the following configuration attributes:

    Should a session always be used once a user is authenticated? This may offer some performance benefits since the session can then be used to cache the authenticated Principal, hence removing the need to authenticate the user via the Realm on every request. This may be of help for combinations such as BASIC authentication used with the JNDIRealm or DataSourceRealms. However there will also be the performance cost of creating and GC'ing the session. If not set, the default value of false will be used.

    Should we cache authenticated Principals if the request is part of an HTTP session? If not specified, the default value of false will be used.

    Controls if the session ID is changed if a session exists at the point where users are authenticated. This is to prevent session fixation attacks. If not set, the default value of true will be used.

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.authenticator.DigestAuthenticator.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers but will also cause secured pages to be cached by proxies which will almost certainly be a security issue. securePagesWithPragma offers an alternative, secure, workaround for browser caching issues. If not set, the default value of true will be used.

    The secret key used by digest authentication. If not set, a secure random value is generated. This should normally only be set when it is necessary to keep key values constant either across server restarts and/or across a cluster.

    To protect against replay attacks, the DIGEST authenticator tracks server nonce and nonce count values. This attribute controls the size of that cache. If not specified, the default value of 1000 is used.

    Client requests may be processed out of order which in turn means that the nonce count values may be processed out of order. To prevent authentication failures when nonce counts are presented out of order the authenticator tracks a window of nonce count values. This attribute controls how big that window is. If not specified, the default value of 100 is used.

    The time, in milliseconds, that a server generated nonce will be considered valid for use in authentication. If not specified, the default value of 300000 (5 minutes) will be used.

    The opaque server string used by digest authentication. If not set, a random value is generated. This should normally only be set when it is necessary to keep opaque values constant either across server restarts and/or across a cluster.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers by using Cache-Control: private rather than the default of Pragma: No-cache and Cache-control: No-cache. If not set, the default value of false will be used.

    Name of the algorithm to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the default algorithm of SHA1PRNG will be used. If the default algorithm is not supported, the platform default will be used. To specify that the platform default should be used, do not set the secureRandomProvider attribute and set this attribute to the empty string.

    Name of the Java class that extends java.security.SecureRandom to use to generate SSO session IDs. If not specified, the default value is java.security.SecureRandom.

    Name of the provider to use to create the java.security.SecureRandom instances that generate SSO session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the platform default provider will be used.

    Should the URI be validated as required by RFC2617? If not specified, the default value of true will be used. This should normally only be set when Tomcat is located behind a reverse proxy and the proxy is modifying the URI passed to Tomcat such that DIGEST authentication always fails.

    The Form Authenticator Valve is automatically added to any Context that is configured to use FORM authentication.

    If any non-default settings are required, the valve may be configured within Context element with the required values.

    The Form Authenticator Valve supports the following configuration attributes:

    Controls if the session ID is changed if a session exists at the point where users are authenticated. This is to prevent session fixation attacks. If not set, the default value of true will be used.

    Character encoding to use to read the username and password parameters from the request. If not set, the encoding of the request body will be used.

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.authenticator.FormAuthenticator.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers but will also cause secured pages to be cached by proxies which will almost certainly be a security issue. securePagesWithPragma offers an alternative, secure, workaround for browser caching issues. If not set, the default value of true will be used.

    Controls the behavior of the FORM authentication process if the process is misused, for example by directly requesting the login page or delaying logging in for so long that the session expires. If this attribute is set, rather than returning an error response code, Tomcat will redirect the user to the specified landing page if the login form is submitted with valid credentials. For the login to be processed, the landing page must be a protected resource (i.e. one that requires authentication). If the landing page does not require authentication then the user will not be logged in and will be prompted for their credentials again when they access a protected page.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers by using Cache-Control: private rather than the default of Pragma: No-cache and Cache-control: No-cache. If not set, the default value of false will be used.

    Name of the algorithm to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the default algorithm of SHA1PRNG will be used. If the default algorithm is not supported, the platform default will be used. To specify that the platform default should be used, do not set the secureRandomProvider attribute and set this attribute to the empty string.

    Name of the Java class that extends java.security.SecureRandom to use to generate SSO session IDs. If not specified, the default value is java.security.SecureRandom.

    Name of the provider to use to create the java.security.SecureRandom instances that generate SSO session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the platform default provider will be used.

    The SSL Authenticator Valve is automatically added to any Context that is configured to use SSL authentication.

    If any non-default settings are required, the valve may be configured within Context element with the required values.

    The SSL Authenticator Valve supports the following configuration attributes:

    Should we cache authenticated Principals if the request is part of an HTTP session? If not specified, the default value of true will be used.

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.authenticator.SSLAuthenticator.

    Controls if the session ID is changed if a session exists at the point where users are authenticated. This is to prevent session fixation attacks. If not set, the default value of true will be used.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers but will also cause secured pages to be cached by proxies which will almost certainly be a security issue. securePagesWithPragma offers an alternative, secure, workaround for browser caching issues. If not set, the default value of true will be used.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers by using Cache-Control: private rather than the default of Pragma: No-cache and Cache-control: No-cache. If not set, the default value of false will be used.

    Name of the algorithm to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the default algorithm of SHA1PRNG will be used. If the default algorithm is not supported, the platform default will be used. To specify that the platform default should be used, do not set the secureRandomProvider attribute and set this attribute to the empty string.

    Name of the Java class that extends java.security.SecureRandom to use to generate SSO session IDs. If not specified, the default value is java.security.SecureRandom.

    Name of the provider to use to create the java.security.SecureRandom instances that generate SSO session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the platform default provider will be used.

    The SPNEGO Authenticator Valve is automatically added to any Context that is configured to use SPNEGO authentication.

    If any non-default settings are required, the valve may be configured within Context element with the required values.

    The SPNEGO Authenticator Valve supports the following configuration attributes:

    Should a session always be used once a user is authenticated? This may offer some performance benefits since the session can then be used to cache the authenticated Principal, hence removing the need to authenticate the user on every request. This will also help with clients that assume that the server will cache the authenticated user. However there will also be the performance cost of creating and GC'ing the session. For an alternative solution see noKeepAliveUserAgents. If not set, the default value of false will be used.

    Should we cache authenticated Principals if the request is part of an HTTP session? If not specified, the default value of true will be used.

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.authenticator.SpnegoAuthenticator.

    Controls if the session ID is changed if a session exists at the point where users are authenticated. This is to prevent session fixation attacks. If not set, the default value of true will be used.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers but will also cause secured pages to be cached by proxies which will almost certainly be a security issue. securePagesWithPragma offers an alternative, secure, workaround for browser caching issues. If not set, the default value of true will be used.

    The name of the JAAS login configuration to be used to login as the service. If not specified, the default of com.sun.security.jgss.krb5.accept is used.

    Some clients (not most browsers) expect the server to cache the authenticated user information for a connection and do not resend the credentials with every request. Tomcat will not do this unless an HTTP session is available. A session will be availble if either the application creates one or if alwaysUseSession is enabled for this Authenticator.

    As an alternative to creating a session, this attribute may be used to define the user agents for which HTTP keep-alive is disabled. This means that a connection will only used for a single request and hence there is no ability to cache authenticated user information per connection. There will be a performance cost in disabling HTTP keep-alive.

    The attribute should be a regular expression that matches the entire user-agent string, e.g. .*Chrome.*. If not specified, no regular expression will be defined and no user agents will have HTTP keep-alive disabled.

    Controls the caching of pages that are protected by security constraints. Setting this to false may help work around caching issues in some browsers by using Cache-Control: private rather than the default of Pragma: No-cache and Cache-control: No-cache. If not set, the default value of false will be used.

    Name of the algorithm to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the default algorithm of SHA1PRNG will be used. If the default algorithm is not supported, the platform default will be used. To specify that the platform default should be used, do not set the secureRandomProvider attribute and set this attribute to the empty string.

    Name of the Java class that extends java.security.SecureRandom to use to generate SSO session IDs. If not specified, the default value is java.security.SecureRandom.

    Name of the provider to use to create the java.security.SecureRandom instances that generate SSO session IDs. If an invalid algorithm and/or provider is specified, the platform default provider and the default algorithm will be used. If not specified, the platform default provider will be used.

    Controls if the user' delegated credential will be stored in the user Principal. If available, the delegated credential will be available to applications (e.g. for onward authentication to external services) via the org.apache.catalina.realm.GSS_CREDENTIAL request attribute. If not set, the default value of true will be used.

    Tomcat port of mod_remoteip, this valve replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. "X-Forwarded-For").

    Another feature of this valve is to replace the apparent scheme (http/https), server port and request.secure with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").

    This Valve may be used at the Engine, Host or Context level as required. Normally, this Valve would be used at the Engine level.

    If used in conjunction with Remote Address/Host valves then this valve should be defined first to ensure that the correct client IP address is presented to the Remote Address/Host valves.

    Note: By default this valve has no effect on the values that are written into access log. The original values are restored when request processing leaves the valve and that always happens earlier than access logging. To pass the remote address, remote host, server port and protocol values set by this valve to the access log, they are put into request attributes. Publishing these values here is enabled by default, but AccessLogValve should be explicitly configured to use them. See documentation for requestAttributesEnabled attribute of AccessLogValve.

    The names of request attributes that are set by this valve and can be used by access logging are the following:

    • org.apache.catalina.AccessLog.RemoteAddr
    • org.apache.catalina.AccessLog.RemoteHost
    • org.apache.catalina.AccessLog.Protocol
    • org.apache.catalina.AccessLog.ServerPort
    • org.apache.tomcat.remoteAddr

    The Remote IP Valve supports the following configuration attributes:

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.valves.RemoteIpValve.

    Name of the HTTP Header read by this valve that holds the list of traversed IP addresses starting from the requesting client. If not specified, the default of x-forwarded-for is used.

    Regular expression (using java.util.regex) that a proxy's IP address must match to be considered an internal proxy. Internal proxies that appear in the remoteIpHeader will be trusted and will not appear in the proxiesHeader value. If not specified the default value of 10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3} will be used.

    Name of the HTTP header created by this valve to hold the list of proxies that have been processed in the incoming remoteIpHeader. If not specified, the default of x-forwarded-by is used.

    Set to true to set the request attributes used by AccessLog implementations to override the values returned by the request for remote address, remote host, server port and protocol. Request attributes are also used to enable the forwarded remote address to be displayed on the status page of the Manager web application. If not set, the default value of true will be used.

    Regular expression (using java.util.regex) that a proxy's IP address must match to be considered an trusted proxy. Trusted proxies that appear in the remoteIpHeader will be trusted and will appear in the proxiesHeader value. If not specified, no proxies will be trusted.

    Name of the HTTP Header read by this valve that holds the protocol used by the client to connect to the proxy. If not specified, the default of null is used.

    Name of the HTTP Header read by this valve that holds the port used by the client to connect to the proxy. If not specified, the default of null is used.

    Value of the protocolHeader to indicate that it is an HTTPS request. If not specified, the default of https is used.

    Value returned by ServletRequest.getServerPort() when the protocolHeader indicates http protocol and no portHeader is present. If not specified, the default of 80 is used.

    Value returned by ServletRequest.getServerPort() when the protocolHeader indicates https protocol and no portHeader is present. If not specified, the default of 443 is used.

    If true, the value returned by ServletRequest.getLocalPort() and ServletRequest.getServerPort() is modified by the this valve. If not specified, the default of false is used.

    Web crawlers can trigger the creation of many thousands of sessions as they crawl a site which may result in significant memory consumption. This Valve ensures that crawlers are associated with a single session - just like normal users - regardless of whether or not they provide a session token with their requests.

    This Valve may be used at the Engine, Host or Context level as required. Normally, this Valve would be used at the Engine level.

    If used in conjunction with Remote IP valve then the Remote IP valve should be defined before this valve to ensure that the correct client IP address is presented to this valve.

    The Crawler Session Manager Valve supports the following configuration attributes:

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.valves.CrawlerSessionManagerValve.

    Regular expression (using java.util.regex) that the user agent HTTP request header is matched against to determine if a request is from a web crawler. If not set, the default of .*[bB]ot.*|.*Yahoo! Slurp.*|.*Feedfetcher-Google.* is used.

    The minimum time in seconds that the Crawler Session Manager Valve should keep the mapping of client IP to session ID in memory without any activity from the client. The client IP / session cache will be periodically purged of mappings that have been inactive for longer than this interval. If not specified the default value of 60 will be used.

    This valve allows to detect requests that take a long time to process, which might indicate that the thread that is processing it is stuck.

    When such a request is detected, the current stack trace of its thread is written to Tomcat log with a WARN level.

    The IDs and names of the stuck threads are available through JMX in the stuckThreadIds and stuckThreadNames attributes. The IDs can be used with the standard Threading JVM MBean (java.lang:type=Threading) to retrieve other information about each stuck thread.

    The Stuck Thread Detection Valve supports the following configuration attributes:

    Java class name of the implementation to use. This MUST be set to org.apache.catalina.valves.StuckThreadDetectionValve.

    Minimum duration in seconds after which a thread is considered stuck. Default is 600 seconds. If set to 0, the detection is disabled.

    Note: since the detection is done in the background thread of the Container (Engine, Host or Context) declaring this Valve, the threshold should be higher than the backgroundProcessorDelay of this Container.

    tomcat7-7.0.52/webapps/docs/config/cluster-valve.xml0000644000175100017510000001150712271304167022326 0ustar locutuslocutus ]> &project; Filip Hanik The Cluster Valve object

    A cluster valve is no different from any other Tomcat Valve. The cluster valves are interceptors in the invocation chain for HTTP requests, and the clustering implementation uses these valves to make intelligent decision around data and when data should be replicated.

    A cluster valve must implement the org.apache.catalina.ha.ClusterValve interface. This is a simple interface that extends the org.apache.catalina.Valve interface.

    The ReplicationValve will notify the cluster at the end of a HTTP request so that the cluster can make a decision whether there is data to be replicated or not. Set value to org.apache.catalina.ha.tcp.ReplicationValve For known file extensions or urls, you can use this Valve to notify the cluster that the session has not been modified during this request and the cluster doesn't have to probe the session managers for changes. If the request matches this filter pattern, the cluster assumes there has been no session change. An example filter would look like filter=".*\.gif|.*\.js|.*\.jpeg|.*\.jpg|.*\.png|.*\.htm|.*\.html|.*\.css|.*\.txt" . The filter is a regular expression using java.util.regex. Boolean value, so to true, and the replication valve will insert a request attribute with the name defined by the primaryIndicatorName attribute. The value inserted into the request attribute is either Boolean.TRUE or Boolean.FALSE Default value is org.apache.catalina.ha.tcp.isPrimarySession The value defined here is the name of the request attribute that contains the boolean value if the session is primary on this server or not. Boolean value. Set to true if you want the valve to collect request statistics. Default value is false
    In case of a mod_jk failover, the JvmRouteBinderValve will replace the jvmWorker attribute in the session Id, to make future requests stick to this node. If you want failback capability, don't enable this valve, but if you want your failover to stick, and for mod_jk not to have to keep probing the node that went down, you use this valve. org.apache.catalina.ha.session.JvmRouteBinderValve Default value is true Runtime attribute to turn on and off turn over of the session's jvmRoute value. Old sessionid before failover is registered in request attributes with this attribute. Default attribute name is org.apache.catalina.ha.session.JvmRouteOrignalSessionID.
    tomcat7-7.0.52/webapps/docs/config/ajp.xml0000644000175100017510000010150612271304167020303 0ustar locutuslocutus ]> &project; Remy Maucherat Yoav Shapira Andrew R. Jaquith The AJP Connector

    The AJP Connector element represents a Connector component that communicates with a web connector via the AJP protocol. This is used for cases where you wish to invisibly integrate Tomcat into an existing (or new) Apache installation, and you want Apache to handle the static content contained in the web application, and/or utilize Apache's SSL processing.

    This connector supports load balancing when used in conjunction with the jvmRoute attribute of the Engine.

    The native connectors supported with this Tomcat release are:

    • JK 1.2.x with any of the supported servers. See the JK docs for details.
    • mod_proxy on Apache httpd 2.x (included by default in Apache HTTP Server 2.2), with AJP enabled: see the httpd docs for details.

    Other native connectors supporting AJP may work, but are no longer supported.

    All implementations of Connector support the following attributes:

    A boolean value which can be used to enable or disable the TRACE HTTP method. If not specified, this attribute is set to false.

    The default timeout for asynchronous requests in milliseconds. If not specified, this attribute is set to 10000 (10 seconds).

    Set to true if you want calls to request.getRemoteHost() to perform DNS lookups in order to return the actual host name of the remote client. Set to false to skip the DNS lookup and return the IP address in String form instead (thereby improving performance). By default, DNS lookups are disabled.

    The maximum number of headers in a request that are allowed by the container. A request that contains more headers than the specified limit will be rejected. A value of less than 0 means no limit. If not specified, a default of 100 is used.

    The maximum number of parameter and value pairs (GET plus POST) which will be automatically parsed by the container. Parameter and value pairs beyond this limit will be ignored. A value of less than 0 means no limit. If not specified, a default of 10000 is used. Note that FailedRequestFilter filter can be used to reject requests that hit the limit.

    The maximum size in bytes of the POST which will be handled by the container FORM URL parameter parsing. The limit can be disabled by setting this attribute to a value less than or equal to 0. If not specified, this attribute is set to 2097152 (2 megabytes).

    The maximum size in bytes of the POST which will be saved/buffered by the container during FORM or CLIENT-CERT authentication. For both types of authentication, the POST will be saved/buffered before the user is authenticated. For CLIENT-CERT authentication, the POST is buffered for the duration of the SSL handshake and the buffer emptied when the request is processed. For FORM authentication the POST is saved whilst the user is re-directed to the login form and is retained until the user successfully authenticates or the session associated with the authentication request expires. The limit can be disabled by setting this attribute to -1. Setting the attribute to zero will disable the saving of POST data during authentication. If not specified, this attribute is set to 4096 (4 kilobytes).

    A comma-separated list of HTTP methods for which request bodies will be parsed for request parameters identically to POST. This is useful in RESTful applications that want to support POST-style semantics for PUT requests. Note that any setting other than POST causes Tomcat to behave in a way that goes against the intent of the servlet specification. The HTTP method TRACE is specifically forbidden here in accordance with the HTTP specification. The default is POST

    The TCP port number on which this Connector will create a server socket and await incoming connections. Your operating system will allow only one server application to listen to a particular port number on a particular IP address. If the special value of 0 (zero) is used, then Tomcat will select a free port at random to use for this connector. This is typically only useful in embedded and testing applications.

    Sets the protocol to handle incoming traffic. To configure an AJP connector this must be specified. If no value for protocol is provided, an HTTP connector rather than an AJP connector will be configured.
    The standard protocol value for an AJP connector is AJP/1.3 which uses an auto-switching mechanism to select either a Java based connector or an APR/native based connector. If the PATH (Windows) or LD_LIBRARY_PATH (on most unix systems) environment variables contain the Tomcat native library, the native/APR connector will be used. If the native library cannot be found, the Java based connector will be used.
    To use an explicit protocol rather than rely on the auto-switching mechanism described above, the following values may be used:
    org.apache.coyote.ajp.AjpProtocol - blocking Java connector
    org.apache.coyote.ajp.AjpNioProtocol - non blocking Java connector.
    org.apache.coyote.ajp.AjpAprProtocol - the APR/native connector.
    Custom implementations may also be used.
    Take a look at our Connector Comparison chart.

    If this Connector is being used in a proxy configuration, configure this attribute to specify the server name to be returned for calls to request.getServerName(). See Proxy Support for more information.

    If this Connector is being used in a proxy configuration, configure this attribute to specify the server port to be returned for calls to request.getServerPort(). See Proxy Support for more information.

    If this Connector is supporting non-SSL requests, and a request is received for which a matching <security-constraint> requires SSL transport, Catalina will automatically redirect the request to the port number specified here.

    Set this attribute to the name of the protocol you wish to have returned by calls to request.getScheme(). For example, you would set this attribute to "https" for an SSL Connector. The default value is "http".

    Set this attribute to true if you wish to have calls to request.isSecure() to return true for requests received by this Connector. You would want this on an SSL Connector or a non SSL connector that is receiving data from a SSL accelerator, like a crypto card, a SSL appliance or even a webserver. The default value is false.

    This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.

    This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitly set using Request.setCharacterEncoding method was also used for the parameters from the URL. The default value is false.

    Set this attribute to true to cause Tomcat to use the IP address passed by the native web server to determine the Host to send the request to. The default value is false.

    Set this attribute to true to cause Tomcat to advertise support for the Servlet specification using the header recommended in the specification. The default value is false.

    To use AJP, you must specify the protocol attribute (see above).

    The standard AJP connectors (BIO, NIO and APR/native) all support the following attributes in addition to the common Connector attributes listed above.

    The maximum queue length for incoming connection requests when all possible request processing threads are in use. Any requests received when the queue is full will be refused. The default value is 100.

    The number of threads to be used to accept connections. Increase this value on a multi CPU machine, although you would never really need more than 2. Also, with a lot of non keep alive connections, you might want to increase this value as well. Default value is 1.

    The priority of the acceptor threads. The threads used to accept new connections. The default value is 5 (the value of the java.lang.Thread.NORM_PRIORITY constant). See the JavaDoc for the java.lang.Thread class for more details on what this priority means.

    For servers with more than one IP address, this attribute specifies which address will be used for listening on the specified port. By default, this port will be used on all IP addresses associated with the server. A value of 127.0.0.1 indicates that the Connector will only listen on the loopback interface.

    Controls when the socket used by the connector is bound. By default it is bound when the connector is initiated and unbound when the connector is destroyed. If set to false, the socket will be bound when the connector is started and unbound when it is stopped.

    When client certificate information is presented in a form other than instances of java.security.cert.X509Certificate it needs to be converted before it can be used and this property controls which JSSE provider is used to perform the conversion. For example it is used with the AJP connectors, the HTTP APR connector and with the org.apache.catalina.valves.SSLValve.If not specified, the default provider will be used.

    The number of seconds during which the sockets used by this Connector will linger when they are closed. If not specified, the JVM default will be used.

    The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented. The default value for AJP protocol connectors is -1 (i.e. infinite).

    A reference to the name in an Executor element. If this attribute is set, and the named executor exists, the connector will use the executor, and all the other thread attributes will be ignored. Note that if a shared executor is not specified for a connector then the connector will use a private, internal executor to provide the thread pool.

    The time that the private internal executor will wait for request processing threads to terminate before continuing with the process of stopping the connector. If not set, the default is 0 (zero) for the BIO connector and 5000 (5 seconds) for the NIO and APR/native connectors.

    The number of milliseconds this Connector will wait for another AJP request before closing the connection. The default value is to use the value that has been set for the connectionTimeout attribute.

    The maximum number of connections that the server will accept and process at any given time. When this number has been reached, the server will accept, but not process, one further connection. This additional connection be blocked until the number of connections being processed falls below maxConnections at which point the server will start accepting and processing new connections again. Note that once the limit has been reached, the operating system may still accept connections based on the acceptCount setting. The default value varies by connector type. For BIO the default is the value of maxThreads unless an Executor is used in which case the default will be the value of maxThreads from the executor. For NIO the default is 10000. For APR/native, the default is 8192.

    Note that for APR/native on Windows, the configured value will be reduced to the highest multiple of 1024 that is less than or equal to maxConnections. This is done for performance reasons.
    If set to a value of -1, the maxConnections feature is disabled and connections are not counted.

    The maximum number of request processing threads to be created by this Connector, which therefore determines the maximum number of simultaneous requests that can be handled. If not specified, this attribute is set to 200. If an executor is associated with this connector, this attribute is ignored as the connector will execute tasks using the executor rather than an internal thread pool.

    The minimum number of threads always kept running. If not specified, the default of 10 is used.

    This attribute sets the maximum AJP packet size in Bytes. The maximum value is 65536. It should be the same as the max_packet_size directive configured for mod_jk. Normally it is not necessary to change the maximum packet size. Problems with the default value have been reported when sending certificates or certificate chains. The default value is 8192. If set to less than 8192 then the setting will ignored and the default value of 8192 used.

    The protocol handler caches Processor objects to speed up performance. This setting dictates how many of these objects get cached. -1 means unlimited, default is 200. If not using Servlet 3.0 asynchronous processing, a good default is to use the same as the maxThreads setting. If using Servlet 3.0 asynchronous processing, a good default is to use the larger of maxThreads and the maximum number of expected concurrent requests (synchronous and asynchronous).

    Only requests from workers with this secret keyword will be accepted.

    If set to true, the TCP_NO_DELAY option will be set on the server socket, which improves performance under most circumstances. This is set to true by default.

    The priority of the request processing threads within the JVM. The default value is 5 (the value of the java.lang.Thread.NORM_PRIORITY constant). See the JavaDoc for the java.lang.Thread class for more details on what this priority means.

    If set to true, the authentication will be done in Tomcat. Otherwise, the authenticated principal will be propagated from the native webserver and used for authorization in Tomcat. The default value is true.

    The BIO and NIO implementation support the following Java TCP socket attributes in addition to the common Connector and HTTP attributes listed above.

    (int)The socket receive buffer (SO_RCVBUF) size in bytes. JVM default used if not set.

    (int)The socket send buffer (SO_SNDBUF) size in bytes. JVM default used if not set.

    (bool)This is equivalent to standard attribute tcpNoDelay.

    (bool)Boolean value for the socket's keep alive setting (SO_KEEPALIVE). JVM default used if not set.

    (bool)Boolean value for the socket OOBINLINE setting. JVM default used if not set.

    (bool)Boolean value for the sockets reuse address option (SO_REUSEADDR). JVM default used if not set.

    (bool)Boolean value for the sockets so linger option (SO_LINGER). A value for the standard attribute connectionLinger that is >=0 is equivalent to setting this to true. A value for the standard attribute connectionLinger that is <0 is equivalent to setting this to false. Both this attribute and soLingerTime must be set else the JVM defaults will be used for both.

    (int)Value in seconds for the sockets so linger option (SO_LINGER). This is equivalent to standard attribute connectionLinger. Both this attribute and soLingerOn must be set else the JVM defaults will be used for both.

    This is equivalent to standard attribute connectionTimeout.

    (int)The first value for the performance settings. See Socket Performance Options All three performance attributes must be set else the JVM defaults will be used for all three.

    (int)The second value for the performance settings. See Socket Performance Options All three performance attributes must be set else the JVM defaults will be used for all three.

    (int)The third value for the performance settings. See Socket Performance Options All three performance attributes must be set else the JVM defaults will be used for all three.

    (int) The timeout for a socket unlock. When a connector is stopped, it will try to release the acceptor thread by opening a connector to itself. The default value is 250 and the value is in milliseconds

    The following attributes are specific to the NIO connector.

    (bool)Boolean value, whether to use direct ByteBuffers or java mapped ByteBuffers. Default is false.
    When you are using direct buffers, make sure you allocate the appropriate amount of memory for the direct memory space. On Sun's JDK that would be something like -XX:MaxDirectMemorySize=256m.

    (int)Each connection that is opened up in Tomcat get associated with a read ByteBuffer. This attribute controls the size of this buffer. By default this read buffer is sized at 8192 bytes. For lower concurrency, you can increase this to buffer more data. For an extreme amount of keep alive connections, decrease this number or increase your heap size.

    (int)Each connection that is opened up in Tomcat get associated with a write ByteBuffer. This attribute controls the size of this buffer. By default this write buffer is sized at 8192 bytes. For low concurrency you can increase this to buffer more response data. For an extreme amount of keep alive connections, decrease this number or increase your heap size.
    The default value here is pretty low, you should up it if you are not dealing with tens of thousands concurrent connections.

    (int)The NIO connector uses a class called NioChannel that holds elements linked to a socket. To reduce garbage collection, the NIO connector caches these channel objects. This value specifies the size of this cache. The default value is 500, and represents that the cache will hold 500 NioChannel objects. Other values are -1 for unlimited cache and 0 for no cache.

    (int)The NioChannel pool can also be size based, not used object based. The size is calculated as follows:
    NioChannel buffer size = read buffer size + write buffer size
    SecureNioChannel buffer size = application read buffer size + application write buffer size + network read buffer size + network write buffer size
    The value is in bytes, the default value is 1024*1024*100 (100MB).

    (int)Tomcat will cache SocketProcessor objects to reduce garbage collection. The integer value specifies how many objects to keep in the cache at most. The default is 500. Other values are -1 for unlimited cache and 0 for no cache.

    (int)Tomcat will cache KeyAttachment objects to reduce garbage collection. The integer value specifies how many objects to keep in the cache at most. The default is 500. Other values are -1 for unlimited cache and 0 for no cache.

    (int)Tomcat will cache PollerEvent objects to reduce garbage collection. The integer value specifies how many objects to keep in the cache at most. The default is 500. Other values are -1 for unlimited cache and 0 for no cache.

    (int)The max selectors to be used in the pool, to reduce selector contention. Use this option when the command line org.apache.tomcat.util.net.NioSelectorShared value is set to false. Default value is 200.

    (int)The max spare selectors to be used in the pool, to reduce selector contention. When a selector is returned to the pool, the system can decide to keep it or let it be GC'd. Use this option when the command line org.apache.tomcat.util.net.NioSelectorShared value is set to false. Default value is -1 (unlimited).

    The following command line options are available for the NIO connector:
    -Dorg.apache.tomcat.util.net.NioSelectorShared=true|false - default is true. Set this value to false if you wish to use a selector for each thread. When you set it to false, you can control the size of the pool of selectors by using the selectorPool.maxSelectors attribute.

    The APR/native implementation supports the following attributes in addition to the common Connector and AJP attributes listed above.

    Duration of a poll call in microseconds. Lowering this value will slightly decrease latency of connections being kept alive in some cases , but will use more CPU as more poll calls are being made. The default value is 2000 (2ms).

    Amount of sockets that the poller responsible for polling kept alive connections can hold at a given time. Extra connections will be closed right away. The default value is 8192, corresponding to 8192 keep-alive connections.

    None at this time.

    The proxyName and proxyPort attributes can be used when Tomcat is run behind a proxy server. These attributes modify the values returned to web applications that call the request.getServerName() and request.getServerPort() methods, which are often used to construct absolute URLs for redirects. Without configuring these attributes, the values returned would reflect the server name and port on which the connection from the proxy server was received, rather than the server name and port to whom the client directed the original request.

    For more information, see the Proxy Support HOW-TO.

    Below is a small chart that shows how the connectors differentiate.

    Java Blocking Connector Java Nio Blocking Connector APR/native Connector BIO NIO APR Classname AjpProtocol AjpNioProtocol AjpAprProtocol Tomcat Version 3.x onwards 7.x onwards 5.5.x onwards Support Polling NO YES YES Polling Size N/A maxConnections maxConnections Read Request Headers Blocking Sim Blocking Blocking Read Request Body Blocking Sim Blocking Blocking Write Response Blocking Sim Blocking Blocking Wait for next Request Blocking Non Blocking Non Blocking Max Connections maxConnections maxConnections maxConnections
    tomcat7-7.0.52/webapps/docs/config/service.xml0000644000175100017510000000611712271304167021173 0ustar locutuslocutus ]> &project; Craig R. McClanahan The Service Component

    A Service element represents the combination of one or more Connector components that share a single Engine component for processing incoming requests. One or more Service elements may be nested inside a Server element.

    All implementations of Service support the following attributes:

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Service interface. If no class name is specified, the standard implementation will be used.

    The display name of this Service, which will be included in log messages if you utilize standard Catalina components. The name of each Service that is associated with a particular Server must be unique.

    The standard implementation of Service is org.apache.catalina.core.StandardService. It supports the following additional attributes (in addition to the common attributes listed above):

    The only components that may be nested inside a Service element are one or more Connector elements, followed by exactly one Engine element.

    There are no special features associated with a Service.

    tomcat7-7.0.52/webapps/docs/config/index.xml0000644000175100017510000001032612271304167020637 0ustar locutuslocutus ]> &project; Craig R. McClanahan Overview

    This manual contains reference information about all of the configuration directives that can be included in a conf/server.xml file to configure the behavior of the Tomcat 7 Servlet/JSP container. It does not attempt to describe which configuration directives should be used to perform specific tasks - for that, see the various HOW-TO documents on the main index page.

    Tomcat configuration files are formatted as schemaless XML; elements and attributes are case-sensitive. Apache Ant-style variable substitution is supported; a system property with the name propname may be used in a configuration file using the syntax ${propname}. All system properties are available including those set using the -D syntax, those automatically made available by the JVM and those configured in the $CATALINA_BASE/conf/catalina.properties file.

    The configuration element descriptions are organized into the following major categories:

    • Top Level Elements - <Server> is the root element of the entire configuration file, while <Service> represents a group of Connectors that is associated with an Engine.
    • Connectors - Represent the interface between external clients sending requests to (and receiving responses from) a particular Service.
    • Containers - Represent components whose function is to process incoming requests, and create the corresponding responses. An Engine handles all requests for a Service, a Host handles all requests for a particular virtual host, and a Context handles all requests for a specific web application.
    • Nested Components - Represent elements that can be nested inside the element for a Container. Some elements can be nested inside any Container, while others can only be nested inside a Context.

    For each element, the corresponding documentation follows this general outline:

    • Introduction - Overall description of this particular component. There will be a corresponding Java interface (in the org.apache.catalina package) that is implemented by one or more standard implementations.
    • Attributes - The set of attributes that are legal for this element. Generally, this will be subdivided into Common attributes that are supported by all implementations of the corresponding Java interface, and Standard Implementation attributes that are specific to a particular Java class that implements this interface. The names of required attributes are bolded.
    • Nested Components - Enumerates which of the Nested Components can be legally nested within this element.
    • Special Features - Describes the configuration of a large variety of special features (specific to each element type) that are supported by the standard implementation of this interface.
    tomcat7-7.0.52/webapps/docs/config/manager.xml0000644000175100017510000005041212271304167021142 0ustar locutuslocutus ]> &project; Craig R. McClanahan Yoav Shapira The Manager Component

    The Manager element represents the session manager that will be used to create and maintain HTTP sessions as requested by the associated web application.

    A Manager element MAY be nested inside a Context component. If it is not included, a default Manager configuration will be created automatically, which is sufficient for most requirements, — see Standard Manager Implementation below for the details of this configuration.

    All implementations of Manager support the following attributes:

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Manager interface. If not specified, the standard value (defined below) will be used.

    Set to true to ask the session manager to enforce the restrictions described in the Servlet Specification on distributable applications (primarily, this would mean that all session attributes must implement java.io.Serializable). Set to false (the default) to not enforce these restrictions.

    NOTE - The value for this property is inherited automatically based on the presence or absence of the <distributable> element in the web application deployment descriptor (/WEB-INF/web.xml).

    The maximum number of active sessions that will be created by this Manager, or -1 (the default) for no limit.

    When the limit is reached, any attempt to create a new session (e.g. with HttpServletRequest.getSession() call) will fail with an IllegalStateException.

    The initial maximum time interval, in seconds, between client requests before a session is invalidated. A negative value will result in sessions never timing out. If the attribute is not provided, a default of 1800 seconds (30 minutes) is used.

    This attribute provides the initial value whenever a new session is created, but the interval may be dynamically varied by a servlet via the setMaxInactiveInterval method of the HttpSession object.

    The length of session ids created by this Manager, measured in bytes, excluding subsequent conversion to a hexadecimal string and excluding any JVM route information used for load balancing. The default is 16.

    Tomcat provides two standard implementations of Manager for use — the default one stores active sessions, while the optional one stores active sessions that have been swapped out (in addition to saving sessions across a restart of Tomcat) in a storage location that is selected via the use of an appropriate Store nested element.

    Standard Manager Implementation

    The standard implementation of Manager is org.apache.catalina.session.StandardManager. It supports the following additional attributes (in addition to the common attributes listed above):

    Absolute or relative (to the work directory for this Context) pathname of the file in which session state will be preserved across application restarts, if possible. The default is "SESSIONS.ser".
    See Persistence Across Restarts for more information. This persistence may be disabled by setting this attribute to an empty string.

    Frequency of the session expiration, and related manager operations. Manager operations will be done once for the specified amount of backgroundProcess calls (i.e., the lower the amount, the more often the checks will occur). The minimum value is 1, and the default value is 6.

    Name of the Java class that extends java.security.SecureRandom to use to generate session IDs. If not specified, the default value is java.security.SecureRandom.

    Name of the provider to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the Manager will use the platform default provider and the default algorithm. If not specified, the platform default provider will be used.

    Name of the algorithm to use to create the java.security.SecureRandom instances that generate session IDs. If an invalid algorithm and/or provider is specified, the Manager will use the platform default provider and the default algorithm. If not specified, the default algorithm of SHA1PRNG will be used. If the default algorithm is not supported, the platform default will be used. To specify that the platform default should be used, do not set the secureRandomProvider attribute and set this attribute to the empty string.

    Persistent Manager Implementation

    NOTE: You must set either the org.apache.catalina.session.StandardSession.ACTIVITY_CHECK or org.apache.catalina.STRICT_SERVLET_COMPLIANCE system properties to true for the persistent manager to work correctly.

    The persistent implementation of Manager is org.apache.catalina.session.PersistentManager. In addition to the usual operations of creating and deleting sessions, a PersistentManager has the capability to swap active (but idle) sessions out to a persistent storage mechanism, as well as to save all sessions across a normal restart of Tomcat. The actual persistent storage mechanism used is selected by your choice of a Store element nested inside the Manager element - this is required for use of PersistentManager.

    This implementation of Manager supports the following attributes in addition to the Common Attributes described earlier.

    It has the same meaning as described in the Common Attributes above. You must specify org.apache.catalina.session.PersistentManager to use this manager implementation.

    The time interval (in seconds) since the last access to a session before it is eligible for being persisted to the session store, or -1 to disable this feature. By default, this feature is disabled.

    The time interval (in seconds) since the last access to a session before it should be persisted to the session store, and passivated out of the server's memory, or -1 to disable this feature. If this feature is enabled, the time interval specified here should be equal to or longer than the value specified for maxIdleBackup. By default, this feature is disabled.

    The time interval (in seconds) since the last access to a session before it will be eligible to be persisted to the session store, and passivated out of the server's memory, or -1 for this swapping to be available at any time. If specified, this value should be less than that specified by maxIdleSwap. By default, this value is set to -1.

    It is the same as described above for the org.apache.catalina.session.StandardManager class.

    Should all sessions be persisted and reloaded when Tomcat is shut down and restarted (or when this application is reloaded)? By default, this attribute is set to true.

    It is the same as described above for the org.apache.catalina.session.StandardManager class.

    It is the same as described above for the org.apache.catalina.session.StandardManager class.

    It is the same as described above for the org.apache.catalina.session.StandardManager class.

    In order to successfully use a PersistentManager, you must nest inside it a <Store> element, as described below.

    Standard Manager Implementation

    If you are using the Standard Manager Implementation as described above, no elements may be nested inside your <Manager> element.

    Persistent Manager Implementation

    If you are using the Persistent Manager Implementation as described above, you MUST nest a <Store> element inside, which defines the characteristics of the persistent data storage. Two implementations of the <Store> element are currently available, with different characteristics, as described below.

    File Based Store

    The File Based Store implementation saves swapped out sessions in individual files (named based on the session identifier) in a configurable directory. Therefore, you are likely to encounter scalability problems as the number of active sessions increases, and this should primarily be considered a means to easily experiment.

    To configure this, add a <Store> nested inside your <Manager> element with the following attributes:

    The interval (in seconds) between checks for expired sessions among those sessions that are currently swapped out. By default, this interval is set to 60 seconds (one minute).

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Store interface. You must specify org.apache.catalina.session.FileStore to use this implementation.

    Absolute or relative (to the temporary work directory for this web application) pathname of the directory into which individual session files are written. If not specified, the temporary work directory assigned by the container is utilized.

    JDBC Based Store

    The JDBC Based Store implementation saves swapped out sessions in individual rows of a preconfigured table in a database that is accessed via a JDBC driver. With large numbers of swapped out sessions, this implementation will exhibit improved performance over the File Based Store described above.

    To configure this, add a <Store> nested inside your <Manager> element with the following attributes:

    The interval (in seconds) between checks for expired sessions among those sessions that are currently swapped out. By default, this interval is set to 60 seconds (one minute).

    Java class name of the implementation to use. This class must implement the org.apache.catalina.Store interface. You must specify org.apache.catalina.session.JDBCStore to use this implementation.

    The connection URL that will be handed to the configured JDBC driver to establish a connection to the database containing our session table.

    Name of the JNDI resource for a JDBC DataSource-factory. If this option is given and a valid JDBC resource can be found, it will be used and any direct configuration of a JDBC connection via connectionURL and driverName will be ignored. Since this code uses prepared statements, you might want to configure pooled prepared statements as shown in the JNDI resources HOW-TO.

    Java class name of the JDBC driver to be used.

    Name of the database column, contained in the specified session table, that contains the Engine, Host, and Web Application Context name in the format /Engine/Host/Context.

    Name of the database column, contained in the specified session table, that contains the serialized form of all session attributes for a swapped out session. The column type must accept a binary object (typically called a BLOB).

    Name of the database column, contained in the specified session table, that contains the session identifier of the swapped out session. The column type must accept character string data of at least as many characters as are contained in session identifiers created by Tomcat (typically 32).

    Name of the database column, contained in the specified session table, that contains the lastAccessedTime property of this session. The column type must accept a Java long (64 bits).

    Name of the database column, contained in the specified session table, that contains the maxInactiveInterval property of this session. The column type must accept a Java integer (32 bits).

    Name of the database table to be used for storing swapped out sessions. This table must contain (at least) the database columns that are configured by the other attributes of this element.

    Name of the database column, contained in the specified session table, that contains a flag indicating whether this swapped out session is still valid or not. The column type must accept a single character.

    Before attempting to use the JDBC Based Store for the first time, you must create the table that will be used to store swapped out sessions. Detailed SQL commands vary depending on the database you are using, but a script like this will generally be required:

    create table tomcat_sessions ( session_id varchar(100) not null primary key, valid_session char(1) not null, max_inactive int not null, last_access bigint not null, app_name varchar(255), session_data mediumblob, KEY kapp_name(app_name) );

    In order for the JDBC Based Store to successfully connect to your database, the JDBC driver you configure must be visible to Tomcat's internal class loader. Generally, that means you must place the JAR file containing this driver into the $CATALINA_HOME/lib directory.

    Whenever Apache Tomcat is shut down normally and restarted, or when an application reload is triggered, the standard Manager implementation will attempt to serialize all currently active sessions to a disk file located via the pathname attribute. All such saved sessions will then be deserialized and activated (assuming they have not expired in the mean time) when the application reload is completed.

    In order to successfully restore the state of session attributes, all such attributes MUST implement the java.io.Serializable interface. You MAY cause the Manager to enforce this restriction by including the <distributable> element in your web application deployment descriptor (/WEB-INF/web.xml).

    As documented above, every web application by default has standard manager implementation configured, and it performs session persistence across restarts. To disable this persistence feature, create a Context configuration file for your web application and add the following element there:

    <Manager pathname="" />
    tomcat7-7.0.52/webapps/docs/tribes/0000755000175100017510000000000012301126373017022 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/tribes/leader-election-message-arrives.jpg0000644000175100017510000033126410747071255025676 0ustar locutuslocutusJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( *9[cHU I9rzOiW|Mc'dcsc9m vWշ{#֣嵼i3ءVb`@_⎩^?/jߵϝ<6;h(?;ڧᵟHݣ=BEprC`dSڮt8[OQD쀡QX@u741$ cװJ]C|GZLGӸ s]& oo.iۦȧKeTm# rrsyO6~ҴY7.ca`XF {G#_j9NoHj'B"C+>V$jZWL@2&I\㓃ڽS m}7i}7e (]fFk/Dlgd(ZڤLW { Ԣ ( ( ( (<nO@?Sn(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((?$](ow: ( ( ( (E,sĒ"r( ( ( ( (<nO@?Sn(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((?$](ow: ( pQmty;|-y^k8;K@ӭmO4?OX 9a_.FRN `TLqX\ 4Ts"Bp?LWQ@mo-QM%XaPgH\yrO5>-XkL<3H"?@kۨ$ӟS揮cV^byU AjM-Zoge=9y撄)Q >2|9j7<##Ԣra @TօmlnWBGb#ҭ'z?}? ?VW¬?8+_p*zqygɮm뚥=؟leG9pg̯}v뺖k0mNiK"k[}?xF(<ѭ/mu e݉ ,2RA 8 u7Iӭ4*7ԑ>mp11XH|yg*NP+TkV{Zy?c$xLU„ӑznRti"s* ԀYA>֤K]ܺq֌bWK`'WIC"P>lwBYԵx:٢Ks$7ѵW1Ukx0p@` +((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((gο5 ?ud@(((((-b_ŌZžtfne[PxD:Jڭ}jkY۱dC\cOGo}_,NmfDC: ;gsb5جmMӵ?*I.#fid1v(>wy%+ g;ڑ"*z F,5k K67x|d{iyOR|&9ۑW?X#uk[!aKktk!<_$=}m5q̭q i,:9`ߕs]߇omo-+#Ē-iԢ6>I'kt VǮxb-F6{ѹqNW8 {)!A$RjmiU% ` +Jޯ.kiZ6  @Li$WYiV/ZU8ͤovВBHlPh[Agٵ6zJf U9}O5$^.k]jկ]* 㲝2 8v1'8j+b]$w{gF+[Gn% uQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW,ƻgο5QEQEQEQEQE^Ktck$7roipF1l%e37QYSF  @I22;WPjz^}b^i i\!GwcB 8jZ:ϡYG$ *MJ B31e,HQ^SK僪^{y 6 Eo/ef{[D,|0.6{s@*| 1*zR~VVd+/c<ϐ29 ryNh捷.~v|v=<=?sp\RY34 NVk}VlCm!y'6cdu e#ǥQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE? o96`A#*FxDO-l|C_[j1[xXU5y&~c?_\JC'̗2!SN;QQ&[xH [_xM@< n~-.";e >^\Ke&4=3\2hq@Z*C(`rȯeuZjf$N39l}l];J '|m^vMEpʷꚾmqeiB6M<~|ɓ͒2Hγ&FnuR-J9΅c?|9 0iswqI&$y#8G,;5Gk79-`i7Cl,J 25PYfir$&QO".W` z=J {`Uymḍ@O≣!{{sz%$Qm O@Lc`rzw""|D);dbMvR(dsI$ݗa0 !BC9#'4VRm/0U.̮lOK R-B]j)!%[G4+#1ǖÒH*1sRĒPRc"6L~s̸_"?=bgR tfs*`Yzy8/lj]Sc}{|qq;+dkYZ˥A'6>eM,Uyˁs09 O_^MomqmszfUXFm _^kw/u2V=J {@mXF6D 󷟜gkS¶Z]BSMXdrcnF쟺O8 ((((((((((((((((((((((((((((((((((((((((((((((((((((^ LƤH88q]*|s€=U>?}? +V¬?8((?YSqQ  ׺lK/.q d8ڼv5ܯlsmiY~v῅ dr?}? !Hz?}? ?VWS[^_wu'i2;byN O}P}gyͷ9Պ)?DgzRyܠ2FSNkx׬5=xdS17'R].=Z Jou)^k6>J.'^Po=ȯq4q+:ƭ#UI䊪֜MΪIo7Λ +U\[Z(ծZ-GN?-op|/)ϐJúM/Ⱥ)-LzLڸ]>9o-n%[mmܭ/;Yw3bj[R qe2٥!K D6G^IBV]e╲:8.yCo/m7ڌZIZAc΄ZF b,IaIAlGj0PYUQHBI1ɩxOF[[Ӛ{uvy"O>#*H 1=@9\GO^R]\]]jnKA»3wzWE{5i#݂ X\)kwm>ſ>ò?7]3ڭ.hX%֣uk tۓbs@ozfU d)#k`k+/؋kkBb[9HBn%&XXjЛcE?%`d@PQ\tVuhn-&iM P@Bnǫ޺ (((((((((((((((((((((((((((((((((((((((((((((((:}WW,ƻ ( (34YF HO(X)OY4K.V9 R[V$OeOz_xzuvp=Z?)"4 ǎ[@uEyěH.0|`h<*~HGLS>"ӵ3wcW1)Z01(H,@ ?=O{][GoknB ] s:޽6݃K52f -GpK{NkmD=Ɵ}_26d(k3ykr ( (< ?J _Ht/x҉+(iij-&h22@뒹qڮWxn, x|.%126 n7dKV =I< OմZ7M-/cCe)%IgkgT=:A/:-D{Iܬ*T ҹ{ڄvXbm嵹_/rT RCZK!4v)d`QI ^_qokj\m,/JYJPs7mfܽA]~4Kw$m;ùMs~gm5k-bolei- uAG55{YVXe1F)ys Yk m_Ni ,fONn;G gi%('VMB}KTVi 7NaŒےX| PTsAlGj0PYUQHxVkJ BHgF[$\6םǃzu[c⋽29QO1,w `uGxڧ4W5P"L-|ʹxdbPHbMkxpxoºpھKȦ5?ozDgjCVd/{3>gmQc<|QIu]^FFۃus`O?;>Ms@dg*9. XbhIؤJ!Gs''yx=/ƚoྊ3 <3yܠuUƍ&u[xH " v|劉 Wçk7x)n5Y[؄(rU;67IGq6?EാI3\o_l u^{YW[5cK;#dfqoϑ6wf=Vb[ԵH,MsuM[c'X5DXt;O"S y#@z-5,f!ug&Yd1A B1\ ̾ |fu+Rջy`;܃nK FEzI%ԫ< ݂(Yjz]cNTf']OL91$(bi> p[ 08Qľ{Gf rWsN0wcI=:o.uMb)J1mيB0ԕr zTm>+ln#ݥ䐍_vᶑ@ܷ1*K>| jz8t.5Nm7k&_2ܥJ݇C?^t-~/M!,\(y36L@$44W% GJTFz2Fd4M$rX!pN@4JY5?jر^Co`GR$I 0On1@q\if$%ɰ[nsGJx-h%@WR2#5^-V{aYY]6ݑNJloZvbn$",qpiewg=%Onk0)dU(HRӭm床 CL>|.51x inuXQx! ]!*jJt뻿dWjY,C43ip`Bd{#p;+҆Cch((((((((((((((((((((((((((((((((((((((((((((c]^^g_J (*9 i!yb2Q##IEW}tqin#hU8zU{MFdk-&أaDJ>[)u].VRe;[p 0q6vJKiZElVFز!"³tvY}Rm .X7IGM;OW9uc }'>gisi}'d*<onؚHh.6P2*VU :W1m B{ L5^̍cz1aG =OQ{m^[!+46Db:*@Q[m3(F]͎ 'KEQEQE_WWCI^@Q@q+MJαHAf!UF{@ UkVR-$i [eP PP:mEJ_#3ٻ=X.{;Y/l勵IfpoHblف$q$uoDӵ J4 x-Eb a3 Xk#]꺷H@X#r0r܀z)!A$Rj{{ncUwɘ}?S;|G_OId8dw &8',z r갮hXᵻ#g:ڣܸۼ1|zhh',\*ږrKbq kh1$rF 3 m=ֶ x0(ZGDˇ@Jsa%_l_?;i>6y{1q6~(5gגIY4YT[@!98Ykf}=ҽ U%Wې7bpkF)Eia^f&ctC.I5ZZkMiknq+/u c1(p^;ieekcIdAQ?֗cHlno."kd2Iq#rpϿn^{X[O Y%hw7.: e$($M#:0޼ĩֱXk) ֟}%iP? ުIu#_%,UZUS P2CpZ:;/젼KoqцAPEM^=m+@Zs*hJ637U@FeSkՆkFY5:ԯeLΊhZٟ>ZFڀ=B}///|C<^Rg3WeSI{;~.,/gY\[0!*BPT  on Ҽ?7A!sg{вԭ ,S+mn 꺴v15>[x˹;Iu _RO< lZX㑞gR2$@; +ɬEE3\SG.v<ě&(Px$d_>2iE lK Xw#yK]B-m U_&`?]O^[gx-")Mr>sI$ݗa0 !BC9#'5rXĺP"%֢RU{B3ym9$ Pym6\B1DLזx]*QYlc[#iuٗKGc`T uu '΋D3\ |c&O0;.Kcմn[1i2b]a xϡeKYqz,0,(rF8wQ.=qq(K{ QUMoU!Tڧi( %z3-B臐`9$@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@g_J :}WPEPEx֛^[X`֫vxp68=@OqiwwurB, 6=5 cj˾gEeuر#*q}kP[Z-ڄh>Y0"6~bO8W!K >Kx>`n^+mV,r9@owiwyܳlf\)q֛.4% T@2' aI#\U֫j7z k-jk6fQ\%1~zswQvN߈i|-"eF&̲#23H9n@=iK"HvVXDYgxA=H&ii33K *!2^'DR-l-Vk,EߖfL .ڶjO zu (Q@Q@KIoQ%zy/$:DQE["ĬbTg$;Tl5 }0B!16A8 RP:mEJ_#3ٻ=\mvqq>mi_,O6G\9 =m>MqVe[kv2Mc?! y!_'HxRyt4;]LZCSY$F`%d&V I ;QKפvļ\Mu5$JqNOT1 SpAڼj3F-uoǧަ5,,{@0\6k -sZaws]\{chLe9\7(WWqw<Oי}nֱZ<%;g:f6 fXwU@de I*7Tb=JmA|I6nq;VKJ2e'FL\L( #p~\%@1ʌPY$na$>X)J7N y!GLN˒zdq^eZwp..F9V'Wۅ2q ߃kcG'~C?UIwS̑ۼ'_9n\'~C?U?0TQ\'~C?U?0TQ\'~C?U?0TCI^^KIoQ%zQEG=ȯq4q+:ƭ#UIUu[=JK,[ePblA8#ztO/#;Ggóv{c9׉㻎}P۬;1-,Y]䟘m r@:%UW빘`].Ƨ.-uI ޕ&-RSl,M#8_ l2&_ɩ^B%B9KSJaQeq˜t#Vg}:Y]M2hiyʎd;P|ݾ`9 ;Ak% gr)VGc pzs@Eyi ݬژ?ڰG2QH'ߒw NrC&?ٵvuJԧ1Eunx0#! ۸#@Ep3vzٺ;&)(s~zjߥn`u$KI%f>Óv#gZ?짆IV29s9cWϔ.1Ҁ=:;s^\t~m%ψq2r>ʒT nt>)Լὒx..Fd;S$.##(k*,F(e#n4荫&>+B]CFXF,>l+r]$7kfF;[ ,͜Ԁ~Q^ce.k\Fu[>V)v篜<2RXF l*uy}5IV᠖CZCHGy*~Z(xa7Y#`.8Uҥ&kG6cvEEpv2prRx$bӭ4+kͽ[B'2ȥm!e>Ip(Բ3-yMtneaKj~y1(2%;AWj}mz4XaX.c!Bwwm zEc5k$R/FR2)Kc4bѤX ̪@,ReZtmV>Ǩ鶖,|Ȋu$;yMs}s\%;G?(uBu,hGQK+q? R[]DmDI`-%5.5& ~az-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE?+uq-dži$3;I+I5 SCt?MtP?'T]G SCt?MtP?'T]G SCt?MtP?'T]G SCt?MtP?'T]\? oS[^_J4Q,FNX?%$B(:A<B?  k9A<B?  k9A<B?  k9A<B?  k+YqZAikvCb4\Np2I?X((EUQ RET@ u ( ( ( ( ( ( }iZͨiWrs[¯Q@c47,Pq[un_?^(((((((((((((((((((((((((((((((((((((((((((((((((((((((((+ !пJ$@?%$B(=((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((?xz `k{9J_ZO JaQa0<)wKi0io ҆vU:Ozuͅ~eO ɸzW|__]]]Ar incIg}*v.;8n-ho.uH\yb?5hrrp:fQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEHږ}p,ǠUPK=oYɬ?!a$ CM 8 rv0zj1W%1Fq:/lT `I[Z:_߅+*K .x7aKB!B:$ܬ>x}AOMɳCh?|9<͞?Zn!!Gg&v3Y]Č1O%W䳿LoxĈ  x<ɬxz$Yt {3gMu=2׋tl \Gwib#ժ.Ӏv"-.m>x-32pXzT~Ѽni{,O*N+m5/Xϥ4SDƢPmnqZ/͞//ؽr0wc((((((((((((((((((((((((((((((((((((((((((((((((((((((((G_io^r06ƙ 9O+?5?2KɌ\:<-ī2ĘBr9W #^ ԫw>Ŧ1ÖSFG0mR1SA VG  HB(q'm;ۯ :Ky#I4xGe\#5QEQEQEQEQEq>$խZܝU $KKBGqFGq޹{}AH Vl5_;P%HCyʙ''k( Ht=R\Kb%]'b+LY+IM3Gu_Ekkh$ҭ纚8 K99>(˼#{=GQo2gxsٗS/(8nx@ѯ0_9tIT%-A#*YqTPE 1a<TiVW: _jukRIťAl{OW@e3iz兆t-^YRD0dbFX*Zga=֛Kxuy*S"leFzQEWJï:נWJï:QE-N-NQEQEQEQEQEQX~(v-02F9c_a5.DO MȆ[KBn[!=S[ҒخgްݍF߇*w |/ }"'e%y';g#j rx_ľO_@>{r; WW=Es~΋,etӮ$$r22py ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (#n巸9 I]H#Wmwwel.@ dt N+O"\MYɋ-N݊n)0LҤo< *x?t QF."E; zEuoż9#`FApA椠((xmm常8` $Q@$?|[xRԦt;KH#2Os&8HrI88eDžA&Xo`DnX&kWhm#y"ׯ"8w3wbvn&XeeuM0EW㼰L $0? ^wym}cz63-crɂPS Vzt=OÚ6O &N t9wMwQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQECuo-QRHPF Ab<jT . %s@s~9ӼS>IJ^iWsAܼveRq]Es~*6GmXm$r2r9x[ʶURǬ𿋴_i0(,r6șʜ{d9Xڣk}ދ Fb2*T\2B(uWT型'zc;oH_)\l*`עA<7V\[J6 dGhJ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (#n巸9 I]H#W'ދN=.o-Gwko(fH ðqprǪW,ƻ=(((((((((((((((((ſWOIֽſWOIր=(?o_u@?o_u@}gYywx4r@c ~5:<شq:$ 2@:xBwl { u2;BF9sErqh~/^xMҢ1-do>u*Plk🁴 n2Ϩw,w$vmrXQ@*C2;k;tIG$O$NIQ@Vv/IHrGo\o  ir#;@UU`VxWB][Zx;[$nYH"=l|mj-[ݬ3˺Qt_B a6IC^m"V[[/[h6b$_60I Vu f.B2 QyW'IȮ]rc:vwo*63 ?ϟ4~\u9Er^1 \mKlB:r`25hQEG<[oqsA*92<G;׋wMGSO_JVcf$p7 H9? @ SP'˅׶Ŕk-<@ɐNĀIULmsKE@;XuVS3ȭ (((((((((((((((((((((((((((((((((((((((((+c]^^O3ouZh_h;]cRZ+ΥbEtVM}j4& F# )>wZjQ<Bbda}uQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE-N-NQEy|:t-/;u;B֮EN  eX Jï:נP?FNZxD-7ifGZ#E]5lu 4<;Ꭱbeg=ù8M3? 1*1@xn⸷9$l]H #ԔQET7vvZ[Cso 2FySWɪ/淎C޳g@V]ǷQI F%HIQVtp`gA Ku@ `dCK/\0pF ,@pNsBźǭxݴ}h9 >.X˸/$-[XDi"\䎇q$\H<=Z>VG;d\2gau\8&oxU!a 7DDr(AT=k5=[GR2[[!Α7gsgNmIL' ۩Vӭt6]m4Ku68@˖88z5i--buv{W+eqR~'Fh_5t啋_!9^iNY±>@2=HcҬP")[tcnVn9!<+[念&'Fm!M6?z{I񖻡c֒kvzUȈۡrPiZvb7f"LfxVM#I1HB(v>\-޻7~t7SN$*B͂3oh:uzSj[ k۩i_o+ ڀ:j( ( (R"?jl&FoYBVIePCTa |]xD$~wVl߿W3 ;Y#/]:4&7TC/Wh>lA¸Cá1;~k79xm[VA(;T0$QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^LӮo$mby}EҼgw=_y5?_y绱'@|2yl'ʶ2 Y?.oi4^w6Ʈ%nBBrhzd䳍ͫY?4%#5'KK[y!/6ID*q]A@k@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@y|:zy|:zQ@+'^^+'^@W䳿LoxĈ  Eynે5s{7Ƹ%I10.\<(xo3Kׂ)HSRPoAlH\I >\pms ) ,X84Q^g-d="~6PY"ˏ%Jlu.S.cMJ0A  Q5-NѬ`Ae U$wh [ b6uf0BPd*k/6g|vP[i|F3jQ@{E{t}>IҽH qWg.!UWYdP2=؀jZ(z}R$ۣ,J ${x{EW-OIdwKdX28@5EVM:7WK+ueiJĠs#I$5^-E6(IaG@ ( gjQYPJ>GX dd8eBK3w$OrIh*9[cHU I9I\ kq7{@|H-e q/˵O]9Cah9,4,Wd)71̀2$ZPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE-6kWRҭHj,93*hF[Bn.X.MIA ,Zh^Z]jW/L I*`Sr2\ 4__^k6#Z<+ [*cR}(V+F6`V‡grݹ!QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWJï:נWJï:QE-N-NQEQEW|9[ <u5p[دB )GJ271b(k4?iRx{\+ur^|FW9 m,pYFYgCC=ad3F=UN`kKñ,ItM"}wG?ٶZ1|`j2:yI/O.kuw1I7B,V)',7+2˷g+xRzdQ( y0I2N3lPpA VG  HB(q((((((((((((((((((((((((((((((((((((((((((n.%"BI#TP2I'5_)39̓Ɏ4NNYA#"? k K/%W FpTy}{O$]%Q7VEJ$E `(xn⸷9$l]H #ԕ<-yy|>;K&uXWo *xVC-._l,t/h|C`0(K}#YNwt <rd+c8":J7i틤G.: ;S9V co|R7rij7$ PH(K K =2;; H--c`FIŽI'? lX?nlL|HN1( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (g\==oNYdp(B=kwךׇ<Gk 0,qyJ2_T_ ky) 'h9,4,Wd)71̀2$@>~WԮ?Eu)mVpT,kϖN0( ( ( ( c]/y}VkY.'u$ 0JI۞8#<K9w %B*g%vc|3$FeOW_mqo/XZEvV1,^َ $z,Ea_/tcVK9dLNU2 QEQEQEQEQEQEQEQEQEQEQEQEQE-N-NQEy|:zy|:zQEQEQEQEQE1X`Q),9U8q[P_o6>-k> i/iJՃ|b1Ew6bwwnȒr p022y$?_? ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( *9[cHU I9yI>dItO7ė(R:!PYݑ>RUs,?yoi^"Em08 ZFP9a^S| }yzhKX,lJ1۟ԢtKyMC=Ӊ.=̘s$`e2kr ( ( ( ( ( ( (8x QIFM nХaLW,T)lP#> o&ϊѵy@͘/հfrnH`e%JU#GBhR8oMѻzKwa(R]O +U4}OL7*ta (Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@y|:zy|:zQ@+'^^+'^@Q@Q@Q@Q@Q@Q@7 rנWܩuQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEGcO:'TjB]yLE#MY%M2_@.mYdx9DRʼHqX5 _kV(ymght,ordeT0#⷇gPW-zB [bywU*| yQ<vwڅWv$(hC§o i:V]['HlfY^M +ľ-<)oSHgs'$h9$ FEs׎5x#NT-1wu9ŕ-0`Y>egˍ_RԦY[@qP>Z8žzt $Ra?gx)`Q\0,U?),A VG  HB(q((>x*EI{tKƟ.!7%7Wҡ.&i_Z8;Y#$aUH}+Mzq2rq!dwshKy%X&W=BOD昆0x^{uOi76}CgjdR- fHA$%څ,lKu-w3{ !n";P{y1I2INOMMgK{#ԬkPZ5KBR9\{!s{yvڄ6) 9:Ÿ/-ֱ h+i{$<6w0/)arA8#Wm)ݜgږ]-&UN.|= GJ"\Jo:Ni-,l򬦒=9|PT啹7g4 Xmn!Rgo4fn;m,1u sQiZjwOeugwh#iaNݴ'c"|= VI;渒 6%fb v`8Zo^ol@n cf}\EF}JҢ((;< xfmcvrlЮ 5܌AʍD`|*ϢQ@sxu};[dү#h?ypː⺊c]/y}VkY.'u$ 0JI۞8#K9w %B(((((((((((+[%{k+[%{h(^uq?'Z ^uq?'Z ((((((_?{{_?O>oQ{g>mNT;TO@S@(hw6Ο<b8,A=}*}?VuhM7Pki@Е'r((((((((((((((((((((((((((((((((((Ěu2GCiv)yL0n\ }3 _?U>?}? (V¬?8+(?YSqQ @<gO9aG*|s½U>G?Hn巸fT)$rjԌALGD|t9M[O>c7C6=*' tKi_%ڍwB΢F' NNk:omcѥ]~N Y’0GQJQ>0[+4[wWQ䰕m)/0-hUӭoaPI2>U''N,76`"mMp?)ܤsڱ/tMn[ӵK]K⼐Y{]~g ī xNJ?ؤnu?.Feq#ʹ3$0ITi 9 x-x$H2pjZtA=X ^E"U`sDTJCH:2wVaguۻڪ^ug̶V\`U'Ҧ}SOPM>KTnKfD9.rG; ycM0OO$Q¡ aEP2ݗ5ZڅƵtj,;mEgaT]*\4N;;,OчG F Wao'E߈. $ҙZ[݋>B8 =]qxHN}ݡr*èe` = J( ( ( ( ( ( ( *z]Ƨmgn(d5.".94xz!$yq2CU|~kXmkI)Cm4H?" 2xKKEMg,$ٖ&8T2m<9x[K]7E9}KcԳ1%AOVQEQEQEQEQEQEQEQEQEQEQEQE-N-NQEy|:zy|:zQEQEQEQEQEQEy/ʟw^^7 rנPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^7 rנWܩtQEQEQEQEQEQEQE—h[!b9le[$)^/5D߈4o%1\r8b`d|-+|ce,SX *rq ."K]kHچ!B\`1 GRT(7zwp]ɝA GV((((yᵷX$/$0UE$xs@W/nJ}O]2,R7GF '+c;4߻C})@I08I_hI^)./w{F..02#'IxT&K}2EK{XHc$q*J((((((((((((((ſWOIֽſWOIր=(?o_u@?o_u@((((((?Sn+Tۺ (((((((((((((((((((((((((((((((((((+Tۺ _?=(((((((((;Zo<Vov(({ZJ`[M<$4ȧ'k.C<];K{b8@Fh 4Xg$qHDGhFVLAqvdxKKEMg,$ٖ&8T2m"@TP0%PEPEPEPEPEPEPEPEPEPEPEPEPEPEP^+'^^+'@EPJï:נWJï:נPEPEPEPEPEPEPܩup*zQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEp*zy/ʟw@EPEPEPEPEPEPEPEPEPEP=WJ43S6Ka +7W^{iL-݄[Bnʼnt!( zGtԴ[ ޠVC+T8 pAEXu[K;|E̒p@&F%b3+J((((((((((((((((?o_u@?o_u@([%{k+[%{k(((((((Tۺ _? ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( _?nO@(((((((((((?K0:EO%-'e\}]3W nᏆ>,ĭ:lRy|s ]U;pyzGik6%}M8|d ^A;xGߊW69̿;pA29Z.2ķG$B͎HRI=qjJ(((((((((((((((((ſWOIֽſWOIր=(?o_u@?o_u@(((((+P3_QO]}W-.;0/͍=7grp*z|I|^|O>h;iRFXyEi 3o5S#Qv(T[xZ ~l`(((((((((:75U63'܃&)ljNX.Qmo _!H.>`GY~AjQyM=6ά ?3܌+YxKO˻;dG}|^2#sB4*C2;k;tIG$O$NIk_t/ཱུl vêʜEhWᯙIOj#02n/ݑTerYE}.-dP;A- `d1ܫĀQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWJï:נWJï:QE-N-NQEQEQEQEQEW,伿*/x3eF򐍡~i]K_1A9./̛c O& ^uq?'Z (((((((((((((((((((((((4k?wEo|J.A |akOßh[M u3:&sF~PHPzWIY6NK" V i :`VQEQEQEQEQEQEQEQX~%nKxRC=Ә- =̘#A$de2(rP֥kID] V) v++|˻þ#q&R)b-쌭6b\dK =2;; H--c`FIŽI'O¿ltR]{SZ,.pH #T@^9 h( ( t=/:sj^ڶNɓ;InS[(3K_4DKObHӆ,1MEUI=]KK9Ei`,DT[ nW9/[Xn :J7e Bs!rH o+'QDiKX]" 1(bp\-zQEQEQEQEQEQEQEQEQEQEQEQEQEQE-N-NQEy|:zy|:zQEQETs  !y$($s+g2(&X"bAr69 s@\![1M@.BIܣ`r1^FHa׼I'^Ji۾\ NGIk>a-$!I!]KmAۜdgl?=&G.D`چ3p9 Vʺʰ3%:X<]x%3#_JLXSr+("@TP0%PEP\@/4֩*m^3B1LjBV!BWyEyڷjZd~.è7jyh„K|B׉o iqM]ncJ+_wf_v(8}g!.;P;H 4`d͂xwOZ`E5Mc19e%JU#GBhR7_Dw{V$i.mBnʇLunTh9//m[|/vꭂ2g@QEQEQEQEQEW7HY./tK}: ..F2'#𯉾$o4V VFyډv0Fr< CZ&[Gy&mv2ZH )DG̭.lxk:n>w,.\I>xd i1`v;r@,l,8- ;!1.I' 8$ƬPEPEPEPEPEP=WJ43S6Ka +_K7Ox|o싙X\YFJI,lH@j(4/yV<.$dS +/tz bY4[9 RH[f%bT6sR:?;hCۆk+;@2AYUېD(((F%㱒D6%H8qր6(^o*\o ]@vw65̲E`r/$AnkW'Uⴺݮ`0\\dqaZۢ((((((((?o_u@?o_u@([%{k+[%{kxmm常8` $Q@$W[E߉uBibvt5|'~؋-];CBNc:Ğ8ׄ|jZI& ÆBps\Ǿ* x_ MG$ RC w!s<:Y˨o2>u$eù$ dI@«=CQa_xZ#epRxEU$XYqZAikvCb4\Np2I?X (0|[OE%bRAwj/д+ͳ]D ۹U8:O@s7X𽾻_\-ati!܍^7R~P9=s0yG:b䦓}@Z ❐NT wt^&Xw h  .W$~ 5حIX6 8ݳ8sִ{lMٱ69YxOOx;~:>?i7Z³7rK bEtaԈ $ij?ҭlc&efi40K:FeVe H ݪMSZ䲤hGu7?igV&kK[(좶C.B` ImwTFq$_c̏`RٹTC>a5i|IKsqo=om, p7T 9zWZrOu3;E{e m;;8r=j~d 6hZel #yYr܍3 :4;-Z9x0 3?dhVo;2\-ؠKucٹPm\vy9%6V]hW7W?f&$A X}ߦ@7hR[yXY>H0,=ˏTQEQEQEQEQT]VC5=N;k;t,G$$I7}Ik|*ۈb8e;h~r͐Fу dn%rFt<'}T>z͆w #.?đ  6m׆Yn%U|N K( c\_}7fp夜z/㚹^s[W[?}? \+cR6A C`OPerq=%#VukhFeg8.(QֹU>?}? +V¬?8((?YSqQ @gO9a\|5yG·~1]ڼAig47ڙ6, 3s =(((((ſWOIֽſWOIր=(?o_uYaA{j;&L$OUl#<[%{k(ÍK q]DH-ud܆ц`K09:ׇIqh@b:^ s],X z%k_t/ཱུl vêʜEhW.浪&ڲcMy[;g[ycqqYoq;Q]MqW,HwmJX]K+Ѿ&xkWSK}+Wlj5IWK6!CAua@Q@#0U, ZdZ  ʀ9Ⱦ bk1vy"]]#R_n`'f?i;gr ڢ$RJ~;@lA^kF&>_EigpoHetc0*m) ݶ5(ޑ-FP*#Ӑ։ Ԗk4Y5֎P0eF3 c$fźewwopͷuIYcYL8 ǏIlKjeSr=Lӭ,mbHaME(֊EQEQEQEQEQEQEQEQEQE% \^PHir$*v1 09#Er&N.ۥN^1G]H:f9v, +@6Os]U}*HPw4m bGd݁EQEQEQESu[K;|E̒p@&.Wo4 ,fyh ɂ$w _BЄ˶MRU+w &snS$!۬1)0E8=?V<#K{ b9FX 7TWnQ^o⟇z>ivǪD!TnW1̃YV+U4}OL7*ta (Q@aZGMJdCc RA(^#no&(l͏z8\gK=N; .dɠHA#zu/ M|xMh,Yhv~^ ,O!zyk(RO O/@<H^9?gG-?sνZ!xB : (iԅt ?'(?RO O/@<H^9?gG-?sνZ!xB : (iԅt ?'(7yaS l}8čXn# So|~xĺͧ Hcō-DN2A^jJE'dn|J"V_&DT͌CTozx{غ nkM@2G#rKq@Q@Q@ (5'R2#6c"Ig[dhm Wab;5Okv:Cb~P,pwaH3qL dԶ޻iz}Z,YnB#IilC ;}>5TBvF: GJ;x!i"4v+*d`Ac@\Skci՜,oݻ0=1ӼIEkqs,i>헲(@ 2rp1zD6[EXK۠Y,v˹oSNMKQmF=6/\ %I[f3C=$Rc7s5nk>?y5,?u!ܶyHiNN\ÿR F?{Ħ(ծ'Em@@L| ۹}/Ũ:ދpm.XppJ`(((~agoŬk[GpA>3;8IJ^iWsAܼveRq@EQ@Q@Q@OUlt=.ScM2IrIdc?k_ ߝv/]Aɉʭ!8R |FuH2Mkij,Z]m 6NPJs};}{=z&m%m/q)U9 Ku^9[O+gؼ2]QEQEQEQEQEQEQEQEJg@?2Wv?=zQ@Q@Q@Q@Q@y|:zy|:zQ@+'^^+'^@Q@Q@Q@Q@cºŮA{$sggִ Vz>6:mEeC CX *v(|J<7?i aW 9œ1QT5R֯{Ř c'5ý%][²iv"#NO=H5C⫿Vɶ*w0qc$n C=%a1=YXrkB(((((o^|\=R[@Q `dFNG Q@o|AYVǑL>cb7q/FAܠg x-h%@WR2#4O7VEJ$E `+VuOOpn/?rm1i0>rW8T @=';;SݼK%yG4x ;f\':qw1Yۦe~?$9$2M\??i">Y͵шcQHھ)? =ᕗlVLv/֒Q=criha>v;U@9,A-/눿{J6|[D<9x[K]7E9}KcԳ1%AOVQEQEQEQEQEQEQEQE/'K{Q"; 1aL8>4xMvYC*v+UMzy/$:DV~[W6]$/&:ؒ9F2+:o%຾kayΨ̥F#$p ¹)G"50%mV3au-巛5œ B(̸EPEPEPEPEPEPEPEPEP^Odz %cQEQEQEQEQEWJï:נWJï:QE-N-NQEQEQEQEQEQEp*zy/ʟw^@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@InQzx?ŏVwzj;ıF%շ̙m`⻍ƗExr{u)*7>]QzQ@Q@ymK-Vu:܉4챨vY20@ri#'TԧiTb$KT .Kv<3nO@?Sn(((((((?Y3w%WCC^.'-070gvmz:_ Z3Is{M|lmܻB` >ǢXu~]I )<:Պ(((((((((((V:qjv&b~? 90Ep^){?Cᖗt\ZLbٿxFy@噫( ? E񎖗=sX `'#lʷA#ܮ?5^"XҵH;%!dS m׃ !FT5sKVg;Tuf8Qq .W-";P6pnV jhy5OkܶyXc'Nl2iMlc_bŘ,IcdEQEQEQEQEQEQEQEQEQEWCI^^KIoQ%u^(_]𮫥 d!RBc# 21Y^&N.ۥN^1G]HN?#٩oG ; ; WF<7ᤆ[hP#8 @((((((((((9i&t*>#_Q4/XWfie- 7ܷc|̞~sɩ\.//݄/ AݢO {+ѤܿLOnA@ܬ?MZE,.?3s}_Ŀl 9?QEzc73_pa.Xǒ[Dk (-D+G%~+(?Ca@<߈L?oc~7u?IsطK? s<O~9nO@((((((((((?Sn+Tۺ ( ( ( ( ( ( ( ( ( ( ( _Ht/x҉++ !пJ$@((((((((((xmm常8` $Q@$םxTMc_@o5ll2dY_)39̓Ɏ4NNYA#"cb7q/FAܠg ,o;8,.໵;&A"6  88 ¤n巸9 I]H#WxT',c;__)\\dPQ\}qIxswB7!a ( ( ( ^uq?'Z ^uq?'Z (<ſWOIֽſWOIֽ (<$Zk6;[u6!{]n_Ht/x҉+(ԍt&(?R7Mo@<.H7G]n#wFɺ (A|yg W# qH++둃6'uwFɺ (ԍt&(?R7Mo@<.H7G]n#wFɺ (SO~޹dٽ [s @ýzy$:Du! jK܃nG8…Xˌ#&V ͎/&mʌȮdBzwOtYmɶKi~22y?1Y[\E׮R)QLo0Na)Q@4%- ,K:JvGWRGdddV=b֓UR38Ko-Nm zZ ݭAj`d pFkn. 9ǚ@#*05xwZmiv.#U>$4W2ɁP/"8Y${29$~ؠ p|@Fj2ȱ:i0$8G9N7x$\y|ąw2c`m'<+/zP47>Ϳv1MYOE!:{"̖906<'4b^.ڢO?؁,i2ws&@sZzv&vne,]j:̠KOImc9g#*ĖO*>U8kФPJ%Vɐc*/}yhK|,HѬzԚ_tfV݄k( Ǿ3t8ˑ\TnȬ+^JGlfiF t^hSK;()8ٌVF(7)O9j7]6 Lc@Hi+t(((((((((+ !пJ$9H*Qzp_PQQ<7V\[J6 dGjJ((((((((xmm常8` $Q@$:/R$KNK˱QL ܅U N,qyHM>?'jW%sg#Kɦit+2A"BB pT,+,l,8- ;!1.I' 8$ƬQ@Q@Q@~%xRA=-.=q eTp+oxW׆+4; XѸv;mP)Zzew6w )S9AW+/N6 RY]D <nj2]p|0n!:ާ=BY~PW`r9U6m s{R^*'&TZI +ƶmJY^x!M)쒲p6Fw9sx~SKo-̷!JJv+y6cOu*O|\HH*F[Fy4GF1YZY Ҁ->cGv;Iwm[V1 F$љGU UrG8gޥ M5WG ^PS <o <0^\%ȸ"B"ajymOHmm坯8[* ] Xu 袊(Huw҈ El=|앶ad pVow:6xUx&܅-YFH Fs^\ߊ۔t&'r@,Nӕ$|wWMif Tq ^6m^LF9f㌓q\0Q 0y P!bǖ;g 30 ~4мSE]"LW00~RI\@Q@ߋ/.k2OHhmV̳,e,1ۯA i<:es}"M$NTƱ^3ʢg$89Ѣ(>мWf-u2 !o.'ٿ5Yۿc;su4W%P-ƏD!OQ^?)@?E?(@^7 r?)@k:g.͂ڞ`}~PqEPEPEPEPEPEPEPEPEPEP^/+^^/+@<[aH<#.1Ɵ!AZF [I[qF3lu`˒8N+riMˋqs,1$'$EQEQEQEQEQEp=3zFAC@B :?iԅtW ?'ROQ^ O/H^9?g@Ey-?sΏZ!xaj4.,wn`.csi$?1|yu[@/sȩp>Vە{=k}ON}-nxfO7#d>FA=+_z4egn/. <颲F2cFHPHQ^ O/H^9?g@Ey-?sΏZ!xzB :?iԅtW ?'ROQ^w?Ÿmm常Ga$/$i!U I|9IԡtkRdX/m㸍d0WP3hQ@Q@ko-ıH^I$`I$^#v^Kwkq[x)2Wn{!Wt_I},%hSblyqxK:ny'ش"xrvp(~` F2w<Hj=>er XI u,Fk"@TP0% 'u&ʏHmgs8ʨG wM]kTAymuxe>"BʽHL~EftWiX8c1ڪ<x4t.:-%—d#p`9ϥhQ\M'Slo"s {@:֕wzvڝJά+l9ЌPGt_oaYG0(@pwFʜ`8(u7XIOU߲- ÅeX=ybÄ>k_t/ཱུl vêʜEhW>֞S=gsZjif ~uX;+$Q*(6ky|h08b'.r *7mb;+[%{k+[%{h(^uq?'Z ^uq?'Z (_Ht/x҉++~qxVd0jb4\N&I'?}? +V¬?8((?YSqQ @gO9aG*|s€=U>?}? +'2'|3ێ{Q @gO9aG*|s€=U>?}? +V¬?8((?YSqQ ow: {zw2ݬ )+(((Ğ мS˨m݌W00Ғ~Rŀ9\]r^xgW F7L@,̃<)x>$7Ii'<|.r`7 xI\sW {um%ǩX?ppw 81ր:+լdf [9HP?y lR͒k/ٛS5 Ir2i@28 ( +'4/ yqj7{S-s$cPN)fJ"0Y"G`I`r9}⇄tx2o>-De$*c-^co6Q<3&7#dr2 _(xo<#~<]>S5~Hʒw( ( ( ( ( ( ^p'j ^p'j ((m]^ڵWݭ{HI^y?*T%ڽoqg=ػehNi +[e'ۧ6W crgڋʖ7M Ģ F@KΫcKܯ0(\gޤVmf-"XdJdTF <8=4rqt.H8ʜwWYu+3=!:GR9P=,,_m9 XAA:V_ѤT;r(DDz7 NvЃZ<}H[Pa~-6 9۝pz97nWWwlZ_ g&* QH綪7:ƛixS_ڥe8碓o !mCX <$wnvH }OSlᵽa\r7c4 f>7;1_j<P+{nxd=Xt䷕ H@@].!i-Z3pJ%㑗dd!g:xMBɡ^(wW.b)2!0AG\+SY QWhNG#j?9᝴MVX,X:qt=H@pcȳi`g+"NN ,3ԑ/?ͥ͝:t ̃rWkT:&=W$κd^D*^nӀ^2s '$g%CWQ+'@EPJï:נWJï:נPEPEPEPEPEPEPܩup*zQEQEQEQEQEQEQEQEQEoϧ5M6SorO>63]Ex> ^ c 4j<̰rFQLh/7aof7iUGǗ8*+(O|9[Tԯθvb;’T ]ePEPEPEPEPEPEPEPEPEP^g_J\Ok[a Ln!+0a$>xuxXgsP۹v&<8}EW4k 8[XSq;Q@ 2y8uQEQEQEQEQEQEQEQEQEQEQEQYz imkWZ bzUp.-YRXdu _r y' `@XxBkZILRi@0pAe`O^,"KĻUϚ5lA2d'/—$w6{NK " +U cq z` 8օqWBmOH "bq+|ce,SX *rq?_=D!K=R%-wa spQdʴU=+U4}OL7*ta *QEQEQEx߅ Í'Vմo_OydݶgQ¸R_?^ۏ9G/$:Dнrw>#Imcw}v<$IרWKJ_;PU-^ŵ=OY-uo$"Q )\]<:ey;x% M9 Tm q|??qb.,/ mLe`ŝT|8RG@f%ŭيnė 5 e `^/ I٥_.R1P#g3먠!Nԭ.KU,;9, 1"6#*x8 €,Q^ft{5D.s/cflI9cs>Ga+٤ڸxsIRD<FFFU'7(+I,|AvSjI,̓BV%hP:pYGEy^ ִ/@K ;G XC%>pE(ߌm:tMDGW\r9H'D3VH㹂keX-6+;A7 ``Qx>K-#.%\+!( ;Hlm#"10OEQEU=WUOS7+Q'$k#X6x>Ų"3K(b x9zoۍ[Q[wE(Z(.'`rP5WO)O d%Rwg69C*G*]g#;KK 8@EYg* GXgnQ@7 r+'G/ʟwG|:zQ@+'^^+'^@Q@Q@Q@Q@Q@Q@7 rנWܩuQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQYz imkWZ bzUpG|wM+MFim `qh^Zm^Lf^!R<[j7k4fF){<1a |-д;o}s];Y-M̯B9 MWa}aggiݬ AS$uoż9#`FApA椯7OkڿUdѵ'kI;р]۾bNBVī;{i_R|\˸#av;pX(ɠ(((((((((+/_m--j;K@7,Y@=N<z@>?y5,?u!ܶyHiNN\* :/R!)E7V4iMlc_bŘ,IcdwA]oxMS( $w0=PEPEP_n4Fmo./غaty crs@c^Z*4oح1cC`2{JGt_oaYG0(@pwFʜ`8 +Rqߊ<&VK؃KZ.aĕRF4_{j|$Ul8#<Т(( !пJ$@?%$B( { L߈u IƵ͔ԚrE nP&R7MנQ@o.H7^Ey]n#zwFɺ?ԍuP&R7MנQ@o.H7^Ey]n#zwFɺ?ԍuP&R7MנQ@giuKo,[ћ]J2Zl7t.i쬡$d@q+R(((+WÛ{T^.|KE[BmxRWp${J(~#Ǧ^:mՑZK|c $ *U=WJ43S6Ka +~,i dyBfLL,QX~v-/{NF9SocG5@Q@Q@W/I'+iS:6Ngr&~\ܤuι{N{^ +U3q:`(8WJ[ LLP]ϓB ߈,7%hi uO^G{1X jqQϢP#;KK 8@EYg* GXgnQEQEy/ʟwG|:p*-NQEy|:zy|:zQEQEQEQEQEQEy/ʟw^^7 rנPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEg:9{,W#|ύv̀p$\%)!f]VWF|)Rvι{N{^ +U3q:`(8W G|_i_ٺcWz㷃>Uџ pTZ7ý.QMcW}{]?oN(6!ġeew+?Fw)jOk1ؔ8, vQ@Q@W䳿LoxĈ  Ey Džy-o`ک{3g̋w8'sV,~%YGxO`p>] 9ۂFMwz_t l&vܧ  hQ^_' 8RQEQEQEQEQEQEV~i~ӞWr7@'j 2N8׊%=[²SGwvX&"#rN O|BH5<=[Oeɶ*v;0s$n&~z~$4S2ljaN@ [$4 ik1Z/Ibzf$2I Ԡ((mkwsyo峔E:#cWx4QEQEW ӵOGj{2tDc%ǢQ@?~!$~UDQ[ܖ;A8sIQkV^#:[iՌwvbTYH*z8$t&w_Dw{V$i.mBnʇLunTV~i~!ӒHհ7Hk#*pFyxBLjljI3oSx IKIoQ%zxߝKRG#lθvkdtJ((((((((((((((((M }cQ:ޑ>!+\1XE8ӟButOhkA|!૳|v'נU=WJ43S6Ka (^){?Cᖗt\ZLbٿxFy@噫𿋴_i0(,r6șʜ{d9 u/sYZFQ՛FI|BH5<=[Oeɶ*v;0s$n$Ѽk mkI(1m4N; iu⿉h`~ݖ ȅܓ#r<9x[K]7E9}KcԳ1%AOVQEQEQEp*-NܩtxJï:QE-N-NQEQEQEQEQEQEp*zy/ʟw^@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@_ವ\>7 ڣ6Œy;O7><?`cZ.bL`:k:9{,W#|ύv̀p$\%)!f]VWF|)RI|/cC^wxqs0v@$FWmwE5^it`Q;؆?@8Š(" 2+,E ʁB6we,01{}3N˵JۍC]]JGVy#7N#el1y9 kYt-H|#о.-_ꋻ8TuX2SFE-s^ ЛXMh-9BU{ ^xq͎bIp)=v@+ݱq Q-ou%y'9qdgn6"wXow9&H3<7-d"N"Ԯ%!pPdWK×Oo.r.FLx`Xbm(l8bkִhd%RGm2(Pt=/:sj^ڶNɓ;InS[(?_>5_-19-G[ ,I &}>j#gr0eR䪐rIV~~!ӞWղvLH#r' 0Fx4Ey")H<%]32fWb$9/#rnhy5OkܶyXc'Nl((Z:-) D3$V'ν"լ4ϳ5 6v$tdӭy x/?/IkC/ˍ*2py hSiYX!1YO;$F8Yv3li'lV-Kh##deX؀GzѬ.5\M/ݷE(Os\^Lou1j>]p&9dG)$wc^jV剥;oy \2[j6EFi;#Dfp+ jvH^؋8cH0帊H )N1߾o=)썑['2/W(.IZqDvcoL~1~gw5OSԭ1us3E2wI"ƿ@Q@Q@>XBZyLQi0p2Idnfb o CbN/-*c$dq0r\*1^GźG4GAtOGy{32K#`Acݵ<Q'o!c޹Y.q n*3_O׏ڭׁȆۻ+7,( 39,'PT{QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE4HuMVmWXҮW}S~U~UJg@m-t;K@),YRĖ=I<:ZQ@Q@Q@Q@Q@7 r+'G/ʟwG|:zQ@+'^^+'^@Q@Q@Q@Q@Q@V{ ]`]kB[7\~FV!0%~lHleEsp*z|g7>*].h|$yF}c#ͮ~^ϙ}G ےLH q`N@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@=≼Oqa~v6#- NLFCE^ᏈUZiFi#)lI N\tÞ3)8MO 8X+H4Q^g p <_rC7`.c I,p9~4мSE]"LW00~RI\@Q@Wώum[|i-ݑ`;pj75wOMԭ[ygݲ;p~ח-=<%$NHd=.b#ժ.ӀjHomooK~,RgҚ)epcQ(b6NF8,şo49WQԼ߳æۉaK|= c ?'s׺^y{bwnVF_c]%y-?sΏZ!xJgUҬu.LM0Ar`:l?ik{yW~hFe&+Svo(xP9fjd AjQyM=6ά ?3܌+ZoW]GIy+`hO)t bwc91,*\ŴIe&G{Y涶X_`AOl>Ho.M[JƝ8kP谙366R?%$B( ( ( ( ( ( ( ( ( ( (L$2"H3)E82+橮jzX_ h`%U\^JT*?J2z9-C_+PԤטOf< `-efAG2r2N}(j:Z8u)՗I)fdDͻpk(((((_5Jg@(((((Tۺ<[%{hSno_u@([%{k+[%{k()x7ÚN d_ePÕB gyCI\<%%{/?(v<$?~Wn]?a+7G.߇0@<oJ ?%q(?tyCI\ (v<$?~Wn#čMW wk?#w7׻yCI\ (v<$?~Wn]?a+7G.߇0@<oJ ?%q(?tyCI\ (v<$?~Wn>/Sm,2T$sFJ`dֻ%cנPEPEPEPEPEPEPEPEPEPEPEP\<x˗Q} `a$r (gM"}"ԠAϵ߰~4мSE]"LW00~RI\]s$^.]Fm86bvs,(?7R;>_gw~º BOw 1\yK$esMtQEQEQEQ^JLOV<K\ei&$pvw  !y$($sGOyIG{ݜ iN2B?+棏ᖥ{y]SG3Ce.L3aV,+,l,8- ;!1.I' 8$ƀ8>M\EVMntq,zt`anb1̅IuܭA6[0D#5 `*J((([%{k+[%{k((((X]ƙGsgp%0`სҚ-n0o^Ea_/tcVK9dLNU2 p~(m @"Era8QxQ|=kHq 6ƏM@uFpTcJyEPEPEPEO.Jc)>K;7 p1+۰Eu,9o5+ 2?\Zh+?VM[t4@.((Gˀ~_A_6:.IxwvT]ڑ/SvOJҬt=.L-MD2I$I$䚹EQE_WW’yBN?I|<{'n?zнrR_?^ۏ9@Ey)//vPQ^ K ;q(%W’yBN?I|<{'n?zнrR_?^ۏ9@Ey)//vPQ^ K ;q(%W’yBN?I|<{'n?zнrR_?^ۏ9@Ey)//vPomakisyq[%K;n'{Tʊ83zV-n"+WcHWv’yBN?I|<{'n?u~o".^Xsi,B2[нrR_?^ۏ9@Ey)//vPQ^ K ;q(%W’yBN?I|<{'n?zнrR_?^ۏ9@Ey)//vPWS+ƻR_?^ۏ9V,>xLm/.T\kN ր;( ( ( ( (<nOſWOI֏_?^uq?'Z (<ſWOIֽſWOIֽ<_W"3Iڽ_W"3Iڽ ( ZD1Iy#O*$'|Qf8:{U5^ߴs w ж73$}C".Z67q+g;^w XgjӠ&4-f]T{a-ف!hC|*XV2'VO}'=Ma"B>CdS~PQ^{dr[]R&ʑB#T6H0bH9Mhk53[9dO&9$HK73 쨯(umhMjܢ7I,g%J G`7nOP=("%y "6+@9lmל^xG] C}q-PO,l>WPj Q>c{hO{5XrbԕP]_Mi Ļo"ﱟ>TcJbjVk3k0[pqymWxY‘lvZ\|Î?Zvuחo &M6.,m1v; ^OQ(()̕c]^^Odz (((((((((((((+'/r6oc 3`WHP!`g 31' ž<ڌrNt|(y pMtχg71䳨?ti[[OJԵZF!o@|nr9 h+gqy&>jIEy\cvJ85kx3*ye'nXVL KX#pIhXG<{J/of?l$m`qk,㳰<h$(dEQEQEQEQEy|:zy|:zQEQEQEQEz_t l&vܧ  hQ@f+h w đC YbP P6{zGtԴ[ ޠVC+T8 pAEjW/>'|+wQ"7%'B>N~ldڠwWx/֞QsZjh% >F9rX;+ľ-<)oSHgs'$h9$ FEr/\Mٱվ *<9|և%~((?Ca@߈L?o[W€=K~!0Q o?&_ +-D+G%~((?Ca@G!q?}܇NmsZCa@߈L?o[W€=K~!0Q o?&_ +-D+G%~((?Ca@߈L?o[W€%cנWg~.|7 l5[? !Qщ=:s^@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@yk++c]@EPEPEPEPEPUç\}{"'ɷMI`Q@/}# ^V[3[d RAWxSGPmn崳tOI)$!nI^72: |gxk r5upO P2* > u3:&sF~PHPzPIEPEPEPEPEPEp:/t[Kkn+0bKN_1o%5CSաѾZ[,.wkLk!PUtnI@5KdAV8a3'.=w[ {Fd>I*ckE+ Vd;V6\o|Egw6zevvZZǝ$ OV( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?}? (> iŭ|]s=ﶒmE]l%2*G?}? (V¬?8+(?YSqQ @<_'<#MK\nj$(wJrяzHuw҈(((|kfcz^p:8 c8uw7c]\؛ vg ܬTܥN[P6ZCimqƽT`_ ^p'j ^p'j ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (<gο5 ?ud@(((((((((ſWOIֽſWOIր=(?o_u@?o_u@(((((+kVMJ tѐq$dR `donO@,4x~_wVŭݧ@rw6ukTZڮnˍ!$ !85 >է=^\BB4gR4CG0=k+[{he 7x2l#X>ɳ_(7g1cz`9# t_\MR쭔M,m/ڮRC'֎gVͱ_ < [uR$io $2F)W (cTd RI4]9팞iP|cvc8g^-ť6ip Ռ!vn'v4z}EUf{Ҵ_Dd& ldbU:N $m$ '=Ӽgܭ֥uc.1|9PAQxW՟G\Īs[ ^cNܷgI73)Y&6 2AsQ/>4-1T`0\=;d&8 _Ѵ3NY,gx/wfvNzcڞY]^_}c$y#$n_hK%WB!Q'(p*Zc8c,϶5 73cܒI=&8OHuw҈+6!J#@(((_W"3Iڽ_W"3Iڀ=((((((((((((((I¾c5_]ISɔ$rGU?cyCI\ +v<$?~Wn=]?a+7G.߇0@oJ ?%q+,k%k=XR֓¬Trrm| )~O hu^=ON|[#r0!BddҀ<@ji>`MO_庆Y4UE* ckn-ho.uH\yb?5hrrp:fXQx795mg\͎~7S. g׷yCI\ +v<$?~Wn=]?a+7G.߇0@oJ ?%q(?tyCI\ +?DjM,g˱v*x`ȭ ((((+[%{k+[%{h(^uq?'Z ^uq?'Z Ǿg,AZ]G{n9ƫw?WZ>{cgykIvfp:z ?  h51ס*A<B?  h51ס*A<B?  h51ס*A<B?  h51ס*A<B?  h51ס*A<B?  hxWs|aN״=J.vќb0*=M}'<ko|?  HTP0b*h.OЩ&NC^?; z a*h.OЩ&NC^?; z a*h.OЩ&NC^?; z a*h.OЩ&NC^?; z a*h.OЩ&NC^?; z a*h.OЩ&$ƞĺ4#;$ܯ+FeƗi3,QH\ { J(((((((((((((((+c]^^g_J ( ( (4̩0n&TfEp $dgk)ހ6謋hv\_,Px,YbrBG=1q_)7MlUf],7Q@(K^ⷹVKO!QնFsTIݞKdyv5B$ ٢Ě<:e_j$@d[@a篡gnu̲N [M3\"'3@tT6)wmk*,M ?SPEPCI^^KIoQ%zQEQEQEQE-N-NQEy|:zy|:zy|Egw3U,NxKJ_;We[^W5G4p]Щ(Pi摫<7˭HT{'~K&Y^*im4ִ9AcBWq(,{2c6۴1l<ĹVpK{RQ0`?`?K=6k g"'AOoqg[kíۍ;p$w!TN݌8滿'5y.-bż-3C+{%ؠd\HMo6Z-$-"u\Fy-wAE7>`~QeP$ۏ3ې3ڲϷwϝe>yQvb= ).[#tDQOM{h.oH ŸewQ^Kc-/~ܱ\H|ё"˃ JFmQ:MI"kKm=Dn3ڀ=&P[+nmؐ u$=?Pм1cmgwzT1.92En6r}BUŖE^}n5Hۛo+&=[!I###-yaCn-H5ŖgPۍ߼ϙn~lm n6%XD+m%n'b\+p2X+Ч!Դ.1D1Rfݷȍ>Q)gK^{ka05Zz˩WtR$DIʲS'Dzvg ^+nX ,5!xe rr.EwvweYb[-/>9cfLX`Cq3k,uiyB;C[fŔ?(\EX8 Rx`o$^/8+((Yixy5%cV32p *ZQua$1̷7_s\[ Bb]P;Odz %cנPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^g_J :}PQEQEQEQEQEQE-N5;ßjgG̗c>Тy p+CoJQ^ ?%qtWyCI\?v<$?z~Wn]?a+7@Ey.߇0oJQ^ ?%qtWyCI\?v<$?zy|Eg~Wnzw#Vn>c?w.Mau<0rPQEQEQEQEQEQEQEQEQEQEQEQEQEQEp*zy/ʟw^@Q@wtkJ[ ?NkUI -6#9QLpsڃxPR{kco#NωB\& 4DilǺǓسHr2vdOD—:nGjWmbiTmq< kCvڄBmDrpTTp+HXg85*hv'og5땞mQLo ;*r1WQ@{.[. /-_x_4_g(9+K@$,Igg-FP X A\tŠ{I\o:8C[B : +iԅt ?'(?RO O/@H^9?gG-?s΀=Z!xB : Ed5ۨrRO O/@H^9?gG-?s΀=Z!xB : +iԅt ?'(?RO O/@H^9?gG-?s΀=Z!xB :>)̕c]^^?_xQ𭝟Wg_Z^M5ccRCcp <׀5S;..U2ٕ# x<5{?)//vPQ^ K ;q(%W’yBN?I|<{'n?zнr7m?dk'̞kɗ7 $QPQEQEQEQEQEQEQEQEQEQEWKJ_;WWKJ_;PQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQESUTL8'M'f9ٞ\F@8:}WW3[\\K0EI*OkԬ㻴ͷ&9FU8a$hQ@Q@Q@Q@Q@Q@Q@Q@Q@y|:zy|:zQ@+'^^+'^@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@InQzy$:DuQ\n]i3QbɌXIdy hK4|(APN{rw>'Ѽ'uZs~qamI,`T zj6z"Oka@ewrNWGw:c{5Z\@qZ%!ޭa\r1@G7r x፣v_ z0$OIcc@A%"KY`0d")|2$`FA ;>^Iim:R$iP`{ tVwex4HhdB7lsEyFsh?{$qd弰 Υje$ $fkg ,!O^7 rUmB}[:.tT]Aľ{8H֔mw/,T .2Q&R7M:-(u;^]F$ _ 97oop8*ÿ>u]SKB}Eq[d[TLO_J?ԍtW&R7MQ^o.H7@Ey]n#zwFɺ?ԍtW/ė.&_wW^nHAWAI=w ( ( ( ( ^uq?'Z ^uq?'Z (<ſWOIֽſWOIֽ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (<ow: Huw҈tWyCI\?v<$?z~Wn]?a+7@Ey.߇0oJQ^ ?%qtWyCI\?v<$?zy/ʟwG.߇0 FwY/;ϵ ?$a=~tQEQEQEQEQEQEQEQEQEQENNQEQEQEQEQEQEQEQEQEQEQEQEQEQEy/ʟw^^7 rנPEPE,Ӽ[coPlI,y\6Q\-*[V;K)d8 "mP󓞘j:|uiK=LcIjj$}9Q5=,\CǠ]ݫ'%¯烌 oW_RVNK{\JK9PB1yDKoK3Ʊ$N%wzlc/&Ldqa`¿%壳+̎22`|9A((?o_u@?o_u@((((((((((((((((((((((((((((((((((((((((((Oxg<%HTI!1OƏ~*ťڟcV(]X s ռG4I#C+ q_L5Kn/Les Sk?+ vJ=3kW~=J[D p `bHb` ((((((((((((((?ğ,GsKKAgLn9|+?gO9a^Ey*|sU>z?}? ?VP¬?8(YSqWQ@ gO9a^Exy?H~'nsn=KeN[0=YSqQg_J U>?}? (V¬?8+(?YSqQ @<gO9aG*|s½#MI䵵߱`\vsX(((((((?o_u@?o_u@(((((((((((((((((((((((((((((((((((((Fx?tZ3hodݶaʐG  zy|:нrR_?^ۏ9^Ey)//vWQ@ K ;q(%^P5s<2IǥpнrR_?^ۏ9^Ey)//vWSXy$Vh8>I|<{'n?нrR_?^ۏ9G)//@<vQ K ;q+(?%’yBN (I|<{'n?W;coi,˵-0vŒNk+c]@EPEPEPEPEPEPEPEPEPEPEPEPEPEP,ƻgο5QEQEQEQEQEQEQEQEQEQEQE-N-NQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWJï:נWJï:QEQEQdhٔ錩d{+4}sSCZ ՄDm |kXtGU;Pz )RxVl^jw\0xYcn' 0JS}.C3ZIzAVQ3:2k(({ɪ.Ѵ8#*K$#qabsA|!"^M_ j8=8{PXVW\#--RQvK,W$TB75k*uI,-nehܲ<p]Hb0OI8=)$:n0==yG|c Yf5{ ?Kw{y#$/3Hіchۂ84xZ(QEQE ?ud@?Y3w%zQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@g_J :}WPEPEPEPEPEPEPEPEPEPEPEPJï:נWJï:נPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^+'^^+'@EP\nj UFqtbFmEy~]I&WVQbVTӀO#݃8=}wYuAk%EynPHN܀6HA(<}CS>&oV]x;xƚ^[r1jް]@֗O7F%_%q%8+h+ 0pks}jk&a Ʊ?!pu#~ 5j:}143&⻑p{U(+c]^^g_J ( ( ( ( ( ( ( ( ( ( ( ( ( (<gο5 ?ud@(((((((((((?o_u@?o_u@(((((((((((((((((((((((((((((((((((((Fxs?umZ0hgۺQ‚O$z~Wn]?a+7^Ey.߇0oJנQ@ ?%quPyCI\?v<$?z~Wn]?a+7^Ey.߇0oJנQ@ ?%quPyCI\?v<$?z~Wn]?a+7^Ey.߇0o=;ŗry^%FaS#zEQEQEQEQEQEQEQEQEQEQEQEQEQEQE ?ud@?Y3w%zQEQEQEQEQEQEQEQEQEQEQEy|:zy|:zQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEyk++c]^@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@+'^^+'^@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@g_J :}WPEPEPEPEPEPEPEPEPEPEPEPJï:נWJï:נPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP,ƻgο5QEQEQEQEQEQEQEQEQEQEQE-N-NQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE$uq-IJM<^I$bNI$I<棢(((((((((((_W/xy+((((((((((((((((((((((((tomcat7-7.0.52/webapps/docs/tribes/membership.xml0000644000175100017510000000210711471202736021704 0ustar locutuslocutus ]> &project; Apache Tribes - Membership

    TODO

    tomcat7-7.0.52/webapps/docs/tribes/transport.xml0000644000175100017510000000210411471202736021602 0ustar locutuslocutus ]> &project; Apache Tribes - Transport

    TODO

    tomcat7-7.0.52/webapps/docs/tribes/leader-election-message-arrives.dia0000644000175100017510000001324410501326454025636 0ustar locutuslocutus]sHrJrUn|+:}qA"L!G*V=J6)9H֍vmHC46ezYVX\Vr1}}=۳?Nߴ|bīW^%ej2+oȲxlEο=˲/o0W9l|ˋU-y"nfze5S>{}G66ǹSn}]۷_W-i5UKX~M?|]_jr[vai;Nrnhm9Y]}-j~ey1+v}rw~xほ[zBx0)'6\rWі$f]Qoj:[)TS\0n/z>1_}Y>f n 2ѓ?mؾ} x q5"4Ŭc|S#!H#h]jNLI̝F Tq1J@yQ$XfHlbH,;aqZf6bq3_GrlF;mu~@gli{LdoofoT,[ֶ jay1;~by'eg+fUyhce #)w AM@ގ$_FkSw<ȧ=]̋/Q`GYy᪪-~4PÉ4?l E2Wl  /Q0 BɱicF:*.Q$gH[m"B7iiZ I{:L6#+P (UNS=9rO)Y֗٬//ix !E |A+˧ C `5XHs.b!MĹs\vp*zussKAu6!Yem׃f0y]W߈[~\8hwpY-.idWpaUv_>ӎgcW7:RGX`$(1Ԕz濿5a{ h>=Zi2X`P4kB)32Hp,+?Fts&ۦB8IN8:J6=1j$ qȘ޶^Xn0LqfT6ƕ)V&w%g6]+ פΉs0HJbSj & ޙ%rSa@g WN#TJ5A&>voĄY;MXkd\1:x4'۝\Yj3RJ`TirͪځEJH|*7?`ƼFRѡ=q"J%(FwbFͣDG"@bԼWptT<= A}% % @LmWpp :o]@͡3Iҡ$joG]1 >*|M+[Gq=//)0U!N]z0Vq. };k[ňa\uu_| >FL<=҆y8Rx2Lj"֭nT[sb6 O86&Xշ)VU[aI[Uy`Y7 u3,T=5V8)tܢ6ɰ^ *'4k*rQnۗ J*՜G,VY ?Cb2F\0hv:6NE2F1ťKCp6jۈ`R{b|uDŴ.!:-y\&=L:S=gK5Ǯ%Hx1p4 KuI~oÔ5\9D5 רr\@x' K. q%.E=eAcoNc-+ӃH1v0B[)"۳ ^ ,_LrUL>ICX_X~Ɩvp5)QArCGtƞGTPeɏmGWh5g'>ZPcxn,uD(yh%2uaOv{ vةn\"%WK!nNc(aj ǜN">g/S񄄇Tѳ @] =4M!\t7kq1tfHX9aS5`eՊSWU )ƷƜpOP¼PUT)m!͘| ֯KXHZ;mY θ8mg˵a mi܄DN|p'*5H➥k2`$ג\{bv\:~Nw= r*ɠo )A'%Eశȝ:M l- to :2lqgІmیl NU)d]kX"-WW>U^fg*J` 6lwD=ZCYh"~As-C{ve8\1KF>5MuOSJ-j96V4\'BclZF$w3&{%>~1ė@#!kaD]d➥`+ӄJz7FNnQ']&g+As Gp=%ǎ/TII!˘ZZ)8K/C7S^.AR y:dߝ&ԴpZj 1=C5! n yf*B:D֖S5yMHb/7LWTIG-;19bVb)݃6ר *YDF؆_Iâ1 m*8^FnBDB8pN"}P=pح.wb3So@!B$ö `"" lJ l?z4:6HYHC<7]שax{-<1C u$41ۣx&kAS{KuG1mlǥ2Ky%1XK W0Y,hZ4 B!~l-{b 1yƏ#T$U1y|97qH&\WUv" qq{IkQdLJ[%|9ƢaX:hzϤmY W?VN|.~5u5<<nL>|lH"=vW NV8S{uNjZjSeHsr`8$+qWavu8v@ОFu6p==1ds=۳o4xtomcat7-7.0.52/webapps/docs/tribes/project.xml0000644000175100017510000000441312271304167021221 0ustar locutuslocutus Apache Tribes - The Tomcat Cluster Communication Module Apache Tomcat tomcat7-7.0.52/webapps/docs/tribes/faq.xml0000644000175100017510000000214012271304167020315 0ustar locutuslocutus ]> &project; Apache Tribes - Frequently Asked Questions

    TODO

    tomcat7-7.0.52/webapps/docs/tribes/setup.xml0000644000175100017510000000212112271304167020705 0ustar locutuslocutus ]> &project; Apache Tribes - Configuration

    TODO

    tomcat7-7.0.52/webapps/docs/tribes/introduction.xml0000644000175100017510000003633712271304167022306 0ustar locutuslocutus ]> &project; Filip Hanik Apache Tribes - Introduction

    Apache Tribes is a group or peer-to-peer communication framework that enables you to easily connect your remote objects to communicate with each other.

    • Import: org.apache.catalina.tribes.Channel
    • Import: org.apache.catalina.tribes.Member
    • Import: org.apache.catalina.tribes.MembershipListener
    • Import: org.apache.catalina.tribes.ChannelListener
    • Import: org.apache.catalina.tribes.group.GroupChannel
    • Create a class that implements: org.apache.catalina.tribes.ChannelListener
    • Create a class that implements: org.apache.catalina.tribes.MembershipListener
    • Simple class to demonstrate how to send a message: //create a channel Channel myChannel = new GroupChannel(); //create my listeners ChannelListener msgListener = new MyMessageListener(); MembershipListener mbrListener = new MyMemberListener(); //attach the listeners to the channel myChannel.addMembershipListener(mbrListener); myChannel.addChannelListener(msgListener); //start the channel myChannel.start(Channel.DEFAULT); //create a message to be sent, message must implement java.io.Serializable //for performance reasons you probably want them to implement java.io.Externalizable Serializable myMsg = new MyMessage(); //retrieve my current members Member[] group = myChannel.getMembers(); //send the message channel.send(group,myMsg,Channel.SEND_OPTIONS_DEFAULT);

    Simple yeah? There is a lot more to Tribes than we have shown, hopefully the docs will be able to explain more to you. Remember, that we are always interested in suggestions, improvements, bug fixes and anything that you think would help this project.

    Note: Tribes is currently built for JDK1.5, you can run on JDK1.4 by a small modifications to locks used from the java.util.concurrent package.

    Tribes is a messaging framework with group communication abilities. Tribes allows you to send and receive messages over a network, it also allows for dynamic discovery of other nodes in the network.
    And that is the short story, it really is as simple as that. What makes Tribes useful and unique will be described in the section below.

    The Tribes module was started early 2006 and a small part of the code base comes from the clustering module that has been existing since 2003 or 2004. The current cluster implementation has several short comings and many workarounds were created due to the complexity in group communication. Long story short, what should have been two modules a long time ago, will be now. Tribes takes out the complexity of messaging from the replication module and becomes a fully independent and highly flexible group communication module.

    In Tomcat the old modules/cluster has now become modules/groupcom(Tribes) and modules/ha (replication). This will allow development to proceed and let the developers focus on the issues they are actually working on rather than getting boggled down in details of a module they are not interested in. The understanding is that both communication and replication are complex enough, and when trying to develop them in the same module, well you know, it becomes a cluster :)

    Tribes allows for guaranteed messaging, and can be customized in many ways. Why is this important?
    Well, you as a developer want to know that the messages you are sending are reaching their destination. More than that, if a message doesn't reach its destination, the application on top of Tribes will be notified that the message was never sent, and what node it failed.

    I am a big fan of reusing code and would never dream of developing something if someone else has already done it and it was available to me and the community I try to serve.
    When I did my research to improve the clustering module I was constantly faced with a few obstacles:
    1. The framework wasn't flexible enough
    2. The framework was licensed in a way that neither I nor the community could use it
    3. Several features that I needed were missing
    4. Messaging was guaranteed, but no feedback was reported to me
    5. The semantics of my message delivery had to be configured before runtime
    And the list continues...

    So I came up with Tribes, to address these issues and other issues that came along. When designing Tribes I wanted to make sure I didn't lose any of the flexibility and delivery semantics that the existing frameworks already delivered. The goal was to create a framework that could do everything that the others already did, but to provide more flexibility for the application developer. In the next section will give you the high level overview of what features tribes offers or will offer.

    To give you an idea of the feature set I will list it out here. Some of the features are not yet completed, if that is the case they are marked accordingly.

    Pluggable modules
    Tribes is built using interfaces. Any of the modules or components that are part of Tribes can be swapped out to customize your own Tribes implementation.

    Guaranteed Messaging
    In the default implementation of Tribes uses TCP or UDP for messaging. TCP already has guaranteed message delivery and flow control built in. I believe that the performance of Java TCP, will outperform an implementation of Java/UDP/flow-control/message guarantee since the logic happens further down the stack. UDP messaging has been added in for sending messages over UDP instead of TCP when desired. The same guarantee scenarios as described below are still available over UDP, however, when a UDP message is lost, it's considered failed.
    Tribes supports both non-blocking and blocking IO operations. The recommended setting is to use non blocking as it promotes better parallelism when sending and receiving messages. The blocking implementation is available for those platforms where NIO is still a trouble child.

    Different Guarantee Levels
    There are three different levels of delivery guarantee when a message is sent.

    1. IO Based send guarantee. - fastest, least reliable
      This means that Tribes considers the message transfer to be successful if the message was sent to the socket send buffer and accepted.
      On blocking IO, this would be socket.getOutputStream().write(msg)
      On non blocking IO, this would be socketChannel.write(), and the buffer byte buffer gets emptied followed by a socketChannel.read() to ensure the channel still open. The read() has been added since write() will succeed if the connection has been "closed" when using NIO.
    2. ACK based. - recommended, guaranteed delivery
      When the message has been received on a remote node, an ACK is sent back to the sender, indicating that the message was received successfully.
    3. SYNC_ACK based. - guaranteed delivery, guaranteed processed, slowest
      When the message has been received on a remote node, the node will process the message and if the message was processed successfully, an ACK is sent back to the sender indicating that the message was received and processed successfully. If the message was received, but processing it failed, an ACK_FAIL will be sent back to the sender. This is a unique feature that adds an incredible amount value to the application developer. Most frameworks here will tell you that the message was delivered, and the application developer has to build in logic on whether the message was actually processed properly by the application on the remote node. If configured, Tribes will throw an exception when it receives an ACK_FAIL and associate that exception with the member that didn't process the message.
    You can of course write even more sophisticated guarantee levels, and some of them will be mentioned later on in the documentation. One mentionable level would be a 2-Phase-Commit, where the remote applications don't receive the message until all nodes have received the message. Sort of like a all-or-nothing protocol.

    Per Message Delivery Attributes
    Perhaps the feature that makes Tribes stand out from the crowd of group communication frameworks. Tribes enables you to send to decide what delivery semantics a message transfer should have on a per message basis. Meaning, that your messages are not delivered based on some static configuration that remains fixed after the message framework has been started.
    To give you an example of how powerful this feature is, I'll try to illustrate it with a simple example. Imagine you need to send 10 different messages, you could send the the following way: Message_1 - asynchronous and fast, no guarantee required, fire and forget Message_2 - all-or-nothing, either all receivers get it, or none. Message_3 - encrypted and SYNC_ACK based Message_4 - asynchronous, SYNC_ACK and call back when the message is processed on the remote nodes Message_5 - totally ordered, this message should be received in the same order on all nodes that have been send totally ordered Message_6 - asynchronous and totally ordered Message_7 - RPC message, send a message, wait for all remote nodes to reply before returning Message_8 - RPC message, wait for the first reply Message_9 - RPC message, asynchronous, don't wait for a reply, collect them via a callback Message_10- sent to a member that is not part of this group As you can imagine by now, these are just examples. The number of different semantics you can apply on a per-message-basis is almost limitless. Tribes allows you to set up to 28 different on a message and then configure Tribes to what flag results in what action on the message.
    Imagine a shared transactional cache, probably >90% are reads, and the dirty reads should be completely unordered and delivered as fast as possible. But transactional writes on the other hand, have to be ordered so that no cache gets corrupted. With tribes you would send the write messages totally ordered, while the read messages you simple fire to achieve highest throughput.
    There are probably better examples on how this powerful feature can be used, so use your imagination and your experience to think of how this could benefit you in your application.

    Interceptor based message processing
    Tribes uses a customizable interceptor stack to process messages that are sent and received.
    So what, all frameworks have this!
    Yes, but in Tribes interceptors can react to a message based on the per-message-attributes that are sent runtime. Meaning, that if you add a encryption interceptor that encrypts message you can decide if this interceptor will encrypt all messages, or only certain messages that are decided by the applications running on top of Tribes.
    This is how Tribes is able to send some messages totally ordered and others fire and forget style like the example above.
    The number of interceptors that are available will keep growing, and we would appreciate any contributions that you might have.

    Threadless Interceptor stack The interceptor don't require any separate threads to perform their message manipulation.
    Messages that are sent will piggy back on the thread that is sending them all the way through transmission. The exception is the MessageDispatchInterceptor that will queue up the message and send it on a separate thread for asynchronous message delivery. Messages received are controlled by a thread pool in the receiver component.
    The channel object can send a heartbeat() through the interceptor stack to allow for timeouts, cleanup and other events.
    The MessageDispatchInterceptor is the only interceptor that is configured by default.

    Parallel Delivery
    Tribes support parallel delivery of messages. Meaning that node_A could send three messages to node_B in parallel. This feature becomes useful when sending messages with different delivery semantics. Otherwise if Message_1 was sent totally ordered, Message_2 would have to wait for that message to complete.
    Through NIO, Tribes is also able to send a message to several receivers at the same time on the same thread.

    Silent Member Messaging
    With Tribes you are able to send messages to members that are not in your group. So by default, you can already send messages over a wide area network, even though the dynamic discover module today is limited to local area networks by using multicast for dynamic node discovery. Of course, the membership component will be expanded to support WAN memberships in the future. But this is very useful, when you want to hide members from the rest of the group and only communicate with them

    Tribes ships as a module with Tomcat, and is released as part of the Apache Tomcat release.

    tomcat7-7.0.52/webapps/docs/tribes/status.xml0000644000175100017510000000207311471202736021076 0ustar locutuslocutus ]> &project; Apache Tribes - Status

    TODO

    tomcat7-7.0.52/webapps/docs/tribes/leader-election-initiate-election.jpg0000644000175100017510000010160010747071255026174 0ustar locutuslocutusJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( (N?}? ?VP¬?8(YSqWQ@ gO9a^Ey*|sU>z?}? ?VP¬?8(YSqWQ@ gO9a^Eyo4CZuK[+;rx'zEy|Egzay| ydx˗Hث#yp{6]#T׍V{(n$Xr3bTd?}? (V¬?8+(?YSqQ @<gO9aG*|s½U>?}? (KmºoVS\FjdB(8x.y 닉dytgI;IyG'%Uj< $_ K@xWڏo+wQK a::}P K ;q(%P’yBN?I|<{'n?zнrR_?^ۏ9^Ey)//vWQ@ K ;q(%P’yBN?I|<{'n?zнrR_?^ۏ9^Ey)//LM:c|73WխZ'Ymd5*Ţhz\M,bi(8 㜞jy|Egzy|Egzs;y_]覣O<5`_xIu<Rxnaŝ$׮mH(ofàp}{dΛog{quowlֳE8Ei @ \`*-u{n˧\0f2<ӮA%ޛ֒KH%ެc'x9PT3g8Hng@"% ($,C8+ tFM.y/ lRE4cp2^-Ξ)> 8sJmdlGed+H9>q+GVI⻈'I!2<::Ώ[]v +{ UkU9hE n?,=Hx&;yi[߷!>Ecu9t/Y{ĭ)_"HOԞKTȷP4ԞXQ+"7r9-Gmw;ykLy*0d.3 d7Ý1kIƟ&D3,6 ƴ̒Z5$F2P# x,FNq|<9o{9-xPG#) s@0SMFQ1#^WX16ّ:oe ZVxYFs ʥq.~ g%l4^Vo.UVeB(R6;֟ FW.d( KQCz关-KxHbB\A!J>H ]]Y YLUBY ʪ3ԓT,i^H]CQtmQQ,mΈ ' Ԇ9$\|F쯞ͷʞGhMXpYTxY|AuxgM: `[fQ0x.7kN}@Mn5ݟǯa]xRm&E3"lgy#3$l nq֎⻽sVkigJU24!Lbqso +VoLKx’8nXZ}̗6',Q$"* bIϰ w\AxXf-$L Fp7 %>S+⡏>9yc"E{\+ :q@Տm^kMΣ+"#*GӢŏE\/$p*%wƧKgnֺtĖ%+,-,S6CWຖ9oV ܑp8S}񱸔P>rTry9<Q@|A(~%j~ ?VF}EPEPKJ_;WWxoǚgCxjO5lӗ_*-`d{twFɺ +ԍt&(?R7Mo@.H7G]n=};ğ?Z15n#t.H98]n=#wFɺ +ԍt&(?R7Mo_W"3IڽxoĚgIxM)4֐HFA^J(*E5yZ襫%f|+v{e5m!!C:C\>YѴk.ݼY[oHnE 8=2#wFɺ +ԍt&(?R7Mo@VԾ,5p h,丑cE dQF|YtkR|^q.u #8>=2#wFɺ +ԍt&(?R7MoOx>Ckok  HV ``8z%?}? ?VP¬?8(YSqWQ@ gO9a^Ey*|sU>zyi?}? (V¬?8+(?YSqQ @<gO9a]|#g:Woy4҉$i(bX(v9'(((((((((((? v@? v@((((((((((((˧xڄ,Z_Y>dm137(5 ]TѼKXyWExck,@3nVitGUv \I3re @PK}W_>| <Zj]"ۣ`myQyv;$H[qo,sA*H2AG9 (((((((((((((( ^p'j ^p'j ((((((((((/R:mYPMFi+ Fpj&1׿wc|Oe$2:}U=KVtku5 K,S,J[ g{ηο[Al2 r;o v4zD:LĂ]䌒qq@pxv@:vd#?w~c5ˇFͦF퓂/,%FW܂qA VG  HB(q+*8Uc(;M.nPQ+)Q0 [8;MI #Q_x\1ǸUI,xی1+@ (<O:ţ떓Q`bb]lnr8>Jx[~{j .<6c8=8\+KDjulhy`KXͻqá(?_~tdk;Id3a<;g!sۿj'fs}@ESum7Yk/P\Ik2ʡ RFpAǸQEQEQEQEQEQEQEQEQEQENNQEQEQEQEQEQEQEG<[oqsA*92<G =o>瞺co4|4<˻NzW7')7<-g^I4fE KPn pzf_^Iag>66^i7lpؠ\AysUΉ΁^.0;*uv}ݯ.S="gF85t;xYWoc1*K}ϩ'o?xMB $pĩenx% 7⿂}f=>4&kmI١`@db.N8Lд}Ҭlh$ZM\Kt~Ώnח)Ib3ye?Sڏs\=%8۳ ";'+yc Pp+*#>Q@.RL:E̤ *88chWB[]M l(\\rk(?-;Cu&/7gӼAhDXHpKF0=EuS!u}FMxWH'#آ>|5m[^I$M(+P*9 k{xuy]0,FOnrOD_ 7~GlyݜxflAx#I׬n&wo愙?l8J(zqj03Y.X ,@85wq-5/^DImY<̪ 䀥3Nw dyEyĽj=7G(,vI#'$g2OW"?\Sz~3 =9[&?Y-,P mA4kv؏tgdOBF蛡(((((((((((((((((((((((( Z,8wNѲ0qb6:C@ecǞ+֮ÿ(bYNĀ>L9$ xG" O!yd`HRմn5MBp%8'Ƹ.]%ц Ȝ-'A|p2 ጃ/m#Zԗ;5kyx oRv6|`w!($ qUE81@?]}?6<(ab8:`ԟSG5O?{{F[iG@<ǃm{_ie/]#*rrxW|98H%JA9 rp0}M]K ~Z$yH?a2X|jc忛--]QH[wb0AX^F{J-[򿵴'>_]qg +Sw}s\%=tHݿ?yѼWfUn@ڸRlrHQ^w'ňtWxkYd-V*YB̟|x95h+v #Zy0ΦECY3zr 6((((((((((((((((((xmm常8` $Q@$W}k6XX^OjKzMܼv0 ~n0{UI{ AZ.E1Fp8(mˣnpUsB=hR ;P Qؽ\<z\xlf 5؂TIɑ =9SLWm#7ldqjnqim{c0֦4A5 xZk&(I^1?xt'ƍ!{=N;KX5 ."I$ye>i$1db;J+Yu+7ac8~(BK8dFG tȖ{kIZkx щhӤor E=&+u Uu-R4Ĩ,qv ^-ԭm!tyR6dҀ7[Kx("ƃwy41K^d#S"ux'2~gЕJrʼs{(/Yjj]O?#fd8yawvԸgPN Bye-gXW8rNNpp`ҊdլWPKꉨM*D~\fO9$Fʅ"'sUM)/3I:]ͫ%HEjTprr(_Ysy|;bVaUTaazPrQPN# LxJ(o#վ2cزN(eJ,o;8,.໵;&A"6  88 ‹ =NK;H.dgHʞ/RCKtnA\0ѧ6…BW&O[vC<=oqwdlfcXo6!I@3wGVǙKfs'kBO_+>߲)qEwtsǀW=LJ~ jRci Y]I!LѲ3'=H~"j_u^m < *94ߋm;QAʛ]fnl(r2j\P\4\r2"xʌgfj.nHf[0 oTp+fS Y3h$#`pÃ*s_,4Y#Ki}e8Ql'c=.CLWn.mnw;m `"IS t9 e9:?,GT|/}sSVh{Igvr. +< "Z8BrYKn!l OA+r<|T.Y6+;N 9|Obğ;y!s;jR?fns^Egy:U3gqօPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPU,;9, 1"6#*x8 ¬Q@=_^Iag>66^i7lpؠ\AysT?!]c혘бmxwq0z%xG>ڴIΐäd AֆSڿoXcwg9<лv8Q]gz_U/v.83Pc\=ׅ}gó\%xE$J #2ItOKuݬ_bc pݎxW^=ϊ~mx2kK,4x.ۃW95uuo: f>pdcݗvqj03Y.X ,@85wq-5/^DImY<̪ 䀥3Nw dԚ?OiRgz},ۋ0ov(>A VG  HB(qzznfQY˒*6GtOIV:d̟E6?*8goEzs^Erz'/zw}$ۧhNTB W(((((((((((((((((((((((((y Zm=֙s+=._namk+F%㱒D6%H8qּ__<5M;snwvvDvf*=XgAKsCK݁ y "2`.v:CkoQH8Ppb xWB𥙵,oP`7967dgآ(>n>Vu-)pK(<3ca Ek >3\+Y7(TRY9,~(ImB{o5ūrNw 8'滊t=/:sj^ڶNɓ;InS[R\xzd#m/K]Y7!ta77q(;+i+kZΫvK<.i~!ӒHհ7Hk#*pFyEPEPEPEPEPEPEP S_? j}]U~HW!X3`s"_j?ok>!đpm4~[8YK(v &r1|C /So5P%P-ƏD!OנQ@?)@?E?(^Ey"_hK[z|C /So5P%P-ƏD!OנQ@?)@M ڧȾ!I{y^t4A!n2@Tq'8Iğ<΍$Q :PQEQX,<_Z klTp@\6ZhZJ5 U@Yfۘ2chM'մ}[BXmJ=RWTxcA^PPv1o9㞲 ( +_<,ֱih,e-r3@=MQEu7+p*5}OXq6W NPA%[Aōgd0F#E$G${⨭f??gӼ< nNӂӖ$0-r: ^Ai$ 6ZI8r[o#8tPEP oN,Kv 8׮:^ugږkf\B}E$H<<0K}gnt\i kOʑT+@wfsy'kkM3'j(%'Ωmiu[[~) /o!ϧʍ\е!B?LL1~+.uQxAmfqj'in՘Ҡ 29 wH-\.6qQ@n%XrgxIPUU g}E4n'ҵv:v[L~onR1$\voEv h 6rjQ^wkH[!87dkiąF_ .ԒOxeޅw?j\)_KlFT'ESum7Yk/P\Ik2ʡ RFpAǸQEQE~Wn7kym5T)$rXNF ǂ'/$:DO2[; FG;xUڀ>hթxCVz+>m  c#q!B]H.㱴SI_`*.  v@9s|#~!x~7ʆ\$:ei"C*rWC,!5SH_6>aimfnPFY$glEb6Ϙdd`<7C i4YK;tF#03 6Xy'Y!4]%7}6{0"q\ vťޢl¢I]i\+XY5;pdxc*( >aRT֔~O YhlbHԐ lU\T/j1][w}Yn y >\;@mz[ J; ib kʱe=)zݝ$qcfHһT`f}޼ZzkX^+4U A$𹹳[/Q4m1L.vF`ʧ-Zб=7PU?6!B}ı91q>/iqʈgHUT}8)8̧6ZWҴ m" (s?ivFkPq^@2xHT&#}EV nwWڄ7EĖtm@Ǒ^-KĒ^ۨҴ WbIL ,BqZ1 Ifio.#ho!c4 VY 2 ;;5X]Zm-lp+0bϱw{H"c;Iz0 6cݝ^[Gw%h/ݍ]b̙u剙G>c[!@bIl`zdž>![C@nYL9a3^ uwu" #Yz~bv9h/ u7?zwljdtdR\xvE5w5VWpb(meR0TgLPO-:lkyVwD] R2I|xZP\6iMk "YC>X,Lep$(((B𥘺58,o`v67 g'8?u #nF#[Z<ƣq6I4<-Aca<rbNAӑ W7 E}4) _bϵ! vzsh9,4,Wd)71̀2$@?oĚwi?w˙%u H %Xig^{"3;EUtQ@Q@Q@KIoQ%zy/$:D^LӮo$mby}EҸ6O-`FuOFR%"`QĠQwՄq y(9K soo*8`G~UEPQ^?)@?E?(@Ey"_hK[z|C /So4W%P-ƏD!OQ^?)@?E?(@Ey"_hK[z|C /So4xg'|OͮhV'Sr 0#v$SGp񻼷+O!vI<(WI@Q@Q@Q@Q@Q@G<[oqsA*92<G(?Q[%u; ߼gkYH >`mQF5b^#(]CD<۳eBaTA8J(? x(h Լ )G8`l<rW+8x^.ιAw$x 6Z9BoN'8rV+1NY4#d,J)ڃq<HZ~* 7d,8+ é$$cS Y3h$#`pÃ(Q@!PH$ Җ(C –b\಍rKɂڃ,3q(bxwd5 $2FF Aq4]qe٢(X[Y`Y&TF8 5_qg߉uHw4Za dPWfJ*X")F% *e#btw Gƛ5[z} ;XV%-2B3}\? |-MXhjO/E bl8aEQEQEQEQE_WWCI]:6A{m,Wg,il!UjMg%g}ΦU\r?*@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@7VEJ$E `+Q[%u; ߼gkYH >`mQzc_.5?q4A\6Y$&A$ |C𷋢/VKs `g%r+'5,DrGe.!2sko-ıH^I$`I${/?mK$ExLPk/C5]s[5 {[JF퐀A03a6zevvZZǝ$ O@:oď!}[U;/Ob Jk݉ nx{5xo-jQ^?wgaZSyLex^|Ddr6 Eˁ o0K QϡAy `6Kdž=7@p? 2?inwܣЬI=OYh^+7Zk<8eӌdq@QEQEQEQEQEQEQEQEQEQEQEQEQEyk++c]^@Q@Q@Q@Q@Q@Q@Q@Q@KIoQ%zy/$:DQEG4M?8(Hu=W>YLB#Ol<*j<= vfCཌྷ~BCǒ@܇ q3+bB ^9]>橦mW )Fߘ@hm[@5-2?i5Is< es&:J( ( ( ( ( ( ( ( ( )#I 4L@@%N:2=r5OQk B;5 UW R,p@:+vjRk'YK #9>gڎii+NJue4g Y3 3n9g_J :}WPEPEPEPEPEPEPEPEP e 'I{7yqaw1c1'O&?E?(^Ey"_kOX|Y|2AV\<e  ݯ(:߅W—-cE囬X2C@'+/ \mVѹR6K.Kc%zW$:4{_I,Ѩ2UG1P= vfCཌྷ~BCǒ@܇ q3+b9yr!ۦwJVimRzBWmYIG,6:^U-2j>2P"`Sx՜ieBY7U!pp*vuyi;-%>YXeebW;sWQ@_`(N#ՍĚIw,bEDtͬx$gA+f(8tT~pv1+ (UwtQ&7 m@a\r*Tq^'K(RU޻t;A BCE{ ` 1e5MZj׈d 90Z`0%]6<-#Ѵ=/rXiYZSnc՛eI&9zo8a]ı10`@b0I9zWiEQEQEQEQEQEQEQEQEUkk [Kˈ"-Yq;"<>TQǧY14 Z8KGlԮ^%\` !\S1Eu\EӬY;܅8$d"(?Y3w%zyk+((((((((((((/ \mVѹR6K.Kc%zW$:4{_I,Ѩ2UG1P1= vfCཌྷ~BCǒ@܇ q3+b-еl}]5-1Od MV<(ρ7WCG1,<\T +EvQ K ;q((?%’yBN +I|<{'n?нr=R_?^ۏ9G)//@vQ K ;q(('߅ouC%32y&\܀N\G^@Q@Q@Q@Q@Q@Q@Q@Q@+'^\?7MO~<5&ZGڲHT'7qۭWR7MQ^o.H7@Ey]n#zwFɺ?ԍtxKWki{Ke2( HxuΓK >{}>K4VW~D+n/I*E\FI1ԒzM/\oKY$GM{'6.K6'?1@MEQEQ\ɷ>槝o9ҹ 'ntkO'+oc8cך:+auj%B-n$_*;Iʰ\F sU+0Yere6)2B۶$(بxɾlG>$&+HaI,]Y̋;Oo)3own=;b;+ ,B-b2r7+|[Omm>[yzl*j8pN'4{UK]zhE$clIk8I[ \a;qeח8]d\`15/wѓW>k|k(aiem,'" ọ~ O\pt."a*p9%((?Sn+Tۺ (((((((((((((((((>rķ"MCV3LU m8Odz Wf;<[_3'j(Ҁ="]?a+7G.߇0@oJ ?%q(?tyCI\ +v<$?~Wn=]?a+7G.߇0@oJ ?%q(?tyCI\E6Vv;Gi#22NW8]3'qr_~Wn]?a+7@Ey.߇0oJQ^ ?%qtܩuN_wkF)ËHÀz0(((((((((((((((((((((((( !пJ$@?%$B( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (< ?J _Ht/x҉+((((((((((((((((((((((((((((( !пJ$@?%$B( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (< ?J _Ht/x҉+((((((((((((((((((((((((((((?+7&(?R7Mo@.H7G]n=#wFɺ +ԍt&+;RkxKGh"CsTn6ks.H7Qśym"J$Eeu#x 1@w7ng$V/ e#U ^7*q_[׋#_\'_6IMHp U~Q,޵&(?R7Mo@.H7G]n=#wFɺ +ԍt&(?R7Mo@xĚI=)nՐ#yN^ÿZ((((((((((((((((Oz'ҭHluT&qeA\H'>㘴QwEe.=HXW!}~?6,?bPG"x] _pǷ>rqÞ763 3j ie$k(3vsm=ʊd٣ofc'&`ܐ [8EܳF2#Pee+ h;Lۯm$Agkc6Mf^sֶ<#kѵ+ViJ̀ܚ٢((%%{/?+%%{/?((((((((((((((((Ob2]bݗr5'pmXlۂq]UͷIm[r88PAY#JB7fmBS + =:J( %OpxfY2F0_=/Ss-}LAȪT0R@o\v.<c.6 ܳL: L*pbC"m. EҭG6T =*QEQENNQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEU=[MYѯ`F]J2PoX`GzUE*OU>z?}? ?VP¬?8(YSqWQ@ gO9a^Ey*|sU>z?}? ?VP;}狼 8wW^nV!]Rz(]G*|s_Ht/x҉+(V¬?8+(?YSqQ @<gO9aG*|s½U>?}? (V¬?8+(_~y7Z+3,0_(=砮((((((((((((((((((((((( !пJ$@?%$B( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (o[Ӽ9ϫjgo.}(A'4(?tyCI\ +v<$?~Wn=]?a+7G.߇0@oJ ?%q(?tyCI\ 1/5+\/4)nE]xepwnd WfH$u⯉ W}GC(W'pr;X)y"xL K"I8YPegTl(ڛݰq_O|GijmN|[C٦}@TmdyWyCI\ +v<$?~Wn=]?a+7G.߇0@oJ ?%q(?tyCI\ +v<$?~Wn=ߊtoi_wkS ?8ζ((((((((((((((((?$](ow: (K\e+8c6O#5crqGhPEyk;W̍oX5U4ԭgw`csJ[O2iap{9HtBy1آ(Oi4;!Kp0siEOE,P8F>kdgעBBIM-7\JA2 #*FA"*+-^d5glU~4-U=KRҭv.!]?<,kna@([{-ؘ̍. a~SGF@%ڝjAͽ/<[j^*xn#D o6Q$| 9E ?ud@?Y3w%zQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEנWmCۿG@\~5ɥjW3GuG gnG[ |#tTP& f2 1D,5WU.s3Y[:rvX^O2ccGp8SI;POׯ.BMm]1Xbvμ!u=ROs 8 Һ(.)=Qy5mcAIw_+3x},tDI4x[ki !HW$c5tP5t:e=ۙL{wgk[gFz}o>H9,1) q^EyXIY;jJ6.b ێ| %:іHae[8퓊&^[Y!OF22Q&X {Ix;>:'Sw*O9h&u&[-́X"<.C! J54~ SBJPt*Z.?կ8 $S8_xZ^G[]WmӘL89F qT]miPӮVeE23;X|)$yɯF74K6&DBm8L9eτDyb% x\4HH2 {mwPZxVݝؾ֥nt d9@Q#a>R[:}WW,ƻ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( Huw҈袀<k?ᦿQʗj?ᦿQʗjk(k?ᦿQʗj?ᦿQʗjk(k?ᦿQʗj?ᦿQʗjk(k?ᦿQʗj?ᦿQʗjk(k?ᦿQʗj?ᦿQʗjk(k?ᦿQʗj?ᦿQʗjk(vjO\[lޑgp+( ( (?tomcat7-7.0.52/webapps/docs/tribes/leader-election-initiate-election.dia0000644000175100017510000000525410501326454026151 0ustar locutuslocutus]ms6_Q0_:kLڹCI+EjHڎo?#K"e$7fX2R.~&mq^ JW:N79{w8Vlp+¼]ۋ;a o@]/LB7y;Xeh>? 27e6-*B-(#ؙBօC0X6g?q6TwlyAQ#a{p;BXu8EI#S%mC<'P(ۍ G5G?|೅Ԡ0q%[I%əoxx~"۲] FY@jkr8HnzVqΘp2udC~5[cmi3GKpL1>VO7t"#\چd |@.WNjmo&4Ѹ ŷs/"0Q :|FsE1NwA!^K"EUދ{7Aw)=|.j7 x\d/cD(h/9du)12K0F6X'gD_.``H(aLqJF q@B([|^xi`{_3g4#֢NT;k6! GBG9r b̐إ5r\eH _=~8Ǐ)~ !K1=S9yސQcJ5Rpe!`?('ʦ+[fXr #[V%jȨxUү<? [Ncv`.Ԑd܎UbLjM4쎁uKqZJ>yj~Oa*пѓԏ6P3CSZxxG}nrJ.Za3=Nkg4)Va%×W8H!cTr\̈k9pfS *pWm 5 E.tY<ԀLٹ|~;K(|%feIxxNЗK'Q1cV>H9:?HT Aut]@̚4LXQDT Q eAYO[u# NDbm32y@ PJHPޤ%1_B%yodc{&o Kfq.(T}V@/l8J+F=jw|?{ު|V%k.ƘvT}p8 #pj`.F5OTr/vIǟi%Q09cKV qlV"e/%zXk<}GWcjuy)tomcat7-7.0.52/webapps/docs/tribes/developers.xml0000644000175100017510000000210711471202736021721 0ustar locutuslocutus ]> &project; Apache Tribes - Developers

    TODO

    tomcat7-7.0.52/webapps/docs/tribes/interceptors.xml0000644000175100017510000000211511471202736022271 0ustar locutuslocutus ]> &project; Apache Tribes - Interceptors

    TODO

    tomcat7-7.0.52/webapps/docs/mbeans-descriptor-howto.xml0000644000175100017510000000453712271304167023051 0ustar locutuslocutus ]> &project; Amy Roh MBean Descriptor How To

    Tomcat uses JMX MBeans as the technology for implementing manageability of Tomcat.

    The descriptions of JMX MBeans for Catalina are in the mbeans-descriptor.xml file in each package.

    You will need to add MBean descriptions for your custom components in order to avoid a "ManagedBean is not found" exception.

    You may also add MBean descriptions for custom components in a mbeans-descriptor.xml file, located in the same package as the class files it describes.

    <mbean name="LDAPRealm" className="org.apache.catalina.mbeans.ClassNameMBean" description="Custom LDAPRealm" domain="Catalina" group="Realm" type="com.myfirm.mypackage.LDAPRealm"> <attribute name="className" description="Fully qualified class name of the managed object" type="java.lang.String" writeable="false"/> <attribute name="debug" description="The debugging detail level for this component" type="int"/> . . . </mbean>
    tomcat7-7.0.52/webapps/docs/funcspecs/0000755000175100017510000000000012301126373017523 5ustar locutuslocutustomcat7-7.0.52/webapps/docs/funcspecs/fs-memory-realm.xml0000644000175100017510000002177412271304167023301 0ustar locutuslocutus ]> &project; Craig McClanahan MemoryRealm

    The purpose of the MemoryRealm implementation is to provide a mechanism by which Tomcat can acquire information needed to authenticate web application users, and define their security roles, from a simple text-based configuration file in XML format. This is intended to simplify the initial installation and operation of Tomcat, without the complexity of configuring a database or directory server based Realm. It is not intended for production use.

    This specification reflects a combination of functionality that is already present in the org.apache.catalina.realm.MemoryRealm class, as well as requirements for enhancements that have been discussed. Where appropriate, requirements statements are marked [Current] and [Requested] to distinguish them.

    The current status of this functional specification is PROPOSED. It has not yet been discussed and agreed to on the TOMCAT-DEV mailing list.

    The implementation of this functionality depends on the following external specifications:

    • None

    The implementation of this functionality shall conform to the following requirements:

    • Be realized in one or more implementation classes.
    • Implement the org.apache.catalina.Realm interface. [Current]
    • Implement the org.apache.catalina.Lifecycle interface. [Current]
    • Subclass the org.apache.catalina.realm.RealmBase base class.
    • Live in the org.apache.catalina.realm package. [Current]
    • Support a configurable debugging detail level. [Current]
    • Log debugging and operational messages (suitably internationalized) via the getContainer().log() method. [Current]

    The following environmental dependencies must be met in order for MemoryRealm to operate correctly:

    • The desire to utilize MemoryRealm must be registered in $CATALINA_BASE/conf/server.xml, in a <Realm> element that is nested inside a corresponding <Engine>, <Host>, or <Context> element. (This is already included in the default server.xml file.)

    Correct operation of MemoryRealm depends on the following specific features of the surrounding container:

    • Interactions with MemoryRealm will be initiated by the appropriate Authenticator implementation, based on the login method that is selected.
    • MemoryRealm must have an XML parser compatible with the JAXP/1.1 APIs available to it. This is normally accomplished by placing the corresponding JAR files in directory $CATALINA_HOME/lib.

    The main purpose of MemoryRealm is to allow Catalina to authenticate users, and look up the corresponding security roles, from the information found in an XML-format configuration file. The format of this file is described below. When a MemoryRealm instance is started, it will read the contents of this XML file and create an "in memory database" of all the valid users and their associated security roles.

    Each time that Catalina needs to authenticate a user, it will call the authenticate() method of this Realm implementation, passing the username and password that were specified by the user. If we find the user in the database (and match on the password), we accumulate all of the security roles that are defined for this user, and create a new GenericPrincipal object to be returned. If the user is not authenticated, we return null instead. The GenericUser object caches the set of security roles that were owned by this user at the time of authentication, so that calls to isUserInRole() can be answered without going back to the database every time.

    Configurable Properties

    The implementation shall support the following properties that can be configured with JavaBeans property setters:

    • Configurable debugging detail level.
    • Configurable file pathname (absolute or relative to $CATALINA_BASE of the XML file containing our defined users. [conf/tomcat-users.xml].

    Lifecycle Functionality

    The following processing must be performed when the start() method is called:

    • Open and parse the specified XML file.
    • Create an in-memory database representation of the XML file contents.
    • NOTE - There is no requirement to recognize subsequent changes to the contents of the XML file.

    The following processing must be performed when the stop() method is called:

    • Release object references to the in-memory database representation.

    Method authenticate() Functionality

    When authenticate() is called, the following processing is required:

    • Select the one and only "user" instance from the in-memory database, based on matching the specified username. If there is no such instance, return null.
    • Authenticate the user by comparing the (possibly encrypted) password value that was received against the password presented by the user. If there is no match, return null.
    • Construct a new instance of class org.apache.catalina.realm.GenericPrincipal (if not already using this as the internal database representation) that contains the authenticated username and a List of the security roles associated with this user.
    • Return the newly constructed GenericPrincipal.

    Method hasRole() Functionality

    When hasRole() is called, the following processing is required:

    • The principal that is passed as an argument SHOULD be one that we returned (instanceof class org.apache.catalina.realm.GenericPrincipal, with a realm property that is equal to our instance.
    • If the passed principal meets these criteria, check the specified role against the list returned by getRoles(), and return true if the specified role is included; otherwise, return false.
    • If the passed principal does not meet these criteria, return false.

    In addition the the assertions implied by the functionality requirements listed above, the following additional assertions shall be tested to validate the behavior of MemoryRealm:

    tomcat7-7.0.52/webapps/docs/funcspecs/fs-admin-opers.xml0000644000175100017510000002750412271304167023106 0ustar locutuslocutus ]> &project; Craig McClanahan Administrative Apps - Supported Operations

    This document defines the Supported Operations that may be performed against the Administered Objects that are supported by Tomcat administrative applications. Not all operations are required to be available through every administrative application that is implemented. However, if a given operation is available, it should operate consistently with the descriptions found here.

    Supported Operations are described for the following Administered Objects:

    From the perspective of a particular Access Logger, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Engine, Host, or Context.
    • Edit the configurable properties of this object.

    From the perspective of a particular Connector, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Service.
    • Edit the configurable properties of this object.

    From the perspective of a particular Context, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Host.
    • Edit the configurable properties of this object.
    • Create and configure a new Access Logger associated with this object.
    • Edit the configurable properties of the associated Access Logger.
    • Remove the associated Access Logger.
    • Create and configure a new Environment Entry associated with this object.
    • Select and edit the configurable properties of an associated Environment Entry.
    • Remove an associated Environment Entry.
    • Create and configure a new JDBC Resource associated with this object.
    • Select and edit the configurable properties of an associated JDBC Resource.
    • Remove an associated JDBC Resource.
    • Create and configure a new Loader associated with this object.
    • Edit the configurable properties of the associated Loader.
    • Remove the associated Loader.
    • Create and configure a new Manager associated with this object.
    • Edit the configurable properties of the associated Manager.
    • Remove the associated Manager.
    • Create and configure a new Realm associated with this object.
    • Edit the configurable properties of the associated Realm.
    • Remove the associated Realm.
    • Create and configure a new Request Filter associated with this object.
    • Select and edit the configurable properties of an associated Request Filter
    • Remove an associated Request Filter.

    From the perspective of a particular Default Context, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Engine or Host.
    • Edit the configurable properties of this object.
    • Create and configure a new Environment Entry associated with this object.
    • Select and edit the configurable properties of an associated Environment Entry.
    • Remove an associated Environment Entry.
    • Create and configure a new JDBC Resource associated with this object.
    • Select and edit the configurable properties of an associated JDBC Resource.
    • Remove an associated JDBC Resource.

    From the perspective of a particular Engine, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Service.
    • Edit the configurable properties of this object.
    • Create and configure a new Access Logger associated with this object.
    • Edit the configurable properties of the associated Access Logger.
    • Remove the associated Access Logger.
    • Create and configure a new Default Context associated with this object.
    • Edit the configurable properties of the associated Default Context.
    • Remove the associated Default Context.
    • Create and configure a new Host associated with this object.
    • Select and edit the configurable properties of an associated Host.
    • Remove an associated Host.
    • Create and configure a new Realm associated with this object.
    • Edit the configurable properties of the associated Realm.
    • Remove the associated Realm.
    • Create and configure a new Request Filter associated with this object.
    • Select and edit the configurable properties of an associated Request Filter
    • Remove an associated Request Filter.

    From the perspective of a particular Environment Entry, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Context or Default Context.
    • Edit the configurable properties of this object.

    From the perspective of a particular Host, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Engine.
    • Edit the configurable properties of this object.
    • Create and configure a new Access Logger associated with this object.
    • Edit the configurable properties of the associated Access Logger.
    • Remove the associated Access Logger.
    • Create and configure a new Context associated with this object.
    • Select and edit the configurable properties of an associated Context.
    • Remove an associated Context.
    • Create and configure a new Default Context associated with this object.
    • Edit the configurable properties of the associated Default Context.
    • Remove the associated Default Context.
    • Create and configure a new Realm associated with this object.
    • Edit the configurable properties of the associated Realm.
    • Remove the associated Realm.
    • Create and configure a new Request Filter associated with this object.
    • Select and edit the configurable properties of an associated Request Filter
    • Remove an associated Request Filter.

    From the perspective of a particular JDBC Resource, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Context or Default Context.
    • Edit the configurable properties of this object.

    From the perspective of a particular Loader, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Context.
    • Edit the configurable properties of this object.

    From the perspective of a particular Manager, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Context.
    • Edit the configurable properties of this object.

    From the perspective of a particular Realm, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Engine, Host, or Context.
    • Edit the configurable properties of this object.

    From the perspective of a particular Request Filter, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Engine, Host, or Context.
    • Edit the configurable properties of this object.

    From the perspective of the overall Server, it shall be possible to perform the following administrative operations:

    • Edit the configurable properties of this object.
    • Create and configure a new Service associated with this object.
    • Select and edit the configurable properties of an associated Service.

    From the perspective of a particular Service, it shall be possible to perform the following administrative operations:

    • Navigate to the owning Server.
    • Edit the configurable properties of this object.
    • Create and configure a new Connector associated with this object.
    • Select and edit the configurable properties of an associated Connector.
    • Remove an associated Connector.
    • Create and configure a new Engine associated with this object.
    • Edit the configurable properties of the associated Engine.
    • Remove the associated Engine.
    tomcat7-7.0.52/webapps/docs/funcspecs/fs-jdbc-realm.xml0000644000175100017510000002365212271304167022670 0ustar locutuslocutus ]> &project; Craig McClanahan JDBCRealm

    The purpose of the JDBCRealm implementation is to provide a mechanism by which Tomcat can acquire information needed to authenticate web application users, and define their security roles, from a relational database accessed via JDBC APIs. For integration with Catalina, the resulting class(es) must implement the org.apache.catalina.Realm interface.

    This specification reflects a combination of functionality that is already present in the org.apache.catalina.realm.JDBCRealm class, as well as requirements for enhancements that have been discussed. Where appropriate, requirements statements are marked [Current] and [Requested] to distinguish them.

    The current status of this functional specification is PROPOSED. It has not yet been discussed and agreed to on the TOMCAT-DEV mailing list.

    The implementation of this functionality depends on the following external specifications:

    The implementation of this functionality shall conform to the following requirements:

    • Be realized in one or more implementation classes.
    • Implement the org.apache.catalina.Realm interface. [Current]
    • Implement the org.apache.catalina.Lifecycle interface. [Current]
    • Subclass the org.apache.catalina.realm.RealmBase base class.
    • Live in the org.apache.catalina.realm package. [Current]
    • Support a configurable debugging detail level. [Current]
    • Log debugging and operational messages (suitably internationalized) via the getContainer().log() method. [Current]

    The following environmental dependencies must be met in order for JDBCRealm to operate correctly:

    • The desire to utilize JDBCRealm must be registered in $CATALINA_BASE/conf/server.xml, in a <Realm> element that is nested inside a corresponding <Engine>, <Host>, or <Context> element.

    Correct operation of JDBCRealm depends on the following specific features of the surrounding container:

    • Interactions with JDBCRealm will be initiated by the appropriate Authenticator implementation, based on the login method that is selected.
    • JDBCRealm must have the JDBC standard API classes available to it. For a JDK 1.2 or later container, these APIs are included in the standard platform.
    • When connection pooling is implemented, JDBCRealm must have the JDBC Optional Package (version 2.0 or later) APIs available to it. This library is available as a separate download (and will be included in Tomcat binary distributions).

    The main purpose of JDBCRealm is to allow Catalina to authenticate users, and look up the corresponding security roles, from the information found in a relational database accessed via JDBC APIs. For maximum flexibility, the details of how this is done (for example, the names of the required tables and columns) should be configurable.

    Each time that Catalina needs to authenticate a user, it will call the authenticate() method of this Realm implementation, passing the username and password that were specified by the user. If we find the user in the database (and match on the password), we accumulate all of the security roles that are defined for this user, and create a new GenericPrincipal object to be returned. If the user is not authenticated, we return null instead. The GenericUser object caches the set of security roles that were owned by this user at the time of authentication, so that calls to isUserInRole() can be answered without going back to the database every time.

    Configurable Properties

    The implementation shall support the following properties that can be configured with JavaBeans property setters:

    • Configuration parameters defining the JDBC driver to use, the database connection URL to be accessed, and the username/password to use for logging in. [Current]
    • Configuration parameters describing the connection pool to be created to support simultaneous authentications. [Requested]
    • Name of the tables to be searched for users and roles. [Current]
    • Name of the columns to be used for usernames, passwords, and role names. [Current]

    Lifecycle Functionality

    The following processing must be performed when the start() method is called:

    • Establish a connection to the configured database, using the configured username and password. [Current]
    • Configure and establish a connection pool of connections to the database. [Requested]

    The following processing must be performed when the stop() method is called:

    • Close any opened connections to the database.

    Method authenticate() Functionality

    When authenticate() is called, the following processing is required:

    • Acquire the one and only connection [Current] or acquire a connection from the connection pool [Requested].
    • Select the one and only row from the user's table for this user, and retrieve the corresponding password column. If zero rows (or more than one row) are found, return null.
    • Authenticate the user by comparing the (possibly encrypted) password value that was received against the password presented by the user. If there is no match, return null.
    • Acquire a List of the security roles assigned to the authenticated user by selecting from the roles table.
    • Construct a new instance of class org.apache.catalina.realm.GenericPrincipal, passing as constructor arguments: this realm instance, the authenticated username, and a List of the security roles associated with this user.
    • WARNING - Do not attempt to cache and reuse previous GenericPrincipal objects for a particular user, because the information in the directory server might have changed since the last time this user was authenticated.
    • Return the newly constructed GenericPrincipal.

    Method hasRole() Functionality

    When hasRole() is called, the following processing is required:

    • The principal that is passed as an argument SHOULD be one that we returned (instanceof class org.apache.catalina.realm.GenericPrincipal, with a realm property that is equal to our instance.
    • If the passed principal meets these criteria, check the specified role against the list returned by getRoles(), and return true if the specified role is included; otherwise, return false.
    • If the passed principal does not meet these criteria, return false.

    In addition the the assertions implied by the functionality requirements listed above, the following additional assertions shall be tested to validate the behavior of JDBCRealm:

    tomcat7-7.0.52/webapps/docs/funcspecs/mbean-names.xml0000644000175100017510000005776712271304167022463 0ustar locutuslocutus ]> &project; Craig McClanahan Amy Roh Tomcat MBean Names

    We will be using JMX MBeans as the technology for implementing manageability of Tomcat.

    One of the key concepts of JMX (and JSR-77) is that each management bean has a unique name in the MBeanServer's registry, and that management applications can utilize these names to retrieve the MBean of interest to them for a particular management operation. This document proposes a naming convention for MBeans that allows easy calculation of the name for a particular MBean. For background information on JMX MBean names, see the Java Management Extensions Instrumentation and Agent Specification, version 1.0, section 6. In particular, we will be discussing the String Representation of ObjectName instances.

    Tomcat's servlet container implementation, called Catalina, can be represented as a hierarchy of objects that contain references to each other. The object hierarchy can be represented as a tree, or (isomorphically) based on the nesting of configuration elements in the conf/server.xml file that is traditionally used to configure Tomcat stand-alone.

    The valid component nestings for Catalina are depicted in the following table, with columns that contain the following values:

    • Pattern - Nesting pattern of XML elements (in the conf/server.xml file) used to configure this component.
    • Cardinality - Minimum and maximum number of occurrences of this element at this nesting position, which also corresponds to the minimum and maximum number of Catalina components.
    • Identifier - Name of the JavaBeans property of this component that represents the unique identifier (within the nested hierarchy), if any.
    • MBean ObjectName - The portion of the MBean object name that appears after the domain name. For now, it should be assumed that all of these MBeans appear in the default JMX domain.

    In the MBean ObjectName descriptions, several types of symbolic expressions are utilized to define variable text that is replaced by corresponding values:

    • ${GROUP} - One of the standard MBean names of the specified "group" category. For example, the expression ${REALM} represents the values like JDBCRealm and JAASRealm that identify the various MBeans for possible Realm components.
    • ${name} - Replaced by the value of property name from the current component.
    • ${parent.name} - Replaced by the value of property name from a parent of the current component, with the parent's type identified by parent.
    • ${###} - An arbitrary numeric identifier that preserves order but has no other particular meaning. In general, the server will assign numeric values to existing instances with large gaps into which new items can be configured if desired.
    Pattern Cardinality Identifier MBean ObjectName
    Server 1..1 (none) type=${SERVER}
    Server / Listener 0..n (none) type=${LISTENER}, sequence=${###}
    Server / Service 1..n name type=${SERVICE}, name=${name}
    Server / Service / Connector 1..n address, port type=${CONNECTOR}, service=${service}, port=${port}, address=${address}
    Server / Service / Connector / Factory 0..1 (none) (Only defined explicitly for an SSL connector, but can be treated as part of the connector component)
    Server / Service / Connector / Listener 0..n (none) type=${LISTENER}, sequence=${###}, service=${service}, port=${connector.port}, address=${connector.address}
    Server / Service / Engine 1..1 (none) type=${ENGINE}, service=${service.name}
    Server / Service / Engine / Host 1..n name type=${HOST}, host=${name}, service=${service.name}
    Server / Service / Engine / Host / Context 1..n path type=${CONTEXT}, context=${name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / InstanceListener 0..n (none) type=${INSTANCE-LISTENER}, sequence=${###}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / Listener 0..n (none) type=${LISTENER}, sequence=${###}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / Loader 0..1 (none) type=${LOADER}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / Manager 0..1 (none) type=${MANAGER}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / Realm 0..1 (none) type=${REALM}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / Resources 0..1 (none) type=${RESOURCES}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / Valve 0..n (none) type=${VALVE}, sequence=${###}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / Wrapper 0..n (none) j2eeType=Servlet,name=${name}, WebModule=//${host.name}/${context.name}, J2EEApplication=${context.J2EEApplication}, J2EEServer=${context.J2EEServer}
    Server / Service / Engine / Host / Context / WrapperLifecycle 0..n (none) type=${WRAPPER-LIFECYCLE}, sequence=${###}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Context / WrapperListener 0..n (none) type=${WRAPPER-LISTENER}, sequence=${###}, context=${context.name}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Listener 0..n (none) type=${LISTENER}, sequence=${###}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Realm 0..1 (none) type=${REALM}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Host / Valve 0..n (none) type=${VALVE}, sequence=${###}, host=${host.name}, service=${service.name}
    Server / Service / Engine / Listener 0..n (none) type=${LISTENER}, sequence=${###} (FIXME - disambiguate from Server / Service / Listener)
    Server / Service / Engine / Realm 0..1 (none) type=${REALM}, service=${service.name}
    Server / Service / Engine / Valve 0..n (none) type=${VALVE}, sequence=${###}, service=${service.name}
    Server / Service / Listener 0..n (none) type=${LISTENER}, sequence=${###} (FIXME - disambiguate from Server / Service / Engine / Listener)

    The following MBean names shall be defined in the resource file /org/apache/catalina/mbeans/mbeans-descriptors.xml (and therefore available for use within the Administration/Configuration web application for Tomcat):

    MBean Name Group Name Catalina Interface Implementation Class
    AccessLogValve VALVE org.apache.catalina.Valve org.apache.catalina.valves.AccessLogValve
    BasicAuthenticator VALVE org.apache.catalina.Valve org.apache.catalina.authenticator.BasicAuthenticator
    CertificatesValve VALVE org.apache.catalina.Valve org.apache.catalina.valves.CertificatesValve
    ContextConfig LISTENER org.apache.catalina.LifecycleListener org.apache.catalina.startup.ContextConfig
    ContextEnvironment RESOURCES org.apache.catalina.deploy.ContextEnvironment org.apache.catalina.deploy.ContextEnvironment
    ContextResource RESOURCES org.apache.catalina.deploy.ContextResource org.apache.catalina.deploy.ContextResource
    ContextResourceLink RESOURCES org.apache.catalina.deploy.ContextResourceLink org.apache.catalina.deploy.ContextResourceLink
    CoyoteConnector CONNECTOR org.apache.catalina.Connector org.apache.coyote.tomcat4.CoyoteConnector
    DigestAuthenticator VALVE org.apache.catalina.Valve org.apache.catalina.authenticator.DigestAuthenticator
    EngineConfig LISTENER org.apache.catalina.LifecycleListener org.apache.catalina.startup.EngineConfig
    ErrorReportValve VALVE org.apache.catalina.Valve org.apache.catalina.valves.ErrorReportValve
    ErrorDispatcherValve VALVE org.apache.catalina.Valve org.apache.catalina.valves.ErrorDispatcherValve
    FormAuthenticator VALVE org.apache.catalina.Valve org.apache.catalina.authenticator.FormAuthenticator
    Group GROUP org.apache.catalina.Group org.apache.catalina.Group
    HostConfig LISTENER org.apache.catalina.LifecycleListener org.apache.catalina.startup.HostConfig
    HttpConnector10 CONNECTOR org.apache.catalina.Connector org.apache.catalina.connector.http10.HttpConnector
    HttpConnector11 CONNECTOR org.apache.catalina.Connector org.apache.catalina.connector.http.HttpConnector
    JAASRealm REALM org.apache.catalina.Realm org.apache.catalina.realm.JAASRealm
    JDBCRealm REALM org.apache.catalina.Realm org.apache.catalina.realm.JDBCRealm
    JDBCUserDatabase USERDATABASE org.apache.catalina.users.JDBCUserDatabase org.apache.catalina.users.JDBCUserDatabase
    JNDIRealm REALM org.apache.catalina.Realm org.apache.catalina.realm.JNDIRealm
    MBeanFactory org.apache.catalina.mbeans.MBeanFactory
    MemoryRealm REALM org.apache.catalina.Realm org.apache.catalina.realm.MemoryRealm
    MemoryUserDatabase USERDATABASE org.apache.catalina.users.MemoryUserDatabase org.apache.catalina.users.MemoryUserDatabase
    NamingContextListener LISTENER org.apache.catalina.LifecycleListener org.apache.catalina.core.NamingContextListener
    NamingResources RESOURCES org.apache.catalina.deploy.NamingResources org.apache.catalina.deploy.NamingResources
    NonLoginAuthenticator VALVE org.apache.catalina.Valve org.apache.catalina.authenticator.NonLoginAuthenticator
    PersistentManager MANAGER org.apache.catalina.Manager org.apache.catalina.session.PersistentManager
    RemoteAddrValve VALVE org.apache.catalina.Valve org.apache.catalina.valves.RemoteAddrValve
    RemoteHostValve VALVE org.apache.catalina.Valve org.apache.catalina.valves.RemoteHostValve
    RequestDumperValve VALVE org.apache.catalina.Valve org.apache.catalina.valves.RequestDumperValve
    Role ROLE org.apache.catalina.Role org.apache.catalina.Role
    SingleSignOn VALVE org.apache.catalina.Valve org.apache.catalina.valves.SingleSignOn
    SSLAuthenticator VALVE org.apache.catalina.Valve org.apache.catalina.authenticator.SSLAuthenticator
    StandardContext CONTEXT org.apache.catalina.Context org.apache.catalina.core.StandardContext
    StandardContextValve VALVE org.apache.catalina.Valve org.apache.catalina.core.StandardContextValve
    StandardEngine ENGINE org.apache.catalina.Engine org.apache.catalina.core.StandardEngine
    StandardEngineValve VALVE org.apache.catalina.Valve org.apache.catalina.core.StandardEngineValve
    StandardHost HOST org.apache.catalina.Host org.apache.catalina.core.StandardHost
    StandardHostValve VALVE org.apache.catalina.Valve org.apache.catalina.core.StandardHostValve
    StandardManager MANAGER org.apache.catalina.Manager org.apache.catalina.session.StandardManager
    StandardServer SERVER org.apache.catalina.Server org.apache.catalina.core.StandardServer
    StandardService SERVICE org.apache.catalina.Service org.apache.catalina.core.StandardService
    StandardWrapper WRAPPER org.apache.catalina.Wrapper org.apache.catalina.core.StandardWrapper
    StandardWrapperValve VALVE org.apache.catalina.Valve org.apache.catalina.core.StandardWrapperValve
    User USER org.apache.catalina.User org.apache.catalina.User
    UserDatabaseRealm REALM org.apache.catalina.Realm org.apache.catalina.realm.UserDatabaseRealm
    WebappLoader LOADER org.apache.catalina.Loader org.apache.catalina.loader.WebappLoader

    The managed objects in the JSR-77 object hierarchy correspond to the specified MBean names or groups as follows:

    JSR-77 Managed Object MBean Name or Group Comments
    J2EEServer ${SERVICE}
    Node ${SERVICE} Tomcat supports a single node only.
    Port ${CONNECTOR}
    Servlet ${WRAPPER}
    WebModule ${CONTEXT}

    The deployment objects in the JSR-88 API object hierarchy correspond to the specified MBean names or groups as follows:

    JSR-88 API Object MBean Name or Group Comments
    DeployableObject ${CONTEXT} Context deployment info plus the corresponding WAR file
    Target ${HOST}
    tomcat7-7.0.52/webapps/docs/funcspecs/fs-admin-objects.xml0000644000175100017510000005163012271304167023404 0ustar locutuslocutus ]> &project; Craig McClanahan Administrative Apps - Administered Objects

    This document defines the Administered Objects that represent the internal architectural components of the Catalina servlet container. Associated with each is a set of Supported Operations that can be performed when the administrative application is "focused" on a particular configurable object.

    The following Administered Objects are defined:

    An Access Logger is an optional Valve that can create request access logs in the same formats as those provided by web servers. Such access logs are useful input to hit count and user access tracking analysis programs. An Access Logger can be attached to an Engine, a Host, a Context, or a Default Context.

    The standard component implementing an Access Logger is org.apache.catalina.valves.AccessLogValve. It supports the following configurable properties:

    • debug - Debugging detail level. [0]
    • directory - Absolute or relative (to $CATALINA_BASE) path of the directory into which access log files are created. [logs].
    • pattern - Pattern string defining the fields to be included in the access log output, or "common" for the standard access log pattern. See org.apache.catalina.valves.AccessLogValve for more information. [common]
    • prefix - Prefix added to the beginning of each log file name created by this access logger.
    • resolveHosts - Should IP addresses be resolved to host names in the log? [false]
    • suffix - Suffix added to the end of each log file name created by this access logger.

    A Connector is the representation of a communications endpoint by which requests are received from (and responses returned to) a Tomcat client. The administrative applications shall support those connectors that are commonly utilized in Tomcat installations, as described in detail below.

    For standalone use, the standard connector supporting the HTTP/1.1 protocol is org.apache.catalina.connectors.http.HttpConnector. It supports the following configurable properties:

    • acceptCount - The maximum queue length of incoming connections that have not yet been accepted. [10]
    • address - For servers with more than one IP address, the address upon which this connector should listen. [All Addresses]
    • bufferSize - Default input buffer size (in bytes) for requests created by this Connector. [2048]
    • debug - Debugging detail level. [0]
    • enableLookups - Should we perform DNS lookups on remote IP addresses when request.getRemoteHost() is called? [false]
    • maxProcessors - The maximum number of processor threads supported by this connector. [20]
    • minProcessors - The minimum number of processor threads to be created at container startup. [5]
    • port - TCP/IP port number on which this Connector should listen for incoming requests. [8080]
    • proxyName - Host name to be returned when an application calls request.getServerName(). [Value of Host: header]
    • proxyPort - Port number to be returned when an application calls request.getServerPort(). [Same as port]

    A Context is the representation of an individual web application, which is associated with a corresponding Host. Note that the administrable properties of a Context do not include any settings from inside the web application deployment descriptor for that application.

    The standard component implementing a Context is org.apache.catalina.core.StandardContext. It supports the following configurable properties:

    • cookies - Should be use cookies for session identifier communication? [true]
    • crossContext - Should calls to ServletContext.getServletContext() return the actual context responsible for the specified path? [false]
    • debug - Debugging detail level. [0]
    • docBase - The absolute or relative (to the appBase of our owning Host) pathname of a directory containing an unpacked web application, or of a web application archive (WAR) file.
    • override - Should settings in this Context override corresponding settings in the Default Context? [false]
    • path - Context path for this web application, or an empty string for the root application of a Host. [Inferred from directory or WAR file name]
    • reloadable - Should Tomcat monitor classes in the /WEB-INF/classes directory for changes, and reload the application if they occur? [false]
    • useNaming - Should Tomcat provide a JNDI naming context, containing preconfigured entries and resources, corresponding to the requirements of the Java2 Enterprise Edition specification? [true]
    • workDir - Absolute pathname of a scratch directory that is provided to this web application. [Automatically assigned relative to $CATALINA_BASE/work]

    Each Context is owned by a parent Host, and is associated with:

    • An optional Access Logger that logs all requests processed by this web application.
    • Zero or more Environment Entries representing environment entries for the JNDI naming context associated with a web application.
    • Zero or more JDBC Resources representing database connection pools associated with a web application.
    • A Loader representing the web application class loader used by this web application.
    • A Manager representing the session manager used by this web application.
    • An optional Realm used to provide authentication and access control information for this web application.
    • Zero or more Request Filters used to limit access to this web application based on remote host name or IP address.

    A Default Context represents a subset of the configurable properties of a Context, and is used to set defaults for those properties when web applications are automatically deployed. A Default Context object can be associated with an Engine or a Host. The following configurable properties are supported:

    • cookies - Should be use cookies for session identifier communication? [true]
    • crossContext - Should calls to ServletContext.getServletContext() return the actual context responsible for the specified path? [false]
    • reloadable - Should Tomcat monitor classes in the /WEB-INF/classes directory for changes, and reload the application if they occur? [false]
    • useNaming - Should Tomcat provide a JNDI naming context, containing preconfigured entries and resources, corresponding to the requirements of the Java2 Enterprise Edition specification? [true]

    Each Default Context is owned by a parent Engine or Host, and is associated with:

    • Zero or more Environment Entries representing environment entries for the JNDI naming context associated with a web application.
    • Zero or more JDBC Resources representing database connection pools associated with a web application.
    • An optional Loader representing default configuration properties for the Loader component of deployed web applications.
    • An optional Manager representing default configuration properties for the Manager component of deployed web applications.

    Default web application characteristics are configured in a special deployment descriptor named $CATALINA_BASE/conf/web.xml. This section describes the configurable components that may be stored there.

    FIXME - Complete the description of default servlets, default mappings, default MIME types, and so on.

    An Engine is the representation of the entire Catalina servlet container, and processes all requests for all of the associated virtual hosts and web applications.

    The standard component implementing an Engine is org.apache.catalina.core.StandardEngine. It supports the following configurable properties:

    • debug - Debugging detail level. [0]
    • defaultHost - Name of the Host to which requests will be directed if the requested host is unknown. [localhost]
    • name - Logical name of this engine. [Tomcat Stand-Alone]

    Each Engine is owned by a parent Service, and is associated with:

    • An optional Access Logger that logs all requests processed by the entire container.
    • A Default Context, representing default properties of a Context for automatically deployed applications for all associated Hosts (unless overridden by a subordinate component).
    • One or more Hosts representing individual virtual hosts supported by this container.
    • A Realm used to provide authentication and access control information for all virtual hosts and web applications (unless overridden by a subordinate component).
    • Zero or more Request Filters used to limit access to the entire container based on remote host name or IP address.

    An Environment Entry is the representation of a <env-entry> element from a web application deployment descriptor. It will cause the creation of a corresponding entry in the JNDI naming context provided to the corresponding Context. The following configurable properties are supported:

    • description - Description of this environment entry.
    • name - Environment entry name (relative to the java:comp/env context)
    • type - Environment entry type (must be one of the fully qualified Java classes listed in the servlet spec).
    • value - Environment entry value (must be convertible from String to the specified type.

    A Host is the representation of an individual virtual host, which has a unique set of associated web applications.

    The standard component implementing a Host is org.apache.catalina.core.StandardHost. It supports the following configurable properties:

    • aliases - Zero or more DNS names that are also associated with this host (for example, a particular host might be named www.mycompany.com with an alias company.com).
    • appBase - Absolute or relative (to $CATALINA_BASE) path to a directory from which web applications will be automatically deployed.
    • debug - Debugging detail level. [0]
    • name - DNS Name of the virtual host represented by this object.
    • unpackWARs - Should web application archive files deployed by this virtual host be unpacked first? [true]

    Each Host is owned by a parent Engine, and is associated with:

    • An optional Access Logger that logs all requests processed by this virtual host.
    • One or more Contexts representing the web applications operating on this Host.
    • A Default Context representing default Context properties for web applications that are automatically deployed by this Host.
    • A optional Realm used to provide authentication and access control information for all web applications associated with this virtual host (unless overridden by a subordinate component).

    FIXME - Should we support configuration of the User Web Applications functionality?

    A JDBC Resources represents a database connection pool (i.e. an implementation of javax.sql.DataSource that will be configured and made available in the JNDI naming context associated with a web application.

    FIXME - properties of this administered object

    A Loader represents a web application class loader that will be utilized to provide class loading services for a particular Context.

    The standard component implementing a Loader is org.apache.catalina.loader.StandardLoader. It supports the following configurable properties:

    • checkInterval - Number of seconds between checks for modified classes, if automatic reloading is enabled. [15]
    • debug - Debugging detail level. [0]
    • reloadable - Should this class loader check for modified classes and initiate automatic reloads? [Set automatically from the reloadable property of the corresponding Context]

    Each Loader is owned by a parent Context.

    A Manager represents a session manager that will be associated with a particular web application. FIXME - Add support for advanced session managers and their associated Stores.

    The standard component implementing a Manager is org.apache.catalina.session.StandardManager. It supports the following configurable properties:

    • checkInterval - Number of seconds between checks for expired sessions. [60]
    • debug - Debugging detail level. [0]
    • entropy - String initialization parameter used to increase the entropy (initial randomness) of the random number generator used to create session identifiers. [Inferred from engine, host, and context]
    • maxActiveSessions - The maximum number of active sessions that are allowed, or -1 for no limit. [-1]

    Each Manager is owned by a parent Context.

    A Realm represents a "database" of information about authorized users, their passwords, and the security roles assigned to them. This will be used by the container in the implementation of container-managed security in accordance with the Servlet Specification. Several alternative implementations are supported.

    org.apache.catalina.realm.MemoryRealm initializes its user information from a simple XML file at startup time. If changes are made to the information in this file, the corresponding web applications using it must be restarted for the changes to take effect. It supports the following configurable properties:

    • debug - Debugging detail level. [0]
    • pathname - Absolute or relative (to $CATALINA_BASE) path to the XML file containing our user information. [conf/tomcat-users.xml]

    org.apache.catalina.realm.JDBCRealm uses a relational database (accessed via JDBC APIs) to contain the user information. Changes in the contents of this database take effect immediately; however, the roles assigned to a particular user are calculated only when the user initially logs on (and not per request). The following configurable properties are supported:

    • connectionName - Database username to use when establishing a JDBC connection.
    • connectionPassword - Database password to use when establishing a JDBC connection.
    • connectionURL - Connection URL to use when establishing a JDBC connection.
    • debug - Debugging detail level. [0]
    • digest - Name of the MessageDigest algorithm used to encode passwords in the database, or a zero-length string for no encoding. [Zero-length String]
    • driverName - Fully qualified Java class name of the JDBC driver to be utilized.
    • roleNameCol - Name of the column, in the User Roles table, which contains the role name.
    • userCredCol - Name of the column, in the Users table, which contains the password (encrypted or unencrypted).
    • userNameCol - Name of the column, in both the Users and User Roles tables, that contains the username.
    • userRoleTable - Name of the User Roles table, which contains one row per security role assigned to a particular user. This table must contain the columns specified by the userNameCol and roleNameCol properties.
    • userTable - Name of the Users table, which contains one row per authorized user. This table must contain the columns specified by the userNameCol and userCredCol properties.

    FIXME - Should we provide mechanisms to edit the contents of a "tomcat-users.xml" file through the admin applications?

    Each Realm is owned by a parent Engine, Host, or Context.

    FIXME - complete this entry

    FIXME - complete this entry

    FIXME - complete this entry

    tomcat7-7.0.52/webapps/docs/funcspecs/project.xml0000644000175100017510000000415212271304167021722 0ustar locutuslocutus Catalina Functional Specifications Catalina Functional Specifications tomcat7-7.0.52/webapps/docs/funcspecs/fs-jndi-realm.xml0000644000175100017510000004140312271304167022704 0ustar locutuslocutus ]> &project; Craig McClanahan JNDIRealm

    The purpose of the JNDIRealm implementation is to provide a mechanism by which Tomcat can acquire information needed to authenticate web application users, and define their security roles, from a directory server or other service accessed via JNDI APIs. For integration with Catalina, this class must implement the org.apache.catalina.Realm interface.

    This specification reflects a combination of functionality that is already present in the org.apache.catalina.realm.JNDIRealm class, as well as requirements for enhancements that have been discussed. Where appropriate, requirements statements are marked [Current] and [Requested] to distinguish them.

    The current status of this functional specification is PROPOSED. It has not yet been discussed and agreed to on the TOMCAT-DEV mailing list.

    The code in the current version of JNDIRealm, and the ideas expressed in this functional specification, are the results of contributions from many individuals, including (alphabetically):

    • Holman, John <j.g.holman@qmw.ac.uk>
    • Lockhart, Ellen <elockhart@home.com>
    • McClanahan, Craig <craigmcc@apache.org>

    The implementation of this functionality depends on the following external specifications:

    The implementation of this functionality shall conform to the following requirements:

    • Be realized in one or more implementation classes.
    • Implement the org.apache.catalina.Realm interface. [Current]
    • Implement the org.apache.catalina.Lifecycle interface. [Current]
    • Subclass the org.apache.catalina.realm.RealmBase base class.
    • Live in the org.apache.catalina.realm package. [Current]
    • Support a configurable debugging detail level. [Current]
    • Log debugging and operational messages (suitably internationalized) via the getContainer().log() method. [Current]

    The following environmental dependencies must be met in order for JNDIRealm to operate correctly:

    • The desire to utilize JNDIRealm must be registered in $CATALINA_BASE/conf/server.xml, in a <Realm> element that is nested inside a corresponding <Engine>, <Host>, or <Context> element.
    • If the Administrator Login operational mode is selected, the configured administrator username and password must be configured in the corresponding directory server.
    • If the Username Login operational mode is selected, the corresponding directory server must be configured to accept logins with the username and password that will be passed to JNDIRealm by the appropriate Authenticator.

    Correct operation of JNDIRealm depends on the following specific features of the surrounding container:

    • Interactions with JNDIRealm will be initiated by the appropriate Authenticator implementation, based on the login method that is selected.

    The completed JNDIRealm must support two major operational modes in order to support all of the required use cases. For the purposes of this document, the modes are called administrator login and Username Login. They are described further in the following paragraphs.

    For Administrator Login mode, JNDIRealm will be configured to establish one or more connections (using a connection pool) to an appropriate directory server, using JNDI APIs, under a "system administrator" username and password. This is similar to the approach normally used to configure JDBCRealm to access authentication and access control information in a database. It is assumed that the system administrator username and password that are configured provide sufficient privileges within the directory server to read (but not modify) the username, password, and assigned roles for each valid user of the web application associated with this Realm. The password can be stored in cleartext, or in one of the digested modes supported by the org.apache.catalina.realm.RealmBase base class.

    For Username Login mode, JNDIRealm does not normally remain connected to the directory server. Instead, whenever a user is to be authenticated, a connection to the directory server (using the username and password received from the authenticator) is attempted. If this connection is successful, the user is assumed to be successfully authenticated. This connection is then utilized to read the corresponding security roles associated with this user, and the connection is then broken.

    NOTE - Username Login mode cannot be used if you have selected login method DIGEST in your web application deployment descriptor (web.xml) file. This restriction exists because the cleartext password is never available to the container, so it is not possible to bind to the directory server using the user's username and password.

    Because these operational modes work so differently, the functionality for each mode will be described separately. Whether or not both modes are actually supported by a single class (versus a class per mode) is an implementation detail left to the designer.

    NOTE - The current implementation only implements part of the Administrator Lookup mode requirements. It does not support the Username Lookup mode at all, at this point.

    Configurable Properties

    The implementation shall support the following properties that can be configured with JavaBeans property setters:

    • connectionURL - URL of the directory server we will be contacting.
    • contextFactory - Fully qualified class name of the JNDI context factory used to retrieve our InitialContext. [com.sun.jndi.ldap.LdapCtxFactory]
    • Additional configuration properties required to establish the appropriate connection. [Requested]
    • Connection pool configuration properties. [Requested]
    • Configuration properties defining how a particular user is authenticated. The following capabilities should be supported:
      • Substitute the specified username into a string. [Requested]
      • Retrieve the distinguished name (DN) of an authorized user via an LDAP search string with a replacement placeholder for the username, and comparison of the password to a configurable attribute retrieved from the search result. [Current]
    • Configuration properties defining how the roles associated with a particular authenticated user can be retrieved. The following approaches should be supported:
      • Retrieve a specified attribute (possibly multi-valued) from an LDAP search expression, with a replacement placeholder for the DN of the user. [Current]
      • Retrieve a set of role names that are defined implicitly (by selecting principals that match a search pattern) rather than explicitly (by finding a particular attribute value). [Requested]

    Lifecycle Functionality

    The following processing must be performed when the start() method is called:

    • Establish a connection to the configured directory server, using the configured system administrator username and password. [Current]
    • Configure and establish a connection pool of connections to the directory server. [Requested]

    The following processing must be performed when the stop() method is called:

    • Close any opened connections to the directory server.

    Method authenticate() Functionality

    When authenticate() is called, the following processing is required:

    • Acquire the one and only connection [Current] or acquire a connection from the connection pool [Requested].
    • Authenticate the user by retrieving the user's Distinguished Name, based on the specified username and password.
    • If the user was not authenticated, release the allocated connection and return null.
    • Acquire a List of the security roles assigned to the authenticated user.
    • Construct a new instance of class org.apache.catalina.realm.GenericPrincipal, passing as constructor arguments: this realm instance, the authenticated username, and a List of the security roles associated with this user.
    • WARNING - Do not attempt to cache and reuse previous GenericPrincipal objects for a particular user, because the information in the directory server might have changed since the last time this user was authenticated.
    • Return the newly constructed GenericPrincipal.

    Method hasRole() Functionality

    When hasRole() is called, the following processing is required:

    • The principal that is passed as an argument SHOULD be one that we returned (instanceof class org.apache.catalina.realm.GenericPrincipal, with a realm property that is equal to our instance.
    • If the passed principal meets these criteria, check the specified role against the list returned by getRoles(), and return true if the specified role is included; otherwise, return false.
    • If the passed principal does not meet these criteria, return false.

    Configurable Properties

    The implementation shall support the following properties that can be configured with JavaBeans property setters:

    • connectionURL - URL of the directory server we will be contacting.
    • contextFactory - Fully qualified class name of the JNDI context factory used to retrieve our InitialContext. [com.sun.jndi.ldap.LdapCtxFactory]
    • Additional configuration properties required to establish the appropriate connection. [Requested]
    • Connection pool configuration properties. [Requested]
    • Configuration properties defining if and how a user might be looked up before binding to the directory server. The following approaches should be supported:
      • No previous lookup is required - username specified by the user is the same as that used to authenticate to the directory server.
      • Substitute the specified username into a string.
      • Search the directory server based on configured criteria to retrieve the distinguished name of the user, then attempt to bind with that distinguished name.
    • Configuration properties defining how the roles associated with a particular authenticated user can be retrieved. The following approaches should be supported:
      • Retrieve a specified attribute (possibly multi-valued) from an LDAP search expression, with a replacement placeholder for the DN of the user. [Current]

    Lifecycle Functionality

    The following processing must be performed when the start() method is called:

    • None required.

    The following processing must be performed when the stop() method is called:

    • None required.

    Method authenticate() Functionality

    When authenticate() is called, the following processing is required:

    • Attempt to bind to the directory server, using the username and password provided by the user.
    • If the user was not authenticated, release the allocated connection and return null.
    • Acquire a List of the security roles assigned to the authenticated user.
    • Construct a new instance of class org.apache.catalina.realm.GenericPrincipal, passing as constructor arguments: this realm instance, the authenticated username, and a List of the security roles associated with this user.
    • WARNING - Do not attempt to cache and reuse previous GenericPrincipal objects for a particular user, because the information in the directory server might have changed since the last time this user was authenticated.
    • Return the newly constructed GenericPrincipal.

    Method hasRole() Functionality

    When hasRole() is called, the following processing is required:

    • The principal that is passed as an argument SHOULD be one that we returned (instanceof class org.apache.catalina.realm.GenericPrincipal, with a realm property that is equal to our instance.
    • If the passed principal meets these criteria, check the specified role against the list returned by getRoles(), and return true if the specified role is included; otherwise, return false.
    • If the passed principal does not meet these criteria, return false.

    In addition the the assertions implied by the functionality requirements listed above, the following additional assertions shall be tested to validate the behavior of JNDIRealm:

    tomcat7-7.0.52/webapps/docs/funcspecs/fs-default.xml0000644000175100017510000002354412271304167022314 0ustar locutuslocutus ]> &project; Craig McClanahan Default Servlet

    The purpose of the Default Servlet is to serve static resources of a web application in response to client requests. As the name implies, it is generally configured as the "default" servlet for a web application, by being mapped to a URL pattern "/".

    The following external specifications have provisions which partially define the correct behavior of the default servlet:

    The implementation of this functionality shall conform to the following requirements:

    • Must be implemented as a servlet.
    • Must support configurable parameters for debugging detail level, input buffer size, output buffer size, whether or not to produce directory listings when no welcome file is present, and whether or not modifications are supported via DELETE and PUT.
    • Log debugging and operational messages (suitably internationalized) via the getServletContext().log() method.

    The following environmental dependencies must be met in order for the default servlet to operate correctly:

    • The default servlet must be registered in the application deployment descriptor (or the default deployment descriptor in file $CATALINA_BASE/conf/web.xml) using a "default servlet" servlet mapping, signified by URL pattern "/".

    Correct operation of the default servlet depends on the following specific features of the surrounding container:

    • The container shall provide a servlet context attribute that lists the welcome file names that have been defined for this web application.
    • The container shall provide a servlet context attribute that contains a javax.naming.directory.DirContext implementation representing the static resources of this web application.

    The following processing must be performed when the init() method of the default servlet is called:

    • Process and sanity check configuration parameters.

    For all HTTP request methods, the resource path is determined from the path information provided to this request, either as request attribute javax.servlet.include.path_info (for a request dispatcher access to a static resource) or by calling request.getPathInfo() directly.

    On each HTTP DELETE request processed by this servlet, the following processing shall be performed:

    • If modifications to the static resources are not allowed (set by a configuration parameter), return HTTP status 403 (forbidden).
    • If an attempt is made to delete a resource from /META-INF or /WEB-INF, return HTTP status 403 (forbidden).
    • If the requested resource does not exist, return HTTP status 404 (not found)
    • Unbind the resource from the directory context containing the static resources for this web application. If successful, return HTTP status 204 (no content). Otherwise, return HTTP status 405 (method not allowed).

    On each HTTP GET request processed by this servlet, the following processing shall be performed:

    • If the request is for a resource under /META-INF or /WEB-INF, return HTTP status 404 (not found).
    • If the requested resource does not exist, return HTTP status 404 (not found).
    • If the requested resource is not a directory, but the resource path ends in "/" or "\", return HTTP status 404 (not found).
    • If the requested resource is a directory:
      • If the request path does not end with "/", redirect to a corresponding path with "/" appended so that relative references in welcome files are resolved correctly.
      • If one of the specified welcome files exists, redirect to the path for that welcome file so that it will be served explicitly.
    • If the request being processed contains an If-Range header, perform the processing described in the HTTP/1.1 specification to determine whether the client's information is up to date.
    • Determine the content type of the response, by looking up the corresponding MIME type in our servlet context.
    • If the requested resource is a directory:
      • If directory listings are suppressed, return HTTP status 404 (not found).
      • Set the content type to text/html.
    • Determine the range(s) to be returned, based on the existence of any If-Range and Range headers.
    • If the requested resource is a directory, include an ETag header in the response, with the value calculated based on the content of the directory.
    • Include a Last-Modified header in the response documenting the date/time that the resource was last modified.
    • Unless we are processing a HEAD request, include the appropriate content (or content ranges) in the response.

    On each HTTP HEAD request processed by this servlet, the following processing shall be performed:

    • Processed identically to an HTTP GET request, except that the data content is not transmitted after the headers.

    On each HTTP POST request processed by this servlet, the following processing shall be performed:

    • Processed identically to an HTTP GET request.

    On each HTTP PUT request processed by this servlet, the following processing shall be performed:

    • If modifications to the static resources are not allowed (set by a configuration parameter), return HTTP status 403 (forbidden).
    • If an attempt is made to delete a resource from /META-INF or /WEB-INF, return HTTP status 403 (forbidden).
    • Create a new resource from the body of this request.
    • Bind or rebind the specified path to the new resource (depending on whether it currently exists or not). Return HTTP status as follows:
      • If binding was unsuccessful, return HTTP status 409 (conflict).
      • If binding was successful and the resource did not previously exist, return HTTP status 201 (created).
      • If binding was successful and the resource previously existed, return HTTP status 204 (no content).

    No specific processing is required when the destroy() method is called:

    In addition the the assertions implied by the functionality requirements listed above, the following additional assertions shall be tested to validate the behavior of the default servlet:

    • Requests for resources that do not exist in the web application must return HTTP status 404 (not found).
    • The default servlet must operate identically for web applications that are run out of a WAR file directly, or from an unpacked directory structure.
    • If the web application is running out of an unpacked directory structure, the default servlet must recognize cases where the resource has been updated through external means.
    tomcat7-7.0.52/webapps/docs/funcspecs/index.xml0000644000175100017510000000531512271304167021365 0ustar locutuslocutus ]> &project; Craig R. McClanahan Table of Contents

    This documentation area includes functional specifications for many features supported by the Catalina servlet container portion of Tomcat. In most cases, these features are not documented in the underlying Servlet or JSP specifications, so a definition of the expected correct behavior is important both to implementors of those features, and to test writers trying to decide what to test.

    The functional specifications are divided into the following categories in the menu (to the left):

    • Administrative Apps - Overall requirements for supporting an ability to configure and operate a Tomcat installation through tools, as well as detailed requirements for the tools themselves.
    • Internal Servlets - Requirements for Catalina features that are implemented as internal, container-managed, servlets.
    • Realm Implementations - Requirements for the implementations of the org.apache.catalina.Realm interface (providing access to collections of users, passwords and roles) that are included in the standard Tomcat distribution.

    NOTE - In some cases, the contents of these functional specs has been "reverse engineered" from existing implementations. This exercise is still useful, because it provides an introduction to what Catalina does, without being as concerned with how this is accomplished.

    TODO - Obviously, this area has a long ways to go before it is complete. Contributions are welcome!

    tomcat7-7.0.52/webapps/docs/funcspecs/fs-admin-apps.xml0000644000175100017510000003010612271304167022711 0ustar locutuslocutus ]> &project; Craig McClanahan Administrative Apps - Overall Requirements

    The purpose of this specification is to define high level requirements for administrative applications that can be used to manage the operation of a running Tomcat container. A variety of Access Methods to the supported administrative functionality shall be supported, to meet varying requirements:

    • As A Scriptable Web Application - The existing Manager web application provides a simple HTTP-based interface for managing Tomcat through commands that are expressed entirely through a request URI. This is useful in environments where you wish to script administrative commands with tools that can generate HTTP transactions.
    • As An HTML-Based Web Application - Use an HTML presentation to provide a GUI-like user interface for humans to interact with the administrative capabilities.
    • As SOAP-Based Web Services - The operational commands to administer Tomcat are made available as web services that utilize SOAP message formats.
    • As Java Management Extensions (JMX) Commands - The operational commands to administer Tomcat are made available through JMX APIs, for integration into management consoles that utilize them.
    • Other Remote Access APIs - Other remote access APIs, such as JINI, RMI, and CORBA can also be utilized to access administrative capabilities.

    Underlying all of the access methods described above, it is assumed that the actual operations are performed either directly on the corresponding Catalina components (such as calling the Deployer.deploy() method to deploy a new web application), or through a "business logic" layer that can be shared across all of the access methods. This approach minimizes the cost of adding new administrative capabilities later -- it is only necessary to add the corresponding business logic function, and then write adapters to it for all desired access methods.

    The current status of this functional specification is PROPOSED. It has not yet been discussed and agreed to on the TOMCAT-DEV mailing list.

    The implementation of this functionality depends on the following external specifications:

    The implementation of this functionality shall conform to the following requirements:

    • To the maximum extent feasible, all administrative functions, and the access methods that support them, shall run portably on all platforms where Tomcat itself runs.
    • In a default Tomcat distribution, all administrative capabilities shall be disabled. It shall be necessary for a system administrator to specifically enable the desired access methods (such as by adding a username/password with a specific role to the Tomcat user's database.
    • Administrative functions shall be realized as direct calls to corresponding Catalina APIs, or through a business logic layer that is independent of the access method used to initiate it.
    • The common business logic components shall be implemented in package org.apache.catalina.admin.
    • The common business logic components shall be built as part of the standard Catalina build process, and made visible in the Catalina class loader.
    • The Java components required for each access method shall be implemented in subpackages of org.apache.catalina.admin.
    • The build scripts should treat each access method as optional, so that it will be built only if the corresponding required APIs are present at build time.
    • It shall be possible to save the configured state of the running Tomcat container such that this state can be reproduced when the container is shut down and restarted.
    • Administrative commands to start up and shut down the overall Tomcat container are out of scope for the purposes of these applications. It is assumed that other (usually platform-specific) mechanisms will be used for container startup and shutdown.

    The following environmental dependencies must be met in order for administrative applications to operate correctly:

    • For access methods that require creation of server sockets, the appropriate ports must be configured and available.

    Correct operation of administrative applications depends on the following specific features of the surrounding container:

    • To the maximum extent feasible, Catalina components that offer direct administrative APIs and property setters shall support "live" changes to their operation, without requiring a container restart.

    The availability of the following technologies can be assumed for the implementation and operation of the various access methods and the corresponding administrative business logic:
    FIXME - This list below is totally outdated, but nobody cares about the administrative app anymore. It is removed and unsupported since Tomcat 6.0.

    Functional requirements for administrative applications are specified in terms of Administered Objects, whose definitions and detailed properties are listed here. In general, Administered Objects correspond to components in the Catalina architecture, but these objects are defined separately here for the following reasons:

    • It is possible that the administrative applications do not expose every possible configurable facet of the underlying components.
    • In some cases, an Administered Object (from the perspective of an administrative operation) is realized by more than one Catalina component, at a finer-grained level of detail.
    • It is necessary to represent the configuration information for a component separately from the component itself (for instance, in order to store that configuration information for later use).
    • It is necessary to represent configuration information (such as a Default Context) when there is no corresponding component instance.
    • Administered Objects, when realized as Java classes, will include methods for administrative operations that have no correspondence to operations performed by the corresponding actual components.

    It is assumed that the reader is familiar with the overall component architecture of Catalina. For further information, see the corresponding Developer Documentation. To distinguish names that are used as both Administered Objects and Components, different font presentations are utilized. Default values for many properties are listed in [square brackets].

    The administrative operations that are available are described in terms of the corresponding Administered Objects (as defined above), in a manner that is independent of the access method by which these operations are requested. In general, such operations are relevant only in the context of a particular Administered Object (and will most likely be realized as method calls on the corresponding Administered Object classes), so they are organized based on the currently "focused" administered object. The available Supported Operations are documented here.

    Scriptable Web Application

    An appropriate subset of the administrative operations described above shall be implemented as commands that can be performed by the "Manager" web application. FIXME - Enumerate them.

    In addition, this web application shall conform to the following requirements:

    • All request URIs shall be protected by security constraints that require a security role to be assigned for processing.
    • The default user database shall not contain any user that has been assigned a security role.
    HTML-Based Web Application

    The entire suite of administrative operations described above shall be made available through a web application designed for human interaction. In addition, this web application shall conform to the following requirements:

    • Must be implemented using servlet, JSP, and MVC framework technologies described under "External Technologies", above.
    • Prompts and error messages must be internationalizable to multiple languages.
    • Rendered HTML must be compatible with Netscape Navigator (version 4.7 or later) and Internet Explorer (version 5.0 or later).

    FIXME - Complete this section.

    tomcat7-7.0.52/webapps/docs/proxy-howto.xml0000644000175100017510000001574512271304167020614 0ustar locutuslocutus ]> &project; Craig R. McClanahan Proxy Support HOW-TO

    Using standard configurations of Tomcat, web applications can ask for the server name and port number to which the request was directed for processing. When Tomcat is running standalone with the HTTP/1.1 Connector, it will generally report the server name specified in the request, and the port number on which the Connector is listening. The servlet API calls of interest, for this purpose, are:

    • ServletRequest.getServerName(): Returns the host name of the server to which the request was sent.
    • ServletRequest.getServerPort(): Returns the host name of the server to which the request was sent.
    • ServletRequest.getLocalName(): Returns the host name of the Internet Protocol (IP) interface on which the request was received.
    • ServletRequest.getLocalPort(): Returns the Internet Protocol (IP) port number of the interface on which the request was received.

    When you are running behind a proxy server (or a web server that is configured to behave like a proxy server), you will sometimes prefer to manage the values returned by these calls. In particular, you will generally want the port number to reflect that specified in the original request, not the one on which the Connector itself is listening. You can use the proxyName and proxyPort attributes on the <Connector> element to configure these values.

    Proxy support can take many forms. The following sections describe proxy configurations for several common cases.

    Apache 1.3 supports an optional module (mod_proxy) that configures the web server to act as a proxy server. This can be used to forward requests for a particular web application to a Tomcat instance, without having to configure a web connector such as mod_jk. To accomplish this, you need to perform the following tasks:

    1. Configure your copy of Apache so that it includes the mod_proxy module. If you are building from source, the easiest way to do this is to include the --enable-module=proxy directive on the ./configure command line.
    2. If not already added for you, make sure that you are loading the mod_proxy module at Apache startup time, by using the following directives in your httpd.conf file: LoadModule proxy_module {path-to-modules}/mod_proxy.so AddModule mod_proxy.c
    3. Include two directives in your httpd.conf file for each web application that you wish to forward to Tomcat. For example, to forward an application at context path /myapp: ProxyPass /myapp http://localhost:8081/myapp ProxyPassReverse /myapp http://localhost:8081/myapp which tells Apache to forward URLs of the form http://localhost/myapp/* to the Tomcat connector listening on port 8081.
    4. Configure your copy of Tomcat to include a special <Connector> element, with appropriate proxy settings, for example: <Connector port="8081" ... proxyName="www.mycompany.com" proxyPort="80"/> which will cause servlets inside this web application to think that all proxied requests were directed to www.mycompany.com on port 80.
    5. It is legal to omit the proxyName attribute from the <Connector> element. If you do so, the value returned by request.getServerName() will by the host name on which Tomcat is running. In the example above, it would be localhost.
    6. If you also have a <Connector> listening on port 8080 (nested within the same Service element), the requests to either port will share the same set of virtual hosts and web applications.
    7. You might wish to use the IP filtering features of your operating system to restrict connections to port 8081 (in this example) to be allowed only from the server that is running Apache.
    8. Alternatively, you can set up a series of web applications that are only available via proxying, as follows:
      • Configure another <Service> that contains only a <Connector> for the proxy port.
      • Configure appropriate Engine, Host, and Context elements for the virtual hosts and web applications accessible via proxying.
      • Optionally, protect port 8081 with IP filters as described earlier.
    9. When requests are proxied by Apache, the web server will be recording these requests in its access log. Therefore, you will generally want to disable any access logging performed by Tomcat itself.

    When requests are proxied in this manner, all requests for the configured web applications will be processed by Tomcat (including requests for static content). You can improve performance by using the mod_jk web connector instead of mod_proxy. mod_jk can be configured so that the web server serves static content that is not processed by filters or security constraints defined within the web application's deployment descriptor (/WEB-INF/web.xml).

    The same instructions hold true as for 1.3. (Except in Apache 2.0, you may omit AddModule mod_proxy.c)
    tomcat7-7.0.52/webapps/docs/developers.xml0000644000175100017510000000567612271304167020447 0ustar locutuslocutus ]> &project; Remy Maucherat Yoav Shapira Tomcat Developers

    The list indicates the developers' main areas of interest. Feel free to add to the list :) The developers email addresses are [login]@apache.org. Please do not contact developers directly for any support issues (please post to the tomcat-users mailing list instead, or one of the other support resources; some organizations and individual consultants also offer for pay Tomcat support, as listed on the support and training page on the Tomcat Wiki).

    • Bill Barker (billbarker): Connectors
    • Costin Manolache (costin): Catalina, Connectors
    • Filip Hanik (fhanik): Clustering, Release Manager
    • Jean-Frederic Clere (jfclere): Connectors
    • Jim Jagielski (jim): Connectors
    • Konstantin Kolinko (kkolinko): Catalina
    • Mark Thomas (markt): CGI, SSI, WebDAV, bug fixing
    • Mladen Turk (mturk): Connectors
    • Peter Rossbach (pero): Catalina, Clustering, JMX
    • Rainer Jung (rjung): Catalina, Clustering, Connectors
    • Remy Maucherat (remm): Catalina, Connectors, Docs
    • Tim Funk (funkman): Catalina, Docs
    • Tim Whittington (timw): Connectors
    • Amy Roh (amyroh): Catalina
    • Glenn Nielsen (glenn): Catalina, Connectors
    • Henri Gomez (hgomez): Connectors
    • Jan Luehe (luehe): Jasper
    • Jean-Francois Arcand (jfarcand): Catalina
    • Kin-Man Chung (kinman): Jasper
    • Yoav Shapira (yoavs): Docs, JMX, Catalina, balancer
    tomcat7-7.0.52/webapps/docs/class-loader-howto.xml0000644000175100017510000002602212271304167021772 0ustar locutuslocutus ]> &project; Craig R. McClanahan Yoav Shapira Class Loader HOW-TO

    Like many server applications, Tomcat installs a variety of class loaders (that is, classes that implement java.lang.ClassLoader) to allow different portions of the container, and the web applications running on the container, to have access to different repositories of available classes and resources. This mechanism is used to provide the functionality defined in the Servlet Specification, version 2.4 — in particular, Sections 9.4 and 9.6.

    In a Java environment, class loaders are arranged in a parent-child tree. Normally, when a class loader is asked to load a particular class or resource, it delegates the request to a parent class loader first, and then looks in its own repositories only if the parent class loader(s) cannot find the requested class or resource. Note, that the model for web application class loaders differs slightly from this, as discussed below, but the main principles are the same.

    When Tomcat is started, it creates a set of class loaders that are organized into the following parent-child relationships, where the parent class loader is above the child class loader:

    Bootstrap | System | Common / \ Webapp1 Webapp2 ...

    The characteristics of each of these class loaders, including the source of classes and resources that they make visible, are discussed in detail in the following section.

    As indicated in the diagram above, Tomcat creates the following class loaders as it is initialized:

    • Bootstrap — This class loader contains the basic runtime classes provided by the Java Virtual Machine, plus any classes from JAR files present in the System Extensions directory ($JAVA_HOME/jre/lib/ext). Note: some JVMs may implement this as more than one class loader, or it may not be visible (as a class loader) at all.

    • System — This class loader is normally initialized from the contents of the CLASSPATH environment variable. All such classes are visible to both Tomcat internal classes, and to web applications. However, the standard Tomcat startup scripts ($CATALINA_HOME/bin/catalina.sh or %CATALINA_HOME%\bin\catalina.bat) totally ignore the contents of the CLASSPATH environment variable itself, and instead build the System class loader from the following repositories:

      • $CATALINA_HOME/bin/bootstrap.jar — Contains the main() method that is used to initialize the Tomcat server, and the class loader implementation classes it depends on.

      • $CATALINA_BASE/bin/tomcat-juli.jar or $CATALINA_HOME/bin/tomcat-juli.jar — Logging implementation classes. These include enhancement classes to java.util.logging API, known as Tomcat JULI, and a package-renamed copy of Apache Commons Logging library used internally by Tomcat. See logging documentation for more details.

        If tomcat-juli.jar is present in $CATALINA_BASE/bin, it is used instead of the one in $CATALINA_HOME/bin. It is useful in certain logging configurations

      • $CATALINA_HOME/bin/commons-daemon.jar — The classes from Apache Commons Daemon project. This JAR file is not present in the CLASSPATH built by catalina.bat|.sh scripts, but is referenced from the manifest file of bootstrap.jar.

    • Common — This class loader contains additional classes that are made visible to both Tomcat internal classes and to all web applications.

      Normally, application classes should NOT be placed here. The locations searched by this class loader are defined by the common.loader property in $CATALINA_BASE/conf/catalina.properties. The default setting will search the following locations in the order they are listed:

      • unpacked classes and resources in $CATALINA_BASE/lib
      • JAR files in $CATALINA_BASE/lib
      • unpacked classes and resources in $CATALINA_HOME/lib
      • JAR files in $CATALINA_HOME/lib

      By default, this includes the following:

      • annotations-api.jar — JavaEE annotations classes.
      • catalina.jar — Implementation of the Catalina servlet container portion of Tomcat.
      • catalina-ant.jar — Tomcat Catalina Ant tasks.
      • catalina-ha.jar — High availability package.
      • catalina-tribes.jar — Group communication package.
      • ecj-*.jar — Eclipse JDT Java compiler.
      • el-api.jar — EL 2.2 API.
      • jasper.jar — Tomcat Jasper JSP Compiler and Runtime.
      • jasper-el.jar — Tomcat Jasper EL implementation.
      • jsp-api.jar — JSP 2.2 API.
      • servlet-api.jar — Servlet 3.0 API.
      • tomcat-api.jar — Several interfaces defined by Tomcat.
      • tomcat-coyote.jar — Tomcat connectors and utility classes.
      • tomcat-dbcp.jar — Database connection pool implementation based on package-renamed copy of Apache Commons Pool and Apache Commons DBCP.
      • tomcat-i18n-**.jar — Optional JARs containing resource bundles for other languages. As default bundles are also included in each individual JAR, they can be safely removed if no internationalization of messages is needed.
      • tomcat-jdbc.jar — An alternative database connection pool implementation, known as Tomcat JDBC pool. See documentation for more details.
      • tomcat-util.jar — Common classes used by various components of Apache Tomcat.
    • WebappX — A class loader is created for each web application that is deployed in a single Tomcat instance. All unpacked classes and resources in the /WEB-INF/classes directory of your web application, plus classes and resources in JAR files under the /WEB-INF/lib directory of your web application, are made visible to this web application, but not to other ones.

    As mentioned above, the web application class loader diverges from the default Java delegation model (in accordance with the recommendations in the Servlet Specification, version 2.4, section 9.7.2 Web Application Classloader). When a request to load a class from the web application's WebappX class loader is processed, this class loader will look in the local repositories first, instead of delegating before looking. There are exceptions. Classes which are part of the JRE base classes cannot be overridden. For some classes (such as the XML parser components in J2SE 1.4+), the J2SE 1.4 endorsed feature can be used. Last, any JAR file that contains Servlet API classes will be explicitly ignored by the classloader — Do not include such JARs in your web application. All other class loaders in Tomcat follow the usual delegation pattern.

    Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:

    • Bootstrap classes of your JVM
    • System class loader classes (described above)
    • /WEB-INF/classes of your web application
    • /WEB-INF/lib/*.jar of your web application
    • Common class loader classes (described above)

    Starting with Java 1.4 a copy of JAXP APIs and an XML parser are packed inside the JRE. This has impacts on applications that wish to use their own XML parser.

    In old versions of Tomcat, you could simply replace the XML parser in the Tomcat libraries directory to change the parser used by all web applications. However, this technique will not be effective when you are running modern versions of Java, because the usual class loader delegation process will always choose the implementation inside the JDK in preference to this one.

    Java supports a mechanism called the "Endorsed Standards Override Mechanism" to allow replacement of APIs created outside of the JCP (i.e. DOM and SAX from W3C). It can also be used to update the XML parser implementation. For more information, see: http://docs.oracle.com/javase/1.5.0/docs/guide/standards/index.html.

    Tomcat utilizes this mechanism by including the system property setting -Djava.endorsed.dirs=$JAVA_ENDORSED_DIRS in the command line that starts the container. The default value of this option is $CATALINA_HOME/endorsed. This endorsed directory is not created by default.

    When running under a security manager the locations from which classes are permitted to be loaded will also depend on the contents of your policy file. See Security Manager HOW-TO for further information.

    tomcat7-7.0.52/webapps/docs/deployer-howto.xml0000644000175100017510000003742112271304167021251 0ustar locutuslocutus ]> &project; Allistair Crossley Tomcat Web Application Deployment

    Deployment is the term used for the process of installing a web application (either a 3rd party WAR or your own custom web application) into the Tomcat server.

    Web application deployment may be accomplished in a number of ways within the Tomcat server.

    • Statically; the web application is setup before Tomcat is started
    • Dynamically; by directly manipulating already deployed web applications (relying on auto-deployment feature) or remotely by using the Tomcat Manager web application

    The Tomcat Manager is a web application that can be used interactively (via HTML GUI) or programmatically (via URL-based API) to deploy and manage web applications.

    There are a number of ways to perform deployment that rely on the Manager web application. Apache Tomcat provides tasks for Apache Ant build tool. Apache Tomcat Maven Plugin project provides integration with Apache Maven. There is also a tool called the Client Deployer, which can be used from a command line and provides additional functionality such as compiling and validating web applications as well as packaging web application into web application resource (WAR) files.

    There is no installation required for static deployment of web applications as this is provided out of the box by Tomcat. Nor is any installation required for deployment functions with the Tomcat Manager, although some configuration is required as detailed in the Tomcat Manager manual. An installation is however required if you wish to use the Tomcat Client Deployer (TCD).

    The TCD is not packaged with the Tomcat core distribution, and must therefore be downloaded separately from the Downloads area. The download is usually labelled apache-tomcat-7.0.x-deployer.

    TCD has prerequisites of Apache Ant 1.6.2+ and a Java installation. Your environment should define an ANT_HOME environment value pointing to the root of your Ant installation, and a JAVA_HOME value pointing to your Java installation. Additionally, you should ensure Ant's ant command, and the Java javac compiler command run from the command shell that your operating system provides.

    1. Download the TCD distribution
    2. The TCD package need not be extracted into any existing Tomcat installation, it can be extracted to any location.
    3. Read Using the Tomcat Client Deployer

    In talking about deployment of web applications, the concept of a Context is required to be understood. A Context is what Tomcat calls a web application.

    In order to configure a Context within Tomcat a Context Descriptor is required. A Context Descriptor is simply an XML file that contains Tomcat related configuration for a Context, e.g naming resources or session manager configuration. In earlier versions of Tomcat the content of a Context Descriptor configuration was often stored within Tomcat's primary configuration file server.xml but this is now discouraged (although it currently still works).

    Context Descriptors not only help Tomcat to know how to configure Contexts but other tools such as the Tomcat Manager and TCD often use these Context Descriptors to perform their roles properly.

    The locations for Context Descriptors are:

    1. $CATALINA_BASE/conf/[enginename]/[hostname]/[webappname].xml
    2. $CATALINA_BASE/webapps/[webappname]/META-INF/context.xml

    Files in (1) are named [webappname].xml but files in (2) are named context.xml. If a Context Descriptor is not provided for a Context, Tomcat configures the Context using default values.

    If you are not interested in using the Tomcat Manager, or TCD, then you'll need to deploy your web applications statically to Tomcat, followed by a Tomcat startup. The location you deploy web applications to for this type of deployment is called the appBase which is specified per Host. You either copy a so-called exploded web application, i.e non-compressed, to this location, or a compressed web application resource .WAR file.

    The web applications present in the location specified by the Host's (default Host is "localhost") appBase attribute (default appBase is "$CATALINA_BASE/webapps") will be deployed on Tomcat startup only if the Host's deployOnStartup attribute is "true".

    The following deployment sequence will occur on Tomcat startup in that case:

    1. Any Context Descriptors will be deployed first.
    2. Exploded web applications not referenced by any Context Descriptor will then be deployed. If they have an associated .WAR file in the appBase and it is newer than the exploded web application, the exploded directory will be removed and the webapp will be redeployed from the .WAR
    3. .WAR files will be deployed

    It is possible to deploy web applications to a running Tomcat server.

    If the Host autoDeploy attribute is "true", the Host will attempt to deploy and update web applications dynamically, as needed, for example if a new .WAR is dropped into the appBase. For this to work, the Host needs to have background processing enabled which is the default configuration.

    autoDeploy set to "true" and a running Tomcat allows for:

    • Deployment of .WAR files copied into the Host appBase.
    • Deployment of exploded web applications which are copied into the Host appBase.
    • Re-deployment of a web application which has already been deployed from a .WAR when the new .WAR is provided. In this case the exploded web application is removed, and the .WAR is expanded again. Note that the explosion will not occur if the Host is configured so that .WARs are not exploded with a unpackWARs attribute set to "false", in which case the web application will be simply redeployed as a compressed archive.
    • Re-loading of a web application if the /WEB-INF/web.xml file (or any other resource defined as a WatchedResource) is updated.
    • Re-deployment of a web application if the Context Descriptor file from which the web application has been deployed is updated.
    • Re-deployment of dependent web applications if the global or per-host Context Descriptor file used by the web application is updated.
    • Re-deployment of a web application if a Context Descriptor file (with a filename corresponding to the Context path of the previously deployed web application) is added to the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory.
    • Undeployment of a web application if its document base (docBase) is deleted. Note that on Windows, this assumes that anti-locking features (see Context configuration) are enabled, otherwise it is not possible to delete the resources of a running web application.

    Note that web application reloading can also be configured in the loader, in which case loaded classes will be tracked for changes.

    The Tomcat Manager is covered in its own manual page.

    Finally, deployment of web application may be achieved using the Tomcat Client Deployer. This is a package which can be used to validate, compile, compress to .WAR, and deploy web applications to production or development Tomcat servers. It should be noted that this feature uses the Tomcat Manager and as such the target Tomcat server should be running.

    It is assumed the user will be familiar with Apache Ant for using the TCD. Apache Ant is a scripted build tool. The TCD comes pre-packaged with a build script to use. Only a modest understanding of Apache Ant is required (installation as listed earlier in this page, and familiarity with using the operating system command shell and configuring environment variables).

    The TCD includes Ant tasks, the Jasper page compiler for JSP compilation before deployment, as well as a task which validates the web application Context Descriptor. The validator task (class org.apache.catalina.ant.ValidatorTask) allows only one parameter: the base path of an exploded web application.

    The TCD uses an exploded web application as input (see the list of the properties used below). A web application that is programmatically deployed with the deployer may include a Context Descriptor in /META-INF/context.xml.

    The TCD includes a ready-to-use Ant script, with the following targets:

    • compile (default): Compile and validate the web application. This can be used standalone, and does not need a running Tomcat server. The compiled application will only run on the associated Tomcat X.Y.Z server release, and is not guaranteed to work on another Tomcat release, as the code generated by Jasper depends on its runtime component. It should also be noted that this target will also compile automatically any Java source file located in the /WEB-INF/classes folder of the web application.
    • deploy: Deploy a web application (compiled or not) to a Tomcat server.
    • undeploy: Undeploy a web application
    • start: Start web application
    • reload: Reload web application
    • stop: Stop web application

    In order for the deployment to be configured, create a file called deployer.properties in the TCD installation directory root. In this file, add the following name=value pairs per line:

    Additionally, you will need to ensure that a user has been setup for the target Tomcat Manager (which TCD uses) otherwise the TCD will not authenticate with the Tomcat Manager and the deployment will fail. To do this, see the Tomcat Manager page.

    • build: The build folder used will be, by default, ${build}/webapp/${path}. After the end of the execution of the compile target, the web application .WAR will be located at ${build}/webapp/${path}.war.
    • webapp: The directory containing the exploded web application which will be compiled and validated. By default, the folder is myapp.
    • path: Deployed context path of the web application, by default /myapp.
    • url: Absolute URL to the Tomcat Manager web application of a running Tomcat server, which will be used to deploy and undeploy the web application. By default, the deployer will attempt to access a Tomcat instance running on localhost, at http://localhost:8080/manager/text.
    • username: Tomcat Manager username (user should have a role of manager-script)
    • password: Tomcat Manager password.
    tomcat7-7.0.52/webapps/docs/jasper-howto.xml0000644000175100017510000004107212271304167020707 0ustar locutuslocutus ]> &project; Glenn L. Nielsen Peter Rossbach Jasper 2 JSP Engine How To

    Tomcat 7.0 uses the Jasper 2 JSP Engine to implement the JavaServer Pages 2.2 specification.

    Jasper 2 has been redesigned to significantly improve performance over the original Jasper. In addition to general code improvements the following changes were made:

    • JSP Custom Tag Pooling - The java objects instantiated for JSP Custom Tags can now be pooled and reused. This significantly boosts the performance of JSP pages which use custom tags.
    • Background JSP compilation - If you make a change to a JSP page which had already been compiled Jasper 2 can recompile that page in the background. The previously compiled JSP page will still be available to serve requests. Once the new page has been compiled successfully it will replace the old page. This helps improve availability of your JSP pages on a production server.
    • Recompile JSP when included page changes - Jasper 2 can now detect when a page included at compile time from a JSP has changed and then recompile the parent JSP.
    • JDT used to compile JSP pages - The Eclipse JDT Java compiler is now used to perform JSP java source code compilation. This compiler loads source dependencies from the container classloader. Ant and javac can still be used.

    Jasper is implemented using the servlet class org.apache.jasper.servlet.JspServlet.

    By default Jasper is configured for use when doing web application development. See the section Production Configuration for information on configuring Jasper for use on a production Tomcat server.

    The servlet which implements Jasper is configured using init parameters in your global $CATALINA_BASE/conf/web.xml.

    • checkInterval - If development is false and checkInterval is greater than zero, background compiles are enabled. checkInterval is the time in seconds between checks to see if a JSP page (and its dependent files) needs to be recompiled. Default 0 seconds.
    • classdebuginfo - Should the class file be compiled with debugging information? true or false, default true.
    • classpath - Defines the class path to be used to compile the generated servlets. This parameter only has an effect if the ServletContext attribute org.apache.jasper.Constants.SERVLET_CLASSPATH is not set. This attribute is always set when Jasper is used within Tomcat. By default the classpath is created dynamically based on the current web application.
    • compiler - Which compiler Ant should use to compile JSP pages. The valid values for this are the same as for the compiler attribute of Ant's javac task. If the value is not set, then the default Eclipse JDT Java compiler will be used instead of using Ant. There is no default value. If this attribute is set then setenv.[sh|bat] should be used to add ant.jar, ant-launcher.jar and tools.jar to the CLASSPATH environment variable.
    • compilerSourceVM - What JDK version are the source files compatible with? (Default value: 1.6)
    • compilerTargetVM - What JDK version are the generated files compatible with? (Default value: 1.6)
    • development - Is Jasper used in development mode? If true, the frequency at which JSPs are checked for modification may be specified via the modificationTestInterval parameter.true or false, default true.
    • displaySourceFragment - Should a source fragment be included in exception messages? true or false, default true.
    • dumpSmap - Should the SMAP info for JSR45 debugging be dumped to a file? true or false, default false. false if suppressSmap is true.
    • enablePooling - Determines whether tag handler pooling is enabled. This is a compilation option. It will not alter the behaviour of JSPs that have already been compiled. true or false, default true.
    • engineOptionsClass - Allows specifying the Options class used to configure Jasper. If not present, the default EmbeddedServletOptions will be used.
    • errorOnUseBeanInvalidClassAttribute - Should Jasper issue an error when the value of the class attribute in an useBean action is not a valid bean class? true or false, default true.
    • fork - Have Ant fork JSP page compiles so they are performed in a separate JVM from Tomcat? true or false, default true.
    • genStringAsCharArray - Should text strings be generated as char arrays, to improve performance in some cases? Default false.
    • ieClassId - The class-id value to be sent to Internet Explorer when using <jsp:plugin> tags. Default clsid:8AD9C840-044E-11D1-B3E9-00805F499D93.
    • javaEncoding - Java file encoding to use for generating java source files. Default UTF8.
    • keepgenerated - Should we keep the generated Java source code for each page instead of deleting it? true or false, default true.
    • mappedfile - Should we generate static content with one print statement per input line, to ease debugging? true or false, default true.
    • maxLoadedJsps - The maximum number of JSPs that will be loaded for a web application. If more than this number of JSPs are loaded, the least recently used JSPs will be unloaded so that the number of JSPs loaded at any one time does not exceed this limit. A value of zero or less indicates no limit. Default -1
    • jspIdleTimeout - The amount of time in seconds a JSP can be idle before it is unloaded. A value of zero or less indicates never unload. Default -1
    • modificationTestInterval - Causes a JSP (and its dependent files) to not be checked for modification during the specified time interval (in seconds) from the last time the JSP was checked for modification. A value of 0 will cause the JSP to be checked on every access. Used in development mode only. Default is 4 seconds.
    • recompileOnFail - If a JSP compilation fails should the modificationTestInterval be ignored and the next access trigger a re-compilation attempt? Used in development mode only and is disabled by default as compilation may be expensive and could lead to excessive resource usage.
    • scratchdir - What scratch directory should we use when compiling JSP pages? Default is the work directory for the current web application.
    • suppressSmap - Should the generation of SMAP info for JSR45 debugging be suppressed? true or false, default false.
    • trimSpaces - Should white spaces in template text between actions or directives be trimmed ?, default false.
    • xpoweredBy - Determines whether X-Powered-By response header is added by generated servlet. true or false, default false.

    The Java compiler from Eclipse JDT in included as the default compiler. It is an advanced Java compiler which will load all dependencies from the Tomcat class loader, which will help tremendously when compiling on large installations with tens of JARs. On fast servers, this will allow sub-second recompilation cycles for even large JSP pages.

    Apache Ant, which was used in previous Tomcat releases, can be used instead of the new compiler by configuring the compiler attribute as explained above.

    As described in bug 39089, a known JVM issue, bug 6294277, may cause a java.lang.InternalError: name is too long to represent exception when compiling very large JSPs. If this is observed then it may be worked around by using one of the following:

    • reduce the size of the JSP
    • disable SMAP generation and JSR-045 support by setting suppressSmap to true.

    The main JSP optimization which can be done is precompilation of JSPs. However, this might not be possible (for example, when using the jsp-property-group feature) or practical, in which case the configuration of the Jasper servlet becomes critical.

    When using Jasper 2 in a production Tomcat server you should consider making the following changes from the default configuration.

    • development - To disable on access checks for JSP pages compilation set this to false.
    • genStringAsCharArray - To generate slightly more efficient char arrays, set this to true.
    • modificationTestInterval - If development has to be set to true for any reason (such as dynamic generation of JSPs), setting this to a high value will improve performance a lot.
    • trimSpaces - To remove useless bytes from the response, set this to true.

    Using Ant is the preferred way to compile web applications using JSPC. Note that when pre-compiling JSPs, SMAP information will only be included in the final classes if suppressSmap is false and compile is true. Use the script given below (a similar script is included in the "deployer" download) to precompile a webapp:

    <project name="Webapp Precompilation" default="all" basedir="."> <import file="${tomcat.home}/bin/catalina-tasks.xml"/> <target name="jspc"> <jasper validateXml="false" uriroot="${webapp.path}" webXmlFragment="${webapp.path}/WEB-INF/generated_web.xml" outputDir="${webapp.path}/WEB-INF/src" /> </target> <target name="compile"> <mkdir dir="${webapp.path}/WEB-INF/classes"/> <mkdir dir="${webapp.path}/WEB-INF/lib"/> <javac destdir="${webapp.path}/WEB-INF/classes" optimize="off" debug="on" failonerror="false" srcdir="${webapp.path}/WEB-INF/src" excludes="**/*.smap"> <classpath> <pathelement location="${webapp.path}/WEB-INF/classes"/> <fileset dir="${webapp.path}/WEB-INF/lib"> <include name="*.jar"/> </fileset> <pathelement location="${tomcat.home}/lib"/> <fileset dir="${tomcat.home}/lib"> <include name="*.jar"/> </fileset> <fileset dir="${tomcat.home}/bin"> <include name="*.jar"/> </fileset> </classpath> <include name="**" /> <exclude name="tags/**" /> </javac> </target> <target name="all" depends="jspc,compile"> </target> <target name="cleanup"> <delete> <fileset dir="${webapp.path}/WEB-INF/src"/> <fileset dir="${webapp.path}/WEB-INF/classes/org/apache/jsp"/> </delete> </target> </project>

    The following command line can be used to run the script (replacing the tokens with the Tomcat base path and the path to the webapp which should be precompiled):
    $ANT_HOME/bin/ant -Dtomcat.home=<$TOMCAT_HOME> -Dwebapp.path=<$WEBAPP_PATH>

    Then, the declarations and mappings for the servlets which were generated during the precompilation must be added to the web application deployment descriptor. Insert the ${webapp.path}/WEB-INF/generated_web.xml at the right place inside the ${webapp.path}/WEB-INF/web.xml file. Restart the web application (using the manager) and test it to verify it is running fine with precompiled servlets. An appropriate token placed in the web application deployment descriptor may also be used to automatically insert the generated servlet declarations and mappings using Ant filtering capabilities. This is actually how all the webapps distributed with Tomcat are automatically compiled as part of the build process.

    At the jasper task you can use the option addWebXmlMappings for automatic merge the ${webapp.path}/WEB-INF/generated_web.xml with the current web application deployment descriptor at ${webapp.path}/WEB-INF/web.xml. When you want to use Java 6 features inside your jsp's, add the following javac compiler task attributes: source="1.6" target="1.6". For live applications you can also compile with optimize="on" and without debug info debug="off".

    When you don't want to stop the jsp generation at first jsp syntax error, use failOnError="false"and with showSuccess="true" all successfull jsp to java generation are printed out. Sometimes it is very helpfull, when you cleanup the generate java source files at ${webapp.path}/WEB-INF/src and the compile jsp servlet classes at ${webapp.path}/WEB-INF/classes/org/apache/jsp.

    Hints:

    • When you switch to another Tomcat release, then regenerate and recompile your jsp's with the new Tomcat version.
    • Use java system property at server runtime to disable PageContext pooling org.apache.jasper.runtime.JspFactoryImpl.USE_POOL=false. and limit the buffering with org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true. Note that changing from the defaults may affect performance, but it will vary depending on the application.

    There are a number of extension points provided within Jasper that enable the user to optimise the behaviour for their environment.

    The first of these extension points is the tag plug-in mechanism. This allows alternative implementations of tag handlers to be provided for a web application to use. Tag plug-ins are registered via a tagPlugins.xml file located under WEB-INF. A sample plug-in for the JSTL is included with Jasper.

    The second extension point is the Expression Language interpreter. Alternative interpreters may be configured through the ServletContext. See the ELInterpreterFactory javadoc for details of how to configure an alternative EL interpreter.

    tomcat7-7.0.52/webapps/docs/index.xml0000644000175100017510000002471212271304167017376 0ustar locutuslocutus ]> &project; Craig R. McClanahan Remy Maucherat Yoav Shapira Documentation Index

    This is the top-level entry point of the documentation bundle for the Apache Tomcat Servlet/JSP container. Apache Tomcat version 7.0 implements the Servlet 3.0 and JavaServer Pages 2.2 specifications from the Java Community Process, and includes many additional features that make it a useful platform for developing and deploying web applications and web services.

    Select one of the links from the navigation menu (to the left) to drill down to the more detailed documentation that is available. Each available manual is described in more detail below.

    The following documents will assist you in downloading, installing Apache Tomcat 7, and using many of the Apache Tomcat features.

    1. Introduction - A brief, high level, overview of Apache Tomcat.
    2. Setup - How to install and run Apache Tomcat on a variety of platforms.
    3. First web application - An introduction to the concepts of a web application as defined in the Servlet Specification. Covers basic organization of your web application source tree, the structure of a web application archive, and an introduction to the web application deployment descriptor (/WEB-INF/web.xml).
    4. Deployer - Operating the Apache Tomcat Deployer to deploy, precompile, and validate web applications.
    5. Manager - Operating the Manager web app to deploy, undeploy, and redeploy applications while Apache Tomcat is running.
    6. Realms and Access Control - Description of how to configure Realms (databases of users, passwords, and their associated roles) for use in web applications that utilize Container Managed Security.
    7. Security Manager - Configuring and using a Java Security Manager to support fine-grained control over the behavior of your web applications.
    8. JNDI Resources - Configuring standard and custom resources in the JNDI naming context that is provided to each web application.
    9. JDBC DataSource - Configuring a JNDI DataSoure with a DB connection pool. Examples for many popular databases.
    10. Classloading - Information about class loading in Apache Tomcat, including where to place your application classes so that they are visible.
    11. JSPs - Information about Jasper configuration, as well as the JSP compiler usage.
    12. SSL - Installing and configuring SSL support so that your Apache Tomcat will serve requests using the https protocol.
    13. SSI - Using Server Side Includes in Apache Tomcat.
    14. CGI - Using CGIs with Apache Tomcat.
    15. Proxy Support - Configuring Apache Tomcat to run behind a proxy server (or a web server functioning as a proxy server).
    16. MBean Descriptor - Configuring MBean descriptors files for custom components.
    17. Default Servlet - Configuring the default servlet and customizing directory listings.
    18. Apache Tomcat Clustering - Enable session replication in a Apache Tomcat environment.
    19. Balancer - Configuring, using, and extending the load balancer application.
    20. Connectors - Connectors available in Apache Tomcat, and native web server integration.
    21. Monitoring and Management - Enabling JMX Remote support, and using tools to monitor and manage Apache Tomcat.
    22. Logging - Configuring logging in Apache Tomcat.
    23. Apache Portable Runtime - Using APR to provide superior performance, scalability and better integration with native server technologies.
    24. Virtual Hosting - Configuring virtual hosting in Apache Tomcat.
    25. Advanced IO - Extensions available over regular, blocking IO.
    26. Additional Components - Obtaining additional, optional components.
    27. Using Tomcat libraries with Maven - Obtaining Tomcat jars through Maven.
    28. Security Considerations - Options to consider when securing an Apache Tomcat installation.
    29. Windows Service - Running Tomcat as a service on Microsoft Windows.
    30. Windows Authentication - Configuring Tomcat to use integrated Windows authentication.
    31. High Concurrency JDBC Pool - Configuring Tomcat to use an alternative JDBC pool.
    32. WebSocket support - Developing WebSocket applications for Apache Tomcat.

    The following documents are aimed at System Administrators who are responsible for installing, configuring, and operating an Apache Tomcat server.

    The following documents are for Java developers who wish to contribute to the development of the Apache Tomcat project.

    • Building from Source - Details the steps necessary to download Apache Tomcat source code (and the other packages that it depends on), and build a binary distribution from those sources.
    • Changelog - Details the changes made to Apache Tomcat.
    • Status - Apache Tomcat development status.
    • Developers - List of active Apache Tomcat contributors.
    • Functional Specifications - Requirements specifications for features of the Catalina servlet container portion of Apache Tomcat.
    • Javadocs - Javadoc API documentation for Apache Tomcat's internals.
    • Apache Tomcat Architecture - Documentation of the Apache Tomcat Server Architecture.
    tomcat7-7.0.52/webapps/host-manager/0000755000175100017510000000000012301126373017167 5ustar locutuslocutustomcat7-7.0.52/webapps/host-manager/META-INF/0000755000175100017510000000000012301126373020327 5ustar locutuslocutustomcat7-7.0.52/webapps/host-manager/META-INF/context.xml0000644000175100017510000000224712271304167022547 0ustar locutuslocutus tomcat7-7.0.52/webapps/host-manager/images/0000755000175100017510000000000012301126373020434 5ustar locutuslocutustomcat7-7.0.52/webapps/host-manager/images/tomcat.gif0000644000175100017510000000361610457676032022434 0ustar locutuslocutusGIF89a\#!Wpq&ӳGB4 ok]ϴbuҤ!,\I8-)\(Zahr**?;8.sJGIMC*ID-w18KǏLx t; u; ~8ٚ- 10 rs5 t6ċxDɲ9!lIܥ35iydfNCL3k ɐ7%M]IX/<|baN@dT\8ʍDKfe^:B TTI QjX{CJpMJ  tQ eV @ODzBbYϘ9b4-NiC$o9$_H`Z o7Qa(b)K^5D#T`U/Ǥ0}%= <=05}ъR  ph#4$޵$@X@B@14  #Kz@gT:DUn4+& Q1S:9EI_P%Ce<B~e@,Mhxgf$5E@fw(RbHXGP*Q衙ǧPGNb熘\ꯘ&G cq肃\PFMٺMHն?aRA2K5{` tjFBo fr)-,Gye6&UوeT r%9"/cfIA |h p`/t ;IX| fp+pJ()0T$kj 09=$ag6ڇ`= _c\zLdXDڢ a܏)7#HkՂp@w"tX'rK(i䣂fNKǞg1W`w M-mNAz_~9e OԽ @c(n}W$q7@@~ 0Mz8V/ a/E'q㩮Y _"(uc2AǃrRT$JP !yCm(/Q ZܜCr w%"j[dDž`v'{%&L1{bȭt<+hfɱ'=H1BRzc f P "C̝'UipЖLЗx?2}0^tR /` {{[CׄNX17 |1Qt_KVL3D {u+&3Jr.)2)Ca>F(@\f.5I;%pRC8fQ7B=S2L3a[ ʷ̥)ةM.K(M# $@F(Šz n!gph߷F7ȧ6ʵbϷ+8)u& )a͚3 k?k<d Ϙ̀Oj .mZ8P x {TH`D lm[0ZxgB#$L;4xpa|.t]!ծ CuxNjJ>uzKtwE;tomcat7-7.0.52/webapps/host-manager/images/code.gif0000644000175100017510000000061210457676032022050 0ustar locutuslocutusGIF89a000///111VVss]]߿..ڊEEJJ/10dd||22KK@@退NNN___kkŰOOO疖002,@pH,Py ((XP80"P, p< 7Zm#dBHSgxg ~E eh tE TqoDg F } B !g"u#$%&' ()*+N,+-.H//#+M00RSA;tomcat7-7.0.52/webapps/host-manager/images/void.gif0000644000175100017510000000005310457676032022076 0ustar locutuslocutusGIF89a! ,L;tomcat7-7.0.52/webapps/host-manager/images/add.gif0000644000175100017510000000201510457676032021665 0ustar locutuslocutusGIF89a# ac 4n _IUr 5؉P8Cޘ\CQJSYfĄ 1ݘ]@@CI[dÁ ӵ $ M>Aà ӖЋҠ ^UyI+ 8."0000026/%A/ Йщѕnd>,אЗтҐ~wđ */Bۓ ǩ5/#Ү,-IڏJKR):1!zohxw속7 EP*Odk2wNh2 FR%e*rC), pp&d p(@0p(X @P ,\A<|yD#H0*Vh 1da5lQu:v B)0#H(Y¤'PHIa *V`ɢe .Dz L1c)cCgФQM7ođ3EsԱsO={30~ $hEQ ,7УG(@@;tomcat7-7.0.52/webapps/host-manager/images/design.gif0000644000175100017510000000114010457676032022404 0ustar locutuslocutusGIF89a???>>>??=@@@=?>>@?*EVeOB?2- z%sJb*FT1Iaooopno@>?Ͽ®¬л~nod|dSkS#}&IJϹͫЦΠБu܃~mskq*w/¯в,ŀ  !"#$%%&&̃''()*++*,-؊./012345667(89:;<=>>? 2H!CgDnPA$%!I4M]ɓ'"Rd"!,ɬ4)Ҥl;tomcat7-7.0.52/webapps/host-manager/images/fix.gif0000644000175100017510000000053110457676032021724 0ustar locutuslocutusGIF89a OOO{st\N7J<,BK2S .3J2QCK5Q 0QK3R R>O9輱3,~@ȤrY\2K`* B@8 MHN`eCQh8$9`)FCX^B !"K#$C%&'()FaJ*+zVB,&-.*/0V1234BþA;tomcat7-7.0.52/webapps/host-manager/images/docs.gif0000644000175100017510000000040510457676032022066 0ustar locutuslocutusGIF89a000///111߿/10NNN___ᰰOOO002, diA0(p `i A$&>bX4"M` i˜>Iv_P6.6F@ࢵњ B& Uf}vxr4lxy(-23!;tomcat7-7.0.52/webapps/host-manager/images/asf-logo.gif0000644000175100017510000001615710457676032022660 0ustar locutuslocutusGIF89ad~fff̙3olJff3OEfffOf3{7O33fffPPPf3333fN@EσYf/XTJϷTffffuf3ff3JmvdfffVPEOVNjE H̙f|~cv3fǰdlԮifIvt33gt|tA{F|{7-}L"Bjx̙OKVE휃0*PjOV]~ff33{M VJqYOCLVAMY UQPw{}Hm~_!tr lT=GQx|N\n{8QuNNNlUHiïNy/f3fQ̙!,d@H*\ȰÇ#JHŋ3jx1,HP8  =p(Pϟ@ JQ:(3ǧ a8 WhB+x FAK͛شB`ǀGfF!@ 5ᆄ+V(`f&<qbwRt@:uL@# Xz+1u@k̗q[W&tkA yB KE ``>CpA 7 W.t7CsjG(hB z6eh^k&U - }(\m]F% @4F +P"QY‘H^A4@W} X_A)P S h@Y lfolq9KkFm#*TxL-VWBf J(xhG{|dp\P (ܰ)74܀DCJRSYGk[by]w.Øk$E\* a&n} D`;=[CMvz7/y?}uwHD/}>͓~Y/ A BgoC@9P̠2,/Bp`FBUՂ%7&70` qXѡ3W1AW@PO/ӜB+xFʉKsVQGez ϤYm|~^ѱ!: <`Zo>06fE"D=I"E* YPpOM^D >AԻmkcB3JWB,3^~kw1 TMؖ -A*ʍ6q(BW(H! GGFdk6Ǔ bA4Ѐء m`9K0^Mk DC8)- hB~P-s!D ]\2Es!`R-,EЀnv@7@S@h %!OHjD@CKBCNpHJ) [ׄTs>Ǖ1{2JC14,c߳mHhd`Qz3:$tCYb:le؍ru臽vc5 .k^zasnZ?G$ժLݡ-qzC6wLj7]겖UucDz2~@s˳ۄδtil~X$򖱤-HZ!"3mo D  ǹQxvϋ1lJN0q#_[I.wL@!/N>2!C$uAo~dm%Pᄏҝ+%Hfz:>5Hb1%kvtwo ڈ#B3h$* h3ELarđ` 6a.vWA1w/X'cWmpyq6X/|!_~Krf $+A5(+lG0A~(3Gmh@M[Jkj@ ,4HQɷ [vF'v 1fK]wI8j޲ V}]a1`"[ 8]hypNOG ن-mxˁRSI'*"ljw0R DUoBv@Ӷp7O M^R4}SST!uHNdc0"Q77 syC1~ P4(@PbPvGzg^uujUgeWrLK/1y[Y\ȅB &g0}(4)NBE*g.7ef&O@UOX% <9|nՄ1:"% W${f%gF;؄R@@=4mcROYX&`osqM4S4-E&XԅdTsWdp^ap/!N]u)apraLOq pO׃B@A9d>*"w\r{Jh_c\{WxUWKqɂ2ypUO0 >BsS٤~ 'lq vtBTv`irPu)1"m&iqW8WdΤ,)ג4ْwWS'CȂ$\L;95G!w$I^a:@qDYQodfKpdVqb]c9K!C5Y?g_V7ҕ]1|LCu%A1sg+4\g9d 8NUW8VyhuK]SX闊4&:ݕ,AL0ty㚥YC!v5i6IRI|a'x3 hV)ǩoi]S^_CgǙLhz^v:i*sY^$LBhq7exguٕFJf`lE  WR&7RVeOS%dg]lW7#ha%#f!7b1v63q0<22&624{6$-6ZIʜ D1ee<ifeDӥAdp$n?Y7$1cd9Î`ZQ/y4֡SL?) = S2کjZD:ڪgcr w,20<=:G ` !%`2P2@ ^H8^J RJ1kii'0'B "ĆEtyTi"x%_m&ER;lwln)PF}LGL_V('RpԮ] gCj gCIv1{}ŒLa?aб?e7WsSr@KUBZ ៨ k6i3isQDA$xs*Ү7'4D)>" 4z:8ZI؄ֵ FF~`#pNkD葨v$RBG1,,}THwI+,}qKw[qsKWpą4DEP#.E5l \K2s48%uez߱iǛhZ3| 0IBV9t $4pD}l"x!1WM!;J3~Wn7«Gqa3\ķ9{$Q 4|rc̿Y3zk8,qCroW}dh!Xʎm]1pnD"TLJ,/2T{.1Z_tWe̼PE1kJ7J'˥|8slX"!HI,pTt$BOǑkrya a$ QMÒP Cmv*0b"tIL+E$Bln}B'GW1+pPpRP@R=ZȿwiH:iǒRMɼ[M{?E^0]vƢ,;@E0&,P.Ru҂ۄxNa"0QE`SKehA`&M0/ Z鎚hOQ`čHas9 qV8;WG50 {p.os6Ex=CMcM `&vTP5/v$)WOH8GpL!KPYPO`tO&0޼qCta#/tM.X,!crҝ& WXs, ?0),a/&U/P}G.0ْm0~ NH;NMWP90p4uku|%1 1ԥ41;FBACiwAQ 0zV^/}oO_ XDŽ5\N` <1GUsd)i`Iݞ 4aaN 1᳇EauXX8^VvrBmawVM^9UXcɄٿ {A 0$H0À D0a@BC hq-`Aɏ%0aCD1M9I0Č) š0L8re̚YQVtVK%{rNNxq@^OjsCy,)pEia<1eLK0ʕxTVވ8g݁beYUC+U\J1}}yuŹOca-S>91d;6춠I'FË:semW >h㋮ .!I;M+žZAAlSQ9 /$1b#>yͿ-22$fS*ro5c !'#z3# ؼHI6O=׌TjȐ,h.D. S5'4uB>&QҳG1QʱpTSOMU8m@肽-X}$_.ٲeXafmڎZj[pw\r5\tUL+ե6dX]z]{|YQ:]3j_7asABaD_ ~ч 1He4EJwҩ H^ $*hD<%iy%%3kRT^+)cׅ0@wX'x-jP^f 'Zfb{kۘ꫒xkk,lT֓k71,n N BA$bV:sQJ;h3߃#\ƫr*u7_w:-Ȼԍݛ_zǾw7׽+ f%}MUΊp?p܍6E0e- 榷H,H?و$ |AX@T1ZNL JYN3eKNJE|{^wCOZ q-_g:@!&QKdbD(FQS4^@;tomcat7-7.0.52/webapps/host-manager/images/update.gif0000644000175100017510000000116310457676032022422 0ustar locutuslocutusGIF89a???>>>??=@@@=?>>@?*EVeOB?2- z%sJb*FT1Iaooopno@>?Ͽ ®¬2 Ģ5E:л~nod|d$,#}&Y\/t1 /%IJϹͫЦΠ7Бu܃Xjt܅ޡ*~mskq$**w/؆4q5 / ¯ -͵в#,؀  !"#$%&փ''()*++*,-./0123456789:;<=>(?@ABC1rI%K XǤ'PHB+qK,ZpE D(90a\S4`2dDEa0YZiRIH%M:(;tomcat7-7.0.52/webapps/host-manager/WEB-INF/0000755000175100017510000000000012301126373020216 5ustar locutuslocutustomcat7-7.0.52/webapps/host-manager/WEB-INF/web.xml0000644000175100017510000001134612271304167021527 0ustar locutuslocutus Tomcat Host Manager Application A scriptable host management web application for the Tomcat Web Server; Manager lets you view, create and remove virtual hosts. HostManager org.apache.catalina.manager.host.HostManagerServlet debug 2 HTMLHostManager org.apache.catalina.manager.host.HTMLHostManagerServlet debug 2 SetCharacterEncoding org.apache.catalina.filters.SetCharacterEncodingFilter encoding UTF-8 SetCharacterEncoding /* CSRF org.apache.catalina.filters.CsrfPreventionFilter entryPoints /html,/html/,/html/list,/index.jsp CSRF HTMLHostManager HostManager /text/* HTMLHostManager /html/* HostManager commands /text/* admin-script HTMLHostManager commands /html/* admin-gui BASIC Tomcat Host Manager Application The role that is required to log in to the Host Manager Application HTML interface admin-gui The role that is required to log in to the Host Manager Application text interface admin-script 401 /WEB-INF/jsp/401.jsp 403 /WEB-INF/jsp/403.jsp 404 /WEB-INF/jsp/404.jsp tomcat7-7.0.52/webapps/host-manager/WEB-INF/jsp/0000755000175100017510000000000012301126373021012 5ustar locutuslocutustomcat7-7.0.52/webapps/host-manager/WEB-INF/jsp/403.jsp0000644000175100017510000000701011656645547022061 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> 403 Access Denied

    403 Access Denied

    You are not authorized to view this page.

    If you have already configured the Host Manager application to allow access and you have used your browsers back button, used a saved book-mark or similar then you may have triggered the cross-site request forgery (CSRF) protection that has been enabled for the HTML interface of the Host Manager application. You will need to reset this protection by returning to the main Host Manager page. Once you return to this page, you will be able to continue using the Host Manager appliction's HTML interface normally. If you continue to see this access denied message, check that you have the necessary permissions to access this application.

    If you have not changed any configuration files, please examine the file conf/tomcat-users.xml in your installation. That file must contain the credentials to let you use this webapp.

    For example, to add the admin-gui role to a user named tomcat with a password of s3cret, add the following to the config file listed above.

    <role rolename="admin-gui"/>
    <user username="tomcat" password="s3cret" roles="admin-gui"/>
    

    Note that for Tomcat 7 onwards, the roles required to use the host manager application were changed from the single admin role to the following two roles. You will need to assign the role(s) required for the functionality you wish to access.

    • admin-gui - allows access to the HTML GUI
    • admin-script - allows access to the text interface

    The HTML interface is protected against CSRF but the text interface is not. To maintain the CSRF protection:

    • Users with the admin-gui role should not be granted the admin-script role.
    • If the text interface is accessed through a browser (e.g. for testing since this interface is intended for tools not humans) then the browser must be closed afterwards to terminate the session.
    tomcat7-7.0.52/webapps/host-manager/WEB-INF/jsp/404.jsp0000644000175100017510000000464211542062150022043 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ page import="org.apache.catalina.util.RequestUtil" %> 404 Not found

    404 Not found

    The page you tried to access (<%=RequestUtil.filter((String) request.getAttribute( "javax.servlet.error.request_uri"))%>) does not exist.

    The Host Manager application has been re-structured for Tomcat 7 onwards and some URLs have changed. All URLs used to access the Manager application should now start with one of the following options:

    • <%=request.getContextPath()%>/html for the HTML GUI
    • <%=request.getContextPath()%>/text for the text interface

    Note that the URL for the text interface has changed from "<%=request.getContextPath()%>" to "<%=request.getContextPath()%>/text".

    You probably need to adjust the URL you are using to access the Host Manager application. However, there is always a chance you have found a bug in the Host Manager application. If you are sure you have found a bug, and that the bug has not already been reported, please report it to the Apache Tomcat team.

    tomcat7-7.0.52/webapps/host-manager/WEB-INF/jsp/401.jsp0000644000175100017510000000542111542062150022034 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> 401 Unauthorized

    401 Unauthorized

    You are not authorized to view this page. If you have not changed any configuration files, please examine the file conf/tomcat-users.xml in your installation. That file must contain the credentials to let you use this webapp.

    For example, to add the admin-gui role to a user named tomcat with a password of s3cret, add the following to the config file listed above.

    <role rolename="admin-gui"/>
    <user username="tomcat" password="s3cret" roles="admin-gui"/>
    

    Note that for Tomcat 7 onwards, the roles required to use the host manager application were changed from the single admin role to the following two roles. You will need to assign the role(s) required for the functionality you wish to access.

    • admin-gui - allows access to the HTML GUI
    • admin-script - allows access to the text interface

    The HTML interface is protected against CSRF but the text interface is not. To maintain the CSRF protection:

    • Users with the admin-gui role should not be granted the admin-script role.
    • If the text interface is accessed through a browser (e.g. for testing since this interface is intended for tools not humans) then the browser must be closed afterwards to terminate the session.
    tomcat7-7.0.52/webapps/host-manager/manager.xml0000644000175100017510000000202312271304167021325 0ustar locutuslocutus tomcat7-7.0.52/webapps/host-manager/index.jsp0000644000175100017510000000157111420020730021007 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <% response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + "/html")); %>tomcat7-7.0.52/webapps/examples/0000755000175100017510000000000012301126373016420 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/0000755000175100017510000000000012301126373017447 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/web.xml0000644000175100017510000003455012271304167020762 0ustar locutuslocutus Servlet and JSP Examples. Servlet and JSP Examples Timing filter filters.ExampleFilter attribute filters.ExampleFilter Request Dumper Filter org.apache.catalina.filters.RequestDumperFilter Set Character Encoding org.apache.catalina.filters.SetCharacterEncodingFilter encoding EUC_JP ignore true Compression Filter compressionFilters.CompressionFilter compressionThreshold 128 compressionBuffer 8192 compressionMimeTypes text/html,text/plain,text/xml debug 0 listeners.ContextListener listeners.SessionListener ServletToJsp ServletToJsp ChatServlet chat.ChatServlet CompressionFilterTestServlet compressionFilters.CompressionFilterTestServlet HelloWorldExample HelloWorldExample RequestInfoExample RequestInfoExample RequestHeaderExample RequestHeaderExample RequestParamExample RequestParamExample CookieExample CookieExample SessionExample SessionExample ChatServlet /jsp/chat/chat CompressionFilterTestServlet /CompressionTest HelloWorldExample /servlets/servlet/HelloWorldExample RequestInfoExample /servlets/servlet/RequestInfoExample/* RequestHeaderExample /servlets/servlet/RequestHeaderExample RequestParamExample /servlets/servlet/RequestParamExample CookieExample /servlets/servlet/CookieExample SessionExample /servlets/servlet/SessionExample ServletToJsp /servletToJsp http://tomcat.apache.org/debug-taglib /WEB-INF/jsp/debug-taglib.tld http://tomcat.apache.org/example-taglib /WEB-INF/jsp/example-taglib.tld http://tomcat.apache.org/jsp2-example-taglib /WEB-INF/jsp2/jsp2-example-taglib.tld Special property group for JSP Configuration JSP example. JSPConfiguration /jsp/jsp2/misc/config.jsp true ISO-8859-1 true /jsp/jsp2/misc/prelude.jspf /jsp/jsp2/misc/coda.jspf Example Security Constraint Protected Area /jsp/security/protected/* DELETE GET POST PUT tomcat role1 FORM Example Form-Based Authentication Area /jsp/security/protected/login.jsp /jsp/security/protected/error.jsp role1 tomcat minExemptions java.lang.Integer 1 foo/name1 java.lang.String value1 foo/bar/name2 java.lang.Boolean true name3 java.lang.Integer 1 foo/name4 java.lang.Integer 10 async0 async.Async0 true async0 /async/async0 async1 async.Async1 true async1 /async/async1 async2 async.Async2 true async2 /async/async2 async3 async.Async3 true async3 /async/async3 stock async.AsyncStockServlet true stock /async/stockticker wsEchoStream websocket.tc7.echo.EchoStream wsEchoStream /websocket/tc7/echoStream wsEchoMessage websocket.tc7.echo.EchoMessage wsEchoMessage /websocket/tc7/echoMessage wsChat websocket.tc7.chat.ChatWebSocketServlet wsChat /websocket/tc7/chat wsSnake websocket.tc7.snake.SnakeWebSocketServlet wsSnake /websocket/tc7/snake websocket.drawboard.DrawboardContextListener index.html index.xhtml index.htm index.jsp tomcat7-7.0.52/webapps/examples/WEB-INF/lib/0000755000175100017510000000000012301126372020214 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/jsp/0000755000175100017510000000000012301126372020242 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/jsp/example-taglib.tld0000644000175100017510000000654212271304167023657 0ustar locutuslocutus 1.0 1.2 simple http://tomcat.apache.org/example-taglib A simple tab library for the examples ShowSource examples.ShowSource Display JSP sources jspFile true true foo examples.FooTag examples.FooTagExtraInfo JSP Perform a server side action; uses 3 mandatory attributes att1 true att2 true att3 true log examples.LogTag TAGDEPENDENT Perform a server side action; Log the message. toBrowser false values examples.ValuesTag empty Accept and return values of different types. This tag is used to illustrate type coercions. object false true java.lang.Object string false true java.lang.String long false true long double false true double tomcat7-7.0.52/webapps/examples/WEB-INF/jsp/debug-taglib.tld0000644000175100017510000000370312271304167023306 0ustar locutuslocutus 1.0 1.2 debug http://tomcat.apache.org/debug-taglib This tag library defines no tags. Instead, its purpose is encapsulated in the TagLibraryValidator implementation that simply outputs the XML version of a JSP page to standard output, whenever this tag library is referenced in a "taglib" directive in a JSP page. validators.DebugValidator log examples.LogTag TAGDEPENDENT Perform a server side action; Log the message. toBrowser false tomcat7-7.0.52/webapps/examples/WEB-INF/jsp/applet/0000755000175100017510000000000012301126372021527 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/jsp/applet/Clock2.java0000644000175100017510000001701412271304167023520 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.applet.Applet; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; /** * Time! * * @author Rachel Gollub */ public class Clock2 extends Applet implements Runnable { private static final long serialVersionUID = 1L; Thread timer; // The thread that displays clock int lastxs, lastys, lastxm, lastym, lastxh, lastyh; // Dimensions used to draw hands SimpleDateFormat formatter; // Formats the date displayed String lastdate; // String to hold date displayed Font clockFaceFont; // Font for number display on clock Date currentDate; // Used to get date to display Color handColor; // Color of main hands and dial Color numberColor; // Color of second hand and numbers @Override public void init() { lastxs = lastys = lastxm = lastym = lastxh = lastyh = 0; formatter = new SimpleDateFormat ("EEE MMM dd hh:mm:ss yyyy", Locale.getDefault()); currentDate = new Date(); lastdate = formatter.format(currentDate); clockFaceFont = new Font("Serif", Font.PLAIN, 14); handColor = Color.blue; numberColor = Color.darkGray; try { setBackground(new Color(Integer.parseInt(getParameter("bgcolor"),16))); } catch (Exception E) { } try { handColor = new Color(Integer.parseInt(getParameter("fgcolor1"),16)); } catch (Exception E) { } try { numberColor = new Color(Integer.parseInt(getParameter("fgcolor2"),16)); } catch (Exception E) { } resize(300,300); // Set clock window size } // Plotpoints allows calculation to only cover 45 degrees of the circle, // and then mirror public void plotpoints(int x0, int y0, int x, int y, Graphics g) { g.drawLine(x0+x,y0+y,x0+x,y0+y); g.drawLine(x0+y,y0+x,x0+y,y0+x); g.drawLine(x0+y,y0-x,x0+y,y0-x); g.drawLine(x0+x,y0-y,x0+x,y0-y); g.drawLine(x0-x,y0-y,x0-x,y0-y); g.drawLine(x0-y,y0-x,x0-y,y0-x); g.drawLine(x0-y,y0+x,x0-y,y0+x); g.drawLine(x0-x,y0+y,x0-x,y0+y); } // Circle is just Bresenham's algorithm for a scan converted circle public void circle(int x0, int y0, int r, Graphics g) { int x,y; float d; x=0; y=r; d=5/4-r; plotpoints(x0,y0,x,y,g); while (y>x){ if (d<0) { d=d+2*x+3; x++; } else { d=d+2*(x-y)+5; x++; y--; } plotpoints(x0,y0,x,y,g); } } // Paint is the main part of the program @Override public void paint(Graphics g) { int xh, yh, xm, ym, xs, ys, s = 0, m = 10, h = 10, xcenter, ycenter; String today; currentDate = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("s",Locale.getDefault()); try { s = Integer.parseInt(formatter.format(currentDate)); } catch (NumberFormatException n) { s = 0; } formatter.applyPattern("m"); try { m = Integer.parseInt(formatter.format(currentDate)); } catch (NumberFormatException n) { m = 10; } formatter.applyPattern("h"); try { h = Integer.parseInt(formatter.format(currentDate)); } catch (NumberFormatException n) { h = 10; } formatter.applyPattern("EEE MMM dd HH:mm:ss yyyy"); today = formatter.format(currentDate); xcenter=80; ycenter=55; // a= s* pi/2 - pi/2 (to switch 0,0 from 3:00 to 12:00) // x = r(cos a) + xcenter, y = r(sin a) + ycenter xs = (int)(Math.cos(s * 3.14f/30 - 3.14f/2) * 45 + xcenter); ys = (int)(Math.sin(s * 3.14f/30 - 3.14f/2) * 45 + ycenter); xm = (int)(Math.cos(m * 3.14f/30 - 3.14f/2) * 40 + xcenter); ym = (int)(Math.sin(m * 3.14f/30 - 3.14f/2) * 40 + ycenter); xh = (int)(Math.cos((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + xcenter); yh = (int)(Math.sin((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + ycenter); // Draw the circle and numbers g.setFont(clockFaceFont); g.setColor(handColor); circle(xcenter,ycenter,50,g); g.setColor(numberColor); g.drawString("9",xcenter-45,ycenter+3); g.drawString("3",xcenter+40,ycenter+3); g.drawString("12",xcenter-5,ycenter-37); g.drawString("6",xcenter-3,ycenter+45); // Erase if necessary, and redraw g.setColor(getBackground()); if (xs != lastxs || ys != lastys) { g.drawLine(xcenter, ycenter, lastxs, lastys); g.drawString(lastdate, 5, 125); } if (xm != lastxm || ym != lastym) { g.drawLine(xcenter, ycenter-1, lastxm, lastym); g.drawLine(xcenter-1, ycenter, lastxm, lastym); } if (xh != lastxh || yh != lastyh) { g.drawLine(xcenter, ycenter-1, lastxh, lastyh); g.drawLine(xcenter-1, ycenter, lastxh, lastyh); } g.setColor(numberColor); g.drawString("", 5, 125); g.drawString(today, 5, 125); g.drawLine(xcenter, ycenter, xs, ys); g.setColor(handColor); g.drawLine(xcenter, ycenter-1, xm, ym); g.drawLine(xcenter-1, ycenter, xm, ym); g.drawLine(xcenter, ycenter-1, xh, yh); g.drawLine(xcenter-1, ycenter, xh, yh); lastxs=xs; lastys=ys; lastxm=xm; lastym=ym; lastxh=xh; lastyh=yh; lastdate = today; currentDate=null; } @Override public void start() { timer = new Thread(this); timer.start(); } @Override public void stop() { timer = null; } @Override public void run() { Thread me = Thread.currentThread(); while (timer == me) { try { Thread.sleep(100); } catch (InterruptedException e) { } repaint(); } } @Override public void update(Graphics g) { paint(g); } @Override public String getAppletInfo() { return "Title: A Clock \nAuthor: Rachel Gollub, 1995 \nAn analog clock."; } @Override public String[][] getParameterInfo() { String[][] info = { {"bgcolor", "hexadecimal RGB number", "The background color. Default is the color of your browser."}, {"fgcolor1", "hexadecimal RGB number", "The color of the hands and dial. Default is blue."}, {"fgcolor2", "hexadecimal RGB number", "The color of the seconds hand and numbers. Default is dark gray."} }; return info; } } tomcat7-7.0.52/webapps/examples/WEB-INF/tags/0000755000175100017510000000000012301126373020405 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/tags/xhtmlbasic.tag0000644000175100017510000000170312271304167023246 0ustar locutuslocutus tomcat7-7.0.52/webapps/examples/WEB-INF/tags/displayProducts.tag0000644000175100017510000000400112271304167024273 0ustar locutuslocutus <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ attribute name="normalPrice" fragment="true" %> <%@ attribute name="onSale" fragment="true" %> <%@ variable name-given="name" %> <%@ variable name-given="price" %> <%@ variable name-given="origPrice" %> <%@ variable name-given="salePrice" %>
    tomcat7-7.0.52/webapps/examples/WEB-INF/tags/helloWorld.tag0000644000175100017510000000144112271304167023222 0ustar locutuslocutus Hello, world! tomcat7-7.0.52/webapps/examples/WEB-INF/tags/panel.tag0000644000175100017510000000202512271304167022205 0ustar locutuslocutus <%@ attribute name="color" %> <%@ attribute name="bgcolor" %> <%@ attribute name="title" %>
    ${title}
    tomcat7-7.0.52/webapps/examples/WEB-INF/classes/0000755000175100017510000000000012301126373021104 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/LocalStrings_es.properties0000644000175100017510000000416612271304167026331 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. helloworld.title = Hola Mundo\! requestinfo.title = Ejemplo de Informacion de Requerimiento\: requestinfo.label.method = M\u00E9todo\: requestinfo.label.requesturi = URI de Requerimiento\: requestinfo.label.protocol = Protocolo\: requestinfo.label.pathinfo = Info de Ruta\: requestinfo.label.remoteaddr = Direccion Remota\: requestheader.title = Ejemplo de Cabecera de Requerimiento\: requestparams.title = Ejemplo de par\u00E1metros de Requerimiento\: requestparams.params-in-req = Par\u00E1metros en este Request\: requestparams.no-params = No hay p\u00E1rametro. Por favor, usa alguno requestparams.firstname = Nombre\: requestparams.lastname = Apellidos\: cookies.title = Ejemplo de Cookies cookies.cookies = Tu navegador est\u00E1 enviando los siguientes cookies\: cookies.no-cookies = Tu navegador no est\u00E1 enviando cookies cookies.make-cookie = Crea un cookie para enviarlo a tu navegador cookies.name = Nombre\: cookies.value = Valor\: cookies.set = Acabas de enviar a tu navegador estos cookies\: sessions.title = Ejemplo de Sesiones sessions.id = ID de Sesi\u00F3n\: sessions.created = Creado\: sessions.lastaccessed = Ultimo Acceso\: sessions.data = Lo siguientes datos est\u00E1n en tu sesi\u00F3n\: sessions.adddata = A\u00F1ade datos a tu sesi\u00F3n\: sessions.dataname = Nombre del atributo de sesi\u00F3n\: sessions.datavalue = Valor del atributo de sesi\u00F3n\: tomcat7-7.0.52/webapps/examples/WEB-INF/classes/chat/0000755000175100017510000000000012301126372022022 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/chat/ChatServlet.java0000644000175100017510000002447512271304167025133 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 chat; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometProcessor; /** * Helper class to implement Comet functionality. */ public class ChatServlet extends HttpServlet implements CometProcessor { private static final long serialVersionUID = 1L; private static final String CHARSET = "UTF-8"; protected ArrayList connections = new ArrayList(); protected transient MessageSender messageSender = null; @Override public void init() throws ServletException { messageSender = new MessageSender(); Thread messageSenderThread = new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]"); messageSenderThread.setDaemon(true); messageSenderThread.start(); } @Override public void destroy() { connections.clear(); messageSender.stop(); messageSender = null; } /** * Process the given Comet event. * * @param event The Comet event that will be processed * @throws IOException * @throws ServletException */ @Override public void event(CometEvent event) throws IOException, ServletException { // Note: There should really be two servlets in this example, to avoid // mixing Comet stuff with regular connection processing HttpServletRequest request = event.getHttpServletRequest(); HttpServletResponse response = event.getHttpServletResponse(); if (event.getEventType() == CometEvent.EventType.BEGIN) { String action = request.getParameter("action"); if (action != null) { if ("login".equals(action)) { String nickname = request.getParameter("nickname"); request.getSession(true).setAttribute("nickname", nickname); response.sendRedirect("index.jsp"); event.close(); return; } String nickname = (String) request.getSession(true).getAttribute("nickname"); String message = request.getParameter("message"); messageSender.send(nickname, message); response.sendRedirect("post.jsp"); event.close(); return; } if (request.getSession(true).getAttribute("nickname") == null) { // Redirect to "login" log("Redirect to login for session: " + request.getSession(true).getId()); response.sendRedirect("login.jsp"); event.close(); return; } begin(event, request, response); } else if (event.getEventType() == CometEvent.EventType.ERROR) { error(event, request, response); } else if (event.getEventType() == CometEvent.EventType.END) { end(event, request, response); } else if (event.getEventType() == CometEvent.EventType.READ) { read(event, request, response); } } protected void begin(@SuppressWarnings("unused") CometEvent event, HttpServletRequest request, HttpServletResponse response) throws IOException { log("Begin for session: " + request.getSession(true).getId()); response.setContentType("text/html; charset=" + CHARSET); PrintWriter writer = response.getWriter(); writer.println(""); writer.println("JSP Chat"); writer.println(""); writer.flush(); synchronized(connections) { connections.add(response); } messageSender.send("Tomcat", request.getSession(true).getAttribute("nickname") + " joined the chat."); } protected void end(CometEvent event, HttpServletRequest request, HttpServletResponse response) throws IOException { log("End for session: " + request.getSession(true).getId()); synchronized(connections) { connections.remove(response); } PrintWriter writer = response.getWriter(); writer.println(""); event.close(); } protected void error(CometEvent event, HttpServletRequest request, HttpServletResponse response) throws IOException { log("Error for session: " + request.getSession(true).getId()); synchronized(connections) { connections.remove(response); } event.close(); } protected void read(CometEvent event, HttpServletRequest request, HttpServletResponse response) throws IOException { InputStream is = request.getInputStream(); byte[] buf = new byte[512]; while (is.available() > 0) { log("Available: " + is.available()); int n = is.read(buf); if (n > 0) { log("Read " + n + " bytes: " + new String(buf, 0, n) + " for session: " + request.getSession(true).getId()); } else if (n < 0) { log("End of file: " + n); end(event, request, response); return; } } } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Compatibility method: equivalent method using the regular connection model response.setContentType("text/html; charset=" + CHARSET); PrintWriter writer = response.getWriter(); writer.println(""); writer.println("JSP Chat"); writer.println("Chat example only supports Comet processing. "); writer.println("Configure a connector that supports Comet and try again."); writer.println(""); } /** * Poller class. */ public class MessageSender implements Runnable { protected boolean running = true; protected ArrayList messages = new ArrayList(); public MessageSender() { // Default contructor } public void stop() { running = false; synchronized (messages) { messages.notify(); } } public void send(String user, String message) { synchronized (messages) { messages.add("[" + user + "]: " + message); messages.notify(); } } /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ @Override public void run() { // Loop until we receive a shutdown command while (running) { String[] pendingMessages; synchronized (messages) { try { if (messages.size() == 0) { messages.wait(); } } catch (InterruptedException e) { // Ignore } pendingMessages = messages.toArray(new String[0]); messages.clear(); } synchronized (connections) { for (int i = 0; i < connections.size(); i++) { try { PrintWriter writer = connections.get(i).getWriter(); for (int j = 0; j < pendingMessages.length; j++) { writer.println("
    "+filter(pendingMessages[j]) + "
    "); } writer.flush(); } catch (IOException e) { log("IOException sending message", e); } } } } } } /** * Filter the specified message string for characters that are sensitive * in HTML. * * @param message The message string to be filtered * @author Copied from org.apache.catalina.util.RequestUtil#filter(String) */ protected static String filter(String message) { if (message == null) return (null); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/error/0000755000175100017510000000000012301126373022235 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/error/Smart.java0000644000175100017510000000174512271304167024202 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 error; public class Smart { String name = "JSP"; public String getName() { return name; } public void setName(String name) { this.name = name; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/colors/0000755000175100017510000000000012301126373022405 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/colors/ColorGameBean.java0000644000175100017510000000554612271304167025725 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 colors; public class ColorGameBean { private String background = "yellow"; private String foreground = "red"; private String color1 = foreground; private String color2 = background; private String hint = "no"; private int attempts = 0; private int intval = 0; private boolean tookHints = false; public void processRequest() { // background = "yellow"; // foreground = "red"; if (! color1.equals(foreground)) { if (color1.equalsIgnoreCase("black") || color1.equalsIgnoreCase("cyan")) { background = color1; } } if (! color2.equals(background)) { if (color2.equalsIgnoreCase("black") || color2.equalsIgnoreCase("cyan")) { foreground = color2; } } attempts++; } public void setColor2(String x) { color2 = x; } public void setColor1(String x) { color1 = x; } public void setAction(String x) { if (!tookHints) tookHints = x.equalsIgnoreCase("Hint"); hint = x; } public String getColor2() { return background; } public String getColor1() { return foreground; } public int getAttempts() { return attempts; } public boolean getHint() { return hint.equalsIgnoreCase("Hint"); } public boolean getSuccess() { if (background.equalsIgnoreCase("black") || background.equalsIgnoreCase("cyan")) { if (foreground.equalsIgnoreCase("black") || foreground.equalsIgnoreCase("cyan")) { return true; } return false; } return false; } public boolean getHintTaken() { return tookHints; } public void reset() { foreground = "red"; background = "yellow"; } public void setIntval(int value) { intval = value; } public int getIntval() { return intval; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/RequestHeaderExample.java0000644000175100017510000000631312271304167026034 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import util.HTMLFilter; /** * Example servlet showing request headers * * @author James Duncan Davidson */ public class RequestHeaderExample extends HttpServlet { private static final long serialVersionUID = 1L; private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings"); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(""); String title = RB.getString("requestheader.title"); out.println("" + title + ""); out.println(""); out.println(""); // all links relative // XXX // making these absolute till we work out the // addition of a PathInfo issue out.println(""); out.println("\"view"); out.println(""); out.println("\"return\""); out.println("

    " + title + "

    "); out.println(""); Enumeration e = request.getHeaderNames(); while (e.hasMoreElements()) { String headerName = e.nextElement(); String headerValue = request.getHeader(headerName); out.println(""); } out.println("
    "); out.println(HTMLFilter.filter(headerName)); out.println(""); out.println(HTMLFilter.filter(headerValue)); out.println("
    "); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/LocalStrings_en.properties0000644000175100017510000000375312271304167026325 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # Default localized resources for example servlets # This locale is en_US helloworld.title=Hello World! requestinfo.title=Request Information Example requestinfo.label.method=Method: requestinfo.label.requesturi=Request URI: requestinfo.label.protocol=Protocol: requestinfo.label.pathinfo=Path Info: requestinfo.label.remoteaddr=Remote Address: requestheader.title=Request Header Example requestparams.title=Request Parameters Example requestparams.params-in-req=Parameters in this request: requestparams.no-params=No Parameters, Please enter some requestparams.firstname=First Name: requestparams.lastname=Last Name: cookies.title=Cookies Example cookies.cookies=Your browser is sending the following cookies: cookies.no-cookies=Your browser isn't sending any cookies cookies.make-cookie=Create a cookie to send to your browser cookies.name=Name: cookies.value=Value: cookies.set=You just sent the following cookie to your browser: sessions.title=Sessions Example sessions.id=Session ID: sessions.created=Created: sessions.lastaccessed=Last Accessed: sessions.data=The following data is in your session: sessions.adddata=Add data to your session sessions.dataname=Name of Session Attribute: sessions.datavalue=Value of Session Attribute: tomcat7-7.0.52/webapps/examples/WEB-INF/classes/filters/0000755000175100017510000000000012301126372022553 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/filters/ExampleFilter.java0000644000175100017510000001016512271304167026170 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 filters; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * Example filter that can be attached to either an individual servlet * or to a URL pattern. This filter performs the following functions: *
      *
    • Attaches itself as a request attribute, under the attribute name * defined by the value of the attribute initialization * parameter.
    • *
    • Calculates the number of milliseconds required to perform the * servlet processing required by this request, including any * subsequently defined filters, and logs the result to the servlet * context log for this application. *
    * * @author Craig McClanahan */ public final class ExampleFilter implements Filter { // ----------------------------------------------------- Instance Variables /** * The request attribute name under which we store a reference to ourself. */ private String attribute = null; /** * The filter configuration object we are associated with. If this value * is null, this filter instance is not currently configured. */ private FilterConfig filterConfig = null; // --------------------------------------------------------- Public Methods /** * Take this filter out of service. */ @Override public void destroy() { this.attribute = null; this.filterConfig = null; } /** * Time the processing that is performed by all subsequent filters in the * current filter stack, including the ultimately invoked servlet. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param chain The filter chain we are processing * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Store ourselves as a request attribute (if requested) if (attribute != null) request.setAttribute(attribute, this); // Time and log the subsequent processing long startTime = System.currentTimeMillis(); chain.doFilter(request, response); long stopTime = System.currentTimeMillis(); filterConfig.getServletContext().log (this.toString() + ": " + (stopTime - startTime) + " milliseconds"); } /** * Place this filter into service. * * @param fConfig The filter configuration object */ @Override public void init(FilterConfig fConfig) throws ServletException { this.filterConfig = fConfig; this.attribute = fConfig.getInitParameter("attribute"); } /** * Return a String representation of this object. */ @Override public String toString() { if (filterConfig == null) return ("TimingFilter()"); StringBuilder sb = new StringBuilder("TimingFilter("); sb.append(filterConfig); sb.append(")"); return (sb.toString()); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/checkbox/0000755000175100017510000000000012301126373022672 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/checkbox/CheckTest.java0000644000175100017510000000176612271304167025431 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 checkbox; public class CheckTest { String b[] = new String[] { "1", "2", "3", "4" }; public String[] getFruit() { return b; } public void setFruit(String [] b) { this.b = b; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/dates/0000755000175100017510000000000012301126373022204 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/dates/JspCalendar.java0000644000175100017510000001014512271304167025243 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 dates; import java.util.Calendar; import java.util.Date; public class JspCalendar { Calendar calendar = null; public JspCalendar() { calendar = Calendar.getInstance(); Date trialTime = new Date(); calendar.setTime(trialTime); } public int getYear() { return calendar.get(Calendar.YEAR); } public String getMonth() { int m = getMonthInt(); String[] months = new String [] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; if (m > 12) return "Unknown to Man"; return months[m - 1]; } public String getDay() { int x = getDayOfWeek(); String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; if (x > 7) return "Unknown to Man"; return days[x - 1]; } public int getMonthInt() { return 1 + calendar.get(Calendar.MONTH); } public String getDate() { return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear(); } public String getTime() { return getHour() + ":" + getMinute() + ":" + getSecond(); } public int getDayOfMonth() { return calendar.get(Calendar.DAY_OF_MONTH); } public int getDayOfYear() { return calendar.get(Calendar.DAY_OF_YEAR); } public int getWeekOfYear() { return calendar.get(Calendar.WEEK_OF_YEAR); } public int getWeekOfMonth() { return calendar.get(Calendar.WEEK_OF_MONTH); } public int getDayOfWeek() { return calendar.get(Calendar.DAY_OF_WEEK); } public int getHour() { return calendar.get(Calendar.HOUR_OF_DAY); } public int getMinute() { return calendar.get(Calendar.MINUTE); } public int getSecond() { return calendar.get(Calendar.SECOND); } public static void main(String args[]) { JspCalendar db = new JspCalendar(); p("date: " + db.getDayOfMonth()); p("year: " + db.getYear()); p("month: " + db.getMonth()); p("time: " + db.getTime()); p("date: " + db.getDate()); p("Day: " + db.getDay()); p("DayOfYear: " + db.getDayOfYear()); p("WeekOfYear: " + db.getWeekOfYear()); p("era: " + db.getEra()); p("ampm: " + db.getAMPM()); p("DST: " + db.getDSTOffset()); p("ZONE Offset: " + db.getZoneOffset()); p("TIMEZONE: " + db.getUSTimeZone()); } private static void p(String x) { System.out.println(x); } public int getEra() { return calendar.get(Calendar.ERA); } public String getUSTimeZone() { String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific", "Mountain", "Central", "Eastern"}; return zones[10 + getZoneOffset()]; } public int getZoneOffset() { return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000); } public int getDSTOffset() { return calendar.get(Calendar.DST_OFFSET)/(60*60*1000); } public int getAMPM() { return calendar.get(Calendar.AM_PM); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/ServletToJsp.java0000644000175100017510000000273312271304167024365 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletToJsp extends HttpServlet { private static final long serialVersionUID = 1L; @Override public void doGet (HttpServletRequest request, HttpServletResponse response) { try { // Set the attribute and Forward to hello.jsp request.setAttribute ("servletName", "servletToJsp"); getServletConfig().getServletContext().getRequestDispatcher( "/jsp/jsptoserv/hello.jsp").forward(request, response); } catch (Exception ex) { ex.printStackTrace (); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/async/0000755000175100017510000000000012301126372022220 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/async/Async1.java0000644000175100017510000000427711656646244024254 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 async; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; public class Async1 extends HttpServlet { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(Async1.class); @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { final AsyncContext actx = req.startAsync(); actx.setTimeout(30*1000); Runnable run = new Runnable() { @Override public void run() { try { String path = "/jsp/async/async1.jsp"; Thread.currentThread().setName("Async1-Thread"); log.info("Putting AsyncThread to sleep"); Thread.sleep(2*1000); log.info("Dispatching to "+path); actx.dispatch(path); }catch (InterruptedException x) { log.error("Async1",x); }catch (IllegalStateException x) { log.error("Async1",x); } } }; Thread t = new Thread(run); t.start(); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/async/Async0.java0000644000175100017510000000523311642411740024226 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 async; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; public class Async0 extends HttpServlet { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(Async0.class); @Override protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { if (Boolean.TRUE == req.getAttribute("dispatch")) { log.info("Received dispatch, completing on the worker thread."); log.info("After complete called started:"+req.isAsyncStarted()); resp.getWriter().write("Async dispatch worked:+"+System.currentTimeMillis()+"\n"); } else { resp.setContentType("text/plain"); final AsyncContext actx = req.startAsync(); actx.setTimeout(Long.MAX_VALUE); Runnable run = new Runnable() { @Override public void run() { try { req.setAttribute("dispatch", Boolean.TRUE); Thread.currentThread().setName("Async0-Thread"); log.info("Putting AsyncThread to sleep"); Thread.sleep(2*1000); log.info("Dispatching"); actx.dispatch(); }catch (InterruptedException x) { log.error("Async1",x); }catch (IllegalStateException x) { log.error("Async1",x); } } }; Thread t = new Thread(run); t.start(); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/async/Async2.java0000644000175100017510000000451711656646244024252 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 async; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; public class Async2 extends HttpServlet { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(Async2.class); @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { final AsyncContext actx = req.startAsync(); actx.setTimeout(30*1000); Runnable run = new Runnable() { @Override public void run() { try { Thread.currentThread().setName("Async2-Thread"); log.info("Putting AsyncThread to sleep"); Thread.sleep(2*1000); log.info("Writing data."); actx.getResponse().getWriter().write("Output from background thread. Time:"+System.currentTimeMillis()+"\n"); actx.complete(); }catch (InterruptedException x) { log.error("Async2",x); }catch (IllegalStateException x) { log.error("Async2",x); }catch (IOException x) { log.error("Async2",x); } } }; Thread t = new Thread(run); t.start(); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java0000644000175100017510000001052711656646244026537 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 async; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import async.Stockticker.Stock; import async.Stockticker.TickListener; public class AsyncStockServlet extends HttpServlet implements TickListener, AsyncListener{ private static final long serialVersionUID = 1L; public static final String POLL = "POLL"; public static final String LONG_POLL = "LONG-POLL"; public static final String STREAM = "STREAM"; static ArrayList ticks = new ArrayList(); static ConcurrentLinkedQueue clients = new ConcurrentLinkedQueue(); static AtomicInteger clientcount = new AtomicInteger(0); static Stockticker ticker = new Stockticker(); public AsyncStockServlet() { System.out.println("AsyncStockServlet created"); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (req.isAsyncStarted()) { req.getAsyncContext().complete(); } else if (req.isAsyncSupported()) { AsyncContext actx = req.startAsync(); actx.addListener(this); resp.setContentType("text/plain"); clients.add(actx); if (clientcount.incrementAndGet()==1) { ticker.addTickListener(this); } } else { new Exception("Async Not Supported").printStackTrace(); resp.sendError(400,"Async is not supported."); } } @Override public void tick(Stock stock) { ticks.add((Stock)stock.clone()); Iterator it = clients.iterator(); while (it.hasNext()) { AsyncContext actx = it.next(); writeStock(actx, stock); } } public void writeStock(AsyncContext actx, Stock stock) { HttpServletResponse response = (HttpServletResponse)actx.getResponse(); try { PrintWriter writer = response.getWriter(); writer.write("STOCK#");//make client parsing easier writer.write(stock.getSymbol()); writer.write("#"); writer.write(stock.getValueAsString()); writer.write("#"); writer.write(stock.getLastChangeAsString()); writer.write("#"); writer.write(String.valueOf(stock.getCnt())); writer.write("\n"); writer.flush(); response.flushBuffer(); }catch (IOException x) { try {actx.complete();}catch (Exception ignore){/* Ignore */} } } @Override public void onComplete(AsyncEvent event) throws IOException { if (clients.remove(event.getAsyncContext()) && clientcount.decrementAndGet()==0) { ticker.removeTickListener(this); } } @Override public void onError(AsyncEvent event) throws IOException { event.getAsyncContext().complete(); } @Override public void onTimeout(AsyncEvent event) throws IOException { event.getAsyncContext().complete(); } @Override public void onStartAsync(AsyncEvent event) throws IOException { // NOOP } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/async/Stockticker.java0000644000175100017510000001321611656646244025374 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 async; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; public class Stockticker implements Runnable { public volatile boolean run = true; protected AtomicInteger counter = new AtomicInteger(0); ArrayList listeners = new ArrayList(); protected volatile Thread ticker = null; protected volatile int ticknr = 0; public synchronized void start() { run = true; ticker = new Thread(this); ticker.setName("Ticker Thread"); ticker.start(); } public synchronized void stop() { run = false; try { ticker.join(); }catch (InterruptedException x) { Thread.interrupted(); } ticker = null; } public void addTickListener(TickListener listener) { if (listeners.add(listener)) { if (counter.incrementAndGet()==1) start(); } } public void removeTickListener(TickListener listener) { if (listeners.remove(listener)) { if (counter.decrementAndGet()==0) stop(); } } @Override public void run() { try { Stock[] stocks = new Stock[] { new Stock("GOOG", 435.43), new Stock("YHOO", 27.88), new Stock("ASF", 1015.55), }; Random r = new Random(System.currentTimeMillis()); while (run) { for (int j = 0; j < 1; j++) { int i = r.nextInt() % 3; if (i < 0) i = i * (-1); Stock stock = stocks[i]; double change = r.nextDouble(); boolean plus = r.nextBoolean(); if (plus) { stock.setValue(stock.getValue() + change); } else { stock.setValue(stock.getValue() - change); } stock.setCnt(++ticknr); for (TickListener l : listeners) { l.tick(stock); } } Thread.sleep(850); } } catch (InterruptedException ix) { // Ignore } catch (Exception x) { x.printStackTrace(); } } public static interface TickListener { public void tick(Stock stock); } public static final class Stock implements Cloneable { protected static DecimalFormat df = new DecimalFormat("0.00"); protected String symbol = ""; protected double value = 0.0d; protected double lastchange = 0.0d; protected int cnt = 0; public Stock(String symbol, double initvalue) { this.symbol = symbol; this.value = initvalue; } public void setCnt(int c) { this.cnt = c; } public int getCnt() { return cnt; } public String getSymbol() { return symbol; } public double getValue() { return value; } public void setValue(double value) { double old = this.value; this.value = value; this.lastchange = value - old; } public String getValueAsString() { return df.format(value); } public double getLastChange() { return this.lastchange; } public void setLastChange(double lastchange) { this.lastchange = lastchange; } public String getLastChangeAsString() { return df.format(lastchange); } @Override public int hashCode() { return symbol.hashCode(); } @Override public boolean equals(Object other) { if (other instanceof Stock) { return this.symbol.equals(((Stock) other).symbol); } return false; } @Override public String toString() { StringBuilder buf = new StringBuilder("STOCK#"); buf.append(getSymbol()); buf.append("#"); buf.append(getValueAsString()); buf.append("#"); buf.append(getLastChangeAsString()); buf.append("#"); buf.append(String.valueOf(getCnt())); return buf.toString(); } @Override public Object clone() { Stock s = new Stock(this.getSymbol(), this.getValue()); s.setLastChange(this.getLastChange()); s.setCnt(this.cnt); return s; } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/async/Async3.java0000644000175100017510000000260211656646244024244 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 async; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Async3 extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { final AsyncContext actx = req.startAsync(); actx.setTimeout(30*1000); actx.dispatch("/jsp/async/async3.jsp"); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/0000755000175100017510000000000012301126373023072 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/chat/0000755000175100017510000000000012301126373024011 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java0000644000175100017510000000657112243423557027610 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.chat; import java.io.IOException; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import util.HTMLFilter; @ServerEndpoint(value = "/websocket/chat") public class ChatAnnotation { private static final Log log = LogFactory.getLog(ChatAnnotation.class); private static final String GUEST_PREFIX = "Guest"; private static final AtomicInteger connectionIds = new AtomicInteger(0); private static final Set connections = new CopyOnWriteArraySet(); private final String nickname; private Session session; public ChatAnnotation() { nickname = GUEST_PREFIX + connectionIds.getAndIncrement(); } @OnOpen public void start(Session session) { this.session = session; connections.add(this); String message = String.format("* %s %s", nickname, "has joined."); broadcast(message); } @OnClose public void end() { connections.remove(this); String message = String.format("* %s %s", nickname, "has disconnected."); broadcast(message); } @OnMessage public void incoming(String message) { // Never trust the client String filteredMessage = String.format("%s: %s", nickname, HTMLFilter.filter(message.toString())); broadcast(filteredMessage); } @OnError public void onError(Throwable t) throws Throwable { log.error("Chat Error: " + t.toString(), t); } private static void broadcast(String msg) { for (ChatAnnotation client : connections) { try { synchronized (client) { client.session.getBasicRemote().sendText(msg); } } catch (IOException e) { log.debug("Chat Error: Failed to send message to client", e); connections.remove(client); try { client.session.close(); } catch (IOException e1) { // Ignore } String message = String.format("* %s %s", client.nickname, "has been disconnected."); broadcast(message); } } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/echo/0000755000175100017510000000000012301126373024010 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java0000644000175100017510000000412012113261052027554 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.echo; import java.io.IOException; import java.nio.ByteBuffer; import javax.websocket.OnMessage; import javax.websocket.PongMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket/echoAnnotation") public class EchoAnnotation { @OnMessage public void echoTextMessage(Session session, String msg, boolean last) { try { if (session.isOpen()) { session.getBasicRemote().sendText(msg, last); } } catch (IOException e) { try { session.close(); } catch (IOException e1) { // Ignore } } } @OnMessage public void echoBinaryMessage(Session session, ByteBuffer bb, boolean last) { try { if (session.isOpen()) { session.getBasicRemote().sendBinary(bb, last); } } catch (IOException e) { try { session.close(); } catch (IOException e1) { // Ignore } } } /** * Process a received pong. This is a NO-OP. * * @param pm Ignored. */ @OnMessage public void echoPongMessage(PongMessage pm) { // NO-OP } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java0000644000175100017510000000376012227220727027245 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.echo; import java.io.IOException; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.RemoteEndpoint; import javax.websocket.Session; public class EchoEndpoint extends Endpoint { @Override public void onOpen(Session session, EndpointConfig endpointConfig) { RemoteEndpoint.Basic remoteEndpointBasic = session.getBasicRemote(); session.addMessageHandler(new EchoMessageHandler(remoteEndpointBasic)); } private static class EchoMessageHandler implements MessageHandler.Whole { private final RemoteEndpoint.Basic remoteEndpointBasic; private EchoMessageHandler(RemoteEndpoint.Basic remoteEndpointBasic) { this.remoteEndpointBasic = remoteEndpointBasic; } @Override public void onMessage(String message) { try { if (remoteEndpointBasic != null) { remoteEndpointBasic.sendText(message); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/0000755000175100017510000000000012301126373025037 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/0000755000175100017510000000000012301126372027217 5ustar locutuslocutus././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootroottomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage.javatomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage0000644000175100017510000000174112225776450033403 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard.wsmessages; /** * Represents a "close" message that closes the session. */ public class CloseWebsocketMessage extends AbstractWebsocketMessage { } ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootroottomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.javatomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMess0000644000175100017510000000175512225776450033431 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard.wsmessages; /** * Abstract base class for Websocket Messages (binary or string) * that can be buffered. */ public abstract class AbstractWebsocketMessage { } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootroottomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.javatomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessag0000644000175100017510000000222312225776450033433 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard.wsmessages; /** * Represents a string websocket message. * */ public final class StringWebsocketMessage extends AbstractWebsocketMessage { private final String string; public StringWebsocketMessage(String string) { this.string = string; } public String getString() { return string; } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootroottomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.javatomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessag0000644000175100017510000000226212225776450033414 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard.wsmessages; import java.nio.ByteBuffer; /** * Represents a binary websocket message. */ public final class BinaryWebsocketMessage extends AbstractWebsocketMessage { private final ByteBuffer bytes; public BinaryWebsocketMessage(ByteBuffer bytes) { this.bytes = bytes; } public ByteBuffer getBytes() { return bytes; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java0000644000175100017510000002217012231605412027120 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard; import java.io.IOException; import java.util.LinkedList; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.RemoteEndpoint.Async; import javax.websocket.SendHandler; import javax.websocket.SendResult; import javax.websocket.Session; import websocket.drawboard.wsmessages.AbstractWebsocketMessage; import websocket.drawboard.wsmessages.BinaryWebsocketMessage; import websocket.drawboard.wsmessages.CloseWebsocketMessage; import websocket.drawboard.wsmessages.StringWebsocketMessage; /** * Represents a client with methods to send messages asynchronously. */ public class Client { private final Session session; private final Async async; /** * Contains the messages wich are buffered until the previous * send operation has finished. */ private final LinkedList messagesToSend = new LinkedList(); /** * If this client is currently sending a messages asynchronously. */ private volatile boolean isSendingMessage = false; /** * If this client is closing. If true, new messages to * send will be ignored. */ private volatile boolean isClosing = false; /** * The length of all current buffered messages, to avoid iterating * over a linked list. */ private volatile long messagesToSendLength = 0; public Client(Session session) { this.session = session; this.async = session.getAsyncRemote(); } /** * Asynchronously closes the Websocket session. This will wait until all * remaining messages have been sent to the Client and then close * the Websocket session. */ public void close() { sendMessage(new CloseWebsocketMessage()); } /** * Sends the given message asynchronously to the client. * If there is already a async sending in progress, then the message * will be buffered and sent when possible.

    * * This method can be called from multiple threads. * @param msg */ public void sendMessage(AbstractWebsocketMessage msg) { synchronized (messagesToSend) { if (!isClosing) { // Check if we have a Close message if (msg instanceof CloseWebsocketMessage) { isClosing = true; } if (isSendingMessage) { // Check if the buffered messages exceed // a specific amount - in that case, disconnect the client // to prevent DoS. // In this case we check if there are >= 1000 messages // or length(of all messages) >= 1000000 bytes. if (messagesToSend.size() >= 1000 || messagesToSendLength >= 1000000) { isClosing = true; // Discard the new message and close the session immediately. CloseReason cr = new CloseReason( CloseCodes.VIOLATED_POLICY, "Send Buffer exceeded"); try { // TODO: close() may block if the remote endpoint doesn't read the data // (eventually there will be a TimeoutException). However, this method // (sendMessage) is intended to run asynchronous code and shouldn't // block. Otherwise it would temporarily stop processing of messages // from other clients. // Maybe call this method on another thread. // Note that when this method is called, the RemoteEndpoint.Async // is still in the process of sending data, so there probably should // be another way to abort the Websocket connection. // Ideally, there should be some abort() method that cancels the // connection immediately... session.close(cr); } catch (IOException e) { // Ignore } } else { // Check if the last message and the new message are // String messages - in that case we concatenate them // to reduce TCP overhead (using ";" as separator). if (msg instanceof StringWebsocketMessage && !messagesToSend.isEmpty() && messagesToSend.getLast() instanceof StringWebsocketMessage) { StringWebsocketMessage ms = (StringWebsocketMessage) messagesToSend.removeLast(); messagesToSendLength -= calculateMessageLength(ms); String concatenated = ms.getString() + ";" + ((StringWebsocketMessage) msg).getString(); msg = new StringWebsocketMessage(concatenated); } messagesToSend.add(msg); messagesToSendLength += calculateMessageLength(msg); } } else { isSendingMessage = true; internalSendMessageAsync(msg); } } } } private long calculateMessageLength(AbstractWebsocketMessage msg) { if (msg instanceof BinaryWebsocketMessage) { return ((BinaryWebsocketMessage) msg).getBytes().capacity(); } else if (msg instanceof StringWebsocketMessage) { return ((StringWebsocketMessage) msg).getString().length() * 2; } return 0; } /** * Internally sends the messages asynchronously. * @param msg */ private void internalSendMessageAsync(AbstractWebsocketMessage msg) { try { if (msg instanceof StringWebsocketMessage) { StringWebsocketMessage sMsg = (StringWebsocketMessage) msg; async.sendText(sMsg.getString(), sendHandler); } else if (msg instanceof BinaryWebsocketMessage) { BinaryWebsocketMessage bMsg = (BinaryWebsocketMessage) msg; async.sendBinary(bMsg.getBytes(), sendHandler); } else if (msg instanceof CloseWebsocketMessage) { // Close the session. session.close(); } } catch (IllegalStateException ex) { // Trying to write to the client when the session has // already been closed. // Ignore } catch (IOException ex) { // Trying to write to the client when the session has // already been closed. // Ignore } } /** * SendHandler that will continue to send buffered messages. */ private final SendHandler sendHandler = new SendHandler() { @Override public void onResult(SendResult result) { if (!result.isOK()) { // Message could not be sent. In this case, we don't // set isSendingMessage to false because we must assume the connection // broke (and onClose will be called), so we don't try to send // other messages. // As a precaution, we close the session (e.g. if a send timeout occured). // TODO: session.close() blocks, while this handler shouldn't block. // Ideally, there should be some abort() method that cancels the // connection immediately... try { session.close(); } catch (IOException ex) { // Ignore } } synchronized (messagesToSend) { if (!messagesToSend.isEmpty()) { AbstractWebsocketMessage msg = messagesToSend.remove(); messagesToSendLength -= calculateMessageLength(msg); internalSendMessageAsync(msg); } else { isSendingMessage = false; } } } }; } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java0000644000175100017510000001701212226006406030105 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Arc2D; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; /** * A message that represents a drawing action. * Note that we use primitive types instead of Point, Color etc. * to reduce object allocation.

    * * TODO: But a Color objects needs to be created anyway for drawing this * onto a Graphics2D object, so this probably does not save much. */ public final class DrawMessage { private int type; private byte colorR, colorG, colorB, colorA; private double thickness; private double x1, y1, x2, y2; private boolean lastInChain; /** * The type.
    * 1: Brush
    * 2: Line
    * 3: Rectangle
    * 4: Ellipse */ public int getType() { return type; } public void setType(int type) { this.type = type; } public double getThickness() { return thickness; } public void setThickness(double thickness) { this.thickness = thickness; } public byte getColorR() { return colorR; } public void setColorR(byte colorR) { this.colorR = colorR; } public byte getColorG() { return colorG; } public void setColorG(byte colorG) { this.colorG = colorG; } public byte getColorB() { return colorB; } public void setColorB(byte colorB) { this.colorB = colorB; } public byte getColorA() { return colorA; } public void setColorA(byte colorA) { this.colorA = colorA; } public double getX1() { return x1; } public void setX1(double x1) { this.x1 = x1; } public double getX2() { return x2; } public void setX2(double x2) { this.x2 = x2; } public double getY1() { return y1; } public void setY1(double y1) { this.y1 = y1; } public double getY2() { return y2; } public void setY2(double y2) { this.y2 = y2; } /** * Specifies if this DrawMessage is the last one in a chain * (e.g. a chain of brush paths).
    * Currently it is unused. */ public boolean isLastInChain() { return lastInChain; } public void setLastInChain(boolean lastInChain) { this.lastInChain = lastInChain; } public DrawMessage(int type, byte colorR, byte colorG, byte colorB, byte colorA, double thickness, double x1, double x2, double y1, double y2, boolean lastInChain) { this.type = type; this.colorR = colorR; this.colorG = colorG; this.colorB = colorB; this.colorA = colorA; this.thickness = thickness; this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; this.lastInChain = lastInChain; } /** * Draws this DrawMessage onto the given Graphics2D. * @param g */ public void draw(Graphics2D g) { g.setStroke(new BasicStroke((float) thickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER)); g.setColor(new Color(colorR & 0xFF, colorG & 0xFF, colorB & 0xFF, colorA & 0xFF)); if (x1 == x2 && y1 == y2) { // Always draw as arc to meet the behavior in the HTML5 Canvas. Arc2D arc = new Arc2D.Double(x1, y1, 0, 0, 0d, 360d, Arc2D.OPEN); g.draw(arc); } else if (type == 1 || type == 2) { // Draw a line. Line2D line = new Line2D.Double(x1, y1, x2, y2); g.draw(line); } else if (type == 3 || type == 4) { double x1 = this.x1, x2 = this.x2, y1 = this.y1, y2 = this.y2; if (x1 > x2) { x1 = this.x2; x2 = this.x1; } if (y1 > y2) { y1 = this.y2; y2 = this.y1; } // TODO: If (x1 == x2 || y1 == y2) draw as line. if (type == 3) { // Draw a rectangle. Rectangle2D rect = new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1); g.draw(rect); } else if (type == 4) { // Draw an ellipse. Arc2D arc = new Arc2D.Double(x1, y1, x2 - x1, y2 - y1, 0d, 360d, Arc2D.OPEN); g.draw(arc); } } } /** * Converts this message into a String representation that * can be sent over WebSocket.
    * Since a DrawMessage consists only of numbers, * we concatenate those numbers with a ",". */ @Override public String toString() { return type + "," + (colorR & 0xFF) + "," + (colorG & 0xFF) + "," + (colorB & 0xFF) + "," + (colorA & 0xFF) + "," + thickness + "," + x1 + "," + y1 + "," + x2 + "," + y2 + "," + (lastInChain ? "1" : "0"); } public static DrawMessage parseFromString(String str) throws ParseException { int type; byte[] colors = new byte[4]; double thickness; double[] coords = new double[4]; boolean last; try { String[] elements = str.split(","); type = Integer.parseInt(elements[0]); if (!(type >= 1 && type <= 4)) throw new ParseException("Invalid type: " + type); for (int i = 0; i < colors.length; i++) { colors[i] = (byte) Integer.parseInt(elements[1 + i]); } thickness = Double.parseDouble(elements[5]); if (Double.isNaN(thickness) || thickness < 0 || thickness > 100) throw new ParseException("Invalid thickness: " + thickness); for (int i = 0; i < coords.length; i++) { coords[i] = Double.parseDouble(elements[6 + i]); if (Double.isNaN(coords[i])) throw new ParseException("Invalid coordinate: " + coords[i]); } last = !"0".equals(elements[10]); } catch (RuntimeException ex) { throw new ParseException(ex); } DrawMessage m = new DrawMessage(type, colors[0], colors[1], colors[2], colors[3], thickness, coords[0], coords[2], coords[1], coords[3], last); return m; } public static class ParseException extends Exception { private static final long serialVersionUID = -6651972769789842960L; public ParseException(Throwable root) { super(root); } public ParseException(String message) { super(message); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java0000644000175100017510000002123012231605412031304 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard; import java.io.EOFException; import javax.websocket.CloseReason; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.Session; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import websocket.drawboard.DrawMessage.ParseException; import websocket.drawboard.wsmessages.StringWebsocketMessage; public final class DrawboardEndpoint extends Endpoint { private static final Log log = LogFactory.getLog(DrawboardEndpoint.class); /** * Our room where players can join. */ private static volatile Room room = null; private static final Object roomLock = new Object(); public static Room getRoom(boolean create) { if (create) { if (room == null) { synchronized (roomLock) { if (room == null) { room = new Room(); } } } return room; } else { return room; } } /** * The player that is associated with this Endpoint and the current room. * Note that this variable is only accessed from the Room Thread.

    * * TODO: Currently, Tomcat uses an Endpoint instance once - however * the java doc of endpoint says: * "Each instance of a websocket endpoint is guaranteed not to be called by * more than one thread at a time per active connection." * This could mean that after calling onClose(), the instance * could be reused for another connection so onOpen() will get called * (possibly from another thread).
    * If this is the case, we would need a variable holder for the variables * that are accessed by the Room thread, and read the reference to the holder * at the beginning of onOpen, onMessage, onClose methods to ensure the room * thread always gets the correct instance of the variable holder. */ private Room.Player player; @Override public void onOpen(Session session, EndpointConfig config) { // Set maximum messages size to 10.000 bytes. session.setMaxTextMessageBufferSize(10000); session.addMessageHandler(stringHandler); final Client client = new Client(session); final Room room = getRoom(true); room.invokeAndWait(new Runnable() { @Override public void run() { try { // Create a new Player and add it to the room. try { player = room.createAndAddPlayer(client); } catch (IllegalStateException ex) { // Probably the max. number of players has been // reached. client.sendMessage(new StringWebsocketMessage( "0" + ex.getLocalizedMessage())); // Close the connection. client.close(); } } catch (RuntimeException ex) { log.error("Unexpected exception: " + ex.toString(), ex); } } }); } @Override public void onClose(Session session, CloseReason closeReason) { Room room = getRoom(false); if (room != null) { room.invokeAndWait(new Runnable() { @Override public void run() { try { // Player can be null if it couldn't enter the room if (player != null) { // Remove this player from the room. player.removeFromRoom(); // Set player to null to prevent NPEs when onMessage events // are processed (from other threads) after onClose has been // called from different thread which closed the Websocket session. player = null; } } catch (RuntimeException ex) { log.error("Unexpected exception: " + ex.toString(), ex); } } }); } } @Override public void onError(Session session, Throwable t) { // Most likely cause is a user closing their browser. Check to see if // the root cause is EOF and if it is ignore it. // Protect against infinite loops. int count = 0; Throwable root = t; while (root.getCause() != null && count < 20) { root = root.getCause(); count ++; } if (root instanceof EOFException) { // Assume this is triggered by the user closing their browser and // ignore it. } else { log.error("onError: " + t.toString(), t); } } private final MessageHandler.Whole stringHandler = new MessageHandler.Whole() { @Override public void onMessage(final String message) { // Invoke handling of the message in the room. room.invokeAndWait(new Runnable() { @Override public void run() { try { // Currently, the only types of messages the client will send // are draw messages prefixed by a Message ID // (starting with char '1'), and pong messages (starting // with char '0'). // Draw messages should look like this: // ID|type,colR,colB,colG,colA,thickness,x1,y1,x2,y2,lastInChain boolean dontSwallowException = false; try { char messageType = message.charAt(0); String messageContent = message.substring(1); switch (messageType) { case '0': // Pong message. // Do nothing. break; case '1': // Draw message int indexOfChar = messageContent.indexOf('|'); long msgId = Long.parseLong( messageContent.substring(0, indexOfChar)); DrawMessage msg = DrawMessage.parseFromString( messageContent.substring(indexOfChar + 1)); // Don't ingore RuntimeExceptions thrown by // this method // TODO: Find a better solution than this variable dontSwallowException = true; if (player != null) { player.handleDrawMessage(msg, msgId); } dontSwallowException = false; break; } } catch (RuntimeException ex) { // Client sent invalid data. // Ignore, TODO: maybe close connection if (dontSwallowException) { throw ex; } } catch (ParseException ex) { // Client sent invalid data. // Ignore, TODO: maybe close connection } } catch (RuntimeException ex) { log.error("Unexpected exception: " + ex.toString(), ex); } } }); } }; } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardContextListener.java0000644000175100017510000000250212227744771032700 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public final class DrawboardContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { // NO-OP } @Override public void contextDestroyed(ServletContextEvent sce) { // Shutdown our room. Room room = DrawboardEndpoint.getRoom(false); if (room != null) { room.shutdown(); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java0000644000175100017510000003664412242404061026630 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.drawboard; import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.locks.ReentrantLock; import javax.imageio.ImageIO; import websocket.drawboard.wsmessages.BinaryWebsocketMessage; import websocket.drawboard.wsmessages.StringWebsocketMessage; /** * A Room represents a drawboard where a number of * users participate.

    * * Note: Instance methods should only be invoked by calling * {@link #invokeAndWait(Runnable)} to ensure access is correctly synchronized. */ public final class Room { /** * Specifies the type of a room message that is sent to a client.
    * Note: Currently we are sending simple string messages - for production * apps, a JSON lib should be used for object-level messages.

    * * The number (single char) will be prefixed to the string when sending * the message. */ public static enum MessageType { /** * '0': Error: contains error message. */ ERROR('0'), /** * '1': DrawMesssage: contains serialized DrawMessage(s) prefixed * with the current Player's {@link Player#lastReceivedMessageId} * and ",".
    * Multiple draw messages are concatenated with "|" as separator. */ DRAW_MESSAGE('1'), /** * '2': ImageMessage: Contains number of current players in this room. * After this message a Binary Websocket message will follow, * containing the current Room image as PNG.
    * This is the first message that a Room sends to a new Player. */ IMAGE_MESSAGE('2'), /** * '3': PlayerChanged: contains "+" or "-" which indicate a player * was added or removed to this Room. */ PLAYER_CHANGED('3'); private final char flag; private MessageType(char flag) { this.flag = flag; } } /** * The lock used to synchronize access to this Room. */ private final ReentrantLock roomLock = new ReentrantLock(); /** * Indicates if this room has already been shutdown. */ private volatile boolean closed = false; /** * If true, outgoing DrawMessages will be buffered until the * drawmessageBroadcastTimer ticks. Otherwise they will be sent * immediately. */ private static final boolean BUFFER_DRAW_MESSAGES = true; /** * A timer which sends buffered drawmessages to the client at once * at a regular interval, to avoid sending a lot of very small * messages which would cause TCP overhead and high CPU usage. */ private final Timer drawmessageBroadcastTimer = new Timer(); private static final int TIMER_DELAY = 30; /** * The current active broadcast timer task. If null, then no Broadcast task is scheduled. * The Task will be scheduled if the first player enters the Room, and * cancelled if the last player exits the Room, to avoid unnecessary timer executions. */ private TimerTask activeBroadcastTimerTask; /** * The current image of the room drawboard. DrawMessages that are * received from Players will be drawn onto this image. */ private final BufferedImage roomImage = new BufferedImage(900, 600, BufferedImage.TYPE_INT_RGB); private final Graphics2D roomGraphics = roomImage.createGraphics(); /** * The maximum number of players that can join this room. */ private static final int MAX_PLAYER_COUNT = 100; /** * List of all currently joined players. */ private final List players = new ArrayList(); public Room() { roomGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Clear the image with white background. roomGraphics.setBackground(Color.WHITE); roomGraphics.clearRect(0, 0, roomImage.getWidth(), roomImage.getHeight()); } private TimerTask createBroadcastTimerTask() { return new TimerTask() { @Override public void run() { invokeAndWait(new Runnable() { @Override public void run() { broadcastTimerTick(); } }); } }; } /** * Creates a Player from the given Client and adds it to this room. * @param client the client */ public Player createAndAddPlayer(Client client) { if (players.size() >= MAX_PLAYER_COUNT) { throw new IllegalStateException("Maximum player count (" + MAX_PLAYER_COUNT + ") has been reached."); } Player p = new Player(this, client); // Broadcast to the other players that one player joined. broadcastRoomMessage(MessageType.PLAYER_CHANGED, "+"); // Add the new player to the list. players.add(p); // If currently no Broacast Timer Task is scheduled, then we need to create one. if (activeBroadcastTimerTask == null) { activeBroadcastTimerTask = createBroadcastTimerTask(); drawmessageBroadcastTimer.schedule(activeBroadcastTimerTask, TIMER_DELAY, TIMER_DELAY); } // Send him the current number of players and the current room image. String content = String.valueOf(players.size()); p.sendRoomMessage(MessageType.IMAGE_MESSAGE, content); // Store image as PNG ByteArrayOutputStream bout = new ByteArrayOutputStream(); try { ImageIO.write(roomImage, "PNG", bout); } catch (IOException e) { /* Should never happen */ } // Send the image as binary message. BinaryWebsocketMessage msg = new BinaryWebsocketMessage( ByteBuffer.wrap(bout.toByteArray())); p.getClient().sendMessage(msg); return p; } /** * @see Player#removeFromRoom() * @param p */ private void internalRemovePlayer(Player p) { boolean removed = players.remove(p); assert removed; // If the last player left the Room, we need to cancel the Broadcast Timer Task. if (players.size() == 0) { // Cancel the task. // Note that it can happen that the TimerTask is just about to execute (from // the Timer thread) but waits until all players are gone (or even until a new // player is added to the list), and then executes. This is OK. To prevent it, // a TimerTask subclass would need to have some boolan "cancel" instance variable and // query it in the invocation of Room#invokeAndWait. activeBroadcastTimerTask.cancel(); activeBroadcastTimerTask = null; } // Broadcast that one player is removed. broadcastRoomMessage(MessageType.PLAYER_CHANGED, "-"); } /** * @see Player#handleDrawMessage(DrawMessage, long) * @param p * @param msg * @param msgId */ private void internalHandleDrawMessage(Player p, DrawMessage msg, long msgId) { p.setLastReceivedMessageId(msgId); // Draw the RoomMessage onto our Room Image. msg.draw(roomGraphics); // Broadcast the Draw Message. broadcastDrawMessage(msg); } /** * Broadcasts the given drawboard message to all connected players.
    * Note: For DrawMessages, please use * {@link #broadcastDrawMessage(DrawMessage)} * as this method will buffer them and prefix them with the correct * last received Message ID. * @param type * @param content */ private void broadcastRoomMessage(MessageType type, String content) { for (Player p : players) { p.sendRoomMessage(type, content); } } /** * Broadcast the given DrawMessage. This will buffer the message * and the {@link #drawmessageBroadcastTimer} will broadcast them * at a regular interval, prefixing them with the player's current * {@link Player#lastReceivedMessageId}. * @param msg */ private void broadcastDrawMessage(DrawMessage msg) { if (!BUFFER_DRAW_MESSAGES) { String msgStr = msg.toString(); for (Player p : players) { String s = String.valueOf(p.getLastReceivedMessageId()) + "," + msgStr; p.sendRoomMessage(MessageType.DRAW_MESSAGE, s); } } else { for (Player p : players) { p.getBufferedDrawMessages().add(msg); } } } /** * Tick handler for the broadcastTimer. */ private void broadcastTimerTick() { // For each Player, send all per Player buffered // DrawMessages, prefixing each DrawMessage with the player's // lastReceivedMessageId. // Multiple messages are concatenated with "|". for (Player p : players) { StringBuilder sb = new StringBuilder(); List drawMessages = p.getBufferedDrawMessages(); if (drawMessages.size() > 0) { for (int i = 0; i < drawMessages.size(); i++) { DrawMessage msg = drawMessages.get(i); String s = String.valueOf(p.getLastReceivedMessageId()) + "," + msg.toString(); if (i > 0) sb.append("|"); sb.append(s); } drawMessages.clear(); p.sendRoomMessage(MessageType.DRAW_MESSAGE, sb.toString()); } } } /** * A list of cached {@link Runnable}s to prevent recursive invocation of Runnables * by one thread. This variable is only used by one thread at a time and then * set to null. */ private List cachedRunnables = null; /** * Submits the given Runnable to the Room Executor and waits until it * has been executed. Currently, this simply means that the Runnable * will be run directly inside of a synchronized() block.
    * Note that if a runnable recursively calls invokeAndWait() with another * runnable on this Room, it will not be executed recursively, but instead * cached until the original runnable is finished, to keep the behavior of * using a Executor. * @param task */ public void invokeAndWait(Runnable task) { // Check if the current thread already holds a lock on this room. // If yes, then we must not directly execute the Runnable but instead // cache it until the original invokeAndWait() has finished. if (roomLock.isHeldByCurrentThread()) { if (cachedRunnables == null) { cachedRunnables = new ArrayList(); } cachedRunnables.add(task); } else { roomLock.lock(); try { // Explicitely overwrite value to ensure data consistency in // current thread cachedRunnables = null; if (!closed) { task.run(); } // Run the cached runnables. if (cachedRunnables != null) { for (int i = 0; i < cachedRunnables.size(); i++) { if (!closed) { cachedRunnables.get(i).run(); } } cachedRunnables = null; } } finally { roomLock.unlock(); } } } /** * Shuts down the roomExecutor and the drawmessageBroadcastTimer. */ public void shutdown() { invokeAndWait(new Runnable() { @Override public void run() { closed = true; drawmessageBroadcastTimer.cancel(); roomGraphics.dispose(); } }); } /** * A Player participates in a Room. It is the interface between the * {@link Room} and the {@link Client}.

    * * Note: This means a player object is actually a join between Room and * Client. */ public final class Player { /** * The room to which this player belongs. */ private Room room; /** * The room buffers the last draw message ID that was received from * this player. */ private long lastReceivedMessageId = 0; private final Client client; /** * Buffered DrawMessages that will be sent by a Timer. */ private final List bufferedDrawMessages = new ArrayList(); private List getBufferedDrawMessages() { return bufferedDrawMessages; } private Player(Room room, Client client) { this.room = room; this.client = client; } public Room getRoom() { return room; } public Client getClient() { return client; } /** * Removes this player from its room, e.g. when * the client disconnects. */ public void removeFromRoom() { if (room != null) { room.internalRemovePlayer(this); room = null; } } private long getLastReceivedMessageId() { return lastReceivedMessageId; } private void setLastReceivedMessageId(long value) { lastReceivedMessageId = value; } /** * Handles the given DrawMessage by drawing it onto this Room's * image and by broadcasting it to the connected players. * @param msg * @param msgId */ public void handleDrawMessage(DrawMessage msg, long msgId) { room.internalHandleDrawMessage(this, msg, msgId); } /** * Sends the given room message. * @param type * @param content */ private void sendRoomMessage(MessageType type, String content) { if (content == null || type == null) throw new NullPointerException(); String completeMsg = String.valueOf(type.flag) + content; client.sendMessage(new StringWebsocketMessage(completeMsg)); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/0000755000175100017510000000000012301126373023567 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/chat/0000755000175100017510000000000012301126373024506 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet.java0000644000175100017510000000707512217363077031427 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.tc7.chat; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import org.apache.catalina.websocket.WsOutbound; import util.HTMLFilter; /** * Example web socket servlet for chat. * @deprecated See {@link websocket.chat.ChatAnnotation} */ @Deprecated public class ChatWebSocketServlet extends WebSocketServlet { private static final long serialVersionUID = 1L; private static final String GUEST_PREFIX = "Guest"; private final AtomicInteger connectionIds = new AtomicInteger(0); private final Set connections = new CopyOnWriteArraySet(); @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { return new ChatMessageInbound(connectionIds.incrementAndGet()); } private final class ChatMessageInbound extends MessageInbound { private final String nickname; private ChatMessageInbound(int id) { this.nickname = GUEST_PREFIX + id; } @Override protected void onOpen(WsOutbound outbound) { connections.add(this); String message = String.format("* %s %s", nickname, "has joined."); broadcast(message); } @Override protected void onClose(int status) { connections.remove(this); String message = String.format("* %s %s", nickname, "has disconnected."); broadcast(message); } @Override protected void onBinaryMessage(ByteBuffer message) throws IOException { throw new UnsupportedOperationException( "Binary message not supported."); } @Override protected void onTextMessage(CharBuffer message) throws IOException { // Never trust the client String filteredMessage = String.format("%s: %s", nickname, HTMLFilter.filter(message.toString())); broadcast(filteredMessage); } private void broadcast(String message) { for (ChatMessageInbound connection : connections) { try { CharBuffer buffer = CharBuffer.wrap(message); connection.getWsOutbound().writeTextMessage(buffer); } catch (IOException ignore) { // Ignore } } } } }tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/echo/0000755000175100017510000000000012301126373024505 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage.java0000644000175100017510000000554612217363077027557 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.tc7.echo; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; /** * @deprecated See {@link websocket.echo.EchoAnnotation} */ @Deprecated public class EchoMessage extends WebSocketServlet { private static final long serialVersionUID = 1L; private volatile int byteBufSize; private volatile int charBufSize; @Override public void init() throws ServletException { super.init(); byteBufSize = getInitParameterIntValue("byteBufferMaxSize", 2097152); charBufSize = getInitParameterIntValue("charBufferMaxSize", 2097152); } public int getInitParameterIntValue(String name, int defaultValue) { String val = this.getInitParameter(name); int result; if(null != val) { try { result = Integer.parseInt(val); }catch (Exception x) { result = defaultValue; } } else { result = defaultValue; } return result; } @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { return new EchoMessageInbound(byteBufSize,charBufSize); } private static final class EchoMessageInbound extends MessageInbound { public EchoMessageInbound(int byteBufferMaxSize, int charBufferMaxSize) { super(); setByteBufferMaxSize(byteBufferMaxSize); setCharBufferMaxSize(charBufferMaxSize); } @Override protected void onBinaryMessage(ByteBuffer message) throws IOException { getWsOutbound().writeBinaryMessage(message); } @Override protected void onTextMessage(CharBuffer message) throws IOException { getWsOutbound().writeTextMessage(message); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream.java0000644000175100017510000000444312217363077027421 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.tc7.echo; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import org.apache.catalina.websocket.WsOutbound; /** * @deprecated See {@link websocket.echo.EchoAnnotation} */ @Deprecated public class EchoStream extends WebSocketServlet { private static final long serialVersionUID = 1L; @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { return new EchoStreamInbound(); } private static final class EchoStreamInbound extends StreamInbound { @Override protected void onBinaryData(InputStream is) throws IOException { // Simply echo the data to back to the client. WsOutbound outbound = getWsOutbound(); int i = is.read(); while (i != -1) { outbound.writeBinaryData(i); i = is.read(); } outbound.flush(); } @Override protected void onTextData(Reader r) throws IOException { // Simply echo the data to back to the client. WsOutbound outbound = getWsOutbound(); int c = r.read(); while (c != -1) { outbound.writeTextData((char) c); c = r.read(); } outbound.flush(); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/snake/0000755000175100017510000000000012301126373024670 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Direction.java0000644000175100017510000000170712217363077027472 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.tc7.snake; /** * @deprecated See {@link websocket.snake.Direction} */ @Deprecated public enum Direction { NONE, NORTH, SOUTH, EAST, WEST } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Snake.java0000644000175100017510000001074512217363077026615 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.tc7.snake; import java.io.IOException; import java.nio.CharBuffer; import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; import org.apache.catalina.websocket.WsOutbound; /** * @deprecated See {@link websocket.snake.Snake} */ @Deprecated public class Snake { private static final int DEFAULT_LENGTH = 5; private final int id; private final WsOutbound outbound; private Direction direction; private int length = DEFAULT_LENGTH; private Location head; private Deque tail = new ArrayDeque(); private String hexColor; public Snake(int id, WsOutbound outbound) { this.id = id; this.outbound = outbound; this.hexColor = SnakeWebSocketServlet.getRandomHexColor(); resetState(); } private void resetState() { this.direction = Direction.NONE; this.head = SnakeWebSocketServlet.getRandomLocation(); this.tail.clear(); this.length = DEFAULT_LENGTH; } private synchronized void kill() { resetState(); try { CharBuffer response = CharBuffer.wrap("{'type': 'dead'}"); outbound.writeTextMessage(response); } catch (IOException ioe) { // Ignore } } private synchronized void reward() { length++; try { CharBuffer response = CharBuffer.wrap("{'type': 'kill'}"); outbound.writeTextMessage(response); } catch (IOException ioe) { // Ignore } } public synchronized void update(Collection snakes) { Location nextLocation = head.getAdjacentLocation(direction); if (nextLocation.x >= SnakeWebSocketServlet.PLAYFIELD_WIDTH) { nextLocation.x = 0; } if (nextLocation.y >= SnakeWebSocketServlet.PLAYFIELD_HEIGHT) { nextLocation.y = 0; } if (nextLocation.x < 0) { nextLocation.x = SnakeWebSocketServlet.PLAYFIELD_WIDTH; } if (nextLocation.y < 0) { nextLocation.y = SnakeWebSocketServlet.PLAYFIELD_HEIGHT; } if (direction != Direction.NONE) { tail.addFirst(head); if (tail.size() > length) { tail.removeLast(); } head = nextLocation; } handleCollisions(snakes); } private void handleCollisions(Collection snakes) { for (Snake snake : snakes) { boolean headCollision = id != snake.id && snake.getHead().equals(head); boolean tailCollision = snake.getTail().contains(head); if (headCollision || tailCollision) { kill(); if (id != snake.id) { snake.reward(); } } } } public synchronized Location getHead() { return head; } public synchronized Collection getTail() { return tail; } public synchronized void setDirection(Direction direction) { this.direction = direction; } public synchronized String getLocationsJson() { StringBuilder sb = new StringBuilder(); sb.append(String.format("{x: %d, y: %d}", Integer.valueOf(head.x), Integer.valueOf(head.y))); for (Location location : tail) { sb.append(','); sb.append(String.format("{x: %d, y: %d}", Integer.valueOf(location.x), Integer.valueOf(location.y))); } return String.format("{'id':%d,'body':[%s]}", Integer.valueOf(id), sb.toString()); } public int getId() { return id; } public String getHexColor() { return hexColor; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location.java0000644000175100017510000000407712217363077027325 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.tc7.snake; /** * @deprecated See {@link websocket.snake.Location} */ @Deprecated public class Location { public int x; public int y; public Location(int x, int y) { this.x = x; this.y = y; } public Location getAdjacentLocation(Direction direction) { switch (direction) { case NORTH: return new Location(x, y - SnakeWebSocketServlet.GRID_SIZE); case SOUTH: return new Location(x, y + SnakeWebSocketServlet.GRID_SIZE); case EAST: return new Location(x + SnakeWebSocketServlet.GRID_SIZE, y); case WEST: return new Location(x - SnakeWebSocketServlet.GRID_SIZE, y); case NONE: // fall through default: return this; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Location location = (Location) o; if (x != location.x) return false; if (y != location.y) return false; return true; } @Override public int hashCode() { int result = x; result = 31 * result + y; return result; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet.java0000644000175100017510000001673312217363077031774 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.tc7.snake; import java.awt.Color; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Random; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.websocket.MessageInbound; import org.apache.catalina.websocket.StreamInbound; import org.apache.catalina.websocket.WebSocketServlet; import org.apache.catalina.websocket.WsOutbound; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Example web socket servlet for simple multi-player snake. * @deprecated See {@link websocket.snake.SnakeAnnotation} */ @Deprecated public class SnakeWebSocketServlet extends WebSocketServlet { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(SnakeWebSocketServlet.class); public static final int PLAYFIELD_WIDTH = 640; public static final int PLAYFIELD_HEIGHT = 480; public static final int GRID_SIZE = 10; private static final long TICK_DELAY = 100; private static final Random random = new Random(); private final Timer gameTimer = new Timer(SnakeWebSocketServlet.class.getSimpleName() + " Timer"); private final AtomicInteger connectionIds = new AtomicInteger(0); private final ConcurrentHashMap snakes = new ConcurrentHashMap(); private final ConcurrentHashMap connections = new ConcurrentHashMap(); @Override public void init() throws ServletException { super.init(); gameTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { tick(); } catch (RuntimeException e) { log.error("Caught to prevent timer from shutting down", e); } } }, TICK_DELAY, TICK_DELAY); } private void tick() { StringBuilder sb = new StringBuilder(); for (Iterator iterator = getSnakes().iterator(); iterator.hasNext();) { Snake snake = iterator.next(); snake.update(getSnakes()); sb.append(snake.getLocationsJson()); if (iterator.hasNext()) { sb.append(','); } } broadcast(String.format("{'type': 'update', 'data' : [%s]}", sb.toString())); } private void broadcast(String message) { for (SnakeMessageInbound connection : getConnections()) { try { CharBuffer buffer = CharBuffer.wrap(message); connection.getWsOutbound().writeTextMessage(buffer); } catch (IOException ignore) { // Ignore } } } private Collection getConnections() { return Collections.unmodifiableCollection(connections.values()); } private Collection getSnakes() { return Collections.unmodifiableCollection(snakes.values()); } public static String getRandomHexColor() { float hue = random.nextFloat(); // sat between 0.1 and 0.3 float saturation = (random.nextInt(2000) + 1000) / 10000f; float luminance = 0.9f; Color color = Color.getHSBColor(hue, saturation, luminance); return '#' + Integer.toHexString( (color.getRGB() & 0xffffff) | 0x1000000).substring(1); } public static Location getRandomLocation() { int x = roundByGridSize( random.nextInt(SnakeWebSocketServlet.PLAYFIELD_WIDTH)); int y = roundByGridSize( random.nextInt(SnakeWebSocketServlet.PLAYFIELD_HEIGHT)); return new Location(x, y); } private static int roundByGridSize(int value) { value = value + (SnakeWebSocketServlet.GRID_SIZE / 2); value = value / SnakeWebSocketServlet.GRID_SIZE; value = value * SnakeWebSocketServlet.GRID_SIZE; return value; } @Override public void destroy() { super.destroy(); if (gameTimer != null) { gameTimer.cancel(); } } @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { return new SnakeMessageInbound(connectionIds.incrementAndGet()); } private final class SnakeMessageInbound extends MessageInbound { private final int id; private Snake snake; private SnakeMessageInbound(int id) { this.id = id; } @Override protected void onOpen(WsOutbound outbound) { this.snake = new Snake(id, outbound); snakes.put(Integer.valueOf(id), snake); connections.put(Integer.valueOf(id), this); StringBuilder sb = new StringBuilder(); for (Iterator iterator = getSnakes().iterator(); iterator.hasNext();) { Snake snake = iterator.next(); sb.append(String.format("{id: %d, color: '%s'}", Integer.valueOf(snake.getId()), snake.getHexColor())); if (iterator.hasNext()) { sb.append(','); } } broadcast(String.format("{'type': 'join','data':[%s]}", sb.toString())); } @Override protected void onClose(int status) { connections.remove(Integer.valueOf(id)); snakes.remove(Integer.valueOf(id)); broadcast(String.format("{'type': 'leave', 'id': %d}", Integer.valueOf(id))); } @Override protected void onBinaryMessage(ByteBuffer message) throws IOException { throw new UnsupportedOperationException( "Binary message not supported."); } @Override protected void onTextMessage(CharBuffer charBuffer) throws IOException { String message = charBuffer.toString(); if ("west".equals(message)) { snake.setDirection(Direction.WEST); } else if ("north".equals(message)) { snake.setDirection(Direction.NORTH); } else if ("east".equals(message)) { snake.setDirection(Direction.EAST); } else if ("south".equals(message)) { snake.setDirection(Direction.SOUTH); } } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/snake/0000755000175100017510000000000012301126373024173 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/snake/SnakeAnnotation.java0000644000175100017510000001057112222756007030143 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.snake; import java.awt.Color; import java.io.EOFException; import java.util.Iterator; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint(value = "/websocket/snake") public class SnakeAnnotation { public static final int PLAYFIELD_WIDTH = 640; public static final int PLAYFIELD_HEIGHT = 480; public static final int GRID_SIZE = 10; private static final AtomicInteger snakeIds = new AtomicInteger(0); private static final Random random = new Random(); private final int id; private Snake snake; public static String getRandomHexColor() { float hue = random.nextFloat(); // sat between 0.1 and 0.3 float saturation = (random.nextInt(2000) + 1000) / 10000f; float luminance = 0.9f; Color color = Color.getHSBColor(hue, saturation, luminance); return '#' + Integer.toHexString( (color.getRGB() & 0xffffff) | 0x1000000).substring(1); } public static Location getRandomLocation() { int x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH)); int y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT)); return new Location(x, y); } private static int roundByGridSize(int value) { value = value + (GRID_SIZE / 2); value = value / GRID_SIZE; value = value * GRID_SIZE; return value; } public SnakeAnnotation() { this.id = snakeIds.getAndIncrement(); } @OnOpen public void onOpen(Session session) { this.snake = new Snake(id, session); SnakeTimer.addSnake(snake); StringBuilder sb = new StringBuilder(); for (Iterator iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) { Snake snake = iterator.next(); sb.append(String.format("{id: %d, color: '%s'}", Integer.valueOf(snake.getId()), snake.getHexColor())); if (iterator.hasNext()) { sb.append(','); } } SnakeTimer.broadcast(String.format("{'type': 'join','data':[%s]}", sb.toString())); } @OnMessage public void onTextMessage(String message) { if ("west".equals(message)) { snake.setDirection(Direction.WEST); } else if ("north".equals(message)) { snake.setDirection(Direction.NORTH); } else if ("east".equals(message)) { snake.setDirection(Direction.EAST); } else if ("south".equals(message)) { snake.setDirection(Direction.SOUTH); } } @OnClose public void onClose() { SnakeTimer.removeSnake(snake); SnakeTimer.broadcast(String.format("{'type': 'leave', 'id': %d}", Integer.valueOf(id))); } @OnError public void onError(Throwable t) throws Throwable { // Most likely cause is a user closing their browser. Check to see if // the root cause is EOF and if it is ignore it. // Protect against infinite loops. int count = 0; Throwable root = t; while (root.getCause() != null && count < 20) { root = root.getCause(); count ++; } if (root instanceof EOFException) { // Assume this is triggered by the user closing their browser and // ignore it. } else { throw t; } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/snake/Direction.java0000644000175100017510000000157211725626603026775 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.snake; public enum Direction { NONE, NORTH, SOUTH, EAST, WEST } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.java0000644000175100017510000000731012222760565027112 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.snake; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Sets up the timer for the multi-player snake game WebSocket example. */ public class SnakeTimer { private static final Log log = LogFactory.getLog(SnakeTimer.class); private static Timer gameTimer = null; private static final long TICK_DELAY = 100; private static final ConcurrentHashMap snakes = new ConcurrentHashMap(); protected static synchronized void addSnake(Snake snake) { if (snakes.size() == 0) { startTimer(); } snakes.put(Integer.valueOf(snake.getId()), snake); } protected static Collection getSnakes() { return Collections.unmodifiableCollection(snakes.values()); } protected static synchronized void removeSnake(Snake snake) { snakes.remove(Integer.valueOf(snake.getId())); if (snakes.size() == 0) { stopTimer(); } } protected static void tick() { StringBuilder sb = new StringBuilder(); for (Iterator iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) { Snake snake = iterator.next(); snake.update(SnakeTimer.getSnakes()); sb.append(snake.getLocationsJson()); if (iterator.hasNext()) { sb.append(','); } } broadcast(String.format("{'type': 'update', 'data' : [%s]}", sb.toString())); } protected static void broadcast(String message) { for (Snake snake : SnakeTimer.getSnakes()) { try { snake.sendMessage(message); } catch (IllegalStateException ise) { // An ISE can occur if an attempt is made to write to a // WebSocket connection after it has been closed. The // alternative to catching this exception is to synchronise // the writes to the clients along with the addSnake() and // removeSnake() methods that are already synchronised. } } } public static void startTimer() { gameTimer = new Timer(SnakeTimer.class.getSimpleName() + " Timer"); gameTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { tick(); } catch (RuntimeException e) { log.error("Caught to prevent timer from shutting down", e); } } }, TICK_DELAY, TICK_DELAY); } public static void stopTimer() { if (gameTimer != null) { gameTimer.cancel(); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/snake/Snake.java0000644000175100017510000001077312224737106026115 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.snake; import java.io.IOException; import java.util.ArrayDeque; import java.util.Collection; import java.util.Deque; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.Session; public class Snake { private static final int DEFAULT_LENGTH = 5; private final int id; private final Session session; private Direction direction; private int length = DEFAULT_LENGTH; private Location head; private final Deque tail = new ArrayDeque(); private final String hexColor; public Snake(int id, Session session) { this.id = id; this.session = session; this.hexColor = SnakeAnnotation.getRandomHexColor(); resetState(); } private void resetState() { this.direction = Direction.NONE; this.head = SnakeAnnotation.getRandomLocation(); this.tail.clear(); this.length = DEFAULT_LENGTH; } private synchronized void kill() { resetState(); sendMessage("{'type': 'dead'}"); } private synchronized void reward() { length++; sendMessage("{'type': 'kill'}"); } protected void sendMessage(String msg) { try { session.getBasicRemote().sendText(msg); } catch (IOException ioe) { CloseReason cr = new CloseReason(CloseCodes.CLOSED_ABNORMALLY, ioe.getMessage()); try { session.close(cr); } catch (IOException ioe2) { // Ignore } } } public synchronized void update(Collection snakes) { Location nextLocation = head.getAdjacentLocation(direction); if (nextLocation.x >= SnakeAnnotation.PLAYFIELD_WIDTH) { nextLocation.x = 0; } if (nextLocation.y >= SnakeAnnotation.PLAYFIELD_HEIGHT) { nextLocation.y = 0; } if (nextLocation.x < 0) { nextLocation.x = SnakeAnnotation.PLAYFIELD_WIDTH; } if (nextLocation.y < 0) { nextLocation.y = SnakeAnnotation.PLAYFIELD_HEIGHT; } if (direction != Direction.NONE) { tail.addFirst(head); if (tail.size() > length) { tail.removeLast(); } head = nextLocation; } handleCollisions(snakes); } private void handleCollisions(Collection snakes) { for (Snake snake : snakes) { boolean headCollision = id != snake.id && snake.getHead().equals(head); boolean tailCollision = snake.getTail().contains(head); if (headCollision || tailCollision) { kill(); if (id != snake.id) { snake.reward(); } } } } public synchronized Location getHead() { return head; } public synchronized Collection getTail() { return tail; } public synchronized void setDirection(Direction direction) { this.direction = direction; } public synchronized String getLocationsJson() { StringBuilder sb = new StringBuilder(); sb.append(String.format("{x: %d, y: %d}", Integer.valueOf(head.x), Integer.valueOf(head.y))); for (Location location : tail) { sb.append(','); sb.append(String.format("{x: %d, y: %d}", Integer.valueOf(location.x), Integer.valueOf(location.y))); } return String.format("{'id':%d,'body':[%s]}", Integer.valueOf(id), sb.toString()); } public int getId() { return id; } public String getHexColor() { return hexColor; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/snake/Location.java0000644000175100017510000000373312064707216026623 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket.snake; public class Location { public int x; public int y; public Location(int x, int y) { this.x = x; this.y = y; } public Location getAdjacentLocation(Direction direction) { switch (direction) { case NORTH: return new Location(x, y - SnakeAnnotation.GRID_SIZE); case SOUTH: return new Location(x, y + SnakeAnnotation.GRID_SIZE); case EAST: return new Location(x + SnakeAnnotation.GRID_SIZE, y); case WEST: return new Location(x - SnakeAnnotation.GRID_SIZE, y); case NONE: // fall through default: return this; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Location location = (Location) o; if (x != location.x) return false; if (y != location.y) return false; return true; } @Override public int hashCode() { int result = x; result = 31 * result + y; return result; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/websocket/ExamplesConfig.java0000644000175100017510000000452712227332147026656 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 websocket; import java.util.HashSet; import java.util.Set; import javax.websocket.Endpoint; import javax.websocket.server.ServerApplicationConfig; import javax.websocket.server.ServerEndpointConfig; import websocket.drawboard.DrawboardEndpoint; import websocket.echo.EchoEndpoint; public class ExamplesConfig implements ServerApplicationConfig { @Override public Set getEndpointConfigs( Set> scanned) { Set result = new HashSet(); if (scanned.contains(EchoEndpoint.class)) { result.add(ServerEndpointConfig.Builder.create( EchoEndpoint.class, "/websocket/echoProgrammatic").build()); } if (scanned.contains(DrawboardEndpoint.class)) { result.add(ServerEndpointConfig.Builder.create( DrawboardEndpoint.class, "/websocket/drawboard").build()); } return result; } @Override public Set> getAnnotatedEndpointClasses(Set> scanned) { // Deploy all WebSocket endpoints defined by annotations in the examples // web application. Filter out all others to avoid issues when running // tests on Gump Set> results = new HashSet>(); for (Class clazz : scanned) { if (clazz.getPackage().getName().startsWith("websocket.")) { results.add(clazz); } } return results; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/HelloWorldExample.java0000644000175100017510000000525212271304167025347 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.io.IOException; import java.io.PrintWriter; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * The simplest possible servlet. * * @author James Duncan Davidson */ public class HelloWorldExample extends HttpServlet { private static final long serialVersionUID = 1L; @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ResourceBundle rb = ResourceBundle.getBundle("LocalStrings",request.getLocale()); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(""); String title = rb.getString("helloworld.title"); out.println("" + title + ""); out.println(""); out.println(""); // note that all links are created to be relative. this // ensures that we can move the web application that this // servlet belongs to to a different place in the url // tree and not have any harmful side effects. // XXX // making these absolute till we work out the // addition of a PathInfo issue out.println(""); out.println("\"view"); out.println(""); out.println("\"return\""); out.println("

    " + title + "

    "); out.println(""); out.println(""); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/RequestInfoExample.java0000644000175100017510000001021512271304167025533 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.io.IOException; import java.io.PrintWriter; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import util.HTMLFilter; /** * Example servlet showing request information. * * @author James Duncan Davidson */ public class RequestInfoExample extends HttpServlet { private static final long serialVersionUID = 1L; private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings"); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(""); String title = RB.getString("requestinfo.title"); out.println("" + title + ""); out.println(""); out.println(""); // img stuff not req'd for source code html showing // all links relative! // XXX // making these absolute till we work out the // addition of a PathInfo issue out.println(""); out.println("\"view"); out.println(""); out.println("\"return\""); out.println("

    " + title + "

    "); out.println(""); String cipherSuite= (String)request.getAttribute("javax.servlet.request.cipher_suite"); if(cipherSuite!=null){ out.println(""); } out.println("
    "); out.println(RB.getString("requestinfo.label.method")); out.println(""); out.println(HTMLFilter.filter(request.getMethod())); out.println("
    "); out.println(RB.getString("requestinfo.label.requesturi")); out.println(""); out.println(HTMLFilter.filter(request.getRequestURI())); out.println("
    "); out.println(RB.getString("requestinfo.label.protocol")); out.println(""); out.println(HTMLFilter.filter(request.getProtocol())); out.println("
    "); out.println(RB.getString("requestinfo.label.pathinfo")); out.println(""); out.println(HTMLFilter.filter(request.getPathInfo())); out.println("
    "); out.println(RB.getString("requestinfo.label.remoteaddr")); out.println(""); out.println(HTMLFilter.filter(request.getRemoteAddr())); out.println("
    "); out.println("SSLCipherSuite:"); out.println(""); out.println(HTMLFilter.filter(cipherSuite)); out.println("
    "); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/compressionFilters/0000755000175100017510000000000012301126373024776 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java0000644000175100017510000002200512271304167031314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 compressionFilters; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.StringTokenizer; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Implementation of javax.servlet.Filter used to compress * the ServletResponse if it is bigger than a threshold. * * @author Amy Roh * @author Dmitri Valdin */ public class CompressionFilter implements Filter { /** * The filter configuration object we are associated with. If this value * is null, this filter instance is not currently configured. */ private FilterConfig config = null; /** * Minimal reasonable threshold. */ private int minThreshold = 128; /** * The threshold number to compress. */ protected int compressionThreshold = 0; /** * Minimal reasonable buffer. */ private int minBuffer = 8192; // 8KB is what tomcat would use by default anyway /** * The compression buffer size to avoid chunking. */ protected int compressionBuffer = 0; /** * The mime types to compress. */ protected String[] compressionMimeTypes = {"text/html", "text/xml", "text/plain"}; /** * Debug level for this filter. */ private int debug = 0; /** * Place this filter into service. * * @param filterConfig The filter configuration object */ @Override public void init(FilterConfig filterConfig) { config = filterConfig; if (filterConfig != null) { String value = filterConfig.getInitParameter("debug"); if (value!=null) { debug = Integer.parseInt(value); } String str = filterConfig.getInitParameter("compressionThreshold"); if (str!=null) { compressionThreshold = Integer.parseInt(str); if (compressionThreshold != 0 && compressionThreshold < minThreshold) { if (debug > 0) { System.out.println("compressionThreshold should be either 0 - no compression or >= " + minThreshold); System.out.println("compressionThreshold set to " + minThreshold); } compressionThreshold = minThreshold; } } str = filterConfig.getInitParameter("compressionBuffer"); if (str!=null) { compressionBuffer = Integer.parseInt(str); if (compressionBuffer < minBuffer) { if (debug > 0) { System.out.println("compressionBuffer should be >= " + minBuffer); System.out.println("compressionBuffer set to " + minBuffer); } compressionBuffer = minBuffer; } } str = filterConfig.getInitParameter("compressionMimeTypes"); if (str!=null) { List values = new ArrayList(); StringTokenizer st = new StringTokenizer(str, ","); while (st.hasMoreTokens()) { String token = st.nextToken().trim(); if (token.length() > 0) { values.add(token); } } if (values.size() > 0) { compressionMimeTypes = values.toArray( new String[values.size()]); } else { compressionMimeTypes = null; } if (debug > 0) { System.out.println("compressionMimeTypes set to " + compressionMimeTypes); } } } } /** * Take this filter out of service. */ @Override public void destroy() { this.config = null; } /** * The doFilter method of the Filter is called by the container * each time a request/response pair is passed through the chain due * to a client request for a resource at the end of the chain. * The FilterChain passed into this method allows the Filter to pass on the * request and response to the next entity in the chain.

    * This method first examines the request to check whether the client support * compression.
    * It simply just pass the request and response if there is no support for * compression.
    * If the compression support is available, it creates a * CompressionServletResponseWrapper object which compresses the content and * modifies the header if the content length is big enough. * It then invokes the next entity in the chain using the FilterChain object * (chain.doFilter()),
    **/ @Override public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { if (debug > 0) { System.out.println("@doFilter"); } if (compressionThreshold == 0) { if (debug > 0) { System.out.println("doFilter got called, but compressionTreshold is set to 0 - no compression"); } chain.doFilter(request, response); return; } boolean supportCompression = false; if (request instanceof HttpServletRequest) { if (debug > 1) { System.out.println("requestURI = " + ((HttpServletRequest)request).getRequestURI()); } // Are we allowed to compress ? String s = ((HttpServletRequest)request).getParameter("gzip"); if ("false".equals(s)) { if (debug > 0) { System.out.println("got parameter gzip=false --> don't compress, just chain filter"); } chain.doFilter(request, response); return; } Enumeration e = ((HttpServletRequest)request).getHeaders("Accept-Encoding"); while (e.hasMoreElements()) { String name = e.nextElement(); if (name.indexOf("gzip") != -1) { if (debug > 0) { System.out.println("supports compression"); } supportCompression = true; } else { if (debug > 0) { System.out.println("no support for compression"); } } } } if (supportCompression) { if (response instanceof HttpServletResponse) { CompressionServletResponseWrapper wrappedResponse = new CompressionServletResponseWrapper((HttpServletResponse)response); wrappedResponse.setDebugLevel(debug); wrappedResponse.setCompressionThreshold(compressionThreshold); wrappedResponse.setCompressionBuffer(compressionBuffer); wrappedResponse.setCompressionMimeTypes(compressionMimeTypes); if (debug > 0) { System.out.println("doFilter gets called with compression"); } try { chain.doFilter(request, wrappedResponse); } finally { wrappedResponse.finishResponse(); } return; } } else { if (debug > 0) { System.out.println("doFilter gets called w/o compression"); } chain.doFilter(request, response); return; } } /** * Set filter config * This function is equivalent to init. Required by Weblogic 6.1 * * @param filterConfig The filter configuration object */ public void setFilterConfig(FilterConfig filterConfig) { init(filterConfig); } /** * Return filter config * Required by Weblogic 6.1 */ public FilterConfig getFilterConfig() { return config; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java0000644000175100017510000003012612271304167033044 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 compressionFilters; import java.io.IOException; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; import javax.servlet.ServletOutputStream; /** * Implementation of ServletOutputStream that works with * the CompressionServletResponseWrapper implementation. * * @author Amy Roh * @author Dmitri Valdin */ public class CompressionResponseStream extends ServletOutputStream { // ----------------------------------------------------------- Constructors /** * Construct a servlet output stream associated with the specified Response. * * @param responseWrapper The associated response wrapper * @param originalOutput the output stream */ public CompressionResponseStream( CompressionServletResponseWrapper responseWrapper, ServletOutputStream originalOutput) { super(); closed = false; this.response = responseWrapper; this.output = originalOutput; } // ----------------------------------------------------- Instance Variables /** * The threshold number which decides to compress or not. * Users can configure in web.xml to set it to fit their needs. */ protected int compressionThreshold = 0; /** * The compression buffer size to avoid chunking */ protected int compressionBuffer = 0; /** * The mime types to compress */ protected String[] compressionMimeTypes = {"text/html", "text/xml", "text/plain"}; /** * Debug level */ private int debug = 0; /** * The buffer through which all of our output bytes are passed. */ protected byte[] buffer = null; /** * The number of data bytes currently in the buffer. */ protected int bufferCount = 0; /** * The underlying gzip output stream to which we should write data. */ protected OutputStream gzipstream = null; /** * Has this stream been closed? */ protected boolean closed = false; /** * The content length past which we will not write, or -1 if there is * no defined content length. */ protected int length = -1; /** * The response with which this servlet output stream is associated. */ protected CompressionServletResponseWrapper response = null; /** * The underlying servlet output stream to which we should write data. */ protected ServletOutputStream output = null; // --------------------------------------------------------- Public Methods /** * Set debug level */ public void setDebugLevel(int debug) { this.debug = debug; } /** * Set the compressionThreshold number and create buffer for this size */ protected void setCompressionThreshold(int compressionThreshold) { this.compressionThreshold = compressionThreshold; buffer = new byte[this.compressionThreshold]; if (debug > 1) { System.out.println("compressionThreshold is set to "+ this.compressionThreshold); } } /** * The compression buffer size to avoid chunking */ protected void setCompressionBuffer(int compressionBuffer) { this.compressionBuffer = compressionBuffer; if (debug > 1) { System.out.println("compressionBuffer is set to "+ this.compressionBuffer); } } /** * Set supported mime types */ public void setCompressionMimeTypes(String[] compressionMimeTypes) { this.compressionMimeTypes = compressionMimeTypes; if (debug > 1) { System.out.println("compressionMimeTypes is set to " + this.compressionMimeTypes); } } /** * Close this output stream, causing any buffered data to be flushed and * any further output data to throw an IOException. */ @Override public void close() throws IOException { if (debug > 1) { System.out.println("close() @ CompressionResponseStream"); } if (closed) throw new IOException("This output stream has already been closed"); if (gzipstream != null) { flushToGZip(); gzipstream.close(); gzipstream = null; } else { if (bufferCount > 0) { if (debug > 2) { System.out.print("output.write("); System.out.write(buffer, 0, bufferCount); System.out.println(")"); } output.write(buffer, 0, bufferCount); bufferCount = 0; } } output.close(); closed = true; } /** * Flush any buffered data for this output stream, which also causes the * response to be committed. */ @Override public void flush() throws IOException { if (debug > 1) { System.out.println("flush() @ CompressionResponseStream"); } if (closed) { throw new IOException("Cannot flush a closed output stream"); } if (gzipstream != null) { gzipstream.flush(); } } public void flushToGZip() throws IOException { if (debug > 1) { System.out.println("flushToGZip() @ CompressionResponseStream"); } if (bufferCount > 0) { if (debug > 1) { System.out.println("flushing out to GZipStream, bufferCount = " + bufferCount); } writeToGZip(buffer, 0, bufferCount); bufferCount = 0; } } /** * Write the specified byte to our output stream. * * @param b The byte to be written * * @exception IOException if an input/output error occurs */ @Override public void write(int b) throws IOException { if (debug > 1) { System.out.println("write "+b+" in CompressionResponseStream "); } if (closed) throw new IOException("Cannot write to a closed output stream"); if (bufferCount >= buffer.length) { flushToGZip(); } buffer[bufferCount++] = (byte) b; } /** * Write b.length bytes from the specified byte array * to our output stream. * * @param b The byte array to be written * * @exception IOException if an input/output error occurs */ @Override public void write(byte b[]) throws IOException { write(b, 0, b.length); } /** * Write len bytes from the specified byte array, starting * at the specified offset, to our output stream. * * @param b The byte array containing the bytes to be written * @param off Zero-relative starting offset of the bytes to be written * @param len The number of bytes to be written * * @exception IOException if an input/output error occurs */ @Override public void write(byte b[], int off, int len) throws IOException { if (debug > 1) { System.out.println("write, bufferCount = " + bufferCount + " len = " + len + " off = " + off); } if (debug > 2) { System.out.print("write("); System.out.write(b, off, len); System.out.println(")"); } if (closed) throw new IOException("Cannot write to a closed output stream"); if (len == 0) return; // Can we write into buffer ? if (len <= (buffer.length - bufferCount)) { System.arraycopy(b, off, buffer, bufferCount, len); bufferCount += len; return; } // There is not enough space in buffer. Flush it ... flushToGZip(); // ... and try again. Note, that bufferCount = 0 here ! if (len <= (buffer.length - bufferCount)) { System.arraycopy(b, off, buffer, bufferCount, len); bufferCount += len; return; } // write direct to gzip writeToGZip(b, off, len); } public void writeToGZip(byte b[], int off, int len) throws IOException { if (debug > 1) { System.out.println("writeToGZip, len = " + len); } if (debug > 2) { System.out.print("writeToGZip("); System.out.write(b, off, len); System.out.println(")"); } if (gzipstream == null) { if (debug > 1) { System.out.println("new GZIPOutputStream"); } boolean alreadyCompressed = false; String contentEncoding = response.getHeader("Content-Encoding"); if (contentEncoding != null) { if (contentEncoding.contains("gzip")) { alreadyCompressed = true; if (debug > 0) { System.out.println("content is already compressed"); } } else { if (debug > 0) { System.out.println("content is not compressed yet"); } } } boolean compressibleMimeType = false; // Check for compatible MIME-TYPE if (compressionMimeTypes != null) { if (startsWithStringArray(compressionMimeTypes, response.getContentType())) { compressibleMimeType = true; if (debug > 0) { System.out.println("mime type " + response.getContentType() + " is compressible"); } } else { if (debug > 0) { System.out.println("mime type " + response.getContentType() + " is not compressible"); } } } if (response.isCommitted()) { if (debug > 1) System.out.print("Response already committed. Using original output stream"); gzipstream = output; } else if (alreadyCompressed) { if (debug > 1) System.out.print("Response already compressed. Using original output stream"); gzipstream = output; } else if (!compressibleMimeType) { if (debug > 1) System.out.print("Response mime type is not compressible. Using original output stream"); gzipstream = output; } else { response.addHeader("Content-Encoding", "gzip"); response.setContentLength(-1); // don't use any preset content-length as it will be wrong after gzipping response.setBufferSize(compressionBuffer); gzipstream = new GZIPOutputStream(output); } } gzipstream.write(b, off, len); } // -------------------------------------------------------- Package Methods /** * Has this response stream been closed? */ public boolean closed() { return (this.closed); } /** * Checks if any entry in the string array starts with the specified value * * @param sArray the StringArray * @param value string */ private boolean startsWithStringArray(String sArray[], String value) { if (value == null) return false; for (int i = 0; i < sArray.length; i++) { if (value.startsWith(sArray[i])) { return true; } } return false; } } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootroottomcat7-7.0.52/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.javatomcat7-7.0.52/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper0000644000175100017510000002001312271304167033650 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 compressionFilters; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; /** * Implementation of HttpServletResponseWrapper that works with * the CompressionServletResponseStream implementation.. * * @author Amy Roh * @author Dmitri Valdin */ public class CompressionServletResponseWrapper extends HttpServletResponseWrapper { // ----------------------------------------------------- Constructor /** * Calls the parent constructor which creates a ServletResponse adaptor * wrapping the given response object. */ public CompressionServletResponseWrapper(HttpServletResponse response) { super(response); origResponse = response; if (debug > 1) { System.out.println("CompressionServletResponseWrapper constructor gets called"); } } // ----------------------------------------------------- Instance Variables /** * Original response */ protected HttpServletResponse origResponse = null; /** * Descriptive information about this Response implementation. */ protected static final String info = "CompressionServletResponseWrapper"; /** * The ServletOutputStream that has been returned by * getOutputStream(), if any. */ protected ServletOutputStream stream = null; /** * The PrintWriter that has been returned by * getWriter(), if any. */ protected PrintWriter writer = null; /** * The threshold number to compress */ protected int compressionThreshold = 0; /** * The compression buffer size */ protected int compressionBuffer = 8192; // 8KB default /** * The mime types to compress */ protected String[] compressionMimeTypes = {"text/html", "text/xml", "text/plain"}; /** * Debug level */ protected int debug = 0; /** * keeps a copy of all headers set */ private Map headerCopies = new HashMap(); // --------------------------------------------------------- Public Methods /** * Set threshold number */ public void setCompressionThreshold(int threshold) { if (debug > 1) { System.out.println("setCompressionThreshold to " + threshold); } this.compressionThreshold = threshold; } /** * Set compression buffer */ public void setCompressionBuffer(int buffer) { if (debug > 1) { System.out.println("setCompressionBuffer to " + buffer); } this.compressionBuffer = buffer; } /** * Set compressible mime types */ public void setCompressionMimeTypes(String[] mimeTypes) { if (debug > 1) { System.out.println("setCompressionMimeTypes to " + mimeTypes); } this.compressionMimeTypes = mimeTypes; } /** * Set debug level */ public void setDebugLevel(int debug) { this.debug = debug; } /** * Create and return a ServletOutputStream to write the content * associated with this Response. * * @exception IOException if an input/output error occurs */ public ServletOutputStream createOutputStream() throws IOException { if (debug > 1) { System.out.println("createOutputStream gets called"); } CompressionResponseStream stream = new CompressionResponseStream( this, origResponse.getOutputStream()); stream.setDebugLevel(debug); stream.setCompressionThreshold(compressionThreshold); stream.setCompressionBuffer(compressionBuffer); stream.setCompressionMimeTypes(compressionMimeTypes); return stream; } /** * Finish a response. */ public void finishResponse() { try { if (writer != null) { writer.close(); } else { if (stream != null) stream.close(); } } catch (IOException e) { // Ignore } } // ------------------------------------------------ ServletResponse Methods /** * Flush the buffer and commit this response. * * @exception IOException if an input/output error occurs */ @Override public void flushBuffer() throws IOException { if (debug > 1) { System.out.println("flush buffer @ GZipServletResponseWrapper"); } ((CompressionResponseStream)stream).flush(); } /** * Return the servlet output stream associated with this Response. * * @exception IllegalStateException if getWriter has * already been called for this response * @exception IOException if an input/output error occurs */ @Override public ServletOutputStream getOutputStream() throws IOException { if (writer != null) throw new IllegalStateException("getWriter() has already been called for this response"); if (stream == null) stream = createOutputStream(); if (debug > 1) { System.out.println("stream is set to "+stream+" in getOutputStream"); } return (stream); } /** * Return the writer associated with this Response. * * @exception IllegalStateException if getOutputStream has * already been called for this response * @exception IOException if an input/output error occurs */ @Override public PrintWriter getWriter() throws IOException { if (writer != null) return (writer); if (stream != null) throw new IllegalStateException("getOutputStream() has already been called for this response"); stream = createOutputStream(); if (debug > 1) { System.out.println("stream is set to "+stream+" in getWriter"); } String charEnc = origResponse.getCharacterEncoding(); if (debug > 1) { System.out.println("character encoding is " + charEnc); } // HttpServletResponse.getCharacterEncoding() shouldn't return null // according the spec, so feel free to remove that "if" if (charEnc != null) { writer = new PrintWriter(new OutputStreamWriter(stream, charEnc)); } else { writer = new PrintWriter(stream); } return (writer); } @Override public String getHeader(String name) { return headerCopies.get(name); } @Override public void addHeader(String name, String value) { if (headerCopies.containsKey(name)) { String existingValue = headerCopies.get(name); if ((existingValue != null) && (existingValue.length() > 0)) headerCopies.put(name, existingValue + "," + value); else headerCopies.put(name, value); } else headerCopies.put(name, value); super.addHeader(name, value); } @Override public void setHeader(String name, String value) { headerCopies.put(name, value); super.setHeader(name, value); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java0000644000175100017510000000444312271304167033527 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 compressionFilters; import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Very Simple test servlet to test compression filter * @author Amy Roh */ public class CompressionFilterTestServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletOutputStream out = response.getOutputStream(); response.setContentType("text/plain"); Enumeration e = request.getHeaders("Accept-Encoding"); while (e.hasMoreElements()) { String name = e.nextElement(); out.println(name); if (name.indexOf("gzip") != -1) { out.println("gzip supported -- able to compress"); } else { out.println("gzip not supported"); } } out.println("Compression Filter Test Servlet"); out.println("Minimum content length for compression is 128 bytes"); out.println("********** 32 bytes **********"); out.println("********** 32 bytes **********"); out.println("********** 32 bytes **********"); out.println("********** 32 bytes **********"); out.close(); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/CookieExample.java0000644000175100017510000001103512271304167024501 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.io.IOException; import java.io.PrintWriter; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import util.HTMLFilter; /** * Example servlet showing request headers * * @author James Duncan Davidson */ public class CookieExample extends HttpServlet { private static final long serialVersionUID = 1L; private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings"); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String cookieName = request.getParameter("cookiename"); String cookieValue = request.getParameter("cookievalue"); Cookie aCookie = null; if (cookieName != null && cookieValue != null) { aCookie = new Cookie(cookieName, cookieValue); response.addCookie(aCookie); } response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(""); String title = RB.getString("cookies.title"); out.println("" + title + ""); out.println(""); out.println(""); // relative links // XXX // making these absolute till we work out the // addition of a PathInfo issue out.println(""); out.println("\"view"); out.println(""); out.println("\"return\""); out.println("

    " + title + "

    "); Cookie[] cookies = request.getCookies(); if ((cookies != null) && (cookies.length > 0)) { out.println(RB.getString("cookies.cookies") + "
    "); for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; out.print("Cookie Name: " + HTMLFilter.filter(cookie.getName()) + "
    "); out.println(" Cookie Value: " + HTMLFilter.filter(cookie.getValue()) + "

    "); } } else { out.println(RB.getString("cookies.no-cookies")); } if (aCookie != null) { out.println("

    "); out.println(RB.getString("cookies.set") + "
    "); out.print(RB.getString("cookies.name") + " " + HTMLFilter.filter(cookieName) + "
    "); out.print(RB.getString("cookies.value") + " " + HTMLFilter.filter(cookieValue)); } out.println("

    "); out.println(RB.getString("cookies.make-cookie") + "
    "); out.print("

    "); out.print(RB.getString("cookies.name") + " "); out.println("
    "); out.print(RB.getString("cookies.value") + " "); out.println("
    "); out.println("
    "); out.println(""); out.println(""); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/LocalStrings.properties0000644000175100017510000000375312271304167025643 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # Default localized resources for example servlets # This locale is en_US helloworld.title=Hello World! requestinfo.title=Request Information Example requestinfo.label.method=Method: requestinfo.label.requesturi=Request URI: requestinfo.label.protocol=Protocol: requestinfo.label.pathinfo=Path Info: requestinfo.label.remoteaddr=Remote Address: requestheader.title=Request Header Example requestparams.title=Request Parameters Example requestparams.params-in-req=Parameters in this request: requestparams.no-params=No Parameters, Please enter some requestparams.firstname=First Name: requestparams.lastname=Last Name: cookies.title=Cookies Example cookies.cookies=Your browser is sending the following cookies: cookies.no-cookies=Your browser isn't sending any cookies cookies.make-cookie=Create a cookie to send to your browser cookies.name=Name: cookies.value=Value: cookies.set=You just sent the following cookie to your browser: sessions.title=Sessions Example sessions.id=Session ID: sessions.created=Created: sessions.lastaccessed=Last Accessed: sessions.data=The following data is in your session: sessions.adddata=Add data to your session sessions.dataname=Name of Session Attribute: sessions.datavalue=Value of Session Attribute: tomcat7-7.0.52/webapps/examples/WEB-INF/classes/LocalStrings_pt.properties0000644000175100017510000000410412271304167026335 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # Default localized resources for example servlets # This locale is pt_PT helloworld.title=Ola Mundo! requestinfo.title=Exemplo da Informacao do Pedido requestinfo.label.method=Metodo: requestinfo.label.requesturi=URI do Pedido: requestinfo.label.protocol=Protocolo: requestinfo.label.pathinfo=Informacao do Caminho: requestinfo.label.remoteaddr=Endereco Remoto: requestheader.title=Exemplo da Cebeceira do Pedido requestparams.title=Examplo de Parametros do Pedido requestparams.params-in-req=Parametros neste pedido: requestparams.no-params=Sem Parametros, Por favor entre alguns requestparams.firstname=Primeiro Nome: requestparams.lastname=Apelido: cookies.title=CExamplo de Cookies cookies.cookies=O se browser esta a enviar os seguintes cookies: cookies.no-cookies=O seu browser nao esta a enviar nenhuns cookies cookies.make-cookie=Crie um cookie para enviar para o seu browser cookies.name=Nome: cookies.value=Valor: cookies.set=Acabou de enviar o seguinte cookie para o seu browser: sessions.title=Examplo de sessoes sessions.id=Identificador da Sessao: sessions.created=Criada: sessions.lastaccessed=Ultima vez acedida: sessions.data=Os seguintes dados fazem parte da sua sessao: sessions.adddata=Adicione data a sua sessao sessions.dataname=Nome do atributo da sessao: sessions.datavalue=Valor do atributo da Sessao: tomcat7-7.0.52/webapps/examples/WEB-INF/classes/sessions/0000755000175100017510000000000012301126372022751 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/sessions/DummyCart.java0000644000175100017510000000342512271304167025533 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 sessions; import java.util.Vector; public class DummyCart { Vector v = new Vector(); String submit = null; String item = null; private void addItem(String name) { v.addElement(name); } private void removeItem(String name) { v.removeElement(name); } public void setItem(String name) { item = name; } public void setSubmit(String s) { submit = s; } public String[] getItems() { String[] s = new String[v.size()]; v.copyInto(s); return s; } public void processRequest() { // null value for submit - user hit enter instead of clicking on // "add" or "remove" if (submit == null || submit.equals("add")) addItem(item); else if (submit.equals("remove")) removeItem(item); // reset at the end of the request reset(); } // reset private void reset() { submit = null; item = null; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/validators/0000755000175100017510000000000012301126372023253 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/validators/DebugValidator.java0000644000175100017510000000542512271304167027026 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 validators; import java.io.IOException; import java.io.InputStream; import javax.servlet.jsp.tagext.PageData; import javax.servlet.jsp.tagext.TagLibraryValidator; import javax.servlet.jsp.tagext.ValidationMessage; /** * Example tag library validator that simply dumps the XML version of each * page to standard output (which will typically be sent to the file * $CATALINA_HOME/logs/catalina.out). To utilize it, simply * include a taglib directive for this tag library at the top * of your JSP page. * * @author Craig McClanahan */ public class DebugValidator extends TagLibraryValidator { // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods /** * Validate a JSP page. This will get invoked once per directive in the * JSP page. This method will return null if the page is * valid; otherwise the method should return an array of * ValidationMessage objects. An array of length zero is * also interpreted as no errors. * * @param prefix The value of the prefix argument in this directive * @param uri The value of the URI argument in this directive * @param page The page data for this page */ @Override public ValidationMessage[] validate(String prefix, String uri, PageData page) { System.out.println("---------- Prefix=" + prefix + " URI=" + uri + "----------"); InputStream is = page.getInputStream(); while (true) { try { int ch = is.read(); if (ch < 0) break; System.out.print((char) ch); } catch (IOException e) { break; } } System.out.println(); System.out.println("-----------------------------------------------"); return (null); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/util/0000755000175100017510000000000012301126372022060 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/util/HTMLFilter.java0000644000175100017510000000404012271304167024641 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 util; /** * HTML filter utility. * * @author Craig R. McClanahan * @author Tim Tye */ public final class HTMLFilter { /** * Filter the specified message string for characters that are sensitive * in HTML. This avoids potential attacks caused by including JavaScript * codes in the request URL that is often reported in error messages. * * @param message The message string to be filtered */ public static String filter(String message) { if (message == null) return (null); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/0000755000175100017510000000000012301126372021761 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/0000755000175100017510000000000012301126372023577 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/ValuesBean.java0000644000175100017510000000265411414656643026513 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 jsp2.examples; /** * Accept and display a value. */ public class ValuesBean { private String string; private double doubleValue; private long longValue; public String getStringValue() { return this.string; } public void setStringValue(String string) { this.string = string; } public double getDoubleValue() { return doubleValue; } public void setDoubleValue(double doubleValue) { this.doubleValue = doubleValue; } public long getLongValue() { return longValue; } public void setLongValue(long longValue) { this.longValue = longValue; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/el/0000755000175100017510000000000012301126372024177 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.java0000644000175100017510000000275512271304167027031 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 jsp2.examples.el; import java.util.Locale; /** * Defines the functions for the jsp2 example tag library. * *

    Each function is defined as a static method.

    */ public class Functions { public static String reverse( String text ) { return new StringBuilder( text ).reverse().toString(); } public static int numVowels( String text ) { String vowels = "aeiouAEIOU"; int result = 0; for( int i = 0; i < text.length(); i++ ) { if( vowels.indexOf( text.charAt( i ) ) != -1 ) { result++; } } return result; } public static String caps( String text ) { return text.toUpperCase(Locale.ENGLISH); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/0000755000175100017510000000000012301126372025564 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java0000644000175100017510000000225712271304167032324 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 jsp2.examples.simpletag; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.SimpleTagSupport; /** * SimpleTag handler that prints "Hello, world!" */ public class HelloWorldSimpleTag extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { getJspContext().getOut().write( "Hello, world!" ); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java0000644000175100017510000000304112271304167031136 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 jsp2.examples.simpletag; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.SimpleTagSupport; /** * Displays a tile as a single cell in a table. */ public class TileSimpleTag extends SimpleTagSupport { private String color; private String label; @Override public void doTag() throws JspException, IOException { getJspContext().getOut().write( "
    " + this.label + "
    " ); } public void setColor( String color ) { this.color = color; } public void setLabel( String label ) { this.label = label; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java0000644000175100017510000000353512271304167032024 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 jsp2.examples.simpletag; import java.io.IOException; import java.util.ArrayList; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.DynamicAttributes; import javax.servlet.jsp.tagext.SimpleTagSupport; /** * SimpleTag handler that echoes all its attributes */ public class EchoAttributesTag extends SimpleTagSupport implements DynamicAttributes { private ArrayList keys = new ArrayList(); private ArrayList values = new ArrayList(); @Override public void doTag() throws JspException, IOException { JspWriter out = getJspContext().getOut(); for( int i = 0; i < keys.size(); i++ ) { String key = keys.get( i ); Object value = values.get( i ); out.println( "
  • " + key + " = " + value + "
  • " ); } } @Override public void setDynamicAttribute( String uri, String localName, Object value ) throws JspException { keys.add( localName ); values.add( value ); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java0000644000175100017510000000541712271304167031646 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 jsp2.examples.simpletag; import java.io.IOException; import java.util.Random; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; /** * SimpleTag handler that accepts takes three attributes of type * JspFragment and invokes then in a random order. */ public class ShuffleSimpleTag extends SimpleTagSupport { // No need for this to use SecureRandom private static Random random = new Random(); private JspFragment fragment1; private JspFragment fragment2; private JspFragment fragment3; @Override public void doTag() throws JspException, IOException { switch(random.nextInt(6)) { case 0: fragment1.invoke( null ); fragment2.invoke( null ); fragment3.invoke( null ); break; case 1: fragment1.invoke( null ); fragment3.invoke( null ); fragment2.invoke( null ); break; case 2: fragment2.invoke( null ); fragment1.invoke( null ); fragment3.invoke( null ); break; case 3: fragment2.invoke( null ); fragment3.invoke( null ); fragment1.invoke( null ); break; case 4: fragment3.invoke( null ); fragment1.invoke( null ); fragment2.invoke( null ); break; case 5: fragment3.invoke( null ); fragment2.invoke( null ); fragment1.invoke( null ); break; } } public void setFragment1( JspFragment fragment1 ) { this.fragment1 = fragment1; } public void setFragment2( JspFragment fragment2 ) { this.fragment2 = fragment2; } public void setFragment3( JspFragment fragment3 ) { this.fragment3 = fragment3; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java0000644000175100017510000000261712271304167031471 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 jsp2.examples.simpletag; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.SimpleTagSupport; /** * SimpleTag handler that accepts a num attribute and * invokes its body 'num' times. */ public class RepeatSimpleTag extends SimpleTagSupport { private int num; @Override public void doTag() throws JspException, IOException { for (int i=0; i table; JspCalendar JspCal; Entries entries; String date; String name = null; String email = null; boolean processError = false; public TableBean() { this.table = new Hashtable(10); this.JspCal = new JspCalendar(); this.date = JspCal.getCurrentDate(); } public void setName(String nm) { this.name = nm; } public String getName() { return this.name; } public void setEmail(String mail) { this.email = mail; } public String getEmail() { return this.email; } public String getDate() { return this.date; } public Entries getEntries() { return this.entries; } public void processRequest(HttpServletRequest request) { // Get the name and e-mail. this.processError = false; if (name == null || name.equals("")) setName(request.getParameter("name")); if (email == null || email.equals("")) setEmail(request.getParameter("email")); if (name == null || email == null || name.equals("") || email.equals("")) { this.processError = true; return; } // Get the date. String dateR = request.getParameter("date"); if (dateR == null) date = JspCal.getCurrentDate(); else if (dateR.equalsIgnoreCase("next")) date = JspCal.getNextDate(); else if (dateR.equalsIgnoreCase("prev")) date = JspCal.getPrevDate(); entries = table.get(date); if (entries == null) { entries = new Entries(); table.put(date, entries); } // If time is provided add the event. String time = request.getParameter("time"); if (time != null) entries.processRequest(request, time); } public boolean getProcessError() { return this.processError; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/cal/Entries.java0000644000175100017510000000361012271304167024124 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 cal; import java.util.Hashtable; import javax.servlet.http.HttpServletRequest; public class Entries { private Hashtable entries; private static final String[] time = { "8am", "9am", "10am", "11am", "12pm", "1pm", "2pm", "3pm", "4pm", "5pm", "6pm", "7pm", "8pm" }; public static final int rows = 12; public Entries() { entries = new Hashtable(rows); for (int i = 0; i < rows; i++) { entries.put(time[i], new Entry(time[i])); } } public int getRows() { return rows; } public Entry getEntry(int index) { return this.entries.get(time[index]); } public int getIndex(String tm) { for (int i = 0; i < rows; i++) if (tm.equals(time[i])) return i; return -1; } public void processRequest(HttpServletRequest request, String tm) { int index = getIndex(tm); if (index >= 0) { String descr = request.getParameter("description"); entries.get(time[index]).setDescription(descr); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/cal/JspCalendar.java0000644000175100017510000000756212271304167024713 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 cal; import java.util.Calendar; import java.util.Date; public class JspCalendar { Calendar calendar = null; public JspCalendar() { calendar = Calendar.getInstance(); Date trialTime = new Date(); calendar.setTime(trialTime); } public int getYear() { return calendar.get(Calendar.YEAR); } public String getMonth() { int m = getMonthInt(); String[] months = new String [] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; if (m > 12) return "Unknown to Man"; return months[m - 1]; } public String getDay() { int x = getDayOfWeek(); String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; if (x > 7) return "Unknown to Man"; return days[x - 1]; } public int getMonthInt() { return 1 + calendar.get(Calendar.MONTH); } public String getDate() { return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear(); } public String getCurrentDate() { Date dt = new Date (); calendar.setTime (dt); return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear(); } public String getNextDate() { calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() + 1); return getDate (); } public String getPrevDate() { calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() - 1); return getDate (); } public String getTime() { return getHour() + ":" + getMinute() + ":" + getSecond(); } public int getDayOfMonth() { return calendar.get(Calendar.DAY_OF_MONTH); } public int getDayOfYear() { return calendar.get(Calendar.DAY_OF_YEAR); } public int getWeekOfYear() { return calendar.get(Calendar.WEEK_OF_YEAR); } public int getWeekOfMonth() { return calendar.get(Calendar.WEEK_OF_MONTH); } public int getDayOfWeek() { return calendar.get(Calendar.DAY_OF_WEEK); } public int getHour() { return calendar.get(Calendar.HOUR_OF_DAY); } public int getMinute() { return calendar.get(Calendar.MINUTE); } public int getSecond() { return calendar.get(Calendar.SECOND); } public int getEra() { return calendar.get(Calendar.ERA); } public String getUSTimeZone() { String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific", "Mountain", "Central", "Eastern"}; return zones[10 + getZoneOffset()]; } public int getZoneOffset() { return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000); } public int getDSTOffset() { return calendar.get(Calendar.DST_OFFSET)/(60*60*1000); } public int getAMPM() { return calendar.get(Calendar.AM_PM); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/cal/Entry.java0000644000175100017510000000261212271304167023615 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 cal; public class Entry { String hour; String description; public Entry(String hour) { this.hour = hour; this.description = ""; } public String getHour() { return this.hour; } public String getColor() { if (description.equals("")) { return "lightblue"; } return "red"; } public String getDescription() { if (description.equals("")) { return "None"; } return this.description; } public void setDescription(String descr) { description = descr; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/RequestParamExample.java0000644000175100017510000000760112271304167025705 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.io.IOException; import java.io.PrintWriter; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import util.HTMLFilter; /** * Example servlet showing request headers * * @author James Duncan Davidson */ public class RequestParamExample extends HttpServlet { private static final long serialVersionUID = 1L; private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings"); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(""); String title = RB.getString("requestparams.title"); out.println("" + title + ""); out.println(""); out.println(""); // img stuff not req'd for source code html showing // all links relative // XXX // making these absolute till we work out the // addition of a PathInfo issue out.println(""); out.println("\"view"); out.println(""); out.println("\"return\""); out.println("

    " + title + "

    "); String firstName = request.getParameter("firstname"); String lastName = request.getParameter("lastname"); out.println(RB.getString("requestparams.params-in-req") + "
    "); if (firstName != null || lastName != null) { out.println(RB.getString("requestparams.firstname")); out.println(" = " + HTMLFilter.filter(firstName) + "
    "); out.println(RB.getString("requestparams.lastname")); out.println(" = " + HTMLFilter.filter(lastName)); } else { out.println(RB.getString("requestparams.no-params")); } out.println("

    "); out.print("

    "); out.println(RB.getString("requestparams.firstname")); out.println(""); out.println("
    "); out.println(RB.getString("requestparams.lastname")); out.println(""); out.println("
    "); out.println(""); out.println("
    "); out.println(""); out.println(""); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/SessionExample.java0000644000175100017510000001233412271304167024716 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.Enumeration; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import util.HTMLFilter; /** * Example servlet showing request headers * * @author James Duncan Davidson */ public class SessionExample extends HttpServlet { private static final long serialVersionUID = 1L; private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings"); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(""); String title = RB.getString("sessions.title"); out.println("" + title + ""); out.println(""); out.println(""); // img stuff not req'd for source code html showing // relative links everywhere! // XXX // making these absolute till we work out the // addition of a PathInfo issue out.println(""); out.println("\"view"); out.println(""); out.println("\"return\""); out.println("

    " + title + "

    "); HttpSession session = request.getSession(true); out.println(RB.getString("sessions.id") + " " + session.getId()); out.println("
    "); out.println(RB.getString("sessions.created") + " "); out.println(new Date(session.getCreationTime()) + "
    "); out.println(RB.getString("sessions.lastaccessed") + " "); out.println(new Date(session.getLastAccessedTime())); String dataName = request.getParameter("dataname"); String dataValue = request.getParameter("datavalue"); if (dataName != null && dataValue != null) { session.setAttribute(dataName, dataValue); } out.println("

    "); out.println(RB.getString("sessions.data") + "
    "); Enumeration names = session.getAttributeNames(); while (names.hasMoreElements()) { String name = names.nextElement(); String value = session.getAttribute(name).toString(); out.println(HTMLFilter.filter(name) + " = " + HTMLFilter.filter(value) + "
    "); } out.println("

    "); out.print("

    "); out.println(RB.getString("sessions.dataname")); out.println(""); out.println("
    "); out.println(RB.getString("sessions.datavalue")); out.println(""); out.println("
    "); out.println(""); out.println("
    "); out.println("

    GET based form:
    "); out.print("

    "); out.println(RB.getString("sessions.dataname")); out.println(""); out.println("
    "); out.println(RB.getString("sessions.datavalue")); out.println(""); out.println("
    "); out.println(""); out.println("
    "); out.print("

    URL encoded "); out.println(""); out.println(""); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/examples/0000755000175100017510000000000012301126372022721 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/examples/FooTag.java0000644000175100017510000000440012271304167024747 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 examples; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; /** * Example1: the simplest tag * Collect attributes and call into some actions * * */ public class FooTag extends ExampleTagBase { private static final long serialVersionUID = 1L; private String atts[] = new String[3]; int i = 0; private final void setAtt(int index, String value) { atts[index] = value; } public void setAtt1(String value) { setAtt(0, value); } public void setAtt2(String value) { setAtt(1, value); } public void setAtt3(String value) { setAtt(2, value); } /** * Process start tag * * @return EVAL_BODY_INCLUDE */ @Override public int doStartTag() throws JspException { i = 0; return EVAL_BODY_BUFFERED; } @Override public void doInitBody() throws JspException { pageContext.setAttribute("member", atts[i]); i++; } @Override public int doAfterBody() throws JspException { try { if (i == 3) { bodyOut.writeOut(bodyOut.getEnclosingWriter()); return SKIP_BODY; } pageContext.setAttribute("member", atts[i]); i++; return EVAL_BODY_BUFFERED; } catch (IOException ex) { throw new JspTagException(ex.toString()); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/examples/ValuesTag.java0000644000175100017510000000501311426360707025467 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 examples; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; /** * Accept and display a value. */ public class ValuesTag extends TagSupport { private static final long serialVersionUID = 1L; // Using "-1" as the default value, // in the assumption that it won't be used as the value. // Cannot use null here, because null is an important case // that should be present in the tests. private Object objectValue = "-1"; private String stringValue = "-1"; private long longValue = -1; private double doubleValue = -1; public void setObject(Object objectValue) { this.objectValue = objectValue; } public void setString(String stringValue) { this.stringValue = stringValue; } public void setLong(long longValue) { this.longValue = longValue; } public void setDouble(double doubleValue) { this.doubleValue = doubleValue; } @Override public int doEndTag() throws JspException { JspWriter out = pageContext.getOut(); try { if (!"-1".equals(objectValue)) { out.print(objectValue); } else if (!"-1".equals(stringValue)) { out.print(stringValue); } else if (longValue != -1) { out.print(longValue); } else if (doubleValue != -1) { out.print(doubleValue); } else { out.print("-1"); } } catch (IOException ex) { throw new JspTagException("IOException: " + ex.toString(), ex); } return super.doEndTag(); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.java0000644000175100017510000000244412271304167026575 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 examples; import javax.servlet.jsp.tagext.TagData; import javax.servlet.jsp.tagext.TagExtraInfo; import javax.servlet.jsp.tagext.VariableInfo; public class FooTagExtraInfo extends TagExtraInfo { @Override public VariableInfo[] getVariableInfo(TagData data) { return new VariableInfo[] { new VariableInfo("member", "String", true, VariableInfo.NESTED) }; } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.java0000644000175100017510000000377212271304167026425 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 examples; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.Tag; public abstract class ExampleTagBase extends BodyTagSupport { private static final long serialVersionUID = 1L; @Override public void setParent(Tag parent) { this.parent = parent; } @Override public void setBodyContent(BodyContent bodyOut) { this.bodyOut = bodyOut; } @Override public Tag getParent() { return this.parent; } @Override public int doStartTag() throws JspException { return SKIP_BODY; } @Override public int doEndTag() throws JspException { return EVAL_PAGE; } @Override public void doInitBody() throws JspException { // Default implementations for BodyTag methods as well // just in case a tag decides to implement BodyTag. } @Override public int doAfterBody() throws JspException { return SKIP_BODY; } @Override public void release() { bodyOut = null; pageContext = null; parent = null; } protected BodyContent bodyOut; protected Tag parent; } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/examples/LogTag.java0000644000175100017510000000347512271304167024760 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 examples; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; /** * Log the contents of the body. Could be used to handle errors etc. */ public class LogTag extends ExampleTagBase { private static final long serialVersionUID = 1L; boolean toBrowser = false; public void setToBrowser(String value) { if (value == null) toBrowser = false; else if (value.equalsIgnoreCase("true")) toBrowser = true; else toBrowser = false; } @Override public int doStartTag() throws JspException { return EVAL_BODY_BUFFERED; } @Override public int doAfterBody() throws JspException { try { String s = bodyOut.getString(); System.err.println(s); if (toBrowser) bodyOut.writeOut(bodyOut.getEnclosingWriter()); return SKIP_BODY; } catch (IOException ex) { throw new JspTagException(ex.toString()); } } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/examples/ShowSource.java0000644000175100017510000000453312271304167025700 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 examples; import java.io.IOException; import java.io.InputStream; import java.util.Locale; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.TagSupport; /** * Display the sources of the JSP file. */ public class ShowSource extends TagSupport { private static final long serialVersionUID = 1L; String jspFile; public void setJspFile(String jspFile) { this.jspFile = jspFile; } @Override public int doEndTag() throws JspException { if ((jspFile.indexOf( ".." ) >= 0) || (jspFile.toUpperCase(Locale.ENGLISH).indexOf("/WEB-INF/") != 0) || (jspFile.toUpperCase(Locale.ENGLISH).indexOf("/META-INF/") != 0)) throw new JspTagException("Invalid JSP file " + jspFile); InputStream in = pageContext.getServletContext().getResourceAsStream(jspFile); if (in == null) throw new JspTagException("Unable to find JSP file: "+jspFile); JspWriter out = pageContext.getOut(); try { out.println(""); out.println("

    ");
                for(int ch = in.read(); ch != -1; ch = in.read())
                    if (ch == '<')
                        out.print("<");
                    else
                        out.print((char) ch);
                out.println("
    "); out.println(""); } catch (IOException ex) { throw new JspTagException("IOException: "+ex.toString()); } return super.doEndTag(); } } tomcat7-7.0.52/webapps/examples/WEB-INF/classes/num/0000755000175100017510000000000012301126373021703 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/classes/num/NumberGuessBean.java0000644000175100017510000000462412271304167025606 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* * Originally written by Jason Hunter, http://www.servlets.com. */ package num; import java.io.Serializable; import java.util.Random; public class NumberGuessBean implements Serializable { private static final long serialVersionUID = 1L; private int answer; private String hint; private int numGuesses; private boolean success; private Random random = new Random(); public NumberGuessBean() { reset(); } public int getAnswer() { return answer; } public void setAnswer(int answer) { this.answer = answer; } public String getHint() { return "" + hint; } public void setHint(String hint) { this.hint = hint; } public void setNumGuesses(int numGuesses) { this.numGuesses = numGuesses; } public int getNumGuesses() { return numGuesses; } public boolean getSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public void setGuess(String guess) { numGuesses++; int g; try { g = Integer.parseInt(guess); } catch (NumberFormatException e) { g = -1; } if (g == answer) { success = true; } else if (g == -1) { hint = "a number next time"; } else if (g < answer) { hint = "higher"; } else if (g > answer) { hint = "lower"; } } public void reset() { answer = Math.abs(random.nextInt() % 100) + 1; success = false; numGuesses = 0; } } tomcat7-7.0.52/webapps/examples/WEB-INF/jsp2/0000755000175100017510000000000012301126373020325 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/WEB-INF/jsp2/jsp2-example-taglib.tld0000644000175100017510000001142312271304167024607 0ustar locutuslocutus A tag library exercising SimpleTag handlers. 1.0 SimpleTagLibrary http://tomcat.apache.org/jsp2-example-taglib Outputs Hello, World helloWorld jsp2.examples.simpletag.HelloWorldSimpleTag empty Repeats the body of the tag 'num' times repeat jsp2.examples.simpletag.RepeatSimpleTag scriptless Current invocation count (1 to num) count num true true Populates the page context with a BookBean findBook jsp2.examples.simpletag.FindBookSimpleTag empty var true true Takes 3 fragments and invokes them in a random order shuffle jsp2.examples.simpletag.ShuffleSimpleTag empty fragment1 true true fragment2 true true fragment3 true true Outputs a colored tile tile jsp2.examples.simpletag.TileSimpleTag empty color true label true Tag that echoes all its attributes and body content echoAttributes jsp2.examples.simpletag.EchoAttributesTag empty true Reverses the characters in the given String reverse jsp2.examples.el.Functions java.lang.String reverse( java.lang.String ) Counts the number of vowels (a,e,i,o,u) in the given String countVowels jsp2.examples.el.Functions java.lang.String numVowels( java.lang.String ) Converts the string to all caps caps jsp2.examples.el.Functions java.lang.String caps( java.lang.String ) tomcat7-7.0.52/webapps/examples/index.html0000644000175100017510000000234512226014050020413 0ustar locutuslocutus Apache Tomcat Examples

    Apache Tomcat Examples

    tomcat7-7.0.52/webapps/examples/jsp/0000755000175100017510000000000012301126372017213 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/chat/0000755000175100017510000000000012301126372020132 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/chat/login.jsp0000644000175100017510000000231212271304167021764 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page contentType="text/html; charset=UTF-8" %> JSP Chat
    Nickname:
    tomcat7-7.0.52/webapps/examples/jsp/chat/post.jsp0000644000175100017510000000404312271304167021644 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page contentType="text/html; charset=UTF-8" %> JSP Chat
    Message:

    <% String serverName = request.getServerName(); if ("localhost".equals(serverName)) { serverName = "127.0.0.1"; } else if ("127.0.0.1".equals(serverName)) { serverName = "localhost"; } String chatUrl = request.getScheme() + "://" + serverName + ":" + request.getServerPort() + request.getContextPath() + request.getServletPath(); // strip "post.jsp" from the address chatUrl = chatUrl.substring(0, chatUrl.lastIndexOf("/") + 1); %> Click to open a new chat window Note: To avoid hitting the limit on the count of simultaneous connections to the same host, imposed by the HTTP specification, the second chat window should be opened using a different URL, e.g. with an IP address instead of the host name. tomcat7-7.0.52/webapps/examples/jsp/chat/index.jsp0000644000175100017510000000237412271304167021773 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page contentType="text/html; charset=UTF-8" %> <% if (session.getAttribute("nickname") == null) { response.sendRedirect("login.jsp"); return; } %> JSP Chat tomcat7-7.0.52/webapps/examples/jsp/forward/0000755000175100017510000000000012301126372020657 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/forward/fwd.html0000644000175100017510000000241512271304167022335 0ustar locutuslocutus Untitled Document

    Source Code for Forward Example

    tomcat7-7.0.52/webapps/examples/jsp/forward/one.jsp0000644000175100017510000000154512271304167022171 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> VM Memory usage < 50%. tomcat7-7.0.52/webapps/examples/jsp/forward/two.html0000644000175100017510000000154412271304167022370 0ustar locutuslocutus VM Memory usage > 50%. tomcat7-7.0.52/webapps/examples/jsp/forward/forward.jsp0000644000175100017510000000205612271304167023052 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <% double freeMem = Runtime.getRuntime().freeMemory(); double totlMem = Runtime.getRuntime().totalMemory(); double percent = freeMem/totlMem; if (percent < 0.5) { %> <% } else { %> <% } %> tomcat7-7.0.52/webapps/examples/jsp/images/0000755000175100017510000000000012301126372020460 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/images/return.gif0000644000175100017510000000231710457676032022506 0ustar locutuslocutusGIF89a!!!)))999JJJRRRZZZccckkksss{{{JBB911)!!199!!!ZcJR199B)1s)1!){sZR)1)!JZ!!BRZscRkccRJ19!k9)1)!)BR)!!!{9Js{Rkk!JZ1sJB1))!)!s!Rk!!)9skRZR9J!!1B{B{1c{!)BZ)9Z{!1!1J9BJsksZRZ!!!,@ HP x 13RhN T9zTT)@aR'1@[0 a7PrQJBJRQTdT`iL@4@4~Qȇ=p# LNhiC $ 1Z臖*ZC<|q|,% /^@h%S1@!44%!\Qʄ5$`@*ea]$r!n8xndY#)V(P <`CD&(0"2TQbQG4C!,$TPy]C-$ E<T  )W`2rjԁFT0`G! ;̑G)TU)aC 5a}EIuG(;tomcat7-7.0.52/webapps/examples/jsp/images/code.gif0000644000175100017510000000044410457676032022100 0ustar locutuslocutusGIF89afff3f33ff3f3333f333ffff33f3f33333!,@ d)&Sb@"H#O: `)Q.4G$Upm#\()bRrPMI\BZ];y,DbD  avG Ar41 &.hI P `A.{ 8=~9xaUyC!;tomcat7-7.0.52/webapps/examples/jsp/images/read.gif0000644000175100017510000000214510457676032022101 0ustar locutuslocutusGIF89afff:::///NNNlllNNOMMM,,,111 洶g^auuu9!f=zC,C,%{|榧痗].d2e3g5U.Z3 `YV﫫kkkt<&g4g3d6f7b4x@*\>3~{CFF-+2K,g3f6g8g5h;_;t@(6H7 V.f2h6f7d7g2d6[6d:(L) b5g2g4O)sUXB% h9h3h5l$ =.>i8h3i6pCcK>Y.f4d3i4f2J'`3rA,x@%f2g5h0h;E h5rA*S-e0g5e8g,hAJ#i1c7"_4d5f8g2a5O(f7U6%  g9e1h5W1b1!g99!/f5f-f5L/u9!_37f3d3f3b*x?'AM4$o="o<$y=!z>!}A$D(H-L/O6T4U/!Q.w:(454><;865-**  2!+GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG!Created with The GIMP! , H<(`‚ 8p \`` D@p .`Ƞa~B%L@BŊ,Zx#4jظc`:v BXHz$QI'OB"*U%[t /`ˆ7L͜AFͿ5l 8x3N;wgW(?AlDciď E4ҿJ.MS&M8rP|B%TK*ڱTV d+Xd͢U-\ ū_#0;tomcat7-7.0.52/webapps/examples/jsp/images/execute.gif0000644000175100017510000000233210457676032022626 0ustar locutuslocutusGIF89a!!!)))111999BBBJJJRRRZZZccckkksssνƽZRR{kkB991)))!!J99!9))1!!{scRJJ91{kc9)!scZ1!{cRZB1{sB91cRBB1!!R9!){skskc{kZ91)scR1)!ZJ9{cJcJ1{Z9ZB)1!kBkcZJB9)!kJ!{ckZBkJZB!R9cR9c1B1sR!Z9{JkRB)sZ1kR)R9J1{kB9){c9!{scZRB{Z91!kZ9{JcR1ZJ)RB!sZ)J9c!{kcRJB11))!k1kRsc9kZ1cR)RB{sZskRZR991kJB!ssk{ccZ11)ccR))!11!!!))!!ƌRRZJJR99B))1!!)!))9!!191B!){s{cZc9191)1)!)!!!,@+@0!B@aTÇ 9b#ItTPT PFʜR0 LTrgQ(Uj95԰ eʣ)h Untitled Document

    Source Code for Error Example

    tomcat7-7.0.52/webapps/examples/jsp/error/errorpge.jsp0000644000175100017510000000170512271304167022720 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ page isErrorPage="true" %>

    The exception <%= exception.getMessage() %> tells me you made a wrong choice. tomcat7-7.0.52/webapps/examples/jsp/error/error.html0000644000175100017510000000240312271304167022370 0ustar locutuslocutus

    This example uses errorpage directive


    Select my favourite car.


    tomcat7-7.0.52/webapps/examples/jsp/error/err.jsp0000644000175100017510000000260412271304167021662 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ page errorPage="errorpge.jsp" %> <% String name = null; if (request.getParameter("name") == null) { %> <%@ include file="error.html" %> <% } else { foo.setName(request.getParameter("name")); if (foo.getName().equalsIgnoreCase("integra")) name = "acura"; if (name.equalsIgnoreCase("acura")) { %>

    Yes!!! Acura is my favorite car. <% } } %> tomcat7-7.0.52/webapps/examples/jsp/colors/0000755000175100017510000000000012301126372020514 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/colors/ColorGameBean.html0000644000175100017510000000460212271304167024050 0ustar locutuslocutus colors.ColorGameBean Bean Properties

    colors.ColorGameBean Bean Properties


    public class ColorGameBean
    extends Object


    Properties Summary
    String ColorGameBean:color2
    Single
    String ColorGameBean:color1
    Single
    int ColorGameBean:attempts
    Single
    boolean ColorGameBean:hint
    Single
    boolean ColorGameBean:success
    Single
    boolean ColorGameBean:hintTaken
    Single


    tomcat7-7.0.52/webapps/examples/jsp/colors/colrs.jsp0000644000175100017510000000322512271304167022364 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <% cb.processRequest(); %> > >

    <% if (cb.getHint()==true) { %>

    Hint #1: Vampires prey at night!

    Hint #2: Nancy without the n. <% } %> <% if (cb.getSuccess()==true) { %>

    CONGRATULATIONS!! <% if (cb.getHintTaken()==true) { %>

    ( although I know you cheated and peeked into the hints) <% } %> <% } %>

    Total attempts so far: <%= cb.getAttempts() %>

    Color #1:
    Color #2:

    tomcat7-7.0.52/webapps/examples/jsp/colors/colors.html0000644000175100017510000000277012271304167022717 0ustar locutuslocutus
    This web page is an example using JSP and BEANs.

    Guess my favorite two colors

    If you fail to guess both of them - you get yellow on red.

    If you guess one of them right, either your foreground or your background will change to the color that was guessed right.

    Guess them both right and your browser foreground/background will change to my two favorite colors to display this page.


    Color #1:
    Color #2:

    tomcat7-7.0.52/webapps/examples/jsp/colors/clr.html0000644000175100017510000000256612271304167022201 0ustar locutuslocutus Untitled Document

    Source Code for Color Example

    Property Sheet for ColorGameBean

    tomcat7-7.0.52/webapps/examples/jsp/plugin/0000755000175100017510000000000012301126372020511 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/plugin/plugin.jsp0000644000175100017510000000233412271304167022535 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Plugin example

    Current time is :

    Plugin tag OBJECT or EMBED not supported by browser.

    The above applet is loaded using the Java Plugin from a jsp page using the plugin tag.

    tomcat7-7.0.52/webapps/examples/jsp/plugin/plugin.html0000644000175100017510000000241212271304167022702 0ustar locutuslocutus Untitled Document

    Source Code for Plugin Example

    tomcat7-7.0.52/webapps/examples/jsp/plugin/applet/0000755000175100017510000000000012301126372021776 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/plugin/applet/Clock2.java0000644000175100017510000001701412271304167023767 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.applet.Applet; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; /** * Time! * * @author Rachel Gollub */ public class Clock2 extends Applet implements Runnable { private static final long serialVersionUID = 1L; Thread timer; // The thread that displays clock int lastxs, lastys, lastxm, lastym, lastxh, lastyh; // Dimensions used to draw hands SimpleDateFormat formatter; // Formats the date displayed String lastdate; // String to hold date displayed Font clockFaceFont; // Font for number display on clock Date currentDate; // Used to get date to display Color handColor; // Color of main hands and dial Color numberColor; // Color of second hand and numbers @Override public void init() { lastxs = lastys = lastxm = lastym = lastxh = lastyh = 0; formatter = new SimpleDateFormat ("EEE MMM dd hh:mm:ss yyyy", Locale.getDefault()); currentDate = new Date(); lastdate = formatter.format(currentDate); clockFaceFont = new Font("Serif", Font.PLAIN, 14); handColor = Color.blue; numberColor = Color.darkGray; try { setBackground(new Color(Integer.parseInt(getParameter("bgcolor"),16))); } catch (Exception E) { } try { handColor = new Color(Integer.parseInt(getParameter("fgcolor1"),16)); } catch (Exception E) { } try { numberColor = new Color(Integer.parseInt(getParameter("fgcolor2"),16)); } catch (Exception E) { } resize(300,300); // Set clock window size } // Plotpoints allows calculation to only cover 45 degrees of the circle, // and then mirror public void plotpoints(int x0, int y0, int x, int y, Graphics g) { g.drawLine(x0+x,y0+y,x0+x,y0+y); g.drawLine(x0+y,y0+x,x0+y,y0+x); g.drawLine(x0+y,y0-x,x0+y,y0-x); g.drawLine(x0+x,y0-y,x0+x,y0-y); g.drawLine(x0-x,y0-y,x0-x,y0-y); g.drawLine(x0-y,y0-x,x0-y,y0-x); g.drawLine(x0-y,y0+x,x0-y,y0+x); g.drawLine(x0-x,y0+y,x0-x,y0+y); } // Circle is just Bresenham's algorithm for a scan converted circle public void circle(int x0, int y0, int r, Graphics g) { int x,y; float d; x=0; y=r; d=5/4-r; plotpoints(x0,y0,x,y,g); while (y>x){ if (d<0) { d=d+2*x+3; x++; } else { d=d+2*(x-y)+5; x++; y--; } plotpoints(x0,y0,x,y,g); } } // Paint is the main part of the program @Override public void paint(Graphics g) { int xh, yh, xm, ym, xs, ys, s = 0, m = 10, h = 10, xcenter, ycenter; String today; currentDate = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("s",Locale.getDefault()); try { s = Integer.parseInt(formatter.format(currentDate)); } catch (NumberFormatException n) { s = 0; } formatter.applyPattern("m"); try { m = Integer.parseInt(formatter.format(currentDate)); } catch (NumberFormatException n) { m = 10; } formatter.applyPattern("h"); try { h = Integer.parseInt(formatter.format(currentDate)); } catch (NumberFormatException n) { h = 10; } formatter.applyPattern("EEE MMM dd HH:mm:ss yyyy"); today = formatter.format(currentDate); xcenter=80; ycenter=55; // a= s* pi/2 - pi/2 (to switch 0,0 from 3:00 to 12:00) // x = r(cos a) + xcenter, y = r(sin a) + ycenter xs = (int)(Math.cos(s * 3.14f/30 - 3.14f/2) * 45 + xcenter); ys = (int)(Math.sin(s * 3.14f/30 - 3.14f/2) * 45 + ycenter); xm = (int)(Math.cos(m * 3.14f/30 - 3.14f/2) * 40 + xcenter); ym = (int)(Math.sin(m * 3.14f/30 - 3.14f/2) * 40 + ycenter); xh = (int)(Math.cos((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + xcenter); yh = (int)(Math.sin((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + ycenter); // Draw the circle and numbers g.setFont(clockFaceFont); g.setColor(handColor); circle(xcenter,ycenter,50,g); g.setColor(numberColor); g.drawString("9",xcenter-45,ycenter+3); g.drawString("3",xcenter+40,ycenter+3); g.drawString("12",xcenter-5,ycenter-37); g.drawString("6",xcenter-3,ycenter+45); // Erase if necessary, and redraw g.setColor(getBackground()); if (xs != lastxs || ys != lastys) { g.drawLine(xcenter, ycenter, lastxs, lastys); g.drawString(lastdate, 5, 125); } if (xm != lastxm || ym != lastym) { g.drawLine(xcenter, ycenter-1, lastxm, lastym); g.drawLine(xcenter-1, ycenter, lastxm, lastym); } if (xh != lastxh || yh != lastyh) { g.drawLine(xcenter, ycenter-1, lastxh, lastyh); g.drawLine(xcenter-1, ycenter, lastxh, lastyh); } g.setColor(numberColor); g.drawString("", 5, 125); g.drawString(today, 5, 125); g.drawLine(xcenter, ycenter, xs, ys); g.setColor(handColor); g.drawLine(xcenter, ycenter-1, xm, ym); g.drawLine(xcenter-1, ycenter, xm, ym); g.drawLine(xcenter, ycenter-1, xh, yh); g.drawLine(xcenter-1, ycenter, xh, yh); lastxs=xs; lastys=ys; lastxm=xm; lastym=ym; lastxh=xh; lastyh=yh; lastdate = today; currentDate=null; } @Override public void start() { timer = new Thread(this); timer.start(); } @Override public void stop() { timer = null; } @Override public void run() { Thread me = Thread.currentThread(); while (timer == me) { try { Thread.sleep(100); } catch (InterruptedException e) { } repaint(); } } @Override public void update(Graphics g) { paint(g); } @Override public String getAppletInfo() { return "Title: A Clock \nAuthor: Rachel Gollub, 1995 \nAn analog clock."; } @Override public String[][] getParameterInfo() { String[][] info = { {"bgcolor", "hexadecimal RGB number", "The background color. Default is the color of your browser."}, {"fgcolor1", "hexadecimal RGB number", "The color of the hands and dial. Default is blue."}, {"fgcolor2", "hexadecimal RGB number", "The color of the seconds hand and numbers. Default is dark gray."} }; return info; } } tomcat7-7.0.52/webapps/examples/jsp/jsptoserv/0000755000175100017510000000000012301126372021252 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsptoserv/jts.html0000644000175100017510000000262012271304167022746 0ustar locutuslocutus Untitled Document

    Source Code for JSP calling servlet

    Source Code for Servlet calling JSP

    tomcat7-7.0.52/webapps/examples/jsp/jsptoserv/jsptoservlet.jsp0000644000175100017510000000157612271304167024553 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> tomcat7-7.0.52/webapps/examples/jsp/jsptoserv/hello.jsp0000644000175100017510000000165012271304167023103 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%>

    I have been invoked by <% out.print (request.getAttribute("servletName").toString()); %> Servlet.

    tomcat7-7.0.52/webapps/examples/jsp/xml/0000755000175100017510000000000012301126372020013 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/xml/xml.jsp0000644000175100017510000000377112271304167021347 0ustar locutuslocutus String getDateTimeStr(Locale l) { DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, l); return df.format(new Date()); } Example JSP in XML format This is the output of a simple JSP using XML format.
    Use a jsp:scriptlet to loop from 1 to 10:
    // Note we need to declare CDATA because we don't escape the less than symbol
    ]]>
    Use a jsp:expression to write the date and time in the browser's locale: getDateTimeStr(request.getLocale())
    <p>This sentence is enclosed in a jsp:text element.</p>
    tomcat7-7.0.52/webapps/examples/jsp/xml/xml.html0000644000175100017510000000241112271304167021505 0ustar locutuslocutus Untitled Document

    Source Code for XML syntax Example

    tomcat7-7.0.52/webapps/examples/jsp/snp/0000755000175100017510000000000012301126372020013 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/snp/snoop.jsp0000644000175100017510000000375012271304167021702 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%>

    Request Information

    JSP Request Method: <%= util.HTMLFilter.filter(request.getMethod()) %>
    Request URI: <%= util.HTMLFilter.filter(request.getRequestURI()) %>
    Request Protocol: <%= util.HTMLFilter.filter(request.getProtocol()) %>
    Servlet path: <%= util.HTMLFilter.filter(request.getServletPath()) %>
    Path info: <%= util.HTMLFilter.filter(request.getPathInfo()) %>
    Query string: <%= util.HTMLFilter.filter(request.getQueryString()) %>
    Content length: <%= request.getContentLength() %>
    Content type: <%= util.HTMLFilter.filter(request.getContentType()) %>
    Server name: <%= util.HTMLFilter.filter(request.getServerName()) %>
    Server port: <%= request.getServerPort() %>
    Remote user: <%= util.HTMLFilter.filter(request.getRemoteUser()) %>
    Remote address: <%= util.HTMLFilter.filter(request.getRemoteAddr()) %>
    Remote host: <%= util.HTMLFilter.filter(request.getRemoteHost()) %>
    Authorization scheme: <%= util.HTMLFilter.filter(request.getAuthType()) %>
    Locale: <%= request.getLocale() %>
    The browser you are using is <%= util.HTMLFilter.filter(request.getHeader("User-Agent")) %>
    tomcat7-7.0.52/webapps/examples/jsp/snp/snoop.html0000644000175100017510000000242412271304167022047 0ustar locutuslocutus Untitled Document

    Source Code for Request Parameters Example

    tomcat7-7.0.52/webapps/examples/jsp/index.html0000644000175100017510000004525712271304167021233 0ustar locutuslocutus JSP Examples JSP Samples

    This is a collection of samples demonstrating the usage of different parts of the Java Server Pages (JSP) specification. Both JSP 2.0 and JSP 1.2 examples are presented below.

    These examples will only work when these pages are being served by a servlet engine; of course, we recommend Tomcat. They will not work if you are viewing these pages via a "file://..." URL.

    To navigate your way through the examples, the following icons will help:
     
    Execute the example
    Look at the source code for the example
    Return to this screen

    Tip: For session scoped beans to work, the cookies must be enabled. This can be done using browser options.
     
    JSP 2.0 Examples
    Expression Language
    Basic Arithmetic Execute Source
    Basic Comparisons Execute Source
    Implicit Objects Execute Source
    Functions Execute Source
    Composite Expressions Execute Source

    SimpleTag Handlers and JSP Fragments
    Hello World Tag Execute Source
    Repeat Tag Execute Source
    Book Example Execute Source

    Tag Files
    Hello World Tag File Execute Source
    Panel Tag File Execute Source
    Display Products Example Execute Source

    New JSP XML Syntax (.jspx)
    XHTML Basic Example Execute Source
    SVG (Scalable Vector Graphics) Execute Source

    Other JSP 2.0 Features
    <jsp:attribute> and <jsp:body> Execute Source
    Shuffle Example Execute Source
    Attributes With Dynamic Names Execute Source
    JSP Configuration Execute Source

    JSP 1.2 Examples
    Numberguess  Execute Source
    Date  Execute Source
    Snoop Execute Source
    ErrorPage  Execute Source
    Carts  Execute Source
    Checkbox  Execute Source
    Color  Execute Source
    Calendar  Execute Source
    Include  Execute Source
    Forward  Execute Source
    Plugin  Execute Source
    JSP-Servlet-JSP  Execute Source
    Custom tag example Execute Source
    XML syntax example Execute Source

    Tag Plugins
    If  Execute Source
    ForEach  Execute Source
    Choose  Execute Source

    Other Examples
    FORM Authentication  Execute
    Example that demonstrates protecting a resource and using Form-Based authentication. To access the page the user must have role of either "tomcat" or "role1". By default no user is configured to have these roles.
    Servlet 3.0 Asynchronous processing examples 
    Examples that demonstrate using Servlet 3.0 asynchronous request processing API.
    async0  Execute
    async1  Execute
    async2  Execute
    async3  Execute
    stockticker  Execute
    Comet processing example 
    Example that demonstrates asynchronous request processing using Comet API. See "Advanced IO" chapter in the User Guide for details. It works only with connectors that support Comet processing (APR or NIO HTTP connectors).
    Comet Chat  Execute
    tomcat7-7.0.52/webapps/examples/jsp/checkbox/0000755000175100017510000000000012301126372021001 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/checkbox/CheckTest.html0000644000175100017510000000256412271304167023561 0ustar locutuslocutus checkbox.CheckTest Bean Properties

    checkbox.CheckTest Bean Properties


    public class CheckTest
    extends Object


    Properties Summary
    String CheckTest:fruit
    Multi


    tomcat7-7.0.52/webapps/examples/jsp/checkbox/checkresult.jsp0000644000175100017510000000317112271304167024043 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%! String[] fruits; %>
    The checked fruits (got using request) are:
    <% fruits = request.getParameterValues("fruit"); %>
      <% if (fruits != null) { for (int i = 0; i < fruits.length; i++) { %>
    • <% out.println (util.HTMLFilter.filter(fruits[i])); } } else out.println ("none selected"); %>


    The checked fruits (got using beans) are
    <% fruits = foo.getFruit(); %>
      <% if (!fruits[0].equals("1")) { for (int i = 0; i < fruits.length; i++) { %>
    • <% out.println (util.HTMLFilter.filter(fruits[i])); } } else out.println ("none selected"); %>
    tomcat7-7.0.52/webapps/examples/jsp/checkbox/cresult.html0000644000175100017510000000256612271304167023367 0ustar locutuslocutus Untitled Document

    Source Code for Checkbox Example

    Property Sheet for CheckTest

    tomcat7-7.0.52/webapps/examples/jsp/checkbox/check.html0000644000175100017510000000233512271304167022755 0ustar locutuslocutus

    Check all Favorite fruits:
    Apples
    Grapes
    Oranges
    Melons

    tomcat7-7.0.52/webapps/examples/jsp/dates/0000755000175100017510000000000012301126372020313 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/dates/date.html0000644000175100017510000000240512271304167022125 0ustar locutuslocutus Untitled Document

    Source Code for Date Example

    tomcat7-7.0.52/webapps/examples/jsp/dates/date.jsp0000644000175100017510000000336112271304167021757 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ page session="false"%>
    • Day of month: is
    • Year: is
    • Month: is
    • Time: is
    • Date: is
    • Day: is
    • Day Of Year: is
    • Week Of Year: is
    • era: is
    • DST Offset: is
    • Zone Offset: is
    tomcat7-7.0.52/webapps/examples/jsp/tagplugin/0000755000175100017510000000000012301126372021205 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/tagplugin/foreach.html0000644000175100017510000000231512271304167023511 0ustar locutuslocutus View Source Code

    Source Code for foreach.jsp

    tomcat7-7.0.52/webapps/examples/jsp/tagplugin/if.html0000644000175100017510000000227612271304167022506 0ustar locutuslocutus View Source Code

    Source Code for if.jsp

    tomcat7-7.0.52/webapps/examples/jsp/tagplugin/howto.html0000644000175100017510000000312512271304167023242 0ustar locutuslocutus Tag Plugin Implementation

    How to write tag plugins

    To write a plugin, you'll need to download the source for Tomcat. There are two steps:

    1. Implement the plugin class.

      This class, which implements org.apache.jasper.compiler.tagplugin.TagPlugin instructs Jasper what Java codes to generate in place of the tag handler calls. See Javadoc for org.apache.jasper.compiler.tagplugin.TagPlugin for details.

    2. Create the plugin descriptor file WEB-INF/tagPlugins.xml

      This file specifies the plugin classes and their corresponding tag handler classes.

    tomcat7-7.0.52/webapps/examples/jsp/tagplugin/if.jsp0000644000175100017510000000302712271304167022331 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Tag Plugin Examples: if

    Tag Plugin Examples - <c:if>



    Plugin Introductory Notes
    Brief Instructions for Writing Plugins



    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

    Set the test result to a variable

    The result of testing for (1==1) is: ${theTruth}

    Conditionally execute the body

    It's true that (2>0)! Working.

    It's not true that (0>2)! Failed.

    tomcat7-7.0.52/webapps/examples/jsp/tagplugin/choose.html0000644000175100017510000000231212271304167023357 0ustar locutuslocutus View Source Code

    Source Code for choose.jsp

    tomcat7-7.0.52/webapps/examples/jsp/tagplugin/notes.html0000644000175100017510000000317312271304167023235 0ustar locutuslocutus Tag Plugin Introduction

    Tag Plugins: Introductory Notes

    Tomcat provides a framework for implementing tag plugins. The plugins instruct Jasper, at translation time, to replace tag handler calls with Java scriptlets. The framework allows tag library authors to implement plugins for their tags.

    Tomcat is released with plugins for several JSTL tags. Note that these plugins work with JSTL 1.1 as well as JSTL 1.0, though the examples uses JSTL 1.1 and JSP 2.0. These plugins are not complete (for instance, some item types are not handled in <c:if>). They do serve as examples to show plugins in action (just examine the generated Java files), and how they can be implemented.

    tomcat7-7.0.52/webapps/examples/jsp/tagplugin/foreach.jsp0000644000175100017510000000313712271304167023344 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Tag Plugin Examples: forEach

    Tag Plugin Examples - <c:forEach>



    Plugin Introductory Notes
    Brief Instructions for Writing Plugins



    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page import="java.util.Vector" %>

    Iterating over a range

    ${item} <% Vector v = new Vector(); v.add("One"); v.add("Two"); v.add("Three"); v.add("Four"); pageContext.setAttribute("vector", v); %>

    Iterating over a Vector

    ${item} tomcat7-7.0.52/webapps/examples/jsp/tagplugin/choose.jsp0000644000175100017510000000310512271304167023210 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Tag Examples - choose

    Tag Plugin Examples - <c:choose>



    Plugin Introductory Notes
    Brief Instructions for Writing Plugins



    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> # ${index}: One!
    Four!
    Three!
    Huh?
    tomcat7-7.0.52/webapps/examples/jsp/async/0000755000175100017510000000000012301126372020330 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/async/async1.jsp0000644000175100017510000000206711522173006022251 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page session="false"%> Output from async1.jsp Type is <%=request.getDispatcherType()%> <% System.out.println("Inside Async 1"); if (request.isAsyncStarted()) { request.getAsyncContext().complete(); } %> Completed async request at <%=new java.sql.Date(System.currentTimeMillis())%>tomcat7-7.0.52/webapps/examples/jsp/async/async3.jsp0000644000175100017510000000167511522173006022257 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page session="false"%> Output from async3.jsp Type is <%=request.getDispatcherType()%> Completed async 3 request at <%=new java.sql.Date(System.currentTimeMillis())%>tomcat7-7.0.52/webapps/examples/jsp/async/index.jsp0000644000175100017510000000456011656645706022205 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@page session="false"%>
    Use cases:
    
    1. Simple dispatch
     - servlet does startAsync()
     - background thread calls ctx.dispatch()
       "> Async 0 
    
    2. Simple dispatch
     - servlet does startAsync()
     - background thread calls dispatch(/path/to/jsp)
       "> Async 1 
    
    3. Simple dispatch
     - servlet does startAsync()
     - background thread calls writes and calls complete()
       "> Async 2 
    
    4. Simple dispatch
     - servlet does a startAsync()
     - servlet calls dispatch(/path/to/jsp)
     - servlet calls complete()
       "> Async 3 
    
    3. Timeout s1
     - servlet does a startAsync()
     - servlet does a setAsyncTimeout
     - returns - waits for timeout to happen should return error page
    
    4. Timeout s2
     - servlet does a startAsync()
     - servlet does a setAsyncTimeout
     - servlet does a addAsyncListener
     - returns - waits for timeout to happen and listener invoked
    
    5. Dispatch to asyncSupported=false servlet
     - servlet1 does a startAsync()
     - servlet1 dispatches to dispatch(/servlet2)
     - the container calls complete() after servlet2 is complete
     - TODO
    
    6. Chained dispatch
     - servlet1 does a startAsync
     - servlet1 does a dispatch to servlet2 (asyncsupported=true)
     - servlet2 does a dispatch to servlet3 (asyncsupported=true)
     - servlet3 does a dispatch to servlet4 (asyncsupported=false)
    
    
    7. Stock ticker
       "> StockTicker 
    
    tomcat7-7.0.52/webapps/examples/jsp/simpletag/0000755000175100017510000000000012301126372021200 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/simpletag/foo.jsp0000644000175100017510000000217412271304167022513 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib uri="http://tomcat.apache.org/example-taglib" prefix="eg"%> Radio stations that rock:
    • <%= member %>
    Did you see me on the stderr window? Did you see me on the browser window as well? tomcat7-7.0.52/webapps/examples/jsp/simpletag/foo.html0000644000175100017510000000241412271304167022660 0ustar locutuslocutus Untitled Document

    Source Code for the Simple Tag Example

    tomcat7-7.0.52/webapps/examples/jsp/sessions/0000755000175100017510000000000012301126372021061 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/sessions/carts.jsp0000644000175100017510000000233612271304167022725 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <% cart.processRequest(); %>
    You have the following items in your cart:
      <% String[] items = cart.getItems(); for (int i=0; i
    1. <% out.print(util.HTMLFilter.filter(items[i])); %> <% } %>

    <%@ include file ="carts.html" %> tomcat7-7.0.52/webapps/examples/jsp/sessions/carts.html0000644000175100017510000000253712271304167023100 0ustar locutuslocutus carts

    Please enter item to add or remove:
    Add Item:

    tomcat7-7.0.52/webapps/examples/jsp/sessions/crt.html0000644000175100017510000000255412271304167022553 0ustar locutuslocutus Untitled Document

    Source Code for Cart Example

    Property Sheet for DummyCart

    tomcat7-7.0.52/webapps/examples/jsp/sessions/DummyCart.html0000644000175100017510000000256412271304167023671 0ustar locutuslocutus sessions.DummyCart Bean Properties

    sessions.DummyCart Bean Properties


    public class DummyCart
    extends Object


    Properties Summary
    String DummyCart:items
    Multi


    tomcat7-7.0.52/webapps/examples/jsp/jsp2/0000755000175100017510000000000012301126372020071 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsp2/jspx/0000755000175100017510000000000012301126372021055 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsp2/jspx/textRotate.html0000644000175100017510000000246412271304167024122 0ustar locutuslocutus View Source Code

    Source Code for SVG (Scalable Vector Graphics) Example

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspx/basic.jspx0000644000175100017510000000411612271304167023054 0ustar locutuslocutus JSPX - XHTML Basic Example

    JSPX - XHTML Basic Example


    This example illustrates how to use JSPX to produce an XHTML basic document suitable for use with mobile phones, televisions, PDAs, vending machines, pagers, car navigation systems, mobile game machines, digital book readers, smart watches, etc.

    JSPX lets you create dynamic documents in a pure XML syntax compatible with existing XML tools. The XML syntax in JSP 1.2 was awkward and required &lt;jsp:root&gt; to be the root element of the document. This is no longer the case in JSP 2.0.

    This particular example uses a tag file to produce the DOCTYPE and namespace declarations to make the output of this page a valid XHTML Basic document.

    Just to prove this is live, here's some dynamic content: tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspx/basic.html0000644000175100017510000000242712271304167023037 0ustar locutuslocutus View Source Code

    Source Code for XHTML Basic Example

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspx/textRotate.jspx0000644000175100017510000000456112271304167024142 0ustar locutuslocutus JSP 2.0 JSPX JSP 2.0 XML Syntax (.jspx) Demo Try changing the name parameter! <g opacity="0.95" transform="scale(1.05) rotate(15)"> ${name} </g> ${name} tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspx/svgexample.html0000644000175100017510000000423112271304167024124 0ustar locutuslocutus JSP 2.0 SVG Example

    JSP 2.0 SVG Example


    This example uses JSP 2.0's new, simplified JSPX syntax to render a Scalable Vector Graphics (SVG) document. When you view the source, notice the lack of a <jsp:root> element! The text to be rendered can be modified by changing the value of the name parameter.

    SVG has many potential uses, such as searchable images, or images customized with the name of your site's visitor (e.g. a "Susan's Store" tab image). JSPX is a natural fit for generating dynamic XML content such as SVG.

    To execute this example, follow these steps:

    1. Download Apache Batik, or any other SVG viewer.
    2. Copy the following URL: http://localhost:8080/examples/jsp/jsp2/jspx/textRotate.jspx?name=JSPX
    3. Paste the URL into Batik's Location field and press Enter
    4. Customize by changing the name=JSPX parameter

    The following is a screenshot of the resulting image, for those that don't have an SVG viewer:
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspx/textRotate.jpg0000644000175100017510000006415112271304167023737 0ustar locutuslocutusJFIF``C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( *-[yJ`>` ( ( dGdmvel(}UT'aU[GF2jj ( ( (#8((((((((((((((TkWu 3Q/Wt_@ψK=N=2WB[Ip#'<_h|Ɵ`g{ds\nR{H5/jus&l$@v+4K^ G5̪kt#|s@$m$pkFe^e|a8[Nl'2 -d8vJ`P%؎[DAM"IŬ^311I ;i.n#],Tzx+Zn{v$ m)#8k#ͼ6sk1cm3D?|Oon{KIUs~Us-If0j P@ΗQ&f2FfcZ(s\麷ćѤqFhFB`wVW=;Y ye4fE=^͡[`3"K _1E\'SIxx[d ZlQH4>7N^M"WꊀC]׃eSIiD(ԳUP:OAY1Hҵ;;,&u+П“Ś xWZR\IJ:HSzGWMy]j B)l55#_⻈1RF<ƪNe( ?U^-sB'_մ[[ՃJJ7 V uOZF:,bHҫ?.dM\f R{W:o|1{Z< )أ )确r>$v޵nA-3.AϘ\`O*r8{|T,y|d<2u58@cxmUUÜgn>Q62VߝU,5!@|TlU+EhQ\4wއj;qXuxgH"A@lU;~\Ÿ#k ( ( ( ( ( ( ( ( ( ( ( ( ( 5ڝ ]&+ŶKb&i#9Pdߍq=]{/% ? 4\לcէi__^AK{*pvse7ܤ`fAYFXYu /w*:չQ<30ʒlbè8Gd)bɤ}339e) vU6VakɥR2ı9WI\/ x:{® ]2k5q cԒA8QdGiM[K.Jb@ʌ^<SSdjU*+02z1b]>[ Pۄn2r^NΡu~R+Nڝ(\I;WCE 0UƎl?zgiAYmnspV@!w1۞+MuJCin^GHrYUP=I*(ؼ=z4^Pv#7fKKu7f6f\gTsuAuc& ;>+ڱd>oލAO [ܥh {20}0OʤzTx/AXC u$/s+#Jb $sm{ MVS˻.]&х%s88;/4լu80Z\blnRb= F5 \s}iǩ7zںԞbU!6*x k}L[D{qk3HK8U99 \͵O ?KYm ɥBRٙcWyf$v@[F-:%`,(^X( +r 3 (&a=)!$mWg@{@ϥIqݮ/RL̐ʑ<}6x#{>6W3le{-[܉O1#+EӦeY.rC 6¤Ygv uUU7Mwko13Yza؄t(((I4P"'F]j>M&Ѣ%צn"zMhi7R][3Jrᱜc"J_*@(((((((((4 '[N[^Fd g\ʼ>52kic;̇ HQ:20qX+ =<d6fvn3~5{MПY];zghD*N,}_ k7 gԝ"[Ind[S]y,C08+TqMx*m#$Ҵ1!p:7fm2K>X)n wvz~Esr.l1f .|XfOihf5ֽ.v9 v.TubxW{+6eX]<$̬@;V#r&k ?Jlp-Ǜ23 a3G9]/< k&(-P+\IBW;y𷇒SIh̘ [ZA6TX./:46 -0i=,;زU`H6wwڧ4[m&VNGsgq L# >a:VWt?iy5a@PAv9>ݦST"\YC%3$%ˆB0 y?7=G5&j%J YYss%O!vv+.ф$=Gv_ i6>!3ZfeuG||9Q:^iN=/fU'lsoe83 kw^#~ w71u#{z w=jڅͼ {oGlWqc>滯f7.Õ I$qPM93|:ט)lnt% qВ9uMwZEY?P\SN[ ȋi2}czWqL#OPծ$} 3Op95Zhdg}{nȲr'?(m q) ]w6)Kuw-0M sxXxVKei0K-lnRr8nxRXZr#ݥ&2@F s~usQ^>$ɪ'*f d6ww:\[ζۤјطO!Uh hi.bױH o6s?-f]d]jlŭHW`\lMX3ZYq+ n:^)%}c_x~IQ'I[3+U-%l<.n#R07`ifVo|VK$WFO>CyCOI,Xף vC((B,3yiqgx'y.--8)VXc;Vr Nkv*"FKyvLѶn],mS/tiV7ck (&M!T$xwOz?_޵`Yƪsvo vmGm8hKK?m.7DCn-csU7Ǻŷd?{V/EQ@bkzO:Z۪z貳iP{E/bHCou{Wb1v:f31<ۗ yD~Ԃv򏔟ZT@lWQQqq&Y[ ?Zﯤ{gK?>U7H 3Ҡf.rk!)גz֝VGW }Tڼ֦)bOP~c{SKi`&g H79?2@khwQ:ׂzg?e~d_lWZpp;P,q4נ2wO$cd/bРs4ew'a426g J1MmhPܬ2n@5?E-9zZ?ۖ_s!ڞ ܶrChܶrCk"ry/5xI8X+0QON\m1G"[ceXV%։, g GNݫnm60**ޡȮK Uwx3iկ-眿?-眿khP >5r2;֊1{maqOyW-l哕jRx7DCYM(o+>w@D5vIPߘ)5yd>?~t?~OyFuRDoֺ="IU+$\괥ۦ@=MMMgh]^տkX')"q.>jlg: XiAD$:^e.oZV~ƙE0:=̈۹\\,gS.0~OgfS^D Tu$Յ^F~Uw>Q`d|;;V3ނYyȧַi* ¨; (Q@S]sQN(U{8<^FmyJ-\֬e/C.w7ޙ^?V叩#[~n"|:mMo_V#+fft"0/ߔ}rAϥhj_<~VB4>F@|ŲTE6!=xv?pR,ʢv=Jw<ՙb[mH1$ (S֊vw# mtkT@c}jg.P9 @$]%md!s}e+֥IK`֦|!9 - :iXn8r5,UwzV>n?SZA#8AU|OJݺ{u +EUj Bv) yw$ΫՏEzVZY2T~4J,1КDyRKBk 5 szmjr~ˢQEQ@Q@:QXm)Xκ*gPx *ͬq{W"FZ2UTH?/"TGjCR9ڌރ5麼4Z\Z%b }u|EJi21C+`R8/KH'p z4W:C\ʚLsV wtd63ArvHg+$Xu`)̇ۊS\ &!{dAd8=P1ޓc)ʞGLR\9ԈmS'ez&vrTri0}Y9 (AS)f8P2IU;~UI2qƝw+]/{pVʇ Eeyq,w|L,.v{q]k +Q}WR*: 9ͳE1;LG<ִ-9aNI?ҹWȵAƪiZΔ 7FZגN Goh%Te oVWe!)a9T/uKI\LYGA¯Ue )Ռ>u( |=L~u^xi5Eځ +m5$Kn>)M-ĆIygbIMe,?3AZmyAS+n] 2MsJ)muQ-$vsN)rxsHK ,4ֹٮay}=jxDHH.N6b-_RMcRJy}2Xk$rC:-< LHZnI#q.> ?ƺX^B>Dcc-TRb,Ȝ iҸPF4~W=N B@)j?`?3T%v=)"|}-}qI E}k[,U)z] |oJ--@@cU5d~WU ;rH6b 6^\b6/,3ڨdh~@v tN/c첯_*`ՆQE ( ( ( H<ƺbvʟ?\bP:El!$cI|EtcvBƿˏOʰ"Y!ĐT  Pخ)pvzTu`ؿgZlV~Mi #xhRi`26j6V$˽ˏ˟έc^'n'Y_h!H|@F4{?/6"taٗ| ۨI4D-tԬ9LCV4 dЅ!FS#Pmv]*g;_?E.,#r޸Fo`4mmu{X%]dt~#o[^Lng^ae"֬\AsjiF۔JRHA15^7 M1sB/IzW5` *#+JT_NۻVn{E} ] V3hwUH 23ޭXYˀZVlEӔnZs/4ڰ $lUj)zNP9__q\9pXrngEeZkq:s8Aɭ'AYrTR) Z ( ( irp*AuqD)sS[ўil]$Z֦>"|:ug)LA䀿RewiZmx~`$ԀulaoQ( \ddU?IұXԵ)>f=, PwwZ5|6NN{W95$I֒ZHՌt2Dl"+j:ڑ 3ڳ#'ֶ>A:=?c3: YfAZ$ҔhQ /i @ުL1Ă q)8#+ǭnxY y ;¼Zv);9ϥԦ3T\[#K!A($q Zn jF[9pw`?7:pFc؞\y51oBlM@G~OAVԽvHF| 鬵8man7tI7zVCz7 לVq1OSWoWH^ENknNOaR()&鷳3-x;6¶ #"_[I,igr[kwo)+ᔑ$~3rx N=ÚQr Ik'tr#  yOoOFH dks^:]~+年dadn4Ե뫫v{imUYs{uƾMf6=:}1EeQF]~7Zi.In|xzE}sL~Q1j6gQT^#Xok*m74Os4~ ]2O*2>WJ| <_Ն+D#5"u6mpuϣU?k+2Xٍdj3?NNR\ 2%6wF+.¹>}=acSXr~ku{"e*uA?7tSlR?!ᏳVuT6n |R;M2#SMT^ FTV?ӥAN_G)sX zu"Qumy"\REs:[@ҿAzJݥ'I#p*֩{!p=ϭ^켴Laz֫W흪[cucjCVxUrv85 bɛAHyj=jX_]̎ڐi`xehe85{Qc \ )VD8e9@XHǫU1>1Zv *aTGjiQPEPMwXлUI5yoxa\]\^>dbފ:®0l [t 4ab+r{LQKa :өOsO9P#CLY6 $(9Jz #Ԋ˲9 prj>_n$ ~4g#Ҍ9wc,J :Ս7Xn D';sJa*>_~y^5[<:Annn->+rJMxIuo|*3+TbW,o,KAqʆjqV`e})wu;nfGPv9fKE!sRiqZxNA@9ϭxI?]^ҽ#:MWxO3Un(e8rH[4odp c>"VR b@{XHzJ?j:[J\ )w¥Wk(Zo6|dpl5.+7MOF!Z@ kq(R+;f>Ҽ@wO"{F>޼ əP`J9} uP ECF$>^wǺOºHRӴZvs?wj7)J}oB+c$R7w@{׈Yտow 8[ovㆾn`/#\/fƦ;8dE>ξm9D75m^^'0eaOz"xJ.4YUO<}?N43R7Wr;zߴƍq퐎H! N+-PHE|daܞNdWRy2']n>u;}kI-[1N*{G^S[=B =e6NY) Hw.~tI?( ~`z׬C4|K}ov~0HNy3^KmZ/uqۉcˆt:},-nO) vwH!=vW/Z麥K$'/́ lsJҔ:^02;cqu#`u 9o)X!Z %H27 6ZRyr mxn33sW4Z@Eu"#ўHQJտYFp[hv:eH?~]ֳcyc=+E-iF|rm;u>֦+ (uM2ֵ # A㨫7֦ʟj[qz=ߕ1!quO]b~uιe((=134~U_OsZm5A*J)7z֞TK:CV KP6wMPUMh!5 s\ ~5 X=<^CM^ZB͂?U WA M==<џ5D]׺&ّKYG22B1]lNZ{Ɱ.5{I; Qn`aJk[ڕZC2`6:V$ϭoqʣ}*lc '8,yr)mX(JFZ[f$'ʾj!v5)w.Y^Vs $HET1s^ Zǩ/)1F[r01[]zZ7PFڤZ#\<~u/n͏u+׈xKLkMnRa&u|r`z zD~xX+ R%Gkwi&1/Vy櫨_N!Wq^I4RWRͦ<|\烞W~j LeaGyEo|,|Gk֩,ڜ(BFx|?O?:ƴ#g[8vXsGU4O[om*ڈ[3A #vEu|V#+jo~6xSY[,cjC-N%@qQ{XJZ tse7XG ^>kt>y QRgIY.XwG߅4f2 kUhKKkսZ]1}kddS_x&O3#ضR~`?pju[/7DO?޽OOԭuK52SGc^4Z_X6Ӽ{ަ%=Vz$EHmLn5Y1y>w{ CordxאHWGk>dN!zz5:EEPEP-NVhr쫛mvYG'>JojՅٴ ~ᇵUj;CAeQBv֬s(ܜzk;z"9תED8@>4)T::䫬%t?J9q/ʟOjϔfsշ]Kyfn1ĂYeuN9W_QkKHI UZ4SOaFJn׉}r jIiqHp)=u1o xvQLU.%ldt X69t{쭮$y RI MORX_",/;Y5mưqFtݷ=+U@% ۺK7I#f){Kg{Y:}01=@jt-'foCԃ[goWgH_ CV<]h-X ,$֮r`soֶ.?})tq\b0ޟڍV 2pA[]ZcA?>GUkUI4v1sZ^ +{g/ {X?X_@ (PM sU{;{ 4{_P2'h7w8i0p+{*x4eY}ƭJ+eY}Ə/{D#Gh:1V+I5€בZ_V_o*x4CvO*x4R;΂׏Oj;rarWB:;XL~ǾKs?\on}cqnsu; )JQ\_楢Z$#sx5VkQwP{}iioyqs;w/fԴ{G۳uqmW2x*zvxַ\m<}5֛[脾Tn3pO*%+=Dp76Yܟt3&:.#KE*[j.s~jCcZbUL~54֠t4nV߮+6VKخu|gj7NjZSs-.ݔ q9LMd,l#dƱU77 *errjU8gsJs'UZ{\{ L;; (V~tTAԡ9Ѕ'7CN'&cBBY2N98#ӭm> o95`sD]IRyHr0ǪլТ9{ZsL?\³!FqZ yT.Y̤ 9 O,&RD "%L vq>cz;V,v߿9ӝe.d w|Cc P1^i ϶+6tFQ8+[,i7/o&NGҽ/š䷚YG^}y/@K9wnkv&lg"HFY%`6K'ͷW?!5P.,Ya{pݏҹ-;NuB+U٤8 s5jwOrw 6#<+&C#4fF SGcRD`LP5u]= /"'CWb/1#'_JM+A՛6틼 n?QtvhO3Ī`o^+nv`QE ( ( ( ( (9W@Z1V_Ƴu]:KFL2ZO#`O`)m:!vWWccs5h4:hSG0f>{V5h{PqNR`=XAt_l\'h^̈́9|j}ͽŤRG*{g:wO>ҲڴVck K:[ͲN{ Ȁ3?Z 54 LAMYǽ6[f: [R<'7l2*jBUF#dZd ("!2',p}jOFpǥC[r[E$O"SO*[/&"ݨKyqH p)UG4"jo/i~"˩Im#cO&x#-FG58NPIj6KF 99?ֻH>,Y/H--cbz玝y(F@A zF'\%{{W=d[Y8et6?W3Eo=8amLs78kokf݈&-WڛySz!?) ^kK_d׭$ϱ]UE @` |c }e'wQ7 hEu~ rKoabV68(8*(¨:NQE ( ( ( ( ( ( ( m'sn'WA{WAE8ɦ M-lkvڑL5>':[E{{֋@.\X=Oy^z$*XkdEmimWeUYsӸ/6pj{gGn2ן\.9~??IE.E'y3p?eȇfN3|MoEʛaLG/v65 GeT+4prȦZUd%e T0yn!/νJ%[+}vRxoEMwm#SS_FcV\?$^”&04"#B`)QXQEQEQEQEQEQEQE^/>hErUoIdcUVs;y1Q*w6<{N+t`mwjibˏI{{U\F!Я|0"泞7:a]Asim0އJ3X?dֵM=(b)QSjф3`'UVxcyG\}+YU9S̸y8,N?J{e nQw` ef08dƯ0HUGbq׎?(cU/{fSXo"%M)$OQiM7Y0;5δLFYZ-ދv{!7!=РխwMD$ـ)y?\j1Jc}>[t[iwg4L jqbpblV { ŝ2^@y1wYbL/ڐJ;t%^fsEoտ.?:{, +O\~ֿc-ϹⳊm0Jcz5hYmdP36p}xrQ >eԭfcTb}"+F AK{mTd{Txv9VPSJLؗ6IVWtr㨫EPEPEPEPEPEPEPEPEPEPEŖ7vEu,xҀYkq HǯhVf?搄*qi33n\o0v?W5 +jʒ78nWMwFT8 Wӯ-Im@d~boؗXG\;]rxJQx yܷrv%I?AWMC5,4Gm`ַhd2Tp?rgDٔⴿu~&? RR4<;qk;[@|ϟB tͫN,#Kw>KY!t\l܆U5f+ '$*MnX= 8G[h޶A{v?C}E7SFɭ !ݘ5xN cs&E p;~c FcTl\EoCO t1 pG_ָ{XB͐]>7X[+AXVf?Ҧú]ԨD\?1\̗rJr6Yt ;0]4{mSf 18`(^O-}T.nW/smyycm #*#nzj-A^ ojc)A;0L~k@&]ndpUU00pr2"Fǧ@j[V<͵d˃wy5=+4;3RaZ2HFFC{jT|/ZqG1Jz(ER((((((((("q>;YW=EuyjgC\+#aVгV+đ8e?s&tRVb)ʱqC%Ĝdӌ," +llđS%I9?i9J+j ܧ0ʒCΞ&[yR{W<❓QOͬ2.ؿS0kZ;bʤXi:Fj $,npGw DOeTFE4H'daN+Ně% ҳ ME߲>}+=A u7by'Ё J4o.+D$09ҴOgSeaoCg=qzj: 6r:/!TrLS*?G5<_R/t#7[ E?KuNvc+3ʤ\̑5L2JJZFJI3[^Ӵ"぀OrMr73ɵTSYiI(@+J#f6pw\eB{Ң$'*W]~=8 ANB=$)$ig:n  nu 7I:(GVoZlylyL`?LqgfURĄP)ʃ:QZ-@!8zq94yH]*ܚ`: ˨ිTN*##u*è#?LM:;t eܮQڃX{}v 9 (P] A=p$,/c[dPr3֏-}JR\((((((((((((+SdY` p8޶([.f}siN%3#ap}[TS`QEHK@FGq.> ]Q]ƍƒqqJEzV#ފkypjp,C沉0.HSMrLlUKKqkLǖ#L4{+S?Jm8BmEӂ~Ϡt eN[}zx`9<#^>eѣrXFC'-U?MWhgk-VE9`}FKy:8ƹ{ss-4Y۽tI.0{~hltթZ΢j(@(((((((((((((+#YԞ"]Kzyg9?êqi=@,u)_2~d'[pT+s{PI [8j &zgᨚ{Hyڤ ~eR.H۽v&́Sz_G4}ֵ<?牭$1SWW;'VgC=)ɷfNMUm6we?Fkf"5zcFZpoO|ufu" sH[ҬjOa{%9S;Z-@( ፝EQt o'𩔔w[i78Op$קQ#U mWh&̵ժnye֩Tݘ~t-)|ف[dE;XiviQHuh,nVl_ ;[^['y&tG{"'"d1^FlM9 tq)f[NkHEFtGvz+4v2G,n>,#[u0>!Y7Y#p&?kDkaF]8s]e爠XYmC<`1iŨC>2۽oOF;->OdOc7ժj:ȊAVw~c dpTF[+#w[a%%N3rM?٤bkHӺN+湵dރWsjIىv;]} r:d~nldy9"E j:* lOQԭ)VW(0!ҴR4vƊE QH((((((((((((((((((]J KEb_x~92cp?OJi hQTڰQR%?2N.}6Lc~bz*>P<Iupg[S\΁R,Q 0*R@c@UF Z(ueoz r>b?V"7֍h VM40mzqE6QE ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/0000755000175100017510000000000012301126372020471 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsp2/el/implicit-objects.html0000644000175100017510000000247112271304167024632 0ustar locutuslocutus View Source Code

    Source Code for Implicit Objects Example

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/composite.jsp0000644000175100017510000000770211656646012023231 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="my" uri="http://tomcat.apache.org/example-taglib" %> JSP 2.0 Expression Language - Composite Expressions

    JSP 2.0 Expression Language - Composite Expressions


    This example illustrates EL composite expressions. Composite expressions are formed by grouping together multiple EL expressions. Each of them is evaluated from left to right, coerced to String, all those strings are concatenated, and the result is coerced to the expected type.
    EL Expression Type Result
    \${'hello'} wo\${'rld'} String ${values.stringValue}
    \${'hello'} wo\${'rld'} String
    \${1+2}.\${220} Double ${values.doubleValue}
    \${1+2}.\${220} Double
    000\${1}\${7} Long ${values.longValue}
    000\${1}\${7} Long
    \${undefinedFoo}hello world\${undefinedBar} String ${values.stringValue}
    \${undefinedFoo}hello world\${undefinedBar} String
    \${undefinedFoo}\${undefinedBar} Double ${values.doubleValue}
    \${undefinedFoo}\${undefinedBar} Double
    \${undefinedFoo}\${undefinedBar} Long ${values.longValue}
    \${undefinedFoo}\${undefinedBar} Long
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/functions.html0000644000175100017510000000261612271304167023402 0ustar locutuslocutus View Source Code

    Source Code for functions.jsp

    Source Code for Functions.java

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/composite.html0000644000175100017510000000261411313755175023377 0ustar locutuslocutus View Source Code

    Source Code for composite.jsp

    Source Code for ValuesTag.java

    Source Code for ValuesBean.java

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/functions.jsp0000644000175100017510000000452512271304167023233 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <%@ taglib prefix="my" uri="http://tomcat.apache.org/jsp2-example-taglib"%> JSP 2.0 Expression Language - Functions

    JSP 2.0 Expression Language - Functions


    An upgrade from the JSTL expression language, the JSP 2.0 EL also allows for simple function invocation. Functions are defined by tag libraries and are implemented by a Java programmer as static methods.
    Change Parameter
    foo =

    EL Expression Result
    \${param["foo"]} ${fn:escapeXml(param["foo"])} 
    \${my:reverse(param["foo"])} ${my:reverse(fn:escapeXml(param["foo"]))} 
    \${my:reverse(my:reverse(param["foo"]))} ${my:reverse(my:reverse(fn:escapeXml(param["foo"])))} 
    \${my:countVowels(param["foo"])} ${my:countVowels(fn:escapeXml(param["foo"]))} 
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/basic-comparisons.jsp0000644000175100017510000000613112271304167024632 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> JSP 2.0 Expression Language - Basic Comparisons

    JSP 2.0 Expression Language - Basic Comparisons


    This example illustrates basic Expression Language comparisons. The following comparison operators are supported:
    • Less-than (< or lt)
    • Greater-than (> or gt)
    • Less-than-or-equal (<= or le)
    • Greater-than-or-equal (>= or ge)
    • Equal (== or eq)
    • Not Equal (!= or ne)
    Numeric
    EL Expression Result
    \${1 < 2} ${1 < 2}
    \${1 lt 2} ${1 lt 2}
    \${1 > (4/2)} ${1 > (4/2)}
    \${1 gt (4/2)} ${1 gt (4/2)}
    \${4.0 >= 3} ${4.0 >= 3}
    \${4.0 ge 3} ${4.0 ge 3}
    \${4 <= 3} ${4 <= 3}
    \${4 le 3} ${4 le 3}
    \${100.0 == 100} ${100.0 == 100}
    \${100.0 eq 100} ${100.0 eq 100}
    \${(10*10) != 100} ${(10*10) != 100}
    \${(10*10) ne 100} ${(10*10) ne 100}

    Alphabetic
    EL Expression Result
    \${'a' < 'b'} ${'a' < 'b'}
    \${'hip' > 'hit'} ${'hip' > 'hit'}
    \${'4' > 3} ${'4' > 3}
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/implicit-objects.jsp0000644000175100017510000000657412271304167024472 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> JSP 2.0 Expression Language - Implicit Objects

    JSP 2.0 Expression Language - Implicit Objects


    This example illustrates some of the implicit objects available in the Expression Language. The following implicit objects are available (not all illustrated here):
    • pageContext - the PageContext object
    • pageScope - a Map that maps page-scoped attribute names to their values
    • requestScope - a Map that maps request-scoped attribute names to their values
    • sessionScope - a Map that maps session-scoped attribute names to their values
    • applicationScope - a Map that maps application-scoped attribute names to their values
    • param - a Map that maps parameter names to a single String parameter value
    • paramValues - a Map that maps parameter names to a String[] of all values for that parameter
    • header - a Map that maps header names to a single String header value
    • headerValues - a Map that maps header names to a String[] of all values for that header
    • initParam - a Map that maps context initialization parameter names to their String parameter value
    • cookie - a Map that maps cookie names to a single Cookie object.
    Change Parameter
    foo =

    EL Expression Result
    \${param.foo} ${fn:escapeXml(param["foo"])} 
    \${param["foo"]} ${fn:escapeXml(param["foo"])} 
    \${header["host"]} ${fn:escapeXml(header["host"])} 
    \${header["accept"]} ${fn:escapeXml(header["accept"])} 
    \${header["user-agent"]} ${fn:escapeXml(header["user-agent"])} 
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/basic-arithmetic.html0000644000175100017510000000246012271304167024577 0ustar locutuslocutus View Source Code

    Source Code for Basic Arithmetic Example

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/basic-comparisons.html0000644000175100017510000000246312271304167025006 0ustar locutuslocutus View Source Code

    Source Code for Basic Comparisons Example

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/el/basic-arithmetic.jsp0000644000175100017510000000452212271304167024430 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> JSP 2.0 Expression Language - Basic Arithmetic

    JSP 2.0 Expression Language - Basic Arithmetic


    This example illustrates basic Expression Language arithmetic. Addition (+), subtraction (-), multiplication (*), division (/ or div), and modulus (% or mod) are all supported. Error conditions, like division by zero, are handled gracefully.
    EL Expression Result
    \${1} ${1}
    \${1 + 2} ${1 + 2}
    \${1.2 + 2.3} ${1.2 + 2.3}
    \${1.2E4 + 1.4} ${1.2E4 + 1.4}
    \${-4 - 2} ${-4 - 2}
    \${21 * 2} ${21 * 2}
    \${3/4} ${3/4}
    \${3 div 4} ${3 div 4}
    \${3/0} ${3/0}
    \${10%4} ${10%4}
    \${10 mod 4} ${10 mod 4}
    \${(1==2) ? 3 : 4} ${(1==2) ? 3 : 4}
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/misc/0000755000175100017510000000000012301126372021024 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsp2/misc/prelude.jspf0000644000175100017510000000154312271304167023361 0ustar locutuslocutus
    This banner included with <include-prelude>

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/misc/config.jsp0000644000175100017510000000307512271304167023022 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="my" uri="http://tomcat.apache.org/jsp2-example-taglib"%>

    JSP 2.0 Examples - JSP Configuration


    Using a <jsp-property-group> element in the web.xml deployment descriptor, this JSP page has been configured in the following ways:

    • Uses <include-prelude> to include the top banner.
    • Uses <include-coda> to include the bottom banner.
    • Uses <scripting-invalid> true to disable <% scripting %> elements
    • Uses <el-ignored> true to disable ${EL} elements
    • Uses <page-encoding> ISO-8859-1 to set the page encoding (though this is the default anyway)
    There are various other configuration options that can be used. tomcat7-7.0.52/webapps/examples/jsp/jsp2/misc/coda.jspf0000644000175100017510000000154012271304167022624 0ustar locutuslocutus
    This banner included with <include-coda>

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/misc/dynamicattrs.html0000644000175100017510000000263412271304167024427 0ustar locutuslocutus View Source Code

    Source Code for dynamicattrs.jsp

    Source Code for EchoAttributesTag.java

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/misc/dynamicattrs.jsp0000644000175100017510000000313312271304167024252 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="my" uri="http://tomcat.apache.org/jsp2-example-taglib"%> JSP 2.0 Examples - Dynamic Attributes

    JSP 2.0 Examples - Dynamic Attributes


    This JSP page invokes a custom tag that accepts a dynamic set of attributes. The tag echoes the name and value of all attributes passed to it.


    Invocation 1 (six attributes)

    Invocation 2 (zero attributes)

    Invocation 3 (three attributes)

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/misc/config.html0000644000175100017510000000272712271304167023175 0ustar locutuslocutus View Source Code

    Source Code for config.jsp

    Source Code for prelude.jspf

    Source Code for coda.jspf

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/simpletag/0000755000175100017510000000000012301126372022056 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsp2/simpletag/repeat.html0000644000175100017510000000263612271304167024241 0ustar locutuslocutus View Source Code

    Source Code for the Repeat Tag Example JSP

    Source Code for the Repeat SimpleTag Handler

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/simpletag/repeat.jsp0000644000175100017510000000326012271304167024063 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="mytag" uri="/WEB-INF/jsp2/jsp2-example-taglib.tld" %> JSP 2.0 Examples - Repeat SimpleTag Handler

    JSP 2.0 Examples - Repeat SimpleTag Handler


    This tag handler accepts a "num" parameter and repeats the body of the tag "num" times. It's a simple example, but the implementation of such a tag in JSP 2.0 is substantially simpler than the equivalent JSP 1.2-style classic tag handler.

    The body of the tag is encapsulated in a "JSP Fragment" and passed to the tag handler, which then executes it five times, inside a for loop. The tag handler passes in the current invocation in a scoped variable called count, which can be accessed using the EL.


    Result:
    Invocation ${count} of 5
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/simpletag/hello.html0000644000175100017510000000265212271304167024062 0ustar locutuslocutus View Source Code

    Source Code for the Hello World Tag Example JSP

    Source Code for the Hello World SimpleTag Handler

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/simpletag/book.html0000644000175100017510000000315112271304167023704 0ustar locutuslocutus View Source Code

    Source Code for the Book Example JSP

    Source Code for the FindBook SimpleTag Handler

    Source Code for BookBean

    Source Code for the EL Functions

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/simpletag/hello.jsp0000644000175100017510000000232612271304167023710 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="mytag" uri="/WEB-INF/jsp2/jsp2-example-taglib.tld" %> JSP 2.0 Examples - Hello World SimpleTag Handler

    JSP 2.0 Examples - Hello World SimpleTag Handler


    This tag handler simply echos "Hello, World!" It's an example of a very basic SimpleTag handler with no body.


    Result: tomcat7-7.0.52/webapps/examples/jsp/jsp2/simpletag/book.jsp0000644000175100017510000000346312271304167023542 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="my" uri="/WEB-INF/jsp2/jsp2-example-taglib.tld" %> JSP 2.0 Examples - Book SimpleTag Handler

    JSP 2.0 Examples - Book SimpleTag Handler


    Illustrates a semi-realistic use of SimpleTag and the Expression Language. First, a <my:findBook> tag is invoked to populate the page context with a BookBean. Then, the books fields are printed in all caps.


    Result:
    Field Value Capitalized
    Title ${book.title} ${my:caps(book.title)}
    Author ${book.author} ${my:caps(book.author)}
    ISBN ${book.isbn} ${my:caps(book.isbn)}
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/tagfiles/0000755000175100017510000000000012301126372021667 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsp2/tagfiles/panel.jsp0000644000175100017510000000416012271304167023513 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> JSP 2.0 Examples - Panels using Tag Files

    JSP 2.0 Examples - Panels using Tag Files


    This JSP page invokes a custom tag that draws a panel around the contents of the tag body. Normally, such a tag implementation would require a Java class with many println() statements, outputting HTML. Instead, we can use a .tag file as a template, and we don't need to write a single line of Java or even a TLD!


    First panel.
    Second panel.
    Second panel.
    Second panel.
    Second panel.
    Third panel.
    A panel in a panel. Third panel.
    tomcat7-7.0.52/webapps/examples/jsp/jsp2/tagfiles/products.jsp0000644000175100017510000000400012271304167024250 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> JSP 2.0 Examples - Display Products Tag File

    JSP 2.0 Examples - Display Products Tag File


    This JSP page invokes a tag file that displays a listing of products. The custom tag accepts two fragments that enable customization of appearance. One for when the product is on sale and one for normal price.

    The tag is invoked twice, using different styles


    Products

    Item: ${name}
    Price: ${price}
    Item: ${name}
    Was: ${origPrice}
    Now: ${salePrice}

    Products (Same tag, alternate style)

    ${name} @ ${price} ea. ${name} @ ${salePrice} ea. (was: ${origPrice}) tomcat7-7.0.52/webapps/examples/jsp/jsp2/tagfiles/products.html0000644000175100017510000000261212271304167024427 0ustar locutuslocutus View Source Code

    Source Code for products.jsp

    Source Code for displayProducts.tag

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/tagfiles/hello.html0000644000175100017510000000256712271304167023700 0ustar locutuslocutus View Source Code

    Source Code for hello.jsp

    Source Code for helloWorld.tag

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/tagfiles/hello.jsp0000644000175100017510000000262312271304167023521 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> JSP 2.0 Examples - Hello World Using a Tag File

    JSP 2.0 Examples - Hello World Using a Tag File


    This JSP page invokes a custom tag that simply echos "Hello, World!" The custom tag is generated from a tag file in the /WEB-INF/tags directory.

    Notice that we did not need to write a TLD for this tag. We just created /WEB-INF/tags/helloWorld.tag, imported it using the taglib directive, and used it!


    Result: tomcat7-7.0.52/webapps/examples/jsp/jsp2/tagfiles/panel.html0000644000175100017510000000255512271304167023671 0ustar locutuslocutus View Source Code

    Source Code for panel.jsp

    Source Code for panel.tag

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspattribute/0000755000175100017510000000000012301126372022611 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/jsp2/jspattribute/jspattribute.jsp0000644000175100017510000000347712271304167026070 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="my" uri="http://tomcat.apache.org/jsp2-example-taglib"%> JSP 2.0 Examples - jsp:attribute and jsp:body

    JSP 2.0 Examples - jsp:attribute and jsp:body


    The new <jsp:attribute> and <jsp:body> standard actions can be used to specify the value of any standard action or custom action attribute.

    This example uses the <jsp:attribute> standard action to use the output of a custom action invocation (one that simply outputs "Hello, World!") to set the value of a bean property. This would normally require an intermediary step, such as using JSTL's <c:set> action.


    Bean created! Setting foo.bar...

    Result: ${foo.bar} tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspattribute/jspattribute.html0000644000175100017510000000301112271304167026220 0ustar locutuslocutus View Source Code

    Source Code for jspattribute.jsp

    Source Code for HelloWorldSimpleTag.java

    Source Code for FooBean.java

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspattribute/shuffle.html0000644000175100017510000000300012271304167025132 0ustar locutuslocutus View Source Code

    Source Code for shuffle.jsp

    Source Code for ShuffleSimpleTag.java

    Source Code for TileSimpleTag.java

    tomcat7-7.0.52/webapps/examples/jsp/jsp2/jspattribute/shuffle.jsp0000644000175100017510000000662112271304167024776 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib prefix="my" uri="http://tomcat.apache.org/jsp2-example-taglib"%> JSP 2.0 Examples - Shuffle Example

    JSP 2.0 Examples - Shuffle Example


    Try reloading the page a few times. Both the rows and the columns are shuffled and appear different each time.

    Here's how the code works. The SimpleTag handler called <my:shuffle> accepts three attributes. Each attribute is a JSP Fragment, meaning it is a fragment of JSP code that can be dynamically executed by the shuffle tag handler on demand. The shuffle tag handler executes the three fragments in a random order. To shuffle both the rows and the columns, the shuffle tag is used with itself as a parameter.


    tomcat7-7.0.52/webapps/examples/jsp/cal/0000755000175100017510000000000012301126372017752 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/cal/cal1.jsp0000644000175100017510000000437212271304167021324 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Calendar: A JSP APPLICATION <%@ page language="java" import="cal.*" %> <% table.processRequest(request); if (table.getProcessError() == false) { %>
    prev Calendar:<%= table.getDate() %> next
    <% for(int i=0; i <% } %>
    Time Appointment
    > <%= entr.getHour() %> > <% out.print(util.HTMLFilter.filter(entr.getDescription())); %>

    <% out.print(util.HTMLFilter.filter(table.getName())); %> : <% out.print(util.HTMLFilter.filter(table.getEmail())); %>
    <% } else { %> You must enter your name and email address correctly. <% } %> tomcat7-7.0.52/webapps/examples/jsp/cal/calendar.html0000644000175100017510000000316612271304167022425 0ustar locutuslocutus Untitled Document

    Source Code for Calendar Example.

    cal1.jsp

    cal2.jsp


    Beans.

    TableBean

    Entries

    Entry

    tomcat7-7.0.52/webapps/examples/jsp/cal/cal2.jsp0000644000175100017510000000270212271304167021320 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Calendar: A JSP APPLICATION <% String time = request.getParameter ("time"); %> Please add the following event:

    Date <%= table.getDate() %>
    Time <%= util.HTMLFilter.filter(time) %>





    Description of the event


    tomcat7-7.0.52/webapps/examples/jsp/cal/login.html0000644000175100017510000000274612271304167021767 0ustar locutuslocutus Login page for the calendar.
    Please Enter the following information:
    Name
    Email

    Note: This application does not implement the complete functionality of a typical calendar application. It demonstrates a way JSP can be used with html tables and forms.
    tomcat7-7.0.52/webapps/examples/jsp/include/0000755000175100017510000000000012301126372020636 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/include/inc.html0000644000175100017510000000241512271304167022305 0ustar locutuslocutus Untitled Document

    Source Code for Include Example

    tomcat7-7.0.52/webapps/examples/jsp/include/foo.jsp0000644000175100017510000000154212271304167022147 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%= System.currentTimeMillis() %> tomcat7-7.0.52/webapps/examples/jsp/include/include.jsp0000644000175100017510000000215612271304167023011 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ page buffer="5kb" autoFlush="false" %>

    In place evaluation of another JSP which gives you the current time: <%@ include file="foo.jsp" %>

    by including the output of another JSP: :-) tomcat7-7.0.52/webapps/examples/jsp/include/foo.html0000644000175100017510000000146112271304167022317 0ustar locutuslocutus To get the current time in ms tomcat7-7.0.52/webapps/examples/jsp/num/0000755000175100017510000000000012301126372020012 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/num/numguess.html0000644000175100017510000000255412271304167022562 0ustar locutuslocutus Untitled Document

    Source Code for Numguess Example

    tomcat7-7.0.52/webapps/examples/jsp/num/numguess.jsp0000644000175100017510000000362212271304167022407 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. Number Guess Game Written by Jason Hunter, CTO, K&A Software http://www.servlets.com --%> <%@ page import = "num.NumberGuessBean" %> Number Guess <% if (numguess.getSuccess()) { %> Congratulations! You got it. And after just <%= numguess.getNumGuesses() %> tries.

    <% numguess.reset(); %> Care to try again? <% } else if (numguess.getNumGuesses() == 0) { %> Welcome to the Number Guess game.

    I'm thinking of a number between 1 and 100.

    What's your guess?
    <% } else { %> Good guess, but nope. Try <%= numguess.getHint() %>. You have made <%= numguess.getNumGuesses() %> guesses.

    I'm thinking of a number between 1 and 100.

    What's your guess?
    <% } %>
    tomcat7-7.0.52/webapps/examples/jsp/security/0000755000175100017510000000000012301126372021062 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/security/protected/0000755000175100017510000000000012301126372023053 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/jsp/security/protected/login.jsp0000644000175100017510000000256712271304167024721 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Login Page for Examples
    Username:
    Password:
    tomcat7-7.0.52/webapps/examples/jsp/security/protected/error.jsp0000644000175100017510000000174112271304167024733 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> Error Page For Examples Invalid username and/or password, please try again. tomcat7-7.0.52/webapps/examples/jsp/security/protected/index.jsp0000644000175100017510000000440212271304167024706 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <% if (request.getParameter("logoff") != null) { session.invalidate(); response.sendRedirect("index.jsp"); return; } %> Protected Page for Examples You are logged in as remote user <%= util.HTMLFilter.filter(request.getRemoteUser()) %> in session <%= session.getId() %>

    <% if (request.getUserPrincipal() != null) { %> Your user principal name is <%= util.HTMLFilter.filter(request.getUserPrincipal().getName()) %>

    <% } else { %> No user principal could be identified.

    <% } %> <% String role = request.getParameter("role"); if (role == null) role = ""; if (role.length() > 0) { if (request.isUserInRole(role)) { %> You have been granted role <%= util.HTMLFilter.filter(role) %>

    <% } else { %> You have not been granted role <%= util.HTMLFilter.filter(role) %>

    <% } } %> To check whether your username has been granted a particular role, enter it here:


    If you have configured this app for form-based authentication, you can log off by clicking here. This should cause you to be returned to the logon page after the redirect that is performed. tomcat7-7.0.52/webapps/examples/jsp/source.jsp0000644000175100017510000000167012271304167021243 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ taglib uri="http://tomcat.apache.org/example-taglib" prefix="eg" %> tomcat7-7.0.52/webapps/examples/websocket/0000755000175100017510000000000012301126372020405 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/websocket/chat.xhtml0000644000175100017510000001067312225771646022430 0ustar locutuslocutus Apache Tomcat WebSocket Examples: Chat

    Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!

    tomcat7-7.0.52/webapps/examples/websocket/drawboard.xhtml0000644000175100017510000011764512234202224023442 0ustar locutuslocutus Apache Tomcat WebSocket Examples: Drawboard
    Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!

    About Drawbord WebSocket Example

    This drawboard is a page where you can draw with your mouse or touch input (using different colors) and everybody else which has the page open will immediately see what you are drawing.
    If someone opens the page later, they will get the current room image (so they can see what was already drawn by other people).

    It uses asynchronous sending of messages so that it doesn't need separate threads for each client to send messages (this needs NIO or APR connector to be used).
    Each "Room" (where the drawing happens) uses a ReentrantLock to synchronize access (currently, only a single Room is implemented).

    When you open the page, first you will receive a binary websocket message containing the current room image as PNG image. After that, you will receive string messages that contain the drawing actions (line from x1,y1 to x2,y2).
    Note that it currently only uses simple string messages instead of JSON because I did not want to introduce a dependency on a JSON lib.

    It uses synchronization mechanisms to ensure that the final image will look the same for every user, regardless of what their network latency/speed is – e.g. if two user draw at the same time on the same place, the server will decide which line was the first one, and that will be reflected on every client.

    tomcat7-7.0.52/webapps/examples/websocket/echo.xhtml0000644000175100017510000001411212225771646022417 0ustar locutuslocutus Apache Tomcat WebSocket Examples: Echo

    Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!

    Connect to service implemented using:
    tomcat7-7.0.52/webapps/examples/websocket/index.xhtml0000644000175100017510000000236412225776450022614 0ustar locutuslocutus Apache Tomcat WebSocket Examples

    Apache Tomcat WebSocket Examples

    tomcat7-7.0.52/webapps/examples/websocket/snake.xhtml0000644000175100017510000002235212225771646022607 0ustar locutuslocutus Apache Tomcat WebSocket Examples: Multiplayer Snake

    Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable Javascript and reload this page!

    tomcat7-7.0.52/webapps/examples/servlets/0000755000175100017510000000000012301126373020267 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/servlets/images/0000755000175100017510000000000012301126373021534 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/servlets/images/return.gif0000644000175100017510000000231710457676032023561 0ustar locutuslocutusGIF89a!!!)))999JJJRRRZZZccckkksss{{{JBB911)!!199!!!ZcJR199B)1s)1!){sZR)1)!JZ!!BRZscRkccRJ19!k9)1)!)BR)!!!{9Js{Rkk!JZ1sJB1))!)!s!Rk!!)9skRZR9J!!1B{B{1c{!)BZ)9Z{!1!1J9BJsksZRZ!!!,@ HP x 13RhN T9zTT)@aR'1@[0 a7PrQJBJRQTdT`iL@4@4~Qȇ=p# LNhiC $ 1Z臖*ZC<|q|,% /^@h%S1@!44%!\Qʄ5$`@*ea]$r!n8xndY#)V(P <`CD&(0"2TQbQG4C!,$TPy]C-$ E<T  )W`2rjԁFT0`G! ;̑G)TU)aC 5a}EIuG(;tomcat7-7.0.52/webapps/examples/servlets/images/code.gif0000644000175100017510000000044410457676032023153 0ustar locutuslocutusGIF89afff3f33ff3f3333f333ffff33f3f33333!,@ d)&Sb@"H#O: `)Q.4G$Upm#\()bRrPMI\BZ];y,DbD  avG Ar41 &.hI P `A.{ 8=~9xaUyC!;tomcat7-7.0.52/webapps/examples/servlets/images/execute.gif0000644000175100017510000000233210457676032023701 0ustar locutuslocutusGIF89a!!!)))111999BBBJJJRRRZZZccckkksssνƽZRR{kkB991)))!!J99!9))1!!{scRJJ91{kc9)!scZ1!{cRZB1{sB91cRBB1!!R9!){skskc{kZ91)scR1)!ZJ9{cJcJ1{Z9ZB)1!kBkcZJB9)!kJ!{ckZBkJZB!R9cR9c1B1sR!Z9{JkRB)sZ1kR)R9J1{kB9){c9!{scZRB{Z91!kZ9{JcR1ZJ)RB!sZ)J9c!{kcRJB11))!k1kRsc9kZ1cR)RB{sZskRZR991kJB!ssk{ccZ11)ccR))!11!!!))!!ƌRRZJJR99B))1!!)!))9!!191B!){s{cZc9191)1)!)!!!,@+@0!B@aTÇ 9b#ItTPT PFʜR0 LTrgQ(Uj95԰ eʣ)h Servlet Examples Servlet Examples with Code

    This is a collection of examples which demonstrate some of the more frequently used parts of the Servlet API. Familiarity with the Java(tm) Programming Language is assumed.

    These examples will only work when viewed via an http URL. They will not work if you are viewing these pages via a "file://..." URL. Please refer to the README file provide with this Tomcat release regarding how to configure and start the provided web server.

    Wherever you see a form, enter some data and see how the servlet reacts. When playing with the Cookie and Session Examples, jump back to the Headers Example to see exactly what your browser is sending the server.

    To navigate your way through the examples, the following icons will help:
     
    Execute the example
    Look at the source code for the example
    Return to this screen

    Tip: To see the cookie interactions with your browser, try turning on the "notify when setting a cookie" option in your browser preferences. This will let you see when a session is created and give some feedback when looking at the cookie demo.
     
    Hello World Execute Source
    Request Info Execute Source
    Request Headers Execute Source
    Request Parameters Execute Source
    Cookies Execute Source
    Sessions Execute Source

    Note: The source code for these examples does not contain all of the source code that is actually in the example, only the important sections of code. Code not important to understand the example has been removed for clarity. tomcat7-7.0.52/webapps/examples/servlets/cookies.html0000644000175100017510000000517012271304167022621 0ustar locutuslocutus Untitled Document

    Source Code for Cookie Example

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class CookieExample extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
        {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
    
            // print out cookies
    
            Cookie[] cookies = request.getCookies();
            for (int i = 0; i < cookies.length; i++) {
                Cookie c = cookies[i];
                String name = c.getName();
                String value = c.getValue();
                out.println(name + " = " + value);
            }
    
            // set a cookie
    
            String name = request.getParameter("cookieName");
            if (name != null && name.length() > 0) {
                String value = request.getParameter("cookieValue");
                Cookie c = new Cookie(name, value);
                response.addCookie(c);
            }
        }
    }
    tomcat7-7.0.52/webapps/examples/servlets/reqinfo.html0000644000175100017510000000702612271304167022632 0ustar locutuslocutus Untitled Document

    Source Code for Request Info Example

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class RequestInfo extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
        {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html>");
            out.println("<body>");
            out.println("<head>");
            out.println("<title>Request Information Example</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h3>Request Information Example</h3>");
            out.println("Method: " + request.getMethod());
            out.println("Request URI: " + request.getRequestURI());
            out.println("Protocol: " + request.getProtocol());
            out.println("PathInfo: " + request.getPathInfo());
            out.println("Remote Address: " + request.getRemoteAddr());
            out.println("</body>");
            out.println("</html>");
        }
    
        /**
         * We are going to perform the same operations for POST requests
         * as for GET methods, so this method just sends the request to
         * the doGet method.
         */
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
        {
            doGet(request, response);
        }
    }
    tomcat7-7.0.52/webapps/examples/servlets/reqparams.html0000644000175100017510000001073412271304167023162 0ustar locutuslocutus Untitled Document

    Source Code for Request Parameter Example

    import java.io.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class RequestParamExample extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
        {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Request Parameters Example</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h3>Request Parameters Example</h3>");
            out.println("Parameters in this request:<br>");
            if (firstName != null || lastName != null) {
                out.println("First Name:");
                out.println(" = " + HTMLFilter.filter(firstName) + "<br>");
                out.println("Last Name:");
                out.println(" = " + HTMLFilter.filter(lastName));
            } else {
                out.println("No Parameters, Please enter some");
            }
            out.println("<P>");
            out.print("<form action=\"");
            out.print("RequestParamExample\" ");
            out.println("method=POST>");
            out.println("First Name:");
            out.println("<input type=text size=20 name=firstname>");
            out.println("<br>");
            out.println("Last Name:");
            out.println("<input type=text size=20 name=lastname>");
            out.println("<br>");
            out.println("<input type=submit>");
            out.println("</form>");
            out.println("</body>");
            out.println("</html>");
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse res)
        throws IOException, ServletException
        {
            doGet(request, response);
        }
    }
    tomcat7-7.0.52/webapps/examples/servlets/reqheaders.html0000644000175100017510000000431712271304167023312 0ustar locutuslocutus Untitled Document

    Source Code for RequestHeader Example

    import java.io.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class RequestHeaderExample extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
        {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            Enumeration e = request.getHeaderNames();
            while (e.hasMoreElements()) {
                String name = (String)e.nextElement();
                String value = request.getHeader(name);
                out.println(name + " = " + value);
            }
        }
    }
    tomcat7-7.0.52/webapps/examples/servlets/helloworld.html0000644000175100017510000000500212271304167023332 0ustar locutuslocutus Untitled Document

    Source Code for HelloWorld Example

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class HelloWorld extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
        {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Hello World!</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Hello World!</h1>");
            out.println("</body>");
            out.println("</html>");
        }
    }
    tomcat7-7.0.52/webapps/examples/servlets/sessions.html0000644000175100017510000000617512271304167023041 0ustar locutuslocutus Untitled Document

    Source Code for Session Example

    import java.io.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class SessionExample extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException
        {
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
    
            HttpSession session = request.getSession(true);
    
            // print session info
    
            Date created = new Date(session.getCreationTime());
            Date accessed = new Date(session.getLastAccessedTime());
            out.println("ID " + session.getId());
            out.println("Created: " + created);
            out.println("Last Accessed: " + accessed);
    
            // set session info if needed
    
            String dataName = request.getParameter("dataName");
            if (dataName != null && dataName.length() > 0) {
                String dataValue = request.getParameter("dataValue");
                session.setAttribute(dataName, dataValue);
            }
    
            // print session contents
    
            Enumeration e = session.getAttributeNames();
            while (e.hasMoreElements()) {
                String name = (String)e.nextElement();
                String value = session.getAttribute(name).toString();
                out.println(name + " = " + value);
            }
        }
    }
    tomcat7-7.0.52/webapps/examples/websocket-deprecated/0000755000175100017510000000000012301126372022503 5ustar locutuslocutustomcat7-7.0.52/webapps/examples/websocket-deprecated/index.html0000644000175100017510000000256312227601423024510 0ustar locutuslocutus Apache Tomcat Deprecated WebSocket Examples

    Apache Tomcat Deprecated WebSocket Examples

    This API has been deprecated. The examples are also available using the JSR 356 Java WebSocket 1.0 API.

    tomcat7-7.0.52/webapps/examples/websocket-deprecated/chat.html0000644000175100017510000000772112217363077024332 0ustar locutuslocutus Apache Tomcat WebSocket Examples: Chat

    tomcat7-7.0.52/webapps/examples/websocket-deprecated/snake.html0000644000175100017510000002177612217363077024522 0ustar locutuslocutus Apache Tomcat WebSocket Examples: Multiplayer Snake
    tomcat7-7.0.52/webapps/examples/websocket-deprecated/echo.html0000644000175100017510000001303212217363077024321 0ustar locutuslocutus Apache Tomcat WebSocket Examples: Echo
    Connect using:
    tomcat7-7.0.52/webapps/ROOT/0000755000175100017510000000000012301126373015365 5ustar locutuslocutustomcat7-7.0.52/webapps/ROOT/bg-nav.png0000644000175100017510000000257111472002616017253 0ustar locutuslocutusPNG  IHDR 2eJ}iCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  1IDATH [ ?n =Nj?r%.cDd^u|]#&#:O XNЂda ΐ+8QMor.<ADo:olXZX,5On9YQkLj\JhO*T~oV /=la - Bie  ScBFi.1YHS!kLkU=0, U{b/;QRH"d!kb첈2,(+ضkqGz@z3m%_+$Lc~#qTW=BhCgSyN*i}T&[#snh|uW~+kXẬڕ%=a5s3?ETg{YCz_m=?ƥ`IENDB`tomcat7-7.0.52/webapps/ROOT/tomcat.png0000644000175100017510000001175711472003300017365 0ustar locutuslocutusPNG  IHDR\J pHYs  IDATx]klSg~$F8tdZw I*jvÏ!7 12b] !QQiN;i 3?H!m6ݑԪSS"uh(g8;c֯dƷsy{ xXUSŬbB2dVT1'A=#yPP(Xc}rGH:<_je\%O2M &n;n@oH 'Sny݅B!FWO Cpf~_sc!Y]0ceWU31 rE3 cX, 0%iEw:umkn]ֺis?r=d14gEw/}m6ֺ >/5 @si}R62rɯ )0aC+ " wBΟW 1ȁ*$E'soulmŲfEҬ]<X,l#9soD7_|aGJ๲ B Q5|]hmݒrC8JERWQJ,]St)7ohw6[9-@HY(4_^UwwBټ o$Z72=^\G6>OՍ"tQ]>[ iuNs`)־|uc$%eI~Hȥy֯SH T5}OGyE~9,vUJ=Ay=n9._ 0}p5|,rBr:8EKmTVVd)ёR;hlN/4๲(+nh=DО ll |'1$Oc 㓯~j8:3R:'V:pmHVkRXII|OR9Ѯ☍nFC @tM(y 吹r /4<4fjfF\?}5pkFB)Yİsum9+=d$i% ;H-N&*Z7W;QYYi1 CS7qhN$kv-M)1<#)L?W 'aW`Etb6tDc3 ?0m@5EV/X_{e&Bs邵)`"51-:K [@ uUbŋɾ$r5M ~_3v`$-teBVK&+7'M=&;hV:~r H"6]($)F9UÚ؉an$j+u<&BFWos3:oi3JB+-}nƖ %@$nFwy|pilhȸv MDN|ŒH۸0}`sewEk9Haf5}ϴ f١tbMnH6iSyE&BDbV~zhi*}|(rT@&7fhZ[hfm흐kLI;hl&NWg"hHD. F ir:x麖92owwif#hlhPzZ5`w'E$iD|ZlM -D4lO :I\ݫ[@46cwG!aё(CzܚX/H}} ނ"w.fI&3$3#wӦp!mFc=-R'رwBsQh&{$B65,E6Wh"?=$]zܼ_]QD<Ĵ D_÷Ocf5f+LyY|c8jjy帚؈/''MUHa9MR.9:Ŏ) zզ2wm)7Î]뒺2rDQq }=+Wd-N!M! R̹d%f p߾3'C` :?:KۇTu-]|! 2FZ;;V7x,Y1O m#f <5u x yvOGƁ |M}FchQMƂL{%YUuiXUu 4g5 TH=N;Ikf|xy=nȉgzM%8ԏ._îXp *ը)rXkt^]#e?&GoxKpUIKS)*氈Uc {b4dG-P5߽W?/v\ReO/>2`͙aǥW3^6ÎE g'nNOp)vy#RjT V7 %$Odd g8fj+p\ ߽Dc3睎b{&BT˪l%Dp\q;PNR9WTh!z=n464XF0F":z;@WD1ZH;v>qZ;FeC'.t0neRwH)+ ȵz5e5br jM&-JGGl'eNp|p0+\qoP-VņE~giI\z|V!  d(- +>|^*WF9,%ֵ{/mT՚>#Ef.]?T+ټm:ߟ&ޔ$2zX"1kH}|rt}i{NڱERzW0!>/S()YYټg4痔hCgEf\l6*++-ual"$ ;ŢQ WzVUiCgHLHWƏ!i8f֬衶5,:r2룏GiZ@!^D\U #n]׹_Qצ;i|Rw:O|fZi Db6@Bhk("LlF65 ,@k]"t{ ،n)7Gλ}s*\.HWF".V`,43(C"W}[5$e-нSPmn׏L w:Y0M$]]h&}g9LVNHW }!zYT"s}g9::E Ua˦Htƚ=/[!?2oz iF⃈mM߳z1[.g:]}gNJH^NmMߧP<]LL٘#x|f"`Uk"vvkXe%X7-v=,".ٌ۬+W=Hئ7tiEw"47ښ\ڭB"?~zMt[mtLIj+رb vIDAm){.SH!Eu&@Є.ĆBuu \oZFWr˒ 9M ti&'Lkhq-""$GKy=nEZᡏ$Eon+|?9qӃI1/#3 NF,`JJC|sNҮ+يhG)mK`R$~ tGp8tlmQ-OJ P)f/*@e Xej^c4$$ $9]vGQ Rw֖vog+ћ-L@E4B˷蕦RJW,$MW L@eۚfBt*MZ\dS* A_s#$ĥef*|=<lHPD:!^ c@ -eH $ oC]x & ҄tFa,#]uT4OѺn'`^$[,,+gSYYi;lL-zv@bk3_\.LF4:ڇDjUBtFi)vq{VfHt#m'{f-jFࠪw#n62:I}͜/mBU3@ffu]Fêb$:(BَHĖJM9|A,@PPtus#Y*Eɒ%g* 0)C fW@2ع\7 EmR{'m<aٜPm6@ uR@8߭5W;uβz1H.ȉ\5!a E~4:vWf\N`-{`J`편Or擓3m`q׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  IDAThr6 Dco=gZθ4L,bA}Zg3? 薟.ӗ |xף/lbn0o$(k4\L.ID|Ю}2H%[*+aHg奰dt0ͣA?ؓvNI "380~#0 @FGO`8,/#Y;?P!?3VpGRʻME!c D[ [&Pou c"Ư'D0#K/uQ9)\ʗy~M3k`g @!Hozn p?Ori{Y&yLz2Q> 5I t~! +q|h=Y*](ZxPBMfH՚0CjVV|p`+´\g9iE@X烮w!Zu|0D`.HLd0toz]Hola4dgLa|'s6] W+5@(A0;Ԩh#}f6u{x>219\e]AO 3On(C`)4b1V ʋ\;GP"g &%=$QAIp3%zNʏgS el`ZWr Pr+p4ώgǸ`$?JH{lXB)\j;Y x'* 梾c8-kz RK eьQTpǴA ~$*dl^ RER9!ǒ;&mJfUgW` I5}WSf5dB^2) ܸ~ 73V_ff_aVʟ\sXfPMS'*h>P;"N@1F9lNn(W(E*Q4A?XD;}⑔ xÀ35)qw+=rխa5"Ƕ}n2WU}!f|)G Āuࣨ(q[7(f 2b#> 9̾?bj&C袏2MAe.})L'EH0Z#ye!3$~Ԇ($nYYJԨ Ԯ7je~pUgEIkiLore].pČ*}2vֈճ5n-bZ(==^vCi3xr"$1M&j}t(h˗(GG[8 s&6αFfl6HM=5!")%["}a2.C﵌Gt>Wt$8M $zUAk:'r-vSBE3+tڇ>u 7a|3>l,p IC42o$ #-Uȹ8W虘V*q3y:aB{AeDWS{Mzu=u1ꗦ$yQS nkbթ.{FȪVR{lWhVcV{Q,FRa]hU({aܕ#iZ蛆&ʔv6;#++H$c}io)mq4wcj>4](AM%] (䙘׳c7 +RRdoEd9=Y.+7rf% YeC~#\ "W3+]VHV#O='a=:D BԽ1tӤeAB_Yy],XO{P',0(/QlFR8(aLRHL4ya1~t᝭PE}i2/g?(Vy 0bz9>p#pf̌A= #6=Ǎi8&gVEm,E2\'V.O}?fp#( d1J]T`u:yL3_nh(],9/#M+=1[og|(3E)[_UTDOs}~ߓ H )0?'C:~~3#oԿi s6qIENDB`tomcat7-7.0.52/webapps/ROOT/bg-button.png0000644000175100017510000000131111472002616017771 0ustar locutuslocutusPNG  IHDRV tEXtSoftwareAdobe ImageReadyqe<kIDATxMP5Z7S$ E ?e~B.w_W]ܶ]HEi+63m'ژ\ԅt}{ovsΕ{DoDdHG Dܐ|!`0x>8F|ncn_߁IĐ9nLQ],yV{J+Ҋ$R"GF BO Vu E Ul~-1B_ŴX,3:KFӴSI}GbL.~I['0HZ@?AR2E-~D$s!~ $8A@!t݁ Í   (1%PbgpA{dp( :lw4/Ac2|~/h􅘖J B_l۞2/jdL|0ŗn e"ܰ҇+I2&+>8z/;N,/dy[)rR. _tf,0{'ҜO%IJ$և&LvD6k; &!$.Ns=uvML@LDIENDB`tomcat7-7.0.52/webapps/ROOT/tomcat.gif0000644000175100017510000000402211471741013017342 0ustar locutuslocutusGIF89a\Ҧ)u" GB4pl^Wr+дbp.!,\ dihbQ(l,LPC@>pxRq !Q_7eZ%HH`e %νJn_k(q4:Οbc7}" umx?"QU4 uGq[^&U&_[ Z'Z[wXD _ `mǩПV tu( Gd# ͿCGpv@3`@1`R ǏcU^5~tTxw̵ܜ֊YwQ H{n͛3L8nÝ2?n+:Pyտ숇OI5[pW/*@)otle-{a :U0/t$Y/a2Y΃_! D@f=@y@J׫L8 S gXP:$Pd>ډ`DN cB%1@PUE)CH" '"m0c b,8^qsٯ8 "ŇF.$fR98 $P!d 2I}Y%?.J2~`[ C'?Ia( 5aʂ聴LI̘Z FJ,%r`s]8rl6#L*<Ci~(fK0D+Zc 鎆m`jZc(ajE!ShzկJjNrKՀ V' x}Ho*$~C2.kHe 4HV%mH8anU]Q[+g4N {IPD=[!ʴ @!(S"gkZN?XƔ B{5?C@GI&_@w9e}# o:Mw9Q+ 4bg?xɍIc!;tomcat7-7.0.52/webapps/ROOT/asf-logo.png0000644000175100017510000004262311472002616017612 0ustar locutuslocutusPNG  IHDR(rKtEXtSoftwareAdobe ImageReadyqe<E5IDATx}xTE̽w{v7{(M)STQl(*]"UzM !!4Hm?Ʌ$ "|??G\fΝr;93w.8]6a% )7ܔ|#roM)7"juW򆺖z:z*-2:Kى7ܔcnj:mZ^~njNMK;yVgZBMvfr  fftܔj޼y_|m&O3 }2HCF"(k!UUU[n5f̘q>p˖-`w*̙|}}WXu}w@iӦ͜9.-VOfJ %XH߾? c \>u0!O @~w{M+0Wy}J? [v-daÆ9H8Vxg K.VuHpû_~۶-ٹMBlIII0xxx\}Qg͝Ly衇֯_W_UVV?nj3r5=S=w}r\/P^x*%ܾ};\Hҗ_~ٙd60a¤w?s='[o}L:zk֬{|IpۍYziZL@lM 2Čbt -97{ 1? ?8 s6/0։Y=m6oߟ|חdg䣏> O|%˖xyzAf#F@^zaSRRt)7@^xtIՁZCȎ? |e+<)ƆF qߎwOɵǟiR\.#|7kW#d/*:xessNYvݜ^0{ 8cdPPt/Ak98iisZJQ-Md{_οQL PN!%ŜN%+} c ASKTE͟s<{s}vzt@C]zjrw1XBtbSw*jٌNW].R?6xP>ݝ}>~5#b4A%RR:LW^+*˖p|x΄qnW,*v}K} C$ Z$ `#lLZK,"I_VP/ J1d 2)mEVBӸH(qXXpT@xa㇓9`"@I?ťũ1dkj枽{ϝ;wpҩT'j97:zx¸N {h bI&͟??00y/ry0Ƀ] L#]*g;vioÇ ,0`Jݷo{ϐ駟B5mǎSOGD23 ma RTTe䤉 v9v$N0O\˒bHkʔ)駍uu @={hgWZU__Nү_{@ء@U@%v\9lG~_e`_up06-X\ѫW)S<ىz:P#<<޼ysZZ:ڻw|k7٠Wg͚y_lw{1;;;i޽03w٬֭ohp Tlgg|Q[֭[S.\_;}؝F;wRysҾ ---0"#F5>??>Cee%hL0 kЁ7gΜu0S|xז@WN: Z3 6\.p[^ND6ٽI|#_2xג;ķn^D$Ud>}G6uF1( 8K+2rCYr%S֯_)O?4\ٳa$GE윜2.vwDz挙 T: ܵkgQC¯<|R\{YNUUՄQk%\7@9}||˦f ^wv]=0nx+n {=CRRүcWtw}CFk%|z2##J Ӂ_?#|V8pZg<1lc=$⳽ |"@0>qƌ|"`=o\Us=sKwQk4DDD\VON߸qW>!<ǏwN޻وr/o_0q/9\@%lyA.q,{@Э՜TK"+m‚<"A&;! J3!(2B҂$[&`I! F޴B%WW^sNL&fV^-L~嗿p^.Q.RV^(A/]2icG 'Tz饗h//(ܭsY&77O78dX uTS*cG/зp˚5kx{. 胇_k0^O@Z9#Q_닗C=)`> ~NP6XJt>wuHKJJ;kNͫ00jkk;FVAxH}x1+,t ЂRU|g}v̘NKu֧3~Q (ƍs/,CN:‹/.#K,m?\d:v'tv7[xh،8y»#fb3n/="殖y]:eղ$o?.)}xq1E!}IԠZj^A>0?i&0<%ߪrܝTkZo[|9{qO>9n;`Ygχ|55= ?xɚO<@sl`0<_Nʒ<83zh U:q')gSNb;0w~ߗ/T].\uBݽ/Ġ79r= \ؽP <18c5i>w;$yHw(3 誥z-gzyyRMF[>[__OtZŤIy/v u߫W/\>ٴi)s~ ^|`% sw]gKqOͧr„)0{)Nc'(gdd@ L`BWO\7<X_;`ߧٴ,w1b6:j5[6V%H1E4$5`ak#"0adnFT4d#9X,jeDP,8?Nid-fP` gĂj GoBUv N֮#|dU>V?ѻOuq=JY111Rx0nrC~SSNx{{66w{A ~CsN0];{ ܁;:A+;}߾szҹ :~&OۜqN9 τAEұSW_]̧wK;.דǏBLBRYS  0w|;>өQ0rD~eƹ\~OM@oN67Tybzmر<ڹ 7 , 0zgvo&R#ouF0 2P= p\ ?CMP$x Zi4b^(]g-,0~V=n&# z×M9y#F N=AejkkտvjEGwS pA^q9Q(аQQN./ÝԚGRNwRk =X/)HӀ-tS©),"!T>nJ-beC"U3(4EL6t.R" sDkd*%DyYٛ T\&NU-2S s0]aWԑ#G+.Š+@3gFeQK &[P>o;``M=+wΙ*]u(hkYO@ 6sÇ1 ?wx/3 h<4k^^^OE$5srrΟ?_p,X: x~;yРd_}յk)]*~K#RHoƌ^ 8.,<#5b_L[@w 9ñ[<xw930g`PPV<x?tA.-NxW˴/}Uv @EA++*DsP246%%H./sXk8/m¿}>ZQmmJ8q"I 0&&>01#wEE-[P_O9s&~+rTGsz\ޅ;mh0*cwvTemZ)ѪϷt! H yS*NVJdݐHl(7-6]E yMhNBr,#@rY1N 31uF5 ^LfVW\I s)ed8 Ө|V^ɹБjB60H55n߶^r6'BG/ؘX@p*5i,YP\'d(H|x~)ر`؊K`Ը+VVV%% rr[z9?QQQLhh(\x$vP^^c;K y ˂cdtt$8|0oB?>>}ޤz|^޷o_F//`ǠEQQQQѮweARP̙3y_BB8h[kScBzz:|\vVZR`sMbWqzĎ6\tp|VVVs:5C"c Mu-u FZD1[.l[v{:rU9ʽ^ ]MŵMvPazҲu"ކ%X:V_D²b72Ʉĉ+9r͉ cNKj)ғ%q2k/1'IA fⶥJ\t[!i=Baq7K&!)lPNbJb~?裁*ǟc-33#=--RM?sl2m'>t69k֬=s,rQ{vw&Lӵ`͘>c޼yV%[n?uUzU}rrAAᄃ~@*<_֮];mڴ&we^zk;p!g߿#R^z !)'Nlu _Όӯ~uc)S&C <eǏBwL\ 2tؖ_750Dfff`` XxZzՏ8 xhHhyE9tӞXd|B<4۶o۸qs_ '߰_4ջ7hˆK)'M χDv g޼f4 [m3٠x('O OߺekՃr y]-1by%M4&իWH߄jj*CK%;VckrxR^"V* "m^x ,kՒeil57BF"On Q,`>%EHaDW!e R{6pd2aw!wq2^4EZXu1y*~\[P0B'J!:sғPp?twG٨+G?^. Ɗ7d M8gב#GBMx}S:YKs]ɗ2w͸o, `k8?o6UfMzs /83u{m[o`Xfo^vW]!|[wo~Ш4zK3ppqKERX+>  LQO=1FrAT^k32yE=DFH=^'bց2)zHʎB= FX`Y~IG:7!RZ0}۹!JH \p f=jvx֭[h4rl jG ]͐`(>!xn,]|i* (->> fgzj6@#%5V#Y fv‹Afk4Y#{JBdnEX@:̉夿.2#c>jp"3 佑@T[:nBFqsROZU6ɼ8c(-DfCHtD" 4&xO qB٦ VDc \(fSSSa t,(+\XXX[[ :ro)'h<*OZ*`'. t 4᯾ZTTXUUﰍK't,y/x+JCsNX\(L0T8/3u}%;;P+N< ֧Oוޅ5NKKV^43g{ a2%레 I"`Ǒ00amСnށ|ܔrOw ¤kVOt{?_cF b#FBD4b,"ZJrFĕs"gRBB~^x٭@r }ZkcK9qBTK4 #AQZ2{rXRAi0gŜNH !(ƲzSYZ{cf̸s݈D_I*8˰=utezDD@"ս=2n r[egXR;S)9UKTܔ?;[A qK+ o~l$:A"Nq$f,BX琢jdq Ip 9Q/'HFĄL3%tY38~I @( y3܊$Ka8 £Rh!ȡF(Dzir  iJ1)T4@I (e?X=J'F !KDɌL ą6;Sv?xiR p=I쌵ߔrS૤&I* hhWubm2BGoRrW'cz)_[9p$P6c# .>Ny9XT8kD-6ֱ-6ԥ&dXڋHkXcJnA:aaa qv=ҪFVp@Z-a (YZ֊47΍AHK$4F#Bb{Hc#U"a$p$^uSnʿc#rϱa/+-m߼! '- E 6-40ŧN_Ng }ax5z:HAA;8Tc/iw+%K,f\@ 7N˖ِE BfEb EFI8)FkS3V7D{'zcs [noDQ"1UZi fZqviʀ>I^ERumg]8S!nrAׇzt:xW:*--wikjjৠ FrO)'w_LFmvA/^|!yj~AInЧÇ <=4YUZ|+@W`jv)Coap 7"Hɶs8dY n+vhHӑYakD#%4 zQ\XK:#>Or]ϳWi2FΒlכub?*TdDroۇbw "[)u,0KWLB% | ӱL0ZCŖLQ'"FbLJSH RE6IbCg(yQ{bBG.o:}%/6tgϾ+997N;qnWzMKb2\%;;;/'3)R"p`Hc6#uR?OSO,° ʇe){'"Bvh G a'XV636rpƲԮbj՗c-D&j)-@zD=Cyy^B,cF:6iqTl"m=Tg0v.5[t/kvn0ĈR9(NjEa[ľ!IQ)6iSdF!ӱLGV@ 9 t;_jw *Ev}FK7}]1OkI ?P@]/ os=>>>+Wֺh" `$M/0pp8ƸRJϗz{$= h<<&NU˖w O:5޼Qrn=9;_ݲe's]V*--ymٲ_7rx}eE PAﯮ*t=]&ϗtM?^]ԩӀ,omm{ZZ;KcǎX;&GFGȜ>}7wy9yy~; _ /f~WEASO8tK!?37SNq|ϗW`/\0`@];v~ (v{ttT`p>]U&MTacFw@H9s޸D(x#e54YeVIjBva{ce12I(:Fsb뀹!6F;(g:\¬2GY*.o09zL QoъK5ؽّ6&=dgʰHپg%Z)áVG!əq,g92X͡$bԱٌȒMAG9ZlQaF~> )(5yxKkfAek"z4g9Ph4>SOX__rJ`Oݗ ;͛c}ggv{4h{wpN==PwZ-FG; 쬆sPrP^-77Lz:3遁USbG֊srj WThpUs?GkkkEE~w`}&wǍ9j玝>kGyd۷wܼ~zGwqj * _tD"5jԌ3\?]޾tҗ^ziΜsxj8ssij @<#>{6 aW^gvxz?xaS&nςmI@iT~>9gGf54iI.)LW׺ v7JHpo"ꬿ9_3I9uMm973ĉj1"KĨa șñ@DgÎLXSCx8p΢c)%pbuzbOJeIQ孈czcB7`kYG/U.ؼ&sp&eVHg[?~df*4Vؑ]ND=.4zaKG̸~CcAAcѶ{K8\ {חo߾.x)Qf _nPtlbO*5=yСǎ6 Z1rܒٴ,}zC\^]6[P .>tcdž R]:0ub>YY,SȊr*26RΉǶ52juq&n#wVm{/A:|pVV_|GعqEW>r䧟~ ^jhx$pcƤ: ݽXb333?՟ٱkw}}㮲E?8 ]OZ׍:=wМ9a˖.`ѝ5ˀ:0pK_SNqc|v:t<ΟW,tc0OSs7&ִn| ?b;`bsnQ2 =`&f FtIJk=<4!S$G0 VC CGcrGG!U#0: ~.' 8[TiiD~4 bL[u>RȞ*ȈHaD5݊xD5"i1'=1th:p7uf_w7;+ͩSBD QRkBwIIm?p#YF]?hx(388/ԓ'Mpk0ջ~ U '"<>2agNH׶iWfͺC˺2l횵aЃs||$t_V^J(&r0yLƼ?vmyUϛϘ/׻wkK[nn.Kwjx+..N&EGslvqy#GΟߢǏ0j3P e=n'شk:w^ LK Fk}|#&M[SS[Q-%F9隶]O_}VQD$EYPBzRXTHIrı{I1@:Uj `NrH;C*D"d b(Ke -C9h@}cʼn0f v ʔ BYw.s9ekp|{77'w۶_>SN7o%M毿y9`tkkk<σjllw=1t楗^Gرcp 6;N_ĂcFFi޼GUf׎<0ٌ.*lݳu!G\J.I%X*W0TP耻I2FI2< ۫ pF\O.jF0$٭&j0TN{$*Ia ݛ! ]IzV#s(L-`,v0aAb1e[˪9# iI`<`hi1JZDI%Qh܄BL=ۆY-2r>>N}πS_{doooG0K0.00ѣEcǎu][ؘO]N ZvWaQa~~SO?QlS||'z].-rWBӧO*ADFE2W^=fVԓL0a\~443f,vH}%qVbbIIɑ#GCyzy޽P潕+C@iii'NkOO%a;~嗊ѣGC?w揍j ]^<ԙ"I&߿{ @p!JLxi>~@;<î̠AGN:]={+K=~={,Yr_QwLkfZjM6]/Y* QL6{h]"~:,QD5}$}ZFd+"$`/G+*7I(ݝNvW5Zh[FRTL0 i @AZ(P܅\[ARN<4@Ig7;)F-NfvTmU,}B1**CzmPGANE,88rE!s,`ZuCʡ64~kxKc6uO5k:|Mp(Ytɓ'},K!]s_sȎ* <ɓL07xb+ox`"]FBIR#F uf(Kdٓ= vjV0pDB&(ZRciKZ+'kl"mlU}S%Gre6$m#q"c[G=9p\Lԧ:Bv!3,,Z T<'  hnnn20puϷ խV=ԓ=. v,!ڒw:rJԑ#ny8rp J,b}bj!VYV󠆐ޤ]T7Vf{}I%+P.*=٬Q}/fZ308N&"E;F%Y-E8eeY$:> A 7Ļt~U$/& HJcS؁;v͑vG#_]?7MrSn_'ɚ MIENDB`tomcat7-7.0.52/webapps/ROOT/WEB-INF/0000755000175100017510000000000012301126373016414 5ustar locutuslocutustomcat7-7.0.52/webapps/ROOT/WEB-INF/web.xml0000644000175100017510000000231612271304167017722 0ustar locutuslocutus Welcome to Tomcat Welcome to Tomcat tomcat7-7.0.52/webapps/ROOT/asf-logo-wide.gif0000644000175100017510000001335210457676032020531 0ustar locutuslocutusGIF89a3OZ1DDDGZ }\RvwwFh78N> Q*jhxFk ? 2<{ l ^~%8kM%5A.0̤u.*y7W"+ŶѲM9&u&efgSVX˼333۽)!,3pH,Ȥrl:ШtJZجvz$.znE~R+?&$}e>>3N.-&?)$th>M&+-' 8C!;?# <Ä'QBNф^ŕb'I'48?8"# 2%;;ۍߪ\Lt8pUjPHF`F WN3NKtPo*GH#Z@#(kףx `DG$ YTNS5@ TQXDԓ}N3 ' Z$A#(F;=ƃ*^Xl/٭Bm* S>L6! Sg.,pҢ@*3r=YU` }j28w^S 4xaG>X%h*ᒘ&@2 d]: gj}M$6EgiyV PB -0dA9PA^{_P :1 GxCH$\L4؁QMA 0D@P25tS*5 A~HYH 'cI6*34DDjD 4lT&q]2&w @1DyB5eD D8&nQY.C .I% -0R%;; ``O6؁bdx"? M% R3O5:gR p# mGS-V DnmUMB>xT&u#Hg̮Wm9'2lۚ1^?bQC'l( m[F$ . pbfPVW6I`~pˮ胳>l*$ '0>lT0[+GMR\U 18R 5yg*ڷ-̵geӱ BTUDuEĪiEm@`@6c*Wο; h]cl4YXuJ@ oxv;~mc)~S  Sx9`\A9zZ'WT߈C&:M<0L4 a'&fȠЄ`G9}PatH/N׬ B2I@۔@>![>$k+1xȖipBX>"x=@󈰔U̎"]E8QQ-TהA<ԪB `OBչd*3YQQs8&dKQ uv =gІ83J KRb]+BMUJ3@`f0O^!ʘ@q(Eր8N3&)"0B-{"NDsCW8-C(8bKTX@^RAITL@fu$b]!S/0̆n;0* p.4i&1S][9mfWT+Z!pUD`J gH@1S;X8 Zt%YFrTYtV)7wDLU^`8+ e|KPn@ X =_ 9tf5*Jiq*{kYؓJ: IN?dMVw#EWN vRaOH;u[]i%Cf9K Sԇ6u0_0OTxd0k$;%HV" lȭ> 83E@v1 0$@t* .'f0JZjeť+H\bI7.EGT~dc,eⳜWH6돗+ȬVA|-Ĕŀ} !>*Q&@ Fh@P]h= .Ug4;uFDX\\$c f$uɫ }H:vQvHL.tQ W$.n D 8Hf3 Ze^U3eBAs^rK#xyg8 P 4`i%ĩ5Rj6F\ ʲG!C0a FRZD$pw{*oZ);_Պ o!({c~Ug8AUR6P ^`f A!l){_q9@e |\4`%~9TUynDK=IZ{$?YeHd'%+GwQ,2Ћ(wpYB&QZpQWЌ'p?]%&M ݰ?f- |33A8US'e)XS傦X3+!xȗ|#m `#0Thp[ q@$I$@h:` @8KdfY9Y8e_G|0Fti36;`L `P. e"yXe @8B BCULgY?4S5eŖt.ES!t+CY`!SiN|0a`ZRp@3?Pv!P1*Xl5\eXS_9E)b;q3#; |2 ^ĘIЛJJ`%}??)Wb(2T?[R/D೥$V Hǚ.LK-S.`GoU@[R , !ڥQŗ$Gaz*X$[&30p3B8PkO  j:S]0$w#dBxj5X˄>`QaZv5`O.bOVI P46 0(_OC#V&0ݣCSн+h]1B?RJ 3V.p%E,x+KSȔy:6uk iw;˯`9۫G;{wI,>P5i%{iGy;2 [-H"zVL`%uV:5& cb"9phf5xťVP Ҹy2(Z3T|z+>udYʣ+a%Pg@~Zں'| ZDtJ;gNMc P(|S.rEAc m (Ǫ}ƴm'R Zf}1 ` t|gFgftͲF2*o-h'pTz(@ MO' ZT<lGP~M%`;N`;D`r] Q4Ѹ7;2T`g81ngiwO}"Y ۍ0R.A {^y-U'nNo,Om ;I, Y>!V#[zgeT]Z47Dp|nmЄ%P#,=L5j#0 L M.RmuL%0/M:2 %IAMeN0OPrgP%_[}/oIPW`ʏX4It>QZ^Y:;tomcat7-7.0.52/webapps/ROOT/favicon.ico0000644000175100017510000005217610436617175017535 0ustar locutuslocutus (hh&  v 00h"00.)007( xxxwwwxwxxxwxx( @qelnfsnnypqnyunq|nkd]W]XCJNVO<5*,|}~uz}ft~\mwYYY "$BBBBBBBBBBBBBBBBBBBBB -BB ,/4BB(=A '2:1BB?7379;8.%BB(38820BB >65!$BB ,!#BB@  !BB&,*&+BB= <BBBBBBBBBBBBBBBBBBBBB( @嘥diӐWN~tz~ "$nD,X\mw8J?*7]yI44A]qe򂜧ft~OVspnn㓙ݹmlpqn݉YYYdnkfyuj|qnvy{|}~( @xxwpxwxwwxxwwxwwwwwwwwxxwwwwwwxwwxxxwxwwxxxwwwwwwxwxx( @pciacijkdZ]UT^kqrpqrmnnnqqonmnl{~jjkeheQJBKGKOXZS0:;367+'".s|oygxgwS}^z]vRzUvSs{||qy~sssku{mptgqwjnranxbmtiiiccc]t~[ozXksVlxRhtUdiMbnZ_dLZbYYYQY^PWYUUUHX_FSZMMMCCC>DF<<<59:048+./|||||||||||||||||||||||||||||||||||||||||  RBCp||l=D b@G@U ||B= nn ]AKJP||>ad|Z f>HHG]||b<t|q ]X=KKNDo||V>Q u||c SX>HLEENAV|| D=mTWYk>=GNLKHHKGTm||mGMMGTLENHHHHK=g5b|| ^;LKGXGHHHHHK?e#6|| TDGIHHNHNLGh9||  xGG>L=F=DFmXn]s}m_lUdi[[[㓓Z_dSr9Rhtt`mXksl^t~kckgqwꌌpx}ZN]uc]qqhona^kzzze^ln_wlm^t~obn҉VVVXXXhfdhqkaqofm~tttKKKy|~e`ooohbcpncs{ٚrzeXdnijnXUTdjtzq{flemqllnlgmw}{lhhhó{{{h{49:<<EKB<<<38:47:012.23./0*,.'))&')"Wofdf~{f[]je@EA<@Ab U>Lu ^pQ;?EGGD:p} t;Lyj X}p>;GE?AAG;=Df x@@[osWTcqfS8;GE?AAAAAGGg| rBHp[>OO>rR;@BGED?AAAAAAGE=Rb mhSEEEEK[>FGGAAAAAAAAAG@by`XBGAAAERREAAAAAAAAAAD@zV yjUfBDADD8aDAAAAAAAAADLr1t j r(G8@@>>IZaRl{Pgu/23___L^hK''4TxsssQkz'KXa󰰰OPQNblJ#6SrSkzS\a___KOfr~~~HHHOOO===󔔔./0RjyB*&9FNT?GM3QVVV׉EJKSpE#*-4L[dPeq3:CH⢢\]^IY`Q='1J>5NbluuuR?CGKљ_abGSZRzG0'/-*KGU_27;EHIA>9=@___؟fff678GT]QD.'043.FK*K]g:AF9;Qm}NSULLLnnnyz{]^aHOTJZaSpPB.'043333)-HWa38<AKQ0*ERZQoQS{R|R@LRTvE>4.'*0133333.'KQwNcoHX_GX`Sr''''QoP"..433333333,9Nco9>CRafccc-125,533'TvTv'3333333333*;7?Dat}k[p8<@___tttJ\f3-4-*QOfr-333333333-?AKQn[ad[lGMO___CNSA/Q99J433333333-?6<@oZaddd[iKU[qqq@DH?GMGWa0.&343..4.'&2IXbr[cgaadk]eWadKKKbbbAMS9'MSr4'=N-FSwR|J\f49:j_fa{nl]s}q]f\pzTTTSSSAFKM_iN!N38DHoXakmENQccc~~~*,/QRn~=*ESu.23O[bknaq^r|on[oyndkke012}}}HV`'*'F=DGg[al?EG^t~llg:@Bp[_]]s}琐022L^hN*QpFNQkaaaeiad[kl[_igqqqUUUikkIOS-12ogakqfmpopaynnl_jTXZZZZ'))nq_plfP]dnmn]q{Wiqmnan389HHHyyyNNN<< tomcat7-7.0.52/webapps/ROOT/tomcat.css0000644000175100017510000001271011656645415017406 0ustar locutuslocutus/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. */ body { margin: 10px 20px; text-align: center; font-family: Arial, sans-serif; } h1, h2, h3, h4, h5, h6, p, ul, ol { margin: 0 0 0.5em; } h1 { font-size: 18pt; margin: 0.5em 0 0; } h2 { font-size: 16pt; } h3 { font-size: 13pt; } h4 { font-size: 12pt; } h5 { font-size: 11pt; } p { font-size: 11pt } ul { margin: 0; padding: 0 0 0 0.25em; text-indent: 0; list-style: none; } li { margin: 0; padding: 0 0 0.25em; text-indent: 0; font-size: 80%; } pre { text-indent: 0.25em; width: 90%; font-size: 90%; } br.separator { margin: 0; padding: 0; clear: both; } a img { border: 0 none; } .container { padding: 10px; margin: 0 0 10px; } .col20 { float: left; width: 20%; } .col25 { float: left; width: 25%; } #wrapper { display: block; margin: 0 auto; text-align: left; min-width: 720px; max-width: 1000px; } .curved { border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; -khtml-border-radius: 10px; } #navigation { background: #eee url(bg-nav.png) repeat-x top left; margin: 0 0 10px; padding: 0; } #navigation span { float: left; } #navigation span a { display: block; padding: 10px; font-weight: bold; text-shadow: 1px 1px 1px #fff; } #navigation span a:link, #navigation span a:visited, #navigation span a:hover, #navigation span a:active { color: #666; text-decoration: none; } #navigation span#nav-help { float: right; margin-right: 0; } #asf-box { height: 40px; background: #fff url(asf-logo.png) no-repeat top right;} #asf-box h1 { padding: 0; margin: 0; } #upper { background: #fff url(bg-upper.png) repeat-x top left; } #congrats { text-align: center; padding: 10px; margin: 0 40px 20px; background-color: #9c9; } #congrats h2 { font-size: 14pt; padding: 0; margin: 0; color: #fff; } #notice { float: left; width: 560px; color: #696; } #notice a:link, #notice a:visited, #notice a:hover, #notice a:active { color: #090; text-decoration: none; } #notice img, #notice #tasks { float: left; } #tasks a:link, #tasks a:visited, #tasks a:hover, #tasks a:active { text-decoration: underline; } #notice img { margin-right: 20px; } #actions { float: right; width: 140px; } #actions .button { display: block; padding: 0; height: 36px; background: url(bg-button.png) no-repeat top left; } #actions .button a { display: block; padding: 0; } #actions .button a:link, #actions .button a:visited, #actions .button a:hover, #actions .button a:active { color: #696; text-decoration: none; } #actions .button a span { display: block; padding: 6px 10px; color: #666; text-shadow: 1px 1px 1px #fff; font-size: 10pt; font-weight: bold; } #middle { background: #eef url(bg-middle.png) repeat-x top left; margin: 20px 0; padding: 1px 10px; } #middle h3 { margin: 0 0 10px; color: #033; } #middle p { font-size: 10pt; } #middle a:link, #middle a:visited, #middle a:hover, #middle a:active { color: #366; font-weight: bold; } #middle .col25 .container { padding: 0 0 1px; } #developers { float: left; width: 40%; } #security { float: right; width: 50%; } #lower { padding: 0; } #lower a:link, #lower a:visited, #lower a:hover, #lower a:active { color: #600; } #lower strong a:link, #lower strong a:visited, #lower strong a:hover, #lower strong a:active { color: #c00; } #lower h3 { color: #963; font-size: 14pt; } #lower h4 { font-size: 12pt; } #lower ul { padding: 0; margin: 0.5em 0; } #lower p, #lower li { font-size: 9pt; color: #753; margin: 0 0 0.1em; } #lower li { padding: 3px 5px; } #lower li strong { color: #a53; } #lower li#list-announce { border: 1px solid #f90; background-color: #ffe8c8; } #lower p { font-size: 10.5pt; } #low-manage, #low-docs, #low-help { float: left; width: 32%; } #low-docs { margin: 0 0 0 2.2%; } #low-help { float: right; } #low-manage div, #low-docs div, #low-help div { min-height: 280px; border: 3px solid #ffdc75; background-color: #fff1c8; padding: 10px; } #footer { padding: 0; margin: 20px 0; color: #999; background-color: #eee; } #footer h4 { margin: 0 0 10px; font-size: 10pt; } #footer p { margin: 0 0 10px; font-size: 10pt; } #footer ul { margin: 6px 0 1px; padding: 0; } #footer li { margin: 0; font-size: 9pt; } #footer a:link, #footer a:visited, #footer a:hover, #footer a:active { color: #666; } .copyright { font-size: 10pt; color: #666; }tomcat7-7.0.52/webapps/ROOT/bg-middle.png0000644000175100017510000000357611472002616017733 0ustar locutuslocutusPNG  IHDR d̡iCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  6IDATX 0 D?q =gWi['زp]_~Dt\O̍)a\L&ψj Њ'1 6L CWw* f{53XNkƮ3V+ʹC׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  (IDATH Qr0C^'ɶd {^=~/0sGG(v74[!V9{#)c&=v;QI4Sb[<)Oȝaٴ$+| Nz8YVDz<%QE@6bEq*7/p-/jRWy*w\:8=ʜ{!B٩:|p#z+>(T !O5'DT0/ᠶ9;= %!f4Rłl-U&$T=z6Z7(/R{ Gb(=fETl&8e"T;gO8D5I>Np -݃WSZN %h8URزSJ^EWHlrRqTHIew٠B=9»(vOv֋ܢ?\O6X+|ȧ{Mg=Qs{PIENDB`tomcat7-7.0.52/webapps/ROOT/tomcat-power.gif0000644000175100017510000000451011472001035020470 0ustar locutuslocutusGIF89aPP' '''1/&???K@ AABXWQkW#___ikkklmt~pE||z Mɞ ]ا!l uss! ?,PP@P8Ȥrl: G>D \g* H q4]"c5yDGG΁Oz"r"xm"cIUoSv'tHhGkCx x G'QDx\&B'&eCq'ˤ'ˡ" 'j&j &HQ嚩 ^GCCH\"&Q8@' W1/\ x$cg&(eBi! T4vd=M2fkي-M1bJDXH(y$A):DQ]LzC(#I@rm*%H w=wG.t D ;=#%'vfl Fͺ7]:Cٸ/$@;'pD ',ma8*wxp'Xg~bP%@DT`a;w' @,BL_ &@IC@A-*!L@x ^p!Si `XC(bˬXZ*Ld0,%Ȓd NAUV![™$XahYBaƩIq0>ћ@yg@`GJ'wv|x}G$Фp jRID煛9e;Z|1@&cod ( ,& <G:fTJ+y(֖+j\K&P0@\ AVil±f6g((Mb+wf`_Yi{ P+ &hdH. @Iƒ|F릋c+ghX`tՉ HI/\hy+!_tC |d /@*=E Aށ+ @ (ݥr 5[ӫL`AyNo$ <`@ ؜ i |g: o 6Hs@՝L0U@fh2"-7w A $B_Dʅ h\خ`.y0A:X@`$-Pp2AKax5a "} p`:8 *} O hluy- 8VIOJ @֘@_*nnXtuDuJC@.Q=P5nk;tomcat7-7.0.52/webapps/ROOT/tomcat.svg0000644000175100017510000020317611656645415017425 0ustar locutuslocutus ]> 2006-05-09T08:17:21Z 2006-05-09T08:37:38Z Illustrator JPEG 256 184 /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAuAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXhH/OYHnWfQ/wAurfRLSUxXXmK49GQqaN9VtwJJqH3cxqfYnFXhP5Y/ 85O+f/JU0enaw769okbBJLS8ZvrUKg0IhnarDj/I9R2HHFX2F+Xn5neT/P8ApP6R8u3glKAfW7KS iXNuzdFljqaezCqnsTirK8VdirsVdirsVdirsVdirC/zM/Nvyd+XemC71255Xcqk2WmQUa5nI2+F CRxUd3ag+nbFXx1+Zf8Azkn+YvneaW1tLh9C0NgwXTrB2V3Sm/rzji8m3UDitP2cVfV//OOfmabz D+T3l+6uHMl1aRPYTsxqSbVzEhJ7kxKhxV6VirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVfHn/ADlxdSa7+bvlvyvGx4RW0EVARtNfXJVqf7BY+uRlKgT3JAt5r/zkD5ZGgfmfqSRR+nZ6 gsd9agdOMq0f/ksj5h9nZvEwgnmNi2Z4cMiw/wAqebPMHlTXLfW9BvHstQtjVZEPwstQWjkXo6NT 4lOxzOan3v8Akl+cel/mX5a+tAJa69ZcU1fTlJojGvGWLluYpKbV6GqmtKlV6NirsVdirsVdirsV eWfnr+eGl/lroywwBLzzPfox02wJqqL0+sT03EanoOrnYdyFXwh5i8x655j1i41jW7yS+1K6blNc SmpPgABQKo6BVFB2xVnf5Q+SjrWh+d9Yli5w6XolylsadbqSNnTj8kiYf7IZg6zUeHKERzlIfL8U 3YoWCe4Pff8AnCfVTN5D1zTCamz1P11HcLcQIAPlWE5nNL6KxV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KuxV2KvjD8wm/Sv/OX8UTGsdrqGnCMNUU+rW0Mp6f5ammY2sNYZ/1T9zZi+oe9m/8A zkx+Xc/mPytFrunRepqehc3ljUVeS0cAyAU6mMqHA8OXfNB2PqhCfAeUvv8A2uZqcdix0fIedQ69 m35OefrryN+YOla2kpjsjKttqqDo9nMwEoI78ftr/lKMVfaeqf8AOSH5KaaSs3meCZx0W1inuanf YNDG69vHFWM3v/OYn5QW5YQ/pK8ArQwWqitPD1pIuvviqVT/APObH5cKR6GjaxIP2i8dqhB9qTvi qmP+c2fIFd9C1Wnfa2/6q4qmFv8A85n/AJUSvxksdZtx/NJb25H/ACTuHOKp3bf85XfkpPBI7avN BIisywS2lwGcqCeIZUdKmm1WGKvijzz5x1bzl5q1HzFqjlrm+lLrHWqxRDaOFP8AJjSij7+uKpNb W1xdXMVtbRtNcTuscMKAszu54qqgbkkmgwE1uVfbHkL8uk8o/lTPoMiK+o3drPNqZHRrieIhlr4I tEB9q5yWo1fi6gS/hBFfN2UMfDAjqwT/AJwdvyt/5usC20sVlOq77em0yMR2/wB2Cudc619ZYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXxZKTJ/zmFc+oedNTmA5b/ZtG49fCgpmH2h/ cS9zbh+sPqDrsc4t2r57/Nf/AJxkGo3c+teSTFb3ExMlxo0hEcTMdybd/spU/sN8PgQNs3+i7Xoc OX5/rcLLpusWIaF/zif56vFWTVr6y0pG6xgtczL81QLH90mZWTtnFH6bk1x0sjz2Z1pf/OIvlOIL +lNbvrthSv1dYrZSe+zC4ND88wp9uTP0xA9+/wCptGkHUsms/wDnGf8AKS3AEunT3dOpmupxXam/ pNFmPPtjOeRA+H67bBpoPDv+ch/yt03yXrdjeaFbG30HUouCQ8pJBFcQ0DqXkZ2+NSrCrfzeGbns vWHNAiX1BxdRi4TtySH8jfJdn5u/MOy07UIfrGl28ct3fw1IDRxrxUEqQaGV0By7X6g4sRkOfRhh hxSp9N3X/OO/5P3FSdBETGnxRXN0nT/JEvH8M50dq6gfxfYHOOnh3JDqP/OKn5a3NTazajYt+yIp 0dfpEsbn/hsvj21lHMRP497A6SPmwzW/+cQr9A76H5himO/CG9haL5AyxGT/AIhmXj7cifqiR7t/ 1NUtIehZh+S3/OP8Xk+5GveYXivNfTkLSKIloLYGqlwzBecjL3p8P45i9odqeIOCH09fNtw6fh3P N7DfIz2VwijkzRuFA6klTmpxmpD3uRLk+bf+cJrrj+Yet2tT+90hpeP7J9O5hWp9/wB5tneunfZm KuxV2KuxV2KuxV2KuxVZLNFDG0srrHGu7O5CqB7k4qks3nzyNC5jm8xaZHIOqPeW6nf2L4qmFhrW j6iK6ff294KVrbypLt1r8BPjirAvzb/Pnyf+WrW9rqKS6hq90vqRaba8eaxVp6krMQEUkEL1JPbq cVYFof8Azmp5BupVj1fR9Q0wNsZo/SuY1/1qGN6fJDir2Xyf+Yfkrzjam48taxb6iqgGSKNisyA9 PUhcLKn+yXFWRYq7FXYq7FXxRrBNj/zl/NVwC+rL8XtcWw+Hf/jJTMXXC8M/6pbMP1h9SZxLtnYq 7FWG+afzg/LnyvdNZ6vrUSXqGj2sKvcSofB1hV+B/wBamZmHs/NkFxjt8mqWaMeZRPk78zvI/nF5 ItA1RLm5hHKS1dXhmC1pyEcoRmXputRkdRosuLeQ2TDLGXJCfm/5JXzj5D1HSo05X8a/WtNPcXMI JUD/AFxVP9lk+z9R4WUE8jsWOaHFGnl3/OI/lpodN1zzFMlGuJUsLcsKELCPUlpXsWkQfNc2Xbmb eMPj+r9LRpI8y+hc0DmuxV2KuxV2Kvl//nClHP5oas4B4Lok6luwLXdqQPpoc9AdK+08VdirsVdi rsVdiqXeYPMOi+XtIudY1q7jsdNtF5z3EpooHQAd2ZjsqjcnYYq+VfPf/OV3nXzNqp0D8stPlto5 mMcF0IfrGoT+8UIDrGD8mbvVcVSqz/5xn/Pjzs66h5t1RbUueX+5W7kurgA/yxx+sq/6pZaeGKsj h/5wanMYM3nNUk7qmml1/wCCN0n6sVQt7/zhDr8B56Z5stppEIMZntZLfcb1qkk9KHFXzr5mtdUs tfv9O1S5a7vtOuJbKaZndwWt3MZ4mSjcartUDFUsxVFabqeo6XfQ3+m3UtlfW7c4Lq3dopUbxV1I IxV9Sfkr/wA5aNcT2+gfmG6K8hWO18wqAi1OwF2q0Vf+Mi0H8w6tir6lVlZQykMrCqsNwQe4xVvF XYq+Kfzzro3/ADlLa6oxKJLdaReFiaApGsMLeG1ISMqzw4sco94LKBogvqPOEdw7FXkf55/mBrlj Jp3kbykX/wAVeYSFE0Zo8FuzFOSt+wzlW+P9lQx2NDm27N0sZXlyfRFxs+Qj0jmUd5B/IHyP5bsI 31Oyh1zWnAa6vb1BMnqHciKKSqKAehI5e+Q1XamTIfSeGPlzTj08YjfcsJ/PDy5pXkHX/LH5geW7 WPTGhvlt9Rt7RBFHKpBk+wgCjnGkiPQbg5m9m5jnhLFM3s1Z4iBEg+hOu4zn3NQOkaLpuj20ltp8 IghlnnunRe8tzK0sh/4JzQdhtlmXLKZuXdXyYxiByR2VsnYqxjV/zO/L3SJWh1DzDYQzoaPD66PI p/ykQsw+kZlY9Dmnyifu+9qOWI6pvoOvaRr+kwato9yt3p1zz9C4UMob03MbbMFOzoR0ynLiljkY yFEM4yBFhV1WVYdLvJWJCxwSOxHWioTjhFzA8wsuRfPn/OEVoX83eZLzekOnxQnpSsswb/mVneOn fYOKuxV2KuxV2KqF9e2lhZT315KsFpaxtNcTuaKkcYLMzHwAFcVfFHnPzR50/wCchPzJi8veXlaH y7aO5sYnqsUUCkK97dU/bYdB2qFXcklV9U/lj+UnlH8u9IWz0a2WS+dQL7VpVBuLhh1q37KV+yg2 Huakqs1xV2KuxV8v/nf/AM4patrnmG+80eSp4Xn1GR7m/wBIuW9ImdyWd4JSOH7xjUq9KGvxb0Cr 5/1j8mPzX0iRkvfKepgL9qSC3e5jG9P7yASJ1PjiqRjyb5vMvpDQ9QMtePpi1m5culKca1xVPtG/ JT82dYdUsvKepUf7MlxA1rGe395cekn44q+zf+cffKv5m+VvJ50bzvPbzRwFf0RFHK01xbxU+KCV 6cCqmnDizU3FaUAVeo4q7FXx5/zmxpD2vnTy7rcdUN5YPbh12POzmL1qO4FyuKsl/Lz/AJyc8ra2 sNj5mUaHqZAU3TGtnI3Qnn1ir1o/wj+bOY1XY8474/UO7r+1z8epB2Oz2iKWKaJJYnWSKQBkkQhl ZTuCCNiDmnIINFygVGXTNOmvYb6W1hkvbbkLe6eNWljDgq3ByOS1UkGhwjJIDhs0ei0LtE5FLxD/ AJyycP5F0ezQcp59WjaNdt+NvMp/GQZuuxI/vJH+j+lxNWfSPe9rgiEMEcQNRGoQE9+IpmmlKyS5 QCpgSsllihieWVxHFGpeR2NFVVFSST0AGEAk0EEvn2fVfOv5269e6foN9Jof5e6fIYbm9QMst2af ZIBUtyG4QkKqkFqmgzfiGLRQBkOLKfx+C4ZMspobRZzof/OOv5U6VCiyaUdSnUUa4vZZJGb5opSL 7kzBydrZ5HY8PuDbHTQDP9G0XStE02HTNJtks9Pt+Xo20Qoi83LtQe7MTmBkyynLikbJboxAFBJv zO1Aaf8Al35lu60ZNNuljP8AlvEyJ/wzDL9FDizQH9IfYxymol59/wA4P6S0eg+adXI+G6ura0Vv e2jeRgP+kkZ2zqX01irsVdirsVdir50/5zJ/MGbSfK1j5PspOFxrrGa/KmhFpAwon/PWWn0KR3xV mf8Azjd+WEPkj8vrae5iA17XES91KQijorrWG333HpI24/mLYq9YxV2KuxV2KuxV2KuxV2KuxV2K obUdT03TbR7zUbuGytI/7y4uJFijX5u5VRir5U/5yz/MX8tfNfl7S7DQtZh1LW9NvS5W2V3iFvJG yyUnC+kfjVPsscVSv8i/yi/LTzn5Ij1XVLSafU4J5rW9C3EkaFlIdCFQrT926980XaOuy4cnDGqI vk5eDDGQsvdvKXkby35StXtdBgmtrZ6Vge6uZ4wf5ljmkkRCe5UCuaPPqp5Tc9/gHLhjEeSN8x3+ o6foGoX2m2hv9QtoJJbWyFazSKpKxjjv8R22yOCEZTAkaBZTJAsPHv8AlcP53/8Altpv+BuP+ac3 H8n6X/VPti4vjZP5rzz8wfPP5i+bfNvluw1Dyq1rqWjzG+g0ROZmuRVZDVGHPjxgbcDpXNhpdNiw wkYy9Mutj8dWnJOUiAQ9D/5XD+d//ltpv+BuP+ac1/8AJ+l/1T7Yt3jZP5rv+Vw/nf8A+W2m/wCB uP8AmnH+T9L/AKp9sV8bJ/NYp+ZX5v8A5qXnli40LVfKbaCutAWkdyxlWRwWXnHGrheRdfhI8DmV pNBgE+KMuLh9zXkzTIoirR/kbzf+bvlHy1Y+XtO/LedobYENM6zK0kjtyeRzxoOTH6BtkNTp9Plm ZyyfaEwnOIoRej+RPO35o6xr62fmPyf+hdNMTub71C1HWnFaV/azX6rS4IQuE+KXds348kyaIZ7q jaqthKdKSCS/pSBbp3jhr4uY1kbbwA38Rmux8PF6r4fJuldbPlv8+YvzstdPS483apafoO7nEEVh pcjJbl6NIA0bKkjgenWsnKhpnTdnHTH+7HqHfz+f6nAz8f8AFyfQ3/OLHl06N+TWkyOnCfVpJ9Rm Hj6r+nEfphiQ5t3GeuYq7FXYq7FXYq+MfzQhXzz/AM5YWmgz1lsLe7sbB4zvW3gRbi5TvSrNLir7 OxV2KuxV2KuxV2KuxV2KuxV5j59/5yM/K7yb6kFxqQ1TU0qP0dpvG4cMO0kgIij36hn5e2KvAvMv /OWP5p+arl9P8laWukxtXiYIzfXvHpUuy+mg+UdR/NkJ5IwFyIA80xiSaDF/+VT/AJo+b7sah5w1 h1kavx3sz3k617KgYoo9uYp4ZptR7QYIbRuZ8uXzP7XMx6GcuezJYf8AnH3yrBptwjXFxd6g8LrB NIwSNJSpCOEQA7NvRmOak+0eQzGwjCxfU11/FOT/ACfEDnZYH+S+sfmZZeajoHlC8htrq6ZnubC/ K/VnMAPLkrAtyUdfT+Kg8BnSa7HhMOLINg6/CZA1F9k6KdbOmw/pxbZdTp/pH1IyNAW8U9UK9Pnn I5eDi9F8PnzdlG63R2VsmndUUu5CooJZiaAAdSTiBaHhP5N8/On5r+bPzEkBbT7dv0do7EGhWgUM tRswgjUsP+LM3vaH7nBDCOZ5/j3/AHOJh9UzJ7vmicx2KvEf+clQLS78i63cEjT9O1cC6O3H4mjl FR/qwPm77G3GSPUj9f63E1XQvbQQQCDUHoc0jlN4pSXzN5z8q+V7ZLjX9Tg0+OSvpLK37x+PXhGv J3pXfiMuw6bJlNQFsJ5BHmXzJ+dn5haf+Z/mby75e8qtLPbLN6EbyI0YluruRI0oh+KigChIHU50 /ZmilhieL6i4GoyiZ2fbWh6Ra6Noun6PaClpp1tFaW4/4rgQRr+C5s3HR2KuxV2KuxV2KvjfymCP +c0p/rdK/pTU+POlKfUp/S/4144q+yMVdirsVdirsVdirsVeQfmX/wA5Ofl55MaaxtZv0/rcdVNl ZMDEj+E1x8SL4ELyYdxir5W/Mf8A5yD/ADJ88GSC6vjpmjyVC6VYFoYmQ1FJXr6kte/I8fADFXme Kvpj8jdTtb3yJBFFGkdxYyyW9zwVU5MDzRzTqSjipPU1zhvaDHKOosk8Mht5d/6/i7rQSBh5h6Fm ic12Kvnvz6l35B/Nqz8z2CEQyzLqMSqeIY143UVf8upr7Pnedl5RqdLwS5gcJ/R9n2uj1MPDyWPe +wdL1Ky1TTbXUrGQTWd5Ek9vKOjJIoZT9xznMkDCRieYc2JsWisgyYZ+b1p5vvfIGqWPlSFZ9Tu0 9F1LiN/q77TelXYuV+EAkddt6A5vZ8sccoMzsPv6NOYSMdnzl+Wn5m/mVoKR+RtEtNLsrmGWSsOp q1vM87t8Su8ssS+p0UKaGgAGdDqtHhyfvJ2fd3fBwseWUfSHq36V/wCcqf8AqzaN/wAGn/ZRms4N B/OP2/qci83c79K/85U/9WbRv+DT/sox4NB/OP2/qW83c8o/Mj8z/wAy/MAm8i6zaaZfXU0sY9HT Ea4lSdGqqxvFLKvqbFSBXqQc2el0eHH+8jY2693xcfJllL0l9KflXb+bbXyJpVp5riWLV7aIQsqu JGMSbRGUio9ThQNQnx70znNccZyk4+R+9zsIkIi2W5iNqB1xdH/RF2+sxQy6XFE8t4tyiyRelGpZ i6uCpAAyzFxcQ4D6ixlVb8nzj/zjB5UtfNn5xal5tisltNE0Rpbu1tEUCOOa6ZktYgBt+7j5tt3U Z3UIkRAJt1BO77PySHYq7FXYq7FXYq+M/wAyX/wb/wA5b2WsP+7s7q90+7Zz8NILlEt7htqV3EmK vszFXYq7FXYq7FWGfmR+bnkn8vrD6xr16PrkilrXS4KPdTdacY6jitRTmxC++Kvjz80/+clPPvnk TWVq50Py45KfULRj6kqntcTjiz1H7K8V8QeuKsQ/KyLyvP5wtbTzFbC4trn91bc2IjW4JBj9QAjk G+zQ7VIrmB2mcowE4jUh93Vv0wiZgS5Po7zD5J8ta/pa6bf2UfoQrxtWiAjeDbb0io+Hp06eIzht N2jmwz4oyu+d7373dZNPCYoh8/effyj17yuZLu3B1DRgSRdRr8cS9f3yD7P+sPh+XTOz7P7Wxajb 6Z936u90+fSyx78wnP8Azj5r4s/M11o8jUi1OHlED/v63qwA+cbP92YvtDp+PCJjnA/Ydv1NugyV Ou99C5xDuWDeefKvnzV9WiufL+v/AKKskt1jkt+Ui8pQ7sX+AEbqyj6M3XZ2t02LGRlhxyvnQO23 e4eow5JSuJoe8sD81/lL+ZF9pj3Go65Hq7WKPLBbMZGc7VZY+S9WC9O+bnSdsaQTEYQ4OLyAHxou Jl0mWrJuvel/5Q/8rK80ySeXdA85S6P9Qh9W2spZ51RouXx+kEDD4CwqPfbvmz1pw4xxzhxX5Bxc XFLYGnv35Y+RfzR0DXri881+af03p0lq8MVp6s0nGZpI2WSkiqNkRh9OaLW6rBkgBjjwm+4D7nMx Y5g7m3p2axyGGfmF+U3k/wA82pGq23paii8bfVIAFuEpWgLU+NN/st9FDvmZpddkwnbePc1ZMMZ+ 95R/iv8AMz8lbm20/wAzMPMvk2Z/Ssr5XpcIBvxXmSwKr/ut6r2Vxm28HDrAZQ9OTr+P0uNxzxbH cNSeb/zJ/Om9uNM8pk+XPJ0Lelf6g7D13DD7L8DyJZf91oafzNTEYMOjAlP1ZOn7P1qZyymhsHrH 5d/lN5R8i2gXS7f1tRdaXGqTgNcPXqAeiJ/kr9NTvmq1euyZjvtHucjHhEPezPMJuePedvy3/OXV fNF/qGg+c/0ZpM7KbWx9a4X0wI1VhxRSoqwJ2zc6fWaaMAJQuXuDizxZCbB2eNfm7F+Z3lQQaDr3 nKXV21SJmm0+GedgIQwCmVXC7OwIUd6HNtopYcvrhDhrrQcbKJR2JeieSv8AnHD8+9H0SJtG83Q+ XlvlS5udPinuonSR0Hwy+nHxLqPhO5zYtD2r8mvJH5m+V/0x/jjzN/iL659W/R/76eb0PS9X1f75 Vpz5p08MVel4q7FXYq7FXYq+Xv8AnNjya81joXnG3Sv1Vm0y/YCp4SEy25PgquJB82GKva/yY87J 5z/LXRNbaTneNALfUfEXVv8Au5SR25leY9mGKs2xV2KrZJI4o2kkYJGgLO7EBVUCpJJ6AYq+aPzm /wCctrTTWn0L8vmjvL1ax3GvOA9vEehFsh2lYH9tvg8A1cVeMfl95AvPzCvLrzP5l1SW6iNwUueT tJdTyqqsQ7tXgvFgPGmwp1zS9rdrflqjEXMj4OZpdL4m5Oz3O18seXrXSP0PDp0C6ZSjWhjVkb3c NXk3ud842etzSyeIZHi73bDDAR4a2eaeb/yBsLlmvPK9x9QuQeX1OYs0JPX4JN3j/EfLN9ovaIj0 5hfmP0j9XycLNoBzh8noHku+1y50OKLXrV7XWLT9xeB6FZGUCkyOvwsHG549DUds03aOLHHJxYiD jluPLy8v1OXp5SMakPUE9IBBBFQdiDmCDTe841/8pLaHW7bzL5U42OqWkyzvYfZt5+JqyrT+6LrV f5fl1zoNL21xQOLPvGQri6j39/3+9wMujo8UOY6PSB06U9s54uewnzt5H8z69qsV5pXme60W3jgW F7WAyhWcO7GQ+nLGKkMB07Zt9BrsGGBjkxiZvnt5d7iZ8M5m4ypj/wDyqbz9/wBT/f8A/BXP/ZRm d/K+k/1CPyj+pp/K5f55+15z518keZ/y91G01W01SZ2nLiPVrYyW8qTMDzQurFgXQnfl8Qrm90Pa GLVxIrl/CXCz4JYiHv8A+Qeia/NDH5tufO155k0u+s3gGm3Tzt9XufUjZuQkmlUPHwZdh0NQaHfV 9qTgP3YgIyB57bhv04PO7eyZp3KYZ+afm/zN5Z0KGby5okmtanezC1gVAXSF3UlXkRPjYbdqDxYd 83Q6eGWR45cIG7TmmYjYMC8p/kVrGu6ovmj81b1tV1Njyi0YODBEOoWQp8FB/vuP4fEtXM7P2nGE eDAKHf8Aj7y1QwEm5orzX+Rd9pepP5n/ACuvm0HWlq0mlhqWc46lFBqqV/kYFP8AVyODtMSHBnHF Hv8Ax9/NM8BBuGxZB+VP5j+ZPMs9/ovmbQJ9J13R1Q3s3ErbPzNEoGPJWehIA5KQKhu2Ua7RwxgT hK4yZYcplsRuHo2a1yHh35u+SvN1nNrXnD/lYl/omiIFli0yB7gBSEVFiiC3EacpHGwAG5zd6HPi lw4/DEpd+3z5OJmhIXLi2eW/lJ+UXnn829Svtdl1ue0XTjGo127MtzM9ytDHHG5dXrGg5E8vh+Hx zo4QERQFBwSSeb2z/oXX86P/AC8Gq/8AI2+/7Kskh6L+UP5dedPJv6W/xN5wu/Nf1/6v9U+tvO/1 f0fV9Th68s3956i1pT7OKvRcVdirsVdirsVY/wCf/J9l5x8nar5bvKLFqMDRpKRX05R8UUlP8iRV b6MVfLf/ADiz50vvJX5han+XXmGtsmoztDHE/SLU4Dw4jt++Qca9yEpir7ExVK/MnmbQvLOjXGs6 5eR2Om2q8pZ5TT5KoG7M3RVUVJ6Yq+M/zS/PHzr+bWrnyv5Vt5rPy67fDZoaS3CqaerduDRU/wAi vEd+RplWbNDFEymaiGUIGRoc0Nc/846uugI1vqXPX1BaRGFLVtv7tTTmtP5z18BnOw9pInLRj+77 +vv/AB9rsD2eeHY+pV/Io6rofmDWPK2rwSWlzJEl3FBIKCsbem5UjZuYddxUHjke34xy4YZYGwDW 3n/YuhJjMxL2rOSdq7FXYq7FXYq7FXYq7FUt8w6Bp2v6Pc6VqCc7a5XiSPtIw3V0J6Mp3GZGl1M8 GQTjzH2+TXlxicaLxryB5w1r8nPPM+i63yl8v3rKbrgCVKE0ju4V8R0ZR13HUDO3ywx67CJw59P1 H8ebpgZYZ0X1xZXlpfWkN5ZyrPa3CLLBNGQyOjiqspHUEZzE4mJo8w54N7q2RS7FXYq73xVTuLi3 treS4uJFht4VMk00hCoiKKszMdgAOpwxiSaHNBNPlfzv5j8wfnh+Yll5O8qBhoVtKTFKwIQqvwzX 047IgNEB33p9p6Z13Z2iGGNn6zz/AFOtz5eM+T7B8j+TdG8m+V7Hy7o8fCzso+Jc/blkO8ksh7s7 bn7htTNi0J9irsVdirsVdirsVdirsVfLP/OXf5WXENxb/mXoKNHNCY4tbMNVdWQhbe7BG9RtGx/1 PfFWefl3/wA5I+VdQ/KqTzN5mu0ttV0YLbavarT1Z7gqfSaCPbl9YCkgdFIb9la4q+cvNPm3z/8A nr5uCUNnolo1YLRSxtrOIkgSSdPUmYd+p7cV6Yms1mPTw4pn3DqW3FhlkNB695O8l6J5U00Wemx/ vHAN1duB6szDux8B2XoM4LXdoZNTK5cug7vx3u7w4I4xQT/MFvUJbGzluYbqSFGubfl6ExA5oHFG AbrQjqMsjmkImIPplzDEwBIPUNahew2Nhc3s54wWsTzSt4JGpZj9wxw4zOYiP4iB81nLhBPc8w/J Tzn5v8y3mqHV7oXFlaIhjHpojLJKxIAZQtQFQ9a50XbujwYYRMI8MifsH4DgaLNOZNmwHq+cy7F2 KuxV2KuxV2KuxVjXnzyLpnm/SDZ3P7m7hq9leAVaJyO/ijftL/EDNj2d2jLTTsbxPMfjq4+o04yD zeb/AJZ/mj5g/KrXZPKnmyKSTQS9QFq5t+Z/v7c/txP1ZR8x8VQet1Gmx6vGMmM+r8bF1UJyxS4Z PqrTNT0/VLCDUNOuI7qyuVDwXETBkZT3BGczkxygeGQohzgQRYRWRZOxVSurq2tLaW6upUgtoVLz TSMEREUVLMxoABhjEyNDcoJp8v8A5n/mrr/5n65D5E8hQTTadcy+kxQcZL1lNeTV+xbpTl8VNvia nTOp7O7OGL1S+v7v2uvz5+LYcn0j+SX5N6V+Wvlv6uCl1r96FfV9RUGjMKlYoq7iKOu38x+I+A2z jPR8VdirsVdirsVdirsVdirsVSDz3rvlfQ/KWp6h5oaMaGsDx3kUgDCZJFK+iqEjm0leIXvir81d SfTpdTupdPhkt9MedzawyMJJI4WYmNGeihmCbV74q+q/y8tfLEHlOyPlsV06VefqGnqvJ0czH/fl RQ+HQbUzzrtWeY5z4v1D5V5eTv8ATCAgOFkma5yHYq7FWIfm3qBsfy81mRftSxLbge08ixN/wrHN r2Jj4tVHys/Z+txdZKsZSD/nH3TRb+S5rwj4767kYH/IjVYwP+CDZm+0mQnNGPQR+/8AAauz4+gn zenZzrnuxV2KuxV2KuxV2KuxVjnnbyLovm3Tfqt+np3MYJtL1APUiY+Feqn9pe/zocz9B2jk00rj vHqPx1aM+njkG/N4/ovmf8xfyX1w2rr9b0W4fkbVyxtLgDq8T0Jikp12r4gimdkPA12PiHP7R7/x 7nUETwyovpX8vvzc8m+eLZf0ZdCDUgKzaVcEJcKR1KitJF/ykr70O2aHVaDJhO4uPf8Ajk5ePNGX vTXzl578seTtMOoa9eLboa+hAPimmYfsxRjdj+A7kZVp9LPMaiP1Mp5BEbvmXzJ54/Mb87vMcflj y1ZyQ6SzhksENFCKf96L2YbcV60+yDQAM1Cep0eghgF85d/6nX5cxn7n1H+S35IaB+Wmkkxlb3zD eIo1LVGHyJhgrukQbfxbqewGe0vSsVdirsVdirsVdirsVdirsVQup6np+l6fc6jqNwlrY2kbTXNx KeKJGgqzMfYYq+HfzQ/MTzL+dvnmHSNFR4PLtm7fo+2eoUIKh7y5pX42BoB+yPhG5JajU6mGGBnM 7BnjxmZoPQ4Pyv8AK8fk1vK5i5W8g5yXVAJjcU2nr/MO3am3TOGl2xmOfxfs6V3ft73dDSQ4OH7X kehaz5g/KfzbLpWqK0+jXLB5VQfDJGaqlxDU7MKfEv0HsR0uowYu0MAlA+ocvI9x/HmHXY5ywTo8 n0Fp2o2OpWMN9YzLcWlwoeGZDUEH/Pcds4jNhljkYyFSDuYTEhY5KzTQoaPIqnwJAOCOOR3AKmQH VyzQueKyKx8AQTiccgLIKiQPV5t/zkDctD5FijHS5voYm37BJJP1x5vPZwf4Qf6h+8OH2h/dj3p3 +UNt9X/LnRkoQXjklNRQ/vJnf9TbZjdtyvVT+H3Bs0Y/dBmOalynYq7FXYq7FXYq7FXYq7FUHq+j 6ZrFhLYanbJdWkwo8Tjb2II3Vh2I3GXYNRPFLigaLCeMSFF4R50/JTXdCnOq+VpJby1ib1FjjJF5 ARuCvGhenYr8Xt3zstB25jzenJ6Z/Yf1fF1OfRShvHcJFJ5F/M7zRY3PmTUI7m8eKMFHvZHa6mRe 0SvV2CjcdK/s1OZsu0NNimMVgHy5D39zQMGSQ4qfTP8AziV518hXnlX/AA3p1lBpPmi0XnqUIr6l 6F2+sq7lnfr8SV+A9AFIzYtD6BxV2KuxV2KuxV2KuxV2KuxV2KvjX/nI7847/wA+eYk/L/ye7XGj QTiO4kgNRfXSnswNDBEeh6Egt0CnIZMkYRMpGgExiSaDJvy88h2PlDRRbJxl1G4o9/dAfbcDZVPX gn7P3988/wC0+0Zamd8oDkP0+93um04xx82vOP5meVvKoMV7OZ7+lVsLejy+3PcKg/1j8q4dF2Tm 1G4HDDvP6O9c2qhj25l47r/mfzt+ak6aXovlxrmO3f1I47SF7meOuxLzAURT32UZ1/Z/ZcNNdEkn n3fJ1OfUnJzDFvNXl7z35Lu/8P8AmCG60uQoLhbNpaxMsg+2nps0TVpQkHqKHcZseEXdbtFsbySH Yqu9ST0/T5H068uFTx5UpWnjir2HyZ+T/wCfGr+U9O1/yreSS6VdKzWkEOo+iQI5HRlMcjxoPjjI pXKMmmxT+qMT7wGcckhyJCOudA/5yq0IfvtM1G4VDuscNvqFadqwidj07HMXJ2Tpp84D4bfc2x1W QdUvl/Oj8y9CmEPmHQ0iPQpc209pKT1/aNP+FzCyezunly4o/H9bbHX5Bzop1pv/ADkboslBqWkX FsfG3dJx8/j9HNfl9mZfwTB94r9bkR7RHUMv0r82/wAvtSoserx28ndLoNb0/wBlIFT7mzWZuxdT D+HiHlv9nP7HIhrMcutMst7i3uIlmt5Umib7MkbBlPyIqM1s8coGpAg+bkxkDuFTIJdirsVdirsV dirH/PXm608q+XZ9Umo8391ZwH/dk7A8V+Qpyb2GZ/Z2iOoyiP8AD19zRqMwxxvq+cfL9n+Yf19/ Omi29ytzYytfnU41CgPyLOyhqCTqeSqDt1FM7+WoxYyIGQBOwDoxjlIE0+1/yK/O7S/zJ0IpP6dp 5nsVA1LT1OzrsPrEAO5jYncdVOx/ZJyGt6jirsVdirsVdirsVdirsVfO/wDzlT+dh8vaa/kfQJ6a 7qUf+5S4jPxWtrINoxTpJMD8wm/7SnFWA/k3+W48v6eNZ1OL/c1ep8EbDe3hbfhQ9Hbq3h08a8V2 52n4svCgfRHn5n9Q/HR3Gi03COI8yl/5qfm5LYTt5d8sP6mqM3pXd3GOZiY7elFStZa9T+z0+10v 7I7G4gMmUbdI/pP6mGr1demPzZX+UH/OJcl6I/MP5lNKZJj6sehB2EjV35XkoPKp68FNfFuq51wF OqfT2j6Jo+i2Een6RZQafYxf3dtbRrFGPfigAqe5xVj35mflh5Y/MLy++k61CBKgLWGoIB69tKf2 o2PY0HJejD6CFXwV+Z35WeaPy715tL1qHlbyFmsNRjB9C4jBoGU/st/Mh3X5UJVYdirsVfb3/OHX mKPUfyrfSS9Z9EvpovTrUiK4/wBIRvYM7yD6MVe7YqsmhhniaKaNZYnFHjcBlI8CDtirDde/JX8q Ne5HUvK1g0j15zQRC1lJPcyW/pOT9OKvMfMn/OF/5eXwZ9D1K+0aY/ZRit3AP9g/CT/krirzTVv+ cTvzh8tSPdeVNVh1EDoLS4exuWp4rIVj/wCSpyGTHGYqQBHmmMiNwxq58/fnT5ImW382aVMYgeIO oWzRch0pHcRhUfp1+LNVn7C02TcDhPl+rk5UNbkj1tlGgf8AOQHlS94x6rBNpUx6uR68P/BIOf8A wmaPUezmWO+MiX2H9X2uZj7QifqFPRNK1vR9Wg9fTL2G9iHVoHV6V7NQ7H2OaTPpsmI1OJi5sMkZ cjaNyhm7FXYqlGq+VNC1fULe91S2F69opW2hn+OFCxqzekfhLGg3avTbMzDrsuKBhA8N8yOfz/U0 zwRlKzumyqqqFUAKBQKNgAO2YhJJttp84edta0nyl+Y0Gu+Qr/0NQtH9W4WAfuI5wfiRSDxdJBUO lOPUd6D0PsqWc4R4w36d5Hm6HUiAn6H2P+TH5xaN+ZXlwXcIW11u0ATVdM5VMbnpJHXcxP8Asnt0 PTNk470PFXYq7FXYq7FXYqwf84fzP078uvJtxrU/GXUJawaTZMf765YbVA34IPic+G3UjFXyR+U/ lPUvNnmK589+ZXa65XDzRPKB/pF2Wq0h7cIz0AFK7D7NM5/tztLwo+HA+uXPyH6z+OjnaLT8R4jy DOPzf89t5Y8v+hZScdX1HlHbEdY0A/eS/MVovufbNJ2J2f4+TikPRD7T3fr/AGubrM/BGhzKf/8A OK/5HQWtjb/mF5ltxLqV3+90K2mBPoxHpdMD1kk6x+C/F1O3dukfTGKuxV2KpL5v8neXfN+hz6J5 gs0vLCffi2zxuPsyROPiR17EfqxV8N/nR/zj/wCZfy5umvYeep+VpXpb6mq/FFyPwx3Kj7Ddg32W 7UO2KvKcVeu/84z/AJoQeRvPwi1KX0tC11Vs7+RjRIpA1YJ29kZipJ6KxPbFX3sCCKjcHocVbxV2 KuxV2Kqc9vBcQvBcRrNDIOMkUihlYHsVNQcVeX+cP+cZ/wAovM3OQ6QNIvH/AOPrSmFsQf8AjDRo D/yLrirw/wA0f84fef8AQZ21DyRrKal6dTHEWNhejwVH5GJvmXT5ZGURIURYSCRyYf8A8rL/ADW8 jXo03zjpUslK8Y7+JreVlXasU6rxdf8AKo3zzT6rsHBk3j6D5cvl+qnLx62cee7P/LX5zeSdbKxS XJ0y7bb0byiKT/kygmP5VIPtnO6rsLPi3iOOPlz+X6rc/HrYS57FnSsrKGUhlIqCNwRmmIINFywW 8CWLebfLnmTzCG0+PVV0jRm2n+rK0lzOpG6s7FFjXtRa17nembXRavBp/VwmeTz2A93P5uLmxTnt dRSjR/yO8g6cVea2l1GVTUPdyEiv+pH6aEfMHL83tBqJ/TUfcP12whocY57sS80+XfMH5YeaLfz3 5JdorSKStxbAExxBz8UUigjlbydP8n58Tm97H7WGccE/7wf7L9vf8/dhavS8BsfT9z6x/Kf81NB/ MbyzHq2nEQXsVI9U0xmDSW03genJHpVHpuPAggb1wmbYq7FXYq7FVK6ure0tprq5lWG2gRpZ5nIV ERByZmJ2AAFTir4W89eZtV/PD81xHas8Xlyw5RWXb0bJGHqTsDt6s7U/4Vei1zE12rjp8Rmfh5lt w4jOVB7Zp2n2enWMFjZxiG1tkWKGMdAqig655xmyyyTM5G5F6CEREUOTxPS9Gb81/wA/YNJlLNo1 tMUuKbUsrEky0I6es9QD25jPQ+zNL4OCMevM+8/inQ6nJxzJfdcUUUUSRRIscUahY41AVVVRQAAb AAZntC/FXYq7FXYqo3dnaXtrLaXkKXFrOpjnglUOjowoVZWqCD74q+T/AM7f+cTri0a48wfl7E09 pvJdeX6lpY+5NqTu6/8AFZ+Ifs16BV8xyRyRSNHIpSRCVdGBDBgaEEHoRiqLv9b1nUEjS/v7m7SF VjhWeV5QiIOKqocmgUbADFU/8k/mp588l38N1oOrzwxREcrCR2ktJFH7MkDHgRTaoow7EYq/Qb8v POFv5y8laR5mt4/RXUoBI8NeXpyqxjlQNtULIjCuKsixV2KuxV2KuxVB6rpGlavZSWGq2cF/ZS7S W1zGssbfNHBGKvD/AD5/zh75B1r1Lny1PL5cvmqREtbizY/8YnYOlT/K9B/LirxDWPy7/Pr8pmea GKW90OI8nuLOt5ZcQakvERzhHixVfnmJqdDhzj1xvz6/Ntx5pw5FNvKv/OQWi3fCDzDbNp0/Q3UI aWAmnUqKyJv2+L55zWr9nJDfEeLyPP58vudhi7QB2kKepWGo6fqNst1YXMd1bP8AZmhcOp+lSc57 LhnjPDMGJ83YRmJCwbROVMlk0MU8LwzIJIZVKSRsKqysKEEHqCMlCZiQRsQggEUXiepWHmf8m/OM PnDyiS+jSH07i3erxhHYFrafuY2oOD9QadwCe77J7UGojwy2yD7fN0mq0xxmx9L7C/Lr8wvL/n3y zBr+iyExSfBc2z/3tvOAC8Ug8RXY9CNxm5cRk+KuxV2Kvm7/AJzA/NOTTNHg8haVKRf6ugn1ZkJ5 JacqJDt3mdTyH8op0bFUg/KjyOvlfy2n1iMDVr8LNfsaVXb4Ia/8Vg7/AOVXOB7Z1/j5aH0R5fpL vNJg4I2eZZRr1/8Ao/Q9Rv8A/lktZp/+RUZf+Ga7SwE8sInkZAfa35ZVEnyYp/zg/o0Ump+atccV mghtbKJu/Gd3ll/GBM9PecfWeKuxV2KuxV2KuxV2KvOfPf5Aflj521UatrGmtHqRFJ7m0kMDTdKG Xjs7CmzUr+GKsb/6FD/Jv/lmvv8ApLb+mKu/6FD/ACb/AOWa+/6S2/pir0/yZ5Q0byf5as/LmirI mmWPqfV1lcyOPWleZ6sevxyHFU7xV2KuxV2KuxV2KuxV2KvMfzC/5x1/LLzr6lzcaf8AovVn3/Se ncYJGbrWSOhikr3LLy9xir5080f846/nH+XVzJqnlK6k1nT1NTLpwYXHFenrWR58/kvMZTmwQyx4 ZgSDKEzE2DSH8r/85ABZRZea7IwSoeD3lup+FgaH1YT8Qp34/wDA5zes9nBzwn4H9B/X83Y4u0Ok w9b0nWdK1e0W80y7iu7ZukkTBgD4Hup9jvnM59PkxS4ZgxLsYZIyFg2q31jaX9pNZ3kKz2s6lJoX FVZT2ORxZZY5CUTUgmURIUeTxy2svzN/KLzbcaj5Eil1DS9RRkNuIZLqMqDVUnij35Rk/A+3z3YZ 3Wg7YxZYXOQhMc7NfK/wHS59JKMthYZVB/zlL+eWlMZNc8owTWiEmRzaXlsaClaS83jp/sTmxx6r FM1GUZe4guPLHIcwQ9C8jf8AOYH5ea7NFaa9bzeW7uUhRLMwns+RNADOgVl+bxhR3OXsHulvcW9z BHcW0qTW8yh4Zo2Do6MKqysKggjoRir849U/MZtX/M6688azZnUTNdNcxWTSekFVPhtk5cZPhhVV FKb0yjU4pZMZjE8JPVnjkIyBItnP/Qyn/fuf9Pv/AF4zm/8AQx/tn+x/487D+Uv6P2/sQWuf85A/ pXRNQ0z9A+j9etprb1vrfLh60ZTlx9Fa05VpXLcHs74eSM+O+Eg/T3f5zGev4okcPPz/AGPU/wDn B7UUbTvNmmkgPFNaXCjuRIsqH7vTH350zrn1DirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirBPzB/JP8uvPivJremKmpFaJqtofQul2oKuopJTsJFYYq+afOP8AzjN+afkK7fWP JF7LrNjGeX+iVjvVUb0ktqlZh/qcq/yjK8uKGSPDIAjzZRkYmwl/lf8AP1opf0f5vsmgnjb05LyB CCrA0PqwH4lI78f+BzmtZ7OA74T8D+g/r+bsMPaHSfzet6TrOlavZreaZdR3ds3SSJgwB8D3B9jv nMZ9PkxS4ZgxLsoZIyFg2jMpZsJ87flR5Z8zxSTLCthqxBKX0Kgcm/4uQUEg9/te+bjQds5cBAke KHcf0H8BxM+kjPlsWPfkJ+aPmL8t/PS+QfNEjHQbycWyo7FktbiZh6U8LH/dMpYcxsN+WxBr3OHN HLATibiXSzgYmjzfWP8AyrzyB/1LOlf9INt/zRlrF3/KvPIH/Us6V/0g23/NGKu/5V55A/6lnSv+ kG2/5oxVHaV5Z8uaRJJJpOlWenySgLK9rbxQMyg1AYxqtRiqZYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqwT8xvyU/L/AM/xFtbsBHqQXjFq1pSG6XsKuARIB2EisB2x V856t/ziZ+bHl/VpT5M1qO4sZhtcpcPYT0B2SVFJBp4hj8hleTFCYqQEh5i2UZGPI0of9C+f85Nf 9XeT/uLS/wDNWUfkNP8A6nD/AEo/Uz8ef84/N3/Qvn/OTX/V3k/7i0v/ADVj+Q0/+pw/0o/Uvjz/ AJx+aX3n/OK/576ldpcalLBdTgKguLi/MzqoNQAzVagqTTMjHijAVECI8tmEpEmybf/Z image/svg+xml eJzdffle8sqy6H0B3gFUFGQwEyEBB2YHUEFwwJlJRJlkWGuv88d59lvVSUgICWmQ75x1716/7aed Tnd1dXXN1fF6iuVQsjmot0J8mHG7vN70qFWbDEYxN2l1n3e70/FkhE2+G7+bZcMMdEqeS29qx7vW aNwZ9GPkEXmYw7d951e565vTrN/t80NbpTPptqB1Mug1apPw+K+2X5sLXs7UJvAwciAfMKKbZWJ8 1J28hOepwbTf7PTbqcF/YPyo6OYZzi3AU0GKwuOzzk1rbO4TjrK8jB3DnAy/CLwYluBNQYInDL6V GTSmvVZ/UhwNGq3xOD3oDkbjmDv9T63vvqy14UnNXW11u4O/3alurfHtgtVG3nKdbgsW1qtN3FFc ZfKcfyOv3o7hHXgdf8fm6Nt5D1rKrckEoIKBESXpy2reOB9Aqv7ne7pptTsEw4CIF78ycqXVG3YB KWRRPCCFl0XtX7UHwEOehqJsmJdlGfAmhiMy9BMlPiwwjAC/RMgj5Q193a2/Oq2/Y+6rQb+lLC45 mpQ7/9XCqRg3xzBK68202xrd9jsTWASHTbKy4stBs9VVm8i7uW6NLJT8x+o/lQ6V2qjdmsBODbrT CaEUSZvhator1P5pjfQJroetfmVwR+ALiUJYFMWIWxQY5Rc2HHFLouyOMoA6ScEgC8tUp2TJtKwy No6E42gTRHHvi7Az16NOu9OPsYLoDnHYint2Ouo09S2Lcm5J+UHWEZYM/5e1/ysAw9onk1Zf2eZs v5ke9BDJY6Re2Ng+7Hp30FaezX4nT2C66VCBlfz9BvtRHHX6CIPrijyR3ordKTw6HQ2mw/P+x8Dl U05lEScd9a/78MunOzWajj/dlcGgC6dtroP6SBkFH44mxt5L54C+9uPrA601drrW7Xbao9rws9Ow Gt7i+Wweu3eXTgjbNGrpY5A/Z/8ufbPcIKi0gnL+0WxwizeWz/BPrz7odsY9fWBDi/67E0XARnVb /eZ4Nozypw5YofOX1rh8sEzrA1idYWtJa7b/V6s7GBrQOGup9Zvu+9poaDcsQvfR6TcBK+VpZ9LS N3rQGyIDd5c/a0NsXuipnBA4PcbzEQotPzgrvyArT5ARTv7ptsaug3x/8Hef/OGOuXxPgJLatDt5 8bsPrmq9ljvoOih3gEm3tC6M+9rFqDzwG367cWn8MO/SuCLjfvgH/riAX76g6W+34L50P70w7ia0 Pty4kIE9NF0HxRoA54673AcwLfxLAIQV6eA5rrFY6wI7axEginWXnbhBkMauhdZiY/bGt+XTYmoG gjbTKvgtwHBGpC6skHRYZyNZRnmkHBsc5v+ozTCQqdFmcBVWTV6CclJzed8OtL9hr/GvTgOxURv9 o/z9cFm4ArlI/vBtN9W+QC3lCQzedvv+0+v2oUMIf/SBgvxAQt436+d/1bpTtYPsPjiHOeceT/4Z qk8PkqNRzQqCXmtSawLgvweAXQ+Av2qjTq3eRT1o/G8A4n8dhv9JLMT1Po3PTrc5avXVPiayNXQE mTXq1KcTBDRIHgUX1xIb15Dn4ZH4H95Y6iXNQ4zvOIPp2+2P3xpg5wx6cZvOBpi5/9lt0NawuB3k QewvuuUBHY7/rYvDNQRpyHFNKoC1A7leEYQ44areIeYk++9DlXEVi8TQHTS+W03n9fXB6vv3rU2D /k9SwQq84N98WCiRNL/28cff/2sScNztNP6/EH9kIeXBdNRoEa/Tv3JN8yD/4wjizFN2cNOqdf81 pP6PpcBzXM3MAfjvWs1/rFbzd6c5+XRcEScyYVbk2H/ZilTgF1f12eq0P53VbVYSwgLL/9uWpUG/ uK76YALqYaH1MVEciM4rdB+kBoN/z9IWF/AvEbYgm/4fl7WbEzgbAt7ggMAWRsVd8pxl3TM/BnFA uwu1fntaa7fcxcFwOjSRLnmhOGqNW6O/Wu5K6z8Td7bZmdTqnW5norJoMRLhI7MJZHdtNKkPaqOm u4HBAjfrHmmKnWPP9qilrdexb31GGRFO4CT7rpwOgGNPAwCOfesLQnyx2zzp4vPJqNYfD2uwr41/ YLpO0z3u/Fdrtk0a2mX3sDZsjeBhb9olfjdNWjMax8RO19PJcDpx39TGk9ao81+ko1sPtajgRebe uWyNPx3eYOb2X6Mldwd61SYtWHmL2EhLO3/3QaUfAHBtdAOrx/3pstXsTHuGCV8MJ9+KPNX4CqCC kOHEbbB/TEdCIxfAvIr4qIb55rATNkFb63bGpqZebfytolnUMDasNXWzJHnuTk4ngxn2tP1nDAeM cX/MQB6RfqG/Wo0JkEy91q31G4t7PfcKYKzb6bfcEzhrdD3Hk9HgWzv7rE3nRrczBJJE581/4Dy0 AW0Obwy1Uz/4qzUaooN0xl4ANY3BqNlqLm6D++BqMJl7vCrvcRhOp5YDne8djJqjcVhx4JgV74Vu tX5/MJmtXdnlhU4aHsbjeQ662HHabzh0AXkHJ6ZJdQSML/9nGNYlpdXo0GEwbE4dOoydRmgM5tmY qQOSzvIOgz6QyEShw6VzqT112iasyaonMOJ5lsQzNj1H5p7RiHXHueNnufNDZd+X7zp0AjY038/A lc1dP2vN1qi1fLwuiyezNlnaCXA3Ia6bpX16eGzHRkZu1a/fagPj/2v5YPUOnsF5CWYGvPVXq2s/ yEd/Eh5P6+MlC8Muze5w9DGY8RcrKlO69UDbUbUDS3S3e9/hXm30PR58fIQVdZe6+0jX+yl6TwZD 6r5d0LhnCLDpDPyh1TRDTdHdADVF7xnUFH3noF7ce+xLNJx6bbSMuLHfyBA9dOg6BGHQ6X8MnGYe GVZi3YUsRO0T5iK2C262PlCKGsxZa2ZMOn8N6hNMZHLsqIiij0532RHDjmMMdjr0mZMfVr0ao2Z4 Ahq5ppFZnSDsM240+ssOo9Jn2G38Y9BrFvGmdKt1W+G/KPt9LiE77DUYtbWxlvZRx7Fi8NhlOBh3 lhMZ9oL9Hn4ORv+lcraoXb/BqIO5YA4DdkfhmYJUx3Sx5X01WTkcTJYcG+ypMztrOgNadFAPsEe9 M+nVhmYRadebrKI2Vl6i6DpYTuGzfnXVW7qsY7M17rT7TugeDkdhYkItoxbs9AlMbNxaxhtJt7/p uhndQksGc2Qi0Enfs2iUDwuWjAm6dTCJcE4cROSIU3eDOGClsLVsmnWeSQNWdOqqC4OozNl1NeJI ZG27GZBkxaewS1NJC1nCFqGTs7Y/nnTVXsNh035G7KbOOOtnPyB0wZPZtfLxL/RF2m+N5lyCS6dX +muGgiHlyGoGEL/dFjGVdJM4PnPZYAJRUuvsRpuKyryyO504WW3icNZHoA6Oxi0cbWS/YOw5/u4M gVv2v504HCoEcNzbluu7GNQxvcywOt0TA52yxbL72mS8zvlP1D4FtKIxexGz2IiPa6kHRX3rdFRr ooAgbyk+FTtDZPaO4jc4uFP8ASk7f4AKumrfV3RrybZP2c4HoHRLo/WfVq3/G6P1T+ORwRGWuGFY o9eqP9D9Be5On7gcUCpbuWwWqc/3ZEg3d69B/1Z2Cq6hmMm9pYmN1TG6Lq3IU+uueT0NEKHrE8BI 14aKA7TTWmKyaOOcItbg6FQ+p716v9bpLpGD2juYtwz/5pZKV61zDojqvlXHd5yhIQncmcHffSWR J9/pNw0kTvuamdI5zkols3mZpMcn64O/dFtu+atp3arV4V2+0/NvlaY1fc+5iOOEmFtf1r17yzZ3 VPtndWzOv7UaMuffXQWX+ObKqDS9tAIm8U16RF4O+oPG52jQa1mh09r5s+xdM1KFpRuCI9gjVaCa 2xK1y4+i8gJIHudDXhl1epfoUXDuCvydsich9tRSA37GDQEl50sNc51vEiUGQajMwnN2Jrh5efct BzeM9sI1UdtzgHhA39+D0XdhpqKu9l7KyU1k++bNuqBWlrphtNdS6MAoLPcdzfW9cTBR5jqvAIMR Q8voWQG4019iAWtds716q3meThdHxILUpOjSU16e1hGNg/7kBo1EZ3hmqh+FCFW0m4ohNkelHi0Z C54rmtKVIdNmKbLNL17W/rNED6UaodO31Ulp3lf01JTJb079OmqdqtKp6JyrD6Hqt2WH0ILD6xVj LM1R4Us2RoN6baLUjc3MDuihrmqmdppNDtkc3hrW+pp7XJOx5btTJGGFmCcLHjv1cWHQqC3OAA/J wVGsCJWm9GcAXqOju/4NM2b7jYEerxX0B6TUQufSM00eHpHyHKRdOBANi+daheLik2L7Y7HxoWZO LcDpu53GDKz4ojmgF77M12Lgjik1Griz2jMX2UljC5oYyXL6/FyKZGDcJlbteAPHYmgnMfY/bGXy F42PnL/EJRM/qVefcHL9fhy955lmvBXz9smf8fPx4CP3Xpju5TyBJ8bUFji5qx8wXHcSSd5UcpVE bPgii49i79HlPQy95wZkMJgvPk6Wp7e+ZL/eHqvvHP/0kvn77PZodFzrn3bvvuqp98tSMhnssy/x E/ZOymw3p9lM+uz5hQwVOD4aeoUxv1MKnHxOeAKIy0sBygqAHNWTweHVRSIvj4+ls8P7cG7wKNy5 vNnR8yOTecxVK7mj5FHDCp7jof9wCBOchdLcztF7JjxN3Cajz29VsTpki7nd0kNXna+R3M18DP1s snIxmeptLq/Smn/wT2Cci2kmfP15OBoJmQ7DiVvDxN1eeUfpzjLFWs4/2a1lgy9XBykxyG2p47wP EqNRfFwBeIPnDBv6iunIiqdu0i2XdyzlJnfc6+B7Vyy19gMRT9p/LRyWYpXA0Y34OXphxodhviBz geNTz64w5saXAM2dFD4YS6eC9BP/gj/9fqa5W83MT/o8erl8LpFJgcbmp4V3o6+R2Plr2HLS152r gu2kYid/6rWa1OUdjQ49vtGY9Y6s1jqWiuyzsMXF9q0mHe8FL0M2k0Y+fbW9apZM6vIurFXwPwcO uXbJctKt3KuwfTvsFqwmZXKpfMJqUpcXphW3d/oj/5E1goXqK5P7uCpbT3rqOdxlL94qlpOennEV Mime/UUEc4/HlXcyKbufrGfnd/V+9Dw9LuCk8cU99VX5py7rh0lDQX1SmEUhpQKTUtda3NszTRqJ 9N6GdpO+jV4++xWbSRM1MZrbYV1e07QqKZ2839hNerbD++LP1pMeel7G25+tG9OkwGGUaUtp//HP Tq9gNWkg3o0d20wa+dw/eUxcW08qVKtMTmaugMas1rqVa0d3bnrctdWkTO7lJWczqbjt/e5fpk2T wizatDXmNPh+Zz3pKZPca/miVUv0TraDJ+qk1ZDPhN6TK+Ho2aWcVTb7/J2bW+vjIVOIhlic9HBh 0rPWQLyphTiYlAmZV1p4eqyZJiWzqGuNfjdzr3aTZpjL/RfZetLzn1jia3R1YzlpOb7Hw6m0Xqu4 nW+VecZm0qcQU37zb1lPmj9rXT09+n36pC6vYdq7vX7bdtLyZ+m9bjfpKXOXHx5aTw== WuC9Lu9tLnF4ZLnWu+HFlu2kd2+nWxO7Sa+Z+5N8Rp8U1mKY9vI4+/ZaenmxnPTl+vvcdtKvaqSZ s5n0Gbgl8zLuhqzXevU17F3LEm856dt5qG876chbDnj0SVGKGc/qLZPt9C4sJ5WuQluexEsoC5Py YfOhmb5F39RJ67zfdGhcXv9jobZPpuX2jn1n82stMO/7sSROemyaFIb9+tGYvnhgnnQ82D1SJ52c BGBf5tfqea49+ZVJU1X2fJ4VBkfj22MPTppY5EnnIW2lh6xpUsBY/GxLVKY9YfMhEysMDoUrRdLw O7F0fn7SndGoVu/jpCnzSkfJ1kCj3hTQmFmUR75iqqQ5iZXCJgRvDVrvFUWmtmpv4jxIZ7e7r4OY 1VMikSNn1RLbu7N7+5M5e/dObZ8C683s2jyFHdgNpL0qt2RaX62o6bkosW8a3ONvyfy0/7n1YPs0 WjyPPetPF3Zf4vZv3m3flj5rr3u2T5Pc7mPD6qmqwxQC/RPO9u1C/fojbvv0eqtRP7N5Kp3tnh3e jjWMfez9yKa3bwMdTT39YLdi5qf1i3Lf9uldJvA90p8uYOzeWz/w2L59/5yJHdk+ffe+RnesnqoY +5oUh2e2b3/fcamS7dPed+741e4poKoUj8wwtvj8ghOOH2yfNvr1csHu6a5n9/x53x5ju9nkZb1l +/YFd7LF2j1Nergdf8wWY5EzJnu0r6065oubznSgUhqfqE/T4UPT08r76X7S+FQI3iBDKSnGXDq0 nwbdcjJ8fUm3Pyvo1EseHctnO0hZ9z7VWj5pxGzMvvFD4u7jtpysVLz3hEUlK5dNIVsbPXkDqcH4 Sm8Du7I2etwjfC7GSp4rwsw8+/k46wlmbu49wbvXsif41qx4fE/+Kf5WBBL8TntC+bfIolFYbSdL fFkCqNMBsE4H3+JOVP5AS3yf82h25YuUe5s81xLxIbuVuQhsR7Sl7faSg8wrkOm2vMXtHRWPM639 rJecOzRnnjQsWvdzKT3R2pKX9yT9jmPpp6pjPzDD6js333o/l9e257730DNwHFHcpl0L2GLRG/8L xYg7fT7+RtHPe925rFGsRdxGod6gGHHvvB5ua/22e7n0x4V0cHnRisKf+9vJ6GOXV2xkPwjHj0OF Tpgx101Wkv0ccxER9hWyQfcHWMsRThe84lZVuMw+Nn4+DjpHdb/4KBbOVLs5ujuaCeB0cvBz60cO s7glft/JU3c5eGhLv9AAt5WrhY1eBVvwmFz+sGgCz3I3hKvMuxVwhFvq4FXfqMA73RFpgDstbT8a dH478KSzOWKxxV31ZjlwQGPK1l7l72jAy2ZvczPcZZLl4PcODFCqHnS2Y8G5CQKHZhqLGUBh9yKv mY9KhkeQBVzaob5SNnjLhvRJR1M+zVBMCjr//LREO15z0kBsMMnipEOCFoabJj7Tn8Kbui+gah4P M9lGsSJqbsX2NNuoth6UNo2P5zPnzSPQlHLTbjReui6ib5GbPb3B38AI/5bPAergdy59EiuTbTdY FuPA8XF2D6At7yOMYbLq46GvOVZdNfMORmWlbW83ebt9hFoBs5Usdz2jXFa6OVAHvWr8BI6LuwOY BYWZOPGxp+qLO82MojYDZKmDz1bGq/wAOriHwYqiam3BfLMtIcvIoJMhN7+MjMGrQJbhNfzAmWPv P8WYQbTOgfezEnDkVC4Fr86fWYFnAdy+LXC4FhW8MQ14hEIJVaojXkh2y53q42m7b7tg+HGjLFfx 3VgsF4yrwvLlulbZjb2tNUlF5ckLu3Fa7CERt/EgbStcR7wgauyddCyf3hbBctr1kh/c3glzjoCc z4YqaZyvKELnpwzsCxhId5T7S0F8A3Y/9ZVjWDnyleATj6jB7fpmvosK04Rd9Xq1H8K+eiCJy2Au AhF7H43rsE3xEC0CXXSn7fT55zcI1LVxFYWoJz/++oDoCORSj/IF+i3nULgSAi042o0VR5udympw aMYyM3xNr8fRsgjNqY4RVSJb4+Q0v4sz31jufvb5emLaq8jwQC6a9oqwd5fXlsHPjXjnoRhR/VF7 yCCCzmx3/zXL78Tzhbm92t6z3KtWMbyr7osFxk5ipcvNYCwToNzJXZfKD615w2sWHQX3Jvm6Okgu LwIVpgXKASSwWatWIFnISic8MU4gDQJHugpBWIFyXi6WgJcOPy3F2K6uihhPL3FeamC6vBbnt7xE I6lzCyLf+fSSfbE8vzkrxcpi43Xd6omMqAbW5sZzeZURT3zZPBUpGYTMpWzNI2G5CmOenTqiw5jO nU+yVv3mUG2giNrWJbcci3he5mhCXzq8PTmdLX2ojy1VdvcuTyvPX02GTT23M+Gb26Ae7iczw1C3 I50nqbLSSiYtV2PnRnwYL5dxLu8cITrrWd/SZHW9zeVdOuJ0M5rgTIp9yx6qEY/q+/o5sKJa7HyK 3v0LM082SXYa82JuXz63N70v8s6m90Wmsm5W2RdppMhSJ5UGjVCCVFXtOrXhtM1TXWt1eZeqXTRM St3u07uB7eYAT17nGN4tCJmlqHR5nY/hiK3t7J39BpUmHQaQSafBroLK+hilmKOWvbJhfmsSgzN7 n2BnckxlXNKpsWe6GutAY7pqb6lscKmHT7PSaYUMl8HosN79yQmVNbn0aJowdkLFPuiM5zPdeP4t xqpbu5vB2PGYjvXMrKlFDV3RYYAcTsv9lSxHW5BWtpGtzQYEqTpcCSQlwmsNFBVfoQDpbUR19uct bDulun1moVQv8Y/NLOxyfD70dKMNe+hLRl89Ye5lXE+lP6Nnw0w+/5PSgjVk0q9zprlXyxJkuLz0 RjjJFrIg55dx34EBuLwWODmzwcnX+Yp7pQHnMqd5auBNHNSSleSey8u9TLzUJGBlZpuWu2hk0/iU bHdjEtijBc5FsxuYg3C7qgfIaN3M8eQTX2ZixSDWJ75PbhZ7XUUu2nD58+UuNKOmREvOq7vQiAZr YyAiAokT7TcIJAxu5k9WtY97eyP8hL1YMGcoXWiWnt4LkxNtTe8LvxPz7ZC9Aj7m7ESjON0wYtgs m/XxFnbf8XT3LlZ3odlgbN6JtjbG5B9m8bys46/qXVC40Fy0QPG/caGpUR4FKDsn2sp4iphAAilG QfNzvpI5igezgcI561qmOqgpJ9eGIOJJrDixCyLmkc6zlB5FZ/89UOD2SttkoOR52hnmTT4um2NB ZTKTUwkjvkxTeZqDhj+WSxX+5DbmM+0V6JbWrnT/LuECdhjzbwpjFnJ4HcI+ufXyixHedRgAgPSx 9/NgC9JcJNERKPNpowXJZO8jUAvi1tYba61Pz+2fxypiZUtZ1j5vC1MfyWc7btLQdT72ULY9uusE 3k6LPTb7Mj416fxrBHPSALdg1o+s+RitzEXCPqDWLubtdEtZiTAe0YTWHE4voo0/uatc0u2+E9r8 PmcPPM25I7Sx4M2jXd+8hwRWuPwQ0x5h3ES/brj9msb8C4FxC4pw0UpfMiJtlM48noHGLGIfrz9L Ylen5T6toHN5KUQd7n7lN+GmmY08B+MqLNPrwDJxPDgvjrFCpxEtnBqob/p1Xcflndd20sARYpTH giJ95OGWGCmEJ//2bIy/HRjcjJJpIyPAAFZXeHAtNioPwugQIaTkTrd4XjZhqyBIgUX/prpIrLBb gaVgrk1w9fXNPIomwlj0TK4lX+4GxFzZEI0FFnmN0S9AMiHnA8eOfBPR5hjlmQsbu+hNF8SibeAY xZL9hilnf6WIRxoenI9W2jU7fzLAvWn75eFuo1kEAKHJ8WCVRUB3crLPz2YHqi3aXN5l5A7bvREj BuULUMeiH3HN9Vkn8Gj1lSvwvjsr7+HaNLZW7p21WCYV3DiiTbThN7EGZGEBIpZdXqtMZmAuBUqc 0IhlktO7Ce8hws3ScRh6sfz8s5JYdjl4IhBG4ddiWeEw9xsSywBSyEos28Qslh++2tblatlzth4S WN+mxPLzD3KYTfgRCbJsxbKuw6wqlq3yuezEMkpkLcePTiy/jZaI5ZiPnlvSiGUA7snJWG9Nbg8s rSS7wOrDg0Vm/9JsRf1sl+O2PPlttHG5/7BZuf82WkHu2/mr5rdb3KgljnlDNLa9YTw7Xx9usrMj ZEY7NA4/Jb7vfPZpMl2tvH5c6qGaJF4/l3cxMv9Q3azXD/OUdL+fDcGumEqKKoSZ9VhERqhSSY1k kXr43lq+k2pkhNqtCIDSOpUNbkXAmE1oGGGcmAP/zoqMJYtSzn6VXiLTkG59bFKvl2baL0tRQtwd OKrXKuXMPL3OZz/18OboZFhMTCdYnJf7qtjSdYpUrPMafEiWgw+D5E2/nk+FpMH1Ap5md2iZb8vi xm1PqF96c3mxejrrCSX5V0/oQs6qhdMXctUT/Pyq4I8wtuWw1DpN6q3xBonDZPm795Ft3J80cC1Z rMisZmrl40LOPzpD9+rOXi7zHdrCKmpB1ZSUAuviWaWYDYz5XV3Sikdf9fNsPZRYLLa9OrnR92pJ v+IBM1f3at+zFCtS9BtN38Mhq34u72LPGEsz81bu1XLExX7NA7q1bOW+KGce8lRrwQuyIlQjnoZk Qz+7StnROBYYG+4hsS/kFR4+C7P7CewKeQ+3fLaFvBizMGwJG6YAL3AY7904Aidub/+I02c98m5f Z/xEV6PdcyggV28GY3KDSoUCvN1C67PpXATdMgEH1qtlfftV6YECd0z26umUYmNd3rnCf3vwSmsX Ru8fHRhojLoeG6ux4ytN6vIa1o/3Da0zqeAvKpOqroXCQyKW89ZUGJRYktgflhOHnckDjn2bDew3 w8lr9uQe2qZbJhVrSTgmNx052vu6OWCvwVsZTcXdnl0aRkbX6hwyh/cpyygX6hnnbT9DJNEYMLWv Gl1wp9AAZ2clFXcXsOxcqGILHHKYhYKt3yTwZywMroy5sn4Fk6u4R12XQ1fDu6gTrkYq8xHe4u6A LkccmB5dyXJghXxLGuKjrUyZVwjtq74tAtoOCCT5lsuqvqkSkp0QiLOoKFyIBv7igJgSy5ZU2C1B oBVHqwb7dhwtq9wISmGp0nG0atCSMa/ugX/Nru6gUSq57OLtMOJGEsu03c8+Vx3sXCofZTVkmYq3 DsZWj8lYZ9pjIIXWs+NYCQ1HeANRUQSJMvJOA5RTloS9V8geY/YRiOX2sNXpVXZfO791bmB3fnO/ Ob0WOSR1jio9nDqMUue3qHMUKUq3csSvZ3Xq1PtgLTyFzj7mWo62It5lsXTHCh7QtxM2FTzNU72C Z3nNCH3NqWNRhjqUGk2gKpSkUist9TbLvL5Tytt6qEs5qXXL+XNgX1tsWcA4x5NpzIu5fVmUPr/e F+dLgFbdFzqVdaV9obsJaJVqZXPYCj0kv7mcCauVnSuZXKsdQ0rl1YzK2W3zVoeG7k4gClSqOgwi 0zH6uCoq9Zqm5TWJKxvmk+MfKzGo172aBeH6hvnk2CwG7Whsptpb00H7bCWTY3anyg== wu6fUTK4oKJdvHOv77ZHU8OYhfm8tvE8OTGL+bUxRjK1N4IxOtaj62N2xDDGU7kop5dYjvYgrWwj 2wK1GBCkAsngUZwBRcVXKEDSbbblZ3/ewrYJUGKQaSFlxto/ZrKwna65GX7YX3PzMm6bkxhcXmcj fEkRNOU2uSjLZH/MVudKwJki71/ny1NNV1U/YTxUc2jvhXOq3+JeJj77GxbsfUpLarRXYS5OudZY tLyOB8jCulF48vlyBrH6ck1aiOXtQBZycUnJMoU8cy0e8SUIdDjitgi01GDPraozV0TgnO7h8qrV mezF2M4Iv/i1C22+sp7NL5gf69X1Utw/ttLphhGdXWgu+urMnRhrvuJgreonwJhDSRZ9JTR93oVT 2TF1FcbyGw6xEnoThV0uLwL1+xxUFSQbF9oKt50Y9+9iungVwpJct1m2rVOe1oN9EBFLQilreaj8 9/k1k5mNGRFaES1Lk51EfRXCyW10b+Gum5XuEzVV5tpehbBaLU9+zTxmK4x5Hd2vlJXQs6sQDBHe Ncuzac6ai648+5cpzKq9j0DRJIFSpoDmrSNWK2bSWSYuF3u2GjreBV17o6rGpzu4WFMaNitda90S gHCvFLYy1FjZlomWf51XvFApvJHbgBFtiSnt7juhjTZ25aIqX/5tPZGijZNiY+p7ih0rvReM7LVp bKWbEVzOhb44In2Zr6U0V2ZZLPT9avlsv4zANHePaOr4dEE3k/u2NxB8tRwvTHYMNyla3wxGjr7e XB/Rtn4dxjugvrfHdkSr+vWRla4zu90US1QXfFhWx4IqfQTFpCFErHGY9eqMaS9ypo6MYLVrYbqm wmNTKbwYa1mzuJffzK1NpHh5wb9pnWlPU77sfAWU7fpUzq+XLzuWKlBXeoc3R2M2gWNT2NgQ5XHO 08eqb6c6TMtUApRijiUmoK8cH9sEjkmBqpPPwbVCxOO0Olxz18z+5PRK30Ogqv/Y++E2mUWQts3d mcsioDo51eGiR3Gte+HSK30UwbF4+W5Aa/E5rW9Td0Mpld4L3sO1acz5ywj0lgwZj13re0mOYnkS WHYXNGiFmxTLYCjSaxfLqeieQizPqjgpxXJt640yZ84olpdVCm9GLAPaIpu5S40ULy8Ry6abJ53K l9cUywseElK+vCGxXNu63NDNkwRZTmIZ7f3VKj8BbSuLZWqPYnFZPhcpZF0ill1GK4pKLL+NVq/7 tF7LfC3watmKVnWfCzwZetZpvlpEL/djPmGjch8g/N6hlfsUt35jzfcKdZ8UlvjbiD6J16buU/X1 kfp+2spP6rrPvaM71vnsr5DpOuf1q49NXr85ywJLWTfo9eNSD82p453DK6aSYuG3zXUFhsiI/YUF NmRRH9O6Falvn6tu+va5+pjarUhzXUE6HF3h7NOVLK9834X9Jq96XQHF2Qfq/+11BarcV8SWzhuO xRKfvBkkaqluNN87DDCZV4tjMftQ9eInqX03O1GsmC5jxXTB5fWEpNCb5Yeq9ytJcc0PVZs+U+3y /pEPVZs+U004/+Y/VG3q5/L+kQ9Vmz5TvXwta3+o2nYtG/1Qtekz1XgTxR/4ULXVl743/6FqE3Au 7x/5UHVg/jPVsJY/8aFqE3DEB7v5D1WbPlOt1b5t+EPVps9UY5baH/hQtWlS/Dr2H/hQNcJg+Ez1 zKuw2Q9Vz0sfowd+kx+qXjVz2KGM0uZD1RaRRINm88sPVdsBZ7aSaD9UTVtAPqar4V3vQ9Wm8Rbv 6nQ0uWg+VL1SDS/dh6qdSUVZC/WHqqlLluc/U22fb0lLfJYfqnbOt/zth6otEGj7pe8Vk8eXIxDv 7KK6LJP2gAysvrFjVWFHjcAF14nTLQEOZu+y8uwNR3lsyrMp/HYLX5Te4P15enE27dcZnDJLlxdn r+KDtSnPXgdjm7ky11Sc/ZuoqFqevYGsG4rybAqQyL78rjybojjbDmNrOq1sirO1L0pv8nKFxeJs my8ZrVKeTZ2j+KvybAqPmm2Uh748m6I4Wz+Va5dnU3A527XQl2dTf7X8V+XZFptoLs6212FWGNGx dtFKiq1Ynm2gWrvi7CX7QluevcK+/KI82xKL87GGjeyLo/a74l2dVuXZv/8CO015NoWyoX+Vae3y bIribGM04beV7vbF2evdaj5Xnk2BSrv85BXKsymKs1eOii6WZ1OUGlvl9a1Ynk1RnO1wLxxNeTZF cfZ81s1a5dlrY2zFCkrH4myn80JRdkwhpV2UQK1YfWkCaZZtu3559iJIFnnjvy7Ppqys/2V5tnNx tjHXGtfaMicOUq/U6uad2bezre7oNn49m75Wfdm3s6m+J05dNm7HmEw1VrTgrfjtbKdM+818O1uX yNZfz157N+a+nU19k96vvp1tpcEuq6OmUmkWlmv7bfRPuotcHAvRSRU1sffX8Out9u1sy7s6qRFI p8jQ36vwuVAZR319CahDBj9//s9VjNvc1LrhinEKL9wGKsYXa0X/RMW4PcY2WTG+gRsOKSrGaW84 /F3FuDHn6s9VjNN80eD3FeMuh4SjzVSML2YQ/YmK8VmFnWWx8aYqxvVK4SjlQVunYnzdb9itVjG+ HGObqhjH/OT1a6doK8bNsdc/UzFuWVm/8Ypx+rsIflMxPl+V9qcqxpfljm6uYnyluwfXrhi3/VrW RivGN1OX5FQxvkJd0i8qxhdy4P9IxfgGaIyiYtxFL31/UTE+R2N/rGJ8lW/Wr18xbvPN+g1XjJMb QTna6Oq6FeMu7+I3zzdfMb6hGiuHinEDJdOXpq1cMa74+uxUnk1VjCvaBb8ptNmUpq1e97pOxbi1 72LTFeObo7HFWPbi3YMrlqatWDHuWsl0Wbdi3Hxn15+pGLe/qXWTFeOz6qc96vvX1qgY/81dN/QV 4y6KD17/XtnQvlpOUdLyi4pxu+/ybLZifDmNLVaMr1rfPXc7kOVHHzZXMY7f4LbKl95sxbjyjdTf 524trxg3c5g/UzHucvZEbKBifMZh2C3ar5KuUTG+5t1QK1aML/GQbLBiHLTxWc34H6kYJ2LZ/gsg m6wY178AssK3gleuGKeIjGygYtzCSvoDFeNk923LiTdVMW6oeqZ1WK9RMb7eDYerVoyvZImvXTFu cUfEH6gYJxVDd5v8NtKc10+tGHd5rT9xv9mKcVjLrGb8z1WMW0ZGNl4xrkdGqN2Ka1SMk7w+20/c b6pifHb20+Hon6sYd8i031DF+Er3j61dMW5z/9jyivFFPC2pGMfacPwG95+qDtdrw+Hs/7HqcL0f YuxPVYfr/VzeP1cdvnwtm6oO1/u5vH+uOlwvtl380vfmqsP12nC9amDz1eE6cHNfYd5wdThdZf1v q8NNlfV/qDrcsbJ+I9Xhepk26Px/rDpcrw3X5MufqA5XRUK3PQWM/bHqcF0xVK2kP1IdbpcDv9nq cJMO84eqw80+pT9THb65L+Utqw5fo15sjerwpV8v3Vh1uF4bvkZOL3V1uL5cy69mbKg63CKj+w9U h1tmdG+8OlwPYzvUWfyqOtzKStpYdbiGO6s6iz9QHa4jw+VIT+tXhy/U8P6R6nC6/LHfVocbswj+ XHX4YtXzn6gOX5ajuLnqcKcI72aqw/XacIds219Vh9thbLPV4XptOE3m8LrV4TbZgxuuDtdlvVrN 8Ueqw3VEm+5V2Gh1uJ6M5PL+uepw27VstDpcrw0309gmq8PtdZhNVodbSbHNV4cv2ZcNVofrteGb 3Re7T3f/Yl9W+HT3Eovv19Xh+mZb6Pwbqw7XNxtj4n+qOtypinMz1eFzttgfqw6nuleB+SgIz0tR afAbqAs3xpENCRIur5Yi0WvZf8A39fC6+gdAz23PfvtsU4W8lLdq6NLeUsOD9X1TfQH4nXtFz1Wn +MA6kFLq4cd8K/ZKpZwLGFuxlNMOY7T3XThjbPHm3xXu7Jpbmq0JvxJIJJL4RpWO5Py9dFtmZZ/X Z4unFYtI56xXE1Br3OJmF+giX2Cnrfek0PlxpQu5O7jSOZ3fwlK31/RPfJmRnaZ/brLTf/0V5uxC GZoN56er9l3L6Wh7EziAt2AU/8bpCON5V/gyi6PT8dzW6bg8D9Z+N/ZWOjQOVtL5eldSLqust0gJ +90nwGcC0eXdxM0Jnwvp7fMItPkO7xIELknctkWgrQ6DxetOyWHUCMRZsHjdyZ5QcWchIS0yRsft JbVv/I48pKlsoPPB9i6sdn+NrMCLjX/172KzXzQALrFwsNcrfdbzvX+LMccP/tH5LbF6ekPfSL0g Gd+/zxsnIFmkelvd1EqBJ0c/03zKnlLLY5eihcXrv/w86sw7Olfsxp9UJhkb79Iwv2aWt7UPlj+5 DZhvgFlnm2IlLSrqlFNHK95jJftjtsaN0/nVE7xtMXbk3wjGPFq92C8TqfMUSWR0X/xEoH6T222I 8eWtfBtr4skUNVoe5XFS8rF0nSYd0LV6gcZwScIClsZaHNy1b5zGuBB1kY/L61RTTCdzl0vcue8j n73HzO6W9S+KwNJ17fQaIrxrfWm39kZzwYOLshSbSvDakrj+FWasW9/EbRFK1fr8EV73Vg1StR7c HI2tKn2tZK9uv5AR69Q0tkLyeLmPPNnGj4iOHqoybmdBp+9+uW97HdLqYWyEcF9nmY66pWFEuzIP MuLSa3VcXooRLWtT95ORI7simFtLD8n6sVAQkxTizUVzNgDuHA3x2TruF+ssgAHQ3j1DVZu6nywu 3j24VvnY3WB5berc7juWYu+vaT6Z/MmEOjZTm4rl15qz9LfyBavWnWtTaWksvpAgYXYiLctAsPlm vQXfNDtCKArlZoFxwpO1ezoAj/u2yaJs9jlNYxRa+Rws13K30lVZSyuKKb9dSx01A/N3o3fcIYyr 3fdg/33ku5Xuy1peiK1V1/76kga7FCVLi8/5S+freB+svl+JdetrXZplhSyrexStXKSUH8PEEe3C H1Y0tsKVEbWt0xM7sXyvi2UHbkkplp9/lovlFeRLbeuBxqtpJZZt7iGB3ac9dzRimdS91jfgc0G0 2Yrlxd13/Hg3taavHz1Lnny/MbGM5dcgljdwi6ZStb5ULK9EY5eOFzzYiOVl36zfnFhe8Chi2DVo K5YBxlsa08wklu3X8uAslqkrV3Ur6W3kqFgtfPPcuX6d27TcfxttWO7HfLQXSnjnIolLyuv7v7xq cd4Sf1jBEaKOaIs7kxuEourZWUxi/brz2aepYLfw+r15lnn96oaPECy3xOm8fh/psIONiH4YmysX lpU0fzpduDCfgeuiuNOg+mu34sI9ilY5Sb9wK1Yt8y3Xvn2YlK7TS2S6z50fUKvXWi2PjdiyTC1a 48KF+bNfpfHzr2JN6kIL8y0LQthebL2M2w7Xg6nLWPZdiHnr9TZ2YDsfRcTcdr7ZjTqqxxHxWKhk 6weNXrLfCA2Ske700iQDyFSpbktkEoff18+5/d1rjbk0kruZj6GfTebvHwuzfQYrSQ== r7xXT5G5+/uV3l3vrNRqqTgpXKe6kodNX92XWrnD7HMY1nfvy/lLXDLxk3r1YWWKYg7MWk8aORyx mIhXSlOsjz6TQp7dafY+de+ZP1zFTCNWa2Yb79niaMSNk5799qh0EPLGdvn7y0gyIgbGn+cHg2nN 5d07a0ny/snTzuOW53zi9yRzNwdb1VcxtlO+3854v/vlwl7rcxgSy4Wft+h3s9BOfL9ffeZbZVm+ ej77uSuzw/xH+bPU6d6eHlxO795O/b63t3TA/1WNfF33ioH4h8s7DDwmJiNv2bc3GvE7nq1Ba3Dg ZXY+4/7HQuMuIAcufcc/O71CjHu/OUoyh4dbo9FJrOjZfzm99HCp624g3hASTI45OWZylfscc7o9 uGJOr68+R6POSWg0/TwGbjneC17Vw3xBjiXL2+09UkIO63vOhqKF3S8pepLOp7rRUoAUb8NKKxWA odUMWFy4YJHnoOyky2t55YK/05U9ga5Qwul5nXRjXG2vlDgMnQlKQfte6ufGGsddVih/3u78jBJ9 8crl9dxf5QMOKJq+h3f2d70PxR0p3k15i+XTi7338vmRIO9eirCqlCdZOaifYIF8JXB0ELpH4KKJ +MtrN3Ph852Qr2NXS0z2Lvo2Grcvthmu9LydjL4kWpnz3slDIjZ8OTR58oFHXv5kg9I4LBcvSp3Z 6TXQOciFYlo/FC6vdixeLnXxznDdyWH6U7yuwl6NX5OwF/dz4zx5rcY2433/JTf1BD+/HvC+i7vX rCd4ef/g8YVqW3jLxQX+iHtCSb7oCR3svuI2HXtC/dKzJ9AIy4iOSPKm8ryXrTPxKBk7es8zTXLz Bfkt3notfgL3vffBqrYP8Tbgs4+XTGs0CiZ7g8IYVnX/g23NXDrl2Up8bSe76U7tgGWY8ftupn79 dpWUgsNBIHv3cAadH7ZgvsA7ov+ceztrBhn2ddub6l2/SLl0clpLDMdsXfvi57HYCGYbje39RPzi G459Pj8hRhPDTSfbidF2c5QKSd0rht3zt5Plxt40WdqX7pKDQbiAiuqOWM3384nYdfor+x5qTxKH J4I3kyrcNXAtUZc39/52PUxWMo8ckHvwKPPBVPFaD5kla8U/3xOHomeEx8I/a+sd+hOFcqrb3wvh YLe4k5HU90/Mmyold8SUMAk85XyDdzbzEXq6Jpz/XQCiak5wnGrm4+U+muomujyOSOJBnvTnU2Ma uwzwT0gHeQI8kFfoIpe9vJNynuBNLvfmf8qLk+FrEfbqJAiAeHynk7dhHVb1ICBPvpgGEvGCB+/V 3d/O5PNnUXh7Ozw3jm9P25zMCBc+zqVboaeUEOn7CQloe/rgTX+Gzptn22FvVN9nPPvv51sAfI8N ZILeac53dn4eu0pNnzLn54ldvS3e5qrfqbPb/o8yHzethmCRzS29i/gofj0lbz7ao8zHwc5btrH9 fUKmgrUAAP5c9uc5ltv3BwPiduyhnG0ED0Nzi7ziYNJUn7iOdBhT35c3B0AHzyO8iyBNeFvmI3Uv 5TKRRw4IqVrIZTk/6DAGdHDbb98JPnXwpfzJtqMDgDa9bVhQ/vF0YAD+KPdzRnYNtuSplBhNc3tA DNU7hvdsSZnw9WeGbCLoYx+9+E6y5Km2YRnRi8zF+3gX5N3RC8MFW92UmLj/IfKVYQfVLrCmh0ny mg2V1c1pDktkf9UuqXorcfdxew8Mda+QKlVPGYIMQmMfsIM3vXLu+azQSl6nU9VM/txzt/CgzVyQ 033kCwXfxWrhNpF7be1UM+fdwFXmYzA6VhgXHy/vptqPpbv4x7SYRsJ9hrOPh1PRrggLm3U68k25 99PDoa+We/fHMhhuu1ZhfNr/zgY6jxNxO339tgCS2JzAvpzswMjnfTwvd2Qtzy9HL/nsQaYd8tWT khgN5zLVShDQFn1iuEk8KRe97Yf4RapxnzsZnxZz73fVJChTFQGPVCpZDu1cpi+P+mmVWzQK41Sp dH2bavSnr+q+SP32M5+tlx5QF8yHxRPx4TSdvREmKgnkq9108z54n/kojd+QCd/msuxoJxOs/eAK HkOZg9rhbqzd37sFuCK+TGt8Iqi48wgyUYJAt+S5wiT3FryLoRpbMpoNVr4prnAPxBmXcP+KtDOD fLGYe+WZc+nPaF710CJHAz6dq6AElMXbI7wVMHm7G38nnfAukXt85yLV9VYq6XZ77AG4LyUET8o2 Iu/+6F23cKqfl+hd6akCP3q13OHp0ylhZqQtdtWOd2KdV+kDHrCwFvVAAgCZVmfwdOo9ff7K1ivZ iD4YcLTUrfhQG96R7UbiLGdaD35+9ud76ps78mhC5GwPr35pprrhmwBYQS9+QmPZXaB5IZvztU5e koPP633VAtMfNL+esrVaRD6Wz7mBgtnLs7vvxOi0B/qD/7WUCd80OPJ0XudPI59+gbW0PytvoFsn jyx02ZjBLQ5MagtY6+1OIj7oVVPXk9o43op5+4oFdj4efOTeC9M9PUtAb5vd1nj80yNX1YDiGN2L 7Q44ARTjn7vEwWQ/E5AjwiH8dniROBgPT+DB5UVmWitew4Ojk5y8c9NMv1xsnxEFK3oX2rrMvV/u RlWn4zAJVtL8Mb0GkLlptvF4RITjDUixwxGezw7uwTnoAjxPfBd44ivkyEXjjYeQqV82sC9+iEdf 9fNsPZQ4V7I7duIfZweV5DUzvERCO1dE+bTH12HPfyrkphhyKxdwgYc0UWjhnAs+YKg/DaJsHIbe cwP99i5JHhx8JMuT4TSZf/RLsBYkP0PrTf/7OVvf3X87O3rm7xV1+PrH30hdT/d8yMzOMh+vW99n 2zenYeDyz/d4MdBPznfx5QO0DBh1qGmJUCAcXCZ44PKysOXHMJjMAQNsbwMf37uA/f3ZBUWm6kve dIf72cb3jwwaUDKEU3WIiILDEHwE9p/YIlRCrhc68t8HOgQtZLnECsTPI4XVbFv29DWMBS/ZrVw2 44+aepqdFWyl4wOQmE9QjbY+U6FYZkdhlLMfYBS2PDDAzVaydNX6grMvtKeNeRLA+wKkQeZi/2kH hmgNDVpfIwVSG9EvC29PN4fBx8xzLhMUAwb5eXJzeJ/z7b50svVyfpoNFMJKpXDKm8mn3vncc3On TXYf21hgAPEJKMHXHrmbazzHW7f+TqrxszVSucXO1jjnL3ZigePo3Vn6/Tu1n2m9Tx9zb5PPbiKW 89ZmD7ZcXmApL8cKD3kU28+gj+UN2gxYP2I0l+kGFUGIBzslTvKTo9xb98CTiGXjxaQcz4e03Q0O QPdoT3PJXiyo3X7Uvp73Wq9iNhivwQvtJMb+h61M/uLxPc3e9sY5z345pD/AL0tefLRhzyPRlBhk H3DEi9Q3W2tkcs+X7Wzg8/URT+A78TilO1/iAehM99PoiD/rpAqPgwc4i7FnEOSfO8Ajr4RE7Opb Tl0Xhx1QaWK78tfI8+TyqqSksLAPJtXtDUPK0dUV7MdGixmNjg6wyzZoLh95llC8PphisOxGBvr1 WFWQcjdbOX+1OAEau06HjomCiRufRMM9hBYKo8O9ON8ooHuzjnzdeAfw2fYkfpLbicRhsNkkl34R X8H2jzi9dHkNyuTifEXDDVx2OFHuvkrvnGRtVwq7r6z1kbuwWqvFzNuOKx3sm1ZK/DBWawXb3pva ySxdaYl2pWBX8udPPaPF0GyXTLhlcw+n7MztlIpx9YMO2mw1NCC+iDwj/EB7UM+bpB2efXgeb3u8 X9lG9Z1LdS8OemAWHkfQ45jCjwsUcu+xgZDzyaI/GwoMhrqNddAJxvAsPsqJ+5J3y/Ld1w+s5AJG ko/GOunMJ+G1KPJ9yDyD8Y/g6DHdvLu/VC3e42wQDTcZTIlTwGKd2cl8fJT4mR3rz4TD58E4c/Lh gS4Hr7psdnnl67v2de71eaAIodgV030Tpzf8Pdj7500Ypxgh3hC8bxF08OHTa/K6cPaIqn0p984l IwqNHcZ7Nwx3dj3NnE6irVQkE7rTnwLG4o3rS5BExQFIIrkGnLgxVuAhasD0nTXc9mcECeSnPUhP I5CzM5BA5zcDlRmXbYEKxLu3V6uDhLtf3O3ZAKXcI3lli6f52wqvwIZ6207ExqEBbvxZNnA1qIBh cwUWX7LYK7dz6cZNGv0+j3jkuHTnKBWwnPSmx71qzuLMOHMR2N9OCfdcCk1PJlke98tAVAfTufUl eCLF/FOQKhcPZNq5Sf3PhnNnNAA7JQWpuWSmYYlyBanntQcyKdiVxmljrPVOT45/aHd6YVKuXTJE RgxoxS8bF3S0Lq7PFqkwaeJ+v0ZAgmMWfCVP0T+mPce7Sp8VoEr78Wcr8rICCXSh70s7kF4JSGhZ 2AGFmDABpT/FOzhfaEGC86IDdVKZXC0Hak2QXN6VgNJBwrinn5YdWZz9ZQxpTXZEfH3V4UrUbzpy 6oGc5J4tJ8XjiDT2ctFWVNq5jajaHMiX2rJzDgfO4pRjnpI6LF7IKh/j7jcsJn3Qd9+O5LoWrOcE bwS6ACm2ucNne/RA66Mlqo90OLQmm4Hd/xMCBUjqc6qTlI0UW0JUR5z1sMVne0rV1rJkWDs+XXz7 oT0AQGP00LbGtsMyuZR4bQuryzveyrUZm2EHnvWPK8A6O654e7bNgV31uL63bY8rruX0LLVMLFf7 NsM23myHBQR9GbgAcpiFYV/smMuLDdWW+9YnrCAc6XFkI0fgT24LBQt0vNpsXXVgqSkFC4G4znDI rebKBAkuVWXPLSZozaLHX9n6wQfGNkqvROlW3kD/fOr7MjQBdf/5PtvYFncUV/j1q3hMwhHogVfM WX6XuInU3y4+vtEPc8MGvqN7DJtP9k4fTo7qSeb4oqc5Z6Gtuu9ppD+fUt6Z77+L8ZwfLb7kF4l3 BTO7NL8QrL8bRhfNceajUsJgzuN++uPos4iGu+KwP6yL8X7q23fzEW/tiUXcqyd84wIMlrO+4myC P6VZXOgZzDrf9uyrGaL/Z2YbfQEXzDJKqIfkTighsVz1VQkVsPnvSS7BXNwCHsKP6p97mXsllKV4 /LEtefotkKgRWuJq3OgcgxhcsnJ3GwC6ewkYbRowOQ5Pu8fVbH1wFkoWm/GmIVjF+/vbYMfd7mTO u7e3JscnCQShlcTEo5pDNzhGk8urhE8OQ/et1Hfha6T4B+eCObXk7e7hMWz33fViQOm+q9u2JCKF 33ycj0lxZ+mhQiL5armv7fTkSwmu5E9+BD3yg9vZSXde3zit7TEOW7LvnwWw9mHNzD5Sss/vM8TF Lr62f8haovf8Yc04PYnHPo2F1PfeaU4z631eY6ArffyilmvNXmPzVZT775feLkasRMXi67xe9IHG RiLG6bbk72QW0ObnZzHTBw8cvvxohp2JEj0ddRp+DdZ7KfHA+MPan7tg7+d8ecaLzulLOHK1XYUY mrvBfG6fO+a0bXyU0Oru5N738i9wAo+2SWQE3ZgZA0sBGkqA/f3QS1Yus3l9c1xezQ== /+uVsVMcWj1fydIVaJkY6tHRMYsgyXgOCkrwCO24+QfFRLx3nDYEfV74bBdsZOKA04JCxEFV1UJG 4ihRTudvQA/xn5MoHjpBJQw4PGldUl9JqfH4kDl4KEWVcNosGAXblPlIxJ+TF4Qnm4GKYrToKNmv 196V84K35xzujVvtrG/rrp3JeT8u5gNKF+J9zz9IDobDekqYpkqmiJTCYT5zJ+Pnu8Dx9uE2vnMG mA/siNssc39wWf5GHfVkB/Sj/SfVEfJ+fgyc6mRsiFx2vZWSIZQzH4QBi6/16v8A7SqHmTPbEvqg B7MY0d3Z9s1RHInhEihmb0LcEYpD15wHqmVuzYIs1/qkuJa5aTc+Kbt3gRbfee27uBjb8l9IJVk6 BS7YqpDAuPoOCcaNIoVUKB6PEe89MArvNF0YTK4RzKF2Srhp+nN6U8HARA45jMLCSGvvK1lJ336Q ZcyOoV8JtxWfLp6zb8PmF9DiVkQbjASC2Ex2J/R5z3Ah3yRZDHUraswf/yxdle8wMuJvXish++/W C4xTYGup7vd5WQvjA51PfOHLxfi++kDc/vGUT4c7hyL63bcQqYVovHF7Q4QWSfZAWQm41aJFC6I1 1u6nSing0lupwmMpqbJWRbqeMBhFD6NQ68/kx2Gq+yzHCAx6nGYWf+metnOJduJZOQJkG9lU/dMU 0VHjNPL4hHwyQOmH9/wnfhKjQ+IdVN+VO57sXn+3BCCxTy6vOTfk+DTvI9GLROzB10lxX2E1Jq70 C4Z7Sngk3SjHzCGTdGtag+mTLVX3eKgWsvVws4VWUqe9rTiWQDiO1SDN6O5UTZBIpTygMBwntFCP b5cczePdcqwTOK4OFE1BCfoQl+xD7eeC8Omzo9c7hhAX0cf0AI/gzZxWE/Vk/8QzyJw/idtKyi1/ 6BOSkebpbeLno91XL/h6mISVQodOMBZAPWqQrNzv7GffxWHD0M/iTntxB4DK/aAH/gsTaUZqoHP2 A0OQmon31MzWvc26iQQQTxktEUqVj2QtO3u5zHfw9Oj+I51guO3vj6z/tdYGPaMyzj62Jruq0Nv7 8CYOI18dZMcvChcAZCW1lL5sH/NdSMpQEiQJxyditUI/9fl+iXZlJ/n8nq2XqjPZpgV97t+PK6nu Vj9HojyyeOpvYDgGtbCHDHkQPbwX3zDtpYMh8lI2WPk4MMCFn6AA6v0Za7qlwj7k5Hvi8CwdxsHi amhY3d9YshxMgLLRqUxIsgtqzJdaduT4v49dAsMKbiHKiu6Dm2m3NboeddqdvjvoirsOkucse9tv DnKjVqvS+s8kM2hMe63+xB1zHyTL6fNzCfhrY9BsQXfvXDyn8aFnOuppV7QxX8sg/aPYe3R5SehT zeES42PMMPWBrGuPF6LEx7X+affuq556vywlk8E++xI/Ye+kzHZzms2kz55ftCjq0FyxBKLIGZQV AAHdPji8ukjk5fGxdHZ4H84NHgVgrNnR8yOTecxVK7mj5FHDCh6NISo6z9dKkfOZwFseORfqB6ks d5YgQfPEx23lKnkmvl9RRc5Re1dVBEWT7/a30KR4UyLit6+5GvD8pytDogS2SZXn1H3qe1eaaCcE j+VXp6bwx5kQ1APgbLDdPlaYkS9br3QOM/n84d68CVMAtb8XxByeoprIo6RHvEQTsWtfCznJKVE0 NTWz9pT6zpwxKg9nMi8khIRhp/RTCxihvK9EX0h8ngTkhffQi/IlF9x4NVyvpRLqOVN6WyzPHhzo gRwlf6ReOdxGsRp8ieTejpM1+4w5e6PncXAJyziVVaEU8vWUPKrKxVRWRYh8+ePyJkaNMFGkJ9lm 7LhnYbj00UwMn748+2LpVrl4OxtnlohmCAKWrYwjlzd2WSudKOaBvtP3l8NzAvycDXSHcfeTH2Nb z7eX8zWeZ+zyBZTP4uOBIeqO6QioVPWOMDmvWwWB+CIbktfQqkp1Wyk20bseltQw3selrKf7YZxw V8lHNybtFB7A0mC+CWtE5OfwEz6RgYRZmSJIxZNbEA3j4JzhkhxlznOPW9qfhwB3/uHDuKDGjxfU ndeQJky07M3rglgiGYGouIeeMOVd+diaoOkWJGW20Mrkdv2lVOSuNNEyygw+EYwEHqN0vP/J+c4f bmabc6mmuoYS6J5gdmD3MTdAswwq9Rk6QpqZ4XlDFfBmMauNPDg6U3TDxWS5C80weQ7PJeeh7UOU Lu1oPj5ye8e+M2OXe/kj0w7kaxa2y2G2cfyyDasPPphAArFaehx2zGL+ZVwvgfWSDYPpIbfErdxb CbpIrOZveX45er5KH+WSjXYDU+Su0vxR5ZjYuEoCByba6VYMWct9kFhBhgQ7dvBzBiRXJCSSydQu Lm4T8ZPpZE4rP79Pd46OYwoTBu39OxEvT4qpkPQVSHXD7f1ksfFRQLjK5FNkzcfsY/MCY7Avx5ge gihq+NKd8SFL6iTmy2FN18KkNPPg+9p2UnSmzE3760nF41vhKskcTscqHzt4BEpW0unZg+3xYeA2 PlI6oXZE3lET4zBZbhZZVlMAX/NZ4xFXbKDgI1ZonKksDNtaA6EBp3LBelET8UwJduoJROvlOtXL qZuMVsDgIvui/4kZna3UWWX7Ffc0jSkfQWK0n2DKSLo3S7W7RLfLQ7J/tv8zy+vSH1zMvvU10JBa 64FmXPlBsVVNxCs3Y+Xp3AUcqyfMcIUK+t0+QUQNt+OtyvsNCNtaz1yaUrmYTGdyXy9YUT7seDHF xN3D0Yib7Hr8h1eCJ3Swd4cp9BnPTkY6nGXUn+CDC0/wZ3iND04wwb7pCV4+nHn2f7ZHsC+XLyYX J70RtroJhqkzqxphq5tgcF5WNsJWN8HURJCVjLDVTTDtoodVjLDVTTDislnRCFvdBMOSjFWNsNVN MCUpfzUjbHUTzOVdNMK0mljiifZXR6TqoZ87zDVZs0Kv2AbG4rezTMszDOIZaiTuKue1XFYqtZRy 39zsURv3PEw+5KoU3UrcbS5ZnmyVcZObWPNxrBTKGzKq2qXXWXrdrVVaHGoXmL71Vpm8ZANjfnfG wpZngiUcM8Eau0ZbbHnWG36is7Q0E+yOIhNMS2jzTHzj5ZlgzPlzMKxFkpalCk7rxR/TSkHuO2e9 2a50a+v45HTpSm/nPnW5NOuNyR5eZx1W2tqKHNiuVNt9ZRmpg0untMiz3TNjcdjJaSATDouPxGhQ 5JlS/aA+uCfSjhTkaPJOed7bAuMk86Vkus1y2fb53fgTO59e92Wwqy4i4bieJ2d61+VV3gbl9gvs pdhuLlnqjWcxpQZ7+tpmQOa8jlDNO8/6b8/HimoL6ucNBu5bWAHYIlFivZgJU+7ec8kn1gPyI/WK 7lq9sH2+NsY+2sy1S7TRZhJrNiVOhUNrRZtfLpcHwNHe/2XGCgVIJPBgCMlerRnsXxLqrwZBVm48 L6+2dXpuymExpM44pUYZP1JtMPvSy/PyDGlAq+TldW9WT3UgsnJZvgdGnH6dFApr2VwWFl6BPbYC yeWlShb8ZQ6P8ZpCI1Cx4mTt/MVFkDBM+/vEorvBcna0/OwvMKQ12ZHp7L+8U1C/He2/2uaqkQJp Mu062WpW59wqVw3k/m+z1Shy1VAik1yamC/4RzKyydGb7f5qRFW3T9SiSP/dlECZJ6kW8fasS1R2 qU/vZkq1Wsvq+dPvS9M1HdOybaFtLMv/ah6YBjWnmD/ZDfvxG8wCT16WXLrmcU2Y8pXNa+ktT5dH dvxjMWwSTbysDReoPitrsR8W7Zd31SF06x0ky4+eSYp7v/wislmpNrlKH7wSp/l83cmLfrOBegH6 8rsNfn2zAWDM+W6DX99soAbpl99t8OubDVxeirsNAr+92YAU4TvdbfDrmw3UhLbldxv8+mYDl5fi boNf32wANOZ8t8GvbzZweSnuNvj1zQbouXK82yDw25sNMC7meLfBr282wFJMx7sNAr+92QB23/lu g1/fbABrcbrbAAxgh/sFHC81QHt/tQsVVptUuc9gVh6/eKPBBu8zUEvKrW402OB9Bvq1OAs3GgQ2 d58BXryl3mhgIVoNlZsF081B0jDIjVPfmb3PmTC6RWob5fZ9/g7AkL4HWVHdJnC5lExV9Au9zF8K EM+cN47u9J7Yj/jopGQ5+L1DHEuGywO2qsJl9rHpbRNXMuxVXxV0IPck5YqfWUq47+ygs1XcnaVN vM2c5kRg9vQwgybU78d6W1LknzvJSJNrq36B0vM2iWjgqVRiGiUmt783muphDxQE7yAIvv2pXmC3 qgyWPxmWofMgljn/+jnjMqGngDGW0mxfZAPj7G7685kPJpnjaZQQl8ur31iAQraRhR0ZAPqDUzWO fFS8IUEYY1TiOBuaRSXUT3ZwwZEHyed7vp93ti/aB8qUKvGr3e/qLBSSnt3Nu6uFQuDgoslBrihY JIHPJ4Z9ufxMRfziyJgRQfJFMOuWI/EJvK/sKdPKPuwBEvQ06fte7r0w4MFw2/pMdfKJseoO1Or9 UUDf4+5Xoe00DIpKqJ3zfUivWP5fx5i4d7hvOGiRA7meaX1dHDKRev4ED1Ioze0cvWfC0/EDSJ/K VHvABJOV7G5HzWzeO+NzvnxSVyH2E7HsAXDQVP1E0S0vSbRBi2Tc1xOVG6mMmaEldX+1AIia4Y4R R/2GgMF/H7viQEbnLPuW7TeNuWQurxdayq3JdIgdIm+pVrvTL9T+aY1crFv5j4H/WDfnjspuLhLB fxg3D/8v1F2+xqA7GI397kLf5X07SI4mmU5j0hn0a6N/3DFsergs3J5n3DH3rGvc7QNImDfoDE/8 mLz2BtC9uRh3Ev7/8LdrfwpzZ+D3axcTZjg+4mbCLCcL8E+EkSWY+tvFqIDBC//AHxfwyxc0/e0W 3JfupxfG3cSxblwCK4R5GcAWInyYkeDtntIWjUKTFGZFRnRjQ1SGhQnRaDgiwUwCy4Yl8prEhwWZ 4dxpl8AIAI0IDyUAxM3LXDjKiCym74UlkHxuXpLDgihIbkFkw5gCBC/xUT4s8xzMIQphjmOjbj4i hAWOg8lEeCREeTfPywCaQF7jZFguvMaL4QjHRsjgcoQX3TwnhMWIDFBH5TDLsvAaQC1HRAXGKBPF 11gmLIk8QBAVwxLDYCc2zETgF5wtKokiaYmwLC6fA0AkjrzHwioFVmljYd2kJRpRWxgYkrREohHS wsusSN7jw1wEloC4EWVWgLXwAGaUcwOCw7LMwS+48IgIA0RkpQXekyPhKC/xSi+JgUHZCKBHgl8Y QIYgSWRT+EhUIDsHC5ZwC8jOMazSxghKJwkXjNsr46YubHja9QETQn+YXMGxBLvWI22wgIjSJsJa sUXgcBBsEQSlJSLwSgP8z91wKZ0krRMfdSsDCbOBRPfidA0AggGiBsTBS6zyROQEAgduiCiSpoiE hAQtUVmQlRYetxGIjYmyCiCw3wIBZLEXjiSpI0UlZaS56RCO/Vvrw0pOoXb4wiyMzA== IPBw1sNSVMLjx8Ay4fBxoFlGOaQlwDEflWRcBeCdY4AKeUEGJCBa4HiJER7pmwHqwpPCSHBSgKp5 IBegdDwgAg/HgQFUzdoKpC0aZZR+oN5ESFtEwSTPiGExipvEc2FJ4pAykT/g8YWJGFw/0iXP424J XAQQF4XXWJhbJCQjKQTCs3Bco4h3eJ8nYEELJ/HaYQfCBrA4EagPVyHKYZ6JwuBwklgBtrvqQtqO EMKOIow8TAa/8BKLrUDRPJwVNxx2RAgH/Tl8EoFfkUphRs7NCZEwnGGBkIyMZMVxeKwFmCfKAb9D YIBvhCWYi8DAsTATxwHIwK2gJRoWETwOliUzEraIsE+AKGA2wEMAoQilIMEpbbhYOHiiRHYJUCVE ZDcL7AQISybwwiRzLSpXSLv0Njie5GQADAycDQ4OmKmN4QSln8wqsDLALqMRmBMQIUUA8xwTBUaJ x59H/gHUzOGGMQJH4OJkgKLhQvgJqQMWYbGMRFCj8KIIo5x2DqkCuQ3wpGiEENQicRacaL6QUoQf iEIi+kKhtYThZNBr1CZUwlDrSiUMiSB0t1eQeVGNBQq6zIuqMk/WZF5ElXkozRSZx2kyT9RlXkST eTyReYwm83hN5kU1mcfrMo/VZJ64IPMiZpnHW8g8XpN5vCrzJE6Tebwm80RN5gGlqTJPVmUesBmT zIOWBZkHbSaZhy3zMg9bFmQeYy/zhAWZJ1rIPEGTeZIq81hGk3lRTeYJusyLajJPUGVeVJN5gibz zBuuyDxWE0K8LvNYTebxmsxjNZnHazKPVWUer8s8VpN5vCbzWE3m8ZrMM083k3mSrAkhXpN50KTK PF6VedCiSjNek2aMJvP4mcxb7EVGktSRiMwzT4dwIHELMuKMCYtAKeRI8ApDR/TLEYmwYCaCHB4o CTghS/YxCoyHsHxRIrsv4mmRCOETKQBDANkCBxeEqCInkZNGeZacLAGJFV8DkmR5RCD8AhySMEMg OlwdSC+ZQTICBHKIUiAaEJ4CvofgImkRlVKAo4AaUwQXIIiEJHG/kGgiynuyQtx4bkVCLNBL5nBX NNkrgFgBquHIsiMRWSRwskyUSGNAU1RAARVl8OiwbgVxiE0CCse7F1CZduKvU3K2EYG8DP/KcHh6 5NzKHApWra1gbOPIlhQMby62zN77mDXCsQ3LUZCehglmbQVjG6yPFwTDeJZNszfxPAE9inxkBgqS kKjqBDPoDE36svQ3rdq0Vw1TzGAxzGGAz9CmL01/16pt9u4HbgfsuETYAHBYVuIJa4jgaRH1poJC fUwkMtfGAwELeAIt20D3kGUydQQYRASp2dgGS5WRunhU6YncRtUZGR7IA4kTUFSwirAXBGQ/ArIR hANoH4hRAJYbxbMCSiacF2xRtSzQhsKiGNUb4DXUcfA8651gX4Fjw2t8FMSOzJOWqERAEhXJogii qBTR2mSi2oFKysC5I2/KyIyUNo5lUO+UUF7gaHjM4QVBANYuskaw1AZlNaAyCoZOEdT0WMJBQNuV CVok5ABkwShj8DUQpiIyOgHPLbK+CAhTCTkPoJOXREXOwmAGpKM0jhJJqTaR/cLtZ/Dko/rECgo3 4ySJJfsQAWUayBKMYxaPu9aCImzWBlwQeQiOBaQYlWW9DWQTTITyiVdsDpwO6JHVQUgrVpQEG2Ak D2xTCVCWOA3QOTolupxiovCgFER5lKPA2qISCKqe0oaESJoiZAxg5qh5ALeXJNRCo7AIGeUbil8B dWHoIQqMYWbEGlgZojxP5lFgqjzqOmAnSBLuN/RiCC9EWxwsFTJ6RJYUoSICTnAs2GdgOpLephyt KIeUgnZTBAWKonQocImipFDB3IlMW59INLhA8qmWTZTQHEgunqwZ9CeOaNDA9QRiXcvAEQhUAop5 BVeirFC0iDJc5MnuE9JWDrLEsaoNilZVgfAK2DhJkb6oguC7qABGFH4eYSKyijGOVfuBbCNNomrb oZohs4Sjo56IG4jTMqgN4NaDwBNV8ECdB4YqabIJNxctzDuVBiReaSPDkhY8FKQFjaYFOklrigmA LEWJwQ1oifJEakTQRANyB8qAHZIi2sZzgtrEaaudf1W1Mm5dstvndz/cu5ZJRK0Ph4pVhKiAcGii HApGMKlQj5VUHQtW0HVxUcQpSm+wfjng5Ni28G4XQLCfkxMRUlRv0XCLAP5gLmAOIOUVNUqG0wHD ossCSJNsBuEqXYtXHaYCWgazQVaEG2jvOFUE7UtBUa4icNpgWCBB0CZEhf3wUVzB4qvLp0IHGyIB 2WOEiaJURnKKsGhBC7hvcIi7hAswHE6vyZfu4qsOM0mCIkN5kEwysapwBKJO88hIQVTgqBJaNsjE gXEC5ZAm05sOExGjAfmliLiAXcc1RZQTh2IRrG6ewI/ePpRT0I8YUV2Ldx3mQncZw0pEFBDeDHNx ILPwBHBwGkEq4LCg0ooiylt4xrEcWejCq05TgeYqEi0BmJhEDhs6TDhUldHW59RhkVsSLhuBbZTJ qsyvLp9J0WKRXDkZLVFclMAAGxNR7YU5QQ1EaJEfS0TX4HhFu+5avOswF4NMl0eGDxKDEYkvDHkC 4V3o5kEGDOPCwY2KaIKybDjKsjJpM7+7fC5V8KG4n3Nzwepwq2zcXBxrdnNxrIWbS1LdXGC8L7q5 ZDRaoIlRLCvQQBn0I6C1CFsDz4jbDu0oBjUAaGPRVIA2dF2xqGihBSSJskpVHDrIOFSyZYJpURkL IOTRT4WePEmUOGKBy+iDRGUClKYosbeiRNxBi4xuCvQIRlVvInE7RfQmlFUo/1nF18QSrzlxcxG5 xqMfh7jQ0JeG+pQiHBUnEqpmcIyEKJxiOHthiZhbyAtZ0c0BouDoKwoFx0RY8hpOi2tDJicR4cYR 7xu6xMhxBV7LEZNZVjGM/jD8BRBEOBF6z2CkCApgVlaYUxQ9hRFeUxRgEjTUOaI/otNMa2kQlspw 6GDRezEKmnliVgLj5UBTg8MkkwWjcgrT8cAtRBRnuMXoSOOQIEgngB+1EHS+SRySmIiCNYLmKScg USP5yKjqwUpA1spIh3iMiJwiXEIhSPTTRKNq2EB1jQqKaxTQBBhTXaOi5hrlFlyj7IJrFOYBjosi JIKyBNaLvh5CKKCHMKiHKO5GpBiM4PACKuEcg5qbdkRBhSDvCSIwaWQGQjQCK4ZHgog8F6hRBnMD 34OHircJoBPRaObQlGAjCmcGUgYwQUkDBRNb0KJnRLKfwLii2AtMBOLcIr1ERlGcJVDHoQU1LZkl DJUokQ0iNVEnBgg4Hl7n0HkUVZkzUfU5UMBFDq0HHmMVMiHfqKS4YdHyAWQAMmFfRRZ1woga2MGR 0Y0gYDhJIjhBB5PMysQw4XmwylAYK6cPNlpGjxi2sCKgXiAqJfH3gdmGDjTSiZFYluxcFIQPaYmi 3sfxsuo0gxYRthIxGVUIDJvIatHhSxyR8DqPh59DhiKyioEDFEe8wgxhqVGVj+PSgLMD61HCeBLL oH8ZGST6LOAXYLKc+l6EHAwZNw5sKw4dh1FB8dezHJIOMk+Dnz1NfNBmP3tkwc8uWPjZuQU/u6h5 1XnNzy7qPvWZn33WFtV96hHNzz7Xtuhn51H9jxBWSyw2JHJRwBYOYzLYMvOzEwPY7GfnzH52IAST n52Z+dmB04DOAfwAqJwHBgK0gfChps6rMoSLomcN0QAnV0RhAu/JnGKdzNoKxjYeScDUJoaBAGA0 9DAyRKRhZAnIEpQTVbrA+WAjxE7mkBGAugRtOABuGViRsEkCacHzzEWRVyBeAFCGJxYBgioJguIj YDmF4cObPEGLwn70yAKrRBbSxrBX1Bz24qSFsBenh71ELezF6WEv0SLsFV0Ie0UWwl68Oeyl2DeE wnlZIFSIZlhPDdDwircRaE5ws6CskOOD+8FEyYFCZiMpwWMiQ4AwgbEz6GuYtRWgDf2caCkAaxcx ukDeRCUHcSZE8HDAoMSYAP01wiiEg5FscoCA3eHZQk4gS0TWgcxB1zOHngMGhS0GDnji58eRMPSA yFdpGTkB8E0SH4oi3zGv1zHaaRX58RZr7VZlVOt0WyNXe1z7q+Wu9fuDSW3SGsITd3vUGk8Go5Z7 /Dn4G1vgFa2715u9zrn+L1T7Dxc= tomcat7-7.0.52/webapps/ROOT/index.jsp0000644000175100017510000002763212271304167017231 0ustar locutuslocutus<%-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. --%> <%@ page session="false" %> <% java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy"); request.setAttribute("year", sdf.format(new java.util.Date())); request.setAttribute("tomcatUrl", "http://tomcat.apache.org/"); request.setAttribute("tomcatDocUrl", "/docs/"); request.setAttribute("tomcatExamplesUrl", "/examples/"); %> <%=request.getServletContext().getServerInfo() %>

    ${pageContext.servletContext.serverInfo}

    If you're seeing this, you've successfully installed Tomcat. Congratulations!


    Managing Tomcat

    For security, access to the manager webapp is restricted. Users are defined in:

    $CATALINA_HOME/conf/tomcat-users.xml

    In Tomcat 7.0 access to the manager application is split between different users.   Read more...


    Release Notes

    Changelog

    Migration Guide

    Security Notices

    Documentation

    Tomcat 7.0 Documentation

    Tomcat 7.0 Configuration

    Tomcat Wiki

    Find additional important configuration information in:

    $CATALINA_HOME/RUNNING.txt

    Developers may be interested in:

    Getting Help

    FAQ and Mailing Lists

    The following mailing lists are available:


    tomcat7-7.0.52/.gitignore0000644000175100017510000000254311727656455015161 0ustar locutuslocutus# ----------------------------------------------------------------------------- # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # ----------------------------------------------------------------------------- logs nbproject output # Next line commented out, because test/webapp-3.0-virtual-library and # test/webapp-3.0-virtual-webapp use it: # target work build.properties mvn.properties .checkstyle .classpath .fbprefs .project .settings *.iml *.asc *.jj *.tmp maven-ant-tasks-*.jar thumbs.db Thumbs.db bin/setenv.* java/org/apache/catalina/startup/catalina.properties modules/jdbc-pool/bin modules/jdbc-pool/includes webapps/docs/jdbc-pool.xml tomcat7-7.0.52/KEYS0000644000175100017510000011002712271005702013636 0ustar locutuslocutusThis file contains the PGP&GPG keys of various Apache developers. Please don't use them for email unless you have to. Their main purpose is code signing. Apache users: pgp < KEYS Apache developers: (pgpk -ll && pgpk -xa ) >> this file. or (gpg --fingerprint --list-sigs && gpg --armor --export ) >> this file. Apache developers: please ensure that your key is also available via the PGP keyservers (such as pgpkeys.mit.edu). Type Bits/KeyID Date User ID pub 2048/F22C4FED 2001/07/02 Andy Armstrong -----BEGIN PGP PUBLIC KEY BLOCK----- Version: PGPfreeware 7.0.3 for non-commercial use mQGiBDtAWuURBADZ0KUEyUkSUiTA09e7tvEbX25STsjxrR+DNTainCls+XlkVOij gBv216lqge9tIsS0L6hCP4OQbFf/64qVtJssX4QXdyiZGb5wpmcj0Mz602Ew8r+N I0S5NvmogoYWW7BlP4r61jNxO5zrr03KaijM5r4ipJdLUxyOmM6P2jRPUwCg/5gm bpqiYl7pXX5FgDeB36tmD+UD/06iLqOnoiKO0vMbOk7URclhCObMNrHqxTxozMTS B9soYURbIeArei+plYo2n+1qB12ayybjhVu3uksXRdT9bEkyxMfslvLbIpDAG8Cz gNftTbKx/MVS7cQU0II8BKo2Akr+1FZah+sD4ovK8SfkMXUQUbTeefTntsAQKyyU 9M9tA/9on9tBiHFl0qVJht6N4GiJ2G689v7rS2giLgKjetjiCduxBXEgvUSuyQID nF9ATrpXjITwsRlGKFmpZiFm5oCeCXihIVH0u6q066xNW2AXkLVoJ1l1Rs2Z0lsb 0cq3xEAcwAmYLKQvCtgDV8CYgWKVmPi+49rSuQn7Lo9l02OUbLQgQW5keSBBcm1z dHJvbmcgPGFuZHlAdGFnaXNoLmNvbT6JAFgEEBECABgFAjtAWuUICwMJCAcCAQoC GQEFGwMAAAAACgkQajrT9PIsT+1plgCfXAovWnVL3MjrTfcGlFSKw7GHCSYAoJkz x+r2ANe8/0e+u5ZcYtSaSry+uQINBDtAWuUQCAD2Qle3CH8IF3KiutapQvMF6PlT ETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZ X9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56N oKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kj wEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obE AxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAIC B/0eHkYQ0Rv6s21TgpOzRBon+rQAv9ka0PlC7bj2eYWsCOBib8K7qO8hND0sW59p 0uFQ01X7kC7L/4Ls1HTk0chEZMV0UrGAOKXHY1QFlxrNtFi5U3pTPITXDDfy+g/G 6FTX3PLnGGvwXbtaiAq5UjQ6iXm03lh0BW6Q+kPtm8swPPfqfjYv0rrT+I8Ic3p2 HplWKR2bpi3wqCSKB/AaTQJwTbh2x2+2cPVONPodgjZSJ9eQkErejkNSvqbumlTx dB81eoGa0Lo2xE7N+DNlCnILGE0X4hPMdj+N5fmyEbyx0WOB8crvCuODGGEQnXs/ zbVO7FP+rj7YWjRh5pVD3bGiiQBMBBgRAgAMBQI7QFrlBRsMAAAAAAoJEGo60/Ty LE/tj/QAoOFNFa7rbAy+eT6mRNb7XztfcAbWAKD6Gd6S/7lEJU0k2TS5tozt4jMl vw== =/91Q -----END PGP PUBLIC KEY BLOCK----- Type Bits/KeyID Date User ID pub 1024D/86867BA6 2001-11-22 Jean-Frederic Clere (jfclere) -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.0.5 (GNU/Linux) Comment: For info see http://www.gnupg.org mQGiBDv9Gx8RBADclmKwDLcibNVipQnhYW+bFIpuQjQnRrqRwn3gXM+/luzzJYJ4 bbWpw13zjX0EkrAJ8qH2A/d0EIU1eZ0zHrLgRvMUfLGFUX7FFFw18JKFLTVGhG4/ 8sSl3ydHSA2Kd1PF6xjBP7iM7sg5dJfEkyMzvK5H4F0ZpTqy3087wsg1wwCgitRy Zg4x3lWZSkOwBj472qaO9GkD/2q6kyWfAK6XFe3GuB5AAs3poMfN1eqW+duM4TA8 zUiWK0Wxx4JXJbL7n0i4d+JdXJsrjSjF++KKfelcxsrSxoUIBegez25MUSvHe09D R3nqkY8CVO+viEtzRBqkSgCMbUjAtfkQ+vp2jDnWSmmkNfY0OYAzt+KRyJKcjUSJ gvOOA/45+DN9wuTELoFTvsXh1JgOL/QvW1fmQ2HrcQk94BkzIsfVGWClCiig5gNw LCxTbfgA5htpI8U7vPR9/5gH7U8Wy3HR6xQUZxcbttMeYit2VbDEJzF5r5S0pJvD vyk3n1kiKU7r49sjhxGgE8J/VvDpO6YcIsDs8LoULwuJTg0DTrRDSmVhbi1GcmVk ZXJpYyBDbGVyZSAoamZjbGVyZSkgPEpGcmVkZXJpYy5DbGVyZUBmdWppdHN1LXNp ZW1lbnMuY29tPohXBBMRAgAXBQI7/RsfBQsHCgMEAxUDAgMWAgECF4AACgkQ0+/m toaGe6amGQCeJU5VZ8QCi8+PY0QJHPA63e5uPyoAmgOWIwFm8A/xmW8qjEvVAWtb TjZxuQENBDv9GyMQBACCbFlSF+udW/Qz2oknDen8Hoql4Q1Q7CUQTbPjoQAcYgZg LrsR6hc9aCIf3Kt4qZBgQ1Oe9M/AemOFhU04UNp3dgHk91EYRvx80Rua992p/8V7 QOhwIBVb2XE8as5nL2j8w6Jz7eSs/bivxm9yD0AH/I5H01RAJivRbOTsUgSkDwAD BQP5ARlW2Nqc0U17asQsmMYvT1UMiOiyBwUD/DIEG2Xy1hlEvdljg8WU26jcjpGq MrT69T4Z+eZ2oVyiRQTW4qMUBKc0Nbz89hL0qv9K41ExxxH+JgE1csRVvmwAT8Iy lnhof7TJLRBtvan3+p21Kxl1uQ7MbmLT875u+vc+J098fIiIRgQYEQIABgUCO/0b IwAKCRDT7+a2hoZ7pn9UAJ9f0TK0QQOtjQBvxAissopYhDKHGACePZg0k9sj69yw nVWrBS9fvFC9jcA= =BTiM -----END PGP PUBLIC KEY BLOCK----- Type Bits/KeyID Date User ID pub 1024D/E86E29AC 2002-02-13 kevin seguin -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.0.6 (MingW32) Comment: For info see http://www.gnupg.org mQGiBDxqtR8RBACbySxGrtf+flbowryS1Hj4z3zzEXD4CAEq6RjSGMtIraCDRJfp 6Gexs+lQ6IhpdC4GfX70SUMjXXvT5suhXYeGOM4iJHqUsksgzEKjUqcfj1l3qmOs /doE8lcGGHcYbMplBcfuop+shZYiv9GEJ3gutwn/dNnhs/QA9bCdIj03lwCgvAcy QpT5JdTym2p2icd5e91mGIUEAJMw6JHTTcCiyoTRy7k8Cf65d8S7bTDLr6pqJVE2 XU41CvW/pgL31akYAxpeZJJnsBaLaUiqh6K0qgfEMlDwDeC6gVogHBxWkEXdK1dr tGL4GIUcxQ1+ZvQhGg7dtjanmfMlylVgS+C48awJySkinRmaQDbQ0MKdFchLc/y1 OR3IA/0VkIvlidehMPbZCalqhS9AEsDiFq5/u5AsQzDEp2nmTGlmBqjhc39kEnu4 qKq08az1Gt6Q7sxXbjH/jYtDgd49FW5Yg4k5B3hpTgnbyRE6SGlKksu8qTmYkDve 4rej6pvJRHwp6hDKxDG8qQoLWIgOfVC8960nurqx56QdV9YMsLQga2V2aW4gc2Vn dWluIDxzZWd1aW5AYXBhY2hlLm9yZz6IVwQTEQIAFwUCPGq1HwULBwoDBAMVAwID FgIBAheAAAoJEKy3f8Lobims3E0An0x3rrUMIijUMFoqnoT7muNGwmAzAJ990TWj dZO4ayh1M+cWhjaw9W+44bkBDQQ8arUkEAQApaMm5HUB1Yk2x5MavAs/O4zfWnOx YFOeXIPfGvhlhF2/Lrjs9icaa/tOM/CTCes19nDWP5Fc+pQxmgSPrgt3fsShwZJe p3iYodLbM76uXEgSvI4Wh6kwViHbN4V1GxJAd2ZPVb1v+lauGUCOgPFGw99UV9sO tTRXSbFS6AgqQzMAAwUD/jq6boxlnab/GUmKrILeLkv1X0G2/AEXEGRmG0nkhVdj OShoqtPr4y/UhMzJUOequs2CdvRlTIyAyZqN7A0Qp4mFfmsvp0dYYssTtE4bCzZe WxSKgjtBWBHXnH+Qzjb5R2Tz28kAxNY+dt7yxC+CkXWDZq/rsPgsXNbWXT49FnF8 iEYEGBECAAYFAjxqtSQACgkQrLd/wuhuKazl7QCfQkz5t/3T6EtXZCcXz/hlswyI z30AoLr/7hwXgedEepBk/Gm9HUsbMnM8 =S1mb -----END PGP PUBLIC KEY BLOCK----- Type bits keyID Date User ID pub 1024D/307A10A5 2002-07-18 Henri Gomez *** RPM SIGNING KEY *** -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.0.6 (GNU/Linux) Comment: For info see http://www.gnupg.org mQGiBD02vbERBAC1v8fR6gjERpaz4UMfdy0hRVWCPSbOdF+Swm/IenjVzErco6zb MTa13umUNrDPBy/tTWiCCZrOnqi7fgDzWqPEqrXJjKAFVLEWE6MmKylPPEPG1/bm idkNGERSAZduvhKv777PzvEJJ/8eGe3wy/O8NbgIjCPtr4UklwCZS8cFuwCg8oMO UdT8qZRtzdxdAyu1m5fUb+MD/3IKJYWXsdtb6iBphCU4f/BoyjVC9EZJ1ywLuiVM siKbuaDUaXU9nWcbNKv+fx8uZ1NaadpfLokqqhnWcpnSiqw8HNR7SwsF1D33rkXK O4FSuVss/tIoqGdWFcJyPkP4yP5shxqR335narVw2vDa0+BiWkALbA2qVsSIdZDB LeFZA/47AMBS0U2BRk2rQT8LmMuFl7mR+wNBM4n7FUGdxsGn3TcYd4pXTNrEQPrV YNdooKlikgGk4hgFnIFX09Spmimqgq0goFue81rttVdZZ4uep8dTghY6gwmvcOxX jATbhWStBhdu9B35kzfHc+1QihD5Z94u4uyWIVBIzikcdiY8LbQqSGVucmkgR29t ZXogPGhnb21lekB1c2Vycy5zb3VyY2Vmb3JnZS5uZXQ+iFcEExECABcFAj02vbEF CwcKAwQDFQMCAxYCAQIXgAAKCRAZMdaEMHoQpYijAKCCP68ndU/kTXR9XAKLvibC 3S8+1QCfUFQYte3Jo+MHKaWjsu9JGptRzo+5Ag0EPTa93RAIAKlsRJ5gOGTFsmaR W9k6MIh4c/MCy7J7HUxT5xTdHROa+3zUh+FAE/JaOx9ZtZtH863DFHA8cP4L+tpi PjBT6g2E94dwGcuH/OiSSCT4JSBukbGbOuLLdmFXqUl8+4gsL90Xal67FtNLwyLG 1n7geLir0byD+OT7VLA5w+6G0NOpJEveV/FIa2qLgdRZ8vz73ybgMh18hBUrUmro jncp0rln2VU7VCH1C2aClKm7kK4mGAjIFIzKbguK+kM3b8NDHmXKpT6syyCtIM3h prkV1TUCAFqLI32aSdlTN79lpeA2zDga9k4/4X/RDHsFpRN2neRFGTNUtuUgYpQQ E5zWBmMAAwUH/RiGxyeBsad923IwE1+GAjxFl2tqF9xWk0J6yTnSK4nfhYAE9evV jwDEok9jRl4ILCcXx6YN/d/lWNuSbARKHz/3hLiTouPpwd3SSJ8is2x9PgpJz5JX cD0y1SkbPLvs3jH3ZmdcxZpuAmJeI/typqFKK5pWP44oXIH+XH/8nWDtmLEBkgKQ /ATQWenMTmZ6MIJ6aWKWGkO9QS6iYRz3PPPGQ1O8W02CeprM2wBtlb8J1Z3RxNhM rZcg/1Qi3V3D1HI4zw6tAFmDeBb8J4PaBQzqlhzx2EBTbfwNPhV8AlPvpxHEeGGn v+O1yhZr33SnyZdINNoNDn+owVMdmkobe9GIRgQYEQIABgUCPTa93QAKCRAZMdaE MHoQpRsTAJ4qst3MhLm48fBAEnzuzi/BIKr+AgCfYaCB/AvPoncQbHc8BcNGRimR P9A= =hQhz -----END PGP PUBLIC KEY BLOCK----- Type Bits/KeyID Date User ID pub 1024D/564C17A3 2003-01-11 Mladen Turk -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.0.6 (MingW32) mQGiBD4fwXIRBAC7WRS8PYxi2YH0T1mX4HCYsF8aHoqxBzMnyFR4J896m1s96vGM BTSAwH2NKbiVqtfLokTbQkUVxtrgrF2HMB5NfYBg/JzT7pZL/Q2ThWUS7SJQQA4f a7/DpiLiHalp6iX45om6JTdIWEyXv26csIVhmtlkGBEPRhNRX8X4//BM0wCg7wcA yQ7c5NmoOJLVs+uHsRrnHo0D/R/dMyuWt7/o0eGIEuRlDl2q+YL8xLuVyJMXQBnd jo7jKpQ+Q1zl93aVTzsJa7mP2zZ7jqaJ855sdz6rvwyhGF1/qYMtm6zrmgBy2XPm J+57sfwSZr0bhIeMpCWjIw98z9sObq0v2r2oA3+J9E3Na/BZsCVTZVb3ew7ILmEp F5D7A/4zvjY41dakCAJsD1Xo8TS6hSqJf4zq9vX3ayJVvUjeo8n4sHNOwcbEnnui 9zZaUH3F0x+3cDo7mS1Y4pD8THuqCZoSbSkiHnlved6nLXsKbqvVrVo+esEhfZCn Iji3gp+2TVNwdHXGM+4BAzMJCLsdXjByO6SNzB9a+H8RsRlZKrQ8TWxhZGVuIFR1 cmsgKCoqKiBERUZBVUxUIFNJR05JTkcgS0VZICoqKikgPG10dXJrQGFwYWNoZS5v cmc+iF0EExECAB0FAj4fwXIFCRLP94AFCwcKAwQDFQMCAxYCAQIXgAAKCRAcUGQH VkwXo0jxAKCgHzXPIB4IAgoD7GMAohPQfX7j2QCeL6pAsf4pPufmPvbrrpDp6rQH GOS5Ag0EPh/BhhAIAKWzq7+/+nNYGpc7sXGkDNo9xncxcx/KbbJVT0rBteuaonQ4 vYar1ITjIhOPmF9yPmpUddNrqgQTSO+Or+ZrVOndn+qC1gdY3qpKIN3KTjXloW38 0Y84ezwdRLznQNkhgXwNcB55l/Z9kLaW2MS8CJzOuYSQT1CYbXg7XP3684ZmV1KC cGgcUt9VkIGqwsa2RFDNGvMbySedSkJ/70Q+PJlkXN+W86f8hi3HTjw2MCkNa5NL +Byg8FEAm95YWrO6kCY3qaJYV7NRt9oVd+2V/NNzwYp3Or/QoYofvfNerupfwBmU GEXPyZCqqNH6nDv6chscsWvEA9KzhsWnsdKhmHsAAwUH/R6LwfWgtpaO42dQI4ZS VRBmCeWrXCuyVk0d13Yz0xLi5Z5m4g3MON3d+cRVUiyNX+hbDGpi2mkbsnL559Ef iqmzDmSz5GQHDutolhOPtLxLrC537ODn2q7hnYQwIQYYIUtYD5sYlzfGYC8olGCB IcKIdlGRWcxxiFCIJm5CX/jnSBsyDRpanlSrdkxhzAGsifqj4NQ19ayoeNoZg2ZP 9SLIY7vbmOxJeHEYkx8AG25xOY1PLotb/0buSXPB8e71zb/DCV1rAhhUxAr/2JOQ RqlZBq6PfcHKLRitXRCeVvfldRxuWBIzhuTLUfRPYR6phjP50EzZPlbJzIvGwsOI RheITAQYEQIADAUCPh/BhgUJEs/3gAAKCRAcUGQHVkwXoy0JAJ9WTfqfYzW/F6qi 5MxmqDnU9/G+6ACfQVmhZNnGTSfcwQCttwCaW3CRhDY= =MWUr -----END PGP PUBLIC KEY BLOCK----- Type bits keyID Date User ID DSS 3072/1024 0x7C037D42 2003/08/05 *** DEFAULT SIGNING KEY *** Yoav Shapira -----BEGIN PGP PUBLIC KEY BLOCK----- Version: PGP 6.5.8 mQGiBD8u/mgRBAD5WKD5xF3CLrnABeS1DvQQhYH+tJjvAmyZgFkYwaQT7eiiOzLa PC5knbcBC4nuw+8OOPDFw0Ghb2MFogQzRxD6gpPH2t9eEUsrkPFax2Kw2vNTHRrQ RGAastmi+EYJsQAoktX2dPseTdrkeJBk240Bfj08ZUFg4uPuho9C45ND6QCg/6SO FMuan62QE+DwlUiMDo4ZcU0EAMDS8k6Dhb5m/0njO6w9OLTEyzohlsM9AP+4mfgB NOJYhrzfkFoElOcWSA/V3nmYn2VS0oIYDDtBnjXVWZidzTAWKsbT9/AepS3/P2tG KMhlXhas+uAiAbMpOglz8fdQ76ivQqyRdS99t4iy/cP2ZC3ShAqZQCacfWY5ZQ8Q kTILBADvp/eayw8fvtfWQXJ9EjBRbhO4THmP6z8J+4ypG6l0V/RBjDWZybrqibO9 ejnOjQYJNCnfrfpzQ5l6dHyy86zLyg+bkFxeId4jp/IfDfJX90sGbuQahNYYwqTp SFiDMI3KN5ZhzhGnx+pKQh59pcux3HyKmcpPa4oB0CT828lWuLQfWW9hdiBTaGFw aXJhIDx5b2F2c0BhcGFjaGUub3JnPokATgQQEQIADgUCPy7+aAQLAwECAhkBAAoJ ECZhkcN8A31CGLkAoPRDGtLRwjkzS2F/OBPkRHKF9/atAKCIh3Fmcr2Cdn05P4qF kBe3QeWVt7kDDQQ/Lv5qEAwAzB13VyQ4SuLE8OiOE2eXTpITYfbb6yUOF/32mPfI fHmwch04dfv2wXPEgxEmK0Ngw+Po1gr9oSgmC66prrNlD6IAUwGgfNaroxIe+g8q zh90hE/K8xfzpEDp19J3tkItAjbBJstoXp18mAkKjX4t7eRdefXUkk+bGI78KqdL fDL2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0Op lK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPF RzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEH NmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4z ISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGf nHy9iUsiGSa6q6Jew1XpTDJvAAICC/4iJF383WNktP9/SxeGVIV74r7C7q5Cxr4a Liy7pEYs52DEft3JzTCLI5O4+NjOw+hEd3QiIytUJRW66V6zd50h4x9lBfK+eMYz GKNN7kd3aBmH/vXEsG9m9bK1ExwyWq4uyf76nRx1Ya9YthNWmxPUHQnSrOYNPU0/ beA87ouZG4RL9tYqdu3NKJ4g/DYiaw+twvhSoCUkBEFHFfKLDlv8zyQvPTaPUSAM Ha5/G2Dj1D5RluMSCEMG1V8+YcYAFh63WEP7Afye0mR1LMJvmlba67ogh0ZSfR+I ju3lhJ9XOp/2W372F9ZbRJofgofVwHQV6INB5uX7KHAdXtPTss+l1nTmydLhsiPC 5oh99ITPdOm8gRzrP10aFwCnwsqXvr+b7fX/CywpuCOQMIr4sbhbYTTClwDo6E0U TQ+Nb7PWE+8KuJuobTvMUqDQSQaQBnkpLcvRt3cPppANtkaADAeNf0RqKxxLlym4 AltN8G8IMLtSJoH9xlQHTQA4tEUeKOeJAEYEGBECAAYFAj8u/moACgkQJmGRw3wD fUJh7ACdE7QuMkzSbxEzTXnbkS61AUPy06QAoI5b613vrWeqg5Gz9C7TzG+FEEoh =O17Z -----END PGP PUBLIC KEY BLOCK----- pub 1024D/33C60243 2004-09-12 Key fingerprint = DCFD 35E0 BF8C A734 4752 DE8B 6FB2 1E89 33C6 0243 uid Mark E D Thomas uid Mark E D Thomas uid Mark E D Thomas sub 2048g/0BECE548 2004-09-12 pub 4096R/2F6059E7 2009-09-18 Key fingerprint = A9C5 DF4D 22E9 9998 D987 5A51 10C0 1C5A 2F60 59E7 uid Mark E D Thomas sub 4096R/5E763BEC 2009-09-18 -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.9 (MingW32) mQGiBEFEjegRBADocGttfROvtLGrTOW3xRqZHmFWybmEaI6jmnRdN/1gGXmb3wQL rHsS3fLFIIOYLPph0Kov9q4qNq36LekShIvjMBDFoj2/wRxaUtFq81asaRZg8Mcw 4kVeIoe8OIOuWmvYhU8SH2jJNUnVVrpTPAa6QWquTmseNi6UJMjLxuL7DwCg//9u k2yj0vk6e4WSO6Fe5+EkQDED/AjQsy0kj9TpNHkKSSUR2evRlWPYA0YtxBSbsgON tT0cYipAp5IcYt6Zq5QzHiZreyQXLAjItDS2oGCIXfNbTYJ3kxxJTCU/3wlefVdq LBh4ttm7gmWaiTDTgG4axLF5oMpAb3m4v6s1KvXVVj2pqkhBknfuoRh1wPqbtwks 7HOIBADVezl1/vny5YzdoqsDx1ByXMLi7CuMexQPllhRbdN+an+ZiJ5YP8J9rPdl NCELsCCcDKLGLjlp43XfMxsgYAPEZNG2ObjKTarhk3uGYN3aJrx7s+G+c2bu8o2n SyAFQ1iDsjS87PgSPCONA2/36ZShmv1OjLWz5Vo7hGSPcW4ZdLQiTWFyayBFIEQg VGhvbWFzIDxtYXJrdEBhcGFjaGUub3JnPohGBBARAgAGBQJJEoLqAAoJEJsf2p88 BiIx2ssAnjsjHqeIOdOQYuNjDxVIqfAQN8vaAJwLv/HLCQwTZdxOFqwt/Pf/Ae5L 6IhGBBARAgAGBQJJE0bmAAoJEJA4TZo1x+lCCH0Anj1yuBFfP+bNK+51xQhqFsSN cB1vAKCzK5HbowxZd2MjzMU31USprksZTIhGBBARAgAGBQJJGG7wAAoJELDgGPyz tNmL35kAniTaqQ+uSzJgX1o7Bp8BAFYoQ+o0AKCm4eD3gf06AK20FZwSck8ibIQ2 3ohGBBARAgAGBQJJGekxAAoJEC0hq2VlRht59xoAnRcmnR1vJZsRCGcSuxKv+0nA FrKsAJ9R7Gdc25unU6zF/UwUs7LdWTIFN4hGBBARAgAGBQJJGjZhAAoJEFuWgBDg T5qJQLAAniDrgK53AhSBmZRGLU6HaI4jPO6jAJ4gWQWhnovMkAKqLRtc18Z1Q60N vYhGBBARAgAGBQJJHtOZAAoJEFMmz0Afnhe7pzMAnAu/W6rzeOXe7SoMtbPF4mg/ OycXAJoDQfqJpGoUFEjsoePDY0WOd5hI9YhGBBARAgAGBQJJVjbUAAoJELlbvT+k PESS4lIAniLTQ0XnArkk0TCIBeSWWRL2SvWjAJ4+9XuK0Mg5Pk2454JbWxXqv0cW i4hGBBARAgAGBQJJXgPpAAoJEA9FCiZiEL/ADcsAnAns0QDk3Iwb0X1GbhRfRHFf GeV2AJ9+8rA4UfTtUnFMZZCEdyohyunM5YhKBBARAgAKBQJDme2qAwUDeAAKCRAM PU85FKClKanOAKCIBOdqECQwSoSS6Bsw/j0rhhhOHQCfTCp+IgPx+uJ9YhhgKDyr U3psooeIagQQEQIAKgIZAQUbAwAAAAUeAQAAAAUCSrQLBwULCQgHAwUVCgkICwUW AgMBAAIXgAAKCRBvsh6JM8YCQ/3tAKDTsnK90MamPgLtqRxEDmCMu6mX7ACg5rF4 05TH5JA7h23YfJCsC9ZTeoCIqQQQEQIAaQUCSVsZ6iAcU2FuZGVyIFRlbW1lIDxz YW5kZXJAdGVtbWUubmV0PiIcU2FuZGVyIFRlbW1lIDxzY3RlbW1lQGFwYWNoZS5v cmc+HhxTYW5kZXIgVGVtbWUgPHNhbmRlckBtYWMuY29tPgAKCRCyvrxAFSkkr91K AJ93ymf/0iywAVIno5/T8/QUJSKVBgCfe4UPcLtISs3GI8mpYyjCXq35OEmJARsE EAECAAYFAkkSbKQACgkQW+YxwZmV0krHkgf407SOW6qaU4nqHUJ5kFPWgcLcVVo2 w4gQ1u6s+HzEXNTmvKZrOIzKJMnttyM2RDklmCwaI/lkJApyMbQoMW5UksTGVgnF WHKyiYx03SnVNPH+QID9IhPzAvp2rLH9IQUtfu1vxvfsQQEZGNmKXUgaG0OduXTY J+EkhaIFotOa6pLBcUuqjmbSI840IjnVV5a5wLyonDGFFJ7FbbHDecOcLzI9jmSd mLQlgXD8XwYe8XqNknc6C4uOniDc+iuDRqzGFAMs7f8YK6C1fh3mWCjuNNQ64wvm JqvxWinFKh6BpTBecqtXwta1Vzfa3tGKSrWCPfODAUHqXni+hhdEqMftiEYEEBEC AAYFAkoVTuwACgkQarqkr5Czi1hBvACeLUdijz+jB9K9XGL1O5ZhPv8bEWwAoIIw 5uol5zSFoHcK1WHJI5D9CUhgtCdNYXJrIEUgRCBUaG9tYXMgPG1lZC50aG9tYXNA dmlyZ2luLm5ldD6IYQQTEQIAIQIbAwIeAQIXgAUCSrQLFgULCQgHAwUVCgkICwUW AgMBAAAKCRBvsh6JM8YCQ/rAAKCcgX1TjaeqTP62LIxml8Z1hL0cSQCeOZiYPXub vNxwTWh01BOrh5oztDqIRgQQEQIABgUCSRKC6gAKCRCbH9qfPAYiMTeJAKCfTgLW 8OR8o1SY8DHu5/Lw/QyffQCfefq9NCLX99dWBqQqQhX8Ov/vt1yIRgQQEQIABgUC SRNG5gAKCRCQOE2aNcfpQsvGAKDh7MWTZaEaEe9zBbiHiUQOtZYsSQCgqdqu199/ TDjuXF+frwmzaZqOB3qIRgQQEQIABgUCSRnpMQAKCRAtIatlZUYbeZNCAJ9e6ogA O4ZpKrEQHuuJnpPnDYT5fgCaAgyY2X29cnP+r79XpqngCGqKR6iIRgQQEQIABgUC SRo2ZwAKCRBbloAQ4E+aicu/AJ9w90lBNZNBRpoQ6BpSGi88e7GrOgCfe9sD/Qbj xJJ4FifW8I0/sHbpaNeIRgQQEQIABgUCSR7TmQAKCRBTJs9AH54XuxYdAJ46GTR8 lGoMPK/hUnjeTZ0neTacyACcC6y/DMgkUi499c/zqq9PbIfq7+2IRgQQEQIABgUC SVY21AAKCRC5W70/pDxEkvlHAKCKieHMrMKnD2U+43ryLJa1S1hr9gCcDnBl6uvO 7qcTozf9k/S8lYvOGs+IRgQQEQIABgUCSV4D6QAKCRAPRQomYhC/wGLfAKCp+OYb ANzRA7CKs/3bcGjGmFet+gCffHlkrqm7ZgaBVl/2thvldg+obqmISgQQEQIACgUC Q5ntuwMFA3gACgkQDD1PORSgpSm/uQCfUdtXgb+/jBVYS9zEFy5MNEssdsIAnRv5 oMNzdqDJ7F/UuU6hUm1QhdkUiKkEEBECAGkFAklbGeogHFNhbmRlciBUZW1tZSA8 c2FuZGVyQHRlbW1lLm5ldD4iHFNhbmRlciBUZW1tZSA8c2N0ZW1tZUBhcGFjaGUu b3JnPh4cU2FuZGVyIFRlbW1lIDxzYW5kZXJAbWFjLmNvbT4ACgkQsr68QBUpJK/d SgCfd8pn/9IssAFSJ6Of0/P0FCUilQYAn3uFD3C7SErNxiPJqWMowl6t+ThJiQEc BBABAgAGBQJJEmykAAoJEFvmMcGZldJKI50H/iCJKvk1gi9oIiL6EISeuSngzsis Jzcg951BN0GVCvLvvVwKNHD7+myiB2gkKKp2yv/A1DVPaZ7ZNkB4KEPLlorLw7iK gb4QrqgezJaRcJ3zisTh6JslOKuV/7Ojy4DZOXVFsr7LSFXPgl6O29AEPD6SHjOH 0x6RTJPqrsccQ49/KBAUAm1oMmRhcE7jsMl6Y3gQGIkSxG7Pag9zj5qxeqljdhf+ QbM4cb9a8jPCSvU3RfXH531PILENGpprvH1oFforY7sNyI8AOMQ1on7Pnk09zbNx lRBq73dV5RCBtg0xF6v4/dA/X1O1cGnXGAYM7Tp6WXifJzPssRySCuwTZvWIRgQQ EQIABgUCShVO7AAKCRBquqSvkLOLWAz2AKCfHh162MhNPvfzMtvqR3Vz+x92WgCf e16LZToIN8IUA2Sqyru9Y6J5Hlm0Lk1hcmsgRSBEIFRob21hcyA8bWFyay50aG9t YXNAc3ByaW5nc291cmNlLmNvbT6IRgQQEQIABgUCSRKC6gAKCRCbH9qfPAYiMUdj AJ41QcpKYNSt1tHNV3YATFcYf/XIKgCg7MFeSGbpvW1W1/weqnraMzFzLfeIRgQQ EQIABgUCSRNG5gAKCRCQOE2aNcfpQnTyAKCdCXp8TBXMKajXNbepnP/8AcxuvwCf ZABpYIEZ2up4mOTpQCKtAfuj3XaIRgQQEQIABgUCSRnpMQAKCRAtIatlZUYbeY7m AJ4hT6Y9bnDyS2ZQgxDoe0q1KmeLEACfTNOmAvfFCPpJd5jefNSAg5hblpaIRgQQ EQIABgUCSRo2ZwAKCRBbloAQ4E+aiXu8AJ9+n0GqPb0pLsFd1bHAnbUFE7wQAgCf YuHmCCO1a7o1ZhOMmTqjQY8znMaIRgQQEQIABgUCSR7TmQAKCRBTJs9AH54Xu8TF AJ46JXUYFXbZocbqNxfhfusocDncxQCg180xr/NoOPTmUqne1xT3CNb2gJSIRgQQ EQIABgUCSVY21AAKCRC5W70/pDxEkm2rAJ9sBYuejJ4w8CXwSSiH56j26JnqqACf dwaQ5K/fBzZCZO3XeHq/CGF+uQmIRgQQEQIABgUCSV4D6QAKCRAPRQomYhC/wJ8p AKChOJ08LU1Ji+c0TdCrUS3xHPusvACfX4b7m9UU4KPSjFBt86Wy+7Tl/1iIYQQT EQIAIQIbAwIeAQIXgAUCSrQLFgULCQgHAwUVCgkICwUWAgMBAAAKCRBvsh6JM8YC QyLIAKDfzPcdTFN6Iu7MENRKHRgkhlWwcwCg4WwimtdbIuNUaJlHAaDCkXDOK66I qQQQEQIAaQUCSVsZ6iAcU2FuZGVyIFRlbW1lIDxzYW5kZXJAdGVtbWUubmV0PiIc U2FuZGVyIFRlbW1lIDxzY3RlbW1lQGFwYWNoZS5vcmc+HhxTYW5kZXIgVGVtbWUg PHNhbmRlckBtYWMuY29tPgAKCRCyvrxAFSkkr91KAJ93ymf/0iywAVIno5/T8/QU JSKVBgCfe4UPcLtISs3GI8mpYyjCXq35OEmJARwEEAECAAYFAkkSbKQACgkQW+Yx wZmV0krGSgf/RlmcEUwth7OQkmpIGPeGbrfjpbuK/AV0+Q8nBJAsAWiMl1ydBo9m L3oSh2D+0G3gLCyckgA1bcsNdtxMPctxJdmju3rWbq0cEVG26U/qeRDjkZafLa8n iPReRVRuJP9uAgQ19cv7mOYjRiEjTqeA2IJ8J2RWLZSOf/3u4mWwjq6hMXKGxHc4 phKVQyjgRh45DzG3wuXa5FpHaG1gYgkUhIvW+RGPbuvKNKMSRIuXs8GzsTbWvNWG /aAOG8B3gR48hQCq7Ja//+ebfKWWi0c37X09VHt9VlNrhWvKziDaofwsobbAa2+F fby/1fBgoMVNdmtvXWlzugkQ+G3xXZkzdIhGBBARAgAGBQJKFU7sAAoJEGq6pK+Q s4tYOREAn3tCOMDivfkSiyRdAOB8sjd8H76KAKDFbj1BkgeYIzWQhHxR0SHC9eoL NLkCDQRBRI3pEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTp j0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39 uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1Y TknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9 fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCb AkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAggAri0hN7wUjnkzDNOHs7j7 eM2VKdDxUBkC9287maduH9fEvD9wXphgJNldx2WCZs5jYHeC9LyAvcchXbiAhYG4 lfbssyj8B7woEMGrqRbxSxp+0PSydJ5WsBjeyptd7yUxt660/1DCsC05PiDBGEMF IAYbeh05wWjPlKlcf3geDx6G4preUXnc/Qp0+A65QNDOjod3j1gQ+vTZ4cKNgDeN nV/1tinJw3tokTbvyRGzmLLLI9Ht1Zh8BJsGtOuE6UKcNXwpclu7H+GljnEL3E9d kdITb0YU0dU1dKc4yDJG0T5EXs4SGOeQE0yH3Gma8PmLm5psP6af9cCA0cx3sTqv a4hMBBgRAgAMBQJBRI3pBRsMAAAAAAoJEG+yHokzxgJDfKIAoOLR5oMpV8OGN7ox fieHH9qJZRmtAJ0ZMl/F/rvzazItoNsYRL6bE2wBlpkCDQRKtA7pARAA+I6Lxzjy Q8aA/iZztRqNpIsKYEVC2rBpa1SrklHT+sM3Gqlpl6arTiSisFtjEBUC5oO50PUY ycMt0AmyjQyUAP28G0E9Re1s0ws9kur8QuM8SnJOLekWQatnSbGChdAhIemX2OHZ ir4avt4rLUqBUXR2KDjxlmabkQ6n2T3Rpv5t9+f+ihh+faMrJ9TRO2tmvpGc4wUh IL9t/peGdUYO/n6c9SXHR0nQtmfmUcTC9uXlWrUVc+MrwzmSLag1ET9uM1jqHcYG 6JXVemPPAt7/+ykUftb5Jc5LgNhahfEOK/9n9LLuzFFb4kHMtvcv0ZS0g002KFZQ mdZ4teKhVOx6cONyibYF5nFMKt9U9fkpV3WIzSdWhZFIvAYwhw3EoBPyEXilGp4x 85uF0spig03qqs4nYuJOjww+I8h2/JPL8Yuqk+lHZ5XH6OTQZJFE9U2roRMvJLR4 W5fZOtAb7zAT/ZenFEYiYNVku+3oCOD//NqD288xYhhal8iSlC1YMbXUNyYpAqaH ad39X4ej5WGcJFuMQiSybnCeTIkKdOxwJDFVucPpPF77pOIuarodzftpMyhzjokA g5jdLM9F4zhPu1wbzNZb89/lGqy34ElZlvGoXi3e3miJeSLQZPPOOGSetC60PiYi Kr6iXpsciDOnqaGb2OWt2bIWaXC4pQuYVvEAEQEAAbQiTWFyayBFIEQgVGhvbWFz IDxtYXJrdEBhcGFjaGUub3JnPokCNwQTAQoAIQUCSrQO6QIbAwULCQgHAwUVCgkI CwUWAgMBAAIeAQIXgAAKCRAQwBxaL2BZ59mIEACjehSxvyNSI9z1JQv1zZYWrEMT 3hN8Njr7bcHjkD2JG5SfZx7Rh+aTahtv6qBkoZaSNOIycvRsVijqOzVeL+zNJm1Z Ql1YI3ZbzBVnS+5Z6HIIMCQBXo0HGJVbccobuJudCwbwbpxIcQm0HCp51ppAeznJ tCHLWqo3PawnNRf2jYVTFKSdMxtZMk6fYcbzek2wkJWnDMeaHE1sy9M5+kGYW1H6 2MH8WCZkp5FWGTmM1yFyLCzebCfUOD/LY2OKloHfm0Lzqj1q5My/S1UZxjq0mCLK DOc1naI9YNYJTMyv2aiXUaqqgYXuhWE214qc/KF/Ipgnm3GsWZ3y4Roqql/sg2t2 FMA4qqJvrGTnNIlxrypKpbTy6TXhdDFU+2mY2pbEP79mLG9uEUJfRX431pr0/GT1 s/CqK3tQCOFHCCIBVbTPs7i5S/QiLBo4PoBwxNnYWQ2NKn4s5Ry/QqAFlAzN6SH8 TNleAUZ9cTvo/5jKHYY5mC2b5xVc+ChpDTu8EZKHwADSFmKN1iOcfNwRgx9+9bdz Ua66UkhT9F6UF+vy3mo9o+lOqbgAS9qgcYbHLDunIXN7uP/tNfX3/qXmVbHPbbXE 0F7CiLo5jG/KdrJObrJr+jylV96Fv0QMaW1R1OZGeacdR6u5jEHWXy7OX3+GMplw R9Ns+P0Zksz2ptF2+bkCDQRKtA7pARAAwjRJMLOWK6AZm7vO/PV39NOoE5eS8w/x 3bd7AKfYgnz4LnDvpe1PsW6NVx0zCUMBFX0vkcd0W2i2ERvoVOxbiS0Af+TWggzU bqsOSh8kLSVB/s6POCKqnzMxvGjknR4Ncq9sSh+EE5oEDjQbv1tMRGZma6Ok42Dc JJNqcFytsriJmT1DsvpitahfFpt4U7ZDxPhRUjRSGnhw6Expsf9EYrvyu3TSU6wt E5UaZ9iunetMwed2GE3PtA2Eg8gdBbqV4gMf/lxBp90O3jYtgVesOdL+a+dUD/M6 bYhX5THxSjQH1fMUuTLXkHffGEuaqnfyz6N4EuRxT0Gki9JN0Uwpb+30DR3GRapr 9DlqYses5tp6WMYarEwxnkmudv7l3oVVxeSbm2BYnzEi6WxlWana5huYa9nMnMbI xYmNMyTmkYrZjfyVmzhi4sK3DeLpCjchZ7RRuYz2hZyXcfax38iTXhfXIL/SZWXh cSelqiAIZSjrh9yvP6ctEjxOmThX0aNGFMb4duSv7IjnDy5utd2jscmO2H0PDBNr 4J+yNJgLYPWpvmBQ2mxqo/N/aHcGXc2b9k9plB58mxUyRQbjFhlimLLWA0unmRJo bqWz71CpA7oP5jvoHaPqUihfWEugzOUbQnUzSauDWWOdMqQW+UUo/iDRz6HCKdlf ww0288krLusAEQEAAYkCHwQYAQoACQUCSrQO6QIbDAAKCRAQwBxaL2BZ5y3tD/4t +KCuXBNi5alBCExHEzveMdRF9FJrSqJEX0NwGFivF3hQ/HJkrcu9oTJC/tXNFf/+ EHOd0lMiyFl5PBSlhe4XS988rgapUW+ee9tQmAt+RgP40fdKdJNb6+9NYGmrdnDU zlQtP+h/XBOcmF0/szK/U0oigg8DjYYUm5gCWXOl9H4LJgg+yOcVCOVa4oTf1sdA mQba1xlMhOIYBWmEhqbWZpGOS59XvpyNfOQXWu26S8HACBqyPZ2LVV4H+9cmxinT z7RX1yKD17nLZ/fTOzZ1gYTbhg5rNmFpDgu3nlgU8SpGQ1kd70ZkcudgehsUe1Ep Pyl7O8qhj5H0/3OAmRXzrq2VF17gtz7zpntA0JqsBMbSaK5qBuBcurLhBT634WDI oE8u5Em1UwjgTI0Cx/lPxRTbIb4PfjP2b2ik/tJaUbwUrhuZ4LAtGztMVrF4W+qn x9oed4OFXMBbwgS+SH6oAHlGwpxhhzXBlqZsHXm+w+2oazWUhxFFGEe5U245GEtN f0AznBMDWTqg0SCVEDjlKt+e9tVXkTpHYWZjGbRZbEHkCbFqKhq0KP5BGInFZTFT oI5jjszmuX0W/yKpRpQZ+GuJnt4VrYSy7TMvjjhIpuhDY57VUwUIkz/2Kq8Vg2wp Gg+29nvcGOTdyZUcTCEB33B2jQ9z0XUEp+6B2F5iZQ== =hSkx -----END PGP PUBLIC KEY BLOCK----- pub 1024D/288584E7 2008-07-02 uid Rémy Maucherat sub 4096g/4B6FAEFB 2008-07-02 -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.9 (GNU/Linux) mQGiBEhrfkMRBADbIagwebBmnRUKF/g699t9ozZeqI75uCkHoqwji1rxVDSeJskU DguBbC9kpMT6m2Qr4MRYEHItXccsT5FPMM94P0VF7zL8sTCNRmLsLSq/dX4C2YuX ejGaLIQ/P1kkqvXJc1BU8tduJyo3FNaAGjGzWmcx6yDUq6NVFaKBi2GdowCg4/+s rgxoktNz97a1KRVyEkjGEFEEAJMl73H6AyimIfKoAVmlPlE4KZvJNtmybF3Ws86M CAraW9j/yhIRkkOiFZ1dKnxpFPBLHImzfXXFIt1/vJm1PCQUx2jaEQXZIMl/YNU3 57+5AjkbjWD6pKG7axWcsuPQ5uTGmqAspBNscLaEbqA29luDmrIcyL6SD8WW9uA9 KPyCBAC9nCXxKyLsHLqluHAi0wld+A5x2q7RISkxDAuveroi6AYP3TZof4FEi9Mt hKsw7sVJD6Tpnz7qqSWx77hCeNVy4t10u11Jgd2s3ieqh4Zt5WKmVCdsuubLE9/c WsViJopWYJ2YOZaPtDi8t7HFW0vjVTYKG7zEpURgYqHZr8GcbrQhUsOpbXkgTWF1 Y2hlcmF0IDxyZW1tQGFwYWNoZS5vcmc+iGAEExECACAFAkhrfkMCGwMGCwkIBwMC BBUCCAMEFgIDAQIeAQIXgAAKCRA8NwOJKIWE5zIHAJ9T+cL0L1oABSUxS4ae9UQI WB5hHQCeJWQhnEpBzrQ5EmHCSeoGDhl9Q3KIRgQQEQIABgUCSGuIMAAKCRAPRQom YhC/wOoBAKCeWVTg4wkwbtGwcY8IdBZhYKhvVwCeNXq6lQaUa4l4sxxjBLS9MTQ0 0vq5BA0ESGt+QxAQAMQMOJ3K9Z6gAaElTt9ZgPtdQtztA1iDesRmrN1ovbKmGptl Hkg6B/nRZXIgHke6TNfXxoJ5MOj1pHZibyC4G8B0H2dKieR+yw+P55GVKSDUMGuk ewBWdbfOLapQCtK5oYvWHycRFCttk4QnXdTrtwbSXYIC0fiwMoz5OF20CQloqFMn k7BVeKbppbiue0Nu9oiWBDGA9WvjwtePVGAlIQ2Oh6ubt2Bf+lfiBE0E2DjMRcYn /M+qRUI8LsoISyxUWoYEB4wZxwiPQYaxVUdiOWDlVR+jgYK+GIMQtTaFqxXESFTR 6DXlGGvpiOpfTTATuuqgVd5qhOXoLxyB4J7987Puv/SshCl1Y64T9coFkmAce2k6 eZNJdbKvVffPzrUjBv4w3poN7iBs5N+g655s2bHY7D6yIUIGIh19NsLroYDHlC4T vF70SP/1l64T8w+srgynHDGYPzKQLdTq2y43YSr0RIVARNpUDQ385/aCbBLze3Su v+sxhvAhEIWTL9XTWiTo32RR/b+uMNsbWF9hNLli+vI60kgduyw0LbHU0aIpbIZk 5FaCLblub2EzBG4MmOrFX6VTlkWz5I/oIxTM7yesJV5aF6WA0u9rhQy1cvgj8dHa h+Vwf74SNJiR4OZrV7Pl1uVU05MhO8YQx50mEJRKNe6BA+vvQW4AW7w9zz1/AAUR D/9FXBgYltaBLgzftIctM7MAV7CXNDvXBmZSAvHbfa9iLEHc+sQGmvpWYHJ/uOs5 GbOxZcYCj7qFTkhCa/jbwO6PYkneBbKfZf3L4lXXaOi+pLOn+LD6QvZtvR6WLYue d0akCTc/vftbPbsk56PqV4CFGv5vIzEkxACAaT9nchHH+7iHLbrMj9+XG+k6mcrD 8knF04xgDN5P9TkngFfabLPXXpYrJ8ZpHxUN2Qrh06P2dN97vimYXCZB87lUncHu WpFmWOS4K1aF+Xexi3mZaXdRwGY1oPEFj9lzhUe8S99eHFY5ru9xbV5uPei5C9xo qVNf6D1UaqqJOkShnvYlzFBUliYKqE0ksE6EXa95qAGqdm5GxXqjsQEXZ3IipAW8 HUSeX4d/ze+GHs4hIT2ATE0ShANoVq0boeTzn9zWXleHO75L895t01ZeybJofMkC JHuAhV3LbtthMlxiBrJwkBenpP63i/Kyz9GeafMfhsXC9M2FtnEI9ZSOlu9/ZWXl f21tGr3pMXYuWurs7GMwZzzhELLhQxgG15p5MPAzWWlZ/j7nXJ2pQWZC/zL4a2DA hTHsiZd36PIoLON5IFXxDjKFHKLSPH3xNbXVQArNEyUgtR6WUUeeB3k6DCbx1bfJ 0UVWWirO0eUtXCm2dHFD3WDq6pMUkRou5gMrzSjCxh6mOYhJBBgRAgAJBQJIa35D AhsMAAoJEDw3A4kohYTncYsAn0ULUIAZf6x+A81JFu6MsqtrZxkRAJ4uWAXFhEtj SiHKkU7BarrCyjm1Kg== =1Oke -----END PGP PUBLIC KEY BLOCK----- pub 1024D/0D811BBE 2006-11-14 Key fingerprint = F3A0 4C59 5DB5 B6A5 F1EC A43E 3B7B BB10 0D81 1BBE uid Yoav Shapira sig 3 0D811BBE 2006-11-14 Yoav Shapira sub 2048g/286BACF1 2006-11-14 sig 0D811BBE 2006-11-14 Yoav Shapira -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.5 (MingW32) mQGiBEVZ4AwRBAC9WDbCjRX9Q81Con7cycGkkui6JZndLhX3Jbzlc/eHG0/fUetP 0c5ZdIvTyjj+L/DRI6btrgl+jR64qkuapsYD/KDXQGkpK5zPpmxUPmXJ5tfVTbOj gacUm2cZjYjSK3dsIs4sDUqNYfBfdwesJ+Hycc7XqkTF1lO2MN9yp8g+4wCg0W8x /ZYCTb9D8JOPzfSNf8cIFCkD/j5GXA2xlSXuAFBgWpFak5OkeF8cwEkv0CQ0zCqP R/rTmDGO/73dpQEzgY+gLMSvtkK0pVEYaE15lg2mxma9d0pGE+fmsu5w7SQUip15 HN5E3qP/VB4X1yp+YiHPGTDjRgJm+xbvTGSFFr0wNSSYCVpVGdYHNmetYsB5JqkH YmiWA/4vnkWnkzQeUNNPvep0lSrEG9jiON4k/d5opWwjxIP4aev8V7//V9ASzznF D6eEL23ePX5ZuKLyDeOSRAwaPpa/Rp4AkiUGzKK21wAwKip+lcbT5m2ButoQhgNI ZlmnfhN7E2t2S6iS9VzHEo1S8Jv9uQZJ89Tp5fiFe1pXL2qBHrQhWW9hdiBTaGFw aXJhIDx5b2F2c0Bjb21wdXRlci5vcmc+iGAEExECACAFAkVZ4AwCGwMGCwkIBwMC BBUCCAMEFgIDAQIeAQIXgAAKCRA7e7sQDYEbvgiLAKDHEgeJyxlrxNJ4m51jOnhG xlsLOQCbBWAdTjpMVcNqmd6Fa5fgyCbh8XS5Ag0ERVngFBAIAIEVU1iOoq4CyD3I f+AChfSFAgqjKmjqEyPv2RDLPkI3g2FvC6HvOlUucIe6IjqvTXztdxSRQu2EGq5i W8e5ajTZiI9ZNs26XLL4/q/gYRaDjUsI7J3PAOL9lNdws6ZoqlCh44R/cvekuixx HoHGskGxAHBRdjv9Oqy4x5hR5kebGq9Ayf8CQZ3l7aRekwlMUyCsmMkNxmqMls2g ViBFD0/9a/xodE2VMVMg5eQ8A0enlrGDghG9d2m586JtOje55rMVnVPkEuNkz9AC DkR0CiwQqX72Ub10t/qcNqbDeMHFacOBYRKfS7Qdm3/jb8Tc4jO/AXFcUGbH5niz pPGs+UMAAwUH/1M2unaFyfJddVPQRZCJEFxdlxkg40tewgjaNJLwnqOJXw1RENNM bSx4Gvz8M6WvZtkvITt29P+O4EmGq+LYTKmLM/E399KuqoZGbyCu3Gm+RIxKmRkf Y3izseOhrUX2ycUIOF1BFzIYs6HeO/sZeba1bapOFo/xS6NwnuJl6uXUmynGjVtY gvQ+dLYAcDXUQJd+QjyXdsbnp1jmdSrqqscPGOquRAw7/sp/ivom4DDHMTz4HErz NfHzn4z8kUE7T1EEpnFU4SBiJkpm/+yEhEq9hDG2GZmxfQd34iRXpC5B4ZbRiwW8 p/bhzvcxZcrahQzu5yyq2+kGhK7IA9APFGSISQQYEQIACQUCRVngFAIbDAAKCRA7 e7sQDYEbvppSAJ9+i7TzCNvZ4PK/odiIWeZ61+KKyACfSjQXnC5UbxndwtkOzFKf Io8ZP0E= =xT1M -----END PGP PUBLIC KEY BLOCK----- pub 4096R/731FABEE 2011-05-27 Key fingerprint = 9BA4 4C26 2138 5CB9 66EB A586 F72C 284D 731F ABEE uid Tim Whittington (CODE SIGNING KEY) sig 3 731FABEE 2011-05-27 Tim Whittington (CODE SIGNING KEY) sub 4096R/461B342D 2011-05-27 sig 731FABEE 2011-05-27 Tim Whittington (CODE SIGNING KEY) -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.11 (Darwin) mQINBE3fcdABEADmpbGMmnQiMc4biU+CIhV6EJ7lBaRzXzh4tJ4eITfw6IbImDRn 0JHZNjeE5zXLeH0PQ0K8/bYzFhMGwQOgvZETV7LPVLid6F9LbvDnItcWyoiZ+HPG 9SNdxIAsIVxchW6j/4NcIWaEwJks/+3vveBbRc1q0UgL5b72Yxpwwk3o6LMb08vJ wn0LuljqM/+MHc+/KuxO54jJZ2OwNbKr2cxsYwVCpj+vEF6wNh2s6v+5VLs7NimN UufiKVGcz6fceza3eYOS+0aLe4JXUPfmbad55x7H7wGMbfv+XLsBUKJ9Bz5nF3QD jLwGBId8/K51yXGqZUqwjzTkhIalJeZEMZuAxGkLXsYM47OH/BGPNvqfcX6X+17i 9urz5go5kWQJJLGiBDVxiwpyrcZfrqc2I0DicLUsAbdyd6q6gkEcQKLCFmm9GTW8 c0Bb/kqlfGnDcBBl3kwK8MvvTeEAq7mteZEEOu/aV+417qDx+dNzFIx/jVjkihnC O10vIXKmog8Dy36gNuJdnqsNuV8oGK4vPRFy80XajmYBl94xfR/ZsWWo7y66UGQr NsCrCC+DV/AlDMJE8fjoLKyTtGnu7U5keyiuUIPvDurbrn2JKGefRnlRAoXRWdiO nzO7vBbfOQ4g3pjUwuXqQTBzqHwnL9z8gX/MR0Wm5RU+B0ZielPkrt82YQARAQAB tDRUaW0gV2hpdHRpbmd0b24gKENPREUgU0lHTklORyBLRVkpIDx0aW13QGFwYWNo ZS5vcmc+iQI4BBMBAgAiBQJN33HQAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIX gAAKCRD3LChNcx+r7gOgD/9DgtptXELyFxaazptqmNkjIp6X4JKjl1Kp99Aq2wwR 4DdHBbZNN2qpQ+Q66klxWeJRbf3t2z/4oCkY3G9g+UB0NTgZBcBMl9c4sDxYzlC/ B9GaHTByaXLWhqv5I6IAiiECiyxhkAVHVqDYjpg5voCD0ZcYSWX9IMZLGAlBU2fe /0g0QEaAV+4SSFsnp7xGaEwoFQd7VH9bS9Q8mdCPZf96Dz7S8XlSpm7Wc0Wvsd7z wXGqmBZVQ0w4mVhGWeaaRUKuVn5nDF6djI+Erg079Vrla6pcXfoBiIugLOUhvvmv Zb5yBi+RJ5CQAnb8ApKm1IXotUCq4GJ05SwDR7xvpS/s8BKIlXmY6h64q7sy66a1 SdRtKL5dncVptknxVzyw3QjEMt9Q9v9W5kgeSabebjAztzPFRR9EBxWkcpL8lwml bTSlheb/+fsEiE0Hw6460xCLPtLFm2RnigdacQgSffhtEzZ5OB7aoXRG/M1McN1v zrjHxg8Vo7stPiGSSvWQKZJQFvWgFUbugoOum5GTNFJeHwlAyjBydkLJ0A/nwUgD efXMV8a65+LUAFVJuEgnOw2Ut68bU96KOSHbNaauErqiWZlcnJIOqD3wRxB3OtBc 2lFL49n3bJ37k7CuhEZUAgU/cqN7meH0wo1aI4KOfo5PHm548qckLi4P/pAj8jHL 0bkCDQRN33HQARAAzeAQNb4AfB9v4r3qrN3bwF01VdMpVTaQl3RaJKGbdO52f4gW 8iIfR+Xc6ALeX/1ADsH6nyOuQ+gnTpf4Gr09Lf/EzcrJRN8okVFehjuaahWYdmbL rln3ZorzbLxHp52dvLS1EX9L1+MEgGuUxsN9fDJSuif6f7+E/a80Q/WEbQ3261lB f7GDSGvr3xz6M0OlTS08YgUeUsx33PQRHV1TU9RTSASsivy316u86gxMp+9PJ+6n m99iNvZB1VXpthG6ybgyxhheQv1o2SBAhJ3Ee6Neds1kPkLiKiAbGq9K9IApqC8X DYZ9FUYBT+CGm8KbU8QS10wJuIVIXRYuvNZBjjhZdbGIGJ2CGIn9cO8RmzDVVu0A Ch9gCGh12Rsr4uZkY9tJ6/+s/ipHuft1AnPETbrET2Wm1rrUZ8sFykP6cOwP0gen MNEjTAHnLE0x2yAjFfvjz/y0H+gMQqcbmyGvAgY0URl41+5+yxtLVJIcuszut77s DV7sM8CoXz2I8/K+R/lB5p8d6AriAV+iYqzATmyfFD27GVHp18wTuyusfwy8301q CqjZdR5cXQHcp+/yCxz/I+PXx21QE4e3nY8YpC6PWFC/XPy7s6L71uNauqPi5WwG 1CeYEwqd70Ds3aeVErYZxYg/kiInfFGnXjUplvz2goT3LQFWHFS5TN0sUqsAEQEA AYkCHwQYAQIACQUCTd9x0AIbDAAKCRD3LChNcx+r7jscEADgCt4SmzeEWuU1fZYx FsdnC3wLZUU57HnGMAQdxCzC6lMXNHUiS+y8of1TEYccjM8JK0zSTwnizhbQzOkh ICR/0tGz3qCOAZjv91YHs5RcLzeWxbor29my4VlQU6vqEwOEPwFz1b1Grp2rbwhL hot81tqv4PP/wn3ES/FIuTALZ3/hgunfGlO6FGZC20rtOJHd6DpX2ZPeYi2mfYom KF9N7F9q0WhYn0GvMyV5pqZ6Ui7N8egvw1gokUtO3D8lWnjZy1BmbizozyLmrG13 xr280Juv7zM0Jy5YR01vsqfvClBbczBzoEnkRijMYVJgUj03dr5Cdn5HFRfA5wLD sNuSYKMTL/WWNQgIp24/MLxyYa4sVH9WMh9a7BbdRHJEjVR2HTA/lqrKVIfR6NwT 6DhThBA7XxGbQ9nuBOjClTpRBXyCnFN+krmyhvVk3caVcQu/BbaZZXFEuKhJzbon YrQkfyvT/rQoM/ufLlIIPZgpKxP96a9zF/eyATiamAnU7idEHIZ0Drrj60vz4sPH A5Ty5GWKYSZa6suPaalqZ+7dpD/UWiNMzSX+YPLQUW9jH/k7zuJ9aZN4AmIkm30c YB5npZhfo59tF4uuvKvYKWghrF8wSwEE7F4cJAuqklo0TArBUd2WB0Wl8kAWtThf /PLn/VX9dZEFVPVbPapJpkNv8A== =Vxhw -----END PGP PUBLIC KEY BLOCK----- pub 3072D/0D498E23 2013-01-14 uid Mladen Turk (Default signing key) sig 3 0D498E23 2013-01-14 Mladen Turk (Default signing key) sub 4096g/DC3D1B18 2013-01-14 sig 0D498E23 2013-01-14 Mladen Turk (Default signing key) -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.12 (GNU/Linux) mQSuBFDzsBQRDADVTeaOjvWuZ84mWFi5Rj0TmnIOdK9evO+6Bnr6eI0MCKxLfEYu tpcq3hrIN/sXoVJW14Kb2Vm5Zt0PLWBmlQoi+99QwfHRvrejQnYA5VCGql61Vkbz NbpZ3Eq3n9d1HOLhdRnZAUGYtFYm7etkdpUZSHOErZWdiCebc8Og2NdWU4xIG6f8 16UxuzOWv+fPCtSjciHxYWmzrVc4fYNTvJiyN5OtJ08dCaRfMeAMqec4fNMOn1uX KXuwlFsHk5ieK4K91RP1zSGQEe1gGaMDSQsR6wwmnnEoP7QzlvPkr5gni2+uGccl UCfejUUQaBsEXDX+S9CesFLv/EtWMgjpnyVCF+uSCrj/pMNHJHX1zktp79NJFCJM BrifvthC7cVHl5eWVTMb+xFC9leEKcUPQj8GQmUlXKd3iiUCQEhoEAk9IC0cVaMq 2wp2lZRAK+7MSO+iLYA6GSeCBBQowCC8fvc/1ihZ+JtcmR0uqErrLRpSfBbn6Ynw K6cu+Dd6zRBOegcBAMIQg3biwAjnP6AhB3Ul8J/Jlk3CL/v+ChMUuwTGgDKlC/9C kg3KctWPhlImHATy1STBBqIoebYxe+CCxxiukt9gp2NCZOdm2ZU7weT9kS7DYQz8 scKcAbSFBTILSeDOHehCb1Qz47H3JfyRzv23VoJ4hA/0sfm1kWeqXwQEBkAtZfrF /C/N0Sdnf2OUf7LsEDdkaVzkVQVJZLzZGjpNq+W8zoHhOOi1KwIzx8y1opEysmiv /CitQOhnLJT5odM1a+AimUjdgyQ0p+U1EkcAnLAYD3UIKMA8wnGzfJZJ4tkrYkBu YLW/lyS50ddhzPniz2XeCc5SG+tCi8le4B+qZb4GhC+nKXD+heuRXA+45hQXEx9M dGgsormYKnCTF5v3Bf8sSnId8nj0eBbKZFJhUBVgNpwNrW5QjYfJHGHTMBnWy/Jv SF3CnWwg/IPTNcX9ctxL4FatpPREXE/Su/4/BDjm3R14cCBfBeiVdcRZ6J1TLuLP K+qcT62PHqd/ibthfkLlnuehr4Qsfy75UypY8/2zrLz9QCIEo8MEFcUicfc+HB8L /1AYsI4c1lkgOU8aubasn1GpNrvyz5NrehIPevPEjSeBGJnOxQEtWKDrD8TMd+Or 7r9+SLGVog1NYnkhzdEGbO1m/VXGk7JQI6UU5Rgu3PaJbfBPnON9kABfDnIQMqH1 LeylZUqAnnv4Fa3YtiQOyro3FM8Gv+r2E40SgIbX1bLfCzgqdYpDIIK1FLfCu9oO NiMolC4gl+zOjCQ+ilV74J4vODBX701Zg3nM9WnQcXBBrNcuz2ofTzg9wm61zjsE JSRPLIaiT63cyV1kvjMN1oAkCuc3Am5albC13mOAryEF3UB2ROrc1BwdBMC+aQ/z BLNrxEeT7M1YiE1cFnmZZdb0X6pz2UWsiBgmproRriAOzsMW3fToJxcMykBzg/f5 6QCgoCbJ6Fv0UC1yDulnujxFXRrBPH7PCxeRVLi3cH0sXCBZbHRMRJDhyFn137Br qKiP+UTPNgrj8dc3UGi13RNApHxYBcBO05JFSh0KrFlJFBd0jITLa4LGGUC08RDT 07Q0TWxhZGVuIFR1cmsgKERlZmF1bHQgc2lnbmluZyBrZXkpIDxtdHVya0BhcGFj aGUub3JnPoh6BBMRCAAiBQJQ87AUAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIX gAAKCRA1zSPBDUmOIziZAQCZD/YvZ1vrxmwAgDeJoMajmvHpWJPECkUzF0GFLW99 CwEAs0ZZKpwqQEEewdGocKld7hEvlbmvqllrCNJDkeDdJPa5BA0EUPOwMxAQAL6j 2zs8UQCVhPxf/RO0PhLqTPk8/6NW/W9uN1QjxPtdFaDmIpkIdY6RI3bo9bRlKf/F vWWQfteUDhRiWosE/ERDrLDoFzSAKIEE3/rm1jYTVuWbfYnBA+zHbZmN0KgV8fbh cLxt5qX+YTIp9mg2rXawCc5j2vQvPmCce/JkaR8k4ZF9XhWIrpH/afH1LE3ExePK 019Zo9thP9dw+IiJGWmL5v3JCiJDNmmJwqSKtBDMRX/9ygIZUWABAmvPzsr+fkee FyPaezwtj1Qx96U+gZJiYO+eW8f2d3PrK2hC9yc8vD+N6w/ZdD4UIMBz/sSgmcD7 WRVs+j1KpEzIMVwxJY2V2bcuqDRKdPrhOO4zen26wutKRzZF5SRx8ruRE/Hbxmqh H2teUtN+3xR0ARkbVDrTJwG8rvsUex5pzQk/z4V2s1Dm8ihirEuDFYE5B7Hpht8U 17JhVH6wIrBvwMNfd+Ac1mlfvBZ19JGOnjCwkR9o44N5lx0BSSndJVnrjitV//Zf irASTVc/GEw5150kkZRCkaW3Hn5KMysGNXxgFf6aBbgVBlR56mNHT+6qbZV3Owbh i5hSSKqxXMPsv3XEANg0isdLiv3E4/KxozChph+93EWuZwdrD0PbBccyJlUCywaj pMBaKXzRDsuZOImi3ujcZbqPb0bZW1eZRpQ3LePrAAMGEAC5V1gmisUffyR5I3kk HBcEkKW4fCQFZ/FLB6cQi4t9sunOYPT56klokhSIE0AJq/ndkOLz9eW2+D4RK3aj IBtFTtBnXzn6nGbg+G9cpwPCpcWyuAMsiPwcFItH7mbcD9h/TCXJE+ILyhXaocOb n9D9IsQ16WAIIQQsBbGYMvaemJv4xsZQrLhCHr/ofHye5huEBn/wwyBKnTCLd+P0 AkF+whf4Vl3yF4W3vnrYRFjU0XEXnVQ/nmiQH3cM0JxkVy46H3Zoe68Sjt49ZJt9 eEWH4M7KyJc86DWjRl/YMNdHE9SMx0ReKJTTNATfzgWIMvH+xUsD9K85Evm70jxc 13XziHwL0BjtMQzml19f/TDCUeLE9FiO5fyDgc6ueehsCxoKCvG8acQz25rkAJBv i0WqdFSJG4rrJaLEwbSDkAkpY9yVk73acamwa42/E4G7v7sKuGVHzW5xBX8ac7lz 3CqKw771vWGZPgd8v2FIkk5ShikVyKQxnVADVACy2eqL8A8fmQMRSc/FYVMHfo0O MD5jeWWAIPo3g8bguqwqyTC0DQo60Y38t4lyXxAvg5oWvwzKdrWKwm/WmQJaJuk6 TufoONXlsl0cc4LLHZESIwLRSP5YfxV9chplmA92vhekV0f2IchmJky/a25KEIRH OdCCQTyOitoKXYy2swx9j69Q7YhhBBgRCAAJBQJQ87AzAhsMAAoJEDXNI8ENSY4j plIA/R4QYFbde0Jw11KjqAr1AkQHaume7p5mv7Vt6I/D2CkUAP9i2PGC8mgArtlP XDH35tl64G5lNKNum0D8NSGV955R2g== =gxY8 -----END PGP PUBLIC KEY BLOCK----- pub 4096R/D63011C7 2013-09-19 Key fingerprint = 713D A88B E509 1153 5FE7 16F5 208B 0AB1 D630 11C7 uid Violeta Georgieva Georgieva (CODE SIGNING KEY) sig 3 D63011C7 2013-09-19 Violeta Georgieva Georgieva (CODE SIGNING KEY) sub 4096R/30480593 2013-09-19 sig D63011C7 2013-09-19 Violeta Georgieva Georgieva (CODE SIGNING KEY) -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2.0.21 (MingW32) mQINBFI6WiwBEAD+kkswnsY8eaqvYkS+ZB5MJr7juWrv9Lw9OGsIXFlTvD1XK01c E8k4+uA2sOtaXQ5wTMdc5N3YzAXqFxplWuafQgEvhyTTq37M5YCxvtYEZy/EHQYT iok5H97lMRKbhLdZB+wkdsa0P/L1FveCUiEawKY/Rrfi+UeRAneSV+m7S+RrPphZ M9aNSczqYKfAqlpUAlUcrF/bt59vjhepoHcE4ev6SB+PCs0vbvX4iTvvZCTk1lZ9 InS2wdK80Jz9pRB0Uf3LEnZxt9e3RkIFdQOCcEISmNlBKQQKFG+zCpIAbVoMLKEw rXWl8mLzGzBbhGmLpFroem3Ln1YiAxUqnPR/MoBquYnpTINwePgwKVWyQ1TXG2MF Z7DPayBMN+G51rfLS/8iy35pAnNeqbWQjavdUis6/0aRMv5EYMFMAerutQ5v99bA rGj6OL3R6repJLOGT4YWcD/Tw+eU1lMWxbq8BbbRU9Fd0iVFhFyKB/DQSxofvTCe PdWXRrptrE0/SmvuoTRVPmB21WyJenKdNmVOQ6U+W1Rs+5IKAdWWrGPcUt0qTrRC SL8vAQ7MejYLovFtRHslJRs7T3ratpRcQUNOx1jytJhmSUJktNWZWNHqBTe/eOAU Yr+QAkQVQXvRVWzHkDHQRTOFmNYIDZYRkzSP19sBWRnYdCs6CbIVPgMJVwARAQAB tEVWaW9sZXRhIEdlb3JnaWV2YSBHZW9yZ2lldmEgKENPREUgU0lHTklORyBLRVkp IDx2aW9sZXRhZ2dAYXBhY2hlLm9yZz6JAjcEEwEKACEFAlI6WiwCGwMFCwkIBwMF FQoJCAsFFgIDAQACHgECF4AACgkQIIsKsdYwEccMXA/+KMQKWfw2T2CXLhqvQLoh Irj1Vi9leAttKqKp2NCHLK1jf1qKzUx5U81VvizIGUsDXGlAvnnavrj+hmQqZdsO CoJAo7ViIR1ZhNca1tFK4Sy03wdpNyUkvxVuC+3peXmwhjPJoqU2ONCuDl/bCczl QAQpgZCMO93h45U9H6JkjqK01aDorQHxvXo+Ap2IViQvDkNtJ515vG2k5K+x2XHw Tv19wr5N2rz407TWKzS5hh7QHRgg+PZs/zPf1YHD7Tg5K6vvmZd+5EsDrse6tZXy mzz2+8Yg1SNa765Aq6p1uAQf5NKeej/25TbRYT7RyIlgDXPcPrKxy0cKzpqFqCFs jJEcN3NlQq+f1tOvUk8cQQS0G+Qws3EU7I74z8KaUfqmO/5ROrXLS50cKC9CODO0 UFY8FbJDGzS5cFSBlqXYLeQvaOMg0LsV6wZLu6brxEsRYjSpwM8yBFO4bMcTxt4P VYtinNZ+6ude8mMz6BK/0/XbAL6rc5jwO2xj7GTCFNRTWOa8IGtwqg3qnAiHcg/V bTBQCOmzMujHBXLnZu6vg79BwzE7Ikq634D6HEwi1bC3XuVz+7NqdUQAGPSapwUo +0wC5DVwdjhe1zWcf2Zc45HWsx0HaGW28x/tBrw78fgwrSSyV2xunbxGpVaaysTy Oini8V70uLofn1SHtxvEQCm5Ag0EUjpaLAEQAKV7FnaAcxkzDa7zjrAgLRho44KM +lBt28+5KO3Jye1Lpf2+4aspu0PXkGW2Twv2tBQNZYs2CWF+vnHNUDuU8TkSpPt+ 2PRSZrQ0K+IpQF/qY3Wf+LYWFNXk5/wHJLGiQv/008svtupng6Ov39JwCNQ1iG3d nSWfnqHwQULyE7JcZf1It94G43+6NBvKakstOdK7d40dVhmRIKDdJkWhN3MKrGab FGFAF2Nb57IugQ9QO6Ve/BnjKZmJg7TyUZk27LVTC0aUQgGgDOvsF2Iw95IplCZ/ jVbwdBGjeCStvI3c0DB+E2xwJ0g2Wf/CBLvmU9GKOW0toBfRUXFbfzNTJfW8kglt pDuELsVY5vHHxgujdDInHuTW1930zUw0cNA2+ai3sf+UGejh0e3nGfy1uOK3YQ6H 2YWgqXlOkri9pMlE0NJo/3PW9QDu0YRplGl65k+GtHD2La1akq5V5Et0VNaOypBP OqnUM08LofAS126Kerm7uBSUQDDV6t1VTOBgPW5cJF9I8kdp04pzj4qb/3fuOuGc kBRfmO/Vkug8U81w/TnxX6EYGy5fyA4JFBJl++waPS/9dXhVnA0qXEivzw9gNQvC uXYcM3nm4yUrOouC/OlC1cS+6Wxjrx6qn3NnsVzMCtefNK93+TdheZ0cJrMhJKkW v+qttOzPIleqvDK9ABEBAAGJAh8EGAEKAAkFAlI6WiwCGwwACgkQIIsKsdYwEcdN tQ/+L8cw9Z9tfrqovO1fGFQwCSaomShsbjoUb5AR3Hj3OuPGwXd8J62mrw+RnGN+ 0w2RyTz52izYvcoB1jmMFQwqi7vM5KCbw6KA8oRX58WSqiWCIwpbUuTODvJrSXjX pz/J/d+PVZi8T1HAu5HxDqNC1XR+eUd1xA9Pgnmmw99+0rmzES7xexWADXo/RRPH mDCxGK3UKMHDYJLTx8D3MacMitzQulxVo9xWwH1C7ioL3o5zCv2mfIl32WNjqwpD h4gNpnAGRthizeYTgyJM9nCrSWgeE+izGZ9F0g5uXzhyk1f6jlUmXiwjMu/XOcJO 5Rr1e42bWITuP49nB2QbdSqVvVscwCd5TEpOnQtVNZGsss/wQHXDmGSVrYYUQwO/ cUrU+hTti1IJXgyFi7F1oxde+LCUxXmizKGoY96dVN+TYH5c17ub1/4/DYpOmcly tsQ2TOV0BqK4rgKLGfg2mA4zIFOdqXeGefLQVAF5fFzjFKKDi0ewp3sqy+ed6mKY 1M/HmRX/YzIouFZ3ChFPIpeY23XxJC0BXkWR4pS7qxnelrWBZ+UbleNr9uHat5rC B77712dCT9zz85b380DnuMkrgz4HCnHuTcbHXIF1J604lars6ZrjtBvX+OsRHt7V f72qKJufP+n01xliW68LP4v93auM8nuE4kkEJ8ncHyuDq/Q= =fM0q -----END PGP PUBLIC KEY BLOCK----- tomcat7-7.0.52/NOTICE0000644000175100017510000000225012261573157014057 0ustar locutuslocutusApache Tomcat Copyright 1999-2014 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). The Windows Installer is built with the Nullsoft Scriptable Install System (NSIS), which is open source software. The original software and related information is available at http://nsis.sourceforge.net. Java compilation software for JSP pages is provided by Eclipse, which is open source software. The original software and related information is available at http://www.eclipse.org. For the bayeux implementation The org.apache.cometd.bayeux API is derivative work originating at the Dojo Foundation * Copyright 2007-2008 Guy Molinari * Copyright 2007-2008 Filip Hanik * Copyright 2007 Dojo Foundation * Copyright 2007 Mort Bay Consulting Pty. Ltd. The original XML Schemas for Java EE Deployment Descriptors: - javaee_5.xsd - javaee_web_services_1_2.xsd - javaee_web_services_client_1_2.xsd - javaee_6.xsd - javaee_web_services_1_3.xsd - javaee_web_services_client_1_3.xsd - jsp_2_2.xsd - web-app_3_0.xsd - web-common_3_0.xsd - web-fragment_3_0.xsd may be obtained from http://java.sun.com/xml/ns/javaee/ tomcat7-7.0.52/STATUS.txt0000644000175100017510000000463012077555644014751 0ustar locutuslocutus================================================================================ Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You 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. ================================================================================ ================================= Apache Tomcat 7.0 Patch Proposals ================================= RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT: [ start all new proposals below, under PATCHES PROPOSED. ] PATCHES PROPOSED TO BACKPORT: [ New proposals should be added at the end of the list ] * For https://issues.apache.org/bugzilla/show_bug.cgi?id=53119 Prevent possible overflow exception with buffer in AjpNioProcessor.output() if it is called again after previous write failed with IOException. I have not observed it, but it is from analogy with AjpAprProcessor fix in r1344253. http://svn.apache.org/viewvc?view=revision&revision=1346365 +1: kkolinko -1: * https://issues.apache.org/bugzilla/show_bug.cgi?id=54330 Refactor Member interface to reduce dependency on concrete implementation. Based on a patch by Greg Turnquist. I have added this to the status file because it changes an interface. I don't believe there is any harm in this - the interface isn't really usable prior to this patch - but I'd prefer this change to be RTC. http://svn.apache.org/viewvc?rev=1430602&view=rev +1: markt -1: * Back-port r1437083 from trunk. http://svn.apache.org/viewvc?view=revision&revision=1437083 Adds SSLContext.clearOptions method to allow clearing of SSL_OP_* options in OpenSSL. This will require tcnative 1.1.25 or errors may be thrown when attempting to call this method. tomcat7-7.0.52/java/0000755000175100017510000000000012301126371014060 5ustar locutuslocutustomcat7-7.0.52/java/org/0000755000175100017510000000000012301126366014653 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/0000755000175100017510000000000012301126371016070 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/0000755000175100017510000000000012301126367017364 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/InstanceManager.java0000644000175100017510000000336312271453632023277 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat; import java.lang.reflect.InvocationTargetException; import javax.naming.NamingException; public interface InstanceManager { public Object newInstance(Class clazz) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException; public Object newInstance(String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException; public Object newInstance(String fqcn, ClassLoader classLoader) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException; public void newInstance(Object o) throws IllegalAccessException, InvocationTargetException, NamingException; public void destroyInstance(Object o) throws IllegalAccessException, InvocationTargetException; } tomcat7-7.0.52/java/org/apache/tomcat/buildutil/0000755000175100017510000000000012301126366021360 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/buildutil/Txt2Html.java0000644000175100017510000001213312271453632023716 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.buildutil; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; /** * Ant task to convert a given set of files from Text to HTML. * Inserts an HTML header including pre tags and replaces special characters * with their HTML escaped equivalents. * *

    This task is currently used by the ant script to build our examples

    * * @author Mark Roth */ public class Txt2Html extends Task { /** The directory to contain the resulting files */ private File todir; /** The file to be converted into HTML */ private List filesets = new LinkedList(); /** * Sets the directory to contain the resulting files * * @param todir The directory */ public void setTodir( File todir ) { this.todir = todir; } /** * Sets the files to be converted into HTML * * @param fs The fileset to be converted. */ public void addFileset( FileSet fs ) { filesets.add( fs ); } /** * Perform the conversion * * @throws BuildException if an error occurs during execution of * this task. */ @Override public void execute() throws BuildException { int count = 0; // Step through each file and convert. Iterator iter = filesets.iterator(); while( iter.hasNext() ) { FileSet fs = iter.next(); DirectoryScanner ds = fs.getDirectoryScanner(getProject()); File basedir = ds.getBasedir(); String[] files = ds.getIncludedFiles(); for( int i = 0; i < files.length; i++ ) { File from = new File( basedir, files[i] ); File to = new File( todir, files[i] + ".html" ); if( !to.exists() || (from.lastModified() > to.lastModified()) ) { log( "Converting file '" + from.getAbsolutePath() + "' to '" + to.getAbsolutePath(), Project.MSG_VERBOSE ); try { convert( from, to ); } catch( IOException e ) { throw new BuildException( "Could not convert '" + from.getAbsolutePath() + "' to '" + to.getAbsolutePath() + "'", e ); } count++; } } if( count > 0 ) { log( "Converted " + count + " file" + (count > 1 ? "s" : "") + " to " + todir.getAbsolutePath() ); } } } /** * Perform the actual copy and conversion * * @param from The input file * @param to The output file * @throws IOException Thrown if an error occurs during the conversion */ private void convert( File from, File to ) throws IOException { // Open files: BufferedReader in = new BufferedReader( new FileReader( from ) ); PrintWriter out = new PrintWriter( new FileWriter( to ) ); // Output header: out.println( "
    " );
    
            // Convert, line-by-line:
            String line;
            while( (line = in.readLine()) != null ) {
                StringBuilder result = new StringBuilder();
                int len = line.length();
                for( int i = 0; i < len; i++ ) {
                    char c = line.charAt( i );
                    switch( c ) {
                        case '&':
                            result.append( "&" );
                            break;
                        case '<':
                            result.append( "<" );
                            break;
                        default:
                            result.append( c );
                    }
                }
                out.println( result.toString() );
            }
    
            // Output footer:
            out.println( "
    " ); // Close streams: out.close(); in.close(); } } tomcat7-7.0.52/java/org/apache/tomcat/buildutil/CheckEol.java0000644000175100017510000001305011717170446023707 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.buildutil; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; /** * Ant task that checks that all the files in the given fileset have end-of-line * delimiters that are appropriate for the current OS. * *

    * The goal is to check whether we have problems with svn:eol-style property * when files are committed on one OS and then checked on another one. */ public class CheckEol extends Task { private static final String eoln = System.getProperty("line.separator"); /** The files to be checked */ private final List filesets = new LinkedList(); /** * Sets the files to be checked * * @param fs The fileset to be checked. */ public void addFileset( FileSet fs ) { filesets.add( fs ); } /** * Perform the check * * @throws BuildException if an error occurs during execution of * this task. */ @Override public void execute() throws BuildException { Mode mode = null; if ("\n".equals(eoln)) { mode = Mode.LF; } else if ("\r\n".equals(eoln)) { mode = Mode.CRLF; } else { log("Line ends check skipped, because OS line ends setting is neither LF nor CRLF.", Project.MSG_VERBOSE); return; } int count = 0; List errors = new ArrayList(); // Step through each file and check. for (FileSet fs : filesets) { DirectoryScanner ds = fs.getDirectoryScanner(getProject()); File basedir = ds.getBasedir(); String[] files = ds.getIncludedFiles(); if (files.length > 0) { log("Checking line ends in " + files.length + " file(s)"); for (int i = 0; i < files.length; i++) { File file = new File(basedir, files[i]); log("Checking file '" + file + "' for correct line ends", Project.MSG_DEBUG); try { check(file, errors, mode); } catch (IOException e) { throw new BuildException("Could not check file '" + file.getAbsolutePath() + "'", e); } count++; } } } if (count > 0) { log("Done line ends check in " + count + " file(s), " + errors.size() + " error(s) found."); } if (errors.size() > 0) { String message = "The following files have wrong line ends: " + errors; // We need to explicitly write the message to the log, because // long BuildException messages may be trimmed. E.g. I observed // this problem with Eclipse IDE 3.7. log(message, Project.MSG_ERR); throw new BuildException(message); } } private static enum Mode { LF, CRLF } private static class CheckFailure { private final File file; private final int line; private final String value; public CheckFailure(File file, int line, String value) { this.file = file; this.line = line; this.value = value; } @Override public String toString() { return eoln + file + ": uses " + value + " on line " + line; } } private void check(File file, List errors, Mode mode) throws IOException { BufferedInputStream is = new BufferedInputStream(new FileInputStream( file)); try { int line = 1; int prev = -1; int ch; while ((ch = is.read()) != -1) { if (ch == '\n') { if (mode == Mode.LF && prev == '\r') { errors.add(new CheckFailure(file, line, "CRLF")); return; } else if (mode == Mode.CRLF && prev != '\r') { errors.add(new CheckFailure(file, line, "LF")); return; } line++; } else if (prev == '\r') { errors.add(new CheckFailure(file, line, "CR")); return; } prev = ch; } } finally { is.close(); } } } tomcat7-7.0.52/java/org/apache/tomcat/jni/0000755000175100017510000000000012301126367020144 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/jni/Poll.java0000644000175100017510000001446312271453221021723 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Poll * * @author Mladen Turk */ public class Poll { /** * Poll return values */ /** Can read without blocking */ public static final int APR_POLLIN = 0x001; /** Priority data available */ public static final int APR_POLLPRI = 0x002; /** Can write without blocking */ public static final int APR_POLLOUT = 0x004; /** Pending error */ public static final int APR_POLLERR = 0x010; /** Hangup occurred */ public static final int APR_POLLHUP = 0x020; /** Descriptor invalid */ public static final int APR_POLLNVAL = 0x040; /** * Pollset Flags */ /** Adding or Removing a Descriptor is thread safe */ public static final int APR_POLLSET_THREADSAFE = 0x001; /** Used in apr_pollfd_t to determine what the apr_descriptor is * apr_datatype_e enum */ public static final int APR_NO_DESC = 0; /** nothing here */ public static final int APR_POLL_SOCKET = 1; /** descriptor refers to a socket */ public static final int APR_POLL_FILE = 2; /** descriptor refers to a file */ public static final int APR_POLL_LASTDESC = 3; /** descriptor is the last one in the list */ /** * Setup a pollset object. * If flags equals APR_POLLSET_THREADSAFE, then a pollset is * created on which it is safe to make concurrent calls to * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() from * separate threads. This feature is only supported on some * platforms; the apr_pollset_create() call will fail with * APR_ENOTIMPL on platforms where it is not supported. * @param size The maximum number of descriptors that this pollset can hold * @param p The pool from which to allocate the pollset * @param flags Optional flags to modify the operation of the pollset. * @param ttl Maximum time to live for a particular socket. * @return The pointer in which to return the newly created object */ public static native long create(int size, long p, int flags, long ttl) throws Error; /** * Destroy a pollset object * @param pollset The pollset to destroy */ public static native int destroy(long pollset); /** * Add a socket to a pollset with the default timeout. * @param pollset The pollset to which to add the socket * @param sock The sockets to add * @param reqevents requested events */ public static native int add(long pollset, long sock, int reqevents); /** * Add a socket to a pollset with a specific timeout. * @param pollset The pollset to which to add the socket * @param sock The sockets to add * @param reqevents requested events * @param timeout requested timeout in microseconds (-1 for infinite) */ public static native int addWithTimeout(long pollset, long sock, int reqevents, long timeout); /** * Remove a descriptor from a pollset * @param pollset The pollset from which to remove the descriptor * @param sock The socket to remove */ public static native int remove(long pollset, long sock); /** * Block for activity on the descriptor(s) in a pollset * @param pollset The pollset to use * @param timeout Timeout in microseconds * @param descriptors Array of signaled descriptors (output parameter) * The descriptor array must be two times the size of pollset. * and are populated as follows: *

         * descriptors[2n + 0] -> returned events
         * descriptors[2n + 1] -> socket
         * 
    * @param remove Remove signaled descriptors from pollset * @return Number of signaled descriptors (output parameter) * or negative APR error code. */ public static native int poll(long pollset, long timeout, long [] descriptors, boolean remove); /** * Maintain on the descriptor(s) in a pollset * @param pollset The pollset to use * @param descriptors Array of signaled descriptors (output parameter) * The descriptor array must be the size of pollset. * and are populated as follows: *
         * descriptors[n] -> socket
         * 
    * @param remove Remove signaled descriptors from pollset * @return Number of signaled descriptors (output parameter) * or negative APR error code. */ public static native int maintain(long pollset, long [] descriptors, boolean remove); /** * Set the socket time to live. * @param pollset The pollset to use * @param ttl Timeout in microseconds */ public static native void setTtl(long pollset, long ttl); /** * Get the socket time to live. * @param pollset The pollset to use * @return Timeout in microseconds */ public static native long getTtl(long pollset); /** * Return all descriptor(s) in a pollset * @param pollset The pollset to use * @param descriptors Array of descriptors (output parameter) * The descriptor array must be two times the size of pollset. * and are populated as follows: *
         * descriptors[2n + 0] -> returned events
         * descriptors[2n + 1] -> socket
         * 
    * @return Number of descriptors (output parameter) in the Poll * or negative APR error code. */ public static native int pollset(long pollset, long [] descriptors); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Shm.java0000644000175100017510000001160712271453221021541 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; import java.nio.ByteBuffer; /** Shm * * @author Mladen Turk */ public class Shm { /** * Create and make accessible a shared memory segment. *
    * A note about Anonymous vs. Named shared memory segments:
    * Not all platforms support anonymous shared memory segments, but in * some cases it is preferred over other types of shared memory * implementations. Passing a NULL 'file' parameter to this function * will cause the subsystem to use anonymous shared memory segments. * If such a system is not available, APR_ENOTIMPL is returned. *
    * A note about allocation sizes:
    * On some platforms it is necessary to store some metainformation * about the segment within the actual segment. In order to supply * the caller with the requested size it may be necessary for the * implementation to request a slightly greater segment length * from the subsystem. In all cases, the apr_shm_baseaddr_get() * function will return the first usable byte of memory. * @param reqsize The desired size of the segment. * @param filename The file to use for shared memory on platforms that * require it. * @param pool the pool from which to allocate the shared memory * structure. * @return The created shared memory structure. * */ public static native long create(long reqsize, String filename, long pool) throws Error; /** * Remove shared memory segment associated with a filename. *
    * This function is only supported on platforms which support * name-based shared memory segments, and will return APR_ENOTIMPL on * platforms without such support. * @param filename The filename associated with shared-memory segment which * needs to be removed * @param pool The pool used for file operations */ public static native int remove(String filename, long pool); /** * Destroy a shared memory segment and associated memory. * @param m The shared memory segment structure to destroy. */ public static native int destroy(long m); /** * Attach to a shared memory segment that was created * by another process. * @param filename The file used to create the original segment. * (This MUST match the original filename.) * @param pool the pool from which to allocate the shared memory * structure for this process. * @return The created shared memory structure. */ public static native long attach(String filename, long pool) throws Error; /** * Detach from a shared memory segment without destroying it. * @param m The shared memory structure representing the segment * to detach from. */ public static native int detach(long m); /** * Retrieve the base address of the shared memory segment. * NOTE: This address is only usable within the callers address * space, since this API does not guarantee that other attaching * processes will maintain the same address mapping. * @param m The shared memory segment from which to retrieve * the base address. * @return address, aligned by APR_ALIGN_DEFAULT. */ public static native long baseaddr(long m); /** * Retrieve the length of a shared memory segment in bytes. * @param m The shared memory segment from which to retrieve * the segment length. */ public static native long size(long m); /** * Retrieve new ByteBuffer base address of the shared memory segment. * NOTE: This address is only usable within the callers address * space, since this API does not guarantee that other attaching * processes will maintain the same address mapping. * @param m The shared memory segment from which to retrieve * the base address. * @return address, aligned by APR_ALIGN_DEFAULT. */ public static native ByteBuffer buffer(long m); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Procattr.java0000644000175100017510000001614512271453221022612 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Procattr * * @author Mladen Turk */ public class Procattr { /** * Create and initialize a new procattr variable * @param cont The pool to use * @return The newly created procattr. */ public static native long create(long cont) throws Error; /** * Determine if any of stdin, stdout, or stderr should be linked to pipes * when starting a child process. * @param attr The procattr we care about. * @param in Should stdin be a pipe back to the parent? * @param out Should stdout be a pipe back to the parent? * @param err Should stderr be a pipe back to the parent? */ public static native int ioSet(long attr, int in, int out, int err); /** * Set the child_in and/or parent_in values to existing apr_file_t values. *
    * This is NOT a required initializer function. This is * useful if you have already opened a pipe (or multiple files) * that you wish to use, perhaps persistently across multiple * process invocations - such as a log file. You can save some * extra function calls by not creating your own pipe since this * creates one in the process space for you. * @param attr The procattr we care about. * @param in apr_file_t value to use as child_in. Must be a valid file. * @param parent apr_file_t value to use as parent_in. Must be a valid file. */ public static native int childInSet(long attr, long in, long parent); /** * Set the child_out and parent_out values to existing apr_file_t values. *
    * This is NOT a required initializer function. This is * useful if you have already opened a pipe (or multiple files) * that you wish to use, perhaps persistently across multiple * process invocations - such as a log file. * @param attr The procattr we care about. * @param out apr_file_t value to use as child_out. Must be a valid file. * @param parent apr_file_t value to use as parent_out. Must be a valid file. */ public static native int childOutSet(long attr, long out, long parent); /** * Set the child_err and parent_err values to existing apr_file_t values. *
    * This is NOT a required initializer function. This is * useful if you have already opened a pipe (or multiple files) * that you wish to use, perhaps persistently across multiple * process invocations - such as a log file. * @param attr The procattr we care about. * @param err apr_file_t value to use as child_err. Must be a valid file. * @param parent apr_file_t value to use as parent_err. Must be a valid file. */ public static native int childErrSet(long attr, long err, long parent); /** * Set which directory the child process should start executing in. * @param attr The procattr we care about. * @param dir Which dir to start in. By default, this is the same dir as * the parent currently resides in, when the createprocess call * is made. */ public static native int dirSet(long attr, String dir); /** * Set what type of command the child process will call. * @param attr The procattr we care about. * @param cmd The type of command. One of: *
         * APR_SHELLCMD     --  Anything that the shell can handle
         * APR_PROGRAM      --  Executable program   (default)
         * APR_PROGRAM_ENV  --  Executable program, copy environment
         * APR_PROGRAM_PATH --  Executable program on PATH, copy env
         * 
    */ public static native int cmdtypeSet(long attr, int cmd); /** * Determine if the child should start in detached state. * @param attr The procattr we care about. * @param detach Should the child start in detached state? Default is no. */ public static native int detachSet(long attr, int detach); /** * Specify that apr_proc_create() should do whatever it can to report * failures to the caller of apr_proc_create(), rather than find out in * the child. * @param attr The procattr describing the child process to be created. * @param chk Flag to indicate whether or not extra work should be done * to try to report failures to the caller. *
    * This flag only affects apr_proc_create() on platforms where * fork() is used. This leads to extra overhead in the calling * process, but that may help the application handle such * errors more gracefully. */ public static native int errorCheckSet(long attr, int chk); /** * Determine if the child should start in its own address space or using the * current one from its parent * @param attr The procattr we care about. * @param addrspace Should the child start in its own address space? Default * is no on NetWare and yes on other platforms. */ public static native int addrspaceSet(long attr, int addrspace); /** * Specify an error function to be called in the child process if APR * encounters an error in the child prior to running the specified program. * @param attr The procattr describing the child process to be created. * @param pool The the pool to use. * @param o The Object to call in the child process. *
    * At the present time, it will only be called from apr_proc_create() * on platforms where fork() is used. It will never be called on other * platforms, on those platforms apr_proc_create() will return the error * in the parent process rather than invoke the callback in the now-forked * child process. */ public static native void errfnSet(long attr, long pool, Object o); /** * Set the username used for running process * @param attr The procattr we care about. * @param username The username used * @param password User password if needed. Password is needed on WIN32 * or any other platform having * APR_PROCATTR_USER_SET_REQUIRES_PASSWORD set. */ public static native int userSet(long attr, String username, String password); /** * Set the group used for running process * @param attr The procattr we care about. * @param groupname The group name used */ public static native int groupSet(long attr, String groupname); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Error.java0000644000175100017510000000543412271453221022104 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Error * * @author Mladen Turk */ public class Error extends Exception { private static final long serialVersionUID = 1L; /** * APR error type. */ private int error; /** * A description of the problem. */ private String description; /** * Construct an APRException. * * @param error one of the value in Error * @param description error message */ private Error(int error, String description) { super(error + ": " + description); this.error = error; this.description = description; } /** * Get the APR error code of the exception. * * @return error of the Exception */ public int getError() { return error; } /** * Get the APR description of the exception. * * @return description of the Exception */ public String getDescription() { return description; } /** * Get the last platform error. * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms * This retrieves errno, or calls a GetLastError() style function, and * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no * such mechanism, so this call may be unsupported. Do NOT use this * call for socket errors from socket, send, recv etc! */ public static native int osError(); /** * Get the last platform socket error. * @return the last socket error, folded into apr_status_t, on all platforms * This retrieves errno or calls a GetLastSocketError() style function, * and folds it with APR_FROM_OS_ERROR. */ public static native int netosError(); /** * Return a human readable string describing the specified error. * @param statcode The error code the get a string for. * @return The error string. */ public static native String strerror(int statcode); } tomcat7-7.0.52/java/org/apache/tomcat/jni/PoolCallback.java0000644000175100017510000000207212271453221023334 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** PoolCallback Interface * * @author Mladen Turk */ public interface PoolCallback { /** * Called when the pool is destroyed or cleared * @return Function must return APR_SUCCESS */ public int callback(); } tomcat7-7.0.52/java/org/apache/tomcat/jni/BIOCallback.java0000644000175100017510000000311212271453221023030 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Open SSL BIO Callback Interface * * @author Mladen Turk */ public interface BIOCallback { /** * Write data * @param buf containing the bytes to write. * @return Number of characters written. */ public int write(byte [] buf); /** * Read data * @param buf buffer to store the read bytes. * @return number of bytes read. */ public int read(byte [] buf); /** * Puts string * @param data String to write * @return Number of characters written */ public int puts(String data); /** * Read string up to the len or CLRLF * @param len Maximum number of characters to read * @return String with up to len bytes read */ public String gets(int len); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Pool.java0000644000175100017510000001350412271453221021721 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; import java.nio.ByteBuffer; /** Pool * * @author Mladen Turk */ public class Pool { /** * Create a new pool. * @param parent The parent pool. If this is 0, the new pool is a root * pool. If it is non-zero, the new pool will inherit all * of its parent pool's attributes, except the apr_pool_t will * be a sub-pool. * @return The pool we have just created. */ public static native long create(long parent); /** * Clear all memory in the pool and run all the cleanups. This also destroys all * subpools. * @param pool The pool to clear * This does not actually free the memory, it just allows the pool * to re-use this memory for the next allocation. */ public static native void clear(long pool); /** * Destroy the pool. This takes similar action as apr_pool_clear() and then * frees all the memory. * This will actually free the memory * @param pool The pool to destroy */ public static native void destroy(long pool); /** * Get the parent pool of the specified pool. * @param pool The pool for retrieving the parent pool. * @return The parent of the given pool. */ public static native long parentGet(long pool); /** * Determine if pool a is an ancestor of pool b * @param a The pool to search * @param b The pool to search for * @return True if a is an ancestor of b, NULL is considered an ancestor * of all pools. */ public static native boolean isAncestor(long a, long b); /* * Cleanup * * Cleanups are performed in the reverse order they were registered. That is: * Last In, First Out. A cleanup function can safely allocate memory from * the pool that is being cleaned up. It can also safely register additional * cleanups which will be run LIFO, directly after the current cleanup * terminates. Cleanups have to take caution in calling functions that * create subpools. Subpools, created during cleanup will NOT automatically * be cleaned up. In other words, cleanups are to clean up after themselves. */ /** * Register a function to be called when a pool is cleared or destroyed * @param pool The pool register the cleanup with * @param o The object to call when the pool is cleared * or destroyed * @return The cleanup handler. */ public static native long cleanupRegister(long pool, Object o); /** * Remove a previously registered cleanup function * @param pool The pool remove the cleanup from * @param data The cleanup handler to remove from cleanup */ public static native void cleanupKill(long pool, long data); /** * Register a process to be killed when a pool dies. * @param a The pool to use to define the processes lifetime * @param proc The process to register * @param how How to kill the process, one of: *
         * APR_KILL_NEVER         -- process is never sent any signals
         * APR_KILL_ALWAYS        -- process is sent SIGKILL on apr_pool_t cleanup
         * APR_KILL_AFTER_TIMEOUT -- SIGTERM, wait 3 seconds, SIGKILL
         * APR_JUST_WAIT          -- wait forever for the process to complete
         * APR_KILL_ONLY_ONCE     -- send SIGTERM and then wait
         * 
    */ public static native void noteSubprocess(long a, long proc, int how); /** * Allocate a block of memory from a pool * @param p The pool to allocate from * @param size The amount of memory to allocate * @return The ByteBuffer with allocated memory */ public static native ByteBuffer alloc(long p, int size); /** * Allocate a block of memory from a pool and set all of the memory to 0 * @param p The pool to allocate from * @param size The amount of memory to allocate * @return The ByteBuffer with allocated memory */ public static native ByteBuffer calloc(long p, int size); /* * User data management */ /** * Set the data associated with the current pool * @param data The user data associated with the pool. * @param key The key to use for association * @param pool The current pool *
    Warning : * The data to be attached to the pool should have a life span * at least as long as the pool it is being attached to. * Object attached to the pool will be globally referenced * until the pool is cleared or dataSet is called with the null data. * @return APR Status code. */ public static native int dataSet(long pool, String key, Object data); /** * Return the data associated with the current pool. * @param key The key for the data to retrieve * @param pool The current pool. */ public static native Object dataGet(long pool, String key); /** * Run all of the child_cleanups, so that any unnecessary files are * closed because we are about to exec a new program */ public static native void cleanupForExec(); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Registry.java0000644000175100017510000002051612271453221022621 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Windows Registy support * * @author Mladen Turk */ public class Registry { /* Registry Enums */ public static final int HKEY_CLASSES_ROOT = 1; public static final int HKEY_CURRENT_CONFIG = 2; public static final int HKEY_CURRENT_USER = 3; public static final int HKEY_LOCAL_MACHINE = 4; public static final int HKEY_USERS = 5; public static final int KEY_ALL_ACCESS = 0x0001; public static final int KEY_CREATE_LINK = 0x0002; public static final int KEY_CREATE_SUB_KEY = 0x0004; public static final int KEY_ENUMERATE_SUB_KEYS = 0x0008; public static final int KEY_EXECUTE = 0x0010; public static final int KEY_NOTIFY = 0x0020; public static final int KEY_QUERY_VALUE = 0x0040; public static final int KEY_READ = 0x0080; public static final int KEY_SET_VALUE = 0x0100; public static final int KEY_WOW64_64KEY = 0x0200; public static final int KEY_WOW64_32KEY = 0x0400; public static final int KEY_WRITE = 0x0800; public static final int REG_BINARY = 1; public static final int REG_DWORD = 2; public static final int REG_EXPAND_SZ = 3; public static final int REG_MULTI_SZ = 4; public static final int REG_QWORD = 5; public static final int REG_SZ = 6; /** * Create or open a Registry Key. * @param name Registry Subkey to open * @param root Root key, one of HKEY_* * @param sam Access mask that specifies the access rights for the key. * @param pool Pool used for native memory allocation * @return Opened Registry key */ public static native long create(int root, String name, int sam, long pool) throws Error; /** * Opens the specified Registry Key. * @param name Registry Subkey to open * @param root Root key, one of HKEY_* * @param sam Access mask that specifies the access rights for the key. * @param pool Pool used for native memory allocation * @return Opened Registry key */ public static native long open(int root, String name, int sam, long pool) throws Error; /** * Close the specified Registry key. * @param key The Registry key descriptor to close. */ public static native int close(long key); /** * Get the Registry key type. * @param key The Registry key descriptor to use. * @param name The name of the value to query * @return Value type or negative error value */ public static native int getType(long key, String name); /** * Get the Registry value for REG_DWORD * @param key The Registry key descriptor to use. * @param name The name of the value to query * @return Registry key value */ public static native int getValueI(long key, String name) throws Error; /** * Get the Registry value for REG_QWORD or REG_DWORD * @param key The Registry key descriptor to use. * @param name The name of the value to query * @return Registry key value */ public static native long getValueJ(long key, String name) throws Error; /** * Get the Registry key length. * @param key The Registry key descriptor to use. * @param name The name of the value to query * @return Value size or negative error value */ public static native int getSize(long key, String name); /** * Get the Registry value for REG_SZ or REG_EXPAND_SZ * @param key The Registry key descriptor to use. * @param name The name of the value to query * @return Registry key value */ public static native String getValueS(long key, String name) throws Error; /** * Get the Registry value for REG_MULTI_SZ * @param key The Registry key descriptor to use. * @param name The name of the value to query * @return Registry key value */ public static native String[] getValueA(long key, String name) throws Error; /** * Get the Registry value for REG_BINARY * @param key The Registry key descriptor to use. * @param name The name of the value to query * @return Registry key value */ public static native byte[] getValueB(long key, String name) throws Error; /** * Set the Registry value for REG_DWORD * @param key The Registry key descriptor to use. * @param name The name of the value to set * @param val The the value to set * @return If the function succeeds, the return value is 0 */ public static native int setValueI(long key, String name, int val); /** * Set the Registry value for REG_QWORD * @param key The Registry key descriptor to use. * @param name The name of the value to set * @param val The the value to set * @return If the function succeeds, the return value is 0 */ public static native int setValueJ(long key, String name, long val); /** * Set the Registry value for REG_SZ * @param key The Registry key descriptor to use. * @param name The name of the value to set * @param val The the value to set * @return If the function succeeds, the return value is 0 */ public static native int setValueS(long key, String name, String val); /** * Set the Registry value for REG_EXPAND_SZ * @param key The Registry key descriptor to use. * @param name The name of the value to set * @param val The the value to set * @return If the function succeeds, the return value is 0 */ public static native int setValueE(long key, String name, String val); /** * Set the Registry value for REG_MULTI_SZ * @param key The Registry key descriptor to use. * @param name The name of the value to set * @param val The the value to set * @return If the function succeeds, the return value is 0 */ public static native int setValueA(long key, String name, String[] val); /** * Set the Registry value for REG_BINARY * @param key The Registry key descriptor to use. * @param name The name of the value to set * @param val The the value to set * @return If the function succeeds, the return value is 0 */ public static native int setValueB(long key, String name, byte[] val); /** * Enumerate the Registry subkeys * @param key The Registry key descriptor to use. * @return Array of all subkey names */ public static native String[] enumKeys(long key) throws Error; /** * Enumerate the Registry values * @param key The Registry key descriptor to use. * @return Array of all value names */ public static native String[] enumValues(long key) throws Error; /** * Delete the Registry value * @param key The Registry key descriptor to use. * @param name The name of the value to delete * @return If the function succeeds, the return value is 0 */ public static native int deleteValue(long key, String name); /** * Delete the Registry subkey * @param root Root key, one of HKEY_* * @param name Subkey to delete * @param onlyIfEmpty If true will not delete a key if * it contains any subkeys or values * @return If the function succeeds, the return value is 0 */ public static native int deleteKey(int root, String name, boolean onlyIfEmpty); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Status.java0000644000175100017510000003570712271453221022304 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Status * * @author Mladen Turk */ public class Status { /** * APR_OS_START_ERROR is where the APR specific error values start. */ public static final int APR_OS_START_ERROR = 20000; /** * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit * into one of the error/status ranges below -- except for * APR_OS_START_USERERR, which see. */ public static final int APR_OS_ERRSPACE_SIZE = 50000; /** * APR_OS_START_STATUS is where the APR specific status codes start. */ public static final int APR_OS_START_STATUS = (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE); /** * APR_OS_START_USERERR are reserved for applications that use APR that * layer their own error codes along with APR's. Note that the * error immediately following this one is set ten times farther * away than usual, so that users of apr have a lot of room in * which to declare custom error codes. */ public static final int APR_OS_START_USERERR = (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE); /** * APR_OS_START_USEERR is obsolete, defined for compatibility only. * Use APR_OS_START_USERERR instead. */ public static final int APR_OS_START_USEERR = APR_OS_START_USERERR; /** * APR_OS_START_CANONERR is where APR versions of errno values are defined * on systems which don't have the corresponding errno. */ public static final int APR_OS_START_CANONERR = (APR_OS_START_USERERR + (APR_OS_ERRSPACE_SIZE * 10)); /** * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into * apr_status_t values. */ public static final int APR_OS_START_EAIERR = (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE); /** * APR_OS_START_SYSERR folds platform-specific system error values into * apr_status_t values. */ public static final int APR_OS_START_SYSERR = (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE); /** no error. */ public static final int APR_SUCCESS = 0; /** * APR Error Values *
         * APR ERROR VALUES
         * APR_ENOSTAT      APR was unable to perform a stat on the file
         * APR_ENOPOOL      APR was not provided a pool with which to allocate memory
         * APR_EBADDATE     APR was given an invalid date
         * APR_EINVALSOCK   APR was given an invalid socket
         * APR_ENOPROC      APR was not given a process structure
         * APR_ENOTIME      APR was not given a time structure
         * APR_ENODIR       APR was not given a directory structure
         * APR_ENOLOCK      APR was not given a lock structure
         * APR_ENOPOLL      APR was not given a poll structure
         * APR_ENOSOCKET    APR was not given a socket
         * APR_ENOTHREAD    APR was not given a thread structure
         * APR_ENOTHDKEY    APR was not given a thread key structure
         * APR_ENOSHMAVAIL  There is no more shared memory available
         * APR_EDSOOPEN     APR was unable to open the dso object.  For more
         *                  information call apr_dso_error().
         * APR_EGENERAL     General failure (specific information not available)
         * APR_EBADIP       The specified IP address is invalid
         * APR_EBADMASK     The specified netmask is invalid
         * APR_ESYMNOTFOUND Could not find the requested symbol
         * 
    * */ public static final int APR_ENOSTAT = (APR_OS_START_ERROR + 1); public static final int APR_ENOPOOL = (APR_OS_START_ERROR + 2); public static final int APR_EBADDATE = (APR_OS_START_ERROR + 4); public static final int APR_EINVALSOCK = (APR_OS_START_ERROR + 5); public static final int APR_ENOPROC = (APR_OS_START_ERROR + 6); public static final int APR_ENOTIME = (APR_OS_START_ERROR + 7); public static final int APR_ENODIR = (APR_OS_START_ERROR + 8); public static final int APR_ENOLOCK = (APR_OS_START_ERROR + 9); public static final int APR_ENOPOLL = (APR_OS_START_ERROR + 10); public static final int APR_ENOSOCKET = (APR_OS_START_ERROR + 11); public static final int APR_ENOTHREAD = (APR_OS_START_ERROR + 12); public static final int APR_ENOTHDKEY = (APR_OS_START_ERROR + 13); public static final int APR_EGENERAL = (APR_OS_START_ERROR + 14); public static final int APR_ENOSHMAVAIL = (APR_OS_START_ERROR + 15); public static final int APR_EBADIP = (APR_OS_START_ERROR + 16); public static final int APR_EBADMASK = (APR_OS_START_ERROR + 17); public static final int APR_EDSOOPEN = (APR_OS_START_ERROR + 19); public static final int APR_EABSOLUTE = (APR_OS_START_ERROR + 20); public static final int APR_ERELATIVE = (APR_OS_START_ERROR + 21); public static final int APR_EINCOMPLETE = (APR_OS_START_ERROR + 22); public static final int APR_EABOVEROOT = (APR_OS_START_ERROR + 23); public static final int APR_EBADPATH = (APR_OS_START_ERROR + 24); public static final int APR_EPATHWILD = (APR_OS_START_ERROR + 25); public static final int APR_ESYMNOTFOUND = (APR_OS_START_ERROR + 26); public static final int APR_EPROC_UNKNOWN = (APR_OS_START_ERROR + 27); public static final int APR_ENOTENOUGHENTROPY = (APR_OS_START_ERROR + 28); /** APR Status Values *
         * APR STATUS VALUES
         * APR_INCHILD        Program is currently executing in the child
         * APR_INPARENT       Program is currently executing in the parent
         * APR_DETACH         The thread is detached
         * APR_NOTDETACH      The thread is not detached
         * APR_CHILD_DONE     The child has finished executing
         * APR_CHILD_NOTDONE  The child has not finished executing
         * APR_TIMEUP         The operation did not finish before the timeout
         * APR_INCOMPLETE     The operation was incomplete although some processing
         *                    was performed and the results are partially valid
         * APR_BADCH          Getopt found an option not in the option string
         * APR_BADARG         Getopt found an option that is missing an argument
         *                    and an argument was specified in the option string
         * APR_EOF            APR has encountered the end of the file
         * APR_NOTFOUND       APR was unable to find the socket in the poll structure
         * APR_ANONYMOUS      APR is using anonymous shared memory
         * APR_FILEBASED      APR is using a file name as the key to the shared memory
         * APR_KEYBASED       APR is using a shared key as the key to the shared memory
         * APR_EINIT          Ininitalizer value.  If no option has been found, but
         *                    the status variable requires a value, this should be used
         * APR_ENOTIMPL       The APR function has not been implemented on this
         *                    platform, either because nobody has gotten to it yet,
         *                    or the function is impossible on this platform.
         * APR_EMISMATCH      Two passwords do not match.
         * APR_EBUSY          The given lock was busy.
         * 
    * */ public static final int APR_INCHILD = (APR_OS_START_STATUS + 1); public static final int APR_INPARENT = (APR_OS_START_STATUS + 2); public static final int APR_DETACH = (APR_OS_START_STATUS + 3); public static final int APR_NOTDETACH = (APR_OS_START_STATUS + 4); public static final int APR_CHILD_DONE = (APR_OS_START_STATUS + 5); public static final int APR_CHILD_NOTDONE = (APR_OS_START_STATUS + 6); public static final int APR_TIMEUP = (APR_OS_START_STATUS + 7); public static final int APR_INCOMPLETE = (APR_OS_START_STATUS + 8); public static final int APR_BADCH = (APR_OS_START_STATUS + 12); public static final int APR_BADARG = (APR_OS_START_STATUS + 13); public static final int APR_EOF = (APR_OS_START_STATUS + 14); public static final int APR_NOTFOUND = (APR_OS_START_STATUS + 15); public static final int APR_ANONYMOUS = (APR_OS_START_STATUS + 19); public static final int APR_FILEBASED = (APR_OS_START_STATUS + 20); public static final int APR_KEYBASED = (APR_OS_START_STATUS + 21); public static final int APR_EINIT = (APR_OS_START_STATUS + 22); public static final int APR_ENOTIMPL = (APR_OS_START_STATUS + 23); public static final int APR_EMISMATCH = (APR_OS_START_STATUS + 24); public static final int APR_EBUSY = (APR_OS_START_STATUS + 25); public static final int TIMEUP = (APR_OS_START_USERERR + 1); public static final int EAGAIN = (APR_OS_START_USERERR + 2); public static final int EINTR = (APR_OS_START_USERERR + 3); public static final int EINPROGRESS = (APR_OS_START_USERERR + 4); public static final int ETIMEDOUT = (APR_OS_START_USERERR + 5); private static native boolean is(int err, int idx); /** * APR_STATUS_IS Status Value Tests *
    Warning : For any particular error condition, more than one of these tests * may match. This is because platform-specific error codes may not * always match the semantics of the POSIX codes these tests (and the * corresponding APR error codes) are named after. A notable example * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on * Win32 platforms. The programmer should always be aware of this and * adjust the order of the tests accordingly. * */ public static final boolean APR_STATUS_IS_ENOSTAT(int s) { return is(s, 1); } public static final boolean APR_STATUS_IS_ENOPOOL(int s) { return is(s, 2); } /* empty slot: +3 */ public static final boolean APR_STATUS_IS_EBADDATE(int s) { return is(s, 4); } public static final boolean APR_STATUS_IS_EINVALSOCK(int s) { return is(s, 5); } public static final boolean APR_STATUS_IS_ENOPROC(int s) { return is(s, 6); } public static final boolean APR_STATUS_IS_ENOTIME(int s) { return is(s, 7); } public static final boolean APR_STATUS_IS_ENODIR(int s) { return is(s, 8); } public static final boolean APR_STATUS_IS_ENOLOCK(int s) { return is(s, 9); } public static final boolean APR_STATUS_IS_ENOPOLL(int s) { return is(s, 10); } public static final boolean APR_STATUS_IS_ENOSOCKET(int s) { return is(s, 11); } public static final boolean APR_STATUS_IS_ENOTHREAD(int s) { return is(s, 12); } public static final boolean APR_STATUS_IS_ENOTHDKEY(int s) { return is(s, 13); } public static final boolean APR_STATUS_IS_EGENERAL(int s) { return is(s, 14); } public static final boolean APR_STATUS_IS_ENOSHMAVAIL(int s){ return is(s, 15); } public static final boolean APR_STATUS_IS_EBADIP(int s) { return is(s, 16); } public static final boolean APR_STATUS_IS_EBADMASK(int s) { return is(s, 17); } /* empty slot: +18 */ public static final boolean APR_STATUS_IS_EDSOPEN(int s) { return is(s, 19); } public static final boolean APR_STATUS_IS_EABSOLUTE(int s) { return is(s, 20); } public static final boolean APR_STATUS_IS_ERELATIVE(int s) { return is(s, 21); } public static final boolean APR_STATUS_IS_EINCOMPLETE(int s){ return is(s, 22); } public static final boolean APR_STATUS_IS_EABOVEROOT(int s) { return is(s, 23); } public static final boolean APR_STATUS_IS_EBADPATH(int s) { return is(s, 24); } public static final boolean APR_STATUS_IS_EPATHWILD(int s) { return is(s, 25); } public static final boolean APR_STATUS_IS_ESYMNOTFOUND(int s) { return is(s, 26); } public static final boolean APR_STATUS_IS_EPROC_UNKNOWN(int s) { return is(s, 27); } public static final boolean APR_STATUS_IS_ENOTENOUGHENTROPY(int s) { return is(s, 28); } /* * APR_Error */ public static final boolean APR_STATUS_IS_INCHILD(int s) { return is(s, 51); } public static final boolean APR_STATUS_IS_INPARENT(int s) { return is(s, 52); } public static final boolean APR_STATUS_IS_DETACH(int s) { return is(s, 53); } public static final boolean APR_STATUS_IS_NOTDETACH(int s) { return is(s, 54); } public static final boolean APR_STATUS_IS_CHILD_DONE(int s) { return is(s, 55); } public static final boolean APR_STATUS_IS_CHILD_NOTDONE(int s) { return is(s, 56); } public static final boolean APR_STATUS_IS_TIMEUP(int s) { return is(s, 57); } public static final boolean APR_STATUS_IS_INCOMPLETE(int s) { return is(s, 58); } /* empty slot: +9 */ /* empty slot: +10 */ /* empty slot: +11 */ public static final boolean APR_STATUS_IS_BADCH(int s) { return is(s, 62); } public static final boolean APR_STATUS_IS_BADARG(int s) { return is(s, 63); } public static final boolean APR_STATUS_IS_EOF(int s) { return is(s, 64); } public static final boolean APR_STATUS_IS_NOTFOUND(int s) { return is(s, 65); } /* empty slot: +16 */ /* empty slot: +17 */ /* empty slot: +18 */ public static final boolean APR_STATUS_IS_ANONYMOUS(int s) { return is(s, 69); } public static final boolean APR_STATUS_IS_FILEBASED(int s) { return is(s, 70); } public static final boolean APR_STATUS_IS_KEYBASED(int s) { return is(s, 71); } public static final boolean APR_STATUS_IS_EINIT(int s) { return is(s, 72); } public static final boolean APR_STATUS_IS_ENOTIMPL(int s) { return is(s, 73); } public static final boolean APR_STATUS_IS_EMISMATCH(int s) { return is(s, 74); } public static final boolean APR_STATUS_IS_EBUSY(int s) { return is(s, 75); } /* Socket errors */ public static final boolean APR_STATUS_IS_EAGAIN(int s) { return is(s, 90); } public static final boolean APR_STATUS_IS_ETIMEDOUT(int s) { return is(s, 91); } public static final boolean APR_STATUS_IS_ECONNABORTED(int s) { return is(s, 92); } public static final boolean APR_STATUS_IS_ECONNRESET(int s) { return is(s, 93); } public static final boolean APR_STATUS_IS_EINPROGRESS(int s) { return is(s, 94); } public static final boolean APR_STATUS_IS_EINTR(int s) { return is(s, 95); } public static final boolean APR_STATUS_IS_ENOTSOCK(int s) { return is(s, 96); } public static final boolean APR_STATUS_IS_EINVAL(int s) { return is(s, 97); } } tomcat7-7.0.52/java/org/apache/tomcat/jni/PasswordCallback.java0000644000175100017510000000214512271453221024226 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** PasswordCallback Interface * * @author Mladen Turk */ public interface PasswordCallback { /** * Called when the password is required * @param prompt Password prompt * @return Valid password or null */ public String callback(String prompt); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Address.java0000644000175100017510000001065012271453221022374 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Address * * @author Mladen Turk */ public class Address { public static final String APR_ANYADDR = "0.0.0.0"; /** * Fill the Sockaddr class from apr_sockaddr_t * @param info Sockaddr class to fill * @param sa Structure pointer */ public static native boolean fill(Sockaddr info, long sa); /** * Create the Sockaddr object from apr_sockaddr_t * @param sa Structure pointer */ public static native Sockaddr getInfo(long sa); /** * Create apr_sockaddr_t from hostname, address family, and port. * @param hostname The hostname or numeric address string to resolve/parse, or * NULL to build an address that corresponds to 0.0.0.0 or :: * @param family The address family to use, or APR_UNSPEC if the system should * decide. * @param port The port number. * @param flags Special processing flags: *
         *       APR_IPV4_ADDR_OK          first query for IPv4 addresses; only look
         *                                 for IPv6 addresses if the first query failed;
         *                                 only valid if family is APR_UNSPEC and hostname
         *                                 isn't NULL; mutually exclusive with
         *                                 APR_IPV6_ADDR_OK
         *       APR_IPV6_ADDR_OK          first query for IPv6 addresses; only look
         *                                 for IPv4 addresses if the first query failed;
         *                                 only valid if family is APR_UNSPEC and hostname
         *                                 isn't NULL and APR_HAVE_IPV6; mutually exclusive
         *                                 with APR_IPV4_ADDR_OK
         * 
    * @param p The pool for the apr_sockaddr_t and associated storage. * @return The new apr_sockaddr_t. */ public static native long info(String hostname, int family, int port, int flags, long p) throws Exception; /** * Look up the host name from an apr_sockaddr_t. * @param sa The apr_sockaddr_t. * @param flags Special processing flags. * @return The hostname. */ public static native String getnameinfo(long sa, int flags); /** * Return the IP address (in numeric address string format) in * an APR socket address. APR will allocate storage for the IP address * string from the pool of the apr_sockaddr_t. * @param sa The socket address to reference. * @return The IP address. */ public static native String getip(long sa); /** * Given an apr_sockaddr_t and a service name, set the port for the service * @param sockaddr The apr_sockaddr_t that will have its port set * @param servname The name of the service you wish to use * @return APR status code. */ public static native int getservbyname(long sockaddr, String servname); /** * Return an apr_sockaddr_t from an apr_socket_t * @param which Which interface do we want the apr_sockaddr_t for? * @param sock The socket to use * @return The returned apr_sockaddr_t. */ public static native long get(int which, long sock) throws Exception; /** * See if the IP addresses in two APR socket addresses are * equivalent. Appropriate logic is present for comparing * IPv4-mapped IPv6 addresses with IPv4 addresses. * * @param a One of the APR socket addresses. * @param b The other APR socket address. * The return value will be True if the addresses * are equivalent. */ public static native boolean equal(long a, long b); } tomcat7-7.0.52/java/org/apache/tomcat/jni/FileInfo.java0000644000175100017510000000471012271453221022502 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Fileinfo * * @author Mladen Turk */ public class FileInfo { /** Allocates memory and closes lingering handles in the specified pool */ public long pool; /** The bitmask describing valid fields of this apr_finfo_t structure * including all available 'wanted' fields and potentially more */ public int valid; /** The access permissions of the file. Mimics Unix access rights. */ public int protection; /** The type of file. One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, * APR_LNK or APR_SOCK. If the type is undetermined, the value is APR_NOFILE. * If the type cannot be determined, the value is APR_UNKFILE. */ public int filetype; /** The user id that owns the file */ public int user; /** The group id that owns the file */ public int group; /** The inode of the file. */ public int inode; /** The id of the device the file is on. */ public int device; /** The number of hard links to the file. */ public int nlink; /** The size of the file */ public long size; /** The storage size consumed by the file */ public long csize; /** The time the file was last accessed */ public long atime; /** The time the file was last modified */ public long mtime; /** The time the file was created, or the inode was last changed */ public long ctime; /** The pathname of the file (possibly unrooted) */ public String fname; /** The file's name (no path) in filesystem case */ public String name; /** The file's handle, if accessed (can be submitted to apr_duphandle) */ public long filehand; } tomcat7-7.0.52/java/org/apache/tomcat/jni/Proc.java0000644000175100017510000002156312271453221021717 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Proc * * @author Mladen Turk */ public class Proc { /* * apr_cmdtype_e enum */ public static final int APR_SHELLCM = 0; /** use the shell to invoke the program */ public static final int APR_PROGRAM = 1; /** invoke the program directly, no copied env */ public static final int APR_PROGRAM_ENV = 2; /** invoke the program, replicating our environment */ public static final int APR_PROGRAM_PATH = 3; /** find program on PATH, use our environment */ public static final int APR_SHELLCMD_ENV = 4; /** use the shell to invoke the program, * replicating our environment */ /* * apr_wait_how_e enum */ public static final int APR_WAIT = 0; /** wait for the specified process to finish */ public static final int APR_NOWAIT = 1; /** do not wait -- just see if it has finished */ /* * apr_exit_why_e enum */ public static final int APR_PROC_EXIT = 1; /** process exited normally */ public static final int APR_PROC_SIGNAL = 2; /** process exited due to a signal */ public static final int APR_PROC_SIGNAL_CORE = 4; /** process exited and dumped a core file */ public static final int APR_NO_PIPE = 0; public static final int APR_FULL_BLOCK = 1; public static final int APR_FULL_NONBLOCK = 2; public static final int APR_PARENT_BLOCK = 3; public static final int APR_CHILD_BLOCK = 4; public static final int APR_LIMIT_CPU = 0; public static final int APR_LIMIT_MEM = 1; public static final int APR_LIMIT_NPROC = 2; public static final int APR_LIMIT_NOFILE = 3; /** child has died, caller must call unregister still */ public static final int APR_OC_REASON_DEATH = 0; /** write_fd is unwritable */ public static final int APR_OC_REASON_UNWRITABLE = 1; /** a restart is occurring, perform any necessary cleanup (including * sending a special signal to child) */ public static final int APR_OC_REASON_RESTART = 2; /** unregister has been called, do whatever is necessary (including * kill the child) */ public static final int APR_OC_REASON_UNREGISTER = 3; /** somehow the child exited without us knowing ... buggy os? */ public static final int APR_OC_REASON_LOST = 4; /** a health check is occurring, for most maintenance functions * this is a no-op. */ public static final int APR_OC_REASON_RUNNING = 5; /* apr_kill_conditions_e enumeration */ /** process is never sent any signals */ public static final int APR_KILL_NEVER = 0; /** process is sent SIGKILL on apr_pool_t cleanup */ public static final int APR_KILL_ALWAYS = 1; /** SIGTERM, wait 3 seconds, SIGKILL */ public static final int APR_KILL_AFTER_TIMEOUT = 2; /** wait forever for the process to complete */ public static final int APR_JUST_WAIT = 3; /** send SIGTERM and then wait */ public static final int APR_KILL_ONLY_ONCE = 4; public static final int APR_PROC_DETACH_FOREGROUND = 0; /** Do not detach */ public static final int APR_PROC_DETACH_DAEMONIZE = 1; /** Detach */ /* Maximum number of arguments for create process call */ public static final int MAX_ARGS_SIZE = 1024; /* Maximum number of environment variables for create process call */ public static final int MAX_ENV_SIZE = 1024; /** * Allocate apr_proc_t structure from pool * This is not an apr function. * @param cont The pool to use. */ public static native long alloc(long cont); /** * This is currently the only non-portable call in APR. This executes * a standard unix fork. * @param proc The resulting process handle. * @param cont The pool to use. * @return APR_INCHILD for the child, and APR_INPARENT for the parent * or an error. */ public static native int fork(long [] proc, long cont); /** * Create a new process and execute a new program within that process. * This function returns without waiting for the new process to terminate; * use apr_proc_wait for that. * @param progname The program to run * @param args The arguments to pass to the new program. The first * one should be the program name. * @param env The new environment table for the new process. This * should be a list of NULL-terminated strings. This argument * is ignored for APR_PROGRAM_ENV, APR_PROGRAM_PATH, and * APR_SHELLCMD_ENV types of commands. * @param attr The procattr we should use to determine how to create the new * process * @param pool The pool to use. * @return The resulting process handle. */ public static native int create(long proc, String progname, String [] args, String [] env, long attr, long pool); /** * Wait for a child process to die * @param proc The process handle that corresponds to the desired child process * @param exit exit[0] The returned exit status of the child, if a child process * dies, or the signal that caused the child to die. * On platforms that don't support obtaining this information, * the status parameter will be returned as APR_ENOTIMPL. * exit[1] Why the child died, the bitwise or of: *
         * APR_PROC_EXIT         -- process terminated normally
         * APR_PROC_SIGNAL       -- process was killed by a signal
         * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
         *                          generated a core dump.
         * 
    * @param waithow How should we wait. One of: *
         * APR_WAIT   -- block until the child process dies.
         * APR_NOWAIT -- return immediately regardless of if the
         *               child is dead or not.
         * 
    * @return The childs status is in the return code to this process. It is one of: *
         * APR_CHILD_DONE     -- child is no longer running.
         * APR_CHILD_NOTDONE  -- child is still running.
         * 
    */ public static native int wait(long proc, int [] exit, int waithow); /** * Wait for any current child process to die and return information * about that child. * @param proc Pointer to NULL on entry, will be filled out with child's * information * @param exit exit[0] The returned exit status of the child, if a child process * dies, or the signal that caused the child to die. * On platforms that don't support obtaining this information, * the status parameter will be returned as APR_ENOTIMPL. * exit[1] Why the child died, the bitwise or of: *
         * APR_PROC_EXIT         -- process terminated normally
         * APR_PROC_SIGNAL       -- process was killed by a signal
         * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
         *                          generated a core dump.
         * 
    * @param waithow How should we wait. One of: *
         * APR_WAIT   -- block until the child process dies.
         * APR_NOWAIT -- return immediately regardless of if the
         *               child is dead or not.
         * 
    * @param pool Pool to allocate child information out of. */ public static native int waitAllProcs(long proc, int [] exit, int waithow, long pool); /** * Detach the process from the controlling terminal. * @param daemonize set to non-zero if the process should daemonize * and become a background process, else it will * stay in the foreground. */ public static native int detach(int daemonize); /** * Terminate a process. * @param proc The process to terminate. * @param sig How to kill the process. */ public static native int kill(long proc, int sig); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Directory.java0000644000175100017510000000675412271453221022765 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Directory * * @author Mladen Turk */ public class Directory { /** * Create a new directory on the file system. * @param path the path for the directory to be created. (use / on all systems) * @param perm Permissions for the new directory. * @param pool the pool to use. */ public static native int make(String path, int perm, long pool); /** Creates a new directory on the file system, but behaves like * 'mkdir -p'. Creates intermediate directories as required. No error * will be reported if PATH already exists. * @param path the path for the directory to be created. (use / on all systems) * @param perm Permissions for the new directory. * @param pool the pool to use. */ public static native int makeRecursive(String path, int perm, long pool); /** * Remove directory from the file system. * @param path the path for the directory to be removed. (use / on all systems) * @param pool the pool to use. */ public static native int remove(String path, long pool); /** * Find an existing directory suitable as a temporary storage location. * @param pool The pool to use for any necessary allocations. * @return The temp directory. * * This function uses an algorithm to search for a directory that an * an application can use for temporary storage. Once such a * directory is found, that location is cached by the library. Thus, * callers only pay the cost of this algorithm once if that one time * is successful. * */ public static native String tempGet(long pool); /** * Open the specified directory. * @param dirname The full path to the directory (use / on all systems) * @param pool The pool to use. * @return The opened directory descriptor. */ public static native long open(String dirname, long pool) throws Error; /** * close the specified directory. * @param thedir the directory descriptor to close. */ public static native int close(long thedir); /** * Rewind the directory to the first entry. * @param thedir the directory descriptor to rewind. */ public static native int rewind(long thedir); /** * Read the next entry from the specified directory. * @param finfo the file info structure and filled in by apr_dir_read * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values * @param thedir the directory descriptor returned from apr_dir_open * No ordering is guaranteed for the entries read. */ public static native int read(FileInfo finfo, int wanted, long thedir); } tomcat7-7.0.52/java/org/apache/tomcat/jni/SSLContext.java0000644000175100017510000003107512271453221023021 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** SSL Context * * @author Mladen Turk */ public final class SSLContext { /** * Initialize new SSL context * @param pool The pool to use. * @param protocol The SSL protocol to use. It can be one of: *
         * SSL_PROTOCOL_SSLV2
         * SSL_PROTOCOL_SSLV3
         * SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_SSLV3
         * SSL_PROTOCOL_TLSV1
         * SSL_PROTOCOL_ALL
         * 
    * @param mode SSL mode to use *
         * SSL_MODE_CLIENT
         * SSL_MODE_SERVER
         * SSL_MODE_COMBINED
         * 
    */ public static native long make(long pool, int protocol, int mode) throws Exception; /** * Free the resources used by the Context * @param ctx Server or Client context to free. * @return APR Status code. */ public static native int free(long ctx); /** * Set Session context id. Usually host:port combination. * @param ctx Context to use. * @param id String that uniquely identifies this context. */ public static native void setContextId(long ctx, String id); /** * Associate BIOCallback for input or output data capture. *
    * First word in the output string will contain error * level in the form: *
         * [ERROR]  -- Critical error messages
         * [WARN]   -- Warning messages
         * [INFO]   -- Informational messages
         * [DEBUG]  -- Debugging messaged
         * 
    * Callback can use that word to determine application logging level * by intercepting write call. * If the bio is set to 0 no error messages will be displayed. * Default is to use the stderr output stream. * @param ctx Server or Client context to use. * @param bio BIO handle to use, created with SSL.newBIO * @param dir BIO direction (1 for input 0 for output). */ public static native void setBIO(long ctx, long bio, int dir); /** * Set OpenSSL Option. * @param ctx Server or Client context to use. * @param options See SSL.SSL_OP_* for option flags. */ public static native void setOptions(long ctx, int options); /** * Sets the "quiet shutdown" flag for ctx to be * mode. SSL objects created from ctx inherit the * mode valid at the time and may be 0 or 1. *
    * Normally when a SSL connection is finished, the parties must send out * "close notify" alert messages using L * for a clean shutdown. *
    * When setting the "quiet shutdown" flag to 1, SSL.shutdown * will set the internal flags to SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN. * (SSL_shutdown then behaves like called with * SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN.) * The session is thus considered to be shutdown, but no "close notify" alert * is sent to the peer. This behaviour violates the TLS standard. * The default is normal shutdown behaviour as described by the TLS standard. * @param ctx Server or Client context to use. * @param mode True to set the quiet shutdown. */ public static native void setQuietShutdown(long ctx, boolean mode); /** * Cipher Suite available for negotiation in SSL handshake. *
    * This complex directive uses a colon-separated cipher-spec string consisting * of OpenSSL cipher specifications to configure the Cipher Suite the client * is permitted to negotiate in the SSL handshake phase. Notice that this * directive can be used both in per-server and per-directory context. * In per-server context it applies to the standard SSL handshake when a * connection is established. In per-directory context it forces a SSL * renegotiation with the reconfigured Cipher Suite after the HTTP request * was read but before the HTTP response is sent. * @param ctx Server or Client context to use. * @param ciphers An SSL cipher specification. */ public static native boolean setCipherSuite(long ctx, String ciphers) throws Exception; /** * Set File of concatenated PEM-encoded CA CRLs or * directory of PEM-encoded CA Certificates for Client Auth *
    * This directive sets the all-in-one file where you can assemble the * Certificate Revocation Lists (CRL) of Certification Authorities (CA) * whose clients you deal with. These are used for Client Authentication. * Such a file is simply the concatenation of the various PEM-encoded CRL * files, in order of preference. *
    * The files in this directory have to be PEM-encoded and are accessed through * hash filenames. So usually you can't just place the Certificate files there: * you also have to create symbolic links named hash-value.N. And you should * always make sure this directory contains the appropriate symbolic links. * Use the Makefile which comes with mod_ssl to accomplish this task. * @param ctx Server or Client context to use. * @param file File of concatenated PEM-encoded CA CRLs for Client Auth. * @param path Directory of PEM-encoded CA Certificates for Client Auth. */ public static native boolean setCARevocation(long ctx, String file, String path) throws Exception; /** * Set File of PEM-encoded Server CA Certificates *
    * This directive sets the optional all-in-one file where you can assemble the * certificates of Certification Authorities (CA) which form the certificate * chain of the server certificate. This starts with the issuing CA certificate * of of the server certificate and can range up to the root CA certificate. * Such a file is simply the concatenation of the various PEM-encoded CA * Certificate files, usually in certificate chain order. *
    * But be careful: Providing the certificate chain works only if you are using * a single (either RSA or DSA) based server certificate. If you are using a * coupled RSA+DSA certificate pair, this will work only if actually both * certificates use the same certificate chain. Else the browsers will be * confused in this situation. * @param ctx Server or Client context to use. * @param file File of PEM-encoded Server CA Certificates. * @param skipfirst Skip first certificate if chain file is inside * certificate file. */ public static native boolean setCertificateChainFile(long ctx, String file, boolean skipfirst); /** * Set Certificate *
    * Point setCertificateFile at a PEM encoded certificate. If * the certificate is encrypted, then you will be prompted for a * pass phrase. Note that a kill -HUP will prompt again. A test * certificate can be generated with `make certificate' under * built time. Keep in mind that if you've both a RSA and a DSA * certificate you can configure both in parallel (to also allow * the use of DSA ciphers, etc.) *
    * If the key is not combined with the certificate, use key param * to point at the key file. Keep in mind that if * you've both a RSA and a DSA private key you can configure * both in parallel (to also allow the use of DSA ciphers, etc.) * @param ctx Server or Client context to use. * @param cert Certificate file. * @param key Private Key file to use if not in cert. * @param password Certificate password. If null and certificate * is encrypted, password prompt will be displayed. * @param idx Certificate index SSL_AIDX_RSA or SSL_AIDX_DSA. */ public static native boolean setCertificate(long ctx, String cert, String key, String password, int idx) throws Exception; /** * Set File and Directory of concatenated PEM-encoded CA Certificates * for Client Auth *
    * This directive sets the all-in-one file where you can assemble the * Certificates of Certification Authorities (CA) whose clients you deal with. * These are used for Client Authentication. Such a file is simply the * concatenation of the various PEM-encoded Certificate files, in order of * preference. This can be used alternatively and/or additionally to * path. *
    * The files in this directory have to be PEM-encoded and are accessed through * hash filenames. So usually you can't just place the Certificate files there: * you also have to create symbolic links named hash-value.N. And you should * always make sure this directory contains the appropriate symbolic links. * Use the Makefile which comes with mod_ssl to accomplish this task. * @param ctx Server or Client context to use. * @param file File of concatenated PEM-encoded CA Certificates for * Client Auth. * @param path Directory of PEM-encoded CA Certificates for Client Auth. */ public static native boolean setCACertificate(long ctx, String file, String path) throws Exception; /** * Set file for randomness * @param ctx Server or Client context to use. * @param file random file. */ public static native void setRandom(long ctx, String file); /** * Set SSL connection shutdown type *
    * The following levels are available for level: *
         * SSL_SHUTDOWN_TYPE_STANDARD
         * SSL_SHUTDOWN_TYPE_UNCLEAN
         * SSL_SHUTDOWN_TYPE_ACCURATE
         * 
    * @param ctx Server or Client context to use. * @param type Shutdown type to use. */ public static native void setShutdownType(long ctx, int type); /** * Set Type of Client Certificate verification and Maximum depth of CA Certificates * in Client Certificate verification. *
    * This directive sets the Certificate verification level for the Client * Authentication. Notice that this directive can be used both in per-server * and per-directory context. In per-server context it applies to the client * authentication process used in the standard SSL handshake when a connection * is established. In per-directory context it forces a SSL renegotiation with * the reconfigured client verification level after the HTTP request was read * but before the HTTP response is sent. *
    * The following levels are available for level: *
         * SSL_CVERIFY_NONE           - No client Certificate is required at all
         * SSL_CVERIFY_OPTIONAL       - The client may present a valid Certificate
         * SSL_CVERIFY_REQUIRE        - The client has to present a valid Certificate
         * SSL_CVERIFY_OPTIONAL_NO_CA - The client may present a valid Certificate
         *                              but it need not to be (successfully) verifiable
         * 
    *
    * The depth actually is the maximum number of intermediate certificate issuers, * i.e. the number of CA certificates which are max allowed to be followed while * verifying the client certificate. A depth of 0 means that self-signed client * certificates are accepted only, the default depth of 1 means the client * certificate can be self-signed or has to be signed by a CA which is directly * known to the server (i.e. the CA's certificate is under * setCACertificatePath), etc. * @param ctx Server or Client context to use. * @param level Type of Client Certificate verification. * @param depth Maximum depth of CA Certificates in Client Certificate * verification. */ public static native void setVerify(long ctx, int level, int depth); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Socket.java0000644000175100017510000005513112271453221022242 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /* Import needed classes */ import java.nio.ByteBuffer; /** Socket * * @author Mladen Turk */ public class Socket { /* Standard socket defines */ public static final int SOCK_STREAM = 0; public static final int SOCK_DGRAM = 1; /* * apr_sockopt Socket option definitions */ public static final int APR_SO_LINGER = 1; /** Linger */ public static final int APR_SO_KEEPALIVE = 2; /** Keepalive */ public static final int APR_SO_DEBUG = 4; /** Debug */ public static final int APR_SO_NONBLOCK = 8; /** Non-blocking IO */ public static final int APR_SO_REUSEADDR = 16; /** Reuse addresses */ public static final int APR_SO_SNDBUF = 64; /** Send buffer */ public static final int APR_SO_RCVBUF = 128; /** Receive buffer */ public static final int APR_SO_DISCONNECTED = 256; /** Disconnected */ /** For SCTP sockets, this is mapped to STCP_NODELAY internally. */ public static final int APR_TCP_NODELAY = 512; public static final int APR_TCP_NOPUSH = 1024; /** No push */ /** This flag is ONLY set internally when we set APR_TCP_NOPUSH with * APR_TCP_NODELAY set to tell us that APR_TCP_NODELAY should be turned on * again when NOPUSH is turned off */ public static final int APR_RESET_NODELAY = 2048; /** Set on non-blocking sockets (timeout != 0) on which the * previous read() did not fill a buffer completely. the next * apr_socket_recv() will first call select()/poll() rather than * going straight into read(). (Can also be set by an application to * force a select()/poll() call before the next read, in cases where * the app expects that an immediate read would fail.) */ public static final int APR_INCOMPLETE_READ = 4096; /** like APR_INCOMPLETE_READ, but for write */ public static final int APR_INCOMPLETE_WRITE = 8192; /** Don't accept IPv4 connections on an IPv6 listening socket. */ public static final int APR_IPV6_V6ONLY = 16384; /** Delay accepting of new connections until data is available. */ public static final int APR_TCP_DEFER_ACCEPT = 32768; /** Define what type of socket shutdown should occur. * apr_shutdown_how_e enum */ public static final int APR_SHUTDOWN_READ = 0; /** no longer allow read request */ public static final int APR_SHUTDOWN_WRITE = 1; /** no longer allow write requests */ public static final int APR_SHUTDOWN_READWRITE = 2; /** no longer allow read or write requests */ public static final int APR_IPV4_ADDR_OK = 0x01; public static final int APR_IPV6_ADDR_OK = 0x02; /* TODO: Missing: * APR_INET * APR_UNSPEC * APR_INET6 */ public static final int APR_UNSPEC = 0; public static final int APR_INET = 1; public static final int APR_INET6 = 2; public static final int APR_PROTO_TCP = 6; /** TCP */ public static final int APR_PROTO_UDP = 17; /** UDP */ public static final int APR_PROTO_SCTP = 132; /** SCTP */ /** * Enum to tell us if we're interested in remote or local socket * apr_interface_e */ public static final int APR_LOCAL = 0; public static final int APR_REMOTE = 1; /* Socket.get types */ public static final int SOCKET_GET_POOL = 0; public static final int SOCKET_GET_IMPL = 1; public static final int SOCKET_GET_APRS = 2; public static final int SOCKET_GET_TYPE = 3; /** * Create a socket. * @param family The address family of the socket (e.g., APR_INET). * @param type The type of the socket (e.g., SOCK_STREAM). * @param protocol The protocol of the socket (e.g., APR_PROTO_TCP). * @param cont The parent pool to use * @return The new socket that has been set up. */ public static native long create(int family, int type, int protocol, long cont) throws Exception; /** * Shutdown either reading, writing, or both sides of a socket. *
    * This does not actually close the socket descriptor, it just * controls which calls are still valid on the socket. * @param thesocket The socket to close * @param how How to shutdown the socket. One of: *
         * APR_SHUTDOWN_READ         no longer allow read requests
         * APR_SHUTDOWN_WRITE        no longer allow write requests
         * APR_SHUTDOWN_READWRITE    no longer allow read or write requests
         * 
    */ public static native int shutdown(long thesocket, int how); /** * Close a socket. * @param thesocket The socket to close */ public static native int close(long thesocket); /** * Destroy a pool associated with socket * @param thesocket The destroy */ public static native void destroy(long thesocket); /** * Bind the socket to its associated port * @param sock The socket to bind * @param sa The socket address to bind to * This may be where we will find out if there is any other process * using the selected port. */ public static native int bind(long sock, long sa); /** * Listen to a bound socket for connections. * @param sock The socket to listen on * @param backlog The number of outstanding connections allowed in the sockets * listen queue. If this value is less than zero, the listen * queue size is set to zero. */ public static native int listen(long sock, int backlog); /** * Accept a new connection request * @param sock The socket we are listening on. * @param pool The pool for the new socket. * @return A copy of the socket that is connected to the socket that * made the connection request. This is the socket which should * be used for all future communication. */ public static native long acceptx(long sock, long pool) throws Exception; /** * Accept a new connection request * @param sock The socket we are listening on. * @return A copy of the socket that is connected to the socket that * made the connection request. This is the socket which should * be used for all future communication. */ public static native long accept(long sock) throws Exception; /** * Set an OS level accept filter. * @param sock The socket to put the accept filter on. * @param name The accept filter * @param args Any extra args to the accept filter. Passing NULL here removes * the accept filter. */ public static native int acceptfilter(long sock, String name, String args); /** * Query the specified socket if at the OOB/Urgent data mark * @param sock The socket to query * @return True if socket is at the OOB/urgent mark, * otherwise return false. */ public static native boolean atmark(long sock); /** * Issue a connection request to a socket either on the same machine * or a different one. * @param sock The socket we wish to use for our side of the connection * @param sa The address of the machine we wish to connect to. */ public static native int connect(long sock, long sa); /** * Send data over a network. *
         * This functions acts like a blocking write by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         *
         * It is possible for both bytes to be sent and an error to be returned.
         *
         * APR_EINTR is never returned.
         * 
    * @param sock The socket to send the data over. * @param buf The buffer which contains the data to be sent. * @param offset Offset in the byte buffer. * @param len The number of bytes to write; (-1) for full array. * @return The number of bytes send. * */ public static native int send(long sock, byte[] buf, int offset, int len); /** * Send data over a network. *
         * This functions acts like a blocking write by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         *
         * It is possible for both bytes to be sent and an error to be returned.
         *
         * APR_EINTR is never returned.
         * 
    * @param sock The socket to send the data over. * @param buf The Byte buffer which contains the data to be sent. * @param offset The offset within the buffer array of the first buffer from * which bytes are to be retrieved; must be non-negative * and no larger than buf.length * @param len The maximum number of buffers to be accessed; must be non-negative * and no larger than buf.length - offset * @return The number of bytes send. * */ public static native int sendb(long sock, ByteBuffer buf, int offset, int len); /** * Send data over a network without retry *
         * This functions acts like a blocking write by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         *
         * It is possible for both bytes to be sent and an error to be returned.
         *
         * 
    * @param sock The socket to send the data over. * @param buf The Byte buffer which contains the data to be sent. * @param offset The offset within the buffer array of the first buffer from * which bytes are to be retrieved; must be non-negative * and no larger than buf.length * @param len The maximum number of buffers to be accessed; must be non-negative * and no larger than buf.length - offset * @return The number of bytes send. * */ public static native int sendib(long sock, ByteBuffer buf, int offset, int len); /** * Send data over a network using internally set ByteBuffer */ public static native int sendbb(long sock, int offset, int len); /** * Send data over a network using internally set ByteBuffer * without internal retry. */ public static native int sendibb(long sock, int offset, int len); /** * Send multiple packets of data over a network. *
         * This functions acts like a blocking write by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         * The number of bytes actually sent is stored in argument 3.
         *
         * It is possible for both bytes to be sent and an error to be returned.
         *
         * APR_EINTR is never returned.
         * 
    * @param sock The socket to send the data over. * @param vec The array from which to get the data to send. * */ public static native int sendv(long sock, byte[][] vec); /** * @param sock The socket to send from * @param where The apr_sockaddr_t describing where to send the data * @param flags The flags to use * @param buf The data to send * @param offset Offset in the byte buffer. * @param len The length of the data to send */ public static native int sendto(long sock, long where, int flags, byte[] buf, int offset, int len); /** * Read data from a network. * *
         * This functions acts like a blocking read by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         * The number of bytes actually received is stored in argument 3.
         *
         * It is possible for both bytes to be received and an APR_EOF or
         * other error to be returned.
         *
         * APR_EINTR is never returned.
         * 
    * @param sock The socket to read the data from. * @param buf The buffer to store the data in. * @param offset Offset in the byte buffer. * @param nbytes The number of bytes to read (-1) for full array. * @return the number of bytes received. */ public static native int recv(long sock, byte[] buf, int offset, int nbytes); /** * Read data from a network with timeout. * *
         * This functions acts like a blocking read by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         * The number of bytes actually received is stored in argument 3.
         *
         * It is possible for both bytes to be received and an APR_EOF or
         * other error to be returned.
         *
         * APR_EINTR is never returned.
         * 
    * @param sock The socket to read the data from. * @param buf The buffer to store the data in. * @param offset Offset in the byte buffer. * @param nbytes The number of bytes to read (-1) for full array. * @param timeout The socket timeout in microseconds. * @return the number of bytes received. */ public static native int recvt(long sock, byte[] buf, int offset, int nbytes, long timeout); /** * Read data from a network. * *
         * This functions acts like a blocking read by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         * The number of bytes actually received is stored in argument 3.
         *
         * It is possible for both bytes to be received and an APR_EOF or
         * other error to be returned.
         *
         * APR_EINTR is never returned.
         * 
    * @param sock The socket to read the data from. * @param buf The buffer to store the data in. * @param offset Offset in the byte buffer. * @param nbytes The number of bytes to read (-1) for full array. * @return the number of bytes received. */ public static native int recvb(long sock, ByteBuffer buf, int offset, int nbytes); /** * Read data from a network using internally set ByteBuffer */ public static native int recvbb(long sock, int offset, int nbytes); /** * Read data from a network with timeout. * *
         * This functions acts like a blocking read by default.  To change
         * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
         * socket option.
         * The number of bytes actually received is stored in argument 3.
         *
         * It is possible for both bytes to be received and an APR_EOF or
         * other error to be returned.
         *
         * APR_EINTR is never returned.
         * 
    * @param sock The socket to read the data from. * @param buf The buffer to store the data in. * @param offset Offset in the byte buffer. * @param nbytes The number of bytes to read (-1) for full array. * @param timeout The socket timeout in microseconds. * @return the number of bytes received. */ public static native int recvbt(long sock, ByteBuffer buf, int offset, int nbytes, long timeout); /** * Read data from a network with timeout using internally set ByteBuffer */ public static native int recvbbt(long sock, int offset, int nbytes, long timeout); /** * @param from The apr_sockaddr_t to fill in the recipient info * @param sock The socket to use * @param flags The flags to use * @param buf The buffer to use * @param offset Offset in the byte buffer. * @param nbytes The number of bytes to read (-1) for full array. * @return the number of bytes received. */ public static native int recvfrom(long from, long sock, int flags, byte[] buf, int offset, int nbytes); /** * Setup socket options for the specified socket * @param sock The socket to set up. * @param opt The option we would like to configure. One of: *
         * APR_SO_DEBUG      --  turn on debugging information
         * APR_SO_KEEPALIVE  --  keep connections active
         * APR_SO_LINGER     --  lingers on close if data is present
         * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
         *                       When this option is enabled, use
         *                       the APR_STATUS_IS_EAGAIN() macro to
         *                       see if a send or receive function
         *                       could not transfer data without
         *                       blocking.
         * APR_SO_REUSEADDR  --  The rules used in validating addresses
         *                       supplied to bind should allow reuse
         *                       of local addresses.
         * APR_SO_SNDBUF     --  Set the SendBufferSize
         * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
         * 
    * @param on Value for the option. */ public static native int optSet(long sock, int opt, int on); /** * Query socket options for the specified socket * @param sock The socket to query * @param opt The option we would like to query. One of: *
         * APR_SO_DEBUG      --  turn on debugging information
         * APR_SO_KEEPALIVE  --  keep connections active
         * APR_SO_LINGER     --  lingers on close if data is present
         * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
         * APR_SO_REUSEADDR  --  The rules used in validating addresses
         *                       supplied to bind should allow reuse
         *                       of local addresses.
         * APR_SO_SNDBUF     --  Set the SendBufferSize
         * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
         * APR_SO_DISCONNECTED -- Query the disconnected state of the socket.
         *                       (Currently only used on Windows)
         * 
    * @return Socket option returned on the call. */ public static native int optGet(long sock, int opt) throws Exception; /** * Setup socket timeout for the specified socket * @param sock The socket to set up. * @param t Value for the timeout in microseconds. *
         * t > 0  -- read and write calls return APR_TIMEUP if specified time
         *           elapses with no data read or written
         * t == 0 -- read and write calls never block
         * t < 0  -- read and write calls block
         * 
    */ public static native int timeoutSet(long sock, long t); /** * Query socket timeout for the specified socket * @param sock The socket to query * @return Socket timeout returned from the query. */ public static native long timeoutGet(long sock) throws Exception; /** * Send a file from an open file descriptor to a socket, along with * optional headers and trailers. *
    * This functions acts like a blocking write by default. To change * this behavior, use apr_socket_timeout_set() or the * APR_SO_NONBLOCK socket option. * The number of bytes actually sent is stored in the len parameter. * The offset parameter is passed by reference for no reason; its * value will never be modified by the apr_socket_sendfile() function. * @param sock The socket to which we're writing * @param file The open file from which to read * @param headers Array containing the headers to send * @param trailers Array containing the trailers to send * @param offset Offset into the file where we should begin writing * @param len Number of bytes to send from the file * @param flags APR flags that are mapped to OS specific flags * @return Number of bytes actually sent, including headers, * file, and trailers * */ public static native long sendfile(long sock, long file, byte [][] headers, byte[][] trailers, long offset, long len, int flags); /** * Send a file without header and trailer arrays. */ public static native long sendfilen(long sock, long file, long offset, long len, int flags); /** * Create a child pool from associated socket pool. * @param thesocket The socket to use */ public static native long pool(long thesocket) throws Exception; /** * Private method for getting the socket struct members * @param socket The socket to use * @param what Struct member to obtain *
         * SOCKET_GET_POOL  - The socket pool
         * SOCKET_GET_IMPL  - The socket implementation object
         * SOCKET_GET_APRS  - APR socket
         * SOCKET_GET_TYPE  - Socket type
         * 
    * @return The structure member address */ private static native long get(long socket, int what); /** * Set internal send ByteBuffer. * This function will preset internal Java ByteBuffer for * consecutive sendbb calls. * @param sock The socket to use * @param buf The ByteBuffer */ public static native void setsbb(long sock, ByteBuffer buf); /** * Set internal receive ByteBuffer. * This function will preset internal Java ByteBuffer for * consecutive revcvbb/recvbbt calls. * @param sock The socket to use * @param buf The ByteBuffer */ public static native void setrbb(long sock, ByteBuffer buf); /** * Set the data associated with the current socket. * @param sock The currently open socket. * @param data The user data to associate with the socket. * @param key The key to associate with the data. */ public static native int dataSet(long sock, String key, Object data); /** * Return the data associated with the current socket * @param key The key to associate with the user data. * @param sock The currently open socket. * @return Data or null in case of error. */ public static native Object dataGet(long sock, String key); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Mmap.java0000644000175100017510000000452512271453221021705 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Mmap * * @author Mladen Turk */ public class Mmap { /** MMap opened for reading */ public static final int APR_MMAP_READ = 1; /** MMap opened for writing */ public static final int APR_MMAP_WRITE = 2; /** * Create a new mmap'ed file out of an existing APR file. * @param file The file turn into an mmap. * @param offset The offset into the file to start the data pointer at. * @param size The size of the file * @param flag bit-wise or of: *
         * APR_MMAP_READ       MMap opened for reading
         * APR_MMAP_WRITE      MMap opened for writing
         * 
    * @param pool The pool to use when creating the mmap. * @return The newly created mmap'ed file. */ public static native long create(long file, long offset, long size, int flag, long pool) throws Error; /** * Duplicate the specified MMAP. * @param mmap The mmap to duplicate. * @param pool The pool to use for new_mmap. * @return Duplicated mmap'ed file. */ public static native long dup(long mmap, long pool) throws Error; /** * Remove a mmap'ed. * @param mm The mmap'ed file. */ public static native int delete(long mm); /** * Move the pointer into the mmap'ed file to the specified offset. * @param mm The mmap'ed file. * @param offset The offset to move to. * @return The pointer to the offset specified. */ public static native long offset(long mm, long offset) throws Error; } tomcat7-7.0.52/java/org/apache/tomcat/jni/File.java0000644000175100017510000007611312271453221021674 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /* Import needed classes */ import java.nio.ByteBuffer; /** File * * @author Mladen Turk */ public class File { /** Open the file for reading */ public static final int APR_FOPEN_READ = 0x00001; /** Open the file for writing */ public static final int APR_FOPEN_WRITE = 0x00002; /** Create the file if not there */ public static final int APR_FOPEN_CREATE = 0x00004; /** Append to the end of the file */ public static final int APR_FOPEN_APPEND = 0x00008; /** Open the file and truncate to 0 length */ public static final int APR_FOPEN_TRUNCATE = 0x00010; /** Open the file in binary mode */ public static final int APR_FOPEN_BINARY = 0x00020; /** Open should fail if APR_CREATE and file exists. */ public static final int APR_FOPEN_EXCL = 0x00040; /** Open the file for buffered I/O */ public static final int APR_FOPEN_BUFFERED = 0x00080; /** Delete the file after close */ public static final int APR_FOPEN_DELONCLOSE = 0x00100; /** Platform dependent tag to open the file for * use across multiple threads */ public static final int APR_FOPEN_XTHREAD = 0x00200; /** Platform dependent support for higher level locked read/write * access to support writes across process/machines */ public static final int APR_FOPEN_SHARELOCK = 0x00400; /** Do not register a cleanup when the file is opened */ public static final int APR_FOPEN_NOCLEANUP = 0x00800; /** Advisory flag that this file should support * apr_socket_sendfile operation */ public static final int APR_FOPEN_SENDFILE_ENABLED = 0x01000; /** Platform dependent flag to enable large file support; *
    Warning : The APR_LARGEFILE flag only has effect on some platforms * where sizeof(apr_off_t) == 4. Where implemented, it allows opening * and writing to a file which exceeds the size which can be * represented by apr_off_t (2 gigabytes). When a file's size does * exceed 2Gb, apr_file_info_get() will fail with an error on the * descriptor, likewise apr_stat()/apr_lstat() will fail on the * filename. apr_dir_read() will fail with APR_INCOMPLETE on a * directory entry for a large file depending on the particular * APR_FINFO_* flags. Generally, it is not recommended to use this * flag. */ public static final int APR_FOPEN_LARGEFILE = 0x04000; /** Set the file position */ public static final int APR_SET = 0; /** Current */ public static final int APR_CUR = 1; /** Go to end of file */ public static final int APR_END = 2; /* flags for apr_file_attrs_set */ /** File is read-only */ public static final int APR_FILE_ATTR_READONLY = 0x01; /** File is executable */ public static final int APR_FILE_ATTR_EXECUTABLE = 0x02; /** File is hidden */ public static final int APR_FILE_ATTR_HIDDEN = 0x04; /* File lock types/flags */ /** Shared lock. More than one process or thread can hold a shared lock * at any given time. Essentially, this is a "read lock", preventing * writers from establishing an exclusive lock. */ public static final int APR_FLOCK_SHARED = 1; /** Exclusive lock. Only one process may hold an exclusive lock at any * given time. This is analogous to a "write lock". */ public static final int APR_FLOCK_EXCLUSIVE = 2; /** mask to extract lock type */ public static final int APR_FLOCK_TYPEMASK = 0x000F; /** do not block while acquiring the file lock */ public static final int APR_FLOCK_NONBLOCK = 0x0010; /* apr_filetype_e values for the filetype member of the * apr_file_info_t structure *
    Warning :: Not all of the filetypes below can be determined. * For example, a given platform might not correctly report * a socket descriptor as APR_SOCK if that type isn't * well-identified on that platform. In such cases where * a filetype exists but cannot be described by the recognized * flags below, the filetype will be APR_UNKFILE. If the * filetype member is not determined, the type will be APR_NOFILE. */ /** no file type determined */ public static final int APR_NOFILE = 0; /** a regular file */ public static final int APR_REG = 1; /** a directory */ public static final int APR_DIR = 2; /** a character device */ public static final int APR_CHR = 3; /** a block device */ public static final int APR_BLK = 4; /** a FIFO / pipe */ public static final int APR_PIPE = 5; /** a symbolic link */ public static final int APR_LNK = 6; /** a [unix domain] socket */ public static final int APR_SOCK = 7; /** a file of some other unknown type */ public static final int APR_UNKFILE = 127; /* * apr_file_permissions File Permissions flags */ public static final int APR_FPROT_USETID = 0x8000; /** Set user id */ public static final int APR_FPROT_UREAD = 0x0400; /** Read by user */ public static final int APR_FPROT_UWRITE = 0x0200; /** Write by user */ public static final int APR_FPROT_UEXECUTE = 0x0100; /** Execute by user */ public static final int APR_FPROT_GSETID = 0x4000; /** Set group id */ public static final int APR_FPROT_GREAD = 0x0040; /** Read by group */ public static final int APR_FPROT_GWRITE = 0x0020; /** Write by group */ public static final int APR_FPROT_GEXECUTE = 0x0010; /** Execute by group */ public static final int APR_FPROT_WSTICKY = 0x2000; /** Sticky bit */ public static final int APR_FPROT_WREAD = 0x0004; /** Read by others */ public static final int APR_FPROT_WWRITE = 0x0002; /** Write by others */ public static final int APR_FPROT_WEXECUTE = 0x0001; /** Execute by others */ public static final int APR_FPROT_OS_DEFAULT = 0x0FFF; /** use OS's default permissions */ public static final int APR_FINFO_LINK = 0x00000001; /** Stat the link not the file itself if it is a link */ public static final int APR_FINFO_MTIME = 0x00000010; /** Modification Time */ public static final int APR_FINFO_CTIME = 0x00000020; /** Creation or inode-changed time */ public static final int APR_FINFO_ATIME = 0x00000040; /** Access Time */ public static final int APR_FINFO_SIZE = 0x00000100; /** Size of the file */ public static final int APR_FINFO_CSIZE = 0x00000200; /** Storage size consumed by the file */ public static final int APR_FINFO_DEV = 0x00001000; /** Device */ public static final int APR_FINFO_INODE = 0x00002000; /** Inode */ public static final int APR_FINFO_NLINK = 0x00004000; /** Number of links */ public static final int APR_FINFO_TYPE = 0x00008000; /** Type */ public static final int APR_FINFO_USER = 0x00010000; /** User */ public static final int APR_FINFO_GROUP = 0x00020000; /** Group */ public static final int APR_FINFO_UPROT = 0x00100000; /** User protection bits */ public static final int APR_FINFO_GPROT = 0x00200000; /** Group protection bits */ public static final int APR_FINFO_WPROT = 0x00400000; /** World protection bits */ public static final int APR_FINFO_ICASE = 0x01000000; /** if dev is case insensitive */ public static final int APR_FINFO_NAME = 0x02000000; /** ->name in proper case */ public static final int APR_FINFO_MIN = 0x00008170; /** type, mtime, ctime, atime, size */ public static final int APR_FINFO_IDENT = 0x00003000; /** dev and inode */ public static final int APR_FINFO_OWNER = 0x00030000; /** user and group */ public static final int APR_FINFO_PROT = 0x00700000; /** all protections */ public static final int APR_FINFO_NORM = 0x0073b170; /** an atomic unix apr_stat() */ public static final int APR_FINFO_DIRENT = 0x02000000; /** an atomic unix apr_dir_read() */ /** * Open the specified file. * @param fname The full path to the file (using / on all systems) * @param flag Or'ed value of: *
         * APR_FOPEN_READ              open for reading
         * APR_FOPEN_WRITE             open for writing
         * APR_FOPEN_CREATE            create the file if not there
         * APR_FOPEN_APPEND            file ptr is set to end prior to all writes
         * APR_FOPEN_TRUNCATE          set length to zero if file exists
         * APR_FOPEN_BINARY            not a text file (This flag is ignored on
         *                             UNIX because it has no meaning)
         * APR_FOPEN_BUFFERED          buffer the data.  Default is non-buffered
         * APR_FOPEN_EXCL              return error if APR_CREATE and file exists
         * APR_FOPEN_DELONCLOSE        delete the file after closing.
         * APR_FOPEN_XTHREAD           Platform dependent tag to open the file
         *                             for use across multiple threads
         * APR_FOPEN_SHARELOCK         Platform dependent support for higher
         *                             level locked read/write access to support
         *                             writes across process/machines
         * APR_FOPEN_NOCLEANUP         Do not register a cleanup with the pool
         *                             passed in on the pool argument (see below).
         *                             The apr_os_file_t handle in apr_file_t will not
         *                             be closed when the pool is destroyed.
         * APR_FOPEN_SENDFILE_ENABLED  Open with appropriate platform semantics
         *                             for sendfile operations.  Advisory only,
         *                             apr_socket_sendfile does not check this flag.
         * 
    * @param perm Access permissions for file. * @param pool The pool to use. * If perm is APR_OS_DEFAULT and the file is being created, * appropriate default permissions will be used. * @return The opened file descriptor. */ public static native long open(String fname, int flag, int perm, long pool) throws Error; /** * Close the specified file. * @param file The file descriptor to close. */ public static native int close(long file); /** * Flush the file's buffer. * @param thefile The file descriptor to flush */ public static native int flush(long thefile); /** * Open a temporary file * @param templ The template to use when creating a temp file. * @param flags The flags to open the file with. If this is zero, * the file is opened with * APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_DELONCLOSE * @param pool The pool to allocate the file out of. * @return The apr file to use as a temporary file. * * This function generates a unique temporary file name from template. * The last six characters of template must be XXXXXX and these are replaced * with a string that makes the filename unique. Since it will be modified, * template must not be a string constant, but should be declared as a character * array. * */ public static native long mktemp(String templ, int flags, long pool) throws Error; /** * Delete the specified file. * @param path The full path to the file (using / on all systems) * @param pool The pool to use. * If the file is open, it won't be removed until all * instances are closed. */ public static native int remove(String path, long pool); /** * Rename the specified file. *
    Warning : If a file exists at the new location, then it will be * overwritten. Moving files or directories across devices may not be * possible. * @param fromPath The full path to the original file (using / on all systems) * @param toPath The full path to the new file (using / on all systems) * @param pool The pool to use. */ public static native int rename(String fromPath, String toPath, long pool); /** * Copy the specified file to another file. * The new file does not need to exist, it will be created if required. *
    Warning : If the new file already exists, its contents will be overwritten. * @param fromPath The full path to the original file (using / on all systems) * @param toPath The full path to the new file (using / on all systems) * @param perms Access permissions for the new file if it is created. * In place of the usual or'd combination of file permissions, the * value APR_FILE_SOURCE_PERMS may be given, in which case the source * file's permissions are copied. * @param pool The pool to use. */ public static native int copy(String fromPath, String toPath, int perms, long pool); /** * Append the specified file to another file. * The new file does not need to exist, it will be created if required. * @param fromPath The full path to the source file (use / on all systems) * @param toPath The full path to the destination file (use / on all systems) * @param perms Access permissions for the destination file if it is created. * In place of the usual or'd combination of file permissions, the * value APR_FILE_SOURCE_PERMS may be given, in which case the source * file's permissions are copied. * @param pool The pool to use. */ public static native int append(String fromPath, String toPath, int perms, long pool); /** * Write the string into the specified file. * @param str The string to write. Must be NUL terminated! * @param thefile The file descriptor to write to */ public static native int puts(byte [] str, long thefile); /** * Move the read/write file offset to a specified byte within a file. * @param thefile The file descriptor * @param where How to move the pointer, one of: *
         * APR_SET  --  set the offset to offset
         * APR_CUR  --  add the offset to the current position
         * APR_END  --  add the offset to the current file size
         * 
    * @param offset The offset to move the pointer to. * @return Offset the pointer was actually moved to. */ public static native long seek(long thefile, int where, long offset) throws Error; /** * Write a character into the specified file. * @param ch The character to write. * @param thefile The file descriptor to write to */ public static native int putc(byte ch, long thefile); /** * Put a character back onto a specified stream. * @param ch The character to write. * @param thefile The file descriptor to write to */ public static native int ungetc(byte ch, long thefile); /** * Write data to the specified file. * * Write will write up to the specified number of * bytes, but never more. If the OS cannot write that many bytes, it * will write as many as it can. The third argument is modified to * reflect the * number of bytes written. * * It is possible for both bytes to be written and an error to * be returned. APR_EINTR is never returned. * @param thefile The file descriptor to write to. * @param buf The buffer which contains the data. * @param offset Start offset in buf * @param nbytes The number of bytes to write; (-1) for full array. * @return The number of bytes written. */ public static native int write(long thefile, byte[] buf, int offset, int nbytes); /** * Write data to the specified file. * * Write will write up to the specified number of * bytes, but never more. If the OS cannot write that many bytes, it * will write as many as it can. The third argument is modified to * reflect the * number of bytes written. * * It is possible for both bytes to be written and an error to * be returned. APR_EINTR is never returned. * @param thefile The file descriptor to write to. * @param buf The direct Byte buffer which contains the data. * @param offset Start offset in buf * @param nbytes The number of bytes to write * @return The number of bytes written. */ public static native int writeb(long thefile, ByteBuffer buf, int offset, int nbytes); /** * Write data to the specified file, ensuring that all of the data is * written before returning. * * Write will write up to the specified number of * bytes, but never more. If the OS cannot write that many bytes, the * process/thread will block until they can be written. Exceptional * error such as "out of space" or "pipe closed" will terminate with * an error. * * It is possible for both bytes to be written and an error to * be returned. And if *bytes_written is less than nbytes, an * accompanying error is _always_ returned. * * APR_EINTR is never returned. * @param thefile The file descriptor to write to. * @param buf The buffer which contains the data. * @param offset Start offset in buf * @param nbytes The number of bytes to write; (-1) for full array. * @return The number of bytes written. */ public static native int writeFull(long thefile, byte[] buf, int offset, int nbytes); /** * Write data to the specified file, ensuring that all of the data is * written before returning. * * Write will write up to the specified number of * bytes, but never more. If the OS cannot write that many bytes, the * process/thread will block until they can be written. Exceptional * error such as "out of space" or "pipe closed" will terminate with * an error. * * It is possible for both bytes to be written and an error to * be returned. And if *bytes_written is less than nbytes, an * accompanying error is _always_ returned. * * APR_EINTR is never returned. * @param thefile The file descriptor to write to. * @param buf The direct ByteBuffer which contains the data. * @param offset Start offset in buf * @param nbytes The number of bytes to write. * @return The number of bytes written. */ public static native int writeFullb(long thefile, ByteBuffer buf, int offset, int nbytes); /** * Write data from array of byte arrays to the specified file. * * It is possible for both bytes to be written and an error to * be returned. APR_EINTR is never returned. * * apr_file_writev is available even if the underlying * operating system doesn't provide writev(). * @param thefile The file descriptor to write to. * @param vec The array from which to get the data to write to the file. * @return The number of bytes written. */ public static native int writev(long thefile, byte[][] vec); /** * Write data from array of byte arrays to the specified file, * ensuring that all of the data is written before returning. * * writevFull is available even if the underlying * operating system doesn't provide writev(). * @param thefile The file descriptor to write to. * @param vec The array from which to get the data to write to the file. * @return The number of bytes written. */ public static native int writevFull(long thefile, byte[][] vec); /** * Read data from the specified file. * * apr_file_read will read up to the specified number of * bytes, but never more. If there isn't enough data to fill that * number of bytes, all of the available data is read. The third * argument is modified to reflect the number of bytes read. If a * char was put back into the stream via ungetc, it will be the first * character returned. * * It is not possible for both bytes to be read and an APR_EOF * or other error to be returned. APR_EINTR is never returned. * @param thefile The file descriptor to read from. * @param buf The buffer to store the data to. * @param offset Start offset in buf * @param nbytes The number of bytes to read (-1) for full array. * @return the number of bytes read. */ public static native int read(long thefile, byte[] buf, int offset, int nbytes); /** * Read data from the specified file. * * apr_file_read will read up to the specified number of * bytes, but never more. If there isn't enough data to fill that * number of bytes, all of the available data is read. The third * argument is modified to reflect the number of bytes read. If a * char was put back into the stream via ungetc, it will be the first * character returned. * * It is not possible for both bytes to be read and an APR_EOF * or other error to be returned. APR_EINTR is never returned. * @param thefile The file descriptor to read from. * @param buf The direct Byte buffer to store the data to. * @param offset Start offset in buf * @param nbytes The number of bytes to read. * @return the number of bytes read. */ public static native int readb(long thefile, ByteBuffer buf, int offset, int nbytes); /** * Read data from the specified file, ensuring that the buffer is filled * before returning. * * Read will read up to the specified number of * bytes, but never more. If there isn't enough data to fill that * number of bytes, then the process/thread will block until it is * available or EOF is reached. If a char was put back into the * stream via ungetc, it will be the first character returned. * * It is possible for both bytes to be read and an error to be * returned. And if *bytes_read is less than nbytes, an accompanying * error is _always_ returned. * * APR_EINTR is never returned. * @param thefile The file descriptor to read from. * @param buf The buffer to store the data to. * @param offset Start offset in buf * @param nbytes The number of bytes to read (-1) for full array. * @return the number of bytes read. */ public static native int readFull(long thefile, byte[] buf, int offset, int nbytes); /** * Read data from the specified file, ensuring that the buffer is filled * before returning. * * Read will read up to the specified number of * bytes, but never more. If there isn't enough data to fill that * number of bytes, then the process/thread will block until it is * available or EOF is reached. If a char was put back into the * stream via ungetc, it will be the first character returned. * * It is possible for both bytes to be read and an error to be * returned. And if *bytes_read is less than nbytes, an accompanying * error is _always_ returned. * * APR_EINTR is never returned. * @param thefile The file descriptor to read from. * @param buf The direct ByteBuffer to store the data to. * @param offset Start offset in buf * @param nbytes The number of bytes to read. * @return the number of bytes read. */ public static native int readFullb(long thefile, ByteBuffer buf, int offset, int nbytes); /** * Read a string from the specified file. * The buffer will be NUL-terminated if any characters are stored. * @param buf The buffer to store the string in. * @param offset Start offset in buf * @param thefile The file descriptor to read from */ public static native int gets(byte[] buf, int offset, long thefile); /** * Read a character from the specified file. * @param thefile The file descriptor to read from * @return The read character */ public static native int getc(long thefile) throws Error; /** * Are we at the end of the file * @param fptr The apr file we are testing. * @return Returns APR_EOF if we are at the end of file, APR_SUCCESS otherwise. */ public static native int eof(long fptr); /** * return the file name of the current file. * @param thefile The currently open file. */ public static native String nameGet(long thefile); /** * Set the specified file's permission bits. *
    Warning : Some platforms may not be able to apply all of the * available permission bits; APR_INCOMPLETE will be returned if some * permissions are specified which could not be set. *
    Warning : Platforms which do not implement this feature will return * APR_ENOTIMPL. * @param fname The file (name) to apply the permissions to. * @param perms The permission bits to apply to the file. * */ public static native int permsSet(String fname, int perms); /** * Set attributes of the specified file. * This function should be used in preference to explicit manipulation * of the file permissions, because the operations to provide these * attributes are platform specific and may involve more than simply * setting permission bits. *
    Warning : Platforms which do not implement this feature will return * APR_ENOTIMPL. * @param fname The full path to the file (using / on all systems) * @param attributes Or'd combination of *
         *            APR_FILE_ATTR_READONLY   - make the file readonly
         *            APR_FILE_ATTR_EXECUTABLE - make the file executable
         *            APR_FILE_ATTR_HIDDEN     - make the file hidden
         * 
    * @param mask Mask of valid bits in attributes. * @param pool the pool to use. */ public static native int attrsSet(String fname, int attributes, int mask, long pool); /** * Set the mtime of the specified file. *
    Warning : Platforms which do not implement this feature will return * APR_ENOTIMPL. * @param fname The full path to the file (using / on all systems) * @param mtime The mtime to apply to the file in microseconds * @param pool The pool to use. */ public static native int mtimeSet(String fname, long mtime, long pool); /** * Establish a lock on the specified, open file. The lock may be advisory * or mandatory, at the discretion of the platform. The lock applies to * the file as a whole, rather than a specific range. Locks are established * on a per-thread/process basis; a second lock by the same thread will not * block. * @param thefile The file to lock. * @param type The type of lock to establish on the file. */ public static native int lock(long thefile, int type); /** * Remove any outstanding locks on the file. * @param thefile The file to unlock. */ public static native int unlock(long thefile); /** * Retrieve the flags that were passed into apr_file_open() * when the file was opened. * @param file The file to retrieve flags. * @return the flags */ public static native int flagsGet(long file); /** * Truncate the file's length to the specified offset * @param fp The file to truncate * @param offset The offset to truncate to. */ public static native int trunc(long fp, long offset); /** * Create an anonymous pipe. * @param io io[0] The file descriptors to use as input to the pipe. * io[1] The file descriptor to use as output from the pipe. * @param pool The pool to operate on. */ public static native int pipeCreate(long [] io, long pool); /** * Get the timeout value for a pipe or manipulate the blocking state. * @param thepipe The pipe we are getting a timeout for. * @return The current timeout value in microseconds. */ public static native long pipeTimeoutGet(long thepipe) throws Error; /** * Set the timeout value for a pipe or manipulate the blocking state. * @param thepipe The pipe we are setting a timeout on. * @param timeout The timeout value in microseconds. Values < 0 mean wait * forever, 0 means do not wait at all. */ public static native int pipeTimeoutSet(long thepipe, long timeout); /** * Duplicate the specified file descriptor. * @param newFile The file to duplicate. * newFile must point to a valid apr_file_t, or point to NULL. * @param oldFile The file to duplicate. * @param pool The pool to use for the new file. * @return Duplicated file structure. */ public static native long dup(long newFile, long oldFile, long pool) throws Error; /** * Duplicate the specified file descriptor and close the original. * @param newFile The old file that is to be closed and reused. * newFile MUST point at a valid apr_file_t. It cannot be NULL. * @param oldFile The file to duplicate. * @param pool The pool to use for the new file. * @return Status code. */ public static native int dup2(long newFile, long oldFile, long pool); /** * Get the specified file's stats. The file is specified by filename, * instead of using a pre-opened file. * @param finfo Where to store the information about the file, which is * never touched if the call fails. * @param fname The name of the file to stat. * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values * @param pool the pool to use to allocate the new file. */ public static native int stat(FileInfo finfo, String fname, int wanted, long pool); /** * Get the specified file's stats. The file is specified by filename, * instead of using a pre-opened file. * @param fname The name of the file to stat. * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values * @param pool the pool to use to allocate the new file. * @return FileInfo object. */ public static native FileInfo getStat(String fname, int wanted, long pool); /** * Get the specified file's stats. * @param finfo Where to store the information about the file. * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values * @param thefile The file to get information about. */ public static native int infoGet(FileInfo finfo, int wanted, long thefile); /** * Get the specified file's stats. * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values * @param thefile The file to get information about. * @return FileInfo object. */ public static native FileInfo getInfo(int wanted, long thefile); } tomcat7-7.0.52/java/org/apache/tomcat/jni/ProcErrorCallback.java0000644000175100017510000000265712271453221024351 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** ProcErrorCallback Interface * * @author Mladen Turk */ public interface ProcErrorCallback { /** * Called in the child process if APR encounters an error * in the child prior to running the specified program. * @param pool Pool associated with the apr_proc_t. If your child * error function needs user data, associate it with this * pool. * @param err APR error code describing the error * @param description Text description of type of processing which failed */ public void callback(long pool, int err, String description); } tomcat7-7.0.52/java/org/apache/tomcat/jni/User.java0000644000175100017510000001071512271453221021727 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** User * * @author Mladen Turk */ public class User { /** * Get the userid (and groupid) of the calling process * This function is available only if APR_HAS_USER is defined. * @param p The pool from which to allocate working space * @return Returns the user id */ public static native long uidCurrent(long p) throws Error; /** * Get the groupid of the calling process * This function is available only if APR_HAS_USER is defined. * @param p The pool from which to allocate working space * @return Returns the group id */ public static native long gidCurrent(long p) throws Error; /** * Get the userid for the specified username * This function is available only if APR_HAS_USER is defined. * @param username The username to lookup * @param p The pool from which to allocate working space * @return Returns the user id */ public static native long uid(String username, long p) throws Error; /** * Get the groupid for the specified username * This function is available only if APR_HAS_USER is defined. * @param username The username to lookup * @param p The pool from which to allocate working space * @return Returns the user's group id */ public static native long usergid(String username, long p) throws Error; /** * Get the groupid for a specified group name * This function is available only if APR_HAS_USER is defined. * @param groupname The group name to look up * @param p The pool from which to allocate working space * @return Returns the user's group id */ public static native long gid(String groupname, long p) throws Error; /** * Get the user name for a specified userid * This function is available only if APR_HAS_USER is defined. * @param userid The userid * @param p The pool from which to allocate the string * @return New string containing user name */ public static native String username(long userid, long p) throws Error; /** * Get the group name for a specified groupid * This function is available only if APR_HAS_USER is defined. * @param groupid The groupid * @param p The pool from which to allocate the string * @return New string containing group name */ public static native String groupname(long groupid, long p) throws Error; /** * Compare two user identifiers for equality. * This function is available only if APR_HAS_USER is defined. * @param left One uid to test * @param right Another uid to test * @return APR_SUCCESS if the apr_uid_t structures identify the same user, * APR_EMISMATCH if not, APR_BADARG if an apr_uid_t is invalid. */ public static native int uidcompare(long left, long right); /** * Compare two group identifiers for equality. * This function is available only if APR_HAS_USER is defined. * @param left One gid to test * @param right Another gid to test * @return APR_SUCCESS if the apr_gid_t structures identify the same group, * APR_EMISMATCH if not, APR_BADARG if an apr_gid_t is invalid. */ public static native int gidcompare(long left, long right); /** * Get the home directory for the named user * This function is available only if APR_HAS_USER is defined. * @param username The named user * @param p The pool from which to allocate the string * @return New string containing directory name */ public static native String homepath(String username, long p) throws Error; } tomcat7-7.0.52/java/org/apache/tomcat/jni/OS.java0000644000175100017510000001052312271453221021327 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** OS * * @author Mladen Turk */ public class OS { /* OS Enums */ private static final int UNIX = 1; private static final int NETWARE = 2; private static final int WIN32 = 3; private static final int WIN64 = 4; private static final int LINUX = 5; private static final int SOLARIS = 6; private static final int BSD = 7; private static final int MACOSX = 8; public static final int LOG_EMERG = 1; public static final int LOG_ERROR = 2; public static final int LOG_NOTICE = 3; public static final int LOG_WARN = 4; public static final int LOG_INFO = 5; public static final int LOG_DEBUG = 6; /** * Check for OS type. * @param type OS type to test. */ private static native boolean is(int type); public static final boolean IS_UNIX = is(UNIX); public static final boolean IS_NETWARE = is(NETWARE); public static final boolean IS_WIN32 = is(WIN32); public static final boolean IS_WIN64 = is(WIN64); public static final boolean IS_LINUX = is(LINUX); public static final boolean IS_SOLARIS = is(SOLARIS); public static final boolean IS_BSD = is(BSD); public static final boolean IS_MACOSX = is(MACOSX); /** * Get the name of the system default character set. * @param pool the pool to allocate the name from, if needed */ public static native String defaultEncoding(long pool); /** * Get the name of the current locale character set. * Defers to apr_os_default_encoding if the current locale's * data can't be retrieved on this system. * @param pool the pool to allocate the name from, if needed */ public static native String localeEncoding(long pool); /** * Generate random bytes. * @param buf Buffer to fill with random bytes * @param len Length of buffer in bytes */ public static native int random(byte [] buf, int len); /** * Gather system info. *
         * On exit the inf array will be filled with:
         * inf[0]  - Total usable main memory size
         * inf[1]  - Available memory size
         * inf[2]  - Total page file/swap space size
         * inf[3]  - Page file/swap space still available
         * inf[4]  - Amount of shared memory
         * inf[5]  - Memory used by buffers
         * inf[6]  - Memory Load
         *
         * inf[7]  - Idle Time in microseconds
         * inf[8]  - Kernel Time in microseconds
         * inf[9]  - User Time in microseconds
         *
         * inf[10] - Process creation time (apr_time_t)
         * inf[11] - Process Kernel Time in microseconds
         * inf[12] - Process User Time in microseconds
         *
         * inf[13] - Current working set size.
         * inf[14] - Peak working set size.
         * inf[15] - Number of page faults.
         * 
    * @param inf array that will be filled with system information. * Array length must be at least 16. */ public static native int info(long [] inf); /** * Expand environment variables. * @param str String to expand * @return Expanded string with replaced environment variables. */ public static native String expand(String str); /** * Initialize system logging. * @param domain String that will be prepended to every message */ public static native void sysloginit(String domain); /** * Log message. * @param level Log message severity. See LOG_XXX enums. * @param message Message to log */ public static native void syslog(int level, String message); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Global.java0000644000175100017510000000754612271453221022221 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Global * * @author Mladen Turk */ public class Global { /** * Create and initialize a mutex that can be used to synchronize both * processes and threads. Note: There is considerable overhead in using * this API if only cross-process or cross-thread mutual exclusion is * required. See apr_proc_mutex.h and apr_thread_mutex.h for more * specialized lock routines. *
    Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. * @param fname A file name to use if the lock mechanism requires one. This * argument should always be provided. The lock code itself will * determine if it should be used. * @param mech The mechanism to use for the interprocess lock, if any; one of *
         *            APR_LOCK_FCNTL
         *            APR_LOCK_FLOCK
         *            APR_LOCK_SYSVSEM
         *            APR_LOCK_POSIXSEM
         *            APR_LOCK_PROC_PTHREAD
         *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
         * 
    * @param pool the pool from which to allocate the mutex. * @return Newly created mutex. */ public static native long create(String fname, int mech, long pool) throws Error; /** * Re-open a mutex in a child process. * @param fname A file name to use if the mutex mechanism requires one. This * argument should always be provided. The mutex code itself will * determine if it should be used. This filename should be the * same one that was passed to apr_proc_mutex_create(). * @param pool The pool to operate on. * This function must be called to maintain portability, even * if the underlying lock mechanism does not require it. * @return Newly opened mutex. */ public static native long childInit(String fname, long pool) throws Error; /** * Acquire the lock for the given mutex. If the mutex is already locked, * the current thread will be put to sleep until the lock becomes available. * @param mutex the mutex on which to acquire the lock. */ public static native int lock(long mutex); /** * Attempt to acquire the lock for the given mutex. If the mutex has already * been acquired, the call returns immediately with APR_EBUSY. Note: it * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine * if the return value was APR_EBUSY, for portability reasons. * @param mutex the mutex on which to attempt the lock acquiring. */ public static native int trylock(long mutex); /** * Release the lock for the given mutex. * @param mutex the mutex from which to release the lock. */ public static native int unlock(long mutex); /** * Destroy the mutex and free the memory associated with the lock. * @param mutex the mutex to destroy. */ public static native int destroy(long mutex); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Stdlib.java0000644000175100017510000000515612271453221022235 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Stdlib * * @author Mladen Turk */ public class Stdlib { /** * Read from plain memory * @param dst Destination byte array * @param src Source memory address * @param sz Number of bytes to copy. */ public static native boolean memread(byte [] dst, long src, int sz); /** * Write to plain memory * @param dst Destination memory address * @param src Source byte array * @param sz Number of bytes to copy. */ public static native boolean memwrite(long dst, byte [] src, int sz); /** * Sets buffers to a specified character * @param dst Destination memory address * @param c Character to set. * @param sz Number of characters. */ public static native boolean memset(long dst, int c, int sz); /** * Allocates memory blocks. * @param sz Bytes to allocate. */ public static native long malloc(int sz); /** * Reallocate memory blocks. * @param mem Pointer to previously allocated memory block. * @param sz New size in bytes. */ public static native long realloc(long mem, int sz); /** * Allocates an array in memory with elements initialized to 0. * @param num Number of elements. * @param sz Length in bytes of each element. */ public static native long calloc(int num, int sz); /** * Deallocates or frees a memory block. * @param mem Previously allocated memory block to be freed. */ public static native void free(long mem); /** * Get current process pid. * @return current pid or < 1 in case of error. */ public static native int getpid(); /** * Get current process parent pid. * @return parent pid or < 1 in case of error. */ public static native int getppid(); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Lock.java0000644000175100017510000001161212271453221021676 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Lock * * @author Mladen Turk */ public class Lock { /** * Enumerated potential types for APR process locking methods *
    Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. */ public static final int APR_LOCK_FCNTL = 0; /** fcntl() */ public static final int APR_LOCK_FLOCK = 1; /** flock() */ public static final int APR_LOCK_SYSVSEM = 2; /** System V Semaphores */ public static final int APR_LOCK_PROC_PTHREAD = 3; /** POSIX pthread process-based locking */ public static final int APR_LOCK_POSIXSEM = 4; /** POSIX semaphore process-based locking */ public static final int APR_LOCK_DEFAULT = 5; /** Use the default process lock */ /** * Create and initialize a mutex that can be used to synchronize processes. *
    Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. * @param fname A file name to use if the lock mechanism requires one. This * argument should always be provided. The lock code itself will * determine if it should be used. * @param mech The mechanism to use for the interprocess lock, if any; one of *
         *            APR_LOCK_FCNTL
         *            APR_LOCK_FLOCK
         *            APR_LOCK_SYSVSEM
         *            APR_LOCK_POSIXSEM
         *            APR_LOCK_PROC_PTHREAD
         *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
         * 
    * @param pool the pool from which to allocate the mutex. * @return Newly created mutex. */ public static native long create(String fname, int mech, long pool) throws Error; /** * Re-open a mutex in a child process. * This function must be called to maintain portability, even * if the underlying lock mechanism does not require it. * @param fname A file name to use if the mutex mechanism requires one. This * argument should always be provided. The mutex code itself will * determine if it should be used. This filename should be the * same one that was passed to apr_proc_mutex_create(). * @param pool The pool to operate on. * @return Newly opened mutex. */ public static native long childInit(String fname, long pool) throws Error; /** * Acquire the lock for the given mutex. If the mutex is already locked, * the current thread will be put to sleep until the lock becomes available. * @param mutex the mutex on which to acquire the lock. */ public static native int lock(long mutex); /** * Attempt to acquire the lock for the given mutex. If the mutex has already * been acquired, the call returns immediately with APR_EBUSY. Note: it * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine * if the return value was APR_EBUSY, for portability reasons. * @param mutex the mutex on which to attempt the lock acquiring. */ public static native int trylock(long mutex); /** * Release the lock for the given mutex. * @param mutex the mutex from which to release the lock. */ public static native int unlock(long mutex); /** * Destroy the mutex and free the memory associated with the lock. * @param mutex the mutex to destroy. */ public static native int destroy(long mutex); /** * Return the name of the lockfile for the mutex, or NULL * if the mutex doesn't use a lock file */ public static native String lockfile(long mutex); /** * Display the name of the mutex, as it relates to the actual method used. * This matches the valid options for Apache's AcceptMutex directive * @param mutex the name of the mutex */ public static native String name(long mutex); /** * Display the name of the default mutex: APR_LOCK_DEFAULT */ public static native String defname(); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Multicast.java0000644000175100017510000000574212271453221022762 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Multicast * * @author Mladen Turk */ public class Multicast { /** * Join a Multicast Group * @param sock The socket to join a multicast group * @param join The address of the multicast group to join * @param iface Address of the interface to use. If NULL is passed, the * default multicast interface will be used. (OS Dependent) * @param source Source Address to accept transmissions from (non-NULL * implies Source-Specific Multicast) */ public static native int join(long sock, long join, long iface, long source); /** * Leave a Multicast Group. All arguments must be the same as * apr_mcast_join. * @param sock The socket to leave a multicast group * @param addr The address of the multicast group to leave * @param iface Address of the interface to use. If NULL is passed, the * default multicast interface will be used. (OS Dependent) * @param source Source Address to accept transmissions from (non-NULL * implies Source-Specific Multicast) */ public static native int leave(long sock, long addr, long iface, long source); /** * Set the Multicast Time to Live (ttl) for a multicast transmission. * @param sock The socket to set the multicast ttl * @param ttl Time to live to Assign. 0-255, default=1 *
    Remark : If the TTL is 0, packets will only be seen * by sockets on the local machine, * and only when multicast loopback is enabled. */ public static native int hops(long sock, int ttl); /** * Toggle IP Multicast Loopback * @param sock The socket to set multicast loopback * @param opt false=disable, true=enable */ public static native int loopback(long sock, boolean opt); /** * Set the Interface to be used for outgoing Multicast Transmissions. * @param sock The socket to set the multicast interface on * @param iface Address of the interface to use for Multicast */ public static native int ointerface(long sock, long iface); } tomcat7-7.0.52/java/org/apache/tomcat/jni/SSL.java0000644000175100017510000003712412271453221021455 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** SSL * * @author Mladen Turk */ public final class SSL { /* * Type definitions mostly from mod_ssl */ public static final int UNSET = -1; /* * Define the certificate algorithm types */ public static final int SSL_ALGO_UNKNOWN = 0; public static final int SSL_ALGO_RSA = (1<<0); public static final int SSL_ALGO_DSA = (1<<1); public static final int SSL_ALGO_ALL = (SSL_ALGO_RSA|SSL_ALGO_DSA); public static final int SSL_AIDX_RSA = 0; public static final int SSL_AIDX_DSA = 1; public static final int SSL_AIDX_MAX = 2; /* * Define IDs for the temporary RSA keys and DH params */ public static final int SSL_TMP_KEY_RSA_512 = 0; public static final int SSL_TMP_KEY_RSA_1024 = 1; public static final int SSL_TMP_KEY_RSA_2048 = 2; public static final int SSL_TMP_KEY_RSA_4096 = 3; public static final int SSL_TMP_KEY_DH_512 = 4; public static final int SSL_TMP_KEY_DH_1024 = 5; public static final int SSL_TMP_KEY_DH_2048 = 6; public static final int SSL_TMP_KEY_DH_4096 = 7; public static final int SSL_TMP_KEY_MAX = 8; /* * Define the SSL options */ public static final int SSL_OPT_NONE = 0; public static final int SSL_OPT_RELSET = (1<<0); public static final int SSL_OPT_STDENVVARS = (1<<1); public static final int SSL_OPT_EXPORTCERTDATA = (1<<3); public static final int SSL_OPT_FAKEBASICAUTH = (1<<4); public static final int SSL_OPT_STRICTREQUIRE = (1<<5); public static final int SSL_OPT_OPTRENEGOTIATE = (1<<6); public static final int SSL_OPT_ALL = (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE); /* * Define the SSL Protocol options */ public static final int SSL_PROTOCOL_NONE = 0; public static final int SSL_PROTOCOL_SSLV2 = (1<<0); public static final int SSL_PROTOCOL_SSLV3 = (1<<1); public static final int SSL_PROTOCOL_TLSV1 = (1<<2); public static final int SSL_PROTOCOL_ALL = (SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1); /* * Define the SSL verify levels */ public static final int SSL_CVERIFY_UNSET = UNSET; public static final int SSL_CVERIFY_NONE = 0; public static final int SSL_CVERIFY_OPTIONAL = 1; public static final int SSL_CVERIFY_REQUIRE = 2; public static final int SSL_CVERIFY_OPTIONAL_NO_CA = 3; /* Use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options * are 'ored' with SSL_VERIFY_PEER if they are desired */ public static final int SSL_VERIFY_NONE = 0; public static final int SSL_VERIFY_PEER = 1; public static final int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2; public static final int SSL_VERIFY_CLIENT_ONCE = 4; public static final int SSL_VERIFY_PEER_STRICT = (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT); public static final int SSL_OP_MICROSOFT_SESS_ID_BUG = 0x00000001; public static final int SSL_OP_NETSCAPE_CHALLENGE_BUG = 0x00000002; public static final int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008; public static final int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = 0x00000010; public static final int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020; public static final int SSL_OP_MSIE_SSLV2_RSA_PADDING = 0x00000040; public static final int SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080; public static final int SSL_OP_TLS_D5_BUG = 0x00000100; public static final int SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200; /* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added * in OpenSSL 0.9.6d. Usually (depending on the application protocol) * the workaround is not needed. Unfortunately some broken SSL/TLS * implementations cannot handle it at all, which is why we include * it in SSL_OP_ALL. */ public static final int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800; /* SSL_OP_ALL: various bug workarounds that should be rather harmless. * This used to be 0x000FFFFFL before 0.9.7. */ public static final int SSL_OP_ALL = 0x00000FFF; /* As server, disallow session resumption on renegotiation */ public static final int SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000; /* Don't use compression even if supported */ public static final int SSL_OP_NO_COMPRESSION = 0x00020000; /* Permit unsafe legacy renegotiation */ public static final int SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0x00040000; /* If set, always create a new key when using tmp_eddh parameters */ public static final int SSL_OP_SINGLE_ECDH_USE = 0x00080000; /* If set, always create a new key when using tmp_dh parameters */ public static final int SSL_OP_SINGLE_DH_USE = 0x00100000; /* Set to always use the tmp_rsa key when doing RSA operations, * even when this violates protocol specs */ public static final int SSL_OP_EPHEMERAL_RSA = 0x00200000; /* Set on servers to choose the cipher according to the server's * preferences */ public static final int SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000; /* If set, a server will allow a client to issue a SSLv3.0 version number * as latest version supported in the premaster secret, even when TLSv1.0 * (version 3.1) was announced in the client hello. Normally this is * forbidden to prevent version rollback attacks. */ public static final int SSL_OP_TLS_ROLLBACK_BUG = 0x00800000; public static final int SSL_OP_NO_SSLv2 = 0x01000000; public static final int SSL_OP_NO_SSLv3 = 0x02000000; public static final int SSL_OP_NO_TLSv1 = 0x04000000; /* The next flag deliberately changes the ciphertest, this is a check * for the PKCS#1 attack */ public static final int SSL_OP_PKCS1_CHECK_1 = 0x08000000; public static final int SSL_OP_PKCS1_CHECK_2 = 0x10000000; public static final int SSL_OP_NETSCAPE_CA_DN_BUG = 0x20000000; public static final int SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 0x40000000; public static final int SSL_CRT_FORMAT_UNDEF = 0; public static final int SSL_CRT_FORMAT_ASN1 = 1; public static final int SSL_CRT_FORMAT_TEXT = 2; public static final int SSL_CRT_FORMAT_PEM = 3; public static final int SSL_CRT_FORMAT_NETSCAPE = 4; public static final int SSL_CRT_FORMAT_PKCS12 = 5; public static final int SSL_CRT_FORMAT_SMIME = 6; public static final int SSL_CRT_FORMAT_ENGINE = 7; public static final int SSL_MODE_CLIENT = 0; public static final int SSL_MODE_SERVER = 1; public static final int SSL_MODE_COMBINED = 2; public static final int SSL_SHUTDOWN_TYPE_UNSET = 0; public static final int SSL_SHUTDOWN_TYPE_STANDARD = 1; public static final int SSL_SHUTDOWN_TYPE_UNCLEAN = 2; public static final int SSL_SHUTDOWN_TYPE_ACCURATE = 3; public static final int SSL_INFO_SESSION_ID = 0x0001; public static final int SSL_INFO_CIPHER = 0x0002; public static final int SSL_INFO_CIPHER_USEKEYSIZE = 0x0003; public static final int SSL_INFO_CIPHER_ALGKEYSIZE = 0x0004; public static final int SSL_INFO_CIPHER_VERSION = 0x0005; public static final int SSL_INFO_CIPHER_DESCRIPTION = 0x0006; public static final int SSL_INFO_PROTOCOL = 0x0007; /* To obtain the CountryName of the Client Certificate Issuer * use the SSL_INFO_CLIENT_I_DN + SSL_INFO_DN_COUNTRYNAME */ public static final int SSL_INFO_CLIENT_S_DN = 0x0010; public static final int SSL_INFO_CLIENT_I_DN = 0x0020; public static final int SSL_INFO_SERVER_S_DN = 0x0040; public static final int SSL_INFO_SERVER_I_DN = 0x0080; public static final int SSL_INFO_DN_COUNTRYNAME = 0x0001; public static final int SSL_INFO_DN_STATEORPROVINCENAME = 0x0002; public static final int SSL_INFO_DN_LOCALITYNAME = 0x0003; public static final int SSL_INFO_DN_ORGANIZATIONNAME = 0x0004; public static final int SSL_INFO_DN_ORGANIZATIONALUNITNAME = 0x0005; public static final int SSL_INFO_DN_COMMONNAME = 0x0006; public static final int SSL_INFO_DN_TITLE = 0x0007; public static final int SSL_INFO_DN_INITIALS = 0x0008; public static final int SSL_INFO_DN_GIVENNAME = 0x0009; public static final int SSL_INFO_DN_SURNAME = 0x000A; public static final int SSL_INFO_DN_DESCRIPTION = 0x000B; public static final int SSL_INFO_DN_UNIQUEIDENTIFIER = 0x000C; public static final int SSL_INFO_DN_EMAILADDRESS = 0x000D; public static final int SSL_INFO_CLIENT_M_VERSION = 0x0101; public static final int SSL_INFO_CLIENT_M_SERIAL = 0x0102; public static final int SSL_INFO_CLIENT_V_START = 0x0103; public static final int SSL_INFO_CLIENT_V_END = 0x0104; public static final int SSL_INFO_CLIENT_A_SIG = 0x0105; public static final int SSL_INFO_CLIENT_A_KEY = 0x0106; public static final int SSL_INFO_CLIENT_CERT = 0x0107; public static final int SSL_INFO_CLIENT_V_REMAIN = 0x0108; public static final int SSL_INFO_SERVER_M_VERSION = 0x0201; public static final int SSL_INFO_SERVER_M_SERIAL = 0x0202; public static final int SSL_INFO_SERVER_V_START = 0x0203; public static final int SSL_INFO_SERVER_V_END = 0x0204; public static final int SSL_INFO_SERVER_A_SIG = 0x0205; public static final int SSL_INFO_SERVER_A_KEY = 0x0206; public static final int SSL_INFO_SERVER_CERT = 0x0207; /* Return client certificate chain. * Add certificate chain number to that flag (0 ... verify depth) */ public static final int SSL_INFO_CLIENT_CERT_CHAIN = 0x0400; /* Return OpenSSL version number */ public static native int version(); /* Return OpenSSL version string */ public static native String versionString(); /** * Initialize OpenSSL support. * This function needs to be called once for the * lifetime of JVM. Library.init() has to be called before. * @param engine Support for external a Crypto Device ("engine"), * usually * a hardware accelerator card for crypto operations. * @return APR status code */ public static native int initialize(String engine); /** * Enable/Disable FIPS Mode. * * @param mode 1 - enable, 0 - disable * * @return FIPS_mode_set return code */ public static native int fipsModeSet(int mode); /** * Add content of the file to the PRNG * @param filename Filename containing random data. * If null the default file will be tested. * The seed file is $RANDFILE if that environment variable is * set, $HOME/.rnd otherwise. * In case both files are unavailable builtin * random seed generator is used. */ public static native boolean randLoad(String filename); /** * Writes a number of random bytes (currently 1024) to * file filename which can be used to initialize the PRNG * by calling randLoad in a later session. * @param filename Filename to save the data */ public static native boolean randSave(String filename); /** * Creates random data to filename * @param filename Filename to save the data * @param len The length of random sequence in bytes * @param base64 Output the data in Base64 encoded format */ public static native boolean randMake(String filename, int len, boolean base64); /** * Sets global random filename. * @param filename Filename to use. * If set it will be used for SSL initialization * and all contexts where explicitly not set. */ public static native void randSet(String filename); /** * Initialize new BIO * @param pool The pool to use. * @param callback BIOCallback to use * @return New BIO handle */ public static native long newBIO(long pool, BIOCallback callback) throws Exception; /** * Close BIO and dereference callback object * @param bio BIO to close and destroy. * @return APR Status code */ public static native int closeBIO(long bio); /** * Set global Password callback for obtaining passwords. * @param callback PasswordCallback implementation to use. */ public static native void setPasswordCallback(PasswordCallback callback); /** * Set global Password for decrypting certificates and keys. * @param password Password to use. */ public static native void setPassword(String password); /** * Generate temporary RSA key. *
    * Index can be one of: *
         * SSL_TMP_KEY_RSA_512
         * SSL_TMP_KEY_RSA_1024
         * SSL_TMP_KEY_RSA_2048
         * SSL_TMP_KEY_RSA_4096
         * 
    * By default 512 and 1024 keys are generated on startup. * You can use a low priority thread to generate them on the fly. * @param idx temporary key index. */ public static native boolean generateRSATempKey(int idx); /** * Load temporary DSA key from file *
    * Index can be one of: *
         * SSL_TMP_KEY_DH_512
         * SSL_TMP_KEY_DH_1024
         * SSL_TMP_KEY_DH_2048
         * SSL_TMP_KEY_DH_4096
         * 
    * @param idx temporary key index. * @param file File containing DH params. */ public static native boolean loadDSATempKey(int idx, String file); /** * Return last SSL error string */ public static native String getLastError(); /** * Return true if all the requested SSL_OP_* are supported by OpenSSL. * * Note that for versions of tcnative < 1.1.25, this method will * return true if and only if op= * {@link #SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION} and tcnative * supports that flag. * * @param op Bitwise-OR of all SSL_OP_* to test. * * @return true if all SSL_OP_* are supported by OpenSSL library. */ public static native boolean hasOp(int op); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Sockaddr.java0000644000175100017510000000254112271453221022541 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Sockaddr * * @author Mladen Turk */ public class Sockaddr { /** The pool to use... */ public long pool; /** The hostname */ public String hostname; /** Either a string of the port number or the service name for the port */ public String servname; /** The numeric port */ public int port; /** The family */ public int family; /** If multiple addresses were found by apr_sockaddr_info_get(), this * points to a representation of the next address. */ public long next; } tomcat7-7.0.52/java/org/apache/tomcat/jni/Local.java0000644000175100017510000000513012271453221022036 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Local socket * * @author Mladen Turk */ public class Local { /** * Create a socket. * @param path The address of the new socket. * @param cont The parent pool to use * @return The new socket that has been set up. */ public static native long create(String path, long cont) throws Exception; /** * Bind the socket to its associated port * @param sock The socket to bind * @param sa The socket address to bind to * This may be where we will find out if there is any other process * using the selected port. */ public static native int bind(long sock, long sa); /** * Listen to a bound socket for connections. * @param sock The socket to listen on * @param backlog The number of outstanding connections allowed in the sockets * listen queue. If this value is less than zero, for NT pipes * the number of instances is unlimited. * */ public static native int listen(long sock, int backlog); /** * Accept a new connection request * @param sock The socket we are listening on. * @return A copy of the socket that is connected to the socket that * made the connection request. This is the socket which should * be used for all future communication. */ public static native long accept(long sock) throws Exception; /** * Issue a connection request to a socket either on the same machine * or a different one. * @param sock The socket we wish to use for our side of the connection * @param sa The address of the machine we wish to connect to. * Unused for NT Pipes. */ public static native int connect(long sock, long sa); } tomcat7-7.0.52/java/org/apache/tomcat/jni/SSLSocket.java0000644000175100017510000000773712271453221022635 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** SSL Socket * * @author Mladen Turk */ public class SSLSocket { /** * Attach APR socket on a SSL connection. * @param ctx SSLContext to use. * @param sock APR Socket that already did physical connect or accept. * @return APR_STATUS code. */ public static native int attach(long ctx, long sock) throws Exception; /** * Do a SSL handshake. * @param thesocket The socket to use */ public static native int handshake(long thesocket); /** * Do a SSL renegotiation. * SSL supports per-directory re-configuration of SSL parameters. * This is implemented by performing an SSL renegotiation of the * re-configured parameters after the request is read, but before the * response is sent. In more detail: the renegotiation happens after the * request line and MIME headers were read, but _before_ the attached * request body is read. The reason simply is that in the HTTP protocol * usually there is no acknowledgment step between the headers and the * body (there is the 100-continue feature and the chunking facility * only), so Apache has no API hook for this step. * * @param thesocket The socket to use */ public static native int renegotiate(long thesocket); /** * Set Type of Client Certificate verification and Maximum depth of CA * Certificates in Client Certificate verification. *
    * This is used to change the verification level for a connection prior to * starting a re-negotiation. *
    * The following levels are available for level: *
         * SSL_CVERIFY_NONE           - No client Certificate is required at all
         * SSL_CVERIFY_OPTIONAL       - The client may present a valid Certificate
         * SSL_CVERIFY_REQUIRE        - The client has to present a valid
         *                              Certificate
         * SSL_CVERIFY_OPTIONAL_NO_CA - The client may present a valid Certificate
         *                              but it need not to be (successfully)
         *                              verifiable
         * 
    *
    * @param sock The socket to change. * @param level Type of Client Certificate verification. */ public static native void setVerify(long sock, int level, int depth); /** * Return SSL Info parameter as byte array. * * @param sock The socket to read the data from. * @param id Parameter id. * @return Byte array containing info id value. */ public static native byte[] getInfoB(long sock, int id) throws Exception; /** * Return SSL Info parameter as String. * * @param sock The socket to read the data from. * @param id Parameter id. * @return String containing info id value. */ public static native String getInfoS(long sock, int id) throws Exception; /** * Return SSL Info parameter as integer. * * @param sock The socket to read the data from. * @param id Parameter id. * @return Integer containing info id value or -1 on error. */ public static native int getInfoI(long sock, int id) throws Exception; } tomcat7-7.0.52/java/org/apache/tomcat/jni/Time.java0000644000175100017510000000425112271453221021705 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Time * * @author Mladen Turk */ public class Time { /** number of microseconds per second */ public static final long APR_USEC_PER_SEC = 1000000L; /** number of milliseconds per microsecond */ public static final long APR_MSEC_PER_USEC = 1000L; /** @return apr_time_t as a second */ public static long sec(long t) { return t / APR_USEC_PER_SEC; } /** @return apr_time_t as a msec */ public static long msec(long t) { return t / APR_MSEC_PER_USEC; } /** * number of microseconds since 00:00:00 January 1, 1970 UTC * @return the current time */ public static native long now(); /** * Formats dates in the RFC822 * format in an efficient manner. * @param t the time to convert */ public static native String rfc822(long t); /** * Formats dates in the ctime() format * in an efficient manner. * Unlike ANSI/ISO C ctime(), apr_ctime() does not include * a \n at the end of the string. * @param t the time to convert */ public static native String ctime(long t); /** * Sleep for the specified number of micro-seconds. *
    Warning : May sleep for longer than the specified time. * @param t desired amount of time to sleep. */ public static native void sleep(long t); } tomcat7-7.0.52/java/org/apache/tomcat/jni/Library.java0000644000175100017510000002063012271453221022412 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.jni; /** Library * * @author Mladen Turk */ public final class Library { /* Default library names */ private static String [] NAMES = {"tcnative-1", "libtcnative-1"}; /* * A handle to the unique Library singleton instance. */ private static Library _instance = null; private Library() throws Exception { boolean loaded = false; StringBuilder err = new StringBuilder(); for (int i = 0; i < NAMES.length; i++) { try { System.loadLibrary(NAMES[i]); loaded = true; } catch (Throwable t) { if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } String name = System.mapLibraryName(NAMES[i]); String path = System.getProperty("java.library.path"); String sep = System.getProperty("path.separator"); String [] paths = path.split(sep); for (int j=0; j 0) err.append(", "); err.append(t.getMessage()); } if (loaded) break; } if (!loaded) { err.append('('); err.append(System.getProperty("java.library.path")); err.append(')'); throw new UnsatisfiedLinkError(err.toString()); } } private Library(String libraryName) { System.loadLibrary(libraryName); } /* create global TCN's APR pool * This has to be the first call to TCN library. */ private static native boolean initialize(); /* destroy global TCN's APR pool * This has to be the last call to TCN library. */ public static native void terminate(); /* Internal function for loading APR Features */ private static native boolean has(int what); /* Internal function for loading APR Features */ private static native int version(int what); /* Internal function for loading APR sizes */ private static native int size(int what); /* TCN_MAJOR_VERSION */ public static int TCN_MAJOR_VERSION = 0; /* TCN_MINOR_VERSION */ public static int TCN_MINOR_VERSION = 0; /* TCN_PATCH_VERSION */ public static int TCN_PATCH_VERSION = 0; /* TCN_IS_DEV_VERSION */ public static int TCN_IS_DEV_VERSION = 0; /* APR_MAJOR_VERSION */ public static int APR_MAJOR_VERSION = 0; /* APR_MINOR_VERSION */ public static int APR_MINOR_VERSION = 0; /* APR_PATCH_VERSION */ public static int APR_PATCH_VERSION = 0; /* APR_IS_DEV_VERSION */ public static int APR_IS_DEV_VERSION = 0; /* TCN_VERSION_STRING */ public static native String versionString(); /* APR_VERSION_STRING */ public static native String aprVersionString(); /* APR Feature Macros */ public static boolean APR_HAVE_IPV6 = false; public static boolean APR_HAS_SHARED_MEMORY = false; public static boolean APR_HAS_THREADS = false; public static boolean APR_HAS_SENDFILE = false; public static boolean APR_HAS_MMAP = false; public static boolean APR_HAS_FORK = false; public static boolean APR_HAS_RANDOM = false; public static boolean APR_HAS_OTHER_CHILD = false; public static boolean APR_HAS_DSO = false; public static boolean APR_HAS_SO_ACCEPTFILTER = false; public static boolean APR_HAS_UNICODE_FS = false; public static boolean APR_HAS_PROC_INVOKED = false; public static boolean APR_HAS_USER = false; public static boolean APR_HAS_LARGE_FILES = false; public static boolean APR_HAS_XTHREAD_FILES = false; public static boolean APR_HAS_OS_UUID = false; /* Are we big endian? */ public static boolean APR_IS_BIGENDIAN = false; /* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible * to poll on files/pipes. */ public static boolean APR_FILES_AS_SOCKETS = false; /* This macro indicates whether or not EBCDIC is the native character set. */ public static boolean APR_CHARSET_EBCDIC = false; /* Is the TCP_NODELAY socket option inherited from listening sockets? */ public static boolean APR_TCP_NODELAY_INHERITED = false; /* Is the O_NONBLOCK flag inherited from listening sockets? */ public static boolean APR_O_NONBLOCK_INHERITED = false; public static int APR_SIZEOF_VOIDP; public static int APR_PATH_MAX; public static int APRMAXHOSTLEN; public static int APR_MAX_IOVEC_SIZE; public static int APR_MAX_SECS_TO_LINGER; public static int APR_MMAP_THRESHOLD; public static int APR_MMAP_LIMIT; /* return global TCN's APR pool */ public static native long globalPool(); /** * Setup any APR internal data structures. This MUST be the first function * called for any APR library. * @param libraryName the name of the library to load */ public static boolean initialize(String libraryName) throws Exception { if (_instance == null) { if (libraryName == null) _instance = new Library(); else _instance = new Library(libraryName); TCN_MAJOR_VERSION = version(0x01); TCN_MINOR_VERSION = version(0x02); TCN_PATCH_VERSION = version(0x03); TCN_IS_DEV_VERSION = version(0x04); APR_MAJOR_VERSION = version(0x11); APR_MINOR_VERSION = version(0x12); APR_PATCH_VERSION = version(0x13); APR_IS_DEV_VERSION = version(0x14); APR_SIZEOF_VOIDP = size(1); APR_PATH_MAX = size(2); APRMAXHOSTLEN = size(3); APR_MAX_IOVEC_SIZE = size(4); APR_MAX_SECS_TO_LINGER = size(5); APR_MMAP_THRESHOLD = size(6); APR_MMAP_LIMIT = size(7); APR_HAVE_IPV6 = has(0); APR_HAS_SHARED_MEMORY = has(1); APR_HAS_THREADS = has(2); APR_HAS_SENDFILE = has(3); APR_HAS_MMAP = has(4); APR_HAS_FORK = has(5); APR_HAS_RANDOM = has(6); APR_HAS_OTHER_CHILD = has(7); APR_HAS_DSO = has(8); APR_HAS_SO_ACCEPTFILTER = has(9); APR_HAS_UNICODE_FS = has(10); APR_HAS_PROC_INVOKED = has(11); APR_HAS_USER = has(12); APR_HAS_LARGE_FILES = has(13); APR_HAS_XTHREAD_FILES = has(14); APR_HAS_OS_UUID = has(15); APR_IS_BIGENDIAN = has(16); APR_FILES_AS_SOCKETS = has(17); APR_CHARSET_EBCDIC = has(18); APR_TCP_NODELAY_INHERITED = has(19); APR_O_NONBLOCK_INHERITED = has(20); if (APR_MAJOR_VERSION < 1) { throw new UnsatisfiedLinkError("Unsupported APR Version (" + aprVersionString() + ")"); } if (!APR_HAS_THREADS) { throw new UnsatisfiedLinkError("Missing APR_HAS_THREADS"); } } return initialize(); } } tomcat7-7.0.52/java/org/apache/tomcat/JarScanner.java0000644000175100017510000000341312271453632022262 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat; import java.util.Set; import javax.servlet.ServletContext; /** * Scans a web application and classloader hierarchy for JAR files. Uses * include TLD scanning and web-fragment.xml scanning. Uses a call-back * mechanism so the caller can process each JAR found. */ public interface JarScanner { /** * Scan the provided ServletContext and classloader for JAR files. Each JAR * file found will be passed to the callback handler to be processed. * * @param context The ServletContext - used to locate and access * WEB-INF/lib * @param classloader The classloader - used to access JARs not in * WEB-INF/lib * @param callback The handler to process any JARs found * @param jarsToSkip List of JARs to ignore */ public void scan(ServletContext context, ClassLoader classloader, JarScannerCallback callback, Set jarsToSkip); } tomcat7-7.0.52/java/org/apache/tomcat/JarScannerCallback.java0000644000175100017510000000221212271453632023673 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat; import java.io.File; import java.io.IOException; import java.net.JarURLConnection; public interface JarScannerCallback { /** * * @param urlConn * @throws IOException */ public void scan(JarURLConnection urlConn) throws IOException; public void scan(File file) throws IOException ; } tomcat7-7.0.52/java/org/apache/tomcat/websocket/0000755000175100017510000000000012301126367021352 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/websocket/WsRemoteEndpointBasic.java0000644000175100017510000000414512112654536026435 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import java.nio.ByteBuffer; import javax.websocket.EncodeException; import javax.websocket.RemoteEndpoint; public class WsRemoteEndpointBasic extends WsRemoteEndpointBase implements RemoteEndpoint.Basic { WsRemoteEndpointBasic(WsRemoteEndpointImplBase base) { super(base); } @Override public void sendText(String text) throws IOException { base.sendString(text); } @Override public void sendBinary(ByteBuffer data) throws IOException { base.sendBytes(data); } @Override public void sendText(String fragment, boolean isLast) throws IOException { base.sendPartialString(fragment, isLast); } @Override public void sendBinary(ByteBuffer partialByte, boolean isLast) throws IOException { base.sendPartialBytes(partialByte, isLast); } @Override public OutputStream getSendStream() throws IOException { return base.getSendStream(); } @Override public Writer getSendWriter() throws IOException { return base.getSendWriter(); } @Override public void sendObject(Object o) throws IOException, EncodeException { base.sendObject(o); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsIOException.java0000644000175100017510000000262112067161343024720 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import javax.websocket.CloseReason; /** * Allows the WebSocket implementation to throw an {@link IOException} that * includes a {@link CloseReason} specific to the error that can be passed back * to the client. */ public class WsIOException extends IOException { private static final long serialVersionUID = 1L; private final CloseReason closeReason; public WsIOException(CloseReason closeReason) { this.closeReason = closeReason; } public CloseReason getCloseReason() { return closeReason; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsFrameBase.java0000644000175100017510000006304612267550170024371 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.MessageHandler; import javax.websocket.PongMessage; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.Utf8Decoder; import org.apache.tomcat.util.res.StringManager; /** * Takes the ServletInputStream, processes the WebSocket frames it contains and * extracts the messages. WebSocket Pings received will be responded to * automatically without any action required by the application. */ public abstract class WsFrameBase { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); // Connection level attributes protected final WsSession wsSession; protected final byte[] inputBuffer; // Attributes for control messages // Control messages can appear in the middle of other messages so need // separate attributes private final ByteBuffer controlBufferBinary = ByteBuffer.allocate(125); private final CharBuffer controlBufferText = CharBuffer.allocate(125); // Attributes of the current message private final CharsetDecoder utf8DecoderControl = new Utf8Decoder(). onMalformedInput(CodingErrorAction.REPORT). onUnmappableCharacter(CodingErrorAction.REPORT); private final CharsetDecoder utf8DecoderMessage = new Utf8Decoder(). onMalformedInput(CodingErrorAction.REPORT). onUnmappableCharacter(CodingErrorAction.REPORT); private boolean continuationExpected = false; private boolean textMessage = false; private ByteBuffer messageBufferBinary; private CharBuffer messageBufferText; // Cache the message handler in force when the message starts so it is used // consistently for the entire message private MessageHandler binaryMsgHandler = null; private MessageHandler textMsgHandler = null; // Attributes of the current frame private boolean fin = false; private int rsv = 0; private byte opCode = 0; private final byte[] mask = new byte[4]; private int maskIndex = 0; private long payloadLength = 0; private long payloadWritten = 0; // Attributes tracking state private State state = State.NEW_FRAME; private volatile boolean open = true; private int readPos = 0; protected int writePos = 0; public WsFrameBase(WsSession wsSession) { inputBuffer = new byte[Constants.DEFAULT_BUFFER_SIZE]; messageBufferBinary = ByteBuffer.allocate(wsSession.getMaxBinaryMessageBufferSize()); messageBufferText = CharBuffer.allocate(wsSession.getMaxTextMessageBufferSize()); this.wsSession = wsSession; } protected void processInputBuffer() throws IOException { while (true) { wsSession.updateLastActive(); if (state == State.NEW_FRAME) { if (!processInitialHeader()) { break; } // If a close frame has been received, no further data should // have seen if (!open) { throw new IOException(sm.getString("wsFrame.closed")); } } if (state == State.PARTIAL_HEADER) { if (!processRemainingHeader()) { break; } } if (state == State.DATA) { if (!processData()) { break; } } } } /** * @return true if sufficient data was present to process all * of the initial header */ private boolean processInitialHeader() throws IOException { // Need at least two bytes of data to do this if (writePos - readPos < 2) { return false; } int b = inputBuffer[readPos++]; fin = (b & 0x80) > 0; rsv = (b & 0x70) >>> 4; if (rsv != 0) { // Note extensions may use rsv bits but currently no extensions are // supported throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.wrongRsv", Integer.valueOf(rsv)))); } opCode = (byte) (b & 0x0F); if (Util.isControl(opCode)) { if (!fin) { throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.controlFragmented"))); } if (opCode != Constants.OPCODE_PING && opCode != Constants.OPCODE_PONG && opCode != Constants.OPCODE_CLOSE) { throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.invalidOpCode", Integer.valueOf(opCode)))); } } else { if (continuationExpected) { if (opCode != Constants.OPCODE_CONTINUATION) { throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.noContinuation"))); } } else { try { if (opCode == Constants.OPCODE_BINARY) { // New binary message textMessage = false; int size = wsSession.getMaxBinaryMessageBufferSize(); if (size != messageBufferBinary.capacity()) { messageBufferBinary = ByteBuffer.allocate(size); } binaryMsgHandler = wsSession.getBinaryMessageHandler(); textMsgHandler = null; } else if (opCode == Constants.OPCODE_TEXT) { // New text message textMessage = true; int size = wsSession.getMaxTextMessageBufferSize(); if (size != messageBufferText.capacity()) { messageBufferText = CharBuffer.allocate(size); } binaryMsgHandler = null; textMsgHandler = wsSession.getTextMessageHandler(); } else { throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.invalidOpCode", Integer.valueOf(opCode)))); } } catch (IllegalStateException ise) { // Thrown if the session is already closed throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.sessionClosed"))); } } continuationExpected = !fin; } b = inputBuffer[readPos++]; // Client data must be masked if ((b & 0x80) == 0 && isMasked()) { throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.notMasked"))); } payloadLength = b & 0x7F; state = State.PARTIAL_HEADER; return true; } protected abstract boolean isMasked(); /** * @return true if sufficient data was present to complete the * processing of the header */ private boolean processRemainingHeader() throws IOException { // Ignore the 2 bytes already read. 4 for the mask int headerLength; if (isMasked()) { headerLength = 4; } else { headerLength = 0; } // Add additional bytes depending on length if (payloadLength == 126) { headerLength += 2; } else if (payloadLength == 127) { headerLength += 8; } if (writePos - readPos < headerLength) { return false; } // Calculate new payload length if necessary if (payloadLength == 126) { payloadLength = byteArrayToLong(inputBuffer, readPos, 2); readPos += 2; } else if (payloadLength == 127) { payloadLength = byteArrayToLong(inputBuffer, readPos, 8); readPos += 8; } if (Util.isControl(opCode)) { if (payloadLength > 125) { throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.controlPayloadTooBig", Long.valueOf(payloadLength)))); } if (!fin) { throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.controlNoFin"))); } } if (isMasked()) { System.arraycopy(inputBuffer, readPos, mask, 0, 4); readPos += 4; } state = State.DATA; return true; } private boolean processData() throws IOException { boolean result; if (Util.isControl(opCode)) { result = processDataControl(); } else if (textMessage) { if (textMsgHandler == null) { result = swallowInput(); } else { result = processDataText(); } } else { if (binaryMsgHandler == null) { result = swallowInput(); } else { result = processDataBinary(); } } checkRoomPayload(); return result; } private boolean processDataControl() throws IOException { if (!appendPayloadToMessage(controlBufferBinary)) { return false; } controlBufferBinary.flip(); if (opCode == Constants.OPCODE_CLOSE) { open = false; String reason = null; int code = CloseCodes.NORMAL_CLOSURE.getCode(); if (controlBufferBinary.remaining() == 1) { controlBufferBinary.clear(); // Payload must be zero or greater than 2 throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.oneByteCloseCode"))); } if (controlBufferBinary.remaining() > 1) { code = controlBufferBinary.getShort(); if (controlBufferBinary.remaining() > 0) { CoderResult cr = utf8DecoderControl.decode( controlBufferBinary, controlBufferText, true); if (cr.isError()) { controlBufferBinary.clear(); controlBufferText.clear(); throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.invalidUtf8Close"))); } // There will be no overflow as the output buffer is big // enough. There will be no underflow as all the data is // passed to the decoder in a single call. controlBufferText.flip(); reason = controlBufferText.toString(); } } wsSession.onClose(new CloseReason(Util.getCloseCode(code), reason)); } else if (opCode == Constants.OPCODE_PING) { if (wsSession.isOpen()) { wsSession.getBasicRemote().sendPong(controlBufferBinary); } } else if (opCode == Constants.OPCODE_PONG) { MessageHandler.Whole mhPong = wsSession.getPongMessageHandler(); if (mhPong != null) { try { mhPong.onMessage(new WsPongMessage(controlBufferBinary)); } catch (Throwable t) { handleThrowableOnSend(t); } finally { controlBufferBinary.clear(); } } } else { // Should have caught this earlier but just in case... controlBufferBinary.clear(); throw new WsIOException(new CloseReason( CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.invalidOpCode", Integer.valueOf(opCode)))); } controlBufferBinary.clear(); newFrame(); return true; } @SuppressWarnings("unchecked") private void sendMessageText(boolean last) throws WsIOException { if (textMsgHandler instanceof WrappedMessageHandler) { long maxMessageSize = ((WrappedMessageHandler) textMsgHandler).getMaxMessageSize(); if (maxMessageSize > -1 && messageBufferText.remaining() > maxMessageSize) { throw new WsIOException(new CloseReason(CloseCodes.TOO_BIG, sm.getString("wsFrame.messageTooBig", Long.valueOf(messageBufferText.remaining()), Long.valueOf(maxMessageSize)))); } } try { if (textMsgHandler instanceof MessageHandler.Partial) { ((MessageHandler.Partial) textMsgHandler).onMessage( messageBufferText.toString(), last); } else { // Caller ensures last == true if this branch is used ((MessageHandler.Whole) textMsgHandler).onMessage( messageBufferText.toString()); } } catch (Throwable t) { handleThrowableOnSend(t); } finally { messageBufferText.clear(); } } private boolean processDataText() throws IOException { // Copy the available data to the buffer while (!appendPayloadToMessage(messageBufferBinary)) { // Frame not complete - we ran out of something // Convert bytes to UTF-8 messageBufferBinary.flip(); while (true) { CoderResult cr = utf8DecoderMessage.decode( messageBufferBinary, messageBufferText, false); if (cr.isError()) { throw new WsIOException(new CloseReason( CloseCodes.NOT_CONSISTENT, sm.getString("wsFrame.invalidUtf8"))); } else if (cr.isOverflow()) { // Ran out of space in text buffer - flush it if (usePartial()) { messageBufferText.flip(); sendMessageText(false); messageBufferText.clear(); } else { throw new WsIOException(new CloseReason( CloseCodes.TOO_BIG, sm.getString("wsFrame.textMessageTooBig"))); } } else if (cr.isUnderflow()) { // Need more input // Compact what we have to create as much space as possible messageBufferBinary.compact(); // What did we run out of? if (readPos == writePos) { // Ran out of input data - get some more return false; } else { // Ran out of message buffer - exit inner loop and // refill break; } } } } messageBufferBinary.flip(); boolean last = false; // Frame is fully received // Convert bytes to UTF-8 while (true) { CoderResult cr = utf8DecoderMessage.decode(messageBufferBinary, messageBufferText, last); if (cr.isError()) { throw new WsIOException(new CloseReason( CloseCodes.NOT_CONSISTENT, sm.getString("wsFrame.invalidUtf8"))); } else if (cr.isOverflow()) { // Ran out of space in text buffer - flush it if (usePartial()) { messageBufferText.flip(); sendMessageText(false); messageBufferText.clear(); } else { throw new WsIOException(new CloseReason( CloseCodes.TOO_BIG, sm.getString("wsFrame.textMessageTooBig"))); } } else if (cr.isUnderflow() & !last) { // End of frame and possible message as well. if (continuationExpected) { // If partial messages are supported, send what we have // managed to decode if (usePartial()) { messageBufferText.flip(); sendMessageText(false); messageBufferText.clear(); } messageBufferBinary.compact(); newFrame(); // Process next frame return true; } else { // Make sure coder has flushed all output last = true; } } else { // End of message messageBufferText.flip(); sendMessageText(true); newMessage(); return true; } } } private boolean processDataBinary() throws IOException { // Copy the available data to the buffer while (!appendPayloadToMessage(messageBufferBinary)) { // Frame not complete - what did we run out of? if (readPos == writePos) { // Ran out of input data - get some more return false; } else { // Ran out of message buffer - flush it if (!usePartial()) { CloseReason cr = new CloseReason(CloseCodes.TOO_BIG, sm.getString("wsFrame.bufferTooSmall", Integer.valueOf( messageBufferBinary.capacity()), Long.valueOf(payloadLength))); throw new WsIOException(cr); } messageBufferBinary.flip(); ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit()); copy.put(messageBufferBinary); copy.flip(); sendMessageBinary(copy, false); messageBufferBinary.clear(); } } // Frame is fully received // Send the message if either: // - partial messages are supported // - the message is complete if (usePartial() || !continuationExpected) { messageBufferBinary.flip(); ByteBuffer copy = ByteBuffer.allocate(messageBufferBinary.limit()); copy.put(messageBufferBinary); copy.flip(); sendMessageBinary(copy, !continuationExpected); messageBufferBinary.clear(); } if (continuationExpected) { // More data for this message expected, start a new frame newFrame(); } else { // Message is complete, start a new message newMessage(); } return true; } private void handleThrowableOnSend(Throwable t) throws WsIOException { ExceptionUtils.handleThrowable(t); wsSession.getLocal().onError(wsSession, t); CloseReason cr = new CloseReason(CloseCodes.CLOSED_ABNORMALLY, sm.getString("wsFrame.ioeTriggeredClose")); throw new WsIOException(cr); } @SuppressWarnings("unchecked") private void sendMessageBinary(ByteBuffer msg, boolean last) throws WsIOException { if (binaryMsgHandler instanceof WrappedMessageHandler) { long maxMessageSize = ((WrappedMessageHandler) binaryMsgHandler).getMaxMessageSize(); if (maxMessageSize > -1 && msg.remaining() > maxMessageSize) { throw new WsIOException(new CloseReason(CloseCodes.TOO_BIG, sm.getString("wsFrame.messageTooBig", Long.valueOf(msg.remaining()), Long.valueOf(maxMessageSize)))); } } try { if (binaryMsgHandler instanceof MessageHandler.Partial) { ((MessageHandler.Partial) binaryMsgHandler).onMessage(msg, last); } else { // Caller ensures last == true if this branch is used ((MessageHandler.Whole) binaryMsgHandler).onMessage(msg); } } catch(Throwable t) { handleThrowableOnSend(t); } } private void newMessage() { messageBufferBinary.clear(); messageBufferText.clear(); utf8DecoderMessage.reset(); continuationExpected = false; newFrame(); } private void newFrame() { if (readPos == writePos) { readPos = 0; writePos = 0; } maskIndex = 0; payloadWritten = 0; state = State.NEW_FRAME; // These get reset in processInitialHeader() // fin, rsv, opCode, payloadLength, mask checkRoomHeaders(); } private void checkRoomHeaders() { // Is the start of the current frame too near the end of the input // buffer? if (inputBuffer.length - readPos < 131) { // Limit based on a control frame with a full payload makeRoom(); } } private void checkRoomPayload() { if (inputBuffer.length - readPos - payloadLength + payloadWritten < 0) { makeRoom(); } } private void makeRoom() { System.arraycopy(inputBuffer, readPos, inputBuffer, 0, writePos - readPos); writePos = writePos - readPos; readPos = 0; } private boolean usePartial() { if (Util.isControl(opCode)) { return false; } else if (textMessage) { return textMsgHandler instanceof MessageHandler.Partial; } else { // Must be binary return binaryMsgHandler instanceof MessageHandler.Partial; } } private boolean appendPayloadToMessage(ByteBuffer dest) { if (isMasked()) { while (payloadWritten < payloadLength && readPos < writePos && dest.hasRemaining()) { byte b = (byte) ((inputBuffer[readPos] ^ mask[maskIndex]) & 0xFF); maskIndex++; if (maskIndex == 4) { maskIndex = 0; } readPos++; payloadWritten++; dest.put(b); } return (payloadWritten == payloadLength); } else { long toWrite = Math.min( payloadLength - payloadWritten, writePos - readPos); toWrite = Math.min(toWrite, dest.remaining()); dest.put(inputBuffer, readPos, (int) toWrite); readPos += toWrite; payloadWritten += toWrite; return (payloadWritten == payloadLength); } } private boolean swallowInput() { long toSkip = Math.min(payloadLength - payloadWritten, writePos - readPos); readPos += toSkip; payloadWritten += toSkip; if (payloadWritten == payloadLength) { if (continuationExpected) { newFrame(); } else { newMessage(); } return true; } else { return false; } } protected static long byteArrayToLong(byte[] b, int start, int len) throws IOException { if (len > 8) { throw new IOException(sm.getString("wsFrame.byteToLongFail", Long.valueOf(len))); } int shift = 0; long result = 0; for (int i = start + len - 1; i >= start; i--) { result = result + ((b[i] & 0xFF) << shift); shift += 8; } return result; } protected boolean isOpen() { return open; } private static enum State { NEW_FRAME, PARTIAL_HEADER, DATA } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/SendHandlerToCompletionHandler.java0000644000175100017510000000265312124155776030256 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.nio.channels.CompletionHandler; import javax.websocket.SendHandler; import javax.websocket.SendResult; public class SendHandlerToCompletionHandler implements CompletionHandler { private SendHandler handler; public SendHandlerToCompletionHandler(SendHandler handler) { this.handler = handler; } @Override public void completed(Long result, Void attachment) { handler.onResult(new SendResult()); } @Override public void failed(Throwable exc, Void attachment) { handler.onResult(new SendResult(exc)); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WrappedMessageHandler.java0000644000175100017510000000174212162573554026437 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import javax.websocket.MessageHandler; public interface WrappedMessageHandler { long getMaxMessageSize(); MessageHandler getWrappedHandler(); } tomcat7-7.0.52/java/org/apache/tomcat/websocket/MessageHandlerResultType.java0000644000175100017510000000162112166436036027146 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; public enum MessageHandlerResultType { BINARY, TEXT, PONG } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/0000755000175100017510000000000012301126367022660 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsMappingResult.java0000644000175100017510000000252212125404332026623 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.util.Map; import javax.websocket.server.ServerEndpointConfig; class WsMappingResult { private final ServerEndpointConfig config; private final Map pathParams; WsMappingResult(ServerEndpointConfig config, Map pathParams) { this.config = config; this.pathParams = pathParams; } ServerEndpointConfig getConfig() { return config; } Map getPathParams() { return pathParams; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/UpgradeUtil.java0000644000175100017510000002270312272162743025761 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.websocket.Endpoint; import javax.websocket.Extension; import javax.websocket.HandshakeResponse; import javax.websocket.server.ServerEndpointConfig; import org.apache.catalina.connector.RequestFacade; import org.apache.tomcat.util.codec.binary.Base64; import org.apache.tomcat.websocket.Constants; import org.apache.tomcat.websocket.WsHandshakeResponse; import org.apache.tomcat.websocket.pojo.PojoEndpointServer; public class UpgradeUtil { private static final byte[] WS_ACCEPT = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes( StandardCharsets.ISO_8859_1); private static final Queue sha1Helpers = new ConcurrentLinkedQueue(); private UpgradeUtil() { // Utility class. Hide default constructor. } /** * Checks to see if this is an HTTP request that includes a valid upgrade * request to web socket. *

    * Note: RFC 2616 does not limit HTTP upgrade to GET requests but the Java * WebSocket spec 1.0, section 8.2 implies such a limitation and RFC * 6455 section 4.1 requires that a WebSocket Upgrade uses GET. */ public static boolean isWebSocketUpgradeRequest(ServletRequest request, ServletResponse response) { return ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) && headerContainsToken((HttpServletRequest) request, Constants.UPGRADE_HEADER_NAME, Constants.UPGRADE_HEADER_VALUE) && "GET".equals(((HttpServletRequest) request).getMethod())); } public static void doUpgrade(WsServerContainer sc, HttpServletRequest req, HttpServletResponse resp, ServerEndpointConfig sec, Map pathParams) throws ServletException, IOException { // Validate the rest of the headers and reject the request if that // validation fails String key; String subProtocol = null; List extensions = Collections.emptyList(); if (!headerContainsToken(req, Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE)) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } if (!headerContainsToken(req, Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE)) { resp.setStatus(426); resp.setHeader(Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE); return; } key = req.getHeader(Constants.WS_KEY_HEADER_NAME); if (key == null) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } // Origin check String origin = req.getHeader("Origin"); if (!sec.getConfigurator().checkOrigin(origin)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } // Sub-protocols List subProtocols = getTokensFromHeader(req, "Sec-WebSocket-Protocol"); subProtocol = sec.getConfigurator().getNegotiatedSubprotocol( sec.getSubprotocols(), subProtocols); // Extensions // Currently no extensions are supported by this implementation // If we got this far, all is good. Accept the connection. resp.setHeader(Constants.UPGRADE_HEADER_NAME, Constants.UPGRADE_HEADER_VALUE); resp.setHeader(Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE); resp.setHeader(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, getWebSocketAccept(key)); if (subProtocol != null && subProtocol.length() > 0) { // RFC6455 4.2.2 explicitly states "" is not valid here resp.setHeader("Sec-WebSocket-Protocol", subProtocol); } if (!extensions.isEmpty()) { StringBuilder sb = new StringBuilder(); Iterator iter = extensions.iterator(); // There must be at least one sb.append(iter.next()); while (iter.hasNext()) { sb.append(','); sb.append(iter.next().getName()); } resp.setHeader("Sec-WebSocket-Extensions", sb.toString()); } WsHandshakeRequest wsRequest = new WsHandshakeRequest(req); WsHandshakeResponse wsResponse = new WsHandshakeResponse(); WsPerSessionServerEndpointConfig perSessionServerEndpointConfig = new WsPerSessionServerEndpointConfig(sec); sec.getConfigurator().modifyHandshake(perSessionServerEndpointConfig, wsRequest, wsResponse); wsRequest.finished(); // Add any additional headers for (Entry> entry : wsResponse.getHeaders().entrySet()) { for (String headerValue: entry.getValue()) { resp.addHeader(entry.getKey(), headerValue); } } Endpoint ep; try { Class clazz = sec.getEndpointClass(); if (Endpoint.class.isAssignableFrom(clazz)) { ep = (Endpoint) sec.getConfigurator().getEndpointInstance( clazz); } else { ep = new PojoEndpointServer(); } } catch (InstantiationException e) { throw new ServletException(e); } // Small hack until the Servlet API provides a way to do this. ServletRequest inner = req; // Unwrap the request while (inner instanceof ServletRequestWrapper) { inner = ((ServletRequestWrapper) inner).getRequest(); } if (inner instanceof RequestFacade) { WsHttpUpgradeHandler wsHandler = ((RequestFacade) inner).upgrade(WsHttpUpgradeHandler.class); wsHandler.preInit(ep, perSessionServerEndpointConfig, sc, wsRequest, subProtocol, pathParams, req.isSecure()); } else { throw new ServletException("Upgrade failed"); } } /* * This only works for tokens. Quoted strings need more sophisticated * parsing. */ private static boolean headerContainsToken(HttpServletRequest req, String headerName, String target) { Enumeration headers = req.getHeaders(headerName); while (headers.hasMoreElements()) { String header = headers.nextElement(); String[] tokens = header.split(","); for (String token : tokens) { if (target.equalsIgnoreCase(token.trim())) { return true; } } } return false; } /* * This only works for tokens. Quoted strings need more sophisticated * parsing. */ private static List getTokensFromHeader(HttpServletRequest req, String headerName) { List result = new ArrayList(); Enumeration headers = req.getHeaders(headerName); while (headers.hasMoreElements()) { String header = headers.nextElement(); String[] tokens = header.split(","); for (String token : tokens) { result.add(token.trim()); } } return result; } private static String getWebSocketAccept(String key) throws ServletException { MessageDigest sha1Helper = sha1Helpers.poll(); if (sha1Helper == null) { try { sha1Helper = MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException e) { throw new ServletException(e); } } sha1Helper.reset(); sha1Helper.update(key.getBytes(StandardCharsets.ISO_8859_1)); String result = Base64.encodeBase64String(sha1Helper.digest(WS_ACCEPT)); sha1Helpers.add(sha1Helper); return result; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsHttpUpgradeHandler.java0000644000175100017510000002143412251655650027574 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.io.EOFException; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpSession; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.DeploymentException; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import org.apache.coyote.http11.upgrade.AbstractServletInputStream; import org.apache.coyote.http11.upgrade.AbstractServletOutputStream; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.coyote.http11.upgrade.servlet31.ReadListener; import org.apache.coyote.http11.upgrade.servlet31.WebConnection; import org.apache.coyote.http11.upgrade.servlet31.WriteListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.websocket.WsIOException; import org.apache.tomcat.websocket.WsSession; /** * Servlet 3.1 HTTP upgrade handler for WebSocket connections. */ public class WsHttpUpgradeHandler implements HttpUpgradeHandler { private static final Log log = LogFactory.getLog(WsHttpUpgradeHandler.class); private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private final ClassLoader applicationClassLoader; private Endpoint ep; private EndpointConfig endpointConfig; private WsServerContainer webSocketContainer; private WsHandshakeRequest handshakeRequest; private String subProtocol; private Map pathParameters; private boolean secure; private WebConnection connection; private WsSession wsSession; public WsHttpUpgradeHandler() { applicationClassLoader = Thread.currentThread().getContextClassLoader(); } public void preInit(Endpoint ep, EndpointConfig endpointConfig, WsServerContainer wsc, WsHandshakeRequest handshakeRequest, String subProtocol, Map pathParameters, boolean secure) { this.ep = ep; this.endpointConfig = endpointConfig; this.webSocketContainer = wsc; this.handshakeRequest = handshakeRequest; this.subProtocol = subProtocol; this.pathParameters = pathParameters; this.secure = secure; } @Override public void init(WebConnection connection) { if (ep == null) { throw new IllegalStateException( sm.getString("wsHttpUpgradeHandler.noPreInit")); } this.connection = connection; AbstractServletInputStream sis; AbstractServletOutputStream sos; try { sis = connection.getInputStream(); sos = connection.getOutputStream(); } catch (IOException e) { throw new IllegalStateException(e); } String httpSessionId = null; Object session = handshakeRequest.getHttpSession(); if (session != null ) { httpSessionId = ((HttpSession) session).getId(); } // Need to call onOpen using the web application's class loader // Create the frame using the application's class loader so it can pick // up application specific config from the ServerContainerImpl Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { WsRemoteEndpointImplServer wsRemoteEndpointServer = new WsRemoteEndpointImplServer(sos, webSocketContainer); wsSession = new WsSession(ep, wsRemoteEndpointServer, webSocketContainer, handshakeRequest.getRequestURI(), handshakeRequest.getParameterMap(), handshakeRequest.getQueryString(), handshakeRequest.getUserPrincipal(), httpSessionId, subProtocol, pathParameters, secure, endpointConfig); WsFrameServer wsFrame = new WsFrameServer( sis, wsSession); sos.setWriteListener( new WsWriteListener(this, wsRemoteEndpointServer)); ep.onOpen(wsSession, endpointConfig); webSocketContainer.registerSession(ep, wsSession); sis.setReadListener(new WsReadListener(this, wsFrame)); } catch (DeploymentException e) { throw new IllegalArgumentException(e); } finally { t.setContextClassLoader(cl); } } @Override public void destroy() { if (connection != null) { try { connection.close(); } catch (Exception e) { log.error(sm.getString("wsHttpUpgradeHandler.destroyFailed"), e); } } } private void onError(Throwable throwable) { // Need to call onError using the web application's class loader Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { ep.onError(wsSession, throwable); } finally { t.setContextClassLoader(cl); } } private void close(CloseReason cr) { /* * Any call to this method is a result of a problem reading from the * client. At this point that state of the connection is unknown. * Attempt to send a close frame to the client and then close the socket * immediately. There is no point in waiting for a close frame from the * client because there is no guarantee that we can recover from * whatever messed up state the client put the connection into. */ wsSession.onClose(cr); } private static class WsReadListener implements ReadListener { private final WsHttpUpgradeHandler wsProtocolHandler; private final WsFrameServer wsFrame; private WsReadListener(WsHttpUpgradeHandler wsProtocolHandler, WsFrameServer wsFrame) { this.wsProtocolHandler = wsProtocolHandler; this.wsFrame = wsFrame; } @Override public void onDataAvailable() { try { wsFrame.onDataAvailable(); } catch (WsIOException ws) { wsProtocolHandler.close(ws.getCloseReason()); } catch (EOFException eof) { CloseReason cr = new CloseReason( CloseCodes.CLOSED_ABNORMALLY, eof.getMessage()); wsProtocolHandler.close(cr); } catch (IOException ioe) { onError(ioe); CloseReason cr = new CloseReason( CloseCodes.CLOSED_ABNORMALLY, ioe.getMessage()); wsProtocolHandler.close(cr); } } @Override public void onAllDataRead() { // Will never happen with WebSocket throw new IllegalStateException(); } @Override public void onError(Throwable throwable) { wsProtocolHandler.onError(throwable); } } private static class WsWriteListener implements WriteListener { private final WsHttpUpgradeHandler wsProtocolHandler; private final WsRemoteEndpointImplServer wsRemoteEndpointServer; private WsWriteListener(WsHttpUpgradeHandler wsProtocolHandler, WsRemoteEndpointImplServer wsRemoteEndpointServer) { this.wsProtocolHandler = wsProtocolHandler; this.wsRemoteEndpointServer = wsRemoteEndpointServer; } @Override public void onWritePossible() { // Triggered by the poller so this isn't the same thread that // triggered the write so no need for a dispatch wsRemoteEndpointServer.onWritePossible(false); } @Override public void onError(Throwable throwable) { wsProtocolHandler.onError(throwable); wsRemoteEndpointServer.close(); } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsSci.java0000644000175100017510000001532712216555616024573 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; import javax.websocket.ContainerProvider; import javax.websocket.DeploymentException; import javax.websocket.Endpoint; import javax.websocket.server.ServerApplicationConfig; import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpointConfig; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Registers an interest in any class that is annotated with * {@link ServerEndpoint} so that Endpoint can be published via the WebSocket * server. */ @HandlesTypes({ServerEndpoint.class, ServerApplicationConfig.class, Endpoint.class}) public class WsSci implements ServletContainerInitializer { private static boolean logMessageWritten = false; private static final Log log = LogFactory.getLog(WsSci.class); private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); @Override public void onStartup(Set> clazzes, ServletContext ctx) throws ServletException { if (!isJava7OrLater()) { // The WebSocket implementation requires Java 7 so don't initialise // it if Java 7 is not available. if (!logMessageWritten) { logMessageWritten = true; log.info(sm.getString("sci.noWebSocketSupport")); } return; } WsServerContainer sc = init(ctx, true); if (clazzes == null || clazzes.size() == 0) { return; } // Group the discovered classes by type Set serverApplicationConfigs = new HashSet(); Set> scannedEndpointClazzes = new HashSet>(); Set> scannedPojoEndpoints = new HashSet>(); try { // wsPackage is "javax.websocket." String wsPackage = ContainerProvider.class.getName(); wsPackage = wsPackage.substring(0, wsPackage.lastIndexOf('.') + 1); for (Class clazz : clazzes) { int modifiers = clazz.getModifiers(); if (!Modifier.isPublic(modifiers) || Modifier.isAbstract(modifiers)) { // Non-public or abstract - skip it. continue; } // Protect against scanning the WebSocket API JARs if (clazz.getName().startsWith(wsPackage)) { continue; } if (ServerApplicationConfig.class.isAssignableFrom(clazz)) { serverApplicationConfigs.add( (ServerApplicationConfig) clazz.newInstance()); } if (Endpoint.class.isAssignableFrom(clazz)) { @SuppressWarnings("unchecked") Class endpoint = (Class) clazz; scannedEndpointClazzes.add(endpoint); } if (clazz.isAnnotationPresent(ServerEndpoint.class)) { scannedPojoEndpoints.add(clazz); } } } catch (InstantiationException e) { throw new ServletException(e); } catch (IllegalAccessException e) { throw new ServletException(e); } // Filter the results Set filteredEndpointConfigs = new HashSet(); Set> filteredPojoEndpoints = new HashSet>(); if (serverApplicationConfigs.isEmpty()) { filteredPojoEndpoints.addAll(scannedPojoEndpoints); } else { for (ServerApplicationConfig config : serverApplicationConfigs) { Set configFilteredEndpoints = config.getEndpointConfigs(scannedEndpointClazzes); if (configFilteredEndpoints != null) { filteredEndpointConfigs.addAll(configFilteredEndpoints); } Set> configFilteredPojos = config.getAnnotatedEndpointClasses( scannedPojoEndpoints); if (configFilteredPojos != null) { filteredPojoEndpoints.addAll(configFilteredPojos); } } } try { // Deploy endpoints for (ServerEndpointConfig config : filteredEndpointConfigs) { sc.addEndpoint(config); } // Deploy POJOs for (Class clazz : filteredPojoEndpoints) { sc.addEndpoint(clazz); } } catch (DeploymentException e) { throw new ServletException(e); } } static WsServerContainer init(ServletContext servletContext, boolean initBySciMechanism) { WsServerContainer sc = new WsServerContainer(servletContext); servletContext.setAttribute( Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE, sc); servletContext.addListener(new WsSessionListener(sc)); // Can't register the ContextListener again if the ContextListener is // calling this method if (initBySciMechanism) { servletContext.addListener(new WsContextListener()); } return sc; } private static boolean isJava7OrLater() { try { Class.forName("java.nio.channels.AsynchronousSocketChannel"); } catch (ClassNotFoundException e) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsFrameServer.java0000644000175100017510000000425312203413046026254 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.io.EOFException; import java.io.IOException; import org.apache.coyote.http11.upgrade.AbstractServletInputStream; import org.apache.tomcat.websocket.WsFrameBase; import org.apache.tomcat.websocket.WsSession; public class WsFrameServer extends WsFrameBase { private final AbstractServletInputStream sis; private final Object connectionReadLock = new Object(); public WsFrameServer(AbstractServletInputStream sis, WsSession wsSession) { super(wsSession); this.sis = sis; } /** * Called when there is data in the ServletInputStream to process. */ public void onDataAvailable() throws IOException { synchronized (connectionReadLock) { while (isOpen() && sis.isReady()) { // Fill up the input buffer with as much data as we can int read = sis.read( inputBuffer, writePos, inputBuffer.length - writePos); if (read == 0) { return; } if (read == -1) { throw new EOFException(); } writePos += read; processInputBuffer(); } } } @Override protected boolean isMasked() { // Data is from the client so it should be masked return true; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsWriteTimeout.java0000644000175100017510000001045512234166134026504 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicInteger; import org.apache.tomcat.websocket.BackgroundProcess; import org.apache.tomcat.websocket.BackgroundProcessManager; /** * Provides timeouts for asynchronous web socket writes. On the server side we * only have access to {@link javax.servlet.ServletOutputStream} and * {@link javax.servlet.ServletInputStream} so there is no way to set a timeout * for writes to the client. */ public class WsWriteTimeout implements BackgroundProcess { private final Set endpoints = new ConcurrentSkipListSet(new EndpointComparator()); private final AtomicInteger count = new AtomicInteger(0); private int backgroundProcessCount = 0; private volatile int processPeriod = 1; @Override public void backgroundProcess() { // This method gets called once a second. backgroundProcessCount ++; if (backgroundProcessCount >= processPeriod) { backgroundProcessCount = 0; long now = System.currentTimeMillis(); Iterator iter = endpoints.iterator(); while (iter.hasNext()) { WsRemoteEndpointImplServer endpoint = iter.next(); if (endpoint.getTimeoutExpiry() < now) { // Background thread, not the thread that triggered the // write so no need to use a dispatch endpoint.onTimeout(false); } else { // Endpoints are ordered by timeout expiry so if this point // is reached there is no need to check the remaining // endpoints break; } } } } @Override public void setProcessPeriod(int period) { this.processPeriod = period; } /** * {@inheritDoc} * * The default value is 1 which means asynchronous write timeouts are * processed every 1 second. */ @Override public int getProcessPeriod() { return processPeriod; } public void register(WsRemoteEndpointImplServer endpoint) { boolean result = endpoints.add(endpoint); if (result) { int newCount = count.incrementAndGet(); if (newCount == 1) { BackgroundProcessManager.getInstance().register(this); } } } public void unregister(WsRemoteEndpointImplServer endpoint) { boolean result = endpoints.remove(endpoint); if (result) { int newCount = count.decrementAndGet(); if (newCount == 0) { BackgroundProcessManager.getInstance().unregister(this); } } } /** * Note: this comparator imposes orderings that are inconsistent with equals */ private static class EndpointComparator implements Comparator { @Override public int compare(WsRemoteEndpointImplServer o1, WsRemoteEndpointImplServer o2) { long t1 = o1.getTimeoutExpiry(); long t2 = o2.getTimeoutExpiry(); if (t1 < t2) { return -1; } else if (t1 == t2) { return 0; } else { return 1; } } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsServerContainer.java0000644000175100017510000004663512254570601027165 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import javax.servlet.DispatcherType; import javax.servlet.FilterRegistration; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.DeploymentException; import javax.websocket.Encoder; import javax.websocket.Endpoint; import javax.websocket.server.ServerContainer; import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpointConfig; import javax.websocket.server.ServerEndpointConfig.Configurator; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.websocket.WsSession; import org.apache.tomcat.websocket.WsWebSocketContainer; import org.apache.tomcat.websocket.pojo.PojoEndpointServer; import org.apache.tomcat.websocket.pojo.PojoMethodMapping; /** * Provides a per class loader (i.e. per web application) instance of a * ServerContainer. Web application wide defaults may be configured by setting * the following servlet context initialisation parameters to the desired * values. *

      *
    • {@link Constants#BINARY_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM}
    • *
    • {@link Constants#TEXT_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM}
    • *
    */ public class WsServerContainer extends WsWebSocketContainer implements ServerContainer { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private static final CloseReason AUTHENTICATED_HTTP_SESSION_CLOSED = new CloseReason(CloseCodes.VIOLATED_POLICY, "This connection was established under an authenticated " + "HTTP session that has ended."); private final WsWriteTimeout wsWriteTimeout = new WsWriteTimeout(); private final ServletContext servletContext; private final Map configExactMatchMap = new ConcurrentHashMap(); private final ConcurrentHashMap> configTemplateMatchMap = new ConcurrentHashMap>(); private volatile boolean enforceNoAddAfterHandshake = org.apache.tomcat.websocket.Constants.STRICT_SPEC_COMPLIANCE; private volatile boolean addAllowed = true; private final ConcurrentHashMap> authenticatedSessions = new ConcurrentHashMap>(); private final ExecutorService executorService; private volatile boolean endpointsRegistered = false; WsServerContainer(ServletContext servletContext) { this.servletContext = servletContext; // Configure servlet context wide defaults String value = servletContext.getInitParameter( Constants.BINARY_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM); if (value != null) { setDefaultMaxBinaryMessageBufferSize(Integer.parseInt(value)); } value = servletContext.getInitParameter( Constants.TEXT_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM); if (value != null) { setDefaultMaxTextMessageBufferSize(Integer.parseInt(value)); } value = servletContext.getInitParameter( Constants.ENFORCE_NO_ADD_AFTER_HANDSHAKE_CONTEXT_INIT_PARAM); if (value != null) { setEnforceNoAddAfterHandshake(Boolean.parseBoolean(value)); } // Executor config int executorCoreSize = 0; int executorMaxSize = 10; long executorKeepAliveTimeSeconds = 60; value = servletContext.getInitParameter( Constants.EXECUTOR_CORE_SIZE_INIT_PARAM); if (value != null) { executorCoreSize = Integer.parseInt(value); } value = servletContext.getInitParameter( Constants.EXECUTOR_MAX_SIZE_INIT_PARAM); if (value != null) { executorMaxSize = Integer.parseInt(value); } value = servletContext.getInitParameter( Constants.EXECUTOR_KEEPALIVETIME_SECONDS_INIT_PARAM); if (value != null) { executorKeepAliveTimeSeconds = Long.parseLong(value); } FilterRegistration.Dynamic fr = servletContext.addFilter( "Tomcat WebSocket (JSR356) Filter", new WsFilter()); fr.setAsyncSupported(true); EnumSet types = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD); fr.addMappingForUrlPatterns(types, true, "/*"); // Use a per web application executor for any threads the the WebSocket // server code needs to create. Group all of the threads under a single // ThreadGroup. StringBuffer threadGroupName = new StringBuffer("WebSocketServer-"); if ("".equals(servletContext.getContextPath())) { threadGroupName.append("ROOT"); } else { threadGroupName.append(servletContext.getContextPath()); } ThreadGroup threadGroup = new ThreadGroup(threadGroupName.toString()); WsThreadFactory wsThreadFactory = new WsThreadFactory(threadGroup); executorService = new ThreadPoolExecutor(executorCoreSize, executorMaxSize, executorKeepAliveTimeSeconds, TimeUnit.SECONDS, new LinkedBlockingQueue(), wsThreadFactory); } /** * Published the provided endpoint implementation at the specified path with * the specified configuration. {@link #WsServerContainer(ServletContext)} * must be called before calling this method. * * @param sec The configuration to use when creating endpoint instances * @throws DeploymentException */ @Override public void addEndpoint(ServerEndpointConfig sec) throws DeploymentException { if (enforceNoAddAfterHandshake && !addAllowed) { throw new DeploymentException( sm.getString("serverContainer.addNotAllowed")); } if (servletContext == null) { throw new DeploymentException( sm.getString("serverContainer.servletContextMissing")); } String path = sec.getPath(); UriTemplate uriTemplate = new UriTemplate(path); if (uriTemplate.hasParameters()) { Integer key = Integer.valueOf(uriTemplate.getSegmentCount()); SortedSet templateMatches = configTemplateMatchMap.get(key); if (templateMatches == null) { // Ensure that if concurrent threads execute this block they // both end up using the same TreeSet instance templateMatches = new TreeSet( TemplatePathMatchComparator.getInstance()); configTemplateMatchMap.putIfAbsent(key, templateMatches); templateMatches = configTemplateMatchMap.get(key); } if (!templateMatches.add(new TemplatePathMatch(sec, uriTemplate))) { // Duplicate uriTemplate; throw new DeploymentException( sm.getString("serverContainer.duplicatePaths", path)); } } else { // Exact match ServerEndpointConfig old = configExactMatchMap.put(path, sec); if (old != null) { // Duplicate path mappings throw new DeploymentException( sm.getString("serverContainer.duplicatePaths", path)); } } endpointsRegistered = true; } /** * Provides the equivalent of {@link #addEndpoint(ServerEndpointConfig)} * for publishing plain old java objects (POJOs) that have been annotated as * WebSocket endpoints. * * @param pojo The annotated POJO */ @Override public void addEndpoint(Class pojo) throws DeploymentException { ServerEndpoint annotation = pojo.getAnnotation(ServerEndpoint.class); if (annotation == null) { throw new DeploymentException( sm.getString("serverContainer.missingAnnotation", pojo.getName())); } String path = annotation.value(); // Validate encoders validateEncoders(annotation.encoders()); // Method mapping PojoMethodMapping methodMapping = new PojoMethodMapping(pojo, annotation.decoders(), path); // ServerEndpointConfig ServerEndpointConfig sec; Class configuratorClazz = annotation.configurator(); Configurator configurator = null; if (!configuratorClazz.equals(Configurator.class)) { try { configurator = annotation.configurator().newInstance(); } catch (InstantiationException e) { throw new DeploymentException(sm.getString( "serverContainer.configuratorFail", annotation.configurator().getName(), pojo.getClass().getName()), e); } catch (IllegalAccessException e) { throw new DeploymentException(sm.getString( "serverContainer.configuratorFail", annotation.configurator().getName(), pojo.getClass().getName()), e); } } sec = ServerEndpointConfig.Builder.create(pojo, path). decoders(Arrays.asList(annotation.decoders())). encoders(Arrays.asList(annotation.encoders())). subprotocols(Arrays.asList(annotation.subprotocols())). configurator(configurator). build(); sec.getUserProperties().put( PojoEndpointServer.POJO_METHOD_MAPPING_KEY, methodMapping); addEndpoint(sec); } boolean areEndpointsRegistered() { return endpointsRegistered; } public void doUpgrade(HttpServletRequest request, HttpServletResponse response, ServerEndpointConfig sec, Map pathParams) throws ServletException, IOException { UpgradeUtil.doUpgrade(this, request, response, sec, pathParams); } public WsMappingResult findMapping(String path) { // Prevent registering additional endpoints once the first attempt has // been made to use one if (addAllowed) { addAllowed = false; } // Check an exact match. Simple case as there are no templates. ServerEndpointConfig sec = configExactMatchMap.get(path); if (sec != null) { return new WsMappingResult(sec, Collections. emptyMap()); } // No exact match. Need to look for template matches. UriTemplate pathUriTemplate = null; try { pathUriTemplate = new UriTemplate(path); } catch (DeploymentException e) { // Path is not valid so can't be matched to a WebSocketEndpoint return null; } // Number of segments has to match Integer key = Integer.valueOf(pathUriTemplate.getSegmentCount()); SortedSet templateMatches = configTemplateMatchMap.get(key); if (templateMatches == null) { // No templates with an equal number of segments so there will be // no matches return null; } // List is in alphabetical order of normalised templates. // Correct match is the first one that matches. Map pathParams = null; for (TemplatePathMatch templateMatch : templateMatches) { pathParams = templateMatch.getUriTemplate().match(pathUriTemplate); if (pathParams != null) { sec = templateMatch.getConfig(); break; } } if (sec == null) { // No match return null; } if (!PojoEndpointServer.class.isAssignableFrom(sec.getEndpointClass())) { // Need to make path params available to POJO sec.getUserProperties().put( PojoEndpointServer.POJO_PATH_PARAM_KEY, pathParams); } return new WsMappingResult(sec, pathParams); } public boolean isEnforceNoAddAfterHandshake() { return enforceNoAddAfterHandshake; } public void setEnforceNoAddAfterHandshake( boolean enforceNoAddAfterHandshake) { this.enforceNoAddAfterHandshake = enforceNoAddAfterHandshake; } protected WsWriteTimeout getTimeout() { return wsWriteTimeout; } /** * {@inheritDoc} * * Overridden to make it visible to other classes in this package. */ @Override protected void registerSession(Endpoint endpoint, WsSession wsSession) { super.registerSession(endpoint, wsSession); if (wsSession.isOpen() && wsSession.getUserPrincipal() != null && wsSession.getHttpSessionId() != null) { registerAuthenticatedSession(wsSession, wsSession.getHttpSessionId()); } } /** * {@inheritDoc} * * Overridden to make it visible to other classes in this package. */ @Override protected void unregisterSession(Endpoint endpoint, WsSession wsSession) { if (wsSession.getUserPrincipal() != null && wsSession.getHttpSessionId() != null) { unregisterAuthenticatedSession(wsSession, wsSession.getHttpSessionId()); } super.unregisterSession(endpoint, wsSession); } private void registerAuthenticatedSession(WsSession wsSession, String httpSessionId) { Set wsSessions = authenticatedSessions.get(httpSessionId); if (wsSessions == null) { wsSessions = Collections.newSetFromMap( new ConcurrentHashMap()); authenticatedSessions.putIfAbsent(httpSessionId, wsSessions); wsSessions = authenticatedSessions.get(httpSessionId); } wsSessions.add(wsSession); } private void unregisterAuthenticatedSession(WsSession wsSession, String httpSessionId) { Set wsSessions = authenticatedSessions.get(httpSessionId); // wsSessions will be null if the HTTP session has ended if (wsSessions != null) { wsSessions.remove(wsSession); } } public void closeAuthenticatedSession(String httpSessionId) { Set wsSessions = authenticatedSessions.remove(httpSessionId); if (wsSessions != null && !wsSessions.isEmpty()) { for (WsSession wsSession : wsSessions) { try { wsSession.close(AUTHENTICATED_HTTP_SESSION_CLOSED); } catch (IOException e) { // Any IOExceptions during close will have been caught and the // onError method called. } } } } ExecutorService getExecutorService() { return executorService; } void shutdownExecutor() { if (executorService == null) { return; } executorService.shutdown(); try { executorService.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { // Ignore the interruption and carry on } } private static void validateEncoders(Class[] encoders) throws DeploymentException { for (Class encoder : encoders) { // Need to instantiate decoder to ensure it is valid and that // deployment can be failed if it is not @SuppressWarnings("unused") Encoder instance; try { encoder.newInstance(); } catch(InstantiationException e) { throw new DeploymentException(sm.getString( "serverContainer.encoderFail", encoder.getName()), e); } catch (IllegalAccessException e) { throw new DeploymentException(sm.getString( "serverContainer.encoderFail", encoder.getName()), e); } } } private static class TemplatePathMatch { private final ServerEndpointConfig config; private final UriTemplate uriTemplate; public TemplatePathMatch(ServerEndpointConfig config, UriTemplate uriTemplate) { this.config = config; this.uriTemplate = uriTemplate; } public ServerEndpointConfig getConfig() { return config; } public UriTemplate getUriTemplate() { return uriTemplate; } } /** * This Comparator implementation is thread-safe so only create a single * instance. */ private static class TemplatePathMatchComparator implements Comparator { private static final TemplatePathMatchComparator INSTANCE = new TemplatePathMatchComparator(); public static TemplatePathMatchComparator getInstance() { return INSTANCE; } private TemplatePathMatchComparator() { // Hide default constructor } @Override public int compare(TemplatePathMatch tpm1, TemplatePathMatch tpm2) { return tpm1.getUriTemplate().getNormalizedPath().compareTo( tpm2.getUriTemplate().getNormalizedPath()); } } private static class WsThreadFactory implements ThreadFactory { private final ThreadGroup tg; private final AtomicLong count = new AtomicLong(0); private WsThreadFactory(ThreadGroup tg) { this.tg = tg; } @Override public Thread newThread(Runnable r) { Thread t = new Thread(tg, r); t.setName(tg.getName() + "-" + count.incrementAndGet()); return t; } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsContextListener.java0000644000175100017510000000433112234166134027171 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * In normal usage, this {@link ServletContextListener} does not need to be * explicitly configured as the {@link WsSci} performs all the necessary * bootstrap and installs this listener in the {@link ServletContext}. If the * {@link WsSci} is disabled, this listener must be added manually to every * {@link ServletContext} that uses WebSocket to bootstrap the * {@link WsServerContainer} correctly. */ public class WsContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { ServletContext sc = sce.getServletContext(); // Don't trigger WebSocket initialization if a WebSocket Server // Container is already present if (sc.getAttribute(Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE) == null) { WsSci.init(sce.getServletContext(), false); } } @Override public void contextDestroyed(ServletContextEvent sce) { ServletContext sc = sce.getServletContext(); Object obj = sc.getAttribute(Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE); if (obj instanceof WsServerContainer) { ((WsServerContainer) obj).shutdownExecutor(); ((WsServerContainer) obj).destroy(); } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/Constants.java0000644000175100017510000000402312234166134025477 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; /** * Internal implementation constants. */ public class Constants { protected static final String PACKAGE_NAME = Constants.class.getPackage().getName(); public static final String BINARY_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM = "org.apache.tomcat.websocket.binaryBufferSize"; public static final String TEXT_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM = "org.apache.tomcat.websocket.textBufferSize"; public static final String ENFORCE_NO_ADD_AFTER_HANDSHAKE_CONTEXT_INIT_PARAM = "org.apache.tomcat.websocket.noAddAfterHandshake"; // Executor configuration public static final String EXECUTOR_CORE_SIZE_INIT_PARAM = "org.apache.tomcat.websocket.executorCoreSize"; public static final String EXECUTOR_MAX_SIZE_INIT_PARAM = "org.apache.tomcat.websocket.executorMaxSize"; public static final String EXECUTOR_KEEPALIVETIME_SECONDS_INIT_PARAM = "org.apache.tomcat.websocket.executorKeepAliveTimeSeconds"; public static final String SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE = "javax.websocket.server.ServerContainer"; private Constants() { // Hide default constructor } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/LocalStrings.properties0000644000175100017510000000612512252426655027416 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. sci.noWebSocketSupport=JSR 356 WebSocket (Java WebSocket 1.0) support is not available when running on Java 6. To suppress this message, run Tomcat on Java 7, remove the WebSocket JARs from $CATALINA_HOME/lib or add the WebSocketJARs to the tomcat.util.scan.DefaultJarScanner.jarsToSkip property in $CATALINA_BASE/conf/catalina.properties. Note that the deprecated Tomcat 7 WebSocket API will be available. serverContainer.addNotAllowed=No further Endpoints may be registered once an attempt has been made to use one of the previously registered endpoints serverContainer.configuratorFail=Failed to create configurator of type [{0}] for POJO of type [{1}] serverContainer.duplicatePaths=Multiple Endpoints may not be deployed to the same path [{0}] serverContainer.encoderFail=Unable to create encoder of type [{0}] serverContainer.endpointDeploy=Endpoint class [{0}] deploying to path [{1}] in ServletContext [{2}] serverContainer.missingAnnotation=Cannot deploy POJO class [{0}] as it is not annotated with @ServerEndpoint serverContainer.missingEndpoint=An Endpoint instance has been request for path [{0}] but no matching Endpoint class was found serverContainer.pojoDeploy=POJO class [{0}] deploying to path [{1}] in ServletContext [{2}] serverContainer.servletContextMismatch=Attempted to register a POJO annotated for WebSocket at path [{0}] in the ServletContext with context path [{1}] when the WebSocket ServerContainer is allocated to the ServletContext with context path [{2}] serverContainer.servletContextMissing=No ServletContext was specified uriTemplate.duplicateParameter=The parameter [{0}] appears more than once in the path which is not permitted uriTemplate.emptySegment=The path [{0}] contains one or more empty segments which are is not permitted uriTemplate.invalidPath=The path [{0}] is not valid. uriTemplate.invalidSegment=The segment [{0}] is not valid in the provided path [{1}] wsHttpUpgradeHandler.destroyFailed=Failed to close WebConnection while destroying the WebSocket HttpUpgradeHandler wsHttpUpgradeHandler.noPreInit=The preInit() method must be called to configure the WebSocket HttpUpgradeHandler before the container calls init(). Usually, this means the Servlet that created the WsHttpUpgradeHandler instance should also call preInit() wsRemoteEndpointServer.closeFailed=Failed to close the ServletOutputStream connection cleanlytomcat7-7.0.52/java/org/apache/tomcat/websocket/server/package-info.java0000644000175100017510000000172612077027473026065 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** * Server-side specific implementation classes. These are in a separate package * to make packaging a pure client JAR simpler. */ package org.apache.tomcat.websocket.server;tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/UriTemplate.java0000644000175100017510000001333612213425510025756 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.websocket.DeploymentException; import org.apache.tomcat.util.res.StringManager; /** * Extracts path parameters from URIs used to create web socket connections * using the URI template defined for the associated Endpoint. */ public class UriTemplate { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private final String normalized; private final List segments = new ArrayList(); private final boolean hasParameters; public UriTemplate(String path) throws DeploymentException { if (path == null || path.length() ==0 || !path.startsWith("/")) { throw new DeploymentException( sm.getString("uriTemplate.invalidPath", path)); } StringBuilder normalized = new StringBuilder(path.length()); Set paramNames = new HashSet(); // Include empty segments. String[] segments = path.split("/", -1); int paramCount = 0; int segmentCount = 0; for (int i = 0; i < segments.length; i++) { String segment = segments[i]; if (segment.length() == 0) { if (i == 0 || (i == segments.length - 1 && paramCount == 0)) { // Ignore the first empty segment as the path must always // start with '/' // Ending with a '/' is also OK for instances used for // matches but not for parameterised templates. continue; } else { // As per EG discussion, all other empty segments are // invalid throw new IllegalArgumentException(sm.getString( "uriTemplate.emptySegment", path)); } } normalized.append('/'); int index = -1; if (segment.startsWith("{") && segment.endsWith("}")) { index = segmentCount; segment = segment.substring(1, segment.length() - 1); normalized.append('{'); normalized.append(paramCount++); normalized.append('}'); if (!paramNames.add(segment)) { throw new IllegalArgumentException(sm.getString( "uriTemplate.duplicateParameter", segment)); } } else { if (segment.contains("{") || segment.contains("}")) { throw new IllegalArgumentException(sm.getString( "uriTemplate.invalidSegment", segment, path)); } normalized.append(segment); } this.segments.add(new Segment(index, segment)); segmentCount++; } this.normalized = normalized.toString(); this.hasParameters = paramCount > 0; } public Map match(UriTemplate candidate) { Map result = new HashMap(); // Should not happen but for safety if (candidate.getSegmentCount() != getSegmentCount()) { return null; } Iterator candidateSegments = candidate.getSegments().iterator(); Iterator targetSegments = segments.iterator(); while (candidateSegments.hasNext()) { Segment candidateSegment = candidateSegments.next(); Segment targetSegment = targetSegments.next(); if (targetSegment.getParameterIndex() == -1) { // Not a parameter - values must match if (!targetSegment.getValue().equals( candidateSegment.getValue())) { // Not a match. Stop here return null; } } else { // Parameter result.put(targetSegment.getValue(), candidateSegment.getValue()); } } return result; } public boolean hasParameters() { return hasParameters; } public int getSegmentCount() { return segments.size(); } public String getNormalizedPath() { return normalized; } private List getSegments() { return segments; } private static class Segment { private final int parameterIndex; private final String value; public Segment(int parameterIndex, String value) { this.parameterIndex = parameterIndex; this.value = value; } public int getParameterIndex() { return parameterIndex; } public String getValue() { return value; } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsFilter.java0000644000175100017510000000573312254402750025272 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Handles the initial HTTP connection for WebSocket connections. */ public class WsFilter implements Filter { private WsServerContainer sc; @Override public void init(FilterConfig filterConfig) throws ServletException { sc = (WsServerContainer) filterConfig.getServletContext().getAttribute( Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // This filter only needs to handle WebSocket upgrade requests if (!sc.areEndpointsRegistered() || !UpgradeUtil.isWebSocketUpgradeRequest(request, response)) { chain.doFilter(request, response); return; } // HTTP request with an upgrade header for WebSocket present HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; // Check to see if this WebSocket implementation has a matching mapping String path; String pathInfo = req.getPathInfo(); if (pathInfo == null) { path = req.getServletPath(); } else { path = req.getServletPath() + pathInfo; } WsMappingResult mappingResult = sc.findMapping(path); if (mappingResult == null) { // No endpoint registered for the requested path. Let the // application handle it (it might redirect or forward for example) chain.doFilter(request, response); return; } UpgradeUtil.doUpgrade(sc, req, resp, mappingResult.getConfig(), mappingResult.getPathParams()); } @Override public void destroy() { // NO-OP } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsRemoteEndpointImplServer.java0000644000175100017510000002107412236024426031006 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.io.EOFException; import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import javax.websocket.SendHandler; import javax.websocket.SendResult; import org.apache.coyote.http11.upgrade.AbstractServletOutputStream; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.websocket.WsRemoteEndpointImplBase; /** * This is the server side {@link javax.websocket.RemoteEndpoint} implementation * - i.e. what the server uses to send data to the client. Communication is over * a {@link javax.servlet.ServletOutputStream}. */ public class WsRemoteEndpointImplServer extends WsRemoteEndpointImplBase { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private static final Log log = LogFactory.getLog(WsHttpUpgradeHandler.class); private static final Queue onResultRunnables = new ConcurrentLinkedQueue(); private final AbstractServletOutputStream sos; private final WsWriteTimeout wsWriteTimeout; private final ExecutorService executorService; private volatile SendHandler handler = null; private volatile ByteBuffer[] buffers = null; private volatile long timeoutExpiry = -1; private volatile boolean close; public WsRemoteEndpointImplServer(AbstractServletOutputStream sos, WsServerContainer serverContainer) { this.sos = sos; this.wsWriteTimeout = serverContainer.getTimeout(); this.executorService = serverContainer.getExecutorService(); } @Override protected final boolean isMasked() { return false; } @Override protected void doWrite(SendHandler handler, ByteBuffer... buffers) { this.handler = handler; this.buffers = buffers; // This is definitely the same thread that triggered the write so a // dispatch will be required. onWritePossible(true); } public void onWritePossible(boolean useDispatch) { boolean complete = true; try { // If this is false there will be a call back when it is true while (sos.isReady()) { complete = true; for (ByteBuffer buffer : buffers) { if (buffer.hasRemaining()) { complete = false; sos.write(buffer.array(), buffer.arrayOffset(), buffer.limit()); buffer.position(buffer.limit()); break; } } if (complete) { wsWriteTimeout.unregister(this); clearHandler(null, useDispatch); if (close) { close(); } break; } } } catch (IOException ioe) { wsWriteTimeout.unregister(this); clearHandler(ioe, useDispatch); close(); } if (!complete) { // Async write is in progress long timeout = getSendTimeout(); if (timeout > 0) { // Register with timeout thread timeoutExpiry = timeout + System.currentTimeMillis(); wsWriteTimeout.register(this); } } } @Override protected void doClose() { if (handler != null) { // close() can be triggered by a wide range of scenarios. It is far // simpler just to always use a dispatch than it is to try and track // whether or not this method was called by the same thread that // triggered the write clearHandler(new EOFException(), true); } try { sos.close(); } catch (IOException e) { if (log.isInfoEnabled()) { log.info(sm.getString("wsRemoteEndpointServer.closeFailed"), e); } } wsWriteTimeout.unregister(this); } protected long getTimeoutExpiry() { return timeoutExpiry; } /* * Currently this is only called from the background thread so we could just * call clearHandler() with useDispatch == false but the method parameter * was added in case other callers started to use this method to make sure * that those callers think through what the correct value of useDispatch is * for them. */ protected void onTimeout(boolean useDispatch) { if (handler != null) { clearHandler(new SocketTimeoutException(), useDispatch); } close(); } /** * * @param t The throwable associated with any error that * occurred * @param useDispatch Should {@link SendHandler#onResult(SendResult)} be * called from a new thread, keeping in mind the * requirements of * {@link javax.websocket.RemoteEndpoint.Async} */ private void clearHandler(Throwable t, boolean useDispatch) { // Setting the result marks this (partial) message as // complete which means the next one may be sent which // could update the value of the handler. Therefore, keep a // local copy before signalling the end of the (partial) // message. SendHandler sh = handler; handler = null; if (sh != null) { if (useDispatch) { OnResultRunnable r = onResultRunnables.poll(); if (r == null) { r = new OnResultRunnable(onResultRunnables); } r.init(sh, t); if (executorService == null || executorService.isShutdown()) { // Can't use the executor so call the runnable directly. // This may not be strictly specification compliant in all // cases but during shutdown only close messages are going // to be sent so there should not be the issue of nested // calls leading to stack overflow as described in bug // 55715. The issues with nested calls was the reason for // the separate thread requirement in the specification. r.run(); } else { executorService.execute(r); } } else { if (t == null) { sh.onResult(new SendResult()); } else { sh.onResult(new SendResult(t)); } } } } private static class OnResultRunnable implements Runnable { private final Queue queue; private volatile SendHandler sh; private volatile Throwable t; private OnResultRunnable(Queue queue) { this.queue = queue; } private void init(SendHandler sh, Throwable t) { this.sh = sh; this.t = t; } @Override public void run() { if (t == null) { sh.onResult(new SendResult()); } else { sh.onResult(new SendResult(t)); } t = null; sh = null; // Return the Runnable to the queue when it has been finished with // Note if this method takes an age to finish there shouldn't be any // thread safety issues as the fields are cleared above. queue.add(this); } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsSessionListener.java0000644000175100017510000000263512163341603027172 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class WsSessionListener implements HttpSessionListener{ private final WsServerContainer wsServerContainer; public WsSessionListener(WsServerContainer wsServerContainer) { this.wsServerContainer = wsServerContainer; } @Override public void sessionCreated(HttpSessionEvent se) { // NO-OP } @Override public void sessionDestroyed(HttpSessionEvent se) { wsServerContainer.closeAuthenticatedSession(se.getSession().getId()); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsPerSessionServerEndpointConfig.java0000644000175100017510000000530512233457045032154 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.websocket.Decoder; import javax.websocket.Encoder; import javax.websocket.Extension; import javax.websocket.server.ServerEndpointConfig; /** * Wraps the provided {@link ServerEndpointConfig} and provides a per session * view - the difference being that the map returned by {@link * #getUserProperties()} is unique to this instance rather than shared with the * wrapped {@link ServerEndpointConfig}. */ class WsPerSessionServerEndpointConfig implements ServerEndpointConfig { private final ServerEndpointConfig perEndpointConfig; private final Map perSessionUserProperties = new ConcurrentHashMap(); WsPerSessionServerEndpointConfig(ServerEndpointConfig perEndpointConfig) { this.perEndpointConfig = perEndpointConfig; perSessionUserProperties.putAll(perEndpointConfig.getUserProperties()); } @Override public List> getEncoders() { return perEndpointConfig.getEncoders(); } @Override public List> getDecoders() { return perEndpointConfig.getDecoders(); } @Override public Map getUserProperties() { return perSessionUserProperties; } @Override public Class getEndpointClass() { return perEndpointConfig.getEndpointClass(); } @Override public String getPath() { return perEndpointConfig.getPath(); } @Override public List getSubprotocols() { return perEndpointConfig.getSubprotocols(); } @Override public List getExtensions() { return perEndpointConfig.getExtensions(); } @Override public Configurator getConfigurator() { return perEndpointConfig.getConfigurator(); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/WsHandshakeRequest.java0000644000175100017510000001060612203443675027304 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.net.URI; import java.net.URISyntaxException; import java.security.Principal; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import javax.websocket.server.HandshakeRequest; /** * Represents the request that this session was opened under. */ public class WsHandshakeRequest implements HandshakeRequest { private final URI requestUri; private final Map> parameterMap; private final String queryString; private final Principal userPrincipal; private final Map> headers; private final Object httpSession; private volatile HttpServletRequest request; public WsHandshakeRequest(HttpServletRequest request) { this.request = request; queryString = request.getQueryString(); userPrincipal = request.getUserPrincipal(); httpSession = request.getSession(false); // URI StringBuilder sb = new StringBuilder(request.getRequestURI()); if (queryString != null) { sb.append("?"); sb.append(queryString); } try { requestUri = new URI(sb.toString()); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } // ParameterMap Map originalParameters = request.getParameterMap(); Map> newParameters = new HashMap>(originalParameters.size()); for (Entry entry : originalParameters.entrySet()) { newParameters.put(entry.getKey(), Collections.unmodifiableList( Arrays.asList(entry.getValue()))); } parameterMap = Collections.unmodifiableMap(newParameters); // Headers Map> newHeaders = new HashMap>(); Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); newHeaders.put(headerName, Collections.unmodifiableList( Collections.list(request.getHeaders(headerName)))); } headers = Collections.unmodifiableMap(newHeaders); } @Override public URI getRequestURI() { return requestUri; } @Override public Map> getParameterMap() { return parameterMap; } @Override public String getQueryString() { return queryString; } @Override public Principal getUserPrincipal() { return userPrincipal; } @Override public Map> getHeaders() { return headers; } @Override public boolean isUserInRole(String role) { if (request == null) { throw new IllegalStateException(); } return request.isUserInRole(role); } @Override public Object getHttpSession() { return httpSession; } /** * Called when the HandshakeRequest is no longer required. Since an instance * of this class retains a reference to the current HttpServletRequest that * reference needs to be cleared as the HttpServletRequest may be reused. * * There is no reason for instances of this class to be accessed once the * handshake has been completed. */ void finished() { request = null; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/server/DefaultServerEndpointConfigurator.java0000644000175100017510000000464112203443675032374 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.server; import java.util.ArrayList; import java.util.List; import javax.websocket.Extension; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig; public class DefaultServerEndpointConfigurator extends ServerEndpointConfig.Configurator { @Override public T getEndpointInstance(Class clazz) throws InstantiationException { try { return clazz.newInstance(); } catch (IllegalAccessException e) { InstantiationException ie = new InstantiationException(); ie.initCause(e); throw ie; } } @Override public String getNegotiatedSubprotocol(List supported, List requested) { for (String request : requested) { if (supported.contains(request)) { return request; } } return ""; } @Override public List getNegotiatedExtensions(List installed, List requested) { List result = new ArrayList(); for (Extension request : requested) { if (installed.contains(request)) { result.add(request); } } return result; } @Override public boolean checkOrigin(String originHeaderValue) { return true; } @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { // NO-OP } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java0000644000175100017510000010441012245654566027116 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import javax.websocket.DeploymentException; import javax.websocket.EncodeException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; import javax.websocket.RemoteEndpoint; import javax.websocket.SendHandler; import javax.websocket.SendResult; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.Utf8Encoder; import org.apache.tomcat.util.res.StringManager; public abstract class WsRemoteEndpointImplBase implements RemoteEndpoint { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); // Milliseconds so this is 20 seconds private static final long DEFAULT_BLOCKING_SEND_TIMEOUT = 20 * 1000; public static final String BLOCKING_SEND_TIMEOUT_PROPERTY = "org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT"; private final Log log = LogFactory.getLog(WsRemoteEndpointImplBase.class); private final StateMachine stateMachine = new StateMachine(); private boolean messagePartInProgress = false; private final Queue messagePartQueue = new ArrayDeque(); private final Object messagePartLock = new Object(); // State private volatile boolean closed = false; private boolean fragmented = false; private boolean nextFragmented = false; private boolean text = false; private boolean nextText = false; // Max size of WebSocket header is 14 bytes private final ByteBuffer headerBuffer = ByteBuffer.allocate(14); private final ByteBuffer outputBuffer = ByteBuffer.allocate(8192); private final CharsetEncoder encoder = new Utf8Encoder(); private final ByteBuffer encoderBuffer = ByteBuffer.allocate(8192); private final AtomicBoolean batchingAllowed = new AtomicBoolean(false); private volatile long sendTimeout = -1; private WsSession wsSession; private List encoderEntries = new ArrayList(); public long getSendTimeout() { return sendTimeout; } public void setSendTimeout(long timeout) { this.sendTimeout = timeout; } @Override public void setBatchingAllowed(boolean batchingAllowed) throws IOException { boolean oldValue = this.batchingAllowed.getAndSet(batchingAllowed); if (oldValue && !batchingAllowed) { flushBatch(); } } @Override public boolean getBatchingAllowed() { return batchingAllowed.get(); } @Override public void flushBatch() throws IOException { startMessageBlock(Constants.INTERNAL_OPCODE_FLUSH, null, true); } public void sendBytes(ByteBuffer data) throws IOException { stateMachine.binaryStart(); startMessageBlock(Constants.OPCODE_BINARY, data, true); stateMachine.complete(true); } public Future sendBytesByFuture(ByteBuffer data) { FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); sendBytesByCompletion(data, f2sh); return f2sh; } public void sendBytesByCompletion(ByteBuffer data, SendHandler handler) { StateUpdateSendHandler sush = new StateUpdateSendHandler(handler); stateMachine.binaryStart(); startMessage(Constants.OPCODE_BINARY, data, true, sush); } public void sendPartialBytes(ByteBuffer partialByte, boolean last) throws IOException { stateMachine.binaryPartialStart(); startMessageBlock(Constants.OPCODE_BINARY, partialByte, last); stateMachine.complete(last); } @Override public void sendPing(ByteBuffer applicationData) throws IOException, IllegalArgumentException { startMessageBlock(Constants.OPCODE_PING, applicationData, true); } @Override public void sendPong(ByteBuffer applicationData) throws IOException, IllegalArgumentException { startMessageBlock(Constants.OPCODE_PONG, applicationData, true); } public void sendString(String text) throws IOException { stateMachine.textStart(); sendPartialString(CharBuffer.wrap(text), true); } public Future sendStringByFuture(String text) { FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); sendStringByCompletion(text, f2sh); return f2sh; } public void sendStringByCompletion(String text, SendHandler handler) { stateMachine.textStart(); TextMessageSendHandler tmsh = new TextMessageSendHandler(handler, CharBuffer.wrap(text), true, encoder, encoderBuffer, this); tmsh.write(); // TextMessageSendHandler will update stateMachine when it completes } public void sendPartialString(String fragment, boolean isLast) throws IOException { stateMachine.textPartialStart(); sendPartialString(CharBuffer.wrap(fragment), isLast); } public OutputStream getSendStream() { stateMachine.streamStart(); return new WsOutputStream(this); } public Writer getSendWriter() { stateMachine.writeStart(); return new WsWriter(this); } void sendPartialString(CharBuffer part, boolean last) throws IOException { try { // Get the timeout before we send the message. The message may // trigger a session close and depending on timing the client // session may close before we can read the timeout. long timeout = getBlockingSendTimeout(); FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); TextMessageSendHandler tmsh = new TextMessageSendHandler(f2sh, part, last, encoder, encoderBuffer, this); tmsh.write(); if (timeout == -1) { f2sh.get(); } else { f2sh.get(timeout, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { throw new IOException(e); } catch (ExecutionException e) { throw new IOException(e); } catch (TimeoutException e) { throw new IOException(e); } } void startMessageBlock(byte opCode, ByteBuffer payload, boolean last) throws IOException { // Get the timeout before we send the message. The message may // trigger a session close and depending on timing the client // session may close before we can read the timeout. long timeout = getBlockingSendTimeout(); FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); startMessage(opCode, payload, last, f2sh); try { if (timeout == -1) { f2sh.get(); } else { f2sh.get(timeout, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { throw new IOException(e); } catch (ExecutionException e) { throw new IOException(e); } catch (TimeoutException e) { throw new IOException(e); } } void startMessage(byte opCode, ByteBuffer payload, boolean last, SendHandler handler) { wsSession.updateLastActive(); MessagePart mp = new MessagePart(opCode, payload, last, handler, this); synchronized (messagePartLock) { if (Constants.OPCODE_CLOSE == mp.getOpCode()) { try { setBatchingAllowed(false); } catch (IOException e) { log.warn(sm.getString( "wsRemoteEndpoint.flushOnCloseFailed"), e); } } if (messagePartInProgress) { // When a control message is sent while another message is being // the control message is queued. Chances are the subsequent // data message part will end up queued while the control // message is sent. The logic in this class (state machine, // EndMessageHanlder, TextMessageSendHandler) ensures that there // will only ever be one data message part in the queue. There // could be multiple control messages in the queue. // Add it to the queue messagePartQueue.add(mp); } else { messagePartInProgress = true; writeMessagePart(mp); } } } void endMessage(SendHandler handler, SendResult result) { synchronized (messagePartLock) { fragmented = nextFragmented; text = nextText; MessagePart mpNext = messagePartQueue.poll(); if (mpNext == null) { messagePartInProgress = false; } else if (!closed){ // Session may have been closed unexpectedly in the middle of // sending a fragmented message closing the endpoint. If this // happens, clearly there is no point trying to send the rest of // the message. writeMessagePart(mpNext); } } wsSession.updateLastActive(); handler.onResult(result); } void writeMessagePart(MessagePart mp) { if (closed) { throw new IllegalStateException( sm.getString("wsRemoteEndpoint.closed")); } if (Constants.INTERNAL_OPCODE_FLUSH == mp.getOpCode()) { nextFragmented = fragmented; nextText = text; doWrite(mp.getHandler(), outputBuffer); return; } // Control messages may be sent in the middle of fragmented message // so they have no effect on the fragmented or text flags boolean first; if (Util.isControl(mp.getOpCode())) { nextFragmented = fragmented; nextText = text; if (mp.getOpCode() == Constants.OPCODE_CLOSE) { closed = true; } first = true; } else { boolean isText = Util.isText(mp.getOpCode()); if (fragmented) { // Currently fragmented if (text != isText) { throw new IllegalStateException( sm.getString("wsRemoteEndpoint.changeType")); } nextText = text; nextFragmented = !mp.isLast(); first = false; } else { // Wasn't fragmented. Might be now if (mp.isLast()) { nextFragmented = false; } else { nextFragmented = true; nextText = isText; } first = true; } } byte[] mask; if (isMasked()) { mask = Util.generateMask(); } else { mask = null; } headerBuffer.clear(); writeHeader(headerBuffer, mp.getOpCode(), mp.getPayload(), first, mp.isLast(), isMasked(), mask); headerBuffer.flip(); if (getBatchingAllowed() || isMasked()) { // Need to write via output buffer OutputBufferSendHandler obsh = new OutputBufferSendHandler( mp.getHandler(), headerBuffer, mp.getPayload(), mask, outputBuffer, !getBatchingAllowed(), this); obsh.write(); } else { // Can write directly doWrite(mp.getHandler(), headerBuffer, mp.getPayload()); } } private long getBlockingSendTimeout() { Object obj = wsSession.getUserProperties().get( BLOCKING_SEND_TIMEOUT_PROPERTY); Long userTimeout = null; if (obj instanceof Long) { userTimeout = (Long) obj; } if (userTimeout == null) { return DEFAULT_BLOCKING_SEND_TIMEOUT; } else { return userTimeout.longValue(); } } private static class MessagePart { private final byte opCode; private final ByteBuffer payload; private final boolean last; private final SendHandler handler; public MessagePart(byte opCode, ByteBuffer payload, boolean last, SendHandler handler, WsRemoteEndpointImplBase endpoint) { this.opCode = opCode; this.payload = payload; this.last = last; this.handler = new EndMessageHandler(endpoint, handler); } public byte getOpCode() { return opCode; } public ByteBuffer getPayload() { return payload; } public boolean isLast() { return last; } public SendHandler getHandler() { return handler; } } /** * Wraps the user provided handler so that the end point is notified when * the message is complete. */ private static class EndMessageHandler implements SendHandler { private final WsRemoteEndpointImplBase endpoint; private final SendHandler handler; public EndMessageHandler(WsRemoteEndpointImplBase endpoint, SendHandler handler) { this.endpoint = endpoint; this.handler = handler; } @Override public void onResult(SendResult result) { endpoint.endMessage(handler, result); } } public void sendObject(Object obj) throws IOException { Future f = sendObjectByFuture(obj); try { f.get(); } catch (InterruptedException e) { throw new IOException(e); } catch (ExecutionException e) { throw new IOException(e); } } public Future sendObjectByFuture(Object obj) { FutureToSendHandler f2sh = new FutureToSendHandler(wsSession); sendObjectByCompletion(obj, f2sh); return f2sh; } @SuppressWarnings({"unchecked", "rawtypes"}) public void sendObjectByCompletion(Object obj, SendHandler completion) { if (Util.isPrimitive(obj.getClass())) { String msg = obj.toString(); sendStringByCompletion(msg, completion); return; } Encoder encoder = findEncoder(obj); try { if (encoder instanceof Encoder.Text) { String msg = ((Encoder.Text) encoder).encode(obj); sendStringByCompletion(msg, completion); } else if (encoder instanceof Encoder.TextStream) { Writer w = null; try { w = getSendWriter(); ((Encoder.TextStream) encoder).encode(obj, w); } finally { if (w != null) { try { w.close(); } catch (IOException ioe) { // Ignore } } } completion.onResult(new SendResult()); } else if (encoder instanceof Encoder.Binary) { ByteBuffer msg = ((Encoder.Binary) encoder).encode(obj); sendBytesByCompletion(msg, completion); } else if (encoder instanceof Encoder.BinaryStream) { OutputStream os = null; try { os = getSendStream(); ((Encoder.BinaryStream) encoder).encode(obj, os); } finally { if (os != null) { try { os.close(); } catch (IOException ioe) { // Ignore } } } completion.onResult(new SendResult()); } else { throw new EncodeException(obj, sm.getString( "wsRemoteEndpoint.noEncoder", obj.getClass())); } } catch (EncodeException e) { SendResult sr = new SendResult(e); completion.onResult(sr); } catch (IOException e) { SendResult sr = new SendResult(e); completion.onResult(sr); } } protected void setSession(WsSession wsSession) { this.wsSession = wsSession; } protected void setEncoders(EndpointConfig endpointConfig) throws DeploymentException { encoderEntries.clear(); for (Class encoderClazz : endpointConfig.getEncoders()) { Encoder instance; try { instance = encoderClazz.newInstance(); instance.init(endpointConfig); } catch (InstantiationException e) { throw new DeploymentException( sm.getString("wsRemoteEndpoint.invalidEncoder", encoderClazz.getName()), e); } catch (IllegalAccessException e) { throw new DeploymentException( sm.getString("wsRemoteEndpoint.invalidEncoder", encoderClazz.getName()), e); } EncoderEntry entry = new EncoderEntry( Util.getEncoderType(encoderClazz), instance); encoderEntries.add(entry); } } private Encoder findEncoder(Object obj) { for (EncoderEntry entry : encoderEntries) { if (entry.getClazz().isAssignableFrom(obj.getClass())) { return entry.getEncoder(); } } return null; } public final void close() { for (EncoderEntry entry : encoderEntries) { entry.getEncoder().destroy(); } doClose(); } protected abstract void doWrite(SendHandler handler, ByteBuffer... data); protected abstract boolean isMasked(); protected abstract void doClose(); private static void writeHeader(ByteBuffer headerBuffer, byte opCode, ByteBuffer payload, boolean first, boolean last, boolean masked, byte[] mask) { byte b = 0; if (last) { // Set the fin bit b = -128; } if (first) { // This is the first fragment of this message b = (byte) (b + opCode); } // If not the first fragment, it is a continuation with opCode of zero headerBuffer.put(b); if (masked) { b = (byte) 0x80; } else { b = 0; } // Next write the mask && length length if (payload.limit() < 126) { headerBuffer.put((byte) (payload.limit() | b)); } else if (payload.limit() < 65536) { headerBuffer.put((byte) (126 | b)); headerBuffer.put((byte) (payload.limit() >>> 8)); headerBuffer.put((byte) (payload.limit() & 0xFF)); } else { // Will never be more than 2^31-1 headerBuffer.put((byte) (127 | b)); headerBuffer.put((byte) 0); headerBuffer.put((byte) 0); headerBuffer.put((byte) 0); headerBuffer.put((byte) 0); headerBuffer.put((byte) (payload.limit() >>> 24)); headerBuffer.put((byte) (payload.limit() >>> 16)); headerBuffer.put((byte) (payload.limit() >>> 8)); headerBuffer.put((byte) (payload.limit() & 0xFF)); } if (masked) { headerBuffer.put(mask[0]); headerBuffer.put(mask[1]); headerBuffer.put(mask[2]); headerBuffer.put(mask[3]); } } private class TextMessageSendHandler implements SendHandler { private final SendHandler handler; private final CharBuffer message; private final boolean isLast; private final CharsetEncoder encoder; private final ByteBuffer buffer; private final WsRemoteEndpointImplBase endpoint; private volatile boolean isDone = false; public TextMessageSendHandler(SendHandler handler, CharBuffer message, boolean isLast, CharsetEncoder encoder, ByteBuffer encoderBuffer, WsRemoteEndpointImplBase endpoint) { this.handler = handler; this.message = message; this.isLast = isLast; this.encoder = encoder.reset(); this.buffer = encoderBuffer; this.endpoint = endpoint; } public void write() { buffer.clear(); CoderResult cr = encoder.encode(message, buffer, true); if (cr.isError()) { throw new IllegalArgumentException(cr.toString()); } isDone = !cr.isOverflow(); buffer.flip(); endpoint.startMessage(Constants.OPCODE_TEXT, buffer, isDone && isLast, this); } @Override public void onResult(SendResult result) { if (isDone) { endpoint.stateMachine.complete(isLast); handler.onResult(result); } else if(!result.isOK()) { handler.onResult(result); } else if (closed){ SendResult sr = new SendResult(new IOException( sm.getString("wsRemoteEndpoint.closedDuringMessage"))); handler.onResult(sr); } else { write(); } } } /** * Used to write data to the output buffer, flushing the buffer if it fills * up. */ private static class OutputBufferSendHandler implements SendHandler { private final SendHandler handler; private final ByteBuffer headerBuffer; private final ByteBuffer payload; private final byte[] mask; private final ByteBuffer outputBuffer; private final boolean flushRequired; private final WsRemoteEndpointImplBase endpoint; private int maskIndex = 0; public OutputBufferSendHandler(SendHandler completion, ByteBuffer headerBuffer, ByteBuffer payload, byte[] mask, ByteBuffer outputBuffer, boolean flushRequired, WsRemoteEndpointImplBase endpoint) { this.handler = completion; this.headerBuffer = headerBuffer; this.payload = payload; this.mask = mask; this.outputBuffer = outputBuffer; this.flushRequired = flushRequired; this.endpoint = endpoint; } public void write() { // Write the header while (headerBuffer.hasRemaining() && outputBuffer.hasRemaining()) { outputBuffer.put(headerBuffer.get()); } if (headerBuffer.hasRemaining()) { // Still more headers to write, need to flush outputBuffer.flip(); endpoint.doWrite(this, outputBuffer); return; } // Write the payload int payloadLeft = payload.remaining(); int payloadLimit = payload.limit(); int outputSpace = outputBuffer.remaining(); int toWrite = payloadLeft; if (payloadLeft > outputSpace) { toWrite = outputSpace; // Temporarily reduce the limit payload.limit(payload.position() + toWrite); } if (mask == null) { // Use a bulk copy outputBuffer.put(payload); } else { for (int i = 0; i < toWrite; i++) { outputBuffer.put( (byte) (payload.get() ^ (mask[maskIndex++] & 0xFF))); if (maskIndex > 3) { maskIndex = 0; } } } if (payloadLeft > outputSpace) { // Restore the original limit payload.limit(payloadLimit); // Still more headers to write, need to flush outputBuffer.flip(); endpoint.doWrite(this, outputBuffer); return; } if (flushRequired) { outputBuffer.flip(); if (outputBuffer.remaining() == 0) { handler.onResult(new SendResult()); } else { endpoint.doWrite(this, outputBuffer); } } else { handler.onResult(new SendResult()); } } // ------------------------------------------------- SendHandler methods @Override public void onResult(SendResult result) { if (result.isOK()) { if (outputBuffer.hasRemaining()) { endpoint.doWrite(this, outputBuffer); } else { outputBuffer.clear(); write(); } } else { handler.onResult(result); } } } private class WsOutputStream extends OutputStream { private final WsRemoteEndpointImplBase endpoint; private final ByteBuffer buffer = ByteBuffer.allocate(8192); private final Object closeLock = new Object(); private volatile boolean closed = false; public WsOutputStream(WsRemoteEndpointImplBase endpoint) { this.endpoint = endpoint; } @Override public void write(int b) throws IOException { if (closed) { throw new IllegalStateException( sm.getString("wsRemoteEndpoint.closedOutputStream")); } if (buffer.remaining() == 0) { flush(); } buffer.put((byte) b); } @Override public void write(byte[] b, int off, int len) throws IOException { if (closed) { throw new IllegalStateException( sm.getString("wsRemoteEndpoint.closedOutputStream")); } if (len == 0) { return; } if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } if (buffer.remaining() == 0) { flush(); } int remaining = buffer.remaining(); int written = 0; while (remaining < len - written) { buffer.put(b, off + written, remaining); written += remaining; flush(); remaining = buffer.remaining(); } buffer.put(b, off + written, len - written); } @Override public void flush() throws IOException { if (closed) { throw new IllegalStateException( sm.getString("wsRemoteEndpoint.closedOutputStream")); } doWrite(false); } @Override public void close() throws IOException { synchronized (closeLock) { if (closed) { return; } closed = true; } doWrite(true); } private void doWrite(boolean last) throws IOException { buffer.flip(); endpoint.startMessageBlock(Constants.OPCODE_BINARY, buffer, last); stateMachine.complete(last); buffer.clear(); } } private static class WsWriter extends Writer { private final WsRemoteEndpointImplBase endpoint; private final CharBuffer buffer = CharBuffer.allocate(8192); private final Object closeLock = new Object(); private volatile boolean closed = false; public WsWriter(WsRemoteEndpointImplBase endpoint) { this.endpoint = endpoint; } @Override public void write(char[] cbuf, int off, int len) throws IOException { if (closed) { throw new IllegalStateException( sm.getString("wsRemoteEndpoint.closedWriter")); } if (len == 0) { return; } if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } if (buffer.remaining() == 0) { flush(); } int remaining = buffer.remaining(); int written = 0; while (remaining < len - written) { buffer.put(cbuf, off + written, remaining); written += remaining; flush(); remaining = buffer.remaining(); } buffer.put(cbuf, off + written, len - written); } @Override public void flush() throws IOException { if (closed) { throw new IllegalStateException( sm.getString("wsRemoteEndpoint.closedWriter")); } doWrite(false); } @Override public void close() throws IOException { synchronized (closeLock) { if (closed) { return; } closed = true; } doWrite(true); } private void doWrite(boolean last) throws IOException { buffer.flip(); endpoint.sendPartialString(buffer, last); buffer.clear(); } } private static class EncoderEntry { private final Class clazz; private final Encoder encoder; public EncoderEntry(Class clazz, Encoder encoder) { this.clazz = clazz; this.encoder = encoder; } public Class getClazz() { return clazz; } public Encoder getEncoder() { return encoder; } } private static enum State { OPEN, STREAM_WRITING, WRITER_WRITING, BINARY_PARTIAL_WRITING, BINARY_PARTIAL_READY, BINARY_FULL_WRITING, TEXT_PARTIAL_WRITING, TEXT_PARTIAL_READY, TEXT_FULL_WRITING } private static class StateMachine { private State state = State.OPEN; public synchronized void streamStart() { checkState(State.OPEN); state = State.STREAM_WRITING; } public synchronized void writeStart() { checkState(State.OPEN); state = State.WRITER_WRITING; } public synchronized void binaryPartialStart() { checkState(State.OPEN, State.BINARY_PARTIAL_READY); state = State.BINARY_PARTIAL_WRITING; } public synchronized void binaryStart() { checkState(State.OPEN); state = State.BINARY_FULL_WRITING; } public synchronized void textPartialStart() { checkState(State.OPEN, State.TEXT_PARTIAL_READY); state = State.TEXT_PARTIAL_WRITING; } public synchronized void textStart() { checkState(State.OPEN); state = State.TEXT_FULL_WRITING; } public synchronized void complete(boolean last) { if (last) { checkState(State.TEXT_PARTIAL_WRITING, State.TEXT_FULL_WRITING, State.BINARY_PARTIAL_WRITING, State.BINARY_FULL_WRITING, State.STREAM_WRITING, State.WRITER_WRITING); state = State.OPEN; } else { checkState(State.TEXT_PARTIAL_WRITING, State.BINARY_PARTIAL_WRITING, State.STREAM_WRITING, State.WRITER_WRITING); if (state == State.TEXT_PARTIAL_WRITING) { state = State.TEXT_PARTIAL_READY; } else if (state == State.BINARY_PARTIAL_WRITING){ state = State.BINARY_PARTIAL_READY; } else if (state == State.WRITER_WRITING) { // NO-OP. Leave state as is. } else if (state == State.STREAM_WRITING) { // NO-OP. Leave state as is. } else { // Should never happen // The if ... else ... blocks above should cover all states // permitted by the preceding checkState() call throw new IllegalStateException( "BUG: This code should never be called"); } } } private void checkState(State... required) { for (State state : required) { if (this.state == state) { return; } } throw new IllegalStateException( sm.getString("wsRemoteEndpoint.wrongState", this.state)); } } private class StateUpdateSendHandler implements SendHandler { private final SendHandler handler; public StateUpdateSendHandler(SendHandler handler) { this.handler = handler; } @Override public void onResult(SendResult result) { if (result.isOK()) { stateMachine.complete(true); } handler.onResult(result); } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/BackgroundProcessManager.java0000644000175100017510000001015012203443675027130 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.util.HashSet; import java.util.Set; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Provides a background processing mechanism that triggers roughly once a * second. The class maintains a thread that only runs when there is at least * one instance of {@link BackgroundProcess} registered. */ public class BackgroundProcessManager { private static final Log log = LogFactory.getLog(BackgroundProcessManager.class); private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private static final BackgroundProcessManager instance; static { instance = new BackgroundProcessManager(); } public static BackgroundProcessManager getInstance() { return instance; } private final Set processes = new HashSet(); private final Object processesLock = new Object(); private WsBackgroundThread wsBackgroundThread = null; private BackgroundProcessManager() { // Hide default constructor } public void register(BackgroundProcess process) { synchronized (processesLock) { if (processes.size() == 0) { wsBackgroundThread = new WsBackgroundThread(this); wsBackgroundThread.setContextClassLoader( this.getClass().getClassLoader()); wsBackgroundThread.setDaemon(true); wsBackgroundThread.start(); } processes.add(process); } } public void unregister(BackgroundProcess process) { synchronized (processesLock) { processes.remove(process); if (wsBackgroundThread != null && processes.size() == 0) { wsBackgroundThread.halt(); wsBackgroundThread = null; } } } private void process() { Set currentProcesses = new HashSet(); synchronized (processesLock) { currentProcesses.addAll(processes); } for (BackgroundProcess process : currentProcesses) { try { process.backgroundProcess(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString( "backgroundProcessManager.processFailed"), t); } } } private static class WsBackgroundThread extends Thread { private final BackgroundProcessManager manager; private volatile boolean running = true; public WsBackgroundThread(BackgroundProcessManager manager) { setName("WebSocket background processing"); this.manager = manager; } @Override public void run() { while (running) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } manager.process(); } } public void halt() { setName("WebSocket background processing - stopping"); running = false; } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsRemoteEndpointImplClient.java0000644000175100017510000000334712161330036027445 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import javax.websocket.SendHandler; public class WsRemoteEndpointImplClient extends WsRemoteEndpointImplBase { private final AsyncChannelWrapper channel; public WsRemoteEndpointImplClient(AsyncChannelWrapper channel) { this.channel = channel; } @Override protected boolean isMasked() { return true; } @Override protected void doWrite(SendHandler handler, ByteBuffer... data) { long timeout = getSendTimeout(); if (timeout < 1) { timeout = Long.MAX_VALUE; } SendHandlerToCompletionHandler sh2ch = new SendHandlerToCompletionHandler(handler); channel.write(data, 0, data.length, timeout, TimeUnit.MILLISECONDS, null, sh2ch); } @Override protected void doClose() { channel.close(); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsWebSocketContainer.java0000644000175100017510000007500412250701331026257 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.AsynchronousSocketChannel; import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; import javax.websocket.ClientEndpoint; import javax.websocket.ClientEndpointConfig; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.DeploymentException; import javax.websocket.Endpoint; import javax.websocket.Extension; import javax.websocket.HandshakeResponse; import javax.websocket.Session; import javax.websocket.WebSocketContainer; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.codec.binary.Base64; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.threads.ThreadPoolExecutor; import org.apache.tomcat.websocket.pojo.PojoEndpointClient; public class WsWebSocketContainer implements WebSocketContainer, BackgroundProcess { /** * Property name to set to configure the value that is passed to * {@link SSLEngine#setEnabledProtocols(String[])}. The value should be a * comma separated string. */ public static final String SSL_PROTOCOLS_PROPERTY = "org.apache.tomcat.websocket.SSL_PROTOCOLS"; public static final String SSL_TRUSTSTORE_PROPERTY = "org.apache.tomcat.websocket.SSL_TRUSTSTORE"; public static final String SSL_TRUSTSTORE_PWD_PROPERTY = "org.apache.tomcat.websocket.SSL_TRUSTSTORE_PWD"; public static final String SSL_TRUSTSTORE_PWD_DEFAULT = "changeit"; /** * Property name to set to configure used SSLContext. The value should be an * instance of SSLContext. If this property is present, the SSL_TRUSTSTORE* * properties are ignored. */ public static final String SSL_CONTEXT_PROPERTY = "org.apache.tomcat.websocket.SSL_CONTEXT"; /** * Property name to set to configure the timeout (in milliseconds) when * establishing a WebSocket connection to server. The default is * {@link #IO_TIMEOUT_MS_DEFAULT}. */ public static final String IO_TIMEOUT_MS_PROPERTY = "org.apache.tomcat.websocket.IO_TIMEOUT_MS"; public static final long IO_TIMEOUT_MS_DEFAULT = 5000; private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private static final Random random = new Random(); private static final byte[] crlf = new byte[] {13, 10}; private static final AsynchronousChannelGroup asynchronousChannelGroup; static { AsynchronousChannelGroup result = null; // Need to do this with the right thread context class loader else the // first web app to call this will trigger a leak ClassLoader original = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( AsyncIOThreadFactory.class.getClassLoader()); // These are the same settings as the default // AsynchronousChannelGroup int initialSize = Runtime.getRuntime().availableProcessors(); ExecutorService executorService = new ThreadPoolExecutor( 0, Integer.MAX_VALUE, Long.MAX_VALUE, TimeUnit.MILLISECONDS, new SynchronousQueue(), new AsyncIOThreadFactory()); try { result = AsynchronousChannelGroup.withCachedThreadPool( executorService, initialSize); } catch (IOException e) { // No good reason for this to happen. throw new IllegalStateException(sm.getString( "wsWebSocketContainer.asynchronousChannelGroupFail")); } } finally { Thread.currentThread().setContextClassLoader(original); } asynchronousChannelGroup = result; } private final Log log = LogFactory.getLog(WsWebSocketContainer.class); private final Map, Set> endpointSessionMap = new HashMap, Set>(); private final Map sessions = new ConcurrentHashMap(); private final Object endPointSessionMapLock = new Object(); private long defaultAsyncTimeout = -1; private int maxBinaryMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; private int maxTextMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; private volatile long defaultMaxSessionIdleTimeout = 0; private int backgroundProcessCount = 0; private int processPeriod = 10; @Override public Session connectToServer(Object pojo, URI path) throws DeploymentException { ClientEndpoint annotation = pojo.getClass().getAnnotation(ClientEndpoint.class); if (annotation == null) { throw new DeploymentException( sm.getString("wsWebSocketContainer.missingAnnotation", pojo.getClass().getName())); } Endpoint ep = new PojoEndpointClient(pojo, annotation.decoders()); Class configuratorClazz = pojo.getClass().getAnnotation( ClientEndpoint.class).configurator(); ClientEndpointConfig.Configurator configurator = null; if (!ClientEndpointConfig.Configurator.class.equals( configuratorClazz)) { try { configurator = configuratorClazz.newInstance(); } catch (InstantiationException e) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.defaultConfiguratorFail"), e); } catch (IllegalAccessException e) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.defaultConfiguratorFail"), e); } } ClientEndpointConfig config = ClientEndpointConfig.Builder.create(). configurator(configurator). decoders(Arrays.asList(annotation.decoders())). encoders(Arrays.asList(annotation.encoders())). build(); return connectToServer(ep, config, path); } @Override public Session connectToServer(Class annotatedEndpointClass, URI path) throws DeploymentException { Object pojo; try { pojo = annotatedEndpointClass.newInstance(); } catch (InstantiationException e) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.endpointCreateFail", annotatedEndpointClass.getName()), e); } catch (IllegalAccessException e) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.endpointCreateFail", annotatedEndpointClass.getName()), e); } return connectToServer(pojo, path); } @Override public Session connectToServer(Class clazz, ClientEndpointConfig clientEndpointConfiguration, URI path) throws DeploymentException { Endpoint endpoint; try { endpoint = clazz.newInstance(); } catch (InstantiationException e) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.endpointCreateFail", clazz.getName()), e); } catch (IllegalAccessException e) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.endpointCreateFail", clazz.getName()), e); } return connectToServer(endpoint, clientEndpointConfiguration, path); } @Override public Session connectToServer(Endpoint endpoint, ClientEndpointConfig clientEndpointConfiguration, URI path) throws DeploymentException { boolean secure = false; String scheme = path.getScheme(); if (!("ws".equalsIgnoreCase(scheme) || "wss".equalsIgnoreCase(scheme))) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.pathWrongScheme", scheme)); } String host = path.getHost(); if (host == null) { throw new DeploymentException( sm.getString("wsWebSocketContainer.pathNoHost")); } int port = path.getPort(); Map> reqHeaders = createRequestHeaders(host, port, clientEndpointConfiguration.getPreferredSubprotocols(), clientEndpointConfiguration.getExtensions()); clientEndpointConfiguration.getConfigurator(). beforeRequest(reqHeaders); ByteBuffer request = createRequest(path, reqHeaders); SocketAddress sa; if (port == -1) { if ("ws".equalsIgnoreCase(scheme)) { sa = new InetSocketAddress(host, 80); } else if ("wss".equalsIgnoreCase(scheme)) { sa = new InetSocketAddress(host, 443); secure = true; } else { throw new DeploymentException( sm.getString("wsWebSocketContainer.invalidScheme")); } } else { if ("wss".equalsIgnoreCase(scheme)) { secure = true; } sa = new InetSocketAddress(host, port); } AsynchronousSocketChannel socketChannel; try { socketChannel = AsynchronousSocketChannel.open(asynchronousChannelGroup); } catch (IOException ioe) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.asynchronousSocketChannelFail"), ioe); } Future fConnect = socketChannel.connect(sa); AsyncChannelWrapper channel; if (secure) { SSLEngine sslEngine = createSSLEngine( clientEndpointConfiguration.getUserProperties()); channel = new AsyncChannelWrapperSecure(socketChannel, sslEngine); } else { channel = new AsyncChannelWrapperNonSecure(socketChannel); } // Get the connection timeout long timeout = IO_TIMEOUT_MS_DEFAULT; String timeoutValue = (String) clientEndpointConfiguration.getUserProperties().get( IO_TIMEOUT_MS_PROPERTY); if (timeoutValue != null) { timeout = Long.valueOf(timeoutValue).intValue(); } ByteBuffer response; String subProtocol; try { fConnect.get(timeout, TimeUnit.MILLISECONDS); Future fHandshake = channel.handshake(); fHandshake.get(timeout, TimeUnit.MILLISECONDS); int toWrite = request.limit(); Future fWrite = channel.write(request); Integer thisWrite = fWrite.get(timeout, TimeUnit.MILLISECONDS); toWrite -= thisWrite.intValue(); while (toWrite > 0) { fWrite = channel.write(request); thisWrite = fWrite.get(timeout, TimeUnit.MILLISECONDS); toWrite -= thisWrite.intValue(); } // Same size as the WsFrame input buffer response = ByteBuffer.allocate(maxBinaryMessageBufferSize); HandshakeResponse handshakeResponse = processResponse(response, channel, timeout); clientEndpointConfiguration.getConfigurator(). afterResponse(handshakeResponse); // Sub-protocol // Header names are always stored in lower case List values = handshakeResponse.getHeaders().get( Constants.WS_PROTOCOL_HEADER_NAME_LOWER); if (values == null || values.size() == 0) { subProtocol = null; } else if (values.size() == 1) { subProtocol = values.get(0); } else { throw new DeploymentException( sm.getString("Sec-WebSocket-Protocol")); } } catch (ExecutionException e) { throw new DeploymentException( sm.getString("wsWebSocketContainer.httpRequestFailed"), e); } catch (InterruptedException e) { throw new DeploymentException( sm.getString("wsWebSocketContainer.httpRequestFailed"), e); } catch (SSLException e) { throw new DeploymentException( sm.getString("wsWebSocketContainer.httpRequestFailed"), e); } catch (EOFException e) { throw new DeploymentException( sm.getString("wsWebSocketContainer.httpRequestFailed"), e); } catch (TimeoutException e) { throw new DeploymentException( sm.getString("wsWebSocketContainer.httpRequestFailed"), e); } // Switch to WebSocket WsRemoteEndpointImplClient wsRemoteEndpointClient = new WsRemoteEndpointImplClient(channel); WsSession wsSession = new WsSession(endpoint, wsRemoteEndpointClient, this, null, null, null, null, null, subProtocol, Collections. emptyMap(), false, clientEndpointConfiguration); endpoint.onOpen(wsSession, clientEndpointConfiguration); registerSession(endpoint, wsSession); // Object creation will trigger input processing @SuppressWarnings("unused") WsFrameClient wsFrameClient = new WsFrameClient(response, channel, wsSession); return wsSession; } protected void registerSession(Endpoint endpoint, WsSession wsSession) { Class endpointClazz = endpoint.getClass(); if (!wsSession.isOpen()) { // The session was closed during onOpen. No need to register it. return; } synchronized (endPointSessionMapLock) { if (endpointSessionMap.size() == 0) { BackgroundProcessManager.getInstance().register(this); } Set wsSessions = endpointSessionMap.get(endpointClazz); if (wsSessions == null) { wsSessions = new HashSet(); endpointSessionMap.put(endpointClazz, wsSessions); } wsSessions.add(wsSession); } sessions.put(wsSession, wsSession); } protected void unregisterSession(Endpoint endpoint, WsSession wsSession) { Class endpointClazz = endpoint.getClass(); synchronized (endPointSessionMapLock) { Set wsSessions = endpointSessionMap.get(endpointClazz); if (wsSessions != null) { wsSessions.remove(wsSession); if (wsSessions.size() == 0) { endpointSessionMap.remove(endpointClazz); } } if (endpointSessionMap.size() == 0) { BackgroundProcessManager.getInstance().unregister(this); } } sessions.remove(wsSession); } Set getOpenSessions(Class endpoint) { HashSet result = new HashSet(); synchronized (endPointSessionMapLock) { Set sessions = endpointSessionMap.get(endpoint); if (sessions != null) { result.addAll(sessions); } } return result; } private Map> createRequestHeaders(String host, int port, List subProtocols, List extensions) { Map> headers = new HashMap>(); // Host header List hostValues = new ArrayList(1); if (port == -1) { hostValues.add(host); } else { hostValues.add(host + ':' + port); } headers.put(Constants.HOST_HEADER_NAME, hostValues); // Upgrade header List upgradeValues = new ArrayList(1); upgradeValues.add(Constants.UPGRADE_HEADER_VALUE); headers.put(Constants.UPGRADE_HEADER_NAME, upgradeValues); // Connection header List connectionValues = new ArrayList(1); connectionValues.add(Constants.CONNECTION_HEADER_VALUE); headers.put(Constants.CONNECTION_HEADER_NAME, connectionValues); // WebSocket version header List wsVersionValues = new ArrayList(1); wsVersionValues.add(Constants.WS_VERSION_HEADER_VALUE); headers.put(Constants.WS_VERSION_HEADER_NAME, wsVersionValues); // WebSocket key List wsKeyValues = new ArrayList(1); wsKeyValues.add(generateWsKeyValue()); headers.put(Constants.WS_KEY_HEADER_NAME, wsKeyValues); // WebSocket sub-protocols if (subProtocols != null && subProtocols.size() > 0) { headers.put(Constants.WS_PROTOCOL_HEADER_NAME, subProtocols); } // WebSocket extensions if (extensions != null && extensions.size() > 0) { headers.put(Constants.WS_EXTENSIONS_HEADER_NAME, generateExtensionHeaders(extensions)); } return headers; } private List generateExtensionHeaders(List extensions) { List result = new ArrayList(extensions.size()); for (Extension extension : extensions) { StringBuilder header = new StringBuilder(); header.append(extension.getName()); for (Extension.Parameter param : extension.getParameters()) { header.append(';'); header.append(param.getName()); String value = param.getValue(); if (value != null && value.length() > 0) { header.append('='); header.append(value); } } } return result; } private String generateWsKeyValue() { byte[] keyBytes = new byte[16]; random.nextBytes(keyBytes); return Base64.encodeBase64String(keyBytes); } private ByteBuffer createRequest(URI uri, Map> reqHeaders) { ByteBuffer result = ByteBuffer.allocate(4 * 1024); // Request line result.put("GET ".getBytes(StandardCharsets.ISO_8859_1)); result.put(uri.getRawPath().getBytes(StandardCharsets.ISO_8859_1)); String query = uri.getRawQuery(); if (query != null) { result.put((byte) '?'); result.put(query.getBytes(StandardCharsets.ISO_8859_1)); } result.put(" HTTP/1.1\r\n".getBytes(StandardCharsets.ISO_8859_1)); // Headers Iterator>> iter = reqHeaders.entrySet().iterator(); while (iter.hasNext()) { Entry> entry = iter.next(); addHeader(result, entry.getKey(), entry.getValue()); } // Terminating CRLF result.put(crlf); result.flip(); return result; } private void addHeader(ByteBuffer result, String key, List values) { StringBuilder sb = new StringBuilder(); Iterator iter = values.iterator(); if (!iter.hasNext()) { return; } sb.append(iter.next()); while (iter.hasNext()) { sb.append(','); sb.append(iter.next()); } result.put(key.getBytes(StandardCharsets.ISO_8859_1)); result.put(": ".getBytes(StandardCharsets.ISO_8859_1)); result.put(sb.toString().getBytes(StandardCharsets.ISO_8859_1)); result.put(crlf); } /** * Process response, blocking until HTTP response has been fully received. * @throws ExecutionException * @throws InterruptedException * @throws DeploymentException * @throws TimeoutException */ private HandshakeResponse processResponse(ByteBuffer response, AsyncChannelWrapper channel, long timeout) throws InterruptedException, ExecutionException, DeploymentException, EOFException, TimeoutException { Map> headers = new HashMap>(); boolean readStatus = false; boolean readHeaders = false; String line = null; while (!readHeaders) { // Blocking read Future read = channel.read(response); Integer bytesRead = read.get(timeout, TimeUnit.MILLISECONDS); if (bytesRead.intValue() == -1) { throw new EOFException(); } response.flip(); while (response.hasRemaining() && !readHeaders) { if (line == null) { line = readLine(response); } else { line += readLine(response); } if ("\r\n".equals(line)) { readHeaders = true; } else if (line.endsWith("\r\n")) { if (readStatus) { parseHeaders(line, headers); } else { parseStatus(line); readStatus = true; } line = null; } } } return new WsHandshakeResponse(headers); } private void parseStatus(String line) throws DeploymentException { // This client only understands HTTP 1.1 // RFC2616 is case specific if (!line.startsWith("HTTP/1.1 101")) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.invalidStatus", line)); } } private void parseHeaders(String line, Map> headers) { // Treat headers as single values by default. int index = line.indexOf(':'); if (index == -1) { log.warn(sm.getString("wsWebSocketContainer.invalidHeader", line)); return; } // Header names are case insensitive so always use lower case String headerName = line.substring(0, index).trim().toLowerCase(); // TODO handle known multi-value headers String headerValue = line.substring(index + 1).trim(); List values = headers.get(headerName); if (values == null) { values = new ArrayList(1); headers.put(headerName, values); } values.add(headerValue); } private String readLine(ByteBuffer response) { // All ISO-8859-1 StringBuilder sb = new StringBuilder(); char c = 0; while (response.hasRemaining()) { c = (char) response.get(); sb.append(c); if (c == 10) { break; } } return sb.toString(); } private SSLEngine createSSLEngine(Map userProperties) throws DeploymentException { try { // See if a custom SSLContext has been provided SSLContext sslContext = (SSLContext) userProperties.get(SSL_CONTEXT_PROPERTY); if (sslContext == null) { // Create the SSL Context sslContext = SSLContext.getInstance("TLS"); // Trust store String sslTrustStoreValue = (String) userProperties.get(SSL_TRUSTSTORE_PROPERTY); if (sslTrustStoreValue != null) { String sslTrustStorePwdValue = (String) userProperties.get( SSL_TRUSTSTORE_PWD_PROPERTY); if (sslTrustStorePwdValue == null) { sslTrustStorePwdValue = SSL_TRUSTSTORE_PWD_DEFAULT; } File keyStoreFile = new File(sslTrustStoreValue); KeyStore ks = KeyStore.getInstance("JKS"); InputStream is = null; try { is = new FileInputStream(keyStoreFile); ks.load(is, sslTrustStorePwdValue.toCharArray()); } finally { if (is != null) { try { is.close(); } catch (IOException ioe) { // Ignore } } } TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); sslContext.init(null, tmf.getTrustManagers(), null); } else { sslContext.init(null, null, null); } } SSLEngine engine = sslContext.createSSLEngine(); String sslProtocolsValue = (String) userProperties.get(SSL_PROTOCOLS_PROPERTY); if (sslProtocolsValue != null) { engine.setEnabledProtocols(sslProtocolsValue.split(",")); } engine.setUseClientMode(true); return engine; } catch (Exception e) { throw new DeploymentException(sm.getString( "wsWebSocketContainer.sslEngineFail"), e); } } @Override public long getDefaultMaxSessionIdleTimeout() { return defaultMaxSessionIdleTimeout; } @Override public void setDefaultMaxSessionIdleTimeout(long timeout) { this.defaultMaxSessionIdleTimeout = timeout; } @Override public int getDefaultMaxBinaryMessageBufferSize() { return maxBinaryMessageBufferSize; } @Override public void setDefaultMaxBinaryMessageBufferSize(int max) { maxBinaryMessageBufferSize = max; } @Override public int getDefaultMaxTextMessageBufferSize() { return maxTextMessageBufferSize; } @Override public void setDefaultMaxTextMessageBufferSize(int max) { maxTextMessageBufferSize = max; } /** * {@inheritDoc} * * Currently, this implementation does not support any extensions. */ @Override public Set getInstalledExtensions() { return Collections.emptySet(); } /** * {@inheritDoc} * * The default value for this implementation is -1. */ @Override public long getDefaultAsyncSendTimeout() { return defaultAsyncTimeout; } /** * {@inheritDoc} * * The default value for this implementation is -1. */ @Override public void setAsyncSendTimeout(long timeout) { this.defaultAsyncTimeout = timeout; } /** * Cleans up the resources still in use by WebSocket sessions created from * this container. This includes closing sessions and cancelling * {@link Future}s associated with blocking read/writes. */ public void destroy() { CloseReason cr = new CloseReason( CloseCodes.GOING_AWAY, sm.getString("wsWebSocketContainer.shutdown")); for (WsSession session : sessions.keySet()) { try { session.close(cr); } catch (IOException ioe) { log.debug(sm.getString( "wsWebSocketContainer.sessionCloseFail", session.getId()), ioe); } } } // ----------------------------------------------- BackgroundProcess methods @Override public void backgroundProcess() { // This method gets called once a second. backgroundProcessCount ++; if (backgroundProcessCount >= processPeriod) { backgroundProcessCount = 0; for (WsSession wsSession : sessions.keySet()) { wsSession.checkExpiration(); } } } @Override public void setProcessPeriod(int period) { this.processPeriod = period; } /** * {@inheritDoc} * * The default value is 10 which means session expirations are processed * every 10 seconds. */ @Override public int getProcessPeriod() { return processPeriod; } /** * Create threads for AsyncIO that have the right context class loader to * prevent memory leaks. */ private static class AsyncIOThreadFactory implements ThreadFactory { private AtomicInteger count = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setName("WebSocketClient-AsyncIO-" + count.incrementAndGet()); t.setContextClassLoader(this.getClass().getClassLoader()); t.setDaemon(true); return t; } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsPongMessage.java0000644000175100017510000000244012164507264024745 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.nio.ByteBuffer; import javax.websocket.PongMessage; public class WsPongMessage implements PongMessage { private final ByteBuffer applicationData; public WsPongMessage(ByteBuffer applicationData) { byte[] dst = new byte[applicationData.limit()]; applicationData.get(dst); this.applicationData = ByteBuffer.wrap(dst); } @Override public ByteBuffer getApplicationData() { return applicationData; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/Util.java0000644000175100017510000005222612231042623023133 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.InputStream; import java.io.Reader; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.nio.ByteBuffer; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import javax.websocket.CloseReason.CloseCode; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.Decoder; import javax.websocket.Decoder.Binary; import javax.websocket.Decoder.BinaryStream; import javax.websocket.Decoder.Text; import javax.websocket.Decoder.TextStream; import javax.websocket.DeploymentException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.PongMessage; import javax.websocket.Session; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBinary; import org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeText; /** * Utility class for internal use only within the * {@link org.apache.tomcat.websocket} package. */ public class Util { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private static final Queue randoms = new ConcurrentLinkedQueue(); private Util() { // Hide default constructor } static boolean isControl(byte opCode) { return (opCode & 0x08) > 0; } static boolean isText(byte opCode) { return opCode == Constants.OPCODE_TEXT; } static CloseCode getCloseCode(int code) { if (code > 2999 && code < 5000) { return CloseCodes.NORMAL_CLOSURE; } switch (code) { case 1000: return CloseCodes.NORMAL_CLOSURE; case 1001: return CloseCodes.GOING_AWAY; case 1002: return CloseCodes.PROTOCOL_ERROR; case 1003: return CloseCodes.CANNOT_ACCEPT; case 1004: // Should not be used in a close frame // return CloseCodes.RESERVED; return CloseCodes.PROTOCOL_ERROR; case 1005: // Should not be used in a close frame // return CloseCodes.NO_STATUS_CODE; return CloseCodes.PROTOCOL_ERROR; case 1006: // Should not be used in a close frame // return CloseCodes.CLOSED_ABNORMALLY; return CloseCodes.PROTOCOL_ERROR; case 1007: return CloseCodes.NOT_CONSISTENT; case 1008: return CloseCodes.VIOLATED_POLICY; case 1009: return CloseCodes.TOO_BIG; case 1010: return CloseCodes.NO_EXTENSION; case 1011: return CloseCodes.UNEXPECTED_CONDITION; case 1012: // Not in RFC6455 // return CloseCodes.SERVICE_RESTART; return CloseCodes.PROTOCOL_ERROR; case 1013: // Not in RFC6455 // return CloseCodes.TRY_AGAIN_LATER; return CloseCodes.PROTOCOL_ERROR; case 1015: // Should not be used in a close frame // return CloseCodes.TLS_HANDSHAKE_FAILURE; return CloseCodes.PROTOCOL_ERROR; default: return CloseCodes.PROTOCOL_ERROR; } } static byte[] generateMask() { // SecureRandom is not thread-safe so need to make sure only one thread // uses it at a time. In theory, the pool could grow to the same size // as the number of request processing threads. In reality it will be // a lot smaller. // Get a SecureRandom from the pool SecureRandom sr = randoms.poll(); // If one isn't available, generate a new one if (sr == null) { try { sr = SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { // Fall back to platform default sr = new SecureRandom(); } } // Generate the mask byte[] result = new byte[4]; sr.nextBytes(result); // Put the SecureRandom back in the poll randoms.add(sr); return result; } static Class getMessageType(MessageHandler listener) { return Util.getGenericType(MessageHandler.class, listener.getClass()).getClazz(); } public static Class getDecoderType(Class decoder) { return Util.getGenericType(Decoder.class, decoder).getClazz(); } static Class getEncoderType(Class encoder) { return Util.getGenericType(Encoder.class, encoder).getClazz(); } private static TypeResult getGenericType(Class type, Class clazz) { // Look to see if this class implements the generic MessageHandler<> // interface // Get all the interfaces Type[] interfaces = clazz.getGenericInterfaces(); for (Type iface : interfaces) { // Only need to check interfaces that use generics if (iface instanceof ParameterizedType) { ParameterizedType pi = (ParameterizedType) iface; // Look for the MessageHandler<> interface if (pi.getRawType() instanceof Class) { if (type.isAssignableFrom((Class) pi.getRawType())) { return getTypeParameter( clazz, pi.getActualTypeArguments()[0]); } } } } // Interface not found on this class. Look at the superclass. @SuppressWarnings("unchecked") Class superClazz = (Class) clazz.getSuperclass(); TypeResult superClassTypeResult = getGenericType(type, superClazz); int dimension = superClassTypeResult.getDimension(); if (superClassTypeResult.getIndex() == -1 && dimension == 0) { // Superclass implements interface and defines explicit type for // MessageHandler<> return superClassTypeResult; } if (superClassTypeResult.getIndex() > -1) { // Superclass implements interface and defines unknown type for // MessageHandler<> // Map that unknown type to the generic types defined in this class ParameterizedType superClassType = (ParameterizedType) clazz.getGenericSuperclass(); TypeResult result = getTypeParameter(clazz, superClassType.getActualTypeArguments()[ superClassTypeResult.getIndex()]); result.incrementDimension(superClassTypeResult.getDimension()); if (result.getClazz() != null && result.getDimension() > 0) { superClassTypeResult = result; } else { return result; } } if (superClassTypeResult.getDimension() > 0) { StringBuilder className = new StringBuilder(); for (int i = 0; i < dimension; i++) { className.append('['); } className.append('L'); className.append(superClassTypeResult.getClazz().getCanonicalName()); className.append(';'); Class arrayClazz; try { arrayClazz = Class.forName(className.toString()); } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } return new TypeResult(arrayClazz, -1, 0); } // Error will be logged further up the call stack return null; } /* * For a generic parameter, return either the Class used or if the type * is unknown, the index for the type in definition of the class */ private static TypeResult getTypeParameter(Class clazz, Type argType) { if (argType instanceof Class) { return new TypeResult((Class) argType, -1, 0); } else if (argType instanceof ParameterizedType) { return new TypeResult((Class)((ParameterizedType) argType).getRawType(), -1, 0); } else if (argType instanceof GenericArrayType) { Type arrayElementType = ((GenericArrayType) argType).getGenericComponentType(); TypeResult result = getTypeParameter(clazz, arrayElementType); result.incrementDimension(1); return result; } else { TypeVariable[] tvs = clazz.getTypeParameters(); for (int i = 0; i < tvs.length; i++) { if (tvs[i].equals(argType)) { return new TypeResult(null, i, 0); } } return null; } } public static boolean isPrimitive(Class clazz) { if (clazz.isPrimitive()) { return true; } else if(clazz.equals(Boolean.class) || clazz.equals(Byte.class) || clazz.equals(Character.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Integer.class) || clazz.equals(Long.class) || clazz.equals(Short.class)) { return true; } return false; } public static Object coerceToType(Class type, String value) { if (type.equals(String.class)) { return value; } else if (type.equals(boolean.class) || type.equals(Boolean.class)) { return Boolean.valueOf(value); } else if (type.equals(byte.class) || type.equals(Byte.class)) { return Byte.valueOf(value); } else if (value.length() == 1 && (type.equals(char.class) || type.equals(Character.class))) { return Character.valueOf(value.charAt(0)); } else if (type.equals(double.class) || type.equals(Double.class)) { return Double.valueOf(value); } else if (type.equals(float.class) || type.equals(Float.class)) { return Float.valueOf(value); } else if (type.equals(int.class) || type.equals(Integer.class)) { return Integer.valueOf(value); } else if (type.equals(long.class) || type.equals(Long.class)) { return Long.valueOf(value); } else if (type.equals(short.class) || type.equals(Short.class)) { return Short.valueOf(value); } else { throw new IllegalArgumentException(sm.getString( "util.invalidType", value, type.getName())); } } public static List getDecoders( Class[] decoderClazzes) throws DeploymentException{ List result = new ArrayList(); for (Class decoderClazz : decoderClazzes) { // Need to instantiate decoder to ensure it is valid and that // deployment can be failed if it is not @SuppressWarnings("unused") Decoder instance; try { instance = decoderClazz.newInstance(); } catch (InstantiationException e) { throw new DeploymentException( sm.getString("pojoMethodMapping.invalidDecoder", decoderClazz.getName()), e); } catch (IllegalAccessException e) { throw new DeploymentException( sm.getString("pojoMethodMapping.invalidDecoder", decoderClazz.getName()), e); } DecoderEntry entry = new DecoderEntry( Util.getDecoderType(decoderClazz), decoderClazz); result.add(entry); } return result; } public static Set getMessageHandlers( MessageHandler listener, EndpointConfig endpointConfig, Session session) { Class target = Util.getMessageType(listener); // Will never be more than 2 types Set results = new HashSet(2); // Simple cases - handlers already accepts one of the types expected by // the frame handling code if (String.class.isAssignableFrom(target)) { MessageHandlerResult result = new MessageHandlerResult(listener, MessageHandlerResultType.TEXT); results.add(result); } else if (ByteBuffer.class.isAssignableFrom(target)) { MessageHandlerResult result = new MessageHandlerResult(listener, MessageHandlerResultType.BINARY); results.add(result); } else if (PongMessage.class.isAssignableFrom(target)) { MessageHandlerResult result = new MessageHandlerResult(listener, MessageHandlerResultType.PONG); results.add(result); // Relatively simple cases - handler needs wrapping but no decoder to // convert it to one of the types expected by the frame handling code } else if (byte[].class.isAssignableFrom(target)) { MessageHandlerResult result = new MessageHandlerResult( new PojoMessageHandlerWholeBinary(listener, getOnMessageMethod(listener), session, endpointConfig, null, new Object[1], 0, true, -1, false, -1), MessageHandlerResultType.BINARY); results.add(result); } else if (InputStream.class.isAssignableFrom(target)) { MessageHandlerResult result = new MessageHandlerResult( new PojoMessageHandlerWholeBinary(listener, getOnMessageMethod(listener), session, endpointConfig, null, new Object[1], 0, true, -1, true, -1), MessageHandlerResultType.BINARY); results.add(result); } else if (Reader.class.isAssignableFrom(target)) { MessageHandlerResult result = new MessageHandlerResult( new PojoMessageHandlerWholeText(listener, getOnMessageMethod(listener), session, endpointConfig, null, new Object[1], 0, true, -1, -1), MessageHandlerResultType.TEXT); results.add(result); } else { // More complex case - listener that requires a decoder DecoderMatch decoderMatch; try { List> decoders = endpointConfig.getDecoders(); @SuppressWarnings("unchecked") List decoderEntries = getDecoders( decoders.toArray(new Class[decoders.size()])); decoderMatch = new DecoderMatch(target, decoderEntries); } catch (DeploymentException e) { throw new IllegalArgumentException(e); } Method m = getOnMessageMethod(listener); if (decoderMatch.getBinaryDecoders().size() > 0) { MessageHandlerResult result = new MessageHandlerResult( new PojoMessageHandlerWholeBinary(listener, m, session, endpointConfig, decoderMatch.getBinaryDecoders(), new Object[1], 0, false, -1, false, -1), MessageHandlerResultType.BINARY); results.add(result); } if (decoderMatch.getTextDecoders().size() > 0) { MessageHandlerResult result = new MessageHandlerResult( new PojoMessageHandlerWholeText(listener, m, session, endpointConfig, decoderMatch.getTextDecoders(), new Object[1], 0, false, -1, -1), MessageHandlerResultType.TEXT); results.add(result); } } if (results.size() == 0) { throw new IllegalArgumentException( sm.getString("wsSession.unknownHandler", listener, target)); } return results; } private static Method getOnMessageMethod(MessageHandler listener) { try { return listener.getClass().getMethod("onMessage", Object.class); } catch (NoSuchMethodException e) { throw new IllegalArgumentException( sm.getString("util.invalidMessageHandler"), e); } catch ( SecurityException e) { throw new IllegalArgumentException( sm.getString("util.invalidMessageHandler"), e); } } public static class DecoderMatch { private final List> textDecoders = new ArrayList>(); private final List> binaryDecoders = new ArrayList>(); public DecoderMatch(Class target, List decoderEntries) { for (DecoderEntry decoderEntry : decoderEntries) { if (decoderEntry.getClazz().isAssignableFrom(target)) { if (Binary.class.isAssignableFrom( decoderEntry.getDecoderClazz())) { binaryDecoders.add(decoderEntry.getDecoderClazz()); // willDecode() method means this decoder may or may not // decode a message so need to carry on checking for // other matches } else if (BinaryStream.class.isAssignableFrom( decoderEntry.getDecoderClazz())) { binaryDecoders.add(decoderEntry.getDecoderClazz()); // Stream decoders have to process the message so no // more decoders can be matched break; } else if (Text.class.isAssignableFrom( decoderEntry.getDecoderClazz())) { textDecoders.add(decoderEntry.getDecoderClazz()); // willDecode() method means this decoder may or may not // decode a message so need to carry on checking for // other matches } else if (TextStream.class.isAssignableFrom( decoderEntry.getDecoderClazz())) { textDecoders.add(decoderEntry.getDecoderClazz()); // Stream decoders have to process the message so no // more decoders can be matched break; } else { throw new IllegalArgumentException( sm.getString("util.unknownDecoderType")); } } } } public List> getTextDecoders() { return textDecoders; } public List> getBinaryDecoders() { return binaryDecoders; } public boolean hasMatches() { return (textDecoders.size() > 0) || (binaryDecoders.size() > 0); } } private static class TypeResult { private final Class clazz; private final int index; private int dimension; public TypeResult(Class clazz, int index, int dimension) { this.clazz= clazz; this.index = index; this.dimension = dimension; } public Class getClazz() { return clazz; } public int getIndex() { return index; } public int getDimension() { return dimension; } public void incrementDimension(int inc) { dimension += inc; } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsContainerProvider.java0000644000175100017510000000211712115653204026163 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import javax.websocket.ContainerProvider; import javax.websocket.WebSocketContainer; public class WsContainerProvider extends ContainerProvider { @Override protected WebSocketContainer getContainer() { return new WsWebSocketContainer(); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsRemoteEndpointAsync.java0000644000175100017510000000417312112654536026472 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.nio.ByteBuffer; import java.util.concurrent.Future; import javax.websocket.RemoteEndpoint; import javax.websocket.SendHandler; public class WsRemoteEndpointAsync extends WsRemoteEndpointBase implements RemoteEndpoint.Async { WsRemoteEndpointAsync(WsRemoteEndpointImplBase base) { super(base); } @Override public long getSendTimeout() { return base.getSendTimeout(); } @Override public void setSendTimeout(long timeout) { base.setSendTimeout(timeout); } @Override public void sendText(String text, SendHandler completion) { base.sendStringByCompletion(text, completion); } @Override public Future sendText(String text) { return base.sendStringByFuture(text); } @Override public Future sendBinary(ByteBuffer data) { return base.sendBytesByFuture(data); } @Override public void sendBinary(ByteBuffer data, SendHandler completion) { base.sendBytesByCompletion(data, completion); } @Override public Future sendObject(Object obj) { return base.sendObjectByFuture(obj); } @Override public void sendObject(Object obj, SendHandler completion) { base.sendObjectByCompletion(obj, completion); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/FutureToSendHandler.java0000644000175100017510000000612712216555616026120 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.websocket.SendHandler; import javax.websocket.SendResult; /** * Converts a Future to a SendHandler. */ class FutureToSendHandler implements Future, SendHandler { private final CountDownLatch latch = new CountDownLatch(1); private final WsSession wsSession; private volatile SendResult result = null; public FutureToSendHandler(WsSession wsSession) { this.wsSession = wsSession; } // --------------------------------------------------------- SendHandler @Override public void onResult(SendResult result) { this.result = result; latch.countDown(); } // -------------------------------------------------------------- Future @Override public boolean cancel(boolean mayInterruptIfRunning) { // Cancelling the task is not supported return false; } @Override public boolean isCancelled() { // Cancelling the task is not supported return false; } @Override public boolean isDone() { return latch.getCount() == 0; } @Override public Void get() throws InterruptedException, ExecutionException { try { wsSession.registerFuture(this); latch.await(); } finally { wsSession.unregisterFuture(this); } if (result.getException() != null) { throw new ExecutionException(result.getException()); } return null; } @Override public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { boolean retval = false; try { wsSession.registerFuture(this); retval = latch.await(timeout, unit); } finally { wsSession.unregisterFuture(this); } if (retval == false) { throw new TimeoutException(); } if (result.getException() != null) { throw new ExecutionException(result.getException()); } return null; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/ReadBufferOverflowException.java0000644000175100017510000000227212167502354027634 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; public class ReadBufferOverflowException extends IOException { private static final long serialVersionUID = 1L; private final int minBufferSize; public ReadBufferOverflowException(int minBufferSize) { this.minBufferSize = minBufferSize; } public int getMinBufferSize() { return minBufferSize; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/AsyncChannelWrapper.java0000644000175100017510000000333612203452534026130 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLException; /** * This is a wrapper for a {@link java.nio.channels.AsynchronousSocketChannel} * that limits the methods available thereby simplifying the process of * implementing SSL/TLS support since there are fewer methods to intercept. */ public interface AsyncChannelWrapper { Future read(ByteBuffer dst); void read(ByteBuffer dst, A attachment, CompletionHandler handler); Future write(ByteBuffer src); void write(ByteBuffer[] srcs, int offset, int length, long timeout, TimeUnit unit, A attachment, CompletionHandler handler); void close(); Future handshake() throws SSLException; } tomcat7-7.0.52/java/org/apache/tomcat/websocket/Constants.java0000644000175100017510000000532412176216144024200 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.util.Locale; /** * Internal implementation constants. */ public class Constants { protected static final String PACKAGE_NAME = Constants.class.getPackage().getName(); // OP Codes public static final byte OPCODE_CONTINUATION = 0x00; public static final byte OPCODE_TEXT = 0x01; public static final byte OPCODE_BINARY = 0x02; public static final byte OPCODE_CLOSE = 0x08; public static final byte OPCODE_PING = 0x09; public static final byte OPCODE_PONG = 0x0A; // Internal OP Codes // RFC 6455 limits OP Codes to 4 bits so these should never clash // Always set bit 4 so these will be treated as control codes static final byte INTERNAL_OPCODE_FLUSH = 0x18; // Buffers static final int DEFAULT_BUFFER_SIZE = 8 * 1024; // Client connection public static final String HOST_HEADER_NAME = "Host"; public static final String UPGRADE_HEADER_NAME = "Upgrade"; public static final String UPGRADE_HEADER_VALUE = "websocket"; public static final String CONNECTION_HEADER_NAME = "Connection"; public static final String CONNECTION_HEADER_VALUE = "upgrade"; public static final String WS_VERSION_HEADER_NAME = "Sec-WebSocket-Version"; public static final String WS_VERSION_HEADER_VALUE = "13"; public static final String WS_KEY_HEADER_NAME = "Sec-WebSocket-Key"; public static final String WS_PROTOCOL_HEADER_NAME = "Sec-WebSocket-Protocol"; public static final String WS_PROTOCOL_HEADER_NAME_LOWER = WS_PROTOCOL_HEADER_NAME.toLowerCase(Locale.ENGLISH); public static final String WS_EXTENSIONS_HEADER_NAME = "Sec-WebSocket-Extensions"; public static final boolean STRICT_SPEC_COMPLIANCE = Boolean.getBoolean( "org.apache.tomcat.websocket.STRICT_SPEC_COMPLIANCE"); private Constants() { // Hide default constructor } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/LocalStrings.properties0000644000175100017510000002063612267550170026107 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. asyncChannelWrapperSecure.closeFail=Failed to close channel cleanly asyncChannelWrapperSecure.concurrentRead=Concurrent read operations are not permitted asyncChannelWrapperSecure.concurrentWrite=Concurrent write operations are not permitted asyncChannelWrapperSecure.eof=Unexpected end of stream asyncChannelWrapperSecure.readOverflow=Buffer overflow. [{0}] bytes to write into a [{1}] byte buffer that already contained [{2}] bytes. asyncChannelWrapperSecure.statusUnwrap=Unexpected Status of SSLEngineResult after an unwrap() operation asyncChannelWrapperSecure.statusWrap=Unexpected Status of SSLEngineResult after a wrap() operation asyncChannelWrapperSecure.tooBig=The result [{0}] is too big to be expressed as an Integer asyncChannelWrapperSecure.wrongStateRead=Flag that indicates a read is in progress was found to be false (it should have been true) when trying to complete a read operation asyncChannelWrapperSecure.wrongStateWrite=Flag that indicates a write is in progress was found to be false (it should have been true) when trying to complete a write operation backgroundProcessManager.processFailed=A background process failed util.invalidMessageHandler=The message handler provided does not have an onMessage(Object) method util.invalidType=Unable to coerce value [{0}] to type [{1}]. That type is not supported. util.unknownDecoderType=The Decoder type [{0}] is not recognized # Note the wsFrame.* messages are used as close reasons in WebSocket control # frames and therefore must be 123 bytes (not characters) or less in length. # Messages are encoded using UTF-8 where a single character may be encoded in # as many as 4 bytes. wsFrame.bufferTooSmall=No async message support and buffer too small. Buffer size: [{0}], Message size: [{1}] wsFrame.byteToLongFail=Too many bytes ([{0}]) were provided to be converted into a long wsFrame.closed=New frame received after a close control frame wsFrame.controlFragmented=A fragmented control frame was received but control frames may not be fragmented wsFrame.controlPayloadTooBig=A control frame was sent with a payload of size [{0}] which is larger than the maximum permitted of 125 bytes wsFrame.controlNoFin=A control frame was sent that did not have the fin bit set. Control frames are not permitted to use continuation frames. wsFrame.invalidOpCode= A WebSocket frame was sent with an unrecognised opCode of [{0}] wsFrame.invalidUtf8=A WebSocket text frame was received that could not be decoded to UTF-8 because it contained invalid byte sequences wsFrame.invalidUtf8Close=A WebSocket close frame was received with a close reason that contained invalid UTF-8 byte sequences wsFrame.ioeTriggeredClose=An unrecoverable IOException occurred so the connection was closed wsFrame.messageTooBig=The message was [{0}] bytes long but the MessageHandler has a limit of [{1}] bytes wsFrame.noContinuation=A new message was started when a continuation frame was expected wsFrame.notMasked=The client frame was not masked but all client frames must be masked wsFrame.oneByteCloseCode=The client sent a close frame with a single byte payload which is not valid wsFrame.sessionClosed=The client data can not be processed because the session has already been closed wsFrame.textMessageTooBig=The decoded text message was too big for the output buffer and the endpoint does not support partial messages wsFrame.wrongRsv=The client frame set the reserved bits to [{0}] which was not supported by this endpoint wsRemoteEndpoint.closed=Message will not be sent because the WebSocket session has been closed wsRemoteEndpoint.closedDuringMessage=The remainder of the message will not be sent because the WebSocket session has been closed wsRemoteEndpoint.closedOutputStream=This method may not be called as the OutputStream has been closed wsRemoteEndpoint.closedWriter=This method may not be called as the Writer has been closed wsRemoteEndpoint.changeType=When sending a fragmented message, all fragments bust be of the same type wsRemoteEndpoint.concurrentMessageSend=Messages may not be sent concurrently even when using the asynchronous send messages. The client must wait for the previous message to complete before sending the next. wsRemoteEndpoint.flushOnCloseFailed=Flushing batched messages before closing the session failed wsRemoteEndpoint.invalidEncoder=The specified encoder of type [{0}] could not be instantiated wsRemoteEndpoint.noEncoder=No encoder specified for object of class [{0}] wsRemoteEndpoint.wrongState=The remote endpoint was in state [{0}] which is an invalid state for called method # Note the following message is used as a close reason in a WebSocket control # frame and therefore must be 123 bytes (not characters) or less in length. # Messages are encoded using UTF-8 where a single character may be encoded in # as many as 4 bytes. wsSession.timeout=The WebSocket session timeout expired wsSession.closed=The WebSocket session has been closed and no method (apart from close()) may be called on a closed session wsSession.duplicateHandlerBinary=A binary message handler has already been configured wsSession.duplicateHandlerPong=A pong message handler has already been configured wsSession.duplicateHandlerText=A text message handler has already been configured wsSession.invalidHandlerTypePong=A pong message handler must implement MessageHandler.Basic wsSession.messageFailed=Unable to write the complete message as the WebSocket connection has been closed wsSession.sendCloseFail=Failed to send close message to remote endpoint wsSession.removeHandlerFailed=Unable to remove the handler [{0}] as it was not registered with this session wsSession.unknownHandler=Unable to add the message handler [{0}] as it was for the unrecognised type [{1}] wsSession.unknownHandlerType=Unable to add the message handler [{0}] as it was wrapped as the unrecognised type [{1}] # Note the following message is used as a close reason in a WebSocket control # frame and therefore must be 123 bytes (not characters) or less in length. # Messages are encoded using UTF-8 where a single character may be encoded in # as many as 4 bytes. wsWebSocketContainer.shutdown=The web application is stopping wsWebSocketContainer.asynchronousChannelGroupFail=Unable to create dedicated AsynchronousChannelGroup for WebSocket clients which is required to prevent memory leaks in complex class loader environments like J2EE containers wsWebSocketContainer.asynchronousSocketChannelFail=Unable to open a connection to the server wsWebSocketContainer.defaultConfiguratorFaill=Failed to create the default configurator wsWebSocketContainer.endpointCreateFail=Failed to create a local endpoint of type [{0}] wsWebSocketContainer.httpRequestFailed=The HTTP request to initiate the WebSocket connection failed wsWebSocketContainer.invalidHeader=Unable to parse HTTP header as no colon is present to delimit header name and header value in [{0}]. The header has been skipped. wsWebSocketContainer.invalidScheme=The requested scheme, [{0}], is not supported. The supported schemes are ws and wss wsWebSocketContainer.invalidStatus=The HTTP response from the server [{0}] did not permit the HTTP upgrade to WebSocket wsWebSocketContainer.invalidSubProtocol=The WebSocket server returned multiple values for the Sec-WebSocket-Protocol header wsWebSocketContainer.maxBuffer=This implementation limits the maximum size of a buffer to Integer.MAX_VALUE wsWebSocketContainer.missingAnnotation=Cannot use POJO class [{0}] as it is not annotated with @ClientEndpoint wsWebSocketContainer.pathNoHost=No host was specified in URI wsWebSocketContainer.pathWrongScheme=The scheme [{0}] is not supported wsWebSocketContainer.sessionCloseFail=Session with ID [{0}] did not close cleanly wsWebSocketContainer.sslEngineFail=Unable to create SSLEngine to support SSL/TLS connections tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsRemoteEndpointBase.java0000644000175100017510000000355612166436036026275 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import java.nio.ByteBuffer; import javax.websocket.RemoteEndpoint; public abstract class WsRemoteEndpointBase implements RemoteEndpoint { protected final WsRemoteEndpointImplBase base; WsRemoteEndpointBase(WsRemoteEndpointImplBase base) { this.base = base; } @Override public final void setBatchingAllowed(boolean batchingAllowed) throws IOException { base.setBatchingAllowed(batchingAllowed); } @Override public final boolean getBatchingAllowed() { return base.getBatchingAllowed(); } @Override public final void flushBatch() throws IOException { base.flushBatch(); } @Override public final void sendPing(ByteBuffer applicationData) throws IOException, IllegalArgumentException { base.sendPing(applicationData); } @Override public final void sendPong(ByteBuffer applicationData) throws IOException, IllegalArgumentException { base.sendPong(applicationData); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/AsyncChannelWrapperSecure.java0000644000175100017510000005002012203452576027275 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLEngineResult.Status; import javax.net.ssl.SSLException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Wraps the {@link AsynchronousSocketChannel} with SSL/TLS. This needs a lot * more testing before it can be considered robust. */ public class AsyncChannelWrapperSecure implements AsyncChannelWrapper { private static final Log log = LogFactory.getLog(AsyncChannelWrapperSecure.class); private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private static final ByteBuffer DUMMY = ByteBuffer.allocate(8192); private final AsynchronousSocketChannel socketChannel; private final SSLEngine sslEngine; private final ByteBuffer socketReadBuffer; private final ByteBuffer socketWriteBuffer; // One thread for read, one for write private final ExecutorService executor = Executors.newFixedThreadPool(2); private AtomicBoolean writing = new AtomicBoolean(false); private AtomicBoolean reading = new AtomicBoolean(false); public AsyncChannelWrapperSecure(AsynchronousSocketChannel socketChannel, SSLEngine sslEngine) { this.socketChannel = socketChannel; this.sslEngine = sslEngine; int socketBufferSize = sslEngine.getSession().getPacketBufferSize(); socketReadBuffer = ByteBuffer.allocateDirect(socketBufferSize); socketWriteBuffer = ByteBuffer.allocateDirect(socketBufferSize); } @Override public Future read(ByteBuffer dst) { WrapperFuture future = new WrapperFuture(); if (!reading.compareAndSet(false, true)) { throw new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.concurrentRead")); } ReadTask readTask = new ReadTask(dst, future); executor.execute(readTask); return future; } @Override public void read(ByteBuffer dst, A attachment, CompletionHandler handler) { WrapperFuture future = new WrapperFuture(handler, attachment); if (!reading.compareAndSet(false, true)) { throw new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.concurrentRead")); } ReadTask readTask = new ReadTask(dst, future); executor.execute(readTask); } @Override public Future write(ByteBuffer src) { WrapperFuture inner = new WrapperFuture(); if (!writing.compareAndSet(false, true)) { throw new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.concurrentWrite")); } WriteTask writeTask = new WriteTask(new ByteBuffer[] {src}, 0, 1, inner); executor.execute(writeTask); Future future = new LongToIntegerFuture(inner); return future; } @Override public void write(ByteBuffer[] srcs, int offset, int length, long timeout, TimeUnit unit, A attachment, CompletionHandler handler) { WrapperFuture future = new WrapperFuture(handler, attachment); if (!writing.compareAndSet(false, true)) { throw new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.concurrentWrite")); } WriteTask writeTask = new WriteTask(srcs, offset, length, future); executor.execute(writeTask); } @Override public void close() { try { socketChannel.close(); } catch (IOException e) { log.info(sm.getString("asyncChannelWrapperSecure.closeFail")); } } @Override public Future handshake() throws SSLException { WrapperFuture wFuture = new WrapperFuture(); Thread t = new WebSocketSslHandshakeThread(wFuture); t.start(); return wFuture; } private class WriteTask implements Runnable { private final ByteBuffer[] srcs; private final int offset; private final int length; private final WrapperFuture future; public WriteTask(ByteBuffer[] srcs, int offset, int length, WrapperFuture future) { this.srcs = srcs; this.future = future; this.offset = offset; this.length = length; } @Override public void run() { long written = 0; try { for (int i = offset; i < offset + length; i++) { ByteBuffer src = srcs[i]; while (src.hasRemaining()) { socketWriteBuffer.clear(); // Encrypt the data SSLEngineResult r = sslEngine.wrap(src, socketWriteBuffer); written += r.bytesConsumed(); Status s = r.getStatus(); if (s == Status.OK || s == Status.BUFFER_OVERFLOW) { // Need to write out the bytes and may need to read from // the source again to empty it } else { // Status.BUFFER_UNDERFLOW - only happens on unwrap // Status.CLOSED - unexpected throw new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.statusWrap")); } // Check for tasks if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { Runnable runnable = sslEngine.getDelegatedTask(); while (runnable != null) { runnable.run(); runnable = sslEngine.getDelegatedTask(); } } socketWriteBuffer.flip(); // Do the write int toWrite = r.bytesProduced(); while (toWrite > 0) { Future f = socketChannel.write(socketWriteBuffer); Integer socketWrite = f.get(); toWrite -= socketWrite.intValue(); } } } if (writing.compareAndSet(true, false)) { future.complete(Long.valueOf(written)); } else { future.fail(new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.wrongStateWrite"))); } } catch (Exception e) { future.fail(e); } } } private class ReadTask implements Runnable { private final ByteBuffer dest; private final WrapperFuture future; public ReadTask(ByteBuffer dest, WrapperFuture future) { this.dest = dest; this.future = future; } @Override public void run() { int read = 0; boolean forceRead = false; try { while (read == 0) { socketReadBuffer.compact(); if (forceRead) { Future f = socketChannel.read(socketReadBuffer); Integer socketRead = f.get(); if (socketRead.intValue() == -1) { throw new EOFException(sm.getString( "asyncChannelWrapperSecure.eof")); } } socketReadBuffer.flip(); if (socketReadBuffer.hasRemaining()) { // Decrypt the data in the buffer SSLEngineResult r = sslEngine.unwrap(socketReadBuffer, dest); read += r.bytesProduced(); Status s = r.getStatus(); if (s == Status.OK) { // Bytes available for reading and there may be // sufficient data in the socketReadBuffer to // support further reads without reading from the // socket } else if (s == Status.BUFFER_UNDERFLOW) { // There is partial data in the socketReadBuffer if (read == 0) { // Need more data before the partial data can be // processed and some output generated forceRead = true; } // else return the data we have and deal with the // partial data on the next read } else if (s == Status.BUFFER_OVERFLOW) { // Not enough space in the destination buffer to // store all of the data. We could use a bytes read // value of -bufferSizeRequired to signal the new // buffer size required but an explicit exception is // clearer. if (reading.compareAndSet(true, false)) { throw new ReadBufferOverflowException(sslEngine. getSession().getApplicationBufferSize()); } else { future.fail(new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.wrongStateRead"))); } } else { // Status.CLOSED - unexpected throw new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.statusUnwrap")); } // Check for tasks if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { Runnable runnable = sslEngine.getDelegatedTask(); while (runnable != null) { runnable.run(); runnable = sslEngine.getDelegatedTask(); } } } else { forceRead = true; } } if (reading.compareAndSet(true, false)) { future.complete(Integer.valueOf(read)); } else { future.fail(new IllegalStateException(sm.getString( "asyncChannelWrapperSecure.wrongStateRead"))); } } catch (Exception e) { future.fail(e); } } } private class WebSocketSslHandshakeThread extends Thread { private final WrapperFuture hFuture; private HandshakeStatus handshakeStatus; private Status resultStatus; public WebSocketSslHandshakeThread(WrapperFuture hFuture) { this.hFuture = hFuture; } @Override public void run() { try { sslEngine.beginHandshake(); // So the first compact does the right thing socketReadBuffer.position(socketReadBuffer.limit()); handshakeStatus = sslEngine.getHandshakeStatus(); resultStatus = Status.OK; boolean handshaking = true; while(handshaking) { switch (handshakeStatus) { case NEED_WRAP: { socketWriteBuffer.clear(); SSLEngineResult r = sslEngine.wrap(DUMMY, socketWriteBuffer); checkResult(r, true); socketWriteBuffer.flip(); Future fWrite = socketChannel.write(socketWriteBuffer); fWrite.get(); break; } case NEED_UNWRAP: { socketReadBuffer.compact(); if (socketReadBuffer.position() == 0 || resultStatus == Status.BUFFER_UNDERFLOW) { Future fRead = socketChannel.read(socketReadBuffer); fRead.get(); } socketReadBuffer.flip(); SSLEngineResult r = sslEngine.unwrap(socketReadBuffer, DUMMY); checkResult(r, false); break; } case NEED_TASK: { Runnable r = null; while ((r = sslEngine.getDelegatedTask()) != null) { r.run(); } handshakeStatus = sslEngine.getHandshakeStatus(); break; } case FINISHED: { handshaking = false; break; } default: { throw new SSLException("TODO"); } } } } catch (SSLException e) { hFuture.fail(e); } catch (InterruptedException e) { hFuture.fail(e); } catch (ExecutionException e) { hFuture.fail(e); } hFuture.complete(null); } private void checkResult(SSLEngineResult result, boolean wrap) throws SSLException { handshakeStatus = result.getHandshakeStatus(); resultStatus = result.getStatus(); if (resultStatus != Status.OK && (wrap || resultStatus != Status.BUFFER_UNDERFLOW)) { throw new SSLException("TODO"); } if (wrap && result.bytesConsumed() != 0) { throw new SSLException("TODO"); } if (!wrap && result.bytesProduced() != 0) { throw new SSLException("TODO"); } } } private static class WrapperFuture implements Future { private final CompletionHandler handler; private final A attachment; private volatile T result = null; private volatile Throwable throwable = null; private CountDownLatch completionLatch = new CountDownLatch(1); public WrapperFuture() { this(null, null); } public WrapperFuture(CompletionHandler handler, A attachment) { this.handler = handler; this.attachment = attachment; } public void complete(T result) { this.result = result; completionLatch.countDown(); if (handler != null) { handler.completed(result, attachment); } } public void fail(Throwable t) { throwable = t; completionLatch.countDown(); if (handler != null) { handler.failed(throwable, attachment); } } @Override public final boolean cancel(boolean mayInterruptIfRunning) { // Could support cancellation by closing the connection return false; } @Override public final boolean isCancelled() { // Could support cancellation by closing the connection return false; } @Override public final boolean isDone() { return completionLatch.getCount() > 0; } @Override public T get() throws InterruptedException, ExecutionException { completionLatch.await(); if (throwable != null) { throw new ExecutionException(throwable); } return result; } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { boolean latchResult = completionLatch.await(timeout, unit); if (latchResult == false) { throw new TimeoutException(); } if (throwable != null) { throw new ExecutionException(throwable); } return result; } } private static final class LongToIntegerFuture implements Future { private final Future wrapped; public LongToIntegerFuture(Future wrapped) { this.wrapped = wrapped; } @Override public boolean cancel(boolean mayInterruptIfRunning) { return wrapped.cancel(mayInterruptIfRunning); } @Override public boolean isCancelled() { return wrapped.isCancelled(); } @Override public boolean isDone() { return wrapped.isDone(); } @Override public Integer get() throws InterruptedException, ExecutionException { Long result = wrapped.get(); if (result.longValue() > Integer.MAX_VALUE) { throw new ExecutionException(sm.getString( "asyncChannelWrapperSecure.tooBig", result), null); } return new Integer(result.intValue()); } @Override public Integer get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { Long result = wrapped.get(timeout, unit); if (result.longValue() > Integer.MAX_VALUE) { throw new ExecutionException(sm.getString( "asyncChannelWrapperSecure.tooBig", result), null); } return new Integer(result.intValue()); } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/0000755000175100017510000000000012301126367022321 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerPartialBinary.java0000644000175100017510000000272312162573554031375 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.lang.reflect.Method; import java.nio.ByteBuffer; import javax.websocket.Session; /** * ByteBuffer specific concrete implementation for handling partial messages. */ public class PojoMessageHandlerPartialBinary extends PojoMessageHandlerPartialBase{ public PojoMessageHandlerPartialBinary(Object pojo, Method method, Session session, Object[] params, int indexPayload, boolean convert, int indexBoolean, int indexSession, long maxMessageSize) { super(pojo, method, session, params, indexPayload, convert, indexBoolean, indexSession, maxMessageSize); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBase.java0000644000175100017510000000620412203443675030477 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.websocket.DecodeException; import javax.websocket.MessageHandler; import javax.websocket.Session; import org.apache.tomcat.websocket.WsSession; /** * Common implementation code for the POJO whole message handlers. All the real * work is done in this class and in the superclass. * * @param The type of message to handle */ public abstract class PojoMessageHandlerWholeBase extends PojoMessageHandlerBase implements MessageHandler.Whole { public PojoMessageHandlerWholeBase(Object pojo, Method method, Session session, Object[] params, int indexPayload, boolean convert, int indexSession, long maxMessageSize) { super(pojo, method, session, params, indexPayload, convert, indexSession, maxMessageSize); } @Override public final void onMessage(T message) { if (params.length == 1 && params[0] instanceof DecodeException) { ((WsSession) session).getLocal().onError(session, (DecodeException) params[0]); return; } // Can this message be decoded? Object payload; try { payload = decode(message); } catch (DecodeException de) { ((WsSession) session).getLocal().onError(session, de); return; } if (payload == null) { // Not decoded. Convert if required. if (convert) { payload = convert(message); } else { payload = message; } } Object[] parameters = params.clone(); if (indexSession != -1) { parameters[indexSession] = session; } parameters[indexPayload] = payload; Object result; try { result = method.invoke(pojo, parameters); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InvocationTargetException e) { throw new IllegalArgumentException(e); } processResult(result); } protected Object convert(T message) { return message; } protected abstract Object decode(T message) throws DecodeException; protected abstract void onClose(); } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeBinary.java0000644000175100017510000001166112253651561031054 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.Decoder.Binary; import javax.websocket.Decoder.BinaryStream; import javax.websocket.EndpointConfig; import javax.websocket.Session; import org.apache.tomcat.util.res.StringManager; /** * ByteBuffer specific concrete implementation for handling whole messages. */ public class PojoMessageHandlerWholeBinary extends PojoMessageHandlerWholeBase { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private final List decoders = new ArrayList(); private final boolean isForInputStream; public PojoMessageHandlerWholeBinary(Object pojo, Method method, Session session, EndpointConfig config, List> decoderClazzes, Object[] params, int indexPayload, boolean convert, int indexSession, boolean isForInputStream, long maxMessageSize) { super(pojo, method, session, params, indexPayload, convert, indexSession, maxMessageSize); // Update binary text size handled by session if (maxMessageSize > -1 && maxMessageSize > session.getMaxBinaryMessageBufferSize()) { if (maxMessageSize > Integer.MAX_VALUE) { throw new IllegalArgumentException(sm.getString( "pojoMessageHandlerWhole.maxBufferSize")); } session.setMaxBinaryMessageBufferSize((int) maxMessageSize); } try { if (decoderClazzes != null) { for (Class decoderClazz : decoderClazzes) { if (Binary.class.isAssignableFrom(decoderClazz)) { Binary decoder = (Binary) decoderClazz.newInstance(); decoder.init(config); decoders.add(decoder); } else if (BinaryStream.class.isAssignableFrom( decoderClazz)) { BinaryStream decoder = (BinaryStream) decoderClazz.newInstance(); decoder.init(config); decoders.add(decoder); } else { // Text decoder - ignore it } } } } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InstantiationException e) { throw new IllegalArgumentException(e); } this.isForInputStream = isForInputStream; } @Override protected Object decode(ByteBuffer message) throws DecodeException { for (Decoder decoder : decoders) { if (decoder instanceof Binary) { if (((Binary) decoder).willDecode(message)) { return ((Binary) decoder).decode(message); } } else { byte[] array = new byte[message.limit() - message.position()]; message.get(array); ByteArrayInputStream bais = new ByteArrayInputStream(array); try { return ((BinaryStream) decoder).decode(bais); } catch (IOException ioe) { throw new DecodeException(message, sm.getString( "pojoMessageHandlerWhole.decodeIoFail"), ioe); } } } return null; } @Override protected Object convert(ByteBuffer message) { byte[] array = new byte[message.remaining()]; message.get(array); if (isForInputStream) { return new ByteArrayInputStream(array); } else { return array; } } @Override protected void onClose() { for (Decoder decoder : decoders) { decoder.destroy(); } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoPathParam.java0000644000175100017510000000305712112637506025700 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; /** * Stores the parameter type and name for a parameter that needs to be passed to * an onXxx method of {@link javax.websocket.Endpoint}. The name is only present * for parameters annotated with * {@link javax.websocket.server.PathParam}. For the * {@link javax.websocket.Session} and {@link java.lang.Throwable} parameters, * {@link #getName()} will always return null. */ public class PojoPathParam { private final Class type; private final String name; public PojoPathParam(Class type, String name) { this.type = type; this.name = name; } public Class getType() { return type; } public String getName() { return name; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoEndpointBase.java0000644000175100017510000001322112163021116026356 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.Set; import javax.websocket.CloseReason; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.Session; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Base implementation (client and server have different concrete * implementations) of the wrapper that converts a POJO instance into a * WebSocket endpoint instance. */ public abstract class PojoEndpointBase extends Endpoint { private static final Log log = LogFactory.getLog(PojoEndpointBase.class); private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private Object pojo; private Map pathParameters; private PojoMethodMapping methodMapping; protected final void doOnOpen(Session session, EndpointConfig config) { PojoMethodMapping methodMapping = getMethodMapping(); Object pojo = getPojo(); Map pathParameters = getPathParameters(); if (methodMapping.getOnOpen() != null) { try { methodMapping.getOnOpen().invoke(pojo, methodMapping.getOnOpenArgs( pathParameters, session, config)); } catch (IllegalAccessException e) { // Reflection related problems log.error(sm.getString( "pojoEndpointBase.onOpenFail", pojo.getClass().getName()), e); handleOnOpenError(session, e); return; } catch (InvocationTargetException e) { Throwable cause = e.getCause(); handleOnOpenError(session, cause); return; } catch (Throwable t) { handleOnOpenError(session, t); return; } } for (MessageHandler mh : methodMapping.getMessageHandlers(pojo, pathParameters, session, config)) { session.addMessageHandler(mh); } } private void handleOnOpenError(Session session, Throwable t) { // If really fatal - re-throw ExceptionUtils.handleThrowable(t); // Trigger the error handler and close the session onError(session, t); try { session.close(); } catch (IOException ioe) { log.warn(sm.getString("pojoEndpointBase.closeSessionFail"), ioe); } } @Override public final void onClose(Session session, CloseReason closeReason) { if (methodMapping.getOnClose() != null) { try { methodMapping.getOnClose().invoke(pojo, methodMapping.getOnCloseArgs(pathParameters, session, closeReason)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("pojoEndpointBase.onCloseFail", pojo.getClass().getName()), t); } } // Trigger the destroy method for any associated decoders Set messageHandlers = session.getMessageHandlers(); for (MessageHandler messageHandler : messageHandlers) { if (messageHandler instanceof PojoMessageHandlerWholeBase) { ((PojoMessageHandlerWholeBase) messageHandler).onClose(); } } } @Override public final void onError(Session session, Throwable throwable) { if (methodMapping.getOnError() == null) { log.error(sm.getString("pojoEndpointBase.onError", pojo.getClass().getName()), throwable); } else { try { methodMapping.getOnError().invoke( pojo, methodMapping.getOnErrorArgs(pathParameters, session, throwable)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("pojoEndpointBase.onErrorFail", pojo.getClass().getName()), t); } } } protected Object getPojo() { return pojo; } protected void setPojo(Object pojo) { this.pojo = pojo; } protected Map getPathParameters() { return pathParameters; } protected void setPathParameters(Map pathParameters) { this.pathParameters = pathParameters; } protected PojoMethodMapping getMethodMapping() { return methodMapping; } protected void setMethodMapping(PojoMethodMapping methodMapping) { this.methodMapping = methodMapping; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerPartialBase.java0000644000175100017510000000554712203443675031026 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.ByteBuffer; import javax.websocket.DecodeException; import javax.websocket.MessageHandler; import javax.websocket.Session; import org.apache.tomcat.websocket.WsSession; /** * Common implementation code for the POJO partial message handlers. All * the real work is done in this class and in the superclass. * * @param The type of message to handle */ public abstract class PojoMessageHandlerPartialBase extends PojoMessageHandlerBase implements MessageHandler.Partial { private final int indexBoolean; public PojoMessageHandlerPartialBase(Object pojo, Method method, Session session, Object[] params, int indexPayload, boolean convert, int indexBoolean, int indexSession, long maxMessageSize) { super(pojo, method, session, params, indexPayload, convert, indexSession, maxMessageSize); this.indexBoolean = indexBoolean; } @Override public final void onMessage(T message, boolean last) { if (params.length == 1 && params[0] instanceof DecodeException) { ((WsSession) session).getLocal().onError(session, (DecodeException) params[0]); return; } Object[] parameters = params.clone(); if (indexBoolean != -1) { parameters[indexBoolean] = Boolean.valueOf(last); } if (indexSession != -1) { parameters[indexSession] = session; } if (convert) { parameters[indexPayload] = ((ByteBuffer) message).array(); } else { parameters[indexPayload] = message; } Object result; try { result = method.invoke(pojo, parameters); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InvocationTargetException e) { throw new IllegalArgumentException(e); } processResult(result); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoEndpointClient.java0000644000175100017510000000326412177467165026757 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.util.Collections; import javax.websocket.Decoder; import javax.websocket.DeploymentException; import javax.websocket.EndpointConfig; import javax.websocket.Session; /** * Wrapper class for instances of POJOs annotated with * {@link javax.websocket.ClientEndpoint} so they appear as standard * {@link javax.websocket.Endpoint} instances. */ public class PojoEndpointClient extends PojoEndpointBase { public PojoEndpointClient(Object pojo, Class[] decoders) throws DeploymentException { setPojo(pojo); setMethodMapping( new PojoMethodMapping(pojo.getClass(), decoders, null)); setPathParameters(Collections. emptyMap()); } @Override public void onOpen(Session session, EndpointConfig config) { doOnOpen(session, config); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java0000644000175100017510000006410712203443675026565 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.io.InputStream; import java.io.Reader; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.websocket.CloseReason; import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.DeploymentException; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.PongMessage; import javax.websocket.Session; import javax.websocket.server.PathParam; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.websocket.DecoderEntry; import org.apache.tomcat.websocket.Util; import org.apache.tomcat.websocket.Util.DecoderMatch; /** * For a POJO class annotated with * {@link javax.websocket.server.ServerEndpoint}, an instance of this class * creates and caches the method handler, method information and parameter * information for the onXXX calls. */ public class PojoMethodMapping { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private final Method onOpen; private final Method onClose; private final Method onError; private final PojoPathParam[] onOpenParams; private final PojoPathParam[] onCloseParams; private final PojoPathParam[] onErrorParams; private final Set onMessage = new HashSet(); private final String wsPath; public PojoMethodMapping(Class clazzPojo, Class[] decoderClazzes, String wsPath) throws DeploymentException { this.wsPath = wsPath; List decoders = Util.getDecoders(decoderClazzes); Method open = null; Method close = null; Method error = null; for (Method method : clazzPojo.getDeclaredMethods()) { if (method.getAnnotation(OnOpen.class) != null) { checkPublic(method); if (open == null) { open = method; } else { // Duplicate annotation throw new DeploymentException(sm.getString( "pojoMethodMapping.duplicateAnnotation", OnOpen.class, clazzPojo)); } } else if (method.getAnnotation(OnClose.class) != null) { checkPublic(method); if (close == null) { close = method; } else { // Duplicate annotation throw new DeploymentException(sm.getString( "pojoMethodMapping.duplicateAnnotation", OnClose.class, clazzPojo)); } } else if (method.getAnnotation(OnError.class) != null) { checkPublic(method); if (error == null) { error = method; } else { // Duplicate annotation throw new DeploymentException(sm.getString( "pojoMethodMapping.duplicateAnnotation", OnError.class, clazzPojo)); } } else if (method.getAnnotation(OnMessage.class) != null) { checkPublic(method); onMessage.add(new MessageHandlerInfo(method, decoders)); } else { // Method not annotated } } this.onOpen = open; this.onClose = close; this.onError = error; onOpenParams = getPathParams(onOpen, MethodType.ON_OPEN); onCloseParams = getPathParams(onClose, MethodType.ON_CLOSE); onErrorParams = getPathParams(onError, MethodType.ON_ERROR); } private void checkPublic(Method m) throws DeploymentException { if (!Modifier.isPublic(m.getModifiers())) { throw new DeploymentException(sm.getString( "pojoMethodMapping.methodNotPublic", m.getName())); } } public String getWsPath() { return wsPath; } public Method getOnOpen() { return onOpen; } public Object[] getOnOpenArgs(Map pathParameters, Session session, EndpointConfig config) throws DecodeException { return buildArgs(onOpenParams, pathParameters, session, config, null, null); } public Method getOnClose() { return onClose; } public Object[] getOnCloseArgs(Map pathParameters, Session session, CloseReason closeReason) throws DecodeException { return buildArgs(onCloseParams, pathParameters, session, null, null, closeReason); } public Method getOnError() { return onError; } public Object[] getOnErrorArgs(Map pathParameters, Session session, Throwable throwable) throws DecodeException { return buildArgs(onErrorParams, pathParameters, session, null, throwable, null); } public Set getMessageHandlers(Object pojo, Map pathParameters, Session session, EndpointConfig config) { Set result = new HashSet(); for (MessageHandlerInfo messageMethod : onMessage) { result.addAll(messageMethod.getMessageHandlers(pojo, pathParameters, session, config)); } return result; } private static PojoPathParam[] getPathParams(Method m, MethodType methodType) throws DeploymentException { if (m == null) { return new PojoPathParam[0]; } boolean foundThrowable = false; Class[] types = m.getParameterTypes(); Annotation[][] paramsAnnotations = m.getParameterAnnotations(); PojoPathParam[] result = new PojoPathParam[types.length]; for (int i = 0; i < types.length; i++) { Class type = types[i]; if (type.equals(Session.class)) { result[i] = new PojoPathParam(type, null); } else if (methodType == MethodType.ON_OPEN && type.equals(EndpointConfig.class)) { result[i] = new PojoPathParam(type, null); } else if (methodType == MethodType.ON_ERROR && type.equals(Throwable.class)) { foundThrowable = true; result[i] = new PojoPathParam(type, null); } else if (methodType == MethodType.ON_CLOSE && type.equals(CloseReason.class)) { result[i] = new PojoPathParam(type, null); } else { Annotation[] paramAnnotations = paramsAnnotations[i]; for (Annotation paramAnnotation : paramAnnotations) { if (paramAnnotation.annotationType().equals( PathParam.class)) { // Check that the type is valid. "0" coerces to every // valid type try { Util.coerceToType(type, "0"); } catch (IllegalArgumentException iae) { throw new DeploymentException(sm.getString( "pojoMethodMapping.invalidPathParamType"), iae); } result[i] = new PojoPathParam(type, ((PathParam) paramAnnotation).value()); break; } } // Parameters without annotations are not permitted if (result[i] == null) { throw new DeploymentException(sm.getString( "pojoMethodMapping.paramWithoutAnnotation", type, m.getName(), m.getClass().getName())); } } } if (methodType == MethodType.ON_ERROR && !foundThrowable) { throw new DeploymentException(sm.getString( "pojoMethodMapping.onErrorNoThrowable", m.getName(), m.getDeclaringClass().getName())); } return result; } private static Object[] buildArgs(PojoPathParam[] pathParams, Map pathParameters, Session session, EndpointConfig config, Throwable throwable, CloseReason closeReason) throws DecodeException { Object[] result = new Object[pathParams.length]; for (int i = 0; i < pathParams.length; i++) { Class type = pathParams[i].getType(); if (type.equals(Session.class)) { result[i] = session; } else if (type.equals(EndpointConfig.class)) { result[i] = config; } else if (type.equals(Throwable.class)) { result[i] = throwable; } else if (type.equals(CloseReason.class)) { result[i] = closeReason; } else { String name = pathParams[i].getName(); String value = pathParameters.get(name); try { result[i] = Util.coerceToType(type, value); } catch (Exception e) { throw new DecodeException(value, sm.getString( "pojoMethodMapping.decodePathParamFail", value, type), e); } } } return result; } private static class MessageHandlerInfo { private final Method m; private int indexString = -1; private int indexByteArray = -1; private int indexByteBuffer = -1; private int indexPong = -1; private int indexBoolean = -1; private int indexSession = -1; private int indexInputStream = -1; private int indexReader = -1; private int indexPrimitive = -1; private Map indexPathParams = new HashMap(); private int indexPayload = -1; private DecoderMatch decoderMatch = null; private long maxMessageSize = -1; public MessageHandlerInfo(Method m, List decoderEntries) { this.m = m; Class[] types = m.getParameterTypes(); Annotation[][] paramsAnnotations = m.getParameterAnnotations(); for (int i = 0; i < types.length; i++) { boolean paramFound = false; Annotation[] paramAnnotations = paramsAnnotations[i]; for (Annotation paramAnnotation : paramAnnotations) { if (paramAnnotation.annotationType().equals( PathParam.class)) { indexPathParams.put( Integer.valueOf(i), new PojoPathParam(types[i], ((PathParam) paramAnnotation).value())); paramFound = true; break; } } if (paramFound) { continue; } if (String.class.isAssignableFrom(types[i])) { if (indexString == -1) { indexString = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } } else if (Reader.class.isAssignableFrom(types[i])) { if (indexReader == -1) { indexReader = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } } else if (boolean.class == types[i]) { if (indexBoolean == -1) { indexBoolean = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateLastParam", m.getName(), m.getDeclaringClass().getName())); } } else if (ByteBuffer.class.isAssignableFrom(types[i])) { if (indexByteBuffer == -1) { indexByteBuffer = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } } else if (byte[].class == types[i]) { if (indexByteArray == -1) { indexByteArray = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } } else if (InputStream.class.isAssignableFrom(types[i])) { if (indexInputStream == -1) { indexInputStream = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } } else if (Util.isPrimitive(types[i])) { if (indexPrimitive == -1) { indexPrimitive = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } } else if (Session.class.isAssignableFrom(types[i])) { if (indexSession == -1) { indexSession = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateSessionParam", m.getName(), m.getDeclaringClass().getName())); } } else if (PongMessage.class.isAssignableFrom(types[i])) { if (indexPong == -1) { indexPong = i; } else { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicatePongMessageParam", m.getName(), m.getDeclaringClass().getName())); } } else { if (decoderMatch != null && decoderMatch.hasMatches()) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } decoderMatch = new DecoderMatch(types[i], decoderEntries); if (decoderMatch.hasMatches()) { indexPayload = i; } } } // Additional checks required if (indexString != -1) { if (indexPayload != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } else { indexPayload = indexString; } } if (indexReader != -1) { if (indexPayload != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } else { indexPayload = indexReader; } } if (indexByteArray != -1) { if (indexPayload != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } else { indexPayload = indexByteArray; } } if (indexByteBuffer != -1) { if (indexPayload != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } else { indexPayload = indexByteBuffer; } } if (indexInputStream != -1) { if (indexPayload != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } else { indexPayload = indexInputStream; } } if (indexPrimitive != -1) { if (indexPayload != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.duplicateMessageParam", m.getName(), m.getDeclaringClass().getName())); } else { indexPayload = indexPrimitive; } } if (indexPong != -1) { if (indexPayload != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.pongWithPayload", m.getName(), m.getDeclaringClass().getName())); } else { indexPayload = indexPong; } } if (indexPayload == -1 && indexPrimitive == -1 && indexBoolean != -1) { // The boolean we found is a payload, not a last flag indexPayload = indexBoolean; indexPrimitive = indexBoolean; indexBoolean = -1; } if (indexPayload == -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.noPayload", m.getName(), m.getDeclaringClass().getName())); } if (indexPong != -1 && indexBoolean != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.partialPong", m.getName(), m.getDeclaringClass().getName())); } if(indexReader != -1 && indexBoolean != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.partialReader", m.getName(), m.getDeclaringClass().getName())); } if(indexInputStream != -1 && indexBoolean != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.partialInputStream", m.getName(), m.getDeclaringClass().getName())); } if (decoderMatch != null && decoderMatch.hasMatches() && indexBoolean != -1) { throw new IllegalArgumentException(sm.getString( "pojoMethodMapping.partialObject", m.getName(), m.getDeclaringClass().getName())); } maxMessageSize = m.getAnnotation(OnMessage.class).maxMessageSize(); } public Set getMessageHandlers(Object pojo, Map pathParameters, Session session, EndpointConfig config) { Object[] params = new Object[m.getParameterTypes().length]; for (Map.Entry entry : indexPathParams.entrySet()) { PojoPathParam pathParam = entry.getValue(); String valueString = pathParameters.get(pathParam.getName()); Object value = null; try { value = Util.coerceToType(pathParam.getType(), valueString); } catch (Exception e) { DecodeException de = new DecodeException(valueString, sm.getString( "pojoMethodMapping.decodePathParamFail", valueString, pathParam.getType()), e); params = new Object[] { de }; } params[entry.getKey().intValue()] = value; } Set results = new HashSet(2); if (indexBoolean == -1) { // Basic if (indexString != -1 || indexPrimitive != -1) { MessageHandler mh = new PojoMessageHandlerWholeText(pojo, m, session, config, null, params, indexPayload, false, indexSession, maxMessageSize); results.add(mh); } else if (indexReader != -1) { MessageHandler mh = new PojoMessageHandlerWholeText(pojo, m, session, config, null, params, indexReader, true, indexSession, maxMessageSize); results.add(mh); } else if (indexByteArray != -1) { MessageHandler mh = new PojoMessageHandlerWholeBinary(pojo, m, session, config, null, params, indexByteArray, true, indexSession, false, maxMessageSize); results.add(mh); } else if (indexByteBuffer != -1) { MessageHandler mh = new PojoMessageHandlerWholeBinary(pojo, m, session, config, null, params, indexByteBuffer, false, indexSession, false, maxMessageSize); results.add(mh); } else if (indexInputStream != -1) { MessageHandler mh = new PojoMessageHandlerWholeBinary(pojo, m, session, config, null, params, indexInputStream, true, indexSession, true, maxMessageSize); results.add(mh); } else if (decoderMatch != null && decoderMatch.hasMatches()) { if (decoderMatch.getBinaryDecoders().size() > 0) { MessageHandler mh = new PojoMessageHandlerWholeBinary( pojo, m, session, config, decoderMatch.getBinaryDecoders(), params, indexPayload, true, indexSession, true, maxMessageSize); results.add(mh); } if (decoderMatch.getTextDecoders().size() > 0) { MessageHandler mh = new PojoMessageHandlerWholeText( pojo, m, session, config, decoderMatch.getTextDecoders(), params, indexPayload, true, indexSession, maxMessageSize); results.add(mh); } } else { MessageHandler mh = new PojoMessageHandlerWholePong(pojo, m, session, params, indexPong, false, indexSession); results.add(mh); } } else { // ASync if (indexString != -1) { MessageHandler mh = new PojoMessageHandlerPartialText(pojo, m, session, params, indexString, false, indexBoolean, indexSession, maxMessageSize); results.add(mh); } else if (indexByteArray != -1) { MessageHandler mh = new PojoMessageHandlerPartialBinary( pojo, m, session, params, indexByteArray, true, indexBoolean, indexSession, maxMessageSize); results.add(mh); } else { MessageHandler mh = new PojoMessageHandlerPartialBinary( pojo, m, session, params, indexByteBuffer, false, indexBoolean, indexSession, maxMessageSize); results.add(mh); } } return results; } } private static enum MethodType { ON_OPEN, ON_CLOSE, ON_ERROR } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholeText.java0000644000175100017510000001160312253651561030550 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.io.IOException; import java.io.StringReader; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.Decoder.Text; import javax.websocket.Decoder.TextStream; import javax.websocket.EndpointConfig; import javax.websocket.Session; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.websocket.Util; /** * Text specific concrete implementation for handling whole messages. */ public class PojoMessageHandlerWholeText extends PojoMessageHandlerWholeBase { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private final List decoders = new ArrayList(); private final Class primitiveType; public PojoMessageHandlerWholeText(Object pojo, Method method, Session session, EndpointConfig config, List> decoderClazzes, Object[] params, int indexPayload, boolean convert, int indexSession, long maxMessageSize) { super(pojo, method, session, params, indexPayload, convert, indexSession, maxMessageSize); // Update max text size handled by session if (maxMessageSize > -1 && maxMessageSize > session.getMaxTextMessageBufferSize()) { if (maxMessageSize > Integer.MAX_VALUE) { throw new IllegalArgumentException(sm.getString( "pojoMessageHandlerWhole.maxBufferSize")); } session.setMaxTextMessageBufferSize((int) maxMessageSize); } // Check for primitives Class type = method.getParameterTypes()[indexPayload]; if (Util.isPrimitive(type)) { primitiveType = type; return; } else { primitiveType = null; } try { if (decoderClazzes != null) { for (Class decoderClazz : decoderClazzes) { if (Text.class.isAssignableFrom(decoderClazz)) { Text decoder = (Text) decoderClazz.newInstance(); decoder.init(config); decoders.add(decoder); } else if (TextStream.class.isAssignableFrom( decoderClazz)) { TextStream decoder = (TextStream) decoderClazz.newInstance(); decoder.init(config); decoders.add(decoder); } else { // Binary decoder - ignore it } } } } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InstantiationException e) { throw new IllegalArgumentException(e); } } @Override protected Object decode(String message) throws DecodeException { // Handle primitives if (primitiveType != null) { return Util.coerceToType(primitiveType, message); } // Handle full decoders for (Decoder decoder : decoders) { if (decoder instanceof Text) { if (((Text) decoder).willDecode(message)) { return ((Text) decoder).decode(message); } } else { StringReader r = new StringReader(message); try { return ((TextStream) decoder).decode(r); } catch (IOException ioe) { throw new DecodeException(message, sm.getString( "pojoMessageHandlerWhole.decodeIoFail"), ioe); } } } return null; } @Override protected Object convert(String message) { return new StringReader(message); } @Override protected void onClose() { for (Decoder decoder : decoders) { decoder.destroy(); } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerPartialText.java0000644000175100017510000000265112162573554031075 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.lang.reflect.Method; import javax.websocket.Session; /** * Text specific concrete implementation for handling partial messages. */ public class PojoMessageHandlerPartialText extends PojoMessageHandlerPartialBase{ public PojoMessageHandlerPartialText(Object pojo, Method method, Session session, Object[] params, int indexPayload, boolean convert, int indexBoolean, int indexSession, long maxMessageSize) { super(pojo, method, session, params, indexPayload, convert, indexBoolean, indexSession, maxMessageSize); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerWholePong.java0000644000175100017510000000311512162573554030532 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.lang.reflect.Method; import javax.websocket.PongMessage; import javax.websocket.Session; /** * PongMessage specific concrete implementation for handling whole messages. */ public class PojoMessageHandlerWholePong extends PojoMessageHandlerWholeBase { public PojoMessageHandlerWholePong(Object pojo, Method method, Session session, Object[] params, int indexPayload, boolean convert, int indexSession) { super(pojo, method, session, params, indexPayload, convert, indexSession, -1); } @Override protected Object decode(PongMessage message) { // Never decoded return null; } @Override protected void onClose() { // NO-OP } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/Constants.java0000644000175100017510000000210212116210013025115 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; /** * Internal implementation constants. */ public class Constants { protected static final String PACKAGE_NAME = Constants.class.getPackage().getName(); private Constants() { // Hide default constructor } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties0000644000175100017510000000733612254067714027063 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. pojoEndpointBase.closeSessionFail=Failed to close WebSocket session during error handling pojoEndpointBase.onCloseFail=Failed to call onClose method of POJO end point for POJO of type [{0}] pojoEndpointBase.onError=No error handling configured for [{0}] and the following error occurred pojoEndpointBase.onErrorFail=Failed to call onError method of POJO end point for POJO of type [{0}] pojoEndpointBase.onOpenFail=Failed to call onOpen method of POJO end point for POJO of type [{0}] pojoEndpointServer.getPojoInstanceFail=Failed to create instance of POJO of type [{0}] pojoMethodMapping.decodePathParamFail=Failed to decode path parameter value [{0}] to expected type [{1}] pojoMethodMapping.duplicateAnnotation=Duplicate annotations [{0}] present on class [{1}] pojoMethodMapping.duplicateLastParam=Multiple boolean (last) parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.duplicateMessageParam=Multiple message parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.duplicatePongMessageParam=Multiple PongMessage parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.duplicateSessionParam=Multiple session parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.invalidDecoder=The specified decoder of type [{0}] could not be instantiated pojoMethodMapping.invalidPathParamType=Parameters annotated with @PathParam may only be Strings, Java primitives or a boxed version thereof pojoMethodMapping.methodNotPublic=The annotated method [{0}] is not public pojoMethodMapping.noPayload=No payload parameter present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.onErrorNoThrowable=No Throwable parameter was present on the method [{0}] of class [{1}] that was annotated with OnError pojoMethodMapping.paramWithoutAnnotation=A parameter of type [{0}] was found on method[{1}] of class [{2}] that did not have a @PathParam annotation pojoMethodMapping.partialInputStream=Invalid InputStream and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.partialObject=Invalid Object and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.partialPong=Invalid PongMesssge and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.partialReader=Invalid Reader and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMethodMapping.pongWithPayload=Invalid PongMessgae and Message parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage pojoMessageHandlerWhole.decodeIoFail=IO error while decoding message pojoMessageHandlerWhole.maxBufferSize=The maximum supported message size for this implementation is Integer.MAX_VALUE tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/package-info.java0000644000175100017510000000172712076056456025531 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** * This package provides the necessary plumbing to convert an annotated POJO * into a WebSocket {@link javax.websocket.Endpoint}. */ package org.apache.tomcat.websocket.pojo;tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoMessageHandlerBase.java0000644000175100017510000000660512203443675027505 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.io.IOException; import java.lang.reflect.Method; import java.nio.ByteBuffer; import javax.websocket.EncodeException; import javax.websocket.MessageHandler; import javax.websocket.RemoteEndpoint; import javax.websocket.Session; import org.apache.tomcat.websocket.WrappedMessageHandler; /** * Common implementation code for the POJO message handlers. * * @param The type of message to handle */ public abstract class PojoMessageHandlerBase implements WrappedMessageHandler { protected final Object pojo; protected final Method method; protected final Session session; protected final Object[] params; protected final int indexPayload; protected final boolean convert; protected final int indexSession; protected final long maxMessageSize; public PojoMessageHandlerBase(Object pojo, Method method, Session session, Object[] params, int indexPayload, boolean convert, int indexSession, long maxMessageSize) { this.pojo = pojo; this.method = method; this.session = session; this.params = params; this.indexPayload = indexPayload; this.convert = convert; this.indexSession = indexSession; this.maxMessageSize = maxMessageSize; } protected final void processResult(Object result) { if (result == null) { return; } RemoteEndpoint.Basic remoteEndpoint = session.getBasicRemote(); try { if (result instanceof String) { remoteEndpoint.sendText((String) result); } else if (result instanceof ByteBuffer) { remoteEndpoint.sendBinary((ByteBuffer) result); } else if (result instanceof byte[]) { remoteEndpoint.sendBinary(ByteBuffer.wrap((byte[]) result)); } else { remoteEndpoint.sendObject(result); } } catch (IOException ioe) { throw new IllegalStateException(ioe); } catch (EncodeException ee) { throw new IllegalStateException(ee); } } /** * Expose the POJO if it is a message handler so the Session is able to * match requests to remove handlers if the original handler has been * wrapped. */ @Override public final MessageHandler getWrappedHandler() { if (pojo instanceof MessageHandler) { return (MessageHandler) pojo; } else { return null; } } @Override public final long getMaxMessageSize() { return maxMessageSize; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/pojo/PojoEndpointServer.java0000644000175100017510000000524212200757157026773 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket.pojo; import java.util.Map; import javax.websocket.EndpointConfig; import javax.websocket.Session; import javax.websocket.server.ServerEndpointConfig; import org.apache.tomcat.util.res.StringManager; /** * Wrapper class for instances of POJOs annotated with * {@link javax.websocket.server.ServerEndpoint} so they appear as standard * {@link javax.websocket.Endpoint} instances. */ public class PojoEndpointServer extends PojoEndpointBase { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); public static final String POJO_PATH_PARAM_KEY = "org.apache.tomcat.websocket.pojo.PojoEndpoint.pathParams"; public static final String POJO_METHOD_MAPPING_KEY = "org.apache.tomcat.websocket.pojo.PojoEndpoint.methodMapping"; @Override public void onOpen(Session session, EndpointConfig endpointConfig) { ServerEndpointConfig sec = (ServerEndpointConfig) endpointConfig; Object pojo; try { pojo = sec.getConfigurator().getEndpointInstance( sec.getEndpointClass()); } catch (InstantiationException e) { throw new IllegalArgumentException(sm.getString( "pojoEndpointServer.getPojoInstanceFail", sec.getEndpointClass().getName()), e); } setPojo(pojo); @SuppressWarnings("unchecked") Map pathParameters = (Map) sec.getUserProperties().get( POJO_PATH_PARAM_KEY); setPathParameters(pathParameters); PojoMethodMapping methodMapping = (PojoMethodMapping) sec.getUserProperties().get( POJO_METHOD_MAPPING_KEY); setMethodMapping(methodMapping); doOnOpen(session, endpointConfig); } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/AsyncChannelWrapperNonSecure.java0000644000175100017510000000652712203452534027757 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * Generally, just passes calls straight to the wrapped * {@link AsynchronousSocketChannel}. In some cases exceptions may be swallowed * to save them being swallowed by the calling code. */ public class AsyncChannelWrapperNonSecure implements AsyncChannelWrapper { private static final Future NOOP_FUTURE = new NoOpFuture(); private final AsynchronousSocketChannel socketChannel; public AsyncChannelWrapperNonSecure( AsynchronousSocketChannel socketChannel) { this.socketChannel = socketChannel; } @Override public Future read(ByteBuffer dst) { return socketChannel.read(dst); } @Override public void read(ByteBuffer dst, A attachment, CompletionHandler handler) { socketChannel.read(dst, attachment, handler); } @Override public Future write(ByteBuffer src) { return socketChannel.write(src); } @Override public void write(ByteBuffer[] srcs, int offset, int length, long timeout, TimeUnit unit, A attachment, CompletionHandler handler) { socketChannel.write( srcs, offset, length, timeout, unit, attachment, handler); } @Override public void close() { try { socketChannel.close(); } catch (IOException e) { // Ignore } } @Override public Future handshake() { return NOOP_FUTURE; } private static final class NoOpFuture implements Future { @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return true; } @Override public Void get() throws InterruptedException, ExecutionException { return null; } @Override public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return null; } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/DecoderEntry.java0000644000175100017510000000244612162561635024620 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import javax.websocket.Decoder; public class DecoderEntry { private final Class clazz; private final Class decoderClazz; public DecoderEntry(Class clazz, Class decoderClazz) { this.clazz = clazz; this.decoderClazz = decoderClazz; } public Class getClazz() { return clazz; } public Class getDecoderClazz() { return decoderClazz; } }tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsFrameClient.java0000644000175100017510000001020412223271602024711 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; public class WsFrameClient extends WsFrameBase { private final AsyncChannelWrapper channel; private final CompletionHandler handler; // Not final as it may need to be re-sized private ByteBuffer response; public WsFrameClient(ByteBuffer response, AsyncChannelWrapper channel, WsSession wsSession) { super(wsSession); this.response = response; this.channel = channel; this.handler = new WsFrameClientCompletionHandler(); try { processSocketRead(); } catch (IOException e) { close(e); } } private void processSocketRead() throws IOException { while (response.hasRemaining()) { int remaining = response.remaining(); int toCopy = Math.min(remaining, inputBuffer.length - writePos); // Copy remaining bytes read in HTTP phase to input buffer used by // frame processing response.get(inputBuffer, writePos, toCopy); writePos += toCopy; // Process the data we have processInputBuffer(); } response.clear(); // Get some more data if (isOpen()) { channel.read(response, null, handler); } } private final void close(Throwable t) { CloseReason cr; if (t instanceof WsIOException) { cr = ((WsIOException) t).getCloseReason(); } else { cr = new CloseReason( CloseCodes.CLOSED_ABNORMALLY, t.getMessage()); } try { wsSession.close(cr); } catch (IOException ignore) { // Ignore } } @Override protected boolean isMasked() { // Data is from the server so it is not masked return false; } private class WsFrameClientCompletionHandler implements CompletionHandler { @Override public void completed(Integer result, Void attachment) { response.flip(); try { processSocketRead(); } catch (IOException e) { // Only send a close message on an IOException if the client // has not yet received a close control message from the server // as the IOException may be in response to the client // continuing to send a message after the server sent a close // control message. if (isOpen()) { close(e); } } } @Override public void failed(Throwable exc, Void attachment) { if (exc instanceof ReadBufferOverflowException) { // response will be empty if this exception is thrown response = ByteBuffer.allocate( ((ReadBufferOverflowException) exc).getMinBufferSize()); response.flip(); try { processSocketRead(); } catch (IOException e) { close(e); } } else { close(exc); } } } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsHandshakeResponse.java0000644000175100017510000000263012122060573026132 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.websocket.HandshakeResponse; /** * Represents the response to a WebSocket handshake. */ public class WsHandshakeResponse implements HandshakeResponse { private final Map> headers; public WsHandshakeResponse() { this(new HashMap>()); } public WsHandshakeResponse(Map> headers) { this.headers = headers; } @Override public Map> getHeaders() { return headers; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/MessageHandlerResult.java0000644000175100017510000000246012166436036026306 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import javax.websocket.MessageHandler; public class MessageHandlerResult { private final MessageHandler handler; private final MessageHandlerResultType type; public MessageHandlerResult(MessageHandler handler, MessageHandlerResultType type) { this.handler = handler; this.type = type; } public MessageHandler getHandler() { return handler; } public MessageHandlerResultType getType() { return type; } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/WsSession.java0000644000175100017510000005014212267550170024160 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; import java.io.IOException; import java.net.URI; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.Principal; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCode; import javax.websocket.CloseReason.CloseCodes; import javax.websocket.DeploymentException; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.Extension; import javax.websocket.MessageHandler; import javax.websocket.PongMessage; import javax.websocket.RemoteEndpoint; import javax.websocket.SendResult; import javax.websocket.Session; import javax.websocket.WebSocketContainer; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; public class WsSession implements Session { // An ellipsis is a single character that looks like three periods in a row // and is used to indicate a continuation. private static final byte[] ELLIPSIS_BYTES = "\u2026".getBytes(StandardCharsets.UTF_8); // An ellipsis is three bytes in UTF-8 private static final int ELLIPSIS_BYTES_LEN = ELLIPSIS_BYTES.length; private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private static AtomicLong ids = new AtomicLong(0); private final Log log = LogFactory.getLog(WsSession.class); private final Endpoint localEndpoint; private final WsRemoteEndpointImplBase wsRemoteEndpoint; private final RemoteEndpoint.Async remoteEndpointAsync; private final RemoteEndpoint.Basic remoteEndpointBasic; private final ClassLoader applicationClassLoader; private final WsWebSocketContainer webSocketContainer; private final URI requestUri; private final Map> requestParameterMap; private final String queryString; private final Principal userPrincipal; private final EndpointConfig endpointConfig; private final String subProtocol; private final Map pathParameters; private final boolean secure; private final String httpSessionId; private final String id; // Expected to handle message types of only private MessageHandler textMessageHandler = null; // Expected to handle message types of only private MessageHandler binaryMessageHandler = null; private MessageHandler.Whole pongMessageHandler = null; private volatile State state = State.OPEN; private final Object stateLock = new Object(); private final Map userProperties = new ConcurrentHashMap(); private volatile int maxBinaryMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; private volatile int maxTextMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE; private volatile long maxIdleTimeout = 0; private volatile long lastActive = System.currentTimeMillis(); private Map futures = new ConcurrentHashMap(); /** * Creates a new WebSocket session for communication between the two * provided end points. The result of {@link Thread#getContextClassLoader()} * at the time this constructor is called will be used when calling * {@link Endpoint#onClose(Session, CloseReason)}. * * @param localEndpoint * @param wsRemoteEndpoint * @throws DeploymentException */ public WsSession(Endpoint localEndpoint, WsRemoteEndpointImplBase wsRemoteEndpoint, WsWebSocketContainer wsWebSocketContainer, URI requestUri, Map> requestParameterMap, String queryString, Principal userPrincipal, String httpSessionId, String subProtocol, Map pathParameters, boolean secure, EndpointConfig endpointConfig) throws DeploymentException { this.localEndpoint = localEndpoint; this.wsRemoteEndpoint = wsRemoteEndpoint; this.wsRemoteEndpoint.setSession(this); this.remoteEndpointAsync = new WsRemoteEndpointAsync(wsRemoteEndpoint); this.remoteEndpointBasic = new WsRemoteEndpointBasic(wsRemoteEndpoint); this.webSocketContainer = wsWebSocketContainer; applicationClassLoader = Thread.currentThread().getContextClassLoader(); wsRemoteEndpoint.setSendTimeout( wsWebSocketContainer.getDefaultAsyncSendTimeout()); this.maxBinaryMessageBufferSize = webSocketContainer.getDefaultMaxBinaryMessageBufferSize(); this.maxTextMessageBufferSize = webSocketContainer.getDefaultMaxTextMessageBufferSize(); this.maxIdleTimeout = webSocketContainer.getDefaultMaxSessionIdleTimeout(); this.requestUri = requestUri; if (requestParameterMap == null) { this.requestParameterMap = Collections.emptyMap(); } else { this.requestParameterMap = requestParameterMap; } this.queryString = queryString; this.userPrincipal = userPrincipal; this.httpSessionId = httpSessionId; if (subProtocol == null) { this.subProtocol = ""; } else { this.subProtocol = subProtocol; } this.pathParameters = pathParameters; this.secure = secure; this.wsRemoteEndpoint.setEncoders(endpointConfig); this.endpointConfig = endpointConfig; this.userProperties.putAll(endpointConfig.getUserProperties()); this.id = Long.toHexString(ids.getAndIncrement()); } @Override public WebSocketContainer getContainer() { checkState(); return webSocketContainer; } @SuppressWarnings("unchecked") @Override public void addMessageHandler(MessageHandler listener) { checkState(); // Message handlers that require decoders may map to text messages, // binary messages, both or neither. // The frame processing code expects binary message handlers to // accept ByteBuffer // Use the POJO message handler wrappers as they are designed to wrap // arbitrary objects with MessageHandlers and can wrap MessageHandlers // just as easily. Set mhResults = Util.getMessageHandlers(listener, endpointConfig, this); for (MessageHandlerResult mhResult : mhResults) { switch (mhResult.getType()) { case TEXT: { if (textMessageHandler != null) { throw new IllegalStateException( sm.getString("wsSession.duplicateHandlerText")); } textMessageHandler = mhResult.getHandler(); break; } case BINARY: { if (binaryMessageHandler != null) { throw new IllegalStateException( sm.getString("wsSession.duplicateHandlerBinary")); } binaryMessageHandler = mhResult.getHandler(); break; } case PONG: { if (pongMessageHandler != null) { throw new IllegalStateException( sm.getString("wsSession.duplicateHandlerPong")); } MessageHandler handler = mhResult.getHandler(); if (handler instanceof MessageHandler.Whole) { pongMessageHandler = (MessageHandler.Whole) handler; } else { throw new IllegalStateException( sm.getString("wsSession.invalidHandlerTypePong")); } break; } default: { throw new IllegalArgumentException(sm.getString( "wsSession.unknownHandlerType", listener, mhResult.getType())); } } } } @Override public Set getMessageHandlers() { checkState(); Set result = new HashSet(); if (binaryMessageHandler != null) { result.add(binaryMessageHandler); } if (textMessageHandler != null) { result.add(textMessageHandler); } if (pongMessageHandler != null) { result.add(pongMessageHandler); } return result; } @Override public void removeMessageHandler(MessageHandler listener) { checkState(); if (listener == null) { return; } MessageHandler wrapped = null; if (listener instanceof WrappedMessageHandler) { wrapped = ((WrappedMessageHandler) listener).getWrappedHandler(); } if (wrapped == null) { wrapped = listener; } boolean removed = false; if (wrapped.equals(textMessageHandler) || listener.equals(textMessageHandler)) { textMessageHandler = null; removed = true; } if (listener.equals(binaryMessageHandler) || listener.equals(binaryMessageHandler)) { binaryMessageHandler = null; removed = true; } if (listener.equals(pongMessageHandler) || listener.equals(pongMessageHandler)) { pongMessageHandler = null; removed = true; } if (!removed) { // ISE for now. Could swallow this silently / log this if the ISE // becomes a problem throw new IllegalStateException( sm.getString("wsSession.removeHandlerFailed", listener)); } } @Override public String getProtocolVersion() { checkState(); return Constants.WS_VERSION_HEADER_VALUE; } @Override public String getNegotiatedSubprotocol() { checkState(); return subProtocol; } @Override public List getNegotiatedExtensions() { checkState(); return Collections.emptyList(); } @Override public boolean isSecure() { checkState(); return secure; } @Override public boolean isOpen() { return state == State.OPEN; } @Override public long getMaxIdleTimeout() { checkState(); return maxIdleTimeout; } @Override public void setMaxIdleTimeout(long timeout) { checkState(); this.maxIdleTimeout = timeout; } @Override public void setMaxBinaryMessageBufferSize(int max) { checkState(); this.maxBinaryMessageBufferSize = max; } @Override public int getMaxBinaryMessageBufferSize() { checkState(); return maxBinaryMessageBufferSize; } @Override public void setMaxTextMessageBufferSize(int max) { checkState(); this.maxTextMessageBufferSize = max; } @Override public int getMaxTextMessageBufferSize() { checkState(); return maxTextMessageBufferSize; } @Override public Set getOpenSessions() { checkState(); return webSocketContainer.getOpenSessions(localEndpoint.getClass()); } @Override public RemoteEndpoint.Async getAsyncRemote() { checkState(); return remoteEndpointAsync; } @Override public RemoteEndpoint.Basic getBasicRemote() { checkState(); return remoteEndpointBasic; } @Override public void close() throws IOException { close(new CloseReason(CloseCodes.NORMAL_CLOSURE, "")); } @Override public void close(CloseReason closeReason) throws IOException { doClose(closeReason, closeReason); } /** * WebSocket 1.0. Section 2.1.5. * Need internal close method as spec requires that the local endpoint * receives a 1006 on timeout. */ private void doClose(CloseReason closeReasonMessage, CloseReason closeReasonLocal) { // Double-checked locking. OK because state is volatile if (state != State.OPEN) { return; } synchronized (stateLock) { if (state != State.OPEN) { return; } state = State.CLOSING; sendCloseMessage(closeReasonMessage); fireEndpointOnClose(closeReasonLocal); state = State.CLOSED; } IOException ioe = new IOException(sm.getString("wsSession.messageFailed")); SendResult sr = new SendResult(ioe); for (FutureToSendHandler f2sh : futures.keySet()) { f2sh.onResult(sr); } } /** * Called when a close message is received. Should only ever happen once. * Also called after a protocol error when the ProtocolHandler needs to * force the closing of the connection. */ public void onClose(CloseReason closeReason) { synchronized (stateLock) { if (state == State.OPEN) { sendCloseMessage(closeReason); fireEndpointOnClose(closeReason); state = State.CLOSED; } // Close the socket wsRemoteEndpoint.close(); } } private void fireEndpointOnClose(CloseReason closeReason) { // Fire the onClose event Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { localEndpoint.onClose(this, closeReason); } finally { t.setContextClassLoader(cl); } } private void sendCloseMessage(CloseReason closeReason) { // 125 is maximum size for the payload of a control message ByteBuffer msg = ByteBuffer.allocate(125); CloseCode closeCode = closeReason.getCloseCode(); // CLOSED_ABNORMALLY should not be put on the wire if (closeCode == CloseCodes.CLOSED_ABNORMALLY) { // PROTOCOL_ERROR is probably better than GOING_AWAY here msg.putShort((short) CloseCodes.PROTOCOL_ERROR.getCode()); } else { msg.putShort((short) closeCode.getCode()); } String reason = closeReason.getReasonPhrase(); if (reason != null && reason.length() > 0) { appendCloseReasonWithTruncation(msg, reason); } msg.flip(); try { wsRemoteEndpoint.startMessageBlock( Constants.OPCODE_CLOSE, msg, true); } catch (IOException ioe) { // Failed to send close message. Close the socket and let the caller // deal with the Exception if (log.isDebugEnabled()) { log.debug(sm.getString("wsSession.sendCloseFail"), ioe); } wsRemoteEndpoint.close(); // Failure to send a close message is not unexpected in the case of // an abnormal closure (usually triggered by a failure to read/write // from/to the client. In this case do not trigger the endpoint's // error handling if (closeCode != CloseCodes.CLOSED_ABNORMALLY) { localEndpoint.onError(this, ioe); } } finally { webSocketContainer.unregisterSession(localEndpoint, this); } } /** * Use protected so unit tests can access this method directly. */ protected static void appendCloseReasonWithTruncation(ByteBuffer msg, String reason) { // Once the close code has been added there are a maximum of 123 bytes // left for the reason phrase. If it is truncated then care needs to be // taken to ensure the bytes are not truncated in the middle of a // multi-byte UTF-8 character. byte[] reasonBytes = reason.getBytes(StandardCharsets.UTF_8); if (reasonBytes.length <= 123) { // No need to truncate msg.put(reasonBytes); } else { // Need to truncate int remaining = 123 - ELLIPSIS_BYTES_LEN; int pos = 0; byte[] bytesNext = reason.substring(pos, pos + 1).getBytes( StandardCharsets.UTF_8); while (remaining >= bytesNext.length) { msg.put(bytesNext); remaining -= bytesNext.length; pos++; bytesNext = reason.substring(pos, pos + 1).getBytes( StandardCharsets.UTF_8); } msg.put(ELLIPSIS_BYTES); } } /** * Make the session aware of a {@link FutureToSendHandler} that will need to * be forcibly closed if the session closes before the * {@link FutureToSendHandler} completes. */ protected void registerFuture(FutureToSendHandler f2sh) { futures.put(f2sh, f2sh); } /** * Remove a {@link FutureToSendHandler} from the set of tracked instances. */ protected void unregisterFuture(FutureToSendHandler f2sh) { futures.remove(f2sh); } @Override public URI getRequestURI() { checkState(); return requestUri; } @Override public Map> getRequestParameterMap() { checkState(); return requestParameterMap; } @Override public String getQueryString() { checkState(); return queryString; } @Override public Principal getUserPrincipal() { checkState(); return userPrincipal; } @Override public Map getPathParameters() { checkState(); return pathParameters; } @Override public String getId() { return id; } @Override public Map getUserProperties() { checkState(); return userProperties; } public Endpoint getLocal() { return localEndpoint; } public String getHttpSessionId() { return httpSessionId; } protected MessageHandler getTextMessageHandler() { return textMessageHandler; } protected MessageHandler getBinaryMessageHandler() { return binaryMessageHandler; } protected MessageHandler.Whole getPongMessageHandler() { return pongMessageHandler; } protected void updateLastActive() { lastActive = System.currentTimeMillis(); } protected void checkExpiration() { long timeout = maxIdleTimeout; if (timeout < 1) { return; } if (System.currentTimeMillis() - lastActive > timeout) { String msg = sm.getString("wsSession.timeout"); doClose(new CloseReason(CloseCodes.GOING_AWAY, msg), new CloseReason(CloseCodes.CLOSED_ABNORMALLY, msg)); } } private void checkState() { if (state == State.CLOSED) { throw new IllegalStateException(sm.getString("wsSession.closed")); } } private static enum State { OPEN, CLOSING, CLOSED } } tomcat7-7.0.52/java/org/apache/tomcat/websocket/BackgroundProcess.java0000644000175100017510000000173712107174710025642 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.websocket; public interface BackgroundProcess { void backgroundProcess(); void setProcessPeriod(int period); int getProcessPeriod(); } tomcat7-7.0.52/java/org/apache/tomcat/PeriodicEventListener.java0000644000175100017510000000172412271453632024505 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat; public interface PeriodicEventListener { /** * Execute a periodic task, such as reloading, etc. */ public void periodicEvent(); } tomcat7-7.0.52/java/org/apache/tomcat/util/0000755000175100017510000000000012301126367020341 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/file/0000755000175100017510000000000012301126367021260 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/file/package.html0000644000175100017510000000171312271452077023551 0ustar locutuslocutus

    This package contains utility classes for file handling.

    tomcat7-7.0.52/java/org/apache/tomcat/util/file/Constants.java0000644000175100017510000000174712271452077024116 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.file; /** * String constants for the file package. */ public final class Constants { public static final String Package = "org.apache.tomcat.util.file"; } tomcat7-7.0.52/java/org/apache/tomcat/util/file/LocalStrings.properties0000644000175100017510000000146512271452077026016 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. matcher.tokenize=Tokenizing path [{0}] tomcat7-7.0.52/java/org/apache/tomcat/util/file/Matcher.java0000644000175100017510000004704212271452077023523 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.file; import java.io.File; import java.util.Locale; import java.util.Set; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** *

    This is a utility class to match file globs. * The class has been derived from * org.apache.tools.ant.types.selectors.SelectorUtils. *

    *

    All methods are static.

    */ public final class Matcher { /** * The pattern that matches an arbitrary number of directories. */ public static final String DEEP_TREE_MATCH = "**"; private static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); private static final String PATH_SEP = System.getProperty("path.separator"); private static final boolean ON_NETWARE = isNetware(); private static final boolean ON_DOS = isDos(); /** * The string resources for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); private static final Log log = LogFactory.getLog(Matcher.class); /** * Tests whether or not a given path matches any pattern in the given set. * * If you need to call this method multiple times with the same * pattern you should rather pre parse the pattern using tokenizePathAsArray. * * @see #tokenizePathAsArray * * @param patternSet The pattern set to match against. Must not be * null. * @param str The path to match, as a String. Must not be * null. * * @return true if any pattern in the set matches against the string, * or false otherwise. */ public static boolean matchPath(Set patternSet, String str) { for (String[] patternTokens: patternSet) { if (matchPath(patternTokens, tokenizePathAsArray(str), true)) { return true; } } return false; } /** * Tests whether or not a given path matches a given pattern. * * If you need to call this method multiple times with the same * pattern you should rather pre parse the pattern using tokenizePathAsArray. * * @see #tokenizePathAsArray * * @param pattern The pattern to match against. Must not be * null. * @param str The path to match, as a String. Must not be * null. * * @return true if the pattern matches against the string, * or false otherwise. */ public static boolean matchPath(String pattern, String str) { String[] patDirs = tokenizePathAsArray(pattern); return matchPath(patDirs, tokenizePathAsArray(str), true); } /** * Tests whether or not a given path matches a given pattern. * * If you need to call this method multiple times with the same * pattern you should rather pre parse the pattern using tokenizePathAsArray. * * @see #tokenizePathAsArray * * @param pattern The pattern to match against. Must not be * null. * @param str The path to match, as a String. Must not be * null. * @param isCaseSensitive Whether or not matching should be performed * case sensitively. * * @return true if the pattern matches against the string, * or false otherwise. */ public static boolean matchPath(String pattern, String str, boolean isCaseSensitive) { String[] patDirs = tokenizePathAsArray(pattern); return matchPath(patDirs, tokenizePathAsArray(str), isCaseSensitive); } /** * Core implementation of matchPath using an already tokenized pattern. */ public static boolean matchPath(String[] tokenizedPattern, String[] strDirs, boolean isCaseSensitive) { int patIdxStart = 0; int patIdxEnd = tokenizedPattern.length - 1; int strIdxStart = 0; int strIdxEnd = strDirs.length - 1; // up to first '**' while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = tokenizedPattern[patIdxStart]; if (patDir.equals(DEEP_TREE_MATCH)) { break; } if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) { return false; } patIdxStart++; strIdxStart++; } if (strIdxStart > strIdxEnd) { // String is exhausted for (int i = patIdxStart; i <= patIdxEnd; i++) { if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { return false; } } return true; } else { if (patIdxStart > patIdxEnd) { // String not exhausted, but pattern is. Failure. return false; } } // up to last '**' while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = tokenizedPattern[patIdxEnd]; if (patDir.equals(DEEP_TREE_MATCH)) { break; } if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) { return false; } patIdxEnd--; strIdxEnd--; } if (strIdxStart > strIdxEnd) { // String is exhausted for (int i = patIdxStart; i <= patIdxEnd; i++) { if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { return false; } } return true; } while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { if (tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { patIdxTmp = i; break; } } if (patIdxTmp == patIdxStart + 1) { // '**/**' situation, so skip one patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd int patLength = (patIdxTmp - patIdxStart - 1); int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: for (int i = 0; i <= strLength - patLength; i++) { for (int j = 0; j < patLength; j++) { String subPat = tokenizedPattern[patIdxStart + j + 1]; String subStr = strDirs[strIdxStart + i + j]; if (!match(subPat, subStr, isCaseSensitive)) { continue strLoop; } } foundIdx = strIdxStart + i; break; } if (foundIdx == -1) { return false; } patIdxStart = patIdxTmp; strIdxStart = foundIdx + patLength; } for (int i = patIdxStart; i <= patIdxEnd; i++) { if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { return false; } } return true; } /** * Tests whether or not a string matches against a pattern. * The pattern may contain two special characters:
    * '*' means zero or more characters
    * '?' means one and only one character * * @param pattern The pattern to match against. * Must not be null. * @param str The string which must be matched against the pattern. * Must not be null. * * @return true if the string matches against the pattern, * or false otherwise. */ public static boolean match(String pattern, String str) { return match(pattern, str, true); } /** * Tests whether or not a string matches against a pattern. * The pattern may contain two special characters:
    * '*' means zero or more characters
    * '?' means one and only one character * * @param pattern The pattern to match against. * Must not be null. * @param str The string which must be matched against the pattern. * Must not be null. * @param caseSensitive Whether or not matching should be performed * case sensitively. * * * @return true if the string matches against the pattern, * or false otherwise. */ public static boolean match(String pattern, String str, boolean caseSensitive) { char[] patArr = pattern.toCharArray(); char[] strArr = str.toCharArray(); int patIdxStart = 0; int patIdxEnd = patArr.length - 1; int strIdxStart = 0; int strIdxEnd = strArr.length - 1; char ch; boolean containsStar = false; for (int i = 0; i < patArr.length; i++) { if (patArr[i] == '*') { containsStar = true; break; } } if (!containsStar) { // No '*'s, so we make a shortcut if (patIdxEnd != strIdxEnd) { return false; // Pattern and string do not have the same size } for (int i = 0; i <= patIdxEnd; i++) { ch = patArr[i]; if (ch != '?') { if (different(caseSensitive, ch, strArr[i])) { return false; // Character mismatch } } } return true; // String matches against pattern } if (patIdxEnd == 0) { return true; // Pattern contains only '*', which matches anything } // Process characters before first star while (true) { ch = patArr[patIdxStart]; if (ch == '*' || strIdxStart > strIdxEnd) { break; } if (ch != '?') { if (different(caseSensitive, ch, strArr[strIdxStart])) { return false; // Character mismatch } } patIdxStart++; strIdxStart++; } if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. return allStars(patArr, patIdxStart, patIdxEnd); } // Process characters after last star while (true) { ch = patArr[patIdxEnd]; if (ch == '*' || strIdxStart > strIdxEnd) { break; } if (ch != '?') { if (different(caseSensitive, ch, strArr[strIdxEnd])) { return false; // Character mismatch } } patIdxEnd--; strIdxEnd--; } if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. return allStars(patArr, patIdxStart, patIdxEnd); } // process pattern between stars. padIdxStart and patIdxEnd point // always to a '*'. while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { if (patArr[i] == '*') { patIdxTmp = i; break; } } if (patIdxTmp == patIdxStart + 1) { // Two stars next to each other, skip the first one. patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd int patLength = (patIdxTmp - patIdxStart - 1); int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: for (int i = 0; i <= strLength - patLength; i++) { for (int j = 0; j < patLength; j++) { ch = patArr[patIdxStart + j + 1]; if (ch != '?') { if (different(caseSensitive, ch, strArr[strIdxStart + i + j])) { continue strLoop; } } } foundIdx = strIdxStart + i; break; } if (foundIdx == -1) { return false; } patIdxStart = patIdxTmp; strIdxStart = foundIdx + patLength; } // All characters in the string are used. Check if only '*'s are left // in the pattern. If so, we succeeded. Otherwise failure. return allStars(patArr, patIdxStart, patIdxEnd); } private static boolean allStars(char[] chars, int start, int end) { for (int i = start; i <= end; ++i) { if (chars[i] != '*') { return false; } } return true; } private static boolean different( boolean caseSensitive, char ch, char other) { return caseSensitive ? ch != other : Character.toUpperCase(ch) != Character.toUpperCase(other); } /** * Breaks a path up into a array of path elements, tokenizing on * File.separator. * * @param path Path to tokenize. Must not be null. * * @return a String array of path elements from the tokenized path */ public static String[] tokenizePathAsArray(String path) { if (log.isTraceEnabled()) { log.trace(sm.getString("matcher.tokenize", path)); } String root = null; if (isAbsolutePath(path)) { String[] s = dissect(path); root = s[0]; path = s[1]; } char sep = File.separatorChar; int start = 0; int len = path.length(); int count = 0; for (int pos = 0; pos < len; pos++) { if (path.charAt(pos) == sep) { if (pos != start) { count++; } start = pos + 1; } } if (len != start) { count++; } String[] l = new String[count + ((root == null) ? 0 : 1)]; if (root != null) { l[0] = root; count = 1; } else { count = 0; } start = 0; for (int pos = 0; pos < len; pos++) { if (path.charAt(pos) == sep) { if (pos != start) { String tok = path.substring(start, pos); l[count++] = tok; } start = pos + 1; } } if (len != start) { String tok = path.substring(start); l[count/*++*/] = tok; } return l; } /** * Dissect the specified absolute path. * @param path the path to dissect (must be absolute). * @return String[] {root, remaining path}. * @throws java.lang.NullPointerException if path is null. */ private static String[] dissect(String path) { char sep = File.separatorChar; path = path.replace('/', sep).replace('\\', sep); String root = null; int colon = path.indexOf(':'); if (colon > 0 && (ON_DOS || ON_NETWARE)) { int next = colon + 1; root = path.substring(0, next); char[] ca = path.toCharArray(); root += sep; //remove the initial separator; the root has it. next = (ca[next] == sep) ? next + 1 : next; StringBuilder sbPath = new StringBuilder(); // Eliminate consecutive slashes after the drive spec: for (int i = next; i < ca.length; i++) { if (ca[i] != sep || ca[i - 1] != sep) { sbPath.append(ca[i]); } } path = sbPath.toString(); } else if (path.length() > 1 && path.charAt(1) == sep) { // UNC drive int nextsep = path.indexOf(sep, 2); nextsep = path.indexOf(sep, nextsep + 1); root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path; path = path.substring(root.length()); } else { root = File.separator; path = path.substring(1); } return new String[] {root, path}; } /** * Verifies that the specified filename represents an absolute path. * Differs from new java.io.File("filename").isAbsolute() in that a path * beginning with a double file separator--signifying a Windows UNC--must * at minimum match "\\a\b" to be considered an absolute path. * @param filename the filename to be checked. * @return true if the filename represents an absolute path. * @throws java.lang.NullPointerException if filename is null. */ private static boolean isAbsolutePath(String filename) { int len = filename.length(); if (len == 0) { return false; } char sep = File.separatorChar; filename = filename.replace('/', sep).replace('\\', sep); char c = filename.charAt(0); if (!(ON_DOS || ON_NETWARE)) { return (c == sep); } if (c == sep) { // CheckStyle:MagicNumber OFF if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) { return false; } // CheckStyle:MagicNumber ON int nextsep = filename.indexOf(sep, 2); return nextsep > 2 && nextsep + 1 < len; } int colon = filename.indexOf(':'); return (Character.isLetter(c) && colon == 1 && filename.length() > 2 && filename.charAt(2) == sep) || (ON_NETWARE && colon > 0); } /** * Determines if our OS is Netware. * * @return true if we run on Netware */ private static boolean isNetware() { return OS_NAME.indexOf("netware") > -1; } /** * Determines if our OS is DOS. * * @return true if we run on DOS */ private static boolean isDos() { return PATH_SEP.equals(";") && !isNetware(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/res/0000755000175100017510000000000012301126366021131 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/res/StringManager.java0000644000175100017510000002165412271452644024554 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.res; import java.text.MessageFormat; import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; /** * An internationalization / localization helper class which reduces * the bother of handling ResourceBundles and takes care of the * common cases of message formating which otherwise require the * creation of Object arrays and such. * *

    The StringManager operates on a package basis. One StringManager * per package can be created and accessed via the getManager method * call. * *

    The StringManager will look for a ResourceBundle named by * the package name given plus the suffix of "LocalStrings". In * practice, this means that the localized information will be contained * in a LocalStrings.properties file located in the package * directory of the classpath. * *

    Please see the documentation for java.util.ResourceBundle for * more information. * * @author James Duncan Davidson [duncan@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Mel Martinez [mmartinez@g1440.com] * @see java.util.ResourceBundle */ public class StringManager { private static int LOCALE_CACHE_SIZE = 10; /** * The ResourceBundle for this StringManager. */ private final ResourceBundle bundle; private final Locale locale; /** * Creates a new StringManager for a given package. This is a * private method and all access to it is arbitrated by the * static getManager method call so that only one StringManager * per package will be created. * * @param packageName Name of package to create StringManager for. */ private StringManager(String packageName, Locale locale) { String bundleName = packageName + ".LocalStrings"; ResourceBundle bnd = null; try { bnd = ResourceBundle.getBundle(bundleName, locale); } catch( MissingResourceException ex ) { // Try from the current loader (that's the case for trusted apps) // Should only be required if using a TC5 style classloader structure // where common != shared != server ClassLoader cl = Thread.currentThread().getContextClassLoader(); if( cl != null ) { try { bnd = ResourceBundle.getBundle(bundleName, locale, cl); } catch(MissingResourceException ex2) { // Ignore } } } bundle = bnd; // Get the actual locale, which may be different from the requested one if (bundle != null) { Locale bundleLocale = bundle.getLocale(); if (bundleLocale.equals(Locale.ROOT)) { this.locale = Locale.ENGLISH; } else { this.locale = bundleLocale; } } else { this.locale = null; } } /** Get a string from the underlying resource bundle or return null if the String is not found. @param key to desired resource String @return resource String matching key from underlying bundle or null if not found. @throws IllegalArgumentException if key is null. */ public String getString(String key) { if(key == null){ String msg = "key may not have a null value"; throw new IllegalArgumentException(msg); } String str = null; try { // Avoid NPE if bundle is null and treat it like an MRE if (bundle != null) { str = bundle.getString(key); } } catch(MissingResourceException mre) { //bad: shouldn't mask an exception the following way: // str = "[cannot find message associated with key '" + key + // "' due to " + mre + "]"; // because it hides the fact that the String was missing // from the calling code. //good: could just throw the exception (or wrap it in another) // but that would probably cause much havoc on existing // code. //better: consistent with container pattern to // simply return null. Calling code can then do // a null check. str = null; } return str; } /** * Get a string from the underlying resource bundle and format * it with the given set of arguments. * * @param key * @param args */ public String getString(final String key, final Object... args) { String value = getString(key); if (value == null) { value = key; } MessageFormat mf = new MessageFormat(value); mf.setLocale(locale); return mf.format(args, new StringBuffer(), null).toString(); } /** * Identify the Locale this StringManager is associated with */ public Locale getLocale() { return locale; } // -------------------------------------------------------------- // STATIC SUPPORT METHODS // -------------------------------------------------------------- private static final Map> managers = new Hashtable>(); /** * Get the StringManager for a particular package. If a manager for * a package already exists, it will be reused, else a new * StringManager will be created and returned. * * @param packageName The package name */ public static final synchronized StringManager getManager( String packageName) { return getManager(packageName, Locale.getDefault()); } /** * Get the StringManager for a particular package and Locale. If a manager * for a package/Locale combination already exists, it will be reused, else * a new StringManager will be created and returned. * * @param packageName The package name * @param locale The Locale */ public static final synchronized StringManager getManager( String packageName, Locale locale) { Map map = managers.get(packageName); if (map == null) { /* * Don't want the HashMap to be expanded beyond LOCALE_CACHE_SIZE. * Expansion occurs when size() exceeds capacity. Therefore keep * size at or below capacity. * removeEldestEntry() executes after insertion therefore the test * for removal needs to use one less than the maximum desired size * */ map = new LinkedHashMap(LOCALE_CACHE_SIZE, 1, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry( Map.Entry eldest) { if (size() > (LOCALE_CACHE_SIZE - 1)) { return true; } return false; } }; managers.put(packageName, map); } StringManager mgr = map.get(locale); if (mgr == null) { mgr = new StringManager(packageName, locale); map.put(locale, mgr); } return mgr; } /** * Retrieve the StringManager for a list of Locales. The first StringManager * found will be returned. * * @param requestedLocales the list of Locales * * @return the found StringManager or the default StringManager */ public static StringManager getManager(String packageName, Enumeration requestedLocales) { while (requestedLocales.hasMoreElements()) { Locale locale = requestedLocales.nextElement(); StringManager result = getManager(packageName, locale); if (result.getLocale().equals(locale)) { return result; } } // Return the default return getManager(packageName); } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/0000755000175100017510000000000012301126366021767 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/modeler/OperationInfo.java0000644000175100017510000001126412271452077025421 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.util.Locale; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; /** *

    Internal configuration information for an Operation * descriptor.

    * * @author Craig R. McClanahan */ public class OperationInfo extends FeatureInfo { static final long serialVersionUID = 4418342922072614875L; // ----------------------------------------------------------- Constructors /** * Standard zero-arguments constructor. */ public OperationInfo() { super(); } // ----------------------------------------------------- Instance Variables protected String impact = "UNKNOWN"; protected String role = "operation"; protected ParameterInfo parameters[] = new ParameterInfo[0]; // ------------------------------------------------------------- Properties /** * The "impact" of this operation, which should be a (case-insensitive) * string value "ACTION", "ACTION_INFO", "INFO", or "UNKNOWN". */ public String getImpact() { return (this.impact); } public void setImpact(String impact) { if (impact == null) this.impact = null; else this.impact = impact.toUpperCase(Locale.ENGLISH); } /** * The role of this operation ("getter", "setter", "operation", or * "constructor"). */ public String getRole() { return (this.role); } public void setRole(String role) { this.role = role; } /** * The fully qualified Java class name of the return type for this * operation. */ public String getReturnType() { if(type == null) { type = "void"; } return type; } public void setReturnType(String returnType) { this.type = returnType; } /** * The set of parameters for this operation. */ public ParameterInfo[] getSignature() { return (this.parameters); } // --------------------------------------------------------- Public Methods /** * Add a new parameter to the set of arguments for this operation. * * @param parameter The new parameter descriptor */ public void addParameter(ParameterInfo parameter) { synchronized (parameters) { ParameterInfo results[] = new ParameterInfo[parameters.length + 1]; System.arraycopy(parameters, 0, results, 0, parameters.length); results[parameters.length] = parameter; parameters = results; this.info = null; } } /** * Create and return a ModelMBeanOperationInfo object that * corresponds to the attribute described by this instance. */ MBeanOperationInfo createOperationInfo() { // Return our cached information (if any) if (info == null) { // Create and return a new information object int impact = MBeanOperationInfo.UNKNOWN; if ("ACTION".equals(getImpact())) impact = MBeanOperationInfo.ACTION; else if ("ACTION_INFO".equals(getImpact())) impact = MBeanOperationInfo.ACTION_INFO; else if ("INFO".equals(getImpact())) impact = MBeanOperationInfo.INFO; info = new MBeanOperationInfo(getName(), getDescription(), getMBeanParameterInfo(), getReturnType(), impact); } return (MBeanOperationInfo)info; } protected MBeanParameterInfo[] getMBeanParameterInfo() { ParameterInfo params[] = getSignature(); MBeanParameterInfo parameters[] = new MBeanParameterInfo[params.length]; for (int i = 0; i < params.length; i++) parameters[i] = params[i].createParameterInfo(); return parameters; } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/Registry.java0000644000175100017510000006740212271452077024462 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import javax.management.DynamicMBean; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.modeler.modules.ModelerSource; /* Issues: - exceptions - too many "throws Exception" - double check the interfaces - start removing the use of the experimental methods in tomcat, then remove the methods ( before 1.1 final ) - is the security enough to prevent Registry beeing used to avoid the permission checks in the mbean server ? */ /** * Registry for modeler MBeans. * * This is the main entry point into modeler. It provides methods to create * and manipulate model mbeans and simplify their use. * * Starting with version 1.1, this is no longer a singleton and the static * methods are strongly deprecated. In a container environment we can expect * different applications to use different registries. * * This class is itself an mbean. * * IMPORTANT: public methods not marked with @since x.x are experimental or * internal. Should not be used. * * @author Craig R. McClanahan * @author Costin Manolache */ public class Registry implements RegistryMBean, MBeanRegistration { /** * The Log instance to which we will write our log messages. */ private static final Log log = LogFactory.getLog(Registry.class); // Support for the factory methods /** Will be used to isolate different apps and enhance security. */ private static HashMap perLoaderRegistries = null; /** * The registry instance created by our factory method the first time * it is called. */ private static Registry registry = null; // Per registy fields /** * The MBeanServer instance that we will use to register * management beans. */ private MBeanServer server = null; /** * The set of ManagedBean instances for the beans this registry * knows about, keyed by name. */ private HashMap descriptors = new HashMap(); /** List of managed beans, keyed by class name */ private HashMap descriptorsByClass = new HashMap(); // map to avoid duplicated searching or loading descriptors private HashMap searchedPaths=new HashMap(); private Object guard; // Id - small ints to use array access. No reset on stop() // Used for notifications private Hashtable> idDomains = new Hashtable>(); private Hashtable ids = new Hashtable(); // ----------------------------------------------------------- Constructors /** */ public Registry() { super(); } // -------------------- Static methods -------------------- // Factories /** * Factory method to create (if necessary) and return our * Registry instance. * * Use this method to obtain a Registry - all other static methods * are deprecated and shouldn't be used. * * The current version uses a static - future versions could use * the thread class loader. * * @param key Support for application isolation. If null, the context class * loader will be used ( if setUseContextClassLoader is called ) or the * default registry is returned. * @param guard Prevent access to the registry by untrusted components * * @since 1.1 */ public static synchronized Registry getRegistry(Object key, Object guard) { Registry localRegistry; if( perLoaderRegistries!=null ) { if( key==null ) key=Thread.currentThread().getContextClassLoader(); if( key != null ) { localRegistry = perLoaderRegistries.get(key); if( localRegistry == null ) { localRegistry=new Registry(); // localRegistry.key=key; localRegistry.guard=guard; perLoaderRegistries.put( key, localRegistry ); return localRegistry; } if( localRegistry.guard != null && localRegistry.guard != guard ) { return null; // XXX Should I throw a permission ex ? } return localRegistry; } } // static if (registry == null) { registry = new Registry(); } if( registry.guard != null && registry.guard != guard ) { return null; } return (registry); } /** * Allow containers to isolate apps. Can be called only once. * It is highly recommended you call this method if using Registry in * a container environment. The default is false for backward compatibility * * @param enable * @since 1.1 */ public static void setUseContextClassLoader( boolean enable ) { if( enable ) { perLoaderRegistries = new HashMap(); } } // -------------------- Generic methods -------------------- /** Lifecycle method - clean up the registry metadata. * Called from resetMetadata(). * * @since 1.1 */ @Override public void stop() { descriptorsByClass = new HashMap(); descriptors = new HashMap(); searchedPaths=new HashMap(); } /** * Load an extended mlet file. The source can be an URL, File or * InputStream. * * All mbeans will be instantiated, registered and the attributes will be * set. The result is a list of ObjectNames. * * @param source InputStream or URL of the file * @param cl ClassLoader to be used to load the mbeans, or null to use the * default JMX mechanism ( i.e. all registered loaders ) * @return List of ObjectName for the loaded mbeans * @throws Exception * * @since 1.1 */ @Override public List loadMBeans( Object source, ClassLoader cl ) throws Exception { return load("MbeansSource", source, null ); } /** Load descriptors. The source can be a File or URL or InputStream for the * descriptors file. In the case of File and URL, if the extension is ".ser" * a serialized version will be loaded. * * This method should be used to explicitly load metadata - but this is not * required in most cases. The registerComponent() method will find metadata * in the same package. * * @param source */ @Override public void loadMetadata(Object source ) throws Exception { loadDescriptors( null, source, null ); } /** Register a bean by creating a modeler mbean and adding it to the * MBeanServer. * * If metadata is not loaded, we'll look up and read a file named * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package * or parent. * * If the bean is an instance of DynamicMBean. it's metadata will be converted * to a model mbean and we'll wrap it - so modeler services will be supported * * If the metadata is still not found, introspection will be used to extract * it automatically. * * If an mbean is already registered under this name, it'll be first * unregistered. * * If the component implements MBeanRegistration, the methods will be called. * If the method has a method "setRegistry" that takes a RegistryMBean as * parameter, it'll be called with the current registry. * * * @param bean Object to be registered * @param oname Name used for registration * @param type The type of the mbean, as declared in mbeans-descriptors. If * null, the name of the class will be used. This can be used as a hint or * by subclasses. * * @since 1.1 */ @Override public void registerComponent(Object bean, String oname, String type) throws Exception { registerComponent(bean, new ObjectName(oname), type); } /** Unregister a component. We'll first check if it is registered, * and mask all errors. This is mostly a helper. * * @param oname * * @since 1.1 */ @Override public void unregisterComponent( String oname ) { try { unregisterComponent(new ObjectName(oname)); } catch (MalformedObjectNameException e) { log.info("Error creating object name " + e ); } } /** Invoke a operation on a list of mbeans. Can be used to implement * lifecycle operations. * * @param mbeans list of ObjectName on which we'll invoke the operations * @param operation Name of the operation ( init, start, stop, etc) * @param failFirst If false, exceptions will be ignored * @throws Exception * @since 1.1 */ @Override public void invoke(List mbeans, String operation, boolean failFirst ) throws Exception { if( mbeans==null ) { return; } Iterator itr = mbeans.iterator(); while(itr.hasNext()) { ObjectName current = itr.next(); try { if(current == null) { continue; } if(getMethodInfo(current, operation) == null) { continue; } getMBeanServer().invoke(current, operation, new Object[] {}, new String[] {}); } catch( Exception t ) { if( failFirst ) throw t; log.info("Error initializing " + current + " " + t.toString()); } } } // -------------------- ID registry -------------------- /** Return an int ID for faster access. Will be used for notifications * and for other operations we want to optimize. * * @param domain Namespace * @param name Type of the notification * @return An unique id for the domain:name combination * @since 1.1 */ @Override public synchronized int getId( String domain, String name) { if( domain==null) { domain=""; } Hashtable domainTable = idDomains.get(domain); if( domainTable == null ) { domainTable = new Hashtable(); idDomains.put( domain, domainTable); } if( name==null ) { name=""; } Integer i = domainTable.get(name); if( i!= null ) { return i.intValue(); } int id[] = ids.get(domain); if( id == null ) { id=new int[1]; ids.put( domain, id); } int code=id[0]++; domainTable.put( name, new Integer( code )); return code; } // -------------------- Metadata -------------------- // methods from 1.0 /** * Add a new bean metadata to the set of beans known to this registry. * This is used by internal components. * * @param bean The managed bean to be added * @since 1.0 */ public void addManagedBean(ManagedBean bean) { // XXX Use group + name descriptors.put(bean.getName(), bean); if( bean.getType() != null ) { descriptorsByClass.put( bean.getType(), bean ); } } /** * Find and return the managed bean definition for the specified * bean name, if any; otherwise return null. * * @param name Name of the managed bean to be returned. Since 1.1, both * short names or the full name of the class can be used. * @since 1.0 */ public ManagedBean findManagedBean(String name) { // XXX Group ?? Use Group + Type ManagedBean mb = descriptors.get(name); if( mb==null ) mb = descriptorsByClass.get(name); return mb; } /** * Return the set of bean names for all managed beans known to * this registry. * * @since 1.0 */ public String[] findManagedBeans() { return descriptors.keySet().toArray(new String[0]); } /** * Return the set of bean names for all managed beans known to * this registry that belong to the specified group. * * @param group Name of the group of interest, or null * to select beans that do not belong to a group * @since 1.0 */ public String[] findManagedBeans(String group) { ArrayList results = new ArrayList(); Iterator items = descriptors.values().iterator(); while (items.hasNext()) { ManagedBean item = items.next(); if ((group == null)) { if (item.getGroup() == null){ results.add(item.getName()); } } else if (group.equals(item.getGroup())) { results.add(item.getName()); } } String values[] = new String[results.size()]; return results.toArray(values); } /** * Remove an existing bean from the set of beans known to this registry. * * @param bean The managed bean to be removed * @since 1.0 */ public void removeManagedBean(ManagedBean bean) { // TODO: change this to use group/name descriptors.remove(bean.getName()); descriptorsByClass.remove( bean.getType()); } // -------------------- Helpers -------------------- /** Get the type of an attribute of the object, from the metadata. * * @param oname * @param attName * @return null if metadata about the attribute is not found * @since 1.1 */ public String getType( ObjectName oname, String attName ) { String type=null; MBeanInfo info=null; try { info=server.getMBeanInfo(oname); } catch (Exception e) { log.info( "Can't find metadata for object" + oname ); return null; } MBeanAttributeInfo attInfo[]=info.getAttributes(); for( int i=0; iMBeanServer instance. * */ public synchronized MBeanServer getMBeanServer() { long t1=System.currentTimeMillis(); if (server == null) { if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { server = MBeanServerFactory.findMBeanServer(null).get(0); if( log.isDebugEnabled() ) { log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1 )); } } else { server = ManagementFactory.getPlatformMBeanServer(); if( log.isDebugEnabled() ) { log.debug("Creating MBeanServer"+ (System.currentTimeMillis() - t1 )); } } } return (server); } /** Find or load metadata. */ public ManagedBean findManagedBean(Object bean, Class beanClass, String type) throws Exception { if( bean!=null && beanClass==null ) { beanClass=bean.getClass(); } if( type==null ) { type=beanClass.getName(); } // first look for existing descriptor ManagedBean managed = findManagedBean(type); // Search for a descriptor in the same package if( managed==null ) { // check package and parent packages if( log.isDebugEnabled() ) { log.debug( "Looking for descriptor "); } findDescriptor( beanClass, type ); managed=findManagedBean(type); } // Still not found - use introspection if( managed==null ) { if( log.isDebugEnabled() ) { log.debug( "Introspecting "); } // introspection loadDescriptors("MbeansDescriptorsIntrospectionSource", beanClass, type); managed=findManagedBean(type); if( managed==null ) { log.warn( "No metadata found for " + type ); return null; } managed.setName( type ); addManagedBean(managed); } return managed; } /** EXPERIMENTAL Convert a string to object, based on type. Used by several * components. We could provide some pluggability. It is here to keep * things consistent and avoid duplication in other tasks * * @param type Fully qualified class name of the resulting value * @param value String value to be converted * @return Converted value */ public Object convertValue(String type, String value) { Object objValue=value; if( type==null || "java.lang.String".equals( type )) { // string is default objValue=value; } else if( "javax.management.ObjectName".equals( type ) || "ObjectName".equals( type )) { try { objValue=new ObjectName( value ); } catch (MalformedObjectNameException e) { return null; } } else if( "java.lang.Integer".equals( type ) || "int".equals( type )) { objValue=new Integer( value ); } else if( "java.lang.Long".equals( type ) || "long".equals( type )) { objValue=new Long( value ); } else if( "java.lang.Boolean".equals( type ) || "boolean".equals( type )) { objValue=Boolean.valueOf( value ); } return objValue; } /** Experimental. * * @param sourceType * @param source * @param param * @return List of descriptors * @throws Exception */ public List load( String sourceType, Object source, String param) throws Exception { if( log.isTraceEnabled()) { log.trace("load " + source ); } String location=null; String type=null; Object inputsource=null; if( source instanceof URL ) { URL url=(URL)source; location=url.toString(); type=param; inputsource=url.openStream(); if( sourceType == null ) { sourceType = sourceTypeFromExt(location); } } else if( source instanceof File ) { location=((File)source).getAbsolutePath(); inputsource=new FileInputStream((File)source); type=param; if( sourceType == null ) { sourceType = sourceTypeFromExt(location); } } else if( source instanceof InputStream ) { type=param; inputsource=source; } else if( source instanceof Class ) { location=((Class)source).getName(); type=param; inputsource=source; if( sourceType== null ) { sourceType="MbeansDescriptorsIntrospectionSource"; } } if( sourceType==null ) { sourceType="MbeansDescriptorsDigesterSource"; } ModelerSource ds=getModelerSource(sourceType); List mbeans = ds.loadDescriptors(this, type, inputsource); return mbeans; } private String sourceTypeFromExt( String s ) { if( s.endsWith( ".ser")) { return "MbeansDescriptorsSerSource"; } else if( s.endsWith(".xml")) { return "MbeansDescriptorsDigesterSource"; } return null; } /** Register a component * XXX make it private * * @param bean * @param oname * @param type * @throws Exception */ public void registerComponent(Object bean, ObjectName oname, String type) throws Exception { if( log.isDebugEnabled() ) { log.debug( "Managed= "+ oname); } if( bean ==null ) { log.error("Null component " + oname ); return; } try { if( type==null ) { type=bean.getClass().getName(); } ManagedBean managed = findManagedBean(bean.getClass(), type); // The real mbean is created and registered DynamicMBean mbean = managed.createMBean(bean); if( getMBeanServer().isRegistered( oname )) { if( log.isDebugEnabled()) { log.debug("Unregistering existing component " + oname ); } getMBeanServer().unregisterMBean( oname ); } getMBeanServer().registerMBean( mbean, oname); } catch( Exception ex) { log.error("Error registering " + oname, ex ); throw ex; } } /** Lookup the component descriptor in the package and * in the parent packages. * * @param packageName */ public void loadDescriptors( String packageName, ClassLoader classLoader ) { String res=packageName.replace( '.', '/'); if( log.isTraceEnabled() ) { log.trace("Finding descriptor " + res ); } if( searchedPaths.get( packageName ) != null ) { return; } String descriptors=res + "/mbeans-descriptors.ser"; URL dURL=classLoader.getResource( descriptors ); if( dURL == null ) { descriptors=res + "/mbeans-descriptors.xml"; dURL=classLoader.getResource( descriptors ); } if( dURL == null ) { return; } log.debug( "Found " + dURL); searchedPaths.put( packageName, dURL ); try { if( descriptors.endsWith(".xml" )) loadDescriptors("MbeansDescriptorsDigesterSource", dURL, null); else loadDescriptors("MbeansDescriptorsSerSource", dURL, null); return; } catch(Exception ex ) { log.error("Error loading " + dURL); } return; } /** * @param sourceType * @param source * @param param * @throws Exception */ private void loadDescriptors(String sourceType, Object source, String param) throws Exception { load(sourceType, source, param); } /** Lookup the component descriptor in the package and * in the parent packages. * * @param beanClass * @param type */ private void findDescriptor(Class beanClass, String type) { if( type==null ) { type=beanClass.getName(); } ClassLoader classLoader=null; if( beanClass!=null ) { classLoader=beanClass.getClassLoader(); } if( classLoader==null ) { classLoader=Thread.currentThread().getContextClassLoader(); } if( classLoader==null ) { classLoader=this.getClass().getClassLoader(); } String className=type; String pkg=className; while( pkg.indexOf( ".") > 0 ) { int lastComp=pkg.lastIndexOf( "."); if( lastComp <= 0 ) return; pkg=pkg.substring(0, lastComp); if( searchedPaths.get( pkg ) != null ) { return; } loadDescriptors(pkg, classLoader); } return; } private ModelerSource getModelerSource( String type ) throws Exception { if( type==null ) type="MbeansDescriptorsDigesterSource"; if( type.indexOf( ".") < 0 ) { type="org.apache.tomcat.util.modeler.modules." + type; } Class c = Class.forName(type); ModelerSource ds=(ModelerSource)c.newInstance(); return ds; } // -------------------- Registration -------------------- @Override public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { this.server=server; return name; } @Override public void postRegister(Boolean registrationDone) { } @Override public void preDeregister() throws Exception { } @Override public void postDeregister() { } // -------------------- DEPRECATED METHODS -------------------- // May still be used in tomcat // Never part of an official release /** * @deprecated */ @Deprecated public ManagedBean findManagedBean(Class beanClass, String type) throws Exception { return findManagedBean(null, beanClass, type); } /** * Set the MBeanServer to be utilized for our * registered management beans. * * @param server The new MBeanServer instance */ public void setMBeanServer( MBeanServer server ) { this.server=server; } public void resetMetadata() { stop(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java0000644000175100017510000001051712271452077026551 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.util.HashSet; import javax.management.AttributeChangeNotification; import javax.management.Notification; import javax.management.NotificationFilter; /** *

    Implementation of NotificationFilter for attribute change * notifications. This class is used by BaseModelMBean to * construct attribute change notification event filters when a filter is not * supplied by the application.

    * * @author Craig R. McClanahan */ public class BaseAttributeFilter implements NotificationFilter { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Construct a new filter that accepts only the specified attribute * name. * * @param name Name of the attribute to be accepted by this filter, or * null to accept all attribute names */ public BaseAttributeFilter(String name) { super(); if (name != null) addAttribute(name); } // ----------------------------------------------------- Instance Variables /** * The set of attribute names that are accepted by this filter. If this * list is empty, all attribute names are accepted. */ private HashSet names = new HashSet(); // --------------------------------------------------------- Public Methods /** * Add a new attribute name to the set of names accepted by this filter. * * @param name Name of the attribute to be accepted */ public void addAttribute(String name) { synchronized (names) { names.add(name); } } /** * Clear all accepted names from this filter, so that it will accept * all attribute names. */ public void clear() { synchronized (names) { names.clear(); } } /** * Return the set of names that are accepted by this filter. If this * filter accepts all attribute names, a zero length array will be * returned. */ public String[] getNames() { synchronized (names) { return names.toArray(new String[names.size()]); } } /** *

    Test whether notification enabled for this event. * Return true if:

    *
      *
    • This is an attribute change notification
    • *
    • Either the set of accepted names is empty (implying that all * attribute names are of interest) or the set of accepted names * includes the name of the attribute in this notification
    • *
    */ @Override public boolean isNotificationEnabled(Notification notification) { if (notification == null) return (false); if (!(notification instanceof AttributeChangeNotification)) return (false); AttributeChangeNotification acn = (AttributeChangeNotification) notification; if (!AttributeChangeNotification.ATTRIBUTE_CHANGE.equals(acn.getType())) return (false); synchronized (names) { if (names.size() < 1) return (true); else return (names.contains(acn.getAttributeName())); } } /** * Remove an attribute name from the set of names accepted by this * filter. * * @param name Name of the attribute to be removed */ public void removeAttribute(String name) { synchronized (names) { names.remove(name); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd0000644000175100017510000002374212271452077026307 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/BaseModelMBean.java0000644000175100017510000012444212271452077025406 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Iterator; import javax.management.Attribute; import javax.management.AttributeChangeNotification; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; import javax.management.InstanceNotFoundException; import javax.management.InvalidAttributeValueException; import javax.management.ListenerNotFoundException; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanNotificationInfo; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.Notification; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.ReflectionException; import javax.management.RuntimeErrorException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import javax.management.modelmbean.ModelMBeanNotificationBroadcaster; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /* * Changes from commons.modeler: * * - use DynamicMBean * - remove methods not used in tomcat and redundant/not very generic * - must be created from the ManagedBean - I don't think there were any direct * uses, but now it is required. * - some of the gratuitous flexibility removed - instead this is more predictive and * strict with the use cases. * - all Method and metadata is stored in ManagedBean. BaseModelBMean and ManagedBean act * like Object and Class. * - setModelMBean is no longer called on resources ( not used in tomcat ) * - no caching of Methods for now - operations and setters are not called repeatedly in most * management use cases. Getters should't be called very frequently either - and even if they * are, the overhead of getting the method should be small compared with other JMX costs ( RMI, etc ). * We can add getter cache if needed. * - removed unused constructor, fields * * TODO: * - clean up catalina.mbeans, stop using weird inheritance */ /** *

    Basic implementation of the DynamicMBean interface, which * supports the minimal requirements of the interface contract.

    * *

    This can be used directly to wrap an existing java bean, or inside * an mlet or anywhere an MBean would be used. * * Limitations: *

      *
    • Only managed resources of type objectReference are * supported.
    • *
    • Caching of attribute values and operation results is not supported. * All calls to invoke() are immediately executed.
    • *
    • Persistence of MBean attributes and operations is not supported.
    • *
    • All classes referenced as attribute types, operation parameters, or * operation return values must be one of the following: *
        *
      • One of the Java primitive types (boolean, byte, char, double, * float, integer, long, short). Corresponding value will be wrapped * in the appropriate wrapper class automatically.
      • *
      • Operations that return no value should declare a return type of * void.
      • *
      *
    • Attribute caching is not supported
    • *
    * * @author Craig R. McClanahan * @author Costin Manolache */ public class BaseModelMBean implements DynamicMBean, MBeanRegistration, ModelMBeanNotificationBroadcaster { private static final Log log = LogFactory.getLog(BaseModelMBean.class); // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ protected BaseModelMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables protected ObjectName oname=null; /** * Notification broadcaster for attribute changes. */ protected BaseNotificationBroadcaster attributeBroadcaster = null; /** * Notification broadcaster for general notifications. */ protected BaseNotificationBroadcaster generalBroadcaster = null; /** Metadata for the mbean instance. */ protected ManagedBean managedBean = null; /** * The managed resource this MBean is associated with (if any). */ protected Object resource = null; // --------------------------------------------------- DynamicMBean Methods // TODO: move to ManagedBean static final Object[] NO_ARGS_PARAM = new Object[0]; static final Class[] NO_ARGS_PARAM_SIG = new Class[0]; protected String resourceType = null; // key: operation val: invoke method //private Hashtable invokeAttMap=new Hashtable(); /** * Obtain and return the value of a specific attribute of this MBean. * * @param name Name of the requested attribute * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException { // Validate the input parameters if (name == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute name is null"), "Attribute name is null"); if( (resource instanceof DynamicMBean) && ! ( resource instanceof BaseModelMBean )) { return ((DynamicMBean)resource).getAttribute(name); } Method m=managedBean.getGetter(name, this, resource); Object result = null; try { Class declaring = m.getDeclaringClass(); // workaround for catalina weird mbeans - the declaring class is BaseModelMBean. // but this is the catalina class. if( declaring.isAssignableFrom(this.getClass()) ) { result = m.invoke(this, NO_ARGS_PARAM ); } else { result = m.invoke(resource, NO_ARGS_PARAM ); } } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); if (t == null) t = e; if (t instanceof RuntimeException) throw new RuntimeOperationsException ((RuntimeException) t, "Exception invoking method " + name); else if (t instanceof Error) throw new RuntimeErrorException ((Error) t, "Error invoking method " + name); else throw new MBeanException (e, "Exception invoking method " + name); } catch (Exception e) { throw new MBeanException (e, "Exception invoking method " + name); } // Return the results of this method invocation // FIXME - should we validate the return type? return (result); } /** * Obtain and return the values of several attributes of this MBean. * * @param names Names of the requested attributes */ @Override public AttributeList getAttributes(String names[]) { // Validate the input parameters if (names == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute names list is null"), "Attribute names list is null"); // Prepare our response, eating all exceptions AttributeList response = new AttributeList(); for (int i = 0; i < names.length; i++) { try { response.add(new Attribute(names[i],getAttribute(names[i]))); } catch (Exception e) { // Not having a particular attribute in the response // is the indication of a getter problem } } return (response); } public void setManagedBean(ManagedBean managedBean) { this.managedBean = managedBean; } /** * Return the MBeanInfo object for this MBean. */ @Override public MBeanInfo getMBeanInfo() { return managedBean.getMBeanInfo(); } /** * Invoke a particular method on this MBean, and return any returned * value. * *

    IMPLEMENTATION NOTE - This implementation will * attempt to invoke this method on the MBean itself, or (if not * available) on the managed resource object associated with this * MBean.

    * * @param name Name of the operation to be invoked * @param params Array containing the method parameters of this operation * @param signature Array containing the class names representing * the signature of this operation * * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking a method */ @Override public Object invoke(String name, Object params[], String signature[]) throws MBeanException, ReflectionException { if( (resource instanceof DynamicMBean) && ! ( resource instanceof BaseModelMBean )) { return ((DynamicMBean)resource).invoke(name, params, signature); } // Validate the input parameters if (name == null) throw new RuntimeOperationsException (new IllegalArgumentException("Method name is null"), "Method name is null"); if( log.isDebugEnabled()) log.debug("Invoke " + name); Method method= managedBean.getInvoke(name, params, signature, this, resource); // Invoke the selected method on the appropriate object Object result = null; try { if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) { result = method.invoke(this, params ); } else { result = method.invoke(resource, params); } } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); log.error("Exception invoking method " + name , t ); if (t == null) t = e; if (t instanceof RuntimeException) throw new RuntimeOperationsException ((RuntimeException) t, "Exception invoking method " + name); else if (t instanceof Error) throw new RuntimeErrorException ((Error) t, "Error invoking method " + name); else throw new MBeanException ((Exception)t, "Exception invoking method " + name); } catch (Exception e) { log.error("Exception invoking method " + name , e ); throw new MBeanException (e, "Exception invoking method " + name); } // Return the results of this method invocation // FIXME - should we validate the return type? return (result); } static Class getAttributeClass(String signature) throws ReflectionException { if (signature.equals(Boolean.TYPE.getName())) return Boolean.TYPE; else if (signature.equals(Byte.TYPE.getName())) return Byte.TYPE; else if (signature.equals(Character.TYPE.getName())) return Character.TYPE; else if (signature.equals(Double.TYPE.getName())) return Double.TYPE; else if (signature.equals(Float.TYPE.getName())) return Float.TYPE; else if (signature.equals(Integer.TYPE.getName())) return Integer.TYPE; else if (signature.equals(Long.TYPE.getName())) return Long.TYPE; else if (signature.equals(Short.TYPE.getName())) return Short.TYPE; else { try { ClassLoader cl=Thread.currentThread().getContextClassLoader(); if( cl!=null ) return cl.loadClass(signature); } catch( ClassNotFoundException e ) { } try { return Class.forName(signature); } catch (ClassNotFoundException e) { throw new ReflectionException (e, "Cannot find Class for " + signature); } } } /** * Set the value of a specific attribute of this MBean. * * @param attribute The identification of the attribute to be set * and the new value * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { if( log.isDebugEnabled() ) log.debug("Setting attribute " + this + " " + attribute ); if( (resource instanceof DynamicMBean) && ! ( resource instanceof BaseModelMBean )) { try { ((DynamicMBean)resource).setAttribute(attribute); } catch (InvalidAttributeValueException e) { throw new MBeanException(e); } return; } // Validate the input parameters if (attribute == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute is null"), "Attribute is null"); String name = attribute.getName(); Object value = attribute.getValue(); if (name == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute name is null"), "Attribute name is null"); Object oldValue=null; //if( getAttMap.get(name) != null ) // oldValue=getAttribute( name ); Method m=managedBean.getSetter(name,this,resource); try { if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) { m.invoke(this, new Object[] { value }); } else { m.invoke(resource, new Object[] { value }); } } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); if (t == null) t = e; if (t instanceof RuntimeException) throw new RuntimeOperationsException ((RuntimeException) t, "Exception invoking method " + name); else if (t instanceof Error) throw new RuntimeErrorException ((Error) t, "Error invoking method " + name); else throw new MBeanException (e, "Exception invoking method " + name); } catch (Exception e) { log.error("Exception invoking method " + name , e ); throw new MBeanException (e, "Exception invoking method " + name); } try { sendAttributeChangeNotification(new Attribute( name, oldValue), attribute); } catch(Exception ex) { log.error("Error sending notification " + name, ex); } //attributes.put( name, value ); // if( source != null ) { // // this mbean is associated with a source - maybe we want to persist // source.updateField(oname, name, value); // } } @Override public String toString() { if( resource==null ) return "BaseModelMbean[" + resourceType + "]"; return resource.toString(); } /** * Set the values of several attributes of this MBean. * * @param attributes THe names and values to be set * * @return The list of attributes that were set and their new values */ @Override public AttributeList setAttributes(AttributeList attributes) { AttributeList response = new AttributeList(); // Validate the input parameters if (attributes == null) return response; // Prepare and return our response, eating all exceptions String names[] = new String[attributes.size()]; int n = 0; Iterator items = attributes.iterator(); while (items.hasNext()) { Attribute item = (Attribute) items.next(); names[n++] = item.getName(); try { setAttribute(item); } catch (Exception e) { // Ignore all exceptions } } return (getAttributes(names)); } // ----------------------------------------------------- ModelMBean Methods /** * Get the instance handle of the object against which we execute * all methods in this ModelMBean management interface. * * @exception InstanceNotFoundException if the managed resource object * cannot be found * @exception InvalidTargetObjectTypeException if the managed resource * object is of the wrong type * @exception MBeanException if the initializer of the object throws * an exception * @exception RuntimeOperationsException if the managed resource or the * resource type is null or invalid */ public Object getManagedResource() throws InstanceNotFoundException, InvalidTargetObjectTypeException, MBeanException, RuntimeOperationsException { if (resource == null) throw new RuntimeOperationsException (new IllegalArgumentException("Managed resource is null"), "Managed resource is null"); return resource; } /** * Set the instance handle of the object against which we will execute * all methods in this ModelMBean management interface. * * This method will detect and call "setModelMbean" method. A resource * can implement this method to get a reference to the model mbean. * The reference can be used to send notification and access the * registry. * The caller can provide the mbean instance or the object name to * the resource, if needed. * * @param resource The resource object to be managed * @param type The type of reference for the managed resource * ("ObjectReference", "Handle", "IOR", "EJBHandle", or * "RMIReference") * * @exception InstanceNotFoundException if the managed resource object * cannot be found * @exception MBeanException if the initializer of the object throws * an exception * @exception RuntimeOperationsException if the managed resource or the * resource type is null or invalid */ public void setManagedResource(Object resource, String type) throws InstanceNotFoundException, MBeanException, RuntimeOperationsException { if (resource == null) throw new RuntimeOperationsException (new IllegalArgumentException("Managed resource is null"), "Managed resource is null"); // if (!"objectreference".equalsIgnoreCase(type)) // throw new InvalidTargetObjectTypeException(type); this.resource = resource; this.resourceType = resource.getClass().getName(); // // Make the resource aware of the model mbean. // try { // Method m=resource.getClass().getMethod("setModelMBean", // new Class[] {ModelMBean.class}); // if( m!= null ) { // m.invoke(resource, new Object[] {this}); // } // } catch( NoSuchMethodException t ) { // // ignore // } catch( Throwable t ) { // log.error( "Can't set model mbean ", t ); // } } // ------------------------------ ModelMBeanNotificationBroadcaster Methods /** * Add an attribute change notification event listener to this MBean. * * @param listener Listener that will receive event notifications * @param name Name of the attribute of interest, or null * to indicate interest in all attributes * @param handback Handback object to be sent along with event * notifications * * @exception IllegalArgumentException if the listener parameter is null */ @Override public void addAttributeChangeNotificationListener (NotificationListener listener, String name, Object handback) throws IllegalArgumentException { if (listener == null) throw new IllegalArgumentException("Listener is null"); if (attributeBroadcaster == null) attributeBroadcaster = new BaseNotificationBroadcaster(); if( log.isDebugEnabled() ) log.debug("addAttributeNotificationListener " + listener); BaseAttributeFilter filter = new BaseAttributeFilter(name); attributeBroadcaster.addNotificationListener (listener, filter, handback); } /** * Remove an attribute change notification event listener from * this MBean. * * @param listener The listener to be removed * @param name The attribute name for which no more events are required * * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ @Override public void removeAttributeChangeNotificationListener (NotificationListener listener, String name) throws ListenerNotFoundException { if (listener == null) throw new IllegalArgumentException("Listener is null"); if (attributeBroadcaster == null) attributeBroadcaster = new BaseNotificationBroadcaster(); // FIXME - currently this removes *all* notifications for this listener attributeBroadcaster.removeNotificationListener(listener); } /** * Remove an attribute change notification event listener from * this MBean. * * @param listener The listener to be removed * @param attributeName The attribute name for which no more events are required * @param handback Handback object to be sent along with event * notifications * * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ public void removeAttributeChangeNotificationListener (NotificationListener listener, String attributeName, Object handback) throws ListenerNotFoundException { removeAttributeChangeNotificationListener(listener, attributeName); } /** * Send an AttributeChangeNotification to all registered * listeners. * * @param notification The AttributeChangeNotification * that will be passed * * @exception MBeanException if an object initializer throws an * exception * @exception RuntimeOperationsException wraps IllegalArgumentException * when the specified notification is null or invalid */ @Override public void sendAttributeChangeNotification (AttributeChangeNotification notification) throws MBeanException, RuntimeOperationsException { if (notification == null) throw new RuntimeOperationsException (new IllegalArgumentException("Notification is null"), "Notification is null"); if (attributeBroadcaster == null) return; // This means there are no registered listeners if( log.isDebugEnabled() ) log.debug( "AttributeChangeNotification " + notification ); attributeBroadcaster.sendNotification(notification); } /** * Send an AttributeChangeNotification to all registered * listeners. * * @param oldValue The original value of the Attribute * @param newValue The new value of the Attribute * * @exception MBeanException if an object initializer throws an * exception * @exception RuntimeOperationsException wraps IllegalArgumentException * when the specified notification is null or invalid */ @Override public void sendAttributeChangeNotification (Attribute oldValue, Attribute newValue) throws MBeanException, RuntimeOperationsException { // Calculate the class name for the change notification String type = null; if (newValue.getValue() != null) type = newValue.getValue().getClass().getName(); else if (oldValue.getValue() != null) type = oldValue.getValue().getClass().getName(); else return; // Old and new are both null == no change AttributeChangeNotification notification = new AttributeChangeNotification (this, 1, System.currentTimeMillis(), "Attribute value has changed", oldValue.getName(), type, oldValue.getValue(), newValue.getValue()); sendAttributeChangeNotification(notification); } /** * Send a Notification to all registered listeners as a * jmx.modelmbean.general notification. * * @param notification The Notification that will be passed * * @exception MBeanException if an object initializer throws an * exception * @exception RuntimeOperationsException wraps IllegalArgumentException * when the specified notification is null or invalid */ @Override public void sendNotification(Notification notification) throws MBeanException, RuntimeOperationsException { if (notification == null) throw new RuntimeOperationsException (new IllegalArgumentException("Notification is null"), "Notification is null"); if (generalBroadcaster == null) return; // This means there are no registered listeners generalBroadcaster.sendNotification(notification); } /** * Send a Notification which contains the specified string * as a jmx.modelmbean.generic notification. * * @param message The message string to be passed * * @exception MBeanException if an object initializer throws an * exception * @exception RuntimeOperationsException wraps IllegalArgumentException * when the specified notification is null or invalid */ @Override public void sendNotification(String message) throws MBeanException, RuntimeOperationsException { if (message == null) throw new RuntimeOperationsException (new IllegalArgumentException("Message is null"), "Message is null"); Notification notification = new Notification ("jmx.modelmbean.generic", this, 1, message); sendNotification(notification); } // ---------------------------------------- NotificationBroadcaster Methods /** * Add a notification event listener to this MBean. * * @param listener Listener that will receive event notifications * @param filter Filter object used to filter event notifications * actually delivered, or null for no filtering * @param handback Handback object to be sent along with event * notifications * * @exception IllegalArgumentException if the listener parameter is null */ @Override public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { if (listener == null) throw new IllegalArgumentException("Listener is null"); if( log.isDebugEnabled() ) log.debug("addNotificationListener " + listener); if (generalBroadcaster == null) generalBroadcaster = new BaseNotificationBroadcaster(); generalBroadcaster.addNotificationListener (listener, filter, handback); // We'll send the attribute change notifications to all listeners ( who care ) // The normal filtering can be used. // The problem is that there is no other way to add attribute change listeners // to a model mbean ( AFAIK ). I suppose the spec should be fixed. if (attributeBroadcaster == null) attributeBroadcaster = new BaseNotificationBroadcaster(); if( log.isDebugEnabled() ) log.debug("addAttributeNotificationListener " + listener); attributeBroadcaster.addNotificationListener (listener, filter, handback); } /** * Return an MBeanNotificationInfo object describing the * notifications sent by this MBean. */ @Override public MBeanNotificationInfo[] getNotificationInfo() { // Acquire the set of application notifications MBeanNotificationInfo current[] = getMBeanInfo().getNotifications(); if (current == null) current = new MBeanNotificationInfo[0]; MBeanNotificationInfo response[] = new MBeanNotificationInfo[current.length + 2]; // Descriptor descriptor = null; // Fill in entry for general notifications // descriptor = new DescriptorSupport // (new String[] { "name=GENERIC", // "descriptorType=notification", // "log=T", // "severity=5", // "displayName=jmx.modelmbean.generic" }); response[0] = new MBeanNotificationInfo (new String[] { "jmx.modelmbean.generic" }, "GENERIC", "Text message notification from the managed resource"); //descriptor); // Fill in entry for attribute change notifications // descriptor = new DescriptorSupport // (new String[] { "name=ATTRIBUTE_CHANGE", // "descriptorType=notification", // "log=T", // "severity=5", // "displayName=jmx.attribute.change" }); response[1] = new MBeanNotificationInfo (new String[] { "jmx.attribute.change" }, "ATTRIBUTE_CHANGE", "Observed MBean attribute value has changed"); //descriptor); // Copy remaining notifications as reported by the application System.arraycopy(current, 0, response, 2, current.length); return (response); } /** * Remove a notification event listener from this MBean. * * @param listener The listener to be removed (any and all registrations * for this listener will be eliminated) * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ @Override public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { if (listener == null) throw new IllegalArgumentException("Listener is null"); if (generalBroadcaster == null) generalBroadcaster = new BaseNotificationBroadcaster(); generalBroadcaster.removeNotificationListener(listener); } /** * Remove a notification event listener from this MBean. * * @param listener The listener to be removed (any and all registrations * for this listener will be eliminated) * @param handback Handback object to be sent along with event * notifications * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ public void removeNotificationListener(NotificationListener listener, Object handback) throws ListenerNotFoundException { removeNotificationListener(listener); } /** * Remove a notification event listener from this MBean. * * @param listener The listener to be removed (any and all registrations * for this listener will be eliminated) * @param filter Filter object used to filter event notifications * actually delivered, or null for no filtering * @param handback Handback object to be sent along with event * notifications * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { removeNotificationListener(listener); } // ------------------------------------------------ PersistentMBean Methods // /** // * Instantiates this MBean instance from data found in the persistent // * store. The data loaded could include attribute and operation values. // * This method should be called during construction or initialization // * of the instance, and before the MBean is registered with the // * MBeanServer. // * // *

    IMPLEMENTATION NOTE - This implementation does // * not support persistence.

    // * // * @exception InstanceNotFoundException if the managed resource object // * cannot be found // * @exception MBeanException if the initializer of the object throws // * an exception // * @exception RuntimeOperationsException if an exception is reported // * by the persistence mechanism // */ // public void load() throws InstanceNotFoundException, // MBeanException, RuntimeOperationsException { // // XXX If a context was set, use it to load the data // throw new MBeanException // (new IllegalStateException("Persistence is not supported"), // "Persistence is not supported"); // // } // /** // * Capture the current state of this MBean instance and write it out // * to the persistent store. The state stored could include attribute // * and operation values. If one of these methods of persistence is not // * supported, a "service not found" exception will be thrown. // * // *

    IMPLEMENTATION NOTE - This implementation does // * not support persistence.

    // * // * @exception InstanceNotFoundException if the managed resource object // * cannot be found // * @exception MBeanException if the initializer of the object throws // * an exception, or persistence is not supported // * @exception RuntimeOperationsException if an exception is reported // * by the persistence mechanism // */ // public void store() throws InstanceNotFoundException, // MBeanException, RuntimeOperationsException { // // // XXX if a context was set, use it to store the data // throw new MBeanException // (new IllegalStateException("Persistence is not supported"), // "Persistence is not supported"); // // } // -------------------- BaseModelMBean methods -------------------- // /** Set the type of the mbean. This is used as a key to locate // * the description in the Registry. // * // * @param type the type of classname of the modeled object // */ // void setModeledType( String type ) { // initModelInfo(type); // createResource(); // } // /** Set the type of the mbean. This is used as a key to locate // * the description in the Registry. // * // * @param type the type of classname of the modeled object // */ // void initModelInfo( String type ) { // try { // if( log.isDebugEnabled()) // log.debug("setModeledType " + type); // // log.debug( "Set model Info " + type); // if(type==null) { // return; // } // resourceType=type; // //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); // Class c=null; // try { // c=Class.forName( type); // } catch( Throwable t ) { // log.debug( "Error creating class " + t); // } // // // The class c doesn't need to exist // ManagedBean descriptor=getRegistry().findManagedBean(c, type); // if( descriptor==null ) // return; // this.setModelMBeanInfo(descriptor.createMBeanInfo()); // } catch( Throwable ex) { // log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), // ex); // } // } // /** Set the type of the mbean. This is used as a key to locate // * the description in the Registry. // */ // protected void createResource() { // try { // //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); // Class c=null; // try { // c=Class.forName( resourceType ); // resource = c.newInstance(); // } catch( Throwable t ) { // log.error( "Error creating class " + t); // } // } catch( Throwable ex) { // log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), // ex); // } // } public String getModelerType() { return resourceType; } public String getClassName() { return getModelerType(); } public ObjectName getJmxName() { return oname; } public String getObjectName() { if (oname != null) { return oname.toString(); } else { return null; } } // public void setRegistry(Registry registry) { // this.registry = registry; // } // // public Registry getRegistry() { // // XXX Need a better solution - to avoid the static // if( registry == null ) // registry=Registry.getRegistry(); // // return registry; // } // ------------------------------------------------------ Protected Methods // /** // * Create and return a default ModelMBeanInfo object. // */ // protected ModelMBeanInfo createDefaultModelMBeanInfo() { // // return (new ModelMBeanInfoSupport(this.getClass().getName(), // "Default ModelMBean", // null, null, null, null)); // // } // /** // * Is the specified ModelMBeanInfo instance valid? // * // *

    IMPLEMENTATION NOTE - This implementation // * does not check anything, but this method can be overridden // * as required.

    // * // * @param info The ModelMBeanInfo object to check // */ // protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) { // return (true); // } // -------------------- Registration -------------------- // XXX We can add some method patterns here- like setName() and // setDomain() for code that doesn't implement the Registration @Override public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { if( log.isDebugEnabled()) log.debug("preRegister " + resource + " " + name ); oname=name; if( resource instanceof MBeanRegistration ) { oname = ((MBeanRegistration)resource).preRegister(server, name ); } return oname; } @Override public void postRegister(Boolean registrationDone) { if( resource instanceof MBeanRegistration ) { ((MBeanRegistration)resource).postRegister(registrationDone); } } @Override public void preDeregister() throws Exception { if( resource instanceof MBeanRegistration ) { ((MBeanRegistration)resource).preDeregister(); } } @Override public void postDeregister() { if( resource instanceof MBeanRegistration ) { ((MBeanRegistration)resource).postDeregister(); } } static class MethodKey { private String name; private String[] signature; MethodKey(String name, String[] signature) { this.name = name; if(signature == null) { signature = new String[0]; } this.signature = signature; } @Override public boolean equals(Object other) { if(!(other instanceof MethodKey)) { return false; } MethodKey omk = (MethodKey)other; if(!name.equals(omk.name)) { return false; } if(signature.length != omk.signature.length) { return false; } for(int i=0; i < signature.length; i++) { if(!signature[i].equals(omk.signature[i])) { return false; } } return true; } @Override public int hashCode() { return name.hashCode(); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/package.html0000644000175100017510000002470012271452077024262 0ustar locutuslocutus Package Documentation for COMMONS-MODELER

    The Modeler component of the Commons project offers convenient support for configuring and instantiating Model MBeans (management beans), as described in the JMX Specification. It is typically used within a server-based application that wants to expose management features via JMX. See the JMX Specification (Version 1.1) for more information about Model MBeans and other JMX concepts.

    Model MBeans are very powerful - and the JMX specification includes a mechanism to use a standard JMX-provided base class to satisfy many of the requirements, without having to create custom Model MBean implementation classes yourself. However, one of the requirements in creating such a Model MBean is to create the corresponding metadata information (i.e. an implementation of the javax.management.modelmbean.ModelMBeanInfo interface and its corresponding subordinate interfaces). Creating this information can be tedious and error prone. The Modeler package makes the process much simpler, because the required information is constructed dynamically from an easy-to-understand XML description of the metadata. Once you have the metadata defined, and registered at runtime in the provided Registry, Modeler also supports convenient factory methods to instantiate new Model MBean instances for you.

    The steps required to use Modeler in your server-based application are described in detail below. You can find some simple usage code in the unit tests that come with Modeler (in the src/test subdirectory of the source distribution), and much more complex usage code in Tomcat 4.1 (in the org.apache.catalina.mbeans package).

    . More advanced uses can be found in Tomcat 5.

    1. Acquire a JMX Implementation

    Modeler has been tested with different JMX implementations:

    After unpacking the release, you will need to ensure that the appropriate JAR file (jmxri.jar or mx4j.jar) is included on your compilation classpath, and in the classpath of your server application when it is executed.

    2. Create a Modeler Configuration File

    Modeler requires that you construct a configuration file that describes the metadata ultimately need to construct the javax.management.modelmbean.ModelMBeanInfo structure that is required by JMX. Your XML file must conform to the mbeans-descriptors.dtd DTD that defines the acceptable structure.

    Fundamentally, you will be constructing an <mbean> element for each type of Model MBean that a registry will know how to create. Nested within this element will be other elements describing the constructors, attributes, operations, and notifications associated with this MBean. See the comments in the DTD for detailed information about the valid attributes and their meanings.

    A simple example configuration file might include the following components (abstracted from the real definitions found in Tomcat 4.1's use of Modeler):

    
      <?xml version="1.0"?>
      <!DOCTYPE mbeans-descriptors PUBLIC
       "-//Apache Software Foundation//DTD Model MBeans Configuration File"
       "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
    
      <mbeans-descriptors>
    
        <!-- ... other MBean definitions ... -->
    
        <mbean         name="Group"
                  className="org.apache.catalina.mbeans.GroupMBean"
                description="Group from a user database"
                     domain="Users"
                      group="Group"
                       type="org.apache.catalina.Group">
    
          <attribute   name="description"
                description="Description of this group"
                       type="java.lang.String"/>
    
          <attribute   name="groupname"
                description="Group name of this group"
                       type="java.lang.String"/>
    
          <attribute   name="roles"
                description="MBean Names of roles for this group"
                       type="java.lang.String[]"
                  writeable="false"/>
    
          <attribute   name="users"
                description="MBean Names of user members of this group"
                       type="java.lang.String[]"
                  writeable="false"/>
    
          <operation   name="addRole"
                description="Add a new authorized role for this group"
                     impact="ACTION"
                 returnType="void">
            <parameter name="role"
                description="Role to be added"
                       type="java.lang.String"/>
          </operation>
    
          <operation   name="removeRole"
                description="Remove an old authorized role for this group"
                     impact="ACTION"
                 returnType="void">
            <parameter name="role"
                description="Role to be removed"
                       type="java.lang.String"/>
          </operation>
    
          <operation   name="removeRoles"
                description="Remove all authorized roles for this group"
                     impact="ACTION"
                 returnType="void">
          </operation>
    
        </mbean>
    
        <!-- ... other MBean definitions ... -->
    
      </mbeans-descriptors>
    
    

    This MBean represents an instance of org.apache.catalina.Group, which is an entity representing a group of users (with a shared set of security roles that all users in the group inherit) in a user database. This MBean advertises support for four attributes (description, groupname, roles, and users) that roughly correspond to JavaBean properties. By default, attributes are assumed to have read/write access. For this particular MBean, the roles and users attributes are read-only (writeable="false"). Finally, this MBean supports three operations (addRole, removeRole, and removeRoles) that roughly correspond to JavaBean methods on the underlying component.

    In general, Modeler provides a standard ModelMBean implementation that simply passes on JMX calls on attributes and operations directly through to the managed component that the ModelMBean is associated with. For special case requirements, you can define a subclass of BaseModelMBean that provides override methods for one or more of these attributes (i.e. the property getter and/or setter methods) and operations (i.e. direct method calls).

    For this particular MBean, a custom BaseModelMBean implementation subclass is described (org.apache.catalina.mbeans.GroupMBean) is configured. It was necessary in this particular case because several of the underlying Catalina component's methods deal with internal objects or arrays of objects, rather than just the Strings and primitives that are supported by all JMX clients. Thus, the following method on the Group interface:

        public void addRole(Role role);
    

    is represented, in the MBean, by an addRole method that takes a String argument representing the role name of the required role. The MBean's implementation class acts as an adapter, and looks up the required Role object (by name) before calling the addRole method on the underlying Group instance within the Server.

    3. Create Modeler Registry at Startup Time

    The metadata information, and the corresponding Model MBean factory, is represented at runtime in an instance of Registry whose contents are initialized from the configuration file prepared as was described above. Typically, such a file will be included in the JAR file containing the MBean implementation classes themselves, and loaded as follows:

        URL url= this.getClass().getResource
          ("/com/mycompany/mypackage/mbeans-descriptors.xml");
        Registry registry = Registry.getRegistry();
        registry.loadMetadata(url);
    

    Besides using the configuration file, it is possible to configure the registry metadata by hand, using the addManagedBean() and removeManagedBean() methods. However, most users will find the standard support for loading a configuration file to be convenient and sufficient.

    Modeler will also look for a mbeans-descriptors.xml in the same package with the class beeing registered and in its parent. If no metadata is found, modeler will use a number of simple patterns, similar with the ones used by ant, to determine a reasonable metadata

    In a future version we should also support xdoclet-based generation of the descriptors

    4. Instantiate Model MBeans As Needed

    When your server application needs to instantiate a new MBean and register it with the corresponding MBeanServer, it can execute code like this:

      Group group = ... managed component instance ...;
    
      MBeanServer mserver = registry.getMBeanServer();
    
      String oname="myDomain:type=Group,name=myGroup";
    
      registry.registerComponent( group, oname, "Group" );
    

    After the Model MBean has been created and registered, it is accessible to JMX clients through the standard JMX client APIs.

    tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/Util.java0000644000175100017510000000237612057474751023573 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; public class Util { private Util() { // Utility class. Hide default constructor. } public static boolean objectNameValueNeedsQuote(String input) { for (int i = 0; i < input.length(); i++) { char ch = input.charAt(i); if (ch == ',' || ch == '=' || ch == ':' || ch == '*' || ch == '?') { return true; } } return false; } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/ManagedBean.java0000644000175100017510000005043712271452077024774 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; import javax.management.InstanceNotFoundException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanConstructorInfo; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanNotificationInfo; import javax.management.MBeanOperationInfo; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; import javax.management.ServiceNotFoundException; /** *

    Internal configuration information for a managed bean (MBean) * descriptor.

    * * @author Craig R. McClanahan */ public class ManagedBean implements java.io.Serializable { private static final long serialVersionUID = 1L; private static final String BASE_MBEAN = "org.apache.tomcat.util.modeler.BaseModelMBean"; // ----------------------------------------------------- Instance Variables static final Object[] NO_ARGS_PARAM = new Object[0]; static final Class[] NO_ARGS_PARAM_SIG = new Class[0]; /** * The ModelMBeanInfo object that corresponds * to this ManagedBean instance. */ transient MBeanInfo info = null; private Map attributes = new HashMap(); private Map operations = new HashMap(); protected String className = BASE_MBEAN; //protected ConstructorInfo constructors[] = new ConstructorInfo[0]; protected String description = null; protected String domain = null; protected String group = null; protected String name = null; //protected List fields = new ArrayList(); protected NotificationInfo notifications[] = new NotificationInfo[0]; protected String type = null; /** Constructor. Will add default attributes. * */ public ManagedBean() { AttributeInfo ai=new AttributeInfo(); ai.setName("modelerType"); ai.setDescription("Type of the modeled resource. Can be set only once"); ai.setType("java.lang.String"); ai.setWriteable(false); addAttribute(ai); } // ------------------------------------------------------------- Properties /** * The collection of attributes for this MBean. */ public AttributeInfo[] getAttributes() { AttributeInfo result[] = new AttributeInfo[attributes.size()]; attributes.values().toArray(result); return result; } /** * The fully qualified name of the Java class of the MBean * described by this descriptor. If not specified, the standard JMX * class (javax.management.modelmbean.RequiredModeLMBean) * will be utilized. */ public String getClassName() { return (this.className); } public void setClassName(String className) { this.className = className; this.info = null; } // /** // * The collection of constructors for this MBean. // */ // public ConstructorInfo[] getConstructors() { // return (this.constructors); // } /** * The human-readable description of this MBean. */ public String getDescription() { return (this.description); } public void setDescription(String description) { this.description = description; this.info = null; } /** * The (optional) ObjectName domain in which this MBean * should be registered in the MBeanServer. */ public String getDomain() { return (this.domain); } public void setDomain(String domain) { this.domain = domain; } /** *

    Return a List of the {@link FieldInfo} objects for * the name/value pairs that should be * added to the Descriptor created from this metadata.

    */ // public List getFields() { // return (this.fields); // } // /** * The (optional) group to which this MBean belongs. */ public String getGroup() { return (this.group); } public void setGroup(String group) { this.group = group; } /** * The name of this managed bean, which must be unique among all * MBeans managed by a particular MBeans server. */ public String getName() { return (this.name); } public void setName(String name) { this.name = name; this.info = null; } /** * The collection of notifications for this MBean. */ public NotificationInfo[] getNotifications() { return (this.notifications); } /** * The collection of operations for this MBean. */ public OperationInfo[] getOperations() { OperationInfo[] result = new OperationInfo[operations.size()]; operations.values().toArray(result); return result; } /** * The fully qualified name of the Java class of the resource * implementation class described by the managed bean described * by this descriptor. */ public String getType() { return (this.type); } public void setType(String type) { this.type = type; this.info = null; } // --------------------------------------------------------- Public Methods /** * Add a new attribute to the set of attributes for this MBean. * * @param attribute The new attribute descriptor */ public void addAttribute(AttributeInfo attribute) { attributes.put(attribute.getName(), attribute); } /** * Add a new constructor to the set of constructors for this MBean. * * @param constructor The new constructor descriptor */ // public void addConstructor(ConstructorInfo constructor) { // // synchronized (constructors) { // ConstructorInfo results[] = // new ConstructorInfo[constructors.length + 1]; // System.arraycopy(constructors, 0, results, 0, constructors.length); // results[constructors.length] = constructor; // constructors = results; // this.info = null; // } // // } /** *

    Add a new field to the fields associated with the * Descriptor that will be created from this metadata.

    * * @param field The field to be added */ // public void addField(FieldInfo field) { // fields.add(field); // } /** * Add a new notification to the set of notifications for this MBean. * * @param notification The new notification descriptor */ public void addNotification(NotificationInfo notification) { synchronized (notifications) { NotificationInfo results[] = new NotificationInfo[notifications.length + 1]; System.arraycopy(notifications, 0, results, 0, notifications.length); results[notifications.length] = notification; notifications = results; this.info = null; } } /** * Add a new operation to the set of operations for this MBean. * * @param operation The new operation descriptor */ public void addOperation(OperationInfo operation) { operations.put(createOperationKey(operation), operation); } /** * Create and return a ModelMBean that has been * preconfigured with the ModelMBeanInfo information * for this managed bean, but is not associated with any particular * managed resource. The returned ModelMBean will * NOT have been registered with our * MBeanServer. * * @exception InstanceNotFoundException if the managed resource * object cannot be found * @exception MBeanException if a problem occurs instantiating the * ModelMBean instance * @exception RuntimeOperationsException if a JMX runtime error occurs */ public DynamicMBean createMBean() throws InstanceNotFoundException, MBeanException, RuntimeOperationsException { return (createMBean(null)); } /** * Create and return a ModelMBean that has been * preconfigured with the ModelMBeanInfo information * for this managed bean, and is associated with the specified * managed object instance. The returned ModelMBean * will NOT have been registered with our * MBeanServer. * * @param instance Instanced of the managed object, or null * for no associated instance * * @exception InstanceNotFoundException if the managed resource * object cannot be found * @exception MBeanException if a problem occurs instantiating the * ModelMBean instance * @exception RuntimeOperationsException if a JMX runtime error occurs */ public DynamicMBean createMBean(Object instance) throws InstanceNotFoundException, MBeanException, RuntimeOperationsException { BaseModelMBean mbean = null; // Load the ModelMBean implementation class if(getClassName().equals(BASE_MBEAN)) { // Skip introspection mbean = new BaseModelMBean(); } else { Class clazz = null; Exception ex = null; try { clazz = Class.forName(getClassName()); } catch (Exception e) { } if( clazz==null ) { try { ClassLoader cl= Thread.currentThread().getContextClassLoader(); if ( cl != null) clazz= cl.loadClass(getClassName()); } catch (Exception e) { ex=e; } } if( clazz==null) { throw new MBeanException (ex, "Cannot load ModelMBean class " + getClassName()); } try { // Stupid - this will set the default minfo first.... mbean = (BaseModelMBean) clazz.newInstance(); } catch (RuntimeOperationsException e) { throw e; } catch (Exception e) { throw new MBeanException (e, "Cannot instantiate ModelMBean of class " + getClassName()); } } mbean.setManagedBean(this); // Set the managed resource (if any) try { if (instance != null) mbean.setManagedResource(instance, "ObjectReference"); } catch (InstanceNotFoundException e) { throw e; } return (mbean); } /** * Create and return a ModelMBeanInfo object that * describes this entire managed bean. */ MBeanInfo getMBeanInfo() { // Return our cached information (if any) if (info != null) return (info); // Create subordinate information descriptors as required AttributeInfo attrs[] = getAttributes(); MBeanAttributeInfo attributes[] = new MBeanAttributeInfo[attrs.length]; for (int i = 0; i < attrs.length; i++) attributes[i] = attrs[i].createAttributeInfo(); OperationInfo opers[] = getOperations(); MBeanOperationInfo operations[] = new MBeanOperationInfo[opers.length]; for (int i = 0; i < opers.length; i++) operations[i] = opers[i].createOperationInfo(); // ConstructorInfo consts[] = getConstructors(); // ModelMBeanConstructorInfo constructors[] = // new ModelMBeanConstructorInfo[consts.length]; // for (int i = 0; i < consts.length; i++) // constructors[i] = consts[i].createConstructorInfo(); NotificationInfo notifs[] = getNotifications(); MBeanNotificationInfo notifications[] = new MBeanNotificationInfo[notifs.length]; for (int i = 0; i < notifs.length; i++) notifications[i] = notifs[i].createNotificationInfo(); // Construct and return a new ModelMBeanInfo object info = new MBeanInfo(getClassName(), getDescription(), attributes, new MBeanConstructorInfo[] {}, operations, notifications); // try { // Descriptor descriptor = info.getMBeanDescriptor(); // Iterator fields = getFields().iterator(); // while (fields.hasNext()) { // FieldInfo field = (FieldInfo) fields.next(); // descriptor.setField(field.getName(), field.getValue()); // } // info.setMBeanDescriptor(descriptor); // } catch (MBeanException e) { // ; // } return (info); } /** * Return a string representation of this managed bean. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ManagedBean["); sb.append("name="); sb.append(name); sb.append(", className="); sb.append(className); sb.append(", description="); sb.append(description); if (group != null) { sb.append(", group="); sb.append(group); } sb.append(", type="); sb.append(type); sb.append("]"); return (sb.toString()); } Method getGetter(String aname, BaseModelMBean mbean, Object resource) throws AttributeNotFoundException, ReflectionException { Method m = null; AttributeInfo attrInfo = attributes.get(aname); // Look up the actual operation to be used if (attrInfo == null) throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource); String getMethod = attrInfo.getGetMethod(); if (getMethod == null) throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name"); Object object = null; NoSuchMethodException exception = null; try { object = mbean; m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG); } catch (NoSuchMethodException e) { exception = e; } if( m== null && resource != null ) { try { object = resource; m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG); exception=null; } catch (NoSuchMethodException e) { exception = e; } } if( exception != null ) throw new ReflectionException(exception, "Cannot find getter method " + getMethod); return m; } public Method getSetter(String aname, BaseModelMBean bean, Object resource) throws AttributeNotFoundException, ReflectionException { Method m = null; AttributeInfo attrInfo = attributes.get(aname); if (attrInfo == null) throw new AttributeNotFoundException(" Cannot find attribute " + aname); // Look up the actual operation to be used String setMethod = attrInfo.getSetMethod(); if (setMethod == null) throw new AttributeNotFoundException("Cannot find attribute " + aname + " set method name"); String argType=attrInfo.getType(); Class signature[] = new Class[] { BaseModelMBean.getAttributeClass( argType ) }; Object object = null; NoSuchMethodException exception = null; try { object = bean; m = object.getClass().getMethod(setMethod, signature); } catch (NoSuchMethodException e) { exception = e; } if( m== null && resource != null ) { try { object = resource; m = object.getClass().getMethod(setMethod, signature); exception=null; } catch (NoSuchMethodException e) { exception = e; } } if( exception != null ) throw new ReflectionException(exception, "Cannot find setter method " + setMethod + " " + resource); return m; } public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource) throws MBeanException, ReflectionException { Method method = null; if (params == null) params = new Object[0]; if (signature == null) signature = new String[0]; if (params.length != signature.length) throw new RuntimeOperationsException( new IllegalArgumentException( "Inconsistent arguments and signature"), "Inconsistent arguments and signature"); // Acquire the ModelMBeanOperationInfo information for // the requested operation OperationInfo opInfo = operations.get(createOperationKey(aname, signature)); if (opInfo == null) throw new MBeanException(new ServiceNotFoundException( "Cannot find operation " + aname), "Cannot find operation " + aname); // Prepare the signature required by Java reflection APIs // FIXME - should we use the signature from opInfo? Class types[] = new Class[signature.length]; for (int i = 0; i < signature.length; i++) { types[i] = BaseModelMBean.getAttributeClass(signature[i]); } // Locate the method to be invoked, either in this MBean itself // or in the corresponding managed resource // FIXME - Accessible methods in superinterfaces? Object object = null; Exception exception = null; try { object = bean; method = object.getClass().getMethod(aname, types); } catch (NoSuchMethodException e) { exception = e; } try { if ((method == null) && (resource != null)) { object = resource; method = object.getClass().getMethod(aname, types); } } catch (NoSuchMethodException e) { exception = e; } if (method == null) { throw new ReflectionException(exception, "Cannot find method " + aname + " with this signature"); } return method; } private String createOperationKey(OperationInfo operation) { StringBuilder key = new StringBuilder(operation.getName()); key.append('('); for (ParameterInfo parameterInfo: operation.getSignature()) { key.append(parameterInfo.getType()); // Note: A trailing ',' does not matter in this case key.append(','); } key.append(')'); return key.toString(); } private String createOperationKey(String methodName, String[] parameterTypes) { StringBuilder key = new StringBuilder(methodName); key.append('('); for (String parameter: parameterTypes) { key.append(parameter); // Note: A trailing ',' does not matter in this case key.append(','); } key.append(')'); return key.toString(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/RegistryMBean.java0000644000175100017510000001163012271452077025355 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.util.List; import javax.management.ObjectName; /** * Interface for modeler MBeans. * * This is the main entry point into modeler. It provides methods to create * and manipulate model mbeans and simplify their use. * * Starting with version 1.1, this is no longer a singleton and the static * methods are strongly deprecated. In a container environment we can expect * different applications to use different registries. * * @author Craig R. McClanahan * @author Costin Manolache * * @since 1.1 */ public interface RegistryMBean { /** * Load an extended mlet file. The source can be an URL, File or * InputStream. * * All mbeans will be instantiated, registered and the attributes will be * set. The result is a list of ObjectNames. * * @param source InputStream or URL of the file * @param cl ClassLoader to be used to load the mbeans, or null to use the * default JMX mechanism ( i.e. all registered loaders ) * @return List of ObjectName for the loaded mbeans * @throws Exception * * @since 1.1 */ public List loadMBeans( Object source, ClassLoader cl ) throws Exception; /** Invoke an operation on a set of mbeans. * * @param mbeans List of ObjectNames * @param operation Operation to perform. Typically "init" "start" "stop" or "destroy" * @param failFirst Behavior in case of exceptions - if false we'll ignore * errors * @throws Exception */ public void invoke( List mbeans, String operation, boolean failFirst ) throws Exception; /** Register a bean by creating a modeler mbean and adding it to the * MBeanServer. * * If metadata is not loaded, we'll look up and read a file named * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package * or parent. * * If the bean is an instance of DynamicMBean. it's metadata will be converted * to a model mbean and we'll wrap it - so modeler services will be supported * * If the metadata is still not found, introspection will be used to extract * it automatically. * * If an mbean is already registered under this name, it'll be first * unregistered. * * If the component implements MBeanRegistration, the methods will be called. * If the method has a method "setRegistry" that takes a RegistryMBean as * parameter, it'll be called with the current registry. * * * @param bean Object to be registered * @param oname Name used for registration * @param type The type of the mbean, as declared in mbeans-descriptors. If * null, the name of the class will be used. This can be used as a hint or * by subclasses. * * @since 1.1 */ public void registerComponent(Object bean, String oname, String type) throws Exception; /** Unregister a component. We'll first check if it is registered, * and mask all errors. This is mostly a helper. * * @param oname * * @since 1.1 */ public void unregisterComponent( String oname ); /** Return an int ID for faster access. Will be used for notifications * and for other operations we want to optimize. * * @param domain Namespace * @param name Type of the notification * @return An unique id for the domain:name combination * @since 1.1 */ public int getId( String domain, String name); /** Reset all metadata cached by this registry. Should be called * to support reloading. Existing mbeans will not be affected or modified. * * It will be called automatically if the Registry is unregistered. * @since 1.1 */ public void stop(); /** Load descriptors. The source can be a File, URL pointing to an * mbeans-descriptors.xml. * * Also ( experimental for now ) a ClassLoader - in which case META-INF/ will * be used. * * @param source */ public void loadMetadata(Object source ) throws Exception; } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/ConstructorInfo.java0000644000175100017510000000343712271452077026011 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import javax.management.MBeanConstructorInfo; /** *

    Internal configuration information for a Constructor * descriptor.

    * * @author Craig R. McClanahan */ public class ConstructorInfo extends OperationInfo { static final long serialVersionUID = -5735336213417238238L; // ------------------------------------------------------------- Properties public ConstructorInfo() { } // --------------------------------------------------------- Public Methods /** * Create and return a ModelMBeanConstructorInfo object that * corresponds to the attribute described by this instance. */ public MBeanConstructorInfo createConstructorInfo() { // Return our cached information (if any) if (info == null) { info = new MBeanConstructorInfo(getName(), getDescription(), getMBeanParameterInfo()); } return (MBeanConstructorInfo)info; } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/ParameterInfo.java0000644000175100017510000000336012271452077025377 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import javax.management.MBeanParameterInfo; /** *

    Internal configuration information for a Parameter * descriptor.

    * * @author Craig R. McClanahan */ public class ParameterInfo extends FeatureInfo { static final long serialVersionUID = 2222796006787664020L; // ----------------------------------------------------------- Constructors /** * Standard zero-arguments constructor. */ public ParameterInfo() { super(); } /** * Create and return a MBeanParameterInfo object that * corresponds to the parameter described by this instance. */ public MBeanParameterInfo createParameterInfo() { // Return our cached information (if any) if (info == null) { info = new MBeanParameterInfo (getName(), getType(), getDescription()); } return (MBeanParameterInfo)info; } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java0000644000175100017510000000601312271452077027415 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.util.HashSet; import javax.management.Notification; import javax.management.NotificationFilter; /** * Special NotificationFilter that allows modeler to optimize its notifications. * * This class is immutable - after you construct it it'll filter based on * a fixed set of notification names. * * The JMX specification requires the filters to be called before the * notifications are sent. We can call this filter well in advance, when * the listener is added. Based on the result we can maintain separate * channels for each notification - and reduce the overhead. * * @author Costin Manolache */ public class FixedNotificationFilter implements NotificationFilter { private static final long serialVersionUID = 1L; /** * The set of attribute names that are accepted by this filter. If this * list is empty, all attribute names are accepted. */ private HashSet names = new HashSet(); String namesA[]=null; /** * Construct a new filter that accepts only the specified notification * names. * * @param names Names of the notification types */ public FixedNotificationFilter(String names[]) { super(); } /** * Return the set of names that are accepted by this filter. If this * filter accepts all attribute names, a zero length array will be * returned. */ public String[] getNames() { synchronized (names) { return names.toArray(new String[names.size()]); } } /** *

    Test whether notification enabled for this event. * Return true if:

    *
      *
    • Either the set of accepted names is empty (implying that all * attribute names are of interest) or the set of accepted names * includes the name of the attribute in this notification
    • *
    */ @Override public boolean isNotificationEnabled(Notification notification) { if (notification == null) return (false); synchronized (names) { if (names.size() < 1) return (true); else return (names.contains(notification.getType())); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/0000755000175100017510000000000012301126366023437 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java0000644000175100017510000000356512271452077027613 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler.modules; import java.util.List; import javax.management.ObjectName; /** * This mbean will load an extended mlet file ( similar in syntax with jboss ). * It'll keep track of all attribute changes and update the file when attributes * change. * @deprecated Unused: Will be removed in Tomcat 8.0.x */ @Deprecated public interface MbeansSourceMBean { /** Set the source to be used to load the mbeans * * @param source File or URL */ public void setSource( Object source ); public Object getSource(); /** Return the list of loaded mbeans names * * @return List of ObjectName */ public List getMBeans(); /** Load the mbeans from the source. Called automatically on init() * * @throws Exception */ public void load() throws Exception; /** Call the init method on all mbeans. Will call load if not done already * * @throws Exception */ public void init() throws Exception; /** Save the file. */ public void save(); } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/MbeansSource.java0000644000175100017510000003243112271452077026702 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler.modules; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.management.Attribute; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.loading.MLet; import javax.xml.transform.TransformerException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.DomUtil; import org.apache.tomcat.util.modeler.AttributeInfo; import org.apache.tomcat.util.modeler.BaseModelMBean; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; import org.w3c.dom.Document; import org.w3c.dom.Node; /** This will create mbeans based on a config file. * The format is an extended version of MLET. * * Classloading. We don't support any explicit classloader tag. * A ClassLoader is just an mbean ( it can be the standard MLetMBean or * a custom one ). * * XXX add a special attribute to reference the loader mbean, * XXX figure out how to deal with private loaders * * @deprecated Unused: Will be removed in Tomcat 8.0.x */ @Deprecated public class MbeansSource extends ModelerSource implements MbeansSourceMBean { private static final Log log = LogFactory.getLog(MbeansSource.class); Registry registry; String type; // true if we are during the original loading boolean loading=true; List mbeans = new ArrayList(); static boolean loaderLoaded=false; private Document document; private HashMap object2Node = new HashMap(); long lastUpdate; long updateInterval=10000; // 10s public void setRegistry(Registry reg) { this.registry=reg; } public void setLocation( String loc ) { this.location=loc; } /** Used if a single component is loaded * * @param type */ public void setType( String type ) { this.type=type; } @Override public void setSource( Object source ) { this.source=source; } @Override public Object getSource() { return source; } public String getLocation() { return location; } /** Return the list of mbeans created by this source. * It can be used to implement runtime services. */ @Override public List getMBeans() { return mbeans; } @Override public List loadDescriptors(Registry registry, String type, Object source) throws Exception { setRegistry(registry); setType(type); setSource(source); execute(); return mbeans; } public void start() throws Exception { registry.invoke(mbeans, "start", false); } public void stop() throws Exception { registry.invoke(mbeans, "stop", false); } @Override public void init() throws Exception { if( mbeans==null) execute(); if( registry==null ) registry=Registry.getRegistry(null, null); registry.invoke(mbeans, "init", false); } public void destroy() throws Exception { registry.invoke(mbeans, "destroy", false); } @Override public void load() throws Exception { execute(); // backward compat } public void execute() throws Exception { if( registry==null ) registry=Registry.getRegistry(null, null); try { InputStream stream=getInputStream(); long t1=System.currentTimeMillis(); document = DomUtil.readXml(stream); // We don't care what the root node is. Node descriptorsN=document.getDocumentElement(); if( descriptorsN == null ) { log.error("No descriptors found"); return; } Node firstMbeanN=DomUtil.getChild(descriptorsN, null); if( firstMbeanN==null ) { // maybe we have a single mlet if( log.isDebugEnabled() ) log.debug("No child " + descriptorsN); firstMbeanN=descriptorsN; } MBeanServer server = Registry.getRegistry(null, null).getMBeanServer(); // XXX Not very clean... Just a workaround if( ! loaderLoaded ) { // Register a loader that will be find ant classes. ObjectName defaultLoader= new ObjectName("modeler", "loader", "modeler"); MLet mlet=new MLet( new URL[0], this.getClass().getClassLoader()); server.registerMBean(mlet, defaultLoader); loaderLoaded=true; } // Process nodes for (Node mbeanN = firstMbeanN; mbeanN != null; mbeanN= DomUtil.getNext(mbeanN, null, Node.ELEMENT_NODE)) { String nodeName=mbeanN.getNodeName(); // mbean is the "official" name if( "mbean".equals(nodeName) || "MLET".equals(nodeName) ) { String code=DomUtil.getAttribute( mbeanN, "code" ); String objectName=DomUtil.getAttribute( mbeanN, "objectName" ); if( objectName==null ) { objectName=DomUtil.getAttribute( mbeanN, "name" ); } if( log.isDebugEnabled()) log.debug( "Processing mbean objectName=" + objectName + " code=" + code); // args can be grouped in constructor or direct childs Node constructorN=DomUtil.getChild(mbeanN, "constructor"); if( constructorN == null ) constructorN=mbeanN; processArg(constructorN); try { ObjectName oname=new ObjectName(objectName); if( ! server.isRegistered( oname )) { // We wrap everything in a model mbean. // XXX need to support "StandardMBeanDescriptorsSource" String modelMBean=BaseModelMBean.class.getName(); server.createMBean(modelMBean, oname, new Object[] { code, this}, new String[] { String.class.getName(), ModelerSource.class.getName() } ); mbeans.add(oname); } object2Node.put( oname, mbeanN ); // XXX Arguments, loader !!! } catch( Exception ex ) { log.error( "Error creating mbean " + objectName, ex); } Node firstAttN=DomUtil.getChild(mbeanN, "attribute"); for (Node descN = firstAttN; descN != null; descN = DomUtil.getNext( descN )) { processAttribute(server, descN, objectName); } } else if("jmx-operation".equals(nodeName) ) { String name=DomUtil.getAttribute(mbeanN, "objectName"); if( name==null ) name=DomUtil.getAttribute(mbeanN, "name"); String operation=DomUtil.getAttribute(mbeanN, "operation"); if( log.isDebugEnabled()) log.debug( "Processing invoke objectName=" + name + " code=" + operation); try { ObjectName oname=new ObjectName(name); processArg( mbeanN ); server.invoke( oname, operation, null, null); } catch (Exception e) { log.error( "Error in invoke " + name + " " + operation); } } ManagedBean managed=new ManagedBean(); DomUtil.setAttributes(managed, mbeanN); Node firstN; // process attribute info firstN=DomUtil.getChild( mbeanN, "attribute"); for (Node descN = firstN; descN != null; descN = DomUtil.getNext( descN )) { AttributeInfo ci=new AttributeInfo(); DomUtil.setAttributes(ci, descN); managed.addAttribute( ci ); } } long t2=System.currentTimeMillis(); log.info( "Reading mbeans " + (t2-t1)); loading=false; } catch( Exception ex ) { log.error( "Error reading mbeans ", ex); } } @Override public void updateField( ObjectName oname, String name, Object value ) { if( loading ) return; // nothing by default //log.info( "XXX UpdateField " + oname + " " + name + " " + value); Node n = object2Node.get(oname); if( n == null ) { log.info( "Node not found " + oname ); return; } Node attNode=DomUtil.findChildWithAtt(n, "attribute", "name", name); if( attNode == null ) { // found no existing attribute with this name attNode=n.getOwnerDocument().createElement("attribute"); DomUtil.setAttribute(attNode, "name", name); n.appendChild(attNode); } String oldValue=DomUtil.getAttribute(attNode, "value"); if( oldValue != null ) { // we'll convert all values to text content DomUtil.removeAttribute( attNode, "value"); } DomUtil.setText(attNode, value.toString()); //store(); } /** Store the mbeans. * XXX add a background thread to store it periodically */ @Override public void save() { // XXX customize no often than ( based on standard descriptor ), etc. // It doesn't work very well if we call this on each set att - // the triger will work for the first att, but all others will be delayed long time=System.currentTimeMillis(); if( location!=null && time - lastUpdate > updateInterval ) { lastUpdate=time; try { FileOutputStream fos=new FileOutputStream(location); DomUtil.writeXml(document, fos); } catch (TransformerException e) { log.error( "Error writing"); } catch (FileNotFoundException e) { log.error( "Error writing" ,e ); } } } private void processAttribute(MBeanServer server, Node descN, String objectName ) { String attName=DomUtil.getAttribute(descN, "name"); String value=DomUtil.getAttribute(descN, "value"); String type=null; // DomUtil.getAttribute(descN, "type"); if( value==null ) { // The value may be specified as CDATA value=DomUtil.getContent(descN); } try { if( log.isDebugEnabled()) log.debug("Set attribute " + objectName + " " + attName + " " + value); ObjectName oname=new ObjectName(objectName); // find the type type=registry.getType( oname, attName ); if( type==null ) { log.info("Can't find attribute " + objectName + " " + attName ); } else { Object valueO=registry.convertValue( type, value); server.setAttribute(oname, new Attribute(attName, valueO)); } } catch( Exception ex) { log.error("Error processing attribute " + objectName + " " + attName + " " + value, ex); } } private void processArg(Node mbeanN) { Node firstArgN=DomUtil.getChild(mbeanN, "arg" ); // process all args for (Node argN = firstArgN; argN != null; argN = DomUtil.getNext( argN )) { DomUtil.getAttribute(argN, "type"); String value=DomUtil.getAttribute(argN, "value"); if( value==null ) { // The value may be specified as CDATA value=DomUtil.getContent(argN); } } } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsSerSource.java0000644000175100017510000000663312271452077031603 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler.modules; import java.io.InputStream; import java.io.ObjectInputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.management.ObjectName; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; public class MbeansDescriptorsSerSource extends ModelerSource { private static final Log log = LogFactory.getLog(MbeansDescriptorsSerSource.class); Registry registry; String type; List mbeans=new ArrayList(); public void setRegistry(Registry reg) { this.registry=reg; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated public void setLocation( String loc ) { this.location=loc; } /** Used if a single component is loaded * * @param type */ public void setType( String type ) { this.type=type; } public void setSource( Object source ) { this.source=source; } @Override public List loadDescriptors( Registry registry, String type, Object source) throws Exception { setRegistry(registry); setType(type); setSource(source); execute(); return mbeans; } public void execute() throws Exception { if( registry==null ) registry=Registry.getRegistry(null, null); long t1=System.currentTimeMillis(); try { InputStream stream=null; if( source instanceof URL ) { stream=((URL)source).openStream(); } if( source instanceof InputStream ) { stream=(InputStream)source; } if( stream==null ) { throw new Exception( "Can't process "+ source); } ObjectInputStream ois=new ObjectInputStream(stream); Thread.currentThread().setContextClassLoader(ManagedBean.class.getClassLoader()); Object obj=ois.readObject(); //log.info("Reading " + obj); ManagedBean beans[]=(ManagedBean[])obj; // after all are read without error for( int i=0; i org.apache.commons.modeler.modules

    Implementation classes - should not be used directly. The API is not stable but eventually the code will be refactored as a collection of mbeans that will be useable ( more or less ) indepedently.

    The MbeanDescriptors* classes are used to extract metadata from different sources. They are result of few stages of refactoring - now they look very similar with ant tasks and are close to normal mbeans, with an execute() method. DOM, SER, Introspection and Dynamic mbean will load metadata from the corresponding sources.

    MbeansSource will load an extended MLET file, similar with jboss. It is not completely implemented - only modeler mbeans and dynamic mbeans are loaded. The important characteristic is that all declared mbeans will be registered in the mbean server as model mbeans. For regular java classes, the description will be used to construct the model mbean. DynamicMbeans metadata will be converted to model mbean and the model mbean wrapper will be loaded.

    The goal of MbeansSource is to implement a simple persistence mechanism. Since all components are model mbeans, we can detect all changes. The source will be loaded as DOM and modifications will be made to the tree. The save() method will save the DOM tree - preserving all comments and having only the changes that are needed.

    There are few remaining issues. First, we need to use the persistence metadata to avoid saving transient fields ( we save an attribute when we detect a change - but we don't know if this attribute should be saved ). The solution is to use the persistence fields in the spec - with some reasonable defaults or patterns for introspection or backward compat.

    Another problem is implementing adding and removing components. In catalina, a factory is used to create the components, and save will operate on all mbeans. For creation we need to also use a factory - using the "Type" as a parameter. This will also work very well with Ant1.6 where we can use the component factory to do a "natural" mapping ( i.e. mbeans can be treated as tasks, with attributes as task attributes ). The second part can be solve by either using a parameter on the factory method ( saveTo ? ), or by having a single mbeans source per domain.

    tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java0000644000175100017510000000630712271452077027067 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler.modules; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.List; import javax.management.ObjectName; import org.apache.tomcat.util.modeler.Registry; /** Source for descriptor data. More sources can be added. * */ public abstract class ModelerSource { protected Object source; @Deprecated protected String location; /** Load data, returns a list of items. * * @param registry * @param location * @param type * @param source Introspected object or some other source * @throws Exception * * @deprecated Location parameter is unused. Will be removed in Tomcat * 8.0.x */ @Deprecated public List loadDescriptors( Registry registry, String location, String type, Object source) throws Exception { return loadDescriptors(registry, type, source); } /** Callback from the BaseMBean to notify that an attribute has changed. * Can be used to implement persistence. * * @param oname * @param name * @param value * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public void updateField( ObjectName oname, String name, Object value ) { // nothing by default } /** * * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public void store() { // nothing } /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected InputStream getInputStream() throws IOException { if( source instanceof URL ) { URL url=(URL)source; location=url.toString(); return url.openStream(); } else if( source instanceof File ) { location=((File)source).getAbsolutePath(); return new FileInputStream((File)source); } else if( source instanceof String) { location=(String)source; return new FileInputStream((String)source); } else if( source instanceof InputStream ) { return (InputStream)source; } return null; } public abstract List loadDescriptors(Registry registry, String type, Object source) throws Exception; } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java0000644000175100017510000002176512271452077032623 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler.modules; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.management.ObjectName; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; public class MbeansDescriptorsDigesterSource extends ModelerSource { private static final Log log = LogFactory.getLog(MbeansDescriptorsDigesterSource.class); Registry registry; String type; List mbeans = new ArrayList(); protected static volatile Digester digester = null; protected static Digester createDigester() { Digester digester = new Digester(); digester.setNamespaceAware(false); digester.setValidating(false); URL url = Registry.getRegistry(null, null).getClass().getResource ("/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd"); digester.register ("-//Apache Software Foundation//DTD Model MBeans Configuration File", url.toString()); // Configure the parsing rules digester.addObjectCreate ("mbeans-descriptors/mbean", "org.apache.tomcat.util.modeler.ManagedBean"); digester.addSetProperties ("mbeans-descriptors/mbean"); digester.addSetNext ("mbeans-descriptors/mbean", "add", "java.lang.Object"); digester.addObjectCreate ("mbeans-descriptors/mbean/attribute", "org.apache.tomcat.util.modeler.AttributeInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/attribute"); digester.addSetNext ("mbeans-descriptors/mbean/attribute", "addAttribute", "org.apache.tomcat.util.modeler.AttributeInfo"); /*digester.addObjectCreate ("mbeans-descriptors/mbean/attribute/descriptor/field", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/attribute/descriptor/field"); digester.addSetNext ("mbeans-descriptors/mbean/attribute/descriptor/field", "addField", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addObjectCreate ("mbeans-descriptors/mbean/constructor", "org.apache.tomcat.util.modeler.ConstructorInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/constructor"); digester.addSetNext ("mbeans-descriptors/mbean/constructor", "addConstructor", "org.apache.tomcat.util.modeler.ConstructorInfo"); digester.addObjectCreate ("mbeans-descriptors/mbean/constructor/descriptor/field", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/constructor/descriptor/field"); digester.addSetNext ("mbeans-descriptors/mbean/constructor/descriptor/field", "addField", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addObjectCreate ("mbeans-descriptors/mbean/constructor/parameter", "org.apache.tomcat.util.modeler.ParameterInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/constructor/parameter"); digester.addSetNext ("mbeans-descriptors/mbean/constructor/parameter", "addParameter", "org.apache.tomcat.util.modeler.ParameterInfo"); digester.addObjectCreate ("mbeans-descriptors/mbean/descriptor/field", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/descriptor/field"); digester.addSetNext ("mbeans-descriptors/mbean/descriptor/field", "addField", "org.apache.tomcat.util.modeler.FieldInfo"); */ digester.addObjectCreate ("mbeans-descriptors/mbean/notification", "org.apache.tomcat.util.modeler.NotificationInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/notification"); digester.addSetNext ("mbeans-descriptors/mbean/notification", "addNotification", "org.apache.tomcat.util.modeler.NotificationInfo"); digester.addObjectCreate ("mbeans-descriptors/mbean/notification/descriptor/field", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/notification/descriptor/field"); digester.addSetNext ("mbeans-descriptors/mbean/notification/descriptor/field", "addField", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addCallMethod ("mbeans-descriptors/mbean/notification/notification-type", "addNotifType", 0); digester.addObjectCreate ("mbeans-descriptors/mbean/operation", "org.apache.tomcat.util.modeler.OperationInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/operation"); digester.addSetNext ("mbeans-descriptors/mbean/operation", "addOperation", "org.apache.tomcat.util.modeler.OperationInfo"); digester.addObjectCreate ("mbeans-descriptors/mbean/operation/descriptor/field", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/operation/descriptor/field"); digester.addSetNext ("mbeans-descriptors/mbean/operation/descriptor/field", "addField", "org.apache.tomcat.util.modeler.FieldInfo"); digester.addObjectCreate ("mbeans-descriptors/mbean/operation/parameter", "org.apache.tomcat.util.modeler.ParameterInfo"); digester.addSetProperties ("mbeans-descriptors/mbean/operation/parameter"); digester.addSetNext ("mbeans-descriptors/mbean/operation/parameter", "addParameter", "org.apache.tomcat.util.modeler.ParameterInfo"); return digester; } public void setRegistry(Registry reg) { this.registry=reg; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated public void setLocation( String loc ) { this.location=loc; } /** Used if a single component is loaded * * @param type */ public void setType( String type ) { this.type=type; } public void setSource( Object source ) { this.source=source; } @Override public List loadDescriptors( Registry registry, String type, Object source) throws Exception { setRegistry(registry); setType(type); setSource(source); execute(); return mbeans; } public void execute() throws Exception { if (registry == null) { registry = Registry.getRegistry(null, null); } InputStream stream = (InputStream) source; if (digester == null) { digester = createDigester(); } ArrayList loadedMbeans = new ArrayList(); synchronized (digester) { // Process the input file to configure our registry try { // Push our registry object onto the stack digester.push(loadedMbeans); digester.parse(stream); } catch (Exception e) { log.error("Error digesting Registry data", e); throw e; } finally { digester.reset(); } } Iterator iter = loadedMbeans.iterator(); while (iter.hasNext()) { registry.addManagedBean(iter.next()); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java0000644000175100017510000002666612271452077031501 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler.modules; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.management.ObjectName; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.DomUtil; import org.apache.tomcat.util.modeler.AttributeInfo; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.NotificationInfo; import org.apache.tomcat.util.modeler.OperationInfo; import org.apache.tomcat.util.modeler.ParameterInfo; import org.apache.tomcat.util.modeler.Registry; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * @deprecated Unused: Will be removed in Tomcat 8.0.x */ @Deprecated public class MbeansDescriptorsDOMSource extends ModelerSource { private static final Log log = LogFactory.getLog(MbeansDescriptorsDOMSource.class); Registry registry; String location; String type; Object source; List mbeans=new ArrayList(); public void setRegistry(Registry reg) { this.registry=reg; } public void setLocation( String loc ) { this.location=loc; } /** Used if a single component is loaded * * @param type */ public void setType( String type ) { this.type=type; } public void setSource( Object source ) { this.source=source; } @Override public List loadDescriptors( Registry registry, String type, Object source) throws Exception { setRegistry(registry); setType(type); setSource(source); execute(); return mbeans; } public void execute() throws Exception { if( registry==null ) registry=Registry.getRegistry(null, null); try { InputStream stream=(InputStream)source; long t1=System.currentTimeMillis(); Document doc=DomUtil.readXml(stream); // Ignore for now the name of the root element Node descriptorsN=doc.getDocumentElement(); //Node descriptorsN=DomUtil.getChild(doc, "mbeans-descriptors"); if( descriptorsN == null ) { log.error("No descriptors found"); return; } Node firstMbeanN=null; if( "mbean".equals( descriptorsN.getNodeName() ) ) { firstMbeanN=descriptorsN; } else { firstMbeanN=DomUtil.getChild(descriptorsN, "mbean"); } if( firstMbeanN==null ) { log.error(" No mbean tags "); return; } // Process each element for (Node mbeanN = firstMbeanN; mbeanN != null; mbeanN= DomUtil.getNext(mbeanN)) { // Create a new managed bean info ManagedBean managed=new ManagedBean(); DomUtil.setAttributes(managed, mbeanN); Node firstN; // Process descriptor subnode /*Node mbeanDescriptorN = DomUtil.getChild(mbeanN, "descriptor"); if (mbeanDescriptorN != null) { Node firstFieldN = DomUtil.getChild(mbeanDescriptorN, "field"); for (Node fieldN = firstFieldN; fieldN != null; fieldN = DomUtil.getNext(fieldN)) { FieldInfo fi = new FieldInfo(); DomUtil.setAttributes(fi, fieldN); managed.addField(fi); } }*/ // process attribute nodes firstN=DomUtil.getChild( mbeanN, "attribute"); for (Node descN = firstN; descN != null; descN = DomUtil.getNext( descN )) { // Create new attribute info AttributeInfo ai=new AttributeInfo(); DomUtil.setAttributes(ai, descN); // Process descriptor subnode /*Node descriptorN = DomUtil.getChild(descN, "descriptor"); if (descriptorN != null) { Node firstFieldN = DomUtil.getChild(descriptorN, "field"); for (Node fieldN = firstFieldN; fieldN != null; fieldN = DomUtil.getNext(fieldN)) { FieldInfo fi = new FieldInfo(); DomUtil.setAttributes(fi, fieldN); ai.addField(fi); } } */ // Add this info to our managed bean info managed.addAttribute( ai ); if (log.isTraceEnabled()) { log.trace("Create attribute " + ai); } } // process constructor nodes /* firstN=DomUtil.getChild( mbeanN, "constructor"); for (Node descN = firstN; descN != null; descN = DomUtil.getNext( descN )) { // Create new constructor info ConstructorInfo ci=new ConstructorInfo(); DomUtil.setAttributes(ci, descN); // Process descriptor subnode Node firstDescriptorN = DomUtil.getChild(descN, "descriptor"); if (firstDescriptorN != null) { Node firstFieldN = DomUtil.getChild(firstDescriptorN, "field"); for (Node fieldN = firstFieldN; fieldN != null; fieldN = DomUtil.getNext(fieldN)) { FieldInfo fi = new FieldInfo(); DomUtil.setAttributes(fi, fieldN); ci.addField(fi); } } // Process parameter subnodes Node firstParamN=DomUtil.getChild( descN, "parameter"); for (Node paramN = firstParamN; paramN != null; paramN = DomUtil.getNext(paramN)) { ParameterInfo pi=new ParameterInfo(); DomUtil.setAttributes(pi, paramN); ci.addParameter( pi ); } // Add this info to our managed bean info managed.addConstructor( ci ); if (log.isTraceEnabled()) { log.trace("Create constructor " + ci); } }*/ // process notification nodes firstN=DomUtil.getChild( mbeanN, "notification"); for (Node descN = firstN; descN != null; descN = DomUtil.getNext( descN )) { // Create new notification info NotificationInfo ni=new NotificationInfo(); DomUtil.setAttributes(ni, descN); // Process descriptor subnode /*Node firstDescriptorN = DomUtil.getChild(descN, "descriptor"); if (firstDescriptorN != null) { Node firstFieldN = DomUtil.getChild(firstDescriptorN, "field"); for (Node fieldN = firstFieldN; fieldN != null; fieldN = DomUtil.getNext(fieldN)) { FieldInfo fi = new FieldInfo(); DomUtil.setAttributes(fi, fieldN); ni.addField(fi); } }*/ // Process notification-type subnodes Node firstParamN=DomUtil.getChild( descN, "notification-type"); for (Node paramN = firstParamN; paramN != null; paramN = DomUtil.getNext(paramN)) { ni.addNotifType( DomUtil.getContent(paramN) ); } // Add this info to our managed bean info managed.addNotification( ni ); if (log.isTraceEnabled()) { log.trace("Created notification " + ni); } } // process operation nodes firstN=DomUtil.getChild( mbeanN, "operation"); for (Node descN = firstN; descN != null; descN = DomUtil.getNext( descN )) { // Create new operation info OperationInfo oi=new OperationInfo(); DomUtil.setAttributes(oi, descN); // Process descriptor subnode /*Node firstDescriptorN = DomUtil.getChild(descN, "descriptor"); if (firstDescriptorN != null) { Node firstFieldN = DomUtil.getChild(firstDescriptorN, "field"); for (Node fieldN = firstFieldN; fieldN != null; fieldN = DomUtil.getNext(fieldN)) { FieldInfo fi = new FieldInfo(); DomUtil.setAttributes(fi, fieldN); oi.addField(fi); } }*/ // Process parameter subnodes Node firstParamN=DomUtil.getChild( descN, "parameter"); for (Node paramN = firstParamN; paramN != null; paramN = DomUtil.getNext(paramN)) { ParameterInfo pi=new ParameterInfo(); DomUtil.setAttributes(pi, paramN); if( log.isTraceEnabled()) log.trace("Add param " + pi.getName()); oi.addParameter( pi ); } // Add this info to our managed bean info managed.addOperation( oi ); if( log.isTraceEnabled()) { log.trace("Create operation " + oi); } } // Add the completed managed bean info to the registry registry.addManagedBean(managed); } long t2=System.currentTimeMillis(); log.debug( "Reading descriptors ( dom ) " + (t2-t1)); } catch( Exception ex ) { log.error( "Error reading descriptors ", ex); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java0000644000175100017510000003524712271452077033715 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler.modules; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import javax.management.ObjectName; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.modeler.AttributeInfo; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.OperationInfo; import org.apache.tomcat.util.modeler.ParameterInfo; import org.apache.tomcat.util.modeler.Registry; public class MbeansDescriptorsIntrospectionSource extends ModelerSource { private static final Log log = LogFactory.getLog(MbeansDescriptorsIntrospectionSource.class); Registry registry; String type; List mbeans = new ArrayList(); public void setRegistry(Registry reg) { this.registry=reg; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated public void setLocation( String loc ) { this.location=loc; } /** Used if a single component is loaded * * @param type */ public void setType( String type ) { this.type=type; } public void setSource( Object source ) { this.source=source; } @Override public List loadDescriptors(Registry registry, String type, Object source) throws Exception { setRegistry(registry); setType(type); setSource(source); execute(); return mbeans; } public void execute() throws Exception { if( registry==null ) registry=Registry.getRegistry(null, null); try { ManagedBean managed = createManagedBean(registry, null, (Class)source, type); if( managed==null ) return; managed.setName( type ); registry.addManagedBean(managed); } catch( Exception ex ) { log.error( "Error reading descriptors ", ex); } } // ------------ Implementation for non-declared introspection classes static Hashtable specialMethods = new Hashtable(); static { specialMethods.put( "preDeregister", ""); specialMethods.put( "postDeregister", ""); } private static String strArray[]=new String[0]; private static ObjectName objNameArray[]=new ObjectName[0]; // createMBean == registerClass + registerMBean private static Class[] supportedTypes = new Class[] { Boolean.class, Boolean.TYPE, Byte.class, Byte.TYPE, Character.class, Character.TYPE, Short.class, Short.TYPE, Integer.class, Integer.TYPE, Long.class, Long.TYPE, Float.class, Float.TYPE, Double.class, Double.TYPE, String.class, strArray.getClass(), BigDecimal.class, BigInteger.class, ObjectName.class, objNameArray.getClass(), java.io.File.class, }; /** * Check if this class is one of the supported types. * If the class is supported, returns true. Otherwise, * returns false. * @param ret The class to check * @return boolean True if class is supported */ private boolean supportedType(Class ret) { for (int i = 0; i < supportedTypes.length; i++) { if (ret == supportedTypes[i]) { return true; } } if (isBeanCompatible(ret)) { return true; } return false; } /** * Check if this class conforms to JavaBeans specifications. * If the class is conformant, returns true. * * @param javaType The class to check * @return boolean True if the class is compatible. */ protected boolean isBeanCompatible(Class javaType) { // Must be a non-primitive and non array if (javaType.isArray() || javaType.isPrimitive()) { return false; } // Anything in the java or javax package that // does not have a defined mapping is excluded. if (javaType.getName().startsWith("java.") || javaType.getName().startsWith("javax.")) { return false; } try { javaType.getConstructor(new Class[]{}); } catch (java.lang.NoSuchMethodException e) { return false; } // Make sure superclass is compatible Class superClass = javaType.getSuperclass(); if (superClass != null && superClass != java.lang.Object.class && superClass != java.lang.Exception.class && superClass != java.lang.Throwable.class) { if (!isBeanCompatible(superClass)) { return false; } } return true; } /** * Process the methods and extract 'attributes', methods, etc * * @param realClass The class to process * @param methods The methods to process * @param attMap The attribute map (complete) * @param getAttMap The readable attributes map * @param setAttMap The settable attributes map * @param invokeAttMap The invokable attributes map */ private void initMethods(Class realClass, Method methods[], Hashtable attMap, Hashtable getAttMap, Hashtable setAttMap, Hashtable invokeAttMap) { for (int j = 0; j < methods.length; ++j) { String name=methods[j].getName(); if( Modifier.isStatic(methods[j].getModifiers())) continue; if( ! Modifier.isPublic( methods[j].getModifiers() ) ) { if( log.isDebugEnabled()) log.debug("Not public " + methods[j] ); continue; } if( methods[j].getDeclaringClass() == Object.class ) continue; Class params[] = methods[j].getParameterTypes(); if( name.startsWith( "get" ) && params.length==0) { Class ret = methods[j].getReturnType(); if( ! supportedType( ret ) ) { if( log.isDebugEnabled() ) log.debug("Unsupported type " + methods[j]); continue; } name=unCapitalize( name.substring(3)); getAttMap.put( name, methods[j] ); // just a marker, we don't use the value attMap.put( name, methods[j] ); } else if( name.startsWith( "is" ) && params.length==0) { Class ret = methods[j].getReturnType(); if( Boolean.TYPE != ret ) { if( log.isDebugEnabled() ) log.debug("Unsupported type " + methods[j] + " " + ret ); continue; } name=unCapitalize( name.substring(2)); getAttMap.put( name, methods[j] ); // just a marker, we don't use the value attMap.put( name, methods[j] ); } else if( name.startsWith( "set" ) && params.length==1) { if( ! supportedType( params[0] ) ) { if( log.isDebugEnabled() ) log.debug("Unsupported type " + methods[j] + " " + params[0]); continue; } name=unCapitalize( name.substring(3)); setAttMap.put( name, methods[j] ); attMap.put( name, methods[j] ); } else { if( params.length == 0 ) { if( specialMethods.get( methods[j].getName() ) != null ) continue; invokeAttMap.put( name, methods[j]); } else { boolean supported=true; for( int i=0; i realClass, String type) { ManagedBean mbean= new ManagedBean(); Method methods[]=null; Hashtable attMap = new Hashtable(); // key: attribute val: getter method Hashtable getAttMap = new Hashtable(); // key: attribute val: setter method Hashtable setAttMap = new Hashtable(); // key: operation val: invoke method Hashtable invokeAttMap = new Hashtable(); methods = realClass.getMethods(); initMethods(realClass, methods, attMap, getAttMap, setAttMap, invokeAttMap ); try { Enumeration en = attMap.keys(); while( en.hasMoreElements() ) { String name = en.nextElement(); AttributeInfo ai=new AttributeInfo(); ai.setName( name ); Method gm = getAttMap.get(name); if( gm!=null ) { //ai.setGetMethodObj( gm ); ai.setGetMethod( gm.getName()); Class t=gm.getReturnType(); if( t!=null ) ai.setType( t.getName() ); } Method sm = setAttMap.get(name); if( sm!=null ) { //ai.setSetMethodObj(sm); Class t = sm.getParameterTypes()[0]; if( t!=null ) ai.setType( t.getName()); ai.setSetMethod( sm.getName()); } ai.setDescription("Introspected attribute " + name); if( log.isDebugEnabled()) log.debug("Introspected attribute " + name + " " + gm + " " + sm); if( gm==null ) ai.setReadable(false); if( sm==null ) ai.setWriteable(false); if( sm!=null || gm!=null ) mbean.addAttribute(ai); } en=invokeAttMap.keys(); while( en.hasMoreElements() ) { String name = en.nextElement(); Method m = invokeAttMap.get(name); if( m!=null && name != null ) { OperationInfo op=new OperationInfo(); op.setName(name); op.setReturnType(m.getReturnType().getName()); op.setDescription("Introspected operation " + name); Class parms[] = m.getParameterTypes(); for(int i=0; iInternal configuration information for an Attribute * descriptor.

    * * @author Craig R. McClanahan */ public class AttributeInfo extends FeatureInfo { static final long serialVersionUID = -2511626862303972143L; // ----------------------------------------------------- Instance Variables protected String displayName = null; // Information about the method to use protected String getMethod = null; protected String setMethod = null; protected boolean readable = true; protected boolean writeable = true; protected boolean is = false; // ------------------------------------------------------------- Properties /** * The display name of this attribute. */ public String getDisplayName() { return (this.displayName); } public void setDisplayName(String displayName) { this.displayName = displayName; } /** * The name of the property getter method, if non-standard. */ public String getGetMethod() { if(getMethod == null) getMethod = getMethodName(getName(), true, isIs()); return (this.getMethod); } public void setGetMethod(String getMethod) { this.getMethod = getMethod; } /** * Is this a boolean attribute with an "is" getter? */ public boolean isIs() { return (this.is); } public void setIs(boolean is) { this.is = is; } /** * Is this attribute readable by management applications? */ public boolean isReadable() { return (this.readable); } public void setReadable(boolean readable) { this.readable = readable; } /** * The name of the property setter method, if non-standard. */ public String getSetMethod() { if( setMethod == null ) setMethod = getMethodName(getName(), false, false); return (this.setMethod); } public void setSetMethod(String setMethod) { this.setMethod = setMethod; } /** * Is this attribute writable by management applications? */ public boolean isWriteable() { return (this.writeable); } public void setWriteable(boolean writeable) { this.writeable = writeable; } // --------------------------------------------------------- Public Methods /** * Create and return a ModelMBeanAttributeInfo object that * corresponds to the attribute described by this instance. */ MBeanAttributeInfo createAttributeInfo() { // Return our cached information (if any) if (info == null) { info = new MBeanAttributeInfo(getName(), getType(), getDescription(), isReadable(), isWriteable(), false); } return (MBeanAttributeInfo)info; } // -------------------------------------------------------- Private Methods /** * Create and return the name of a default property getter or setter * method, according to the specified values. * * @param name Name of the property itself * @param getter Do we want a get method (versus a set method)? * @param is If returning a getter, do we want the "is" form? */ private String getMethodName(String name, boolean getter, boolean is) { StringBuilder sb = new StringBuilder(); if (getter) { if (is) sb.append("is"); else sb.append("get"); } else sb.append("set"); sb.append(Character.toUpperCase(name.charAt(0))); sb.append(name.substring(1)); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java0000644000175100017510000001777412271452077030254 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.util.ArrayList; import java.util.Iterator; import javax.management.ListenerNotFoundException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.NotificationBroadcaster; import javax.management.NotificationFilter; import javax.management.NotificationListener; /** *

    Implementation of NotificationBroadcaster for attribute * change notifications. This class is used by BaseModelMBean to * handle notifications of attribute change events to interested listeners. *

    * * @author Craig R. McClanahan * @author Costin Manolache */ public class BaseNotificationBroadcaster implements NotificationBroadcaster { // ----------------------------------------------------------- Constructors // ----------------------------------------------------- Instance Variables /** * The set of registered BaseNotificationBroadcasterEntry * entries. */ protected ArrayList entries = new ArrayList(); // --------------------------------------------------------- Public Methods /** * Add a notification event listener to this MBean. * * @param listener Listener that will receive event notifications * @param filter Filter object used to filter event notifications * actually delivered, or null for no filtering * @param handback Handback object to be sent along with event * notifications * * @exception IllegalArgumentException if the listener parameter is null */ @Override public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { synchronized (entries) { // Optimization to coalesce attribute name filters if (filter instanceof BaseAttributeFilter) { BaseAttributeFilter newFilter = (BaseAttributeFilter) filter; Iterator items = entries.iterator(); while (items.hasNext()) { BaseNotificationBroadcasterEntry item = items.next(); if ((item.listener == listener) && (item.filter != null) && (item.filter instanceof BaseAttributeFilter) && (item.handback == handback)) { BaseAttributeFilter oldFilter = (BaseAttributeFilter) item.filter; String newNames[] = newFilter.getNames(); String oldNames[] = oldFilter.getNames(); if (newNames.length == 0) { oldFilter.clear(); } else { if (oldNames.length != 0) { for (int i = 0; i < newNames.length; i++) oldFilter.addAttribute(newNames[i]); } } return; } } } // General purpose addition of a new entry entries.add(new BaseNotificationBroadcasterEntry (listener, filter, handback)); } } /** * Return an MBeanNotificationInfo object describing the * notifications sent by this MBean. */ @Override public MBeanNotificationInfo[] getNotificationInfo() { return (new MBeanNotificationInfo[0]); } /** * Remove a notification event listener from this MBean. * * @param listener The listener to be removed (any and all registrations * for this listener will be eliminated) * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ @Override public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { synchronized (entries) { Iterator items = entries.iterator(); while (items.hasNext()) { BaseNotificationBroadcasterEntry item = items.next(); if (item.listener == listener) items.remove(); } } } /** * Remove a notification event listener from this MBean. * * @param listener The listener to be removed (any and all registrations * for this listener will be eliminated) * @param handback Handback object to be sent along with event * notifications * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ public void removeNotificationListener(NotificationListener listener, Object handback) throws ListenerNotFoundException { removeNotificationListener(listener); } /** * Remove a notification event listener from this MBean. * * @param listener The listener to be removed (any and all registrations * for this listener will be eliminated) * @param filter Filter object used to filter event notifications * actually delivered, or null for no filtering * @param handback Handback object to be sent along with event * notifications * * @exception ListenerNotFoundException if this listener is not * registered in the MBean */ public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { removeNotificationListener(listener); } /** * Send the specified notification to all interested listeners. * * @param notification The notification to be sent */ public void sendNotification(Notification notification) { synchronized (entries) { Iterator items = entries.iterator(); while (items.hasNext()) { BaseNotificationBroadcasterEntry item = items.next(); if ((item.filter != null) && (!item.filter.isNotificationEnabled(notification))) continue; item.listener.handleNotification(notification, item.handback); } } } } /** * Utility class representing a particular registered listener entry. */ class BaseNotificationBroadcasterEntry { public BaseNotificationBroadcasterEntry(NotificationListener listener, NotificationFilter filter, Object handback) { this.listener = listener; this.filter = filter; this.handback = handback; } public NotificationFilter filter = null; public Object handback = null; public NotificationListener listener = null; } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/FeatureInfo.java0000644000175100017510000000445512271452077025060 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import java.io.Serializable; import javax.management.MBeanFeatureInfo; /** *

    Convenience base class for AttributeInfo, * ConstructorInfo, and OperationInfo classes * that will be used to collect configuration information for the * ModelMBean beans exposed for management.

    * * @author Craig R. McClanahan */ public class FeatureInfo implements Serializable { static final long serialVersionUID = -911529176124712296L; protected String description = null; protected String name = null; protected MBeanFeatureInfo info = null; // all have type except Constructor protected String type = null; // ------------------------------------------------------------- Properties /** * The human-readable description of this feature. */ public String getDescription() { return (this.description); } public void setDescription(String description) { this.description = description; } /** * The name of this feature, which must be unique among features in the * same collection. */ public String getName() { return (this.name); } public void setName(String name) { this.name = name; } /** * The fully qualified Java class name of this element. */ public String getType() { return (this.type); } public void setType(String type) { this.type = type; } } tomcat7-7.0.52/java/org/apache/tomcat/util/modeler/NotificationInfo.java0000644000175100017510000000747512271452077026120 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.modeler; import javax.management.MBeanNotificationInfo; /** *

    Internal configuration information for a Notification * descriptor.

    * * @author Craig R. McClanahan */ public class NotificationInfo extends FeatureInfo { static final long serialVersionUID = -6319885418912650856L; // ----------------------------------------------------- Instance Variables /** * The ModelMBeanNotificationInfo object that corresponds * to this NotificationInfo instance. */ transient MBeanNotificationInfo info = null; protected String notifTypes[] = new String[0]; // ------------------------------------------------------------- Properties /** * Override the description property setter. * * @param description The new description */ @Override public void setDescription(String description) { super.setDescription(description); this.info = null; } /** * Override the name property setter. * * @param name The new name */ @Override public void setName(String name) { super.setName(name); this.info = null; } /** * The set of notification types for this MBean. */ public String[] getNotifTypes() { return (this.notifTypes); } // --------------------------------------------------------- Public Methods /** * Add a new notification type to the set managed by an MBean. * * @param notifType The new notification type */ public void addNotifType(String notifType) { synchronized (notifTypes) { String results[] = new String[notifTypes.length + 1]; System.arraycopy(notifTypes, 0, results, 0, notifTypes.length); results[notifTypes.length] = notifType; notifTypes = results; this.info = null; } } /** * Create and return a ModelMBeanNotificationInfo object that * corresponds to the attribute described by this instance. */ public MBeanNotificationInfo createNotificationInfo() { // Return our cached information (if any) if (info != null) return (info); // Create and return a new information object info = new MBeanNotificationInfo (getNotifTypes(), getName(), getDescription()); //Descriptor descriptor = info.getDescriptor(); //addFields(descriptor); //info.setDescriptor(descriptor); return (info); } /** * Return a string representation of this notification descriptor. */ @Override public String toString() { StringBuilder sb = new StringBuilder("NotificationInfo["); sb.append("name="); sb.append(name); sb.append(", description="); sb.append(description); sb.append(", notifTypes="); sb.append(notifTypes.length); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/DomUtil.java0000644000175100017510000002211112271452644022564 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Few simple utils to read DOM * * @author Costin Manolache * * @deprecated Unused: Will be removed in Tomcat 8.0.x */ @Deprecated public class DomUtil { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( DomUtil.class ); // -------------------- DOM utils -------------------- /** Get the trimmed text content of a node or null if there is no text */ public static String getContent(Node n ) { if( n==null ) return null; Node n1=DomUtil.getChild(n, Node.TEXT_NODE); if( n1==null ) return null; String s1=n1.getNodeValue(); return s1.trim(); } /** Get the first element child. * @param parent lookup direct children * @param name name of the element. If null return the first element. */ public static Node getChild( Node parent, String name ) { if( parent==null ) return null; Node first=parent.getFirstChild(); if( first==null ) return null; for (Node node = first; node != null; node = node.getNextSibling()) { //System.out.println("getNode: " + name + " " + node.getNodeName()); if( node.getNodeType()!=Node.ELEMENT_NODE) continue; if( name != null && name.equals( node.getNodeName() ) ) { return node; } if( name == null ) { return node; } } return null; } public static String getAttribute(Node element, String attName ) { NamedNodeMap attrs=element.getAttributes(); if( attrs==null ) return null; Node attN=attrs.getNamedItem(attName); if( attN==null ) return null; return attN.getNodeValue(); } public static void setAttribute(Node node, String attName, String val) { NamedNodeMap attributes=node.getAttributes(); Node attNode=node.getOwnerDocument().createAttribute(attName); attNode.setNodeValue( val ); attributes.setNamedItem(attNode); } public static void removeAttribute( Node node, String attName ) { NamedNodeMap attributes=node.getAttributes(); attributes.removeNamedItem(attName); } /** Set or replace the text value */ public static void setText(Node node, String val) { Node chld=DomUtil.getChild(node, Node.TEXT_NODE); if( chld == null ) { Node textN=node.getOwnerDocument().createTextNode(val); node.appendChild(textN); return; } // change the value chld.setNodeValue(val); } /** Find the first direct child with a given attribute. * @param parent * @param elemName name of the element, or null for any * @param attName attribute we're looking for * @param attVal attribute value or null if we just want any */ public static Node findChildWithAtt(Node parent, String elemName, String attName, String attVal) { Node child=DomUtil.getChild(parent, Node.ELEMENT_NODE); if( attVal== null ) { while( child!= null && ( elemName==null || elemName.equals( child.getNodeName())) && DomUtil.getAttribute(child, attName) != null ) { child=getNext(child, elemName, Node.ELEMENT_NODE ); } } else { while( child!= null && ( elemName==null || elemName.equals( child.getNodeName())) && ! attVal.equals( DomUtil.getAttribute(child, attName)) ) { child=getNext(child, elemName, Node.ELEMENT_NODE ); } } return child; } /** Get the first child's content ( ie it's included TEXT node ). */ public static String getChildContent( Node parent, String name ) { Node first=parent.getFirstChild(); if( first==null ) return null; for (Node node = first; node != null; node = node.getNextSibling()) { //System.out.println("getNode: " + name + " " + node.getNodeName()); if( name.equals( node.getNodeName() ) ) { return getContent( node ); } } return null; } /** Get the first direct child with a given type */ public static Node getChild( Node parent, int type ) { Node n=parent.getFirstChild(); while( n!=null && type != n.getNodeType() ) { n=n.getNextSibling(); } if( n==null ) return null; return n; } /** Get the next sibling with the same name and type */ public static Node getNext( Node current ) { String name=current.getNodeName(); int type=current.getNodeType(); return getNext( current, name, type); } /** Return the next sibling with a given name and type */ public static Node getNext( Node current, String name, int type) { Node first=current.getNextSibling(); if( first==null ) return null; for (Node node = first; node != null; node = node.getNextSibling()) { if( type >= 0 && node.getNodeType() != type ) continue; //System.out.println("getNode: " + name + " " + node.getNodeName()); if( name==null ) return node; if( name.equals( node.getNodeName() ) ) { return node; } } return null; } public static class NullResolver implements EntityResolver { @Override public InputSource resolveEntity (String publicId, String systemId) throws SAXException, IOException { if( log.isTraceEnabled()) log.trace("ResolveEntity: " + publicId + " " + systemId); return new InputSource(new StringReader("")); } } public static void setAttributes( Object o, Node parent) { NamedNodeMap attrs=parent.getAttributes(); if( attrs==null ) return; for (int i=0; i The default implementation of the * {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} interface. * *

    After retrieving an instance of this class from a {@link * org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} instance (see * {@link org.apache.tomcat.util.http.fileupload.FileUpload * #parseRequest(org.apache.tomcat.util.http.fileupload.RequestContext)}), you * may either request all contents of file at once using {@link #get()} or * request an {@link java.io.InputStream InputStream} with * {@link #getInputStream()} and process the file without attempting to load * it into memory, which may come handy with large files. * *

    Temporary files, which are created for file items, should be * deleted later on.

    * * @since FileUpload 1.1 */ public class DiskFileItem implements FileItem { // ----------------------------------------------------- Manifest constants /** * Default content charset to be used when no explicit charset * parameter is provided by the sender. Media subtypes of the * "text" type are defined to have a default charset value of * "ISO-8859-1" when received via HTTP. */ public static final String DEFAULT_CHARSET = "ISO-8859-1"; // ----------------------------------------------------------- Data members /** * UID used in unique file name generation. */ private static final String UID = UUID.randomUUID().toString().replace('-', '_'); /** * Counter used in unique identifier generation. */ private static final AtomicInteger COUNTER = new AtomicInteger(0); /** * The name of the form field as provided by the browser. */ private String fieldName; /** * The content type passed by the browser, or null if * not defined. */ private final String contentType; /** * Whether or not this item is a simple form field. */ private boolean isFormField; /** * The original filename in the user's filesystem. */ private final String fileName; /** * The size of the item, in bytes. This is used to cache the size when a * file item is moved from its original location. */ private long size = -1; /** * The threshold above which uploads will be stored on disk. */ private final int sizeThreshold; /** * The directory in which uploaded files will be stored, if stored on disk. */ private final File repository; /** * Cached contents of the file. */ private byte[] cachedContent; /** * Output stream for this item. */ private transient DeferredFileOutputStream dfos; /** * The temporary file to use. */ private transient File tempFile; /** * The file items headers. */ private FileItemHeaders headers; // ----------------------------------------------------------- Constructors /** * Constructs a new DiskFileItem instance. * * @param fieldName The name of the form field. * @param contentType The content type passed by the browser or * null if not specified. * @param isFormField Whether or not this item is a plain form field, as * opposed to a file upload. * @param fileName The original filename in the user's filesystem, or * null if not specified. * @param sizeThreshold The threshold, in bytes, below which items will be * retained in memory and above which they will be * stored as a file. * @param repository The data repository, which is the directory in * which files will be created, should the item size * exceed the threshold. */ public DiskFileItem(String fieldName, String contentType, boolean isFormField, String fileName, int sizeThreshold, File repository) { this.fieldName = fieldName; this.contentType = contentType; this.isFormField = isFormField; this.fileName = fileName; this.sizeThreshold = sizeThreshold; this.repository = repository; } // ------------------------------- Methods from javax.activation.DataSource /** * Returns an {@link java.io.InputStream InputStream} that can be * used to retrieve the contents of the file. * * @return An {@link java.io.InputStream InputStream} that can be * used to retrieve the contents of the file. * * @throws IOException if an error occurs. */ @Override public InputStream getInputStream() throws IOException { if (!isInMemory()) { return new FileInputStream(dfos.getFile()); } if (cachedContent == null) { cachedContent = dfos.getData(); } return new ByteArrayInputStream(cachedContent); } /** * Returns the content type passed by the agent or null if * not defined. * * @return The content type passed by the agent or null if * not defined. */ @Override public String getContentType() { return contentType; } /** * Returns the content charset passed by the agent or null if * not defined. * * @return The content charset passed by the agent or null if * not defined. */ public String getCharSet() { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = parser.parse(getContentType(), ';'); return params.get("charset"); } /** * Returns the original filename in the client's filesystem. * * @return The original filename in the client's filesystem. * @throws org.apache.tomcat.util.http.fileupload.InvalidFileNameException * The file name contains a NUL character, which might be an indicator of * a security attack. If you intend to use the file name anyways, catch * the exception and use {@link * org.apache.tomcat.util.http.fileupload.InvalidFileNameException#getName()}. */ @Override public String getName() { return Streams.checkFileName(fileName); } // ------------------------------------------------------- FileItem methods /** * Provides a hint as to whether or not the file contents will be read * from memory. * * @return true if the file contents will be read * from memory; false otherwise. */ @Override public boolean isInMemory() { if (cachedContent != null) { return true; } return dfos.isInMemory(); } /** * Returns the size of the file. * * @return The size of the file, in bytes. */ @Override public long getSize() { if (size >= 0) { return size; } else if (cachedContent != null) { return cachedContent.length; } else if (dfos.isInMemory()) { return dfos.getData().length; } else { return dfos.getFile().length(); } } /** * Returns the contents of the file as an array of bytes. If the * contents of the file were not yet cached in memory, they will be * loaded from the disk storage and cached. * * @return The contents of the file as an array of bytes. */ @Override public byte[] get() { if (isInMemory()) { if (cachedContent == null) { cachedContent = dfos.getData(); } return cachedContent; } byte[] fileData = new byte[(int) getSize()]; InputStream fis = null; try { fis = new BufferedInputStream(new FileInputStream(dfos.getFile())); fis.read(fileData); } catch (IOException e) { fileData = null; } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // ignore } } } return fileData; } /** * Returns the contents of the file as a String, using the specified * encoding. This method uses {@link #get()} to retrieve the * contents of the file. * * @param charset The charset to use. * * @return The contents of the file, as a string. * * @throws UnsupportedEncodingException if the requested character * encoding is not available. */ @Override public String getString(final String charset) throws UnsupportedEncodingException { return new String(get(), charset); } /** * Returns the contents of the file as a String, using the default * character encoding. This method uses {@link #get()} to retrieve the * contents of the file. * * TODO Consider making this method throw UnsupportedEncodingException. * * @return The contents of the file, as a string. */ @Override public String getString() { byte[] rawdata = get(); String charset = getCharSet(); if (charset == null) { charset = DEFAULT_CHARSET; } try { return new String(rawdata, charset); } catch (UnsupportedEncodingException e) { return new String(rawdata); } } /** * A convenience method to write an uploaded item to disk. The client code * is not concerned with whether or not the item is stored in memory, or on * disk in a temporary location. They just want to write the uploaded item * to a file. *

    * This implementation first attempts to rename the uploaded item to the * specified destination file, if the item was originally written to disk. * Otherwise, the data will be copied to the specified file. *

    * This method is only guaranteed to work once, the first time it * is invoked for a particular item. This is because, in the event that the * method renames a temporary file, that file will no longer be available * to copy or rename again at a later time. * * @param file The File into which the uploaded item should * be stored. * * @throws Exception if an error occurs. */ @Override public void write(File file) throws Exception { if (isInMemory()) { FileOutputStream fout = null; try { fout = new FileOutputStream(file); fout.write(get()); } finally { if (fout != null) { fout.close(); } } } else { File outputFile = getStoreLocation(); if (outputFile != null) { // Save the length of the file size = outputFile.length(); /* * The uploaded file is being stored on disk * in a temporary location so move it to the * desired file. */ if (!outputFile.renameTo(file)) { BufferedInputStream in = null; BufferedOutputStream out = null; try { in = new BufferedInputStream( new FileInputStream(outputFile)); out = new BufferedOutputStream( new FileOutputStream(file)); IOUtils.copy(in, out); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // ignore } } if (out != null) { try { out.close(); } catch (IOException e) { // ignore } } } } } else { /* * For whatever reason we cannot write the * file to disk. */ throw new FileUploadException( "Cannot write uploaded file to disk!"); } } } /** * Deletes the underlying storage for a file item, including deleting any * associated temporary disk file. Although this storage will be deleted * automatically when the FileItem instance is garbage * collected, this method can be used to ensure that this is done at an * earlier time, thus preserving system resources. */ @Override public void delete() { cachedContent = null; File outputFile = getStoreLocation(); if (outputFile != null && outputFile.exists()) { outputFile.delete(); } } /** * Returns the name of the field in the multipart form corresponding to * this file item. * * @return The name of the form field. * * @see #setFieldName(java.lang.String) * */ @Override public String getFieldName() { return fieldName; } /** * Sets the field name used to reference this file item. * * @param fieldName The name of the form field. * * @see #getFieldName() * */ @Override public void setFieldName(String fieldName) { this.fieldName = fieldName; } /** * Determines whether or not a FileItem instance represents * a simple form field. * * @return true if the instance represents a simple form * field; false if it represents an uploaded file. * * @see #setFormField(boolean) * */ @Override public boolean isFormField() { return isFormField; } /** * Specifies whether or not a FileItem instance represents * a simple form field. * * @param state true if the instance represents a simple form * field; false if it represents an uploaded file. * * @see #isFormField() * */ @Override public void setFormField(boolean state) { isFormField = state; } /** * Returns an {@link java.io.OutputStream OutputStream} that can * be used for storing the contents of the file. * * @return An {@link java.io.OutputStream OutputStream} that can be used * for storing the contensts of the file. * * @throws IOException if an error occurs. */ @Override public OutputStream getOutputStream() throws IOException { if (dfos == null) { File outputFile = getTempFile(); dfos = new DeferredFileOutputStream(sizeThreshold, outputFile); } return dfos; } // --------------------------------------------------------- Public methods /** * Returns the {@link java.io.File} object for the FileItem's * data's temporary location on the disk. Note that for * FileItems that have their data stored in memory, * this method will return null. When handling large * files, you can use {@link java.io.File#renameTo(java.io.File)} to * move the file to new location without copying the data, if the * source and destination locations reside within the same logical * volume. * * @return The data file, or null if the data is stored in * memory. */ public File getStoreLocation() { if (dfos == null) { return null; } return dfos.getFile(); } // ------------------------------------------------------ Protected methods /** * Removes the file contents from the temporary storage. */ @Override protected void finalize() { File outputFile = dfos.getFile(); if (outputFile != null && outputFile.exists()) { outputFile.delete(); } } /** * Creates and returns a {@link java.io.File File} representing a uniquely * named temporary file in the configured repository path. The lifetime of * the file is tied to the lifetime of the FileItem instance; * the file will be deleted when the instance is garbage collected. * * @return The {@link java.io.File File} to be used for temporary storage. */ protected File getTempFile() { if (tempFile == null) { File tempDir = repository; if (tempDir == null) { tempDir = new File(System.getProperty("java.io.tmpdir")); } String tempFileName = String.format("upload_%s_%s.tmp", UID, getUniqueId()); tempFile = new File(tempDir, tempFileName); } return tempFile; } // -------------------------------------------------------- Private methods /** * Returns an identifier that is unique within the class loader used to * load this class, but does not have random-like apearance. * * @return A String with the non-random looking instance identifier. */ private static String getUniqueId() { final int limit = 100000000; int current = COUNTER.getAndIncrement(); String id = Integer.toString(current); // If you manage to get more than 100 million of ids, you'll // start getting ids longer than 8 characters. if (current < limit) { id = ("00000000" + id).substring(id.length()); } return id; } /** * Returns a string representation of this object. * * @return a string representation of this object. */ @Override public String toString() { return String.format("name=%s, StoreLocation=%s, size=%s bytes, isFormField=%s, FieldName=%s", getName(), getStoreLocation(), Long.valueOf(getSize()), Boolean.valueOf(isFormField()), getFieldName()); } /** * Returns the file item headers. * @return The file items headers. */ @Override public FileItemHeaders getHeaders() { return headers; } /** * Sets the file item headers. * @param pHeaders The file items headers. */ @Override public void setHeaders(FileItemHeaders pHeaders) { headers = pHeaders; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/disk/package-info.java0000644000175100017510000000445212271447131027573 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** *

    * A disk-based implementation of the * {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} * interface. This implementation retains smaller items in memory, while * writing larger ones to disk. The threshold between these two is * configurable, as is the location of files that are written to disk. *

    *

    * In typical usage, an instance of * {@link org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory DiskFileItemFactory} * would be created, configured, and then passed to a * {@link org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} * implementation such as * {@link org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload ServletFileUpload}. *

    *

    * The following code fragment demonstrates this usage. *

    *
     *        DiskFileItemFactory factory = new DiskFileItemFactory();
     *        // maximum size that will be stored in memory
     *        factory.setSizeThreshold(4096);
     *        // the location for saving data that is larger than getSizeThreshold()
     *        factory.setRepository(new File("/tmp"));
     *
     *        ServletFileUpload upload = new ServletFileUpload(factory);
     * 
    *

    * Please see the FileUpload * User Guide * for further details and examples of how to use this package. *

    */ package org.apache.tomcat.util.http.fileupload.disk; tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java0000644000175100017510000001716012271447131031110 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.disk; import java.io.File; import org.apache.tomcat.util.http.fileupload.FileCleaningTracker; import org.apache.tomcat.util.http.fileupload.FileItem; import org.apache.tomcat.util.http.fileupload.FileItemFactory; /** *

    The default {@link org.apache.tomcat.util.http.fileupload.FileItemFactory} * implementation. This implementation creates * {@link org.apache.tomcat.util.http.fileupload.FileItem} instances which keep * their * content either in memory, for smaller items, or in a temporary file on disk, * for larger items. The size threshold, above which content will be stored on * disk, is configurable, as is the directory in which temporary files will be * created.

    * *

    If not otherwise configured, the default configuration values are as * follows:

    *
      *
    • Size threshold is 10KB.
    • *
    • Repository is the system default temp directory, as returned by * System.getProperty("java.io.tmpdir").
    • *
    *

    * NOTE: Files are created in the system default temp directory with * predictable names. This means that a local attacker with write access to that * directory can perform a TOUTOC attack to replace any uploaded file with a * file of the attackers choice. The implications of this will depend on how the * uploaded file is used but could be significant. When using this * implementation in an environment with local, untrusted users, * {@link #setRepository(File)} MUST be used to configure a repository location * that is not publicly writable. In a Servlet container the location identified * by the ServletContext attribute javax.servlet.context.tempdir * may be used. *

    * *

    Temporary files, which are created for file items, should be * deleted later on.

    * * @since FileUpload 1.1 */ public class DiskFileItemFactory implements FileItemFactory { // ----------------------------------------------------- Manifest constants /** * The default threshold above which uploads will be stored on disk. */ public static final int DEFAULT_SIZE_THRESHOLD = 10240; // ----------------------------------------------------- Instance Variables /** * The directory in which uploaded files will be stored, if stored on disk. */ private File repository; /** * The threshold above which uploads will be stored on disk. */ private int sizeThreshold = DEFAULT_SIZE_THRESHOLD; /** *

    The instance of {@link FileCleaningTracker}, which is responsible * for deleting temporary files.

    *

    May be null, if tracking files is not required.

    */ private FileCleaningTracker fileCleaningTracker; // ----------------------------------------------------------- Constructors /** * Constructs an unconfigured instance of this class. The resulting factory * may be configured by calling the appropriate setter methods. */ public DiskFileItemFactory() { this(DEFAULT_SIZE_THRESHOLD, null); } /** * Constructs a preconfigured instance of this class. * * @param sizeThreshold The threshold, in bytes, below which items will be * retained in memory and above which they will be * stored as a file. * @param repository The data repository, which is the directory in * which files will be created, should the item size * exceed the threshold. */ public DiskFileItemFactory(int sizeThreshold, File repository) { this.sizeThreshold = sizeThreshold; this.repository = repository; } // ------------------------------------------------------------- Properties /** * Returns the directory used to temporarily store files that are larger * than the configured size threshold. * * @return The directory in which temporary files will be located. * * @see #setRepository(java.io.File) * */ public File getRepository() { return repository; } /** * Sets the directory used to temporarily store files that are larger * than the configured size threshold. * * @param repository The directory in which temporary files will be located. * * @see #getRepository() * */ public void setRepository(File repository) { this.repository = repository; } /** * Returns the size threshold beyond which files are written directly to * disk. The default value is 10240 bytes. * * @return The size threshold, in bytes. * * @see #setSizeThreshold(int) */ public int getSizeThreshold() { return sizeThreshold; } /** * Sets the size threshold beyond which files are written directly to disk. * * @param sizeThreshold The size threshold, in bytes. * * @see #getSizeThreshold() * */ public void setSizeThreshold(int sizeThreshold) { this.sizeThreshold = sizeThreshold; } // --------------------------------------------------------- Public Methods /** * Create a new {@link DiskFileItem} * instance from the supplied parameters and the local factory * configuration. * * @param fieldName The name of the form field. * @param contentType The content type of the form field. * @param isFormField true if this is a plain form field; * false otherwise. * @param fileName The name of the uploaded file, if any, as supplied * by the browser or other client. * * @return The newly created file item. */ @Override public FileItem createItem(String fieldName, String contentType, boolean isFormField, String fileName) { DiskFileItem result = new DiskFileItem(fieldName, contentType, isFormField, fileName, sizeThreshold, repository); FileCleaningTracker tracker = getFileCleaningTracker(); if (tracker != null) { tracker.track(result.getTempFile(), result); } return result; } /** * Returns the tracker, which is responsible for deleting temporary * files. * * @return An instance of {@link FileCleaningTracker}, or null * (default), if temporary files aren't tracked. */ public FileCleaningTracker getFileCleaningTracker() { return fileCleaningTracker; } /** * Sets the tracker, which is responsible for deleting temporary * files. * * @param pTracker An instance of {@link FileCleaningTracker}, * which will from now on track the created files, or null * (default), to disable tracking. */ public void setFileCleaningTracker(FileCleaningTracker pTracker) { fileCleaningTracker = pTracker; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/UploadContext.java0000644000175100017510000000263712271447131027111 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; /** * Enhanced access to the request information needed for file uploads, * which fixes the Content Length data access in {@link RequestContext}. * * The reason of introducing this new interface is just for backward compatibility * and it might vanish for a refactored 2.x version moving the new method into * RequestContext again. * * @since 1.3 */ public interface UploadContext extends RequestContext { /** * Retrieve the content length of the request. * * @return The content length of the request. * @since 1.3 */ long contentLength(); } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileUploadException.java0000644000175100017510000000254012271447131030214 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; /** * Exception for errors encountered while processing the request. */ public class FileUploadException extends Exception { private static final long serialVersionUID = -4222909057964038517L; public FileUploadException() { super(); } public FileUploadException(String message, Throwable cause) { super(message, cause); } public FileUploadException(String message) { super(message); } public FileUploadException(Throwable cause) { super(cause); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileItemStream.java0000644000175100017510000000742512271447131027172 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.IOException; import java.io.InputStream; /** *

    This interface provides access to a file or form item that was * received within a multipart/form-data POST request. * The items contents are retrieved by calling {@link #openStream()}.

    *

    Instances of this class are created by accessing the * iterator, returned by * {@link FileUploadBase#getItemIterator(RequestContext)}.

    *

    Note: There is an interaction between the iterator and * its associated instances of {@link FileItemStream}: By invoking * {@link java.util.Iterator#hasNext()} on the iterator, you discard all data, * which hasn't been read so far from the previous data.

    */ public interface FileItemStream extends FileItemHeadersSupport { /** * This exception is thrown, if an attempt is made to read * data from the {@link InputStream}, which has been returned * by {@link FileItemStream#openStream()}, after * {@link java.util.Iterator#hasNext()} has been invoked on the * iterator, which created the {@link FileItemStream}. */ public static class ItemSkippedException extends IOException { /** * The exceptions serial version UID, which is being used * when serializing an exception instance. */ private static final long serialVersionUID = -7280778431581963740L; } /** * Creates an {@link InputStream}, which allows to read the * items contents. * * @return The input stream, from which the items data may * be read. * @throws IllegalStateException The method was already invoked on * this item. It is not possible to recreate the data stream. * @throws IOException An I/O error occurred. * @see ItemSkippedException */ InputStream openStream() throws IOException; /** * Returns the content type passed by the browser or null if * not defined. * * @return The content type passed by the browser or null if * not defined. */ String getContentType(); /** * Returns the original filename in the client's filesystem, as provided by * the browser (or other client software). In most cases, this will be the * base file name, without path information. However, some clients, such as * the Opera browser, do include path information. * * @return The original filename in the client's filesystem. */ String getName(); /** * Returns the name of the field in the multipart form corresponding to * this file item. * * @return The name of the form field. */ String getFieldName(); /** * Determines whether or not a FileItem instance represents * a simple form field. * * @return true if the instance represents a simple form * field; false if it represents an uploaded file. */ boolean isFormField(); } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/servlet/0000755000175100017510000000000012301126367025130 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java0000644000175100017510000000657012271447131032346 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.servlet; import java.io.IOException; import java.io.InputStream; import javax.servlet.http.HttpServletRequest; import org.apache.tomcat.util.http.fileupload.FileUploadBase; import org.apache.tomcat.util.http.fileupload.UploadContext; /** *

    Provides access to the request information needed for a request made to * an HTTP servlet.

    * * @since FileUpload 1.1 */ public class ServletRequestContext implements UploadContext { // ----------------------------------------------------- Instance Variables /** * The request for which the context is being provided. */ private final HttpServletRequest request; // ----------------------------------------------------------- Constructors /** * Construct a context for this request. * * @param request The request to which this context applies. */ public ServletRequestContext(HttpServletRequest request) { this.request = request; } // --------------------------------------------------------- Public Methods /** * Retrieve the character encoding for the request. * * @return The character encoding for the request. */ @Override public String getCharacterEncoding() { return request.getCharacterEncoding(); } /** * Retrieve the content type of the request. * * @return The content type of the request. */ @Override public String getContentType() { return request.getContentType(); } /** * Retrieve the content length of the request. * * @return The content length of the request. * @since 1.3 */ @Override public long contentLength() { long size; try { size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH)); } catch (NumberFormatException e) { size = request.getContentLength(); } return size; } /** * Retrieve the input stream for the request. * * @return The input stream for the request. * * @throws IOException if a problem occurs. */ @Override public InputStream getInputStream() throws IOException { return request.getInputStream(); } /** * Returns a string representation of this object. * * @return a string representation of this object. */ @Override public String toString() { return String.format("ContentLength=%s, ContentType=%s", Long.valueOf(this.contentLength()), this.getContentType()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/servlet/package-info.java0000644000175100017510000000375312271447131030330 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** *

    * An implementation of * {@link org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} * for use in servlets conforming to JSR 53. This implementation requires * only access to the servlet's current HttpServletRequest * instance, and a suitable * {@link org.apache.tomcat.util.http.fileupload.FileItemFactory FileItemFactory} * implementation, such as * {@link org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}. *

    *

    * The following code fragment demonstrates typical usage. *

    *
     *        DiskFileItemFactory factory = new DiskFileItemFactory();
     *        // Configure the factory here, if desired.
     *        ServletFileUpload upload = new ServletFileUpload(factory);
     *        // Configure the uploader here, if desired.
     *        List fileItems = upload.parseRequest(request);
     * 
    *

    * Please see the FileUpload * User Guide * for further details and examples of how to use this package. *

    */ package org.apache.tomcat.util.http.fileupload.servlet; tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java0000644000175100017510000001222612271447131031370 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.servlet; import java.io.IOException; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.tomcat.util.http.fileupload.FileItem; import org.apache.tomcat.util.http.fileupload.FileItemFactory; import org.apache.tomcat.util.http.fileupload.FileItemIterator; import org.apache.tomcat.util.http.fileupload.FileUpload; import org.apache.tomcat.util.http.fileupload.FileUploadBase; import org.apache.tomcat.util.http.fileupload.FileUploadException; /** *

    High level API for processing file uploads.

    * *

    This class handles multiple files per single HTML widget, sent using * multipart/mixed encoding type, as specified by * RFC 1867. Use {@link * #parseRequest(org.apache.tomcat.util.http.fileupload.RequestContext)} to * acquire a list of {@link org.apache.tomcat.util.http.fileupload.FileItem}s * associated with a given HTML widget.

    * *

    How the data for individual parts is stored is determined by the factory * used to create them; a given part may be in memory, on disk, or somewhere * else.

    */ public class ServletFileUpload extends FileUpload { /** * Constant for HTTP POST method. */ private static final String POST_METHOD = "POST"; // ---------------------------------------------------------- Class methods /** * Utility method that determines whether the request contains multipart * content. * * @param request The servlet request to be evaluated. Must be non-null. * * @return true if the request is multipart; * false otherwise. */ public static final boolean isMultipartContent( HttpServletRequest request) { if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) { return false; } return FileUploadBase.isMultipartContent(new ServletRequestContext(request)); } // ----------------------------------------------------------- Constructors /** * Constructs an uninitialised instance of this class. A factory must be * configured, using setFileItemFactory(), before attempting * to parse requests. * * @see FileUpload#FileUpload(FileItemFactory) */ public ServletFileUpload() { super(); } /** * Constructs an instance of this class which uses the supplied factory to * create FileItem instances. * * @see FileUpload#FileUpload() * @param fileItemFactory The factory to use for creating file items. */ public ServletFileUpload(FileItemFactory fileItemFactory) { super(fileItemFactory); } // --------------------------------------------------------- Public methods /** * Processes an RFC 1867 * compliant multipart/form-data stream. * * @param request The servlet request to be parsed. * * @return A map of FileItem instances parsed from the request. * * @throws FileUploadException if there are problems reading/parsing * the request or storing files. * * @since 1.3 */ public Map> parseParameterMap(HttpServletRequest request) throws FileUploadException { return parseParameterMap(new ServletRequestContext(request)); } /** * Processes an RFC 1867 * compliant multipart/form-data stream. * * @param request The servlet request to be parsed. * * @return An iterator to instances of FileItemStream * parsed from the request, in the order that they were * transmitted. * * @throws FileUploadException if there are problems reading/parsing * the request or storing files. * @throws IOException An I/O error occurred. This may be a network * error while communicating with the client or a problem while * storing the uploaded content. */ public FileItemIterator getItemIterator(HttpServletRequest request) throws FileUploadException, IOException { return super.getItemIterator(new ServletRequestContext(request)); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileUpload.java0000644000175100017510000000601212271447131026333 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; /** *

    High level API for processing file uploads.

    * *

    This class handles multiple files per single HTML widget, sent using * multipart/mixed encoding type, as specified by * RFC 1867. Use {@link * #parseRequest(RequestContext)} to acquire a list * of {@link org.apache.tomcat.util.http.fileupload.FileItem FileItems} associated * with a given HTML widget.

    * *

    How the data for individual parts is stored is determined by the factory * used to create them; a given part may be in memory, on disk, or somewhere * else.

    */ public class FileUpload extends FileUploadBase { // ----------------------------------------------------------- Data members /** * The factory to use to create new form items. */ private FileItemFactory fileItemFactory; // ----------------------------------------------------------- Constructors /** * Constructs an uninitialised instance of this class. * * A factory must be * configured, using setFileItemFactory(), before attempting * to parse requests. * * @see #FileUpload(FileItemFactory) */ public FileUpload() { super(); } /** * Constructs an instance of this class which uses the supplied factory to * create FileItem instances. * * @see #FileUpload() * @param fileItemFactory The factory to use for creating file items. */ public FileUpload(FileItemFactory fileItemFactory) { super(); this.fileItemFactory = fileItemFactory; } // ----------------------------------------------------- Property accessors /** * Returns the factory class used when creating file items. * * @return The factory class for new file items. */ @Override public FileItemFactory getFileItemFactory() { return fileItemFactory; } /** * Sets the factory class to use when creating file items. * * @param factory The factory class for new file items. */ @Override public void setFileItemFactory(FileItemFactory factory) { this.fileItemFactory = factory; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java0000644000175100017510000000364712271447131027532 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.IOException; /** * An iterator, as returned by * {@link FileUploadBase#getItemIterator(RequestContext)}. */ public interface FileItemIterator { /** * Returns, whether another instance of {@link FileItemStream} * is available. * * @throws FileUploadException Parsing or processing the * file item failed. * @throws IOException Reading the file item failed. * @return True, if one or more additional file items * are available, otherwise false. */ boolean hasNext() throws FileUploadException, IOException; /** * Returns the next available {@link FileItemStream}. * * @throws java.util.NoSuchElementException No more items are available. Use * {@link #hasNext()} to prevent this exception. * @throws FileUploadException Parsing or processing the * file item failed. * @throws IOException Reading the file item failed. * @return FileItemStream instance, which provides * access to the next file item. */ FileItemStream next() throws FileUploadException, IOException; } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/ThresholdingOutputStream.java0000644000175100017510000001445612271447131031351 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.IOException; import java.io.OutputStream; /** * An output stream which triggers an event when a specified number of bytes of * data have been written to it. The event can be used, for example, to throw * an exception if a maximum has been reached, or to switch the underlying * stream type when the threshold is exceeded. *

    * This class overrides all OutputStream methods. However, these * overrides ultimately call the corresponding methods in the underlying output * stream implementation. *

    * NOTE: This implementation may trigger the event before the threshold * is actually reached, since it triggers when a pending write operation would * cause the threshold to be exceeded. */ public abstract class ThresholdingOutputStream extends OutputStream { // ----------------------------------------------------------- Data members /** * The threshold at which the event will be triggered. */ private final int threshold; /** * The number of bytes written to the output stream. */ private long written; /** * Whether or not the configured threshold has been exceeded. */ private boolean thresholdExceeded; // ----------------------------------------------------------- Constructors /** * Constructs an instance of this class which will trigger an event at the * specified threshold. * * @param threshold The number of bytes at which to trigger an event. */ public ThresholdingOutputStream(int threshold) { this.threshold = threshold; } // --------------------------------------------------- OutputStream methods /** * Writes the specified byte to this output stream. * * @param b The byte to be written. * * @exception IOException if an error occurs. */ @Override public void write(int b) throws IOException { checkThreshold(1); getStream().write(b); written++; } /** * Writes b.length bytes from the specified byte array to this * output stream. * * @param b The array of bytes to be written. * * @exception IOException if an error occurs. */ @Override public void write(byte b[]) throws IOException { checkThreshold(b.length); getStream().write(b); written += b.length; } /** * Writes len bytes from the specified byte array starting at * offset off to this output stream. * * @param b The byte array from which the data will be written. * @param off The start offset in the byte array. * @param len The number of bytes to write. * * @exception IOException if an error occurs. */ @Override public void write(byte b[], int off, int len) throws IOException { checkThreshold(len); getStream().write(b, off, len); written += len; } /** * Flushes this output stream and forces any buffered output bytes to be * written out. * * @exception IOException if an error occurs. */ @Override public void flush() throws IOException { getStream().flush(); } /** * Closes this output stream and releases any system resources associated * with this stream. * * @exception IOException if an error occurs. */ @Override public void close() throws IOException { try { flush(); } catch (IOException ignored) { // ignore } getStream().close(); } // --------------------------------------------------------- Public methods /** * Determines whether or not the configured threshold has been exceeded for * this output stream. * * @return {@code true} if the threshold has been reached; * {@code false} otherwise. */ public boolean isThresholdExceeded() { return written > threshold; } // ------------------------------------------------------ Protected methods /** * Checks to see if writing the specified number of bytes would cause the * configured threshold to be exceeded. If so, triggers an event to allow * a concrete implementation to take action on this. * * @param count The number of bytes about to be written to the underlying * output stream. * * @exception IOException if an error occurs. */ protected void checkThreshold(int count) throws IOException { if (!thresholdExceeded && written + count > threshold) { thresholdExceeded = true; thresholdReached(); } } // ------------------------------------------------------- Abstract methods /** * Returns the underlying output stream, to which the corresponding * OutputStream methods in this class will ultimately delegate. * * @return The underlying output stream. * * @exception IOException if an error occurs. */ protected abstract OutputStream getStream() throws IOException; /** * Indicates that the configured threshold has been reached, and that a * subclass should take whatever action necessary on this event. This may * include changing the underlying output stream. * * @exception IOException if an error occurs. */ protected abstract void thresholdReached() throws IOException; } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/RequestContext.java0000644000175100017510000000332212271447131027305 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.IOException; import java.io.InputStream; /** *

    Abstracts access to the request information needed for file uploads. This * interface should be implemented for each type of request that may be * handled by FileUpload, such as servlets and portlets.

    * * @since FileUpload 1.1 */ public interface RequestContext { /** * Retrieve the character encoding for the request. * * @return The character encoding for the request. */ String getCharacterEncoding(); /** * Retrieve the content type of the request. * * @return The content type of the request. */ String getContentType(); /** * Retrieve the input stream for the request. * * @return The input stream for the request. * * @throws IOException if a problem occurs. */ InputStream getInputStream() throws IOException; } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java0000644000175100017510000007475312274670043027470 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import org.apache.tomcat.util.http.fileupload.FileUploadBase.FileUploadIOException; import org.apache.tomcat.util.http.fileupload.util.Closeable; import org.apache.tomcat.util.http.fileupload.util.Streams; /** *

    Low level API for processing file uploads. * *

    This class can be used to process data streams conforming to MIME * 'multipart' format as defined in * RFC 1867. Arbitrarily * large amounts of data in the stream can be processed under constant * memory usage. * *

    The format of the stream is defined in the following way:
    * * * multipart-body := preamble 1*encapsulation close-delimiter epilogue
    * encapsulation := delimiter body CRLF
    * delimiter := "--" boundary CRLF
    * close-delimiter := "--" boundary "--"
    * preamble := <ignore>
    * epilogue := <ignore>
    * body := header-part CRLF body-part
    * header-part := 1*header CRLF
    * header := header-name ":" header-value
    * header-name := <printable ascii characters except ":">
    * header-value := <any ascii characters except CR & LF>
    * body-data := <arbitrary data>
    *
    * *

    Note that body-data can contain another mulipart entity. There * is limited support for single pass processing of such nested * streams. The nested stream is required to have a * boundary token of the same length as the parent stream (see {@link * #setBoundary(byte[])}). * *

    Here is an example of usage of this class.
    * *

     *   try {
     *     MultipartStream multipartStream = new MultipartStream(input, boundary);
     *     boolean nextPart = multipartStream.skipPreamble();
     *     OutputStream output;
     *     while(nextPart) {
     *       String header = multipartStream.readHeaders();
     *       // process headers
     *       // create some output stream
     *       multipartStream.readBodyData(output);
     *       nextPart = multipartStream.readBoundary();
     *     }
     *   } catch(MultipartStream.MalformedStreamException e) {
     *     // the stream failed to follow required syntax
     *   } catch(IOException e) {
     *     // a read or write error occurred
     *   }
     * 
    */ public class MultipartStream { /** * Internal class, which is used to invoke the * {@link ProgressListener}. */ public static class ProgressNotifier { /** * The listener to invoke. */ private final ProgressListener listener; /** * Number of expected bytes, if known, or -1. */ private final long contentLength; /** * Number of bytes, which have been read so far. */ private long bytesRead; /** * Number of items, which have been read so far. */ private int items; /** * Creates a new instance with the given listener * and content length. * * @param pListener The listener to invoke. * @param pContentLength The expected content length. */ ProgressNotifier(ProgressListener pListener, long pContentLength) { listener = pListener; contentLength = pContentLength; } /** * Called to indicate that bytes have been read. * * @param pBytes Number of bytes, which have been read. */ void noteBytesRead(int pBytes) { /* Indicates, that the given number of bytes have been read from * the input stream. */ bytesRead += pBytes; notifyListener(); } /** * Called to indicate, that a new file item has been detected. */ void noteItem() { ++items; notifyListener(); } /** * Called for notifying the listener. */ private void notifyListener() { if (listener != null) { listener.update(bytesRead, contentLength, items); } } } // ----------------------------------------------------- Manifest constants /** * The Carriage Return ASCII character value. */ public static final byte CR = 0x0D; /** * The Line Feed ASCII character value. */ public static final byte LF = 0x0A; /** * The dash (-) ASCII character value. */ public static final byte DASH = 0x2D; /** * The maximum length of header-part that will be * processed (10 kilobytes = 10240 bytes.). */ public static final int HEADER_PART_SIZE_MAX = 10240; /** * The default length of the buffer used for processing a request. */ protected static final int DEFAULT_BUFSIZE = 4096; /** * A byte sequence that marks the end of header-part * (CRLFCRLF). */ protected static final byte[] HEADER_SEPARATOR = {CR, LF, CR, LF}; /** * A byte sequence that that follows a delimiter that will be * followed by an encapsulation (CRLF). */ protected static final byte[] FIELD_SEPARATOR = {CR, LF}; /** * A byte sequence that that follows a delimiter of the last * encapsulation in the stream (--). */ protected static final byte[] STREAM_TERMINATOR = {DASH, DASH}; /** * A byte sequence that precedes a boundary (CRLF--). */ protected static final byte[] BOUNDARY_PREFIX = {CR, LF, DASH, DASH}; // ----------------------------------------------------------- Data members /** * The input stream from which data is read. */ private final InputStream input; /** * The length of the boundary token plus the leading CRLF--. */ private int boundaryLength; /** * The amount of data, in bytes, that must be kept in the buffer in order * to detect delimiters reliably. */ private int keepRegion; /** * The byte sequence that partitions the stream. */ private byte[] boundary; /** * The length of the buffer used for processing the request. */ private final int bufSize; /** * The buffer used for processing the request. */ private final byte[] buffer; /** * The index of first valid character in the buffer. *
    * 0 <= head < bufSize */ private int head; /** * The index of last valid character in the buffer + 1. *
    * 0 <= tail <= bufSize */ private int tail; /** * The content encoding to use when reading headers. */ private String headerEncoding; /** * The progress notifier, if any, or null. */ private final ProgressNotifier notifier; // ----------------------------------------------------------- Constructors /** *

    Constructs a MultipartStream with a custom size buffer. * *

    Note that the buffer must be at least big enough to contain the * boundary string, plus 4 characters for CR/LF and double dash, plus at * least one byte of data. Too small a buffer size setting will degrade * performance. * * @param input The InputStream to serve as a data source. * @param boundary The token used for dividing the stream into * encapsulations. * @param bufSize The size of the buffer to be used, in bytes. * @param pNotifier The notifier, which is used for calling the * progress listener, if any. * * @throws IllegalArgumentException If the buffer size is too small */ public MultipartStream(InputStream input, byte[] boundary, int bufSize, ProgressNotifier pNotifier) { this.input = input; this.bufSize = bufSize; this.buffer = new byte[bufSize]; this.notifier = pNotifier; // We prepend CR/LF to the boundary to chop trailing CR/LF from // body-data tokens. this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length; if (bufSize < this.boundaryLength + 1) { throw new IllegalArgumentException( "The buffer size specified for the MultipartStream is too small"); } this.boundary = new byte[this.boundaryLength]; this.keepRegion = this.boundary.length; System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, BOUNDARY_PREFIX.length); System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length); head = 0; tail = 0; } /** *

    Constructs a MultipartStream with a default size buffer. * * @param input The InputStream to serve as a data source. * @param boundary The token used for dividing the stream into * encapsulations. * @param pNotifier An object for calling the progress listener, if any. * * * @see #MultipartStream(InputStream, byte[], int, ProgressNotifier) */ MultipartStream(InputStream input, byte[] boundary, ProgressNotifier pNotifier) { this(input, boundary, DEFAULT_BUFSIZE, pNotifier); } // --------------------------------------------------------- Public methods /** * Retrieves the character encoding used when reading the headers of an * individual part. When not specified, or null, the platform * default encoding is used. * * @return The encoding used to read part headers. */ public String getHeaderEncoding() { return headerEncoding; } /** * Specifies the character encoding to be used when reading the headers of * individual parts. When not specified, or null, the platform * default encoding is used. * * @param encoding The encoding used to read part headers. */ public void setHeaderEncoding(String encoding) { headerEncoding = encoding; } /** * Reads a byte from the buffer, and refills it as * necessary. * * @return The next byte from the input stream. * * @throws IOException if there is no more data available. */ public byte readByte() throws IOException { // Buffer depleted ? if (head == tail) { head = 0; // Refill. tail = input.read(buffer, head, bufSize); if (tail == -1) { // No more data available. throw new IOException("No more data is available"); } if (notifier != null) { notifier.noteBytesRead(tail); } } return buffer[head++]; } /** * Skips a boundary token, and checks whether more * encapsulations are contained in the stream. * * @return true if there are more encapsulations in * this stream; false otherwise. * * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits * @throws MalformedStreamException if the stream ends unexpectedly or * fails to follow required syntax. */ public boolean readBoundary() throws FileUploadIOException, MalformedStreamException { byte[] marker = new byte[2]; boolean nextChunk = false; head += boundaryLength; try { marker[0] = readByte(); if (marker[0] == LF) { // Work around IE5 Mac bug with input type=image. // Because the boundary delimiter, not including the trailing // CRLF, must not appear within any file (RFC 2046, section // 5.1.1), we know the missing CR is due to a buggy browser // rather than a file containing something similar to a // boundary. return true; } marker[1] = readByte(); if (arrayequals(marker, STREAM_TERMINATOR, 2)) { nextChunk = false; } else if (arrayequals(marker, FIELD_SEPARATOR, 2)) { nextChunk = true; } else { throw new MalformedStreamException( "Unexpected characters follow a boundary"); } } catch (FileUploadIOException e) { // wraps a SizeException, re-throw as it will be unwrapped later throw e; } catch (IOException e) { throw new MalformedStreamException("Stream ended unexpectedly"); } return nextChunk; } /** *

    Changes the boundary token used for partitioning the stream. * *

    This method allows single pass processing of nested multipart * streams. * *

    The boundary token of the nested stream is required * to be of the same length as the boundary token in parent stream. * *

    Restoring the parent stream boundary token after processing of a * nested stream is left to the application. * * @param boundary The boundary to be used for parsing of the nested * stream. * * @throws IllegalBoundaryException if the boundary * has a different length than the one * being currently parsed. */ public void setBoundary(byte[] boundary) throws IllegalBoundaryException { if (boundary.length != boundaryLength - BOUNDARY_PREFIX.length) { throw new IllegalBoundaryException( "The length of a boundary token can not be changed"); } System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length); } /** *

    Reads the header-part of the current * encapsulation. * *

    Headers are returned verbatim to the input stream, including the * trailing CRLF marker. Parsing is left to the * application. * *

    TODO allow limiting maximum header size to * protect against abuse. * * @return The header-part of the current encapsulation. * * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits. * @throws MalformedStreamException if the stream ends unexpectedly. */ public String readHeaders() throws FileUploadIOException, MalformedStreamException { int i = 0; byte b; // to support multi-byte characters ByteArrayOutputStream baos = new ByteArrayOutputStream(); int size = 0; while (i < HEADER_SEPARATOR.length) { try { b = readByte(); } catch (FileUploadIOException e) { // wraps a SizeException, re-throw as it will be unwrapped later throw e; } catch (IOException e) { throw new MalformedStreamException("Stream ended unexpectedly"); } if (++size > HEADER_PART_SIZE_MAX) { throw new MalformedStreamException(String.format( "Header section has more than %s bytes (maybe it is not properly terminated)", Integer.valueOf(HEADER_PART_SIZE_MAX))); } if (b == HEADER_SEPARATOR[i]) { i++; } else { i = 0; } baos.write(b); } String headers = null; if (headerEncoding != null) { try { headers = baos.toString(headerEncoding); } catch (UnsupportedEncodingException e) { // Fall back to platform default if specified encoding is not // supported. headers = baos.toString(); } } else { headers = baos.toString(); } return headers; } /** *

    Reads body-data from the current * encapsulation and writes its contents into the * output Stream. * *

    Arbitrary large amounts of data can be processed by this * method using a constant size buffer. (see {@link * #MultipartStream(InputStream,byte[],int, * MultipartStream.ProgressNotifier) constructor}). * * @param output The Stream to write data into. May * be null, in which case this method is equivalent * to {@link #discardBodyData()}. * * @return the amount of data written. * * @throws MalformedStreamException if the stream ends unexpectedly. * @throws IOException if an i/o error occurs. */ public int readBodyData(OutputStream output) throws MalformedStreamException, IOException { final InputStream istream = newInputStream(); return (int) Streams.copy(istream, output, false); } /** * Creates a new {@link ItemInputStream}. * @return A new instance of {@link ItemInputStream}. */ ItemInputStream newInputStream() { return new ItemInputStream(); } /** *

    Reads body-data from the current * encapsulation and discards it. * *

    Use this method to skip encapsulations you don't need or don't * understand. * * @return The amount of data discarded. * * @throws MalformedStreamException if the stream ends unexpectedly. * @throws IOException if an i/o error occurs. */ public int discardBodyData() throws MalformedStreamException, IOException { return readBodyData(null); } /** * Finds the beginning of the first encapsulation. * * @return true if an encapsulation was found in * the stream. * * @throws IOException if an i/o error occurs. */ public boolean skipPreamble() throws IOException { // First delimiter may be not preceeded with a CRLF. System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); boundaryLength = boundary.length - 2; try { // Discard all data up to the delimiter. discardBodyData(); // Read boundary - if succeeded, the stream contains an // encapsulation. return readBoundary(); } catch (MalformedStreamException e) { return false; } finally { // Restore delimiter. System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2); boundaryLength = boundary.length; boundary[0] = CR; boundary[1] = LF; } } /** * Compares count first bytes in the arrays * a and b. * * @param a The first array to compare. * @param b The second array to compare. * @param count How many bytes should be compared. * * @return true if count first bytes in arrays * a and b are equal. */ public static boolean arrayequals(byte[] a, byte[] b, int count) { for (int i = 0; i < count; i++) { if (a[i] != b[i]) { return false; } } return true; } /** * Searches for a byte of specified value in the buffer, * starting at the specified position. * * @param value The value to find. * @param pos The starting position for searching. * * @return The position of byte found, counting from beginning of the * buffer, or -1 if not found. */ protected int findByte(byte value, int pos) { for (int i = pos; i < tail; i++) { if (buffer[i] == value) { return i; } } return -1; } /** * Searches for the boundary in the buffer * region delimited by head and tail. * * @return The position of the boundary found, counting from the * beginning of the buffer, or -1 if * not found. */ protected int findSeparator() { int first; int match = 0; int maxpos = tail - boundaryLength; for (first = head; (first <= maxpos) && (match != boundaryLength); first++) { first = findByte(boundary[0], first); if (first == -1 || (first > maxpos)) { return -1; } for (match = 1; match < boundaryLength; match++) { if (buffer[first + match] != boundary[match]) { break; } } } if (match == boundaryLength) { return first - 1; } return -1; } /** * Thrown to indicate that the input stream fails to follow the * required syntax. */ public static class MalformedStreamException extends IOException { /** * The UID to use when serializing this instance. */ private static final long serialVersionUID = 6466926458059796677L; /** * Constructs a MalformedStreamException with no * detail message. */ public MalformedStreamException() { super(); } /** * Constructs an MalformedStreamException with * the specified detail message. * * @param message The detail message. */ public MalformedStreamException(String message) { super(message); } } /** * Thrown upon attempt of setting an invalid boundary token. */ public static class IllegalBoundaryException extends IOException { /** * The UID to use when serializing this instance. */ private static final long serialVersionUID = -161533165102632918L; /** * Constructs an IllegalBoundaryException with no * detail message. */ public IllegalBoundaryException() { super(); } /** * Constructs an IllegalBoundaryException with * the specified detail message. * * @param message The detail message. */ public IllegalBoundaryException(String message) { super(message); } } /** * An {@link InputStream} for reading an items contents. */ public class ItemInputStream extends InputStream implements Closeable { /** * The number of bytes, which have been read so far. */ private long total; /** * The number of bytes, which must be hold, because * they might be a part of the boundary. */ private int pad; /** * The current offset in the buffer. */ private int pos; /** * Whether the stream is already closed. */ private boolean closed; /** * Creates a new instance. */ ItemInputStream() { findSeparator(); } /** * Called for finding the separator. */ private void findSeparator() { pos = MultipartStream.this.findSeparator(); if (pos == -1) { if (tail - head > keepRegion) { pad = keepRegion; } else { pad = tail - head; } } } /** * Returns the number of bytes, which have been read * by the stream. * * @return Number of bytes, which have been read so far. */ public long getBytesRead() { return total; } /** * Returns the number of bytes, which are currently * available, without blocking. * * @throws IOException An I/O error occurs. * @return Number of bytes in the buffer. */ @Override public int available() throws IOException { if (pos == -1) { return tail - head - pad; } return pos - head; } /** * Offset when converting negative bytes to integers. */ private static final int BYTE_POSITIVE_OFFSET = 256; /** * Returns the next byte in the stream. * * @return The next byte in the stream, as a non-negative * integer, or -1 for EOF. * @throws IOException An I/O error occurred. */ @Override public int read() throws IOException { if (closed) { throw new FileItemStream.ItemSkippedException(); } if (available() == 0 && makeAvailable() == 0) { return -1; } ++total; int b = buffer[head++]; if (b >= 0) { return b; } return b + BYTE_POSITIVE_OFFSET; } /** * Reads bytes into the given buffer. * * @param b The destination buffer, where to write to. * @param off Offset of the first byte in the buffer. * @param len Maximum number of bytes to read. * @return Number of bytes, which have been actually read, * or -1 for EOF. * @throws IOException An I/O error occurred. */ @Override public int read(byte[] b, int off, int len) throws IOException { if (closed) { throw new FileItemStream.ItemSkippedException(); } if (len == 0) { return 0; } int res = available(); if (res == 0) { res = makeAvailable(); if (res == 0) { return -1; } } res = Math.min(res, len); System.arraycopy(buffer, head, b, off, res); head += res; total += res; return res; } /** * Closes the input stream. * * @throws IOException An I/O error occurred. */ @Override public void close() throws IOException { close(false); } /** * Closes the input stream. * * @param pCloseUnderlying Whether to close the underlying stream * (hard close) * @throws IOException An I/O error occurred. */ public void close(boolean pCloseUnderlying) throws IOException { if (closed) { return; } if (pCloseUnderlying) { closed = true; input.close(); } else { for (;;) { int av = available(); if (av == 0) { av = makeAvailable(); if (av == 0) { break; } } skip(av); } } closed = true; } /** * Skips the given number of bytes. * * @param bytes Number of bytes to skip. * @return The number of bytes, which have actually been * skipped. * @throws IOException An I/O error occurred. */ @Override public long skip(long bytes) throws IOException { if (closed) { throw new FileItemStream.ItemSkippedException(); } int av = available(); if (av == 0) { av = makeAvailable(); if (av == 0) { return 0; } } long res = Math.min(av, bytes); head += res; return res; } /** * Attempts to read more data. * * @return Number of available bytes * @throws IOException An I/O error occurred. */ private int makeAvailable() throws IOException { if (pos != -1) { return 0; } // Move the data to the beginning of the buffer. total += tail - head - pad; System.arraycopy(buffer, tail - pad, buffer, 0, pad); // Refill buffer with new data. head = 0; tail = pad; for (;;) { int bytesRead = input.read(buffer, tail, bufSize - tail); if (bytesRead == -1) { // The last pad amount is left in the buffer. // Boundary can't be in there so signal an error // condition. final String msg = "Stream ended unexpectedly"; throw new MalformedStreamException(msg); } if (notifier != null) { notifier.noteBytesRead(bytesRead); } tail += bytesRead; findSeparator(); int av = available(); if (av > 0 || pos != -1) { return av; } } } /** * Returns, whether the stream is closed. * * @return True, if the stream is closed, otherwise false. */ @Override public boolean isClosed() { return closed; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/ProgressListener.java0000644000175100017510000000272412271447131027627 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; /** * The {@link ProgressListener} may be used to display a progress bar * or do stuff like that. */ public interface ProgressListener { /** * Updates the listeners status information. * * @param pBytesRead The total number of bytes, which have been read * so far. * @param pContentLength The total number of bytes, which are being * read. May be -1, if this number is unknown. * @param pItems The number of the field, which is currently being * read. (0 = no item so far, 1 = first item is being read, ...) */ void update(long pBytesRead, long pContentLength, int pItems); } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/IOUtils.java0000644000175100017510000001221612271447131025642 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * General IO stream manipulation utilities. *

    * This class provides static utility methods for input/output operations. *

      *
    • closeQuietly - these methods close a stream ignoring nulls and exceptions *
    • toXxx/read - these methods read data from a stream *
    • write - these methods write data to a stream *
    • copy - these methods copy all the data from one stream to another *
    • contentEquals - these methods compare the content of two streams *
    *

    * The byte-to-char methods and char-to-byte methods involve a conversion step. * Two methods are provided in each case, one that uses the platform default * encoding and the other which allows you to specify an encoding. You are * encouraged to always specify an encoding because relying on the platform * default can lead to unexpected results, for example when moving from * development to production. *

    * All the methods in this class that read a stream are buffered internally. * This means that there is no cause to use a BufferedInputStream * or BufferedReader. The default buffer size of 4K has been shown * to be efficient in tests. *

    * Wherever possible, the methods in this class do not flush or close * the stream. This is to avoid making non-portable assumptions about the * streams' origin and further use. Thus the caller is still responsible for * closing streams after use. *

    * Origin of code: Excalibur. */ public class IOUtils { // NOTE: This class is focussed on InputStream, OutputStream, Reader and // Writer. Each method should take at least one of these as a parameter, // or return one of them. private static final int EOF = -1; /** * The default buffer size ({@value}) to use for * {@link #copyLarge(InputStream, OutputStream)} * and * {@link #copyLarge(Reader, Writer)} */ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; /** * Instances should NOT be constructed in standard programming. */ public IOUtils() { super(); } // copy from InputStream //----------------------------------------------------------------------- /** * Copy bytes from an InputStream to an * OutputStream. *

    * This method buffers the input internally, so there is no need to use a * BufferedInputStream. *

    * Large streams (over 2GB) will return a bytes copied value of * -1 after the copy has completed since the correct * number of bytes cannot be returned as an int. For large streams * use the copyLarge(InputStream, OutputStream) method. * * @param input the InputStream to read from * @param output the OutputStream to write to * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE * @throws NullPointerException if the input or output is null * @throws IOException if an I/O error occurs * @since 1.1 */ public static int copy(InputStream input, OutputStream output) throws IOException { long count = copyLarge(input, output); if (count > Integer.MAX_VALUE) { return -1; } return (int) count; } /** * Copy bytes from a large (over 2GB) InputStream to an * OutputStream. *

    * This method buffers the input internally, so there is no need to use a * BufferedInputStream. *

    * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. * * @param input the InputStream to read from * @param output the OutputStream to write to * @return the number of bytes copied * @throws NullPointerException if the input or output is null * @throws IOException if an I/O error occurs * @since 1.3 */ public static long copyLarge(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; long count = 0; int n = 0; while (EOF != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileUtils.java0000644000175100017510000002027412271447131026215 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; /** * General file manipulation utilities. *

    * Facilities are provided in the following areas: *

      *
    • writing to a file *
    • reading from a file *
    • make a directory including parent directories *
    • copying files and directories *
    • deleting files and directories *
    • converting to and from a URL *
    • listing files and directories by filter and extension *
    • comparing file content *
    • file last changed date *
    • calculating a checksum *
    *

    * Origin of code: Excalibur, Alexandria, Commons-Utils */ public class FileUtils { /** * Instances should NOT be constructed in standard programming. */ public FileUtils() { super(); } //----------------------------------------------------------------------- /** * Deletes a directory recursively. * * @param directory directory to delete * @throws IOException in case deletion is unsuccessful */ public static void deleteDirectory(File directory) throws IOException { if (!directory.exists()) { return; } if (!isSymlink(directory)) { cleanDirectory(directory); } if (!directory.delete()) { String message = "Unable to delete directory " + directory + "."; throw new IOException(message); } } /** * Cleans a directory without deleting it. * * @param directory directory to clean * @throws IOException in case cleaning is unsuccessful */ public static void cleanDirectory(File directory) throws IOException { if (!directory.exists()) { String message = directory + " does not exist"; throw new IllegalArgumentException(message); } if (!directory.isDirectory()) { String message = directory + " is not a directory"; throw new IllegalArgumentException(message); } File[] files = directory.listFiles(); if (files == null) { // null if security restricted throw new IOException("Failed to list contents of " + directory); } IOException exception = null; for (File file : files) { try { forceDelete(file); } catch (IOException ioe) { exception = ioe; } } if (null != exception) { throw exception; } } //----------------------------------------------------------------------- /** * Deletes a file. If file is a directory, delete it and all sub-directories. *

    * The difference between File.delete() and this method are: *

      *
    • A directory to be deleted does not have to be empty.
    • *
    • You get exceptions when a file or directory cannot be deleted. * (java.io.File methods returns a boolean)
    • *
    * * @param file file or directory to delete, must not be {@code null} * @throws NullPointerException if the directory is {@code null} * @throws FileNotFoundException if the file was not found * @throws IOException in case deletion is unsuccessful */ public static void forceDelete(File file) throws IOException { if (file.isDirectory()) { deleteDirectory(file); } else { boolean filePresent = file.exists(); if (!file.delete()) { if (!filePresent){ throw new FileNotFoundException("File does not exist: " + file); } String message = "Unable to delete file: " + file; throw new IOException(message); } } } /** * Schedules a file to be deleted when JVM exits. * If file is directory delete it and all sub-directories. * * @param file file or directory to delete, must not be {@code null} * @throws NullPointerException if the file is {@code null} * @throws IOException in case deletion is unsuccessful */ public static void forceDeleteOnExit(File file) throws IOException { if (file.isDirectory()) { deleteDirectoryOnExit(file); } else { file.deleteOnExit(); } } /** * Schedules a directory recursively for deletion on JVM exit. * * @param directory directory to delete, must not be {@code null} * @throws NullPointerException if the directory is {@code null} * @throws IOException in case deletion is unsuccessful */ private static void deleteDirectoryOnExit(File directory) throws IOException { if (!directory.exists()) { return; } directory.deleteOnExit(); if (!isSymlink(directory)) { cleanDirectoryOnExit(directory); } } /** * Cleans a directory without deleting it. * * @param directory directory to clean, must not be {@code null} * @throws NullPointerException if the directory is {@code null} * @throws IOException in case cleaning is unsuccessful */ private static void cleanDirectoryOnExit(File directory) throws IOException { if (!directory.exists()) { String message = directory + " does not exist"; throw new IllegalArgumentException(message); } if (!directory.isDirectory()) { String message = directory + " is not a directory"; throw new IllegalArgumentException(message); } File[] files = directory.listFiles(); if (files == null) { // null if security restricted throw new IOException("Failed to list contents of " + directory); } IOException exception = null; for (File file : files) { try { forceDeleteOnExit(file); } catch (IOException ioe) { exception = ioe; } } if (null != exception) { throw exception; } } /** * Determines whether the specified file is a Symbolic Link rather than an actual file. *

    * Will not return true if there is a Symbolic Link anywhere in the path, * only if the specific file is. *

    * Note: the current implementation always returns {@code false} if * the system is detected as Windows using * {@link File#separatorChar} == '\\' * * @param file the file to check * @return true if the file is a Symbolic Link * @throws IOException if an IO error occurs while checking the file * @since 2.0 */ public static boolean isSymlink(File file) throws IOException { if (file == null) { throw new NullPointerException("File must not be null"); } //FilenameUtils.isSystemWindows() if (File.separatorChar == '\\') { return false; } File fileInCanonicalDir = null; if (file.getParent() == null) { fileInCanonicalDir = file; } else { File canonicalDir = file.getParentFile().getCanonicalFile(); fileInCanonicalDir = new File(canonicalDir, file.getName()); } if (fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) { return false; } else { return true; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/ByteArrayOutputStream.java0000644000175100017510000002204712271447131030614 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; /** * This class implements an output stream in which the data is * written into a byte array. The buffer automatically grows as data * is written to it. *

    * The data can be retrieved using toByteArray() and * toString(). *

    * Closing a ByteArrayOutputStream has no effect. The methods in * this class can be called after the stream has been closed without * generating an IOException. *

    * This is an alternative implementation of the {@link java.io.ByteArrayOutputStream} * class. The original implementation only allocates 32 bytes at the beginning. * As this class is designed for heavy duty it starts at 1024 bytes. In contrast * to the original it doesn't reallocate the whole memory block but allocates * additional buffers. This way no buffers need to be garbage collected and * the contents don't have to be copied to the new buffer. This class is * designed to behave exactly like the original. The only exception is the * deprecated toString(int) method that has been ignored. */ public class ByteArrayOutputStream extends OutputStream { /** A singleton empty byte array. */ private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; /** The list of buffers, which grows and never reduces. */ private final List buffers = new ArrayList(); /** The index of the current buffer. */ private int currentBufferIndex; /** The total count of bytes in all the filled buffers. */ private int filledBufferSum; /** The current buffer. */ private byte[] currentBuffer; /** The total count of bytes written. */ private int count; /** * Creates a new byte array output stream. The buffer capacity is * initially 1024 bytes, though its size increases if necessary. */ public ByteArrayOutputStream() { this(1024); } /** * Creates a new byte array output stream, with a buffer capacity of * the specified size, in bytes. * * @param size the initial size * @throws IllegalArgumentException if size is negative */ public ByteArrayOutputStream(int size) { if (size < 0) { throw new IllegalArgumentException( "Negative initial size: " + size); } synchronized (this) { needNewBuffer(size); } } /** * Makes a new buffer available either by allocating * a new one or re-cycling an existing one. * * @param newcount the size of the buffer if one is created */ private void needNewBuffer(int newcount) { if (currentBufferIndex < buffers.size() - 1) { //Recycling old buffer filledBufferSum += currentBuffer.length; currentBufferIndex++; currentBuffer = buffers.get(currentBufferIndex); } else { //Creating new buffer int newBufferSize; if (currentBuffer == null) { newBufferSize = newcount; filledBufferSum = 0; } else { newBufferSize = Math.max( currentBuffer.length << 1, newcount - filledBufferSum); filledBufferSum += currentBuffer.length; } currentBufferIndex++; currentBuffer = new byte[newBufferSize]; buffers.add(currentBuffer); } } /** * Write the bytes to byte array. * @param b the bytes to write * @param off The start offset * @param len The number of bytes to write */ @Override public void write(byte[] b, int off, int len) { if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } synchronized (this) { int newcount = count + len; int remaining = len; int inBufferPos = count - filledBufferSum; while (remaining > 0) { int part = Math.min(remaining, currentBuffer.length - inBufferPos); System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part); remaining -= part; if (remaining > 0) { needNewBuffer(newcount); inBufferPos = 0; } } count = newcount; } } /** * Write a byte to byte array. * @param b the byte to write */ @Override public synchronized void write(int b) { int inBufferPos = count - filledBufferSum; if (inBufferPos == currentBuffer.length) { needNewBuffer(count + 1); inBufferPos = 0; } currentBuffer[inBufferPos] = (byte) b; count++; } /** * Writes the entire contents of the specified input stream to this * byte stream. Bytes from the input stream are read directly into the * internal buffers of this streams. * * @param in the input stream to read from * @return total number of bytes read from the input stream * (and written to this stream) * @throws IOException if an I/O error occurs while reading the input stream * @since 1.4 */ public synchronized int write(InputStream in) throws IOException { int readCount = 0; int inBufferPos = count - filledBufferSum; int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); while (n != -1) { readCount += n; inBufferPos += n; count += n; if (inBufferPos == currentBuffer.length) { needNewBuffer(currentBuffer.length); inBufferPos = 0; } n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); } return readCount; } /** * Closing a ByteArrayOutputStream has no effect. The methods in * this class can be called after the stream has been closed without * generating an IOException. * * @throws IOException never (this method should not declare this exception * but it has to now due to backwards compatability) */ @Override public void close() throws IOException { //nop } /** * Writes the entire contents of this byte stream to the * specified output stream. * * @param out the output stream to write to * @throws IOException if an I/O error occurs, such as if the stream is closed * @see java.io.ByteArrayOutputStream#writeTo(OutputStream) */ public synchronized void writeTo(OutputStream out) throws IOException { int remaining = count; for (byte[] buf : buffers) { int c = Math.min(buf.length, remaining); out.write(buf, 0, c); remaining -= c; if (remaining == 0) { break; } } } /** * Gets the curent contents of this byte stream as a byte array. * The result is independent of this stream. * * @return the current contents of this output stream, as a byte array * @see java.io.ByteArrayOutputStream#toByteArray() */ public synchronized byte[] toByteArray() { int remaining = count; if (remaining == 0) { return EMPTY_BYTE_ARRAY; } byte newbuf[] = new byte[remaining]; int pos = 0; for (byte[] buf : buffers) { int c = Math.min(buf.length, remaining); System.arraycopy(buf, 0, newbuf, pos, c); pos += c; remaining -= c; if (remaining == 0) { break; } } return newbuf; } /** * Gets the curent contents of this byte stream as a string. * @return the contents of the byte array as a String * @see java.io.ByteArrayOutputStream#toString() */ @Override public String toString() { return new String(toByteArray()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileItemFactory.java0000644000175100017510000000346012271447131027341 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; /** *

    A factory interface for creating {@link FileItem} instances. Factories * can provide their own custom configuration, over and above that provided * by the default file upload implementation.

    */ public interface FileItemFactory { /** * Create a new {@link FileItem} instance from the supplied parameters and * any local factory configuration. * * @param fieldName The name of the form field. * @param contentType The content type of the form field. * @param isFormField true if this is a plain form field; * false otherwise. * @param fileName The name of the uploaded file, if any, as supplied * by the browser or other client. * * @return The newly created file item. */ FileItem createItem( String fieldName, String contentType, boolean isFormField, String fileName ); } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/package-info.java0000644000175100017510000000760312271447131026642 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** *

    NOTE: This code has been copied from commons-fileupload trunk * 1.3 and commons-io 1.4 and package renamed to avoid clashes with * any web apps that may wish to use these libraries. *

    *

    * A component for handling HTML file uploads as specified by * RFC 1867. * This component provides support for uploads within both servlets (JSR 53) * and portlets (JSR 168). *

    *

    * While this package provides the generic functionality for file uploads, * these classes are not typically used directly. Instead, normal usage * involves one of the provided extensions of * {@link org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} such as * {@link org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload ServletFileUpload} * together with a factory for * {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} instances, * such as * {@link org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}. *

    *

    * The following is a brief example of typical usage in a servlet, storing * the uploaded files on disk. *

    *
    public void doPost(HttpServletRequest req, HttpServletResponse res) {
     *   DiskFileItemFactory factory = new DiskFileItemFactory();
     *   // maximum size that will be stored in memory
     *   factory.setSizeThreshold(4096);
     *   // the location for saving data that is larger than getSizeThreshold()
     *   factory.setRepository(new File("/tmp"));
     *
     *   ServletFileUpload upload = new ServletFileUpload(factory);
     *   // maximum size before a FileUploadException will be thrown
     *   upload.setSizeMax(1000000);
     *
     *   List fileItems = upload.parseRequest(req);
     *   // assume we know there are two files. The first file is a small
     *   // text file, the second is unknown and is written to a file on
     *   // the server
     *   Iterator i = fileItems.iterator();
     *   String comment = ((FileItem)i.next()).getString();
     *   FileItem fi = (FileItem)i.next();
     *   // filename on the client
     *   String fileName = fi.getName();
     *   // save comment and filename to database
     *   ...
     *   // write the file
     *   fi.write(new File("/www/uploads/", fileName));
     * }
     * 
    *

    * In the example above, the first file is loaded into memory as a * String. Before calling the getString method, * the data may have been in memory or on disk depending on its size. The * second file we assume it will be large and therefore never explicitly * load it into memory, though if it is less than 4096 bytes it will be * in memory before it is written to its final location. When writing to * the final location, if the data is larger than the threshold, an attempt * is made to rename the temporary file to the given location. If it cannot * be renamed, it is streamed to the new location. *

    *

    * Please see the FileUpload * User Guide * for further details and examples of how to use this package. *

    */ package org.apache.tomcat.util.http.fileupload; tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileItem.java0000644000175100017510000001670112271447131026013 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; /** *

    This class represents a file or form item that was received within a * multipart/form-data POST request. * *

    After retrieving an instance of this class from a {@link * org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} instance (see * {@link org.apache.tomcat.util.http.fileupload.FileUpload * #parseRequest(RequestContext)}), you may * either request all contents of the file at once using {@link #get()} or * request an {@link java.io.InputStream InputStream} with * {@link #getInputStream()} and process the file without attempting to load * it into memory, which may come handy with large files. * *

    While this interface does not extend * javax.activation.DataSource per se (to avoid a seldom used * dependency), several of the defined methods are specifically defined with * the same signatures as methods in that interface. This allows an * implementation of this interface to also implement * javax.activation.DataSource with minimal additional work. * * @since 1.3 additionally implements FileItemHeadersSupport */ public interface FileItem extends FileItemHeadersSupport { // ------------------------------- Methods from javax.activation.DataSource /** * Returns an {@link java.io.InputStream InputStream} that can be * used to retrieve the contents of the file. * * @return An {@link java.io.InputStream InputStream} that can be * used to retrieve the contents of the file. * * @throws IOException if an error occurs. */ InputStream getInputStream() throws IOException; /** * Returns the content type passed by the browser or null if * not defined. * * @return The content type passed by the browser or null if * not defined. */ String getContentType(); /** * Returns the original filename in the client's filesystem, as provided by * the browser (or other client software). In most cases, this will be the * base file name, without path information. However, some clients, such as * the Opera browser, do include path information. * * @return The original filename in the client's filesystem. * @throws InvalidFileNameException The file name contains a NUL character, * which might be an indicator of a security attack. If you intend to * use the file name anyways, catch the exception and use * InvalidFileNameException#getName(). */ String getName(); // ------------------------------------------------------- FileItem methods /** * Provides a hint as to whether or not the file contents will be read * from memory. * * @return true if the file contents will be read from memory; * false otherwise. */ boolean isInMemory(); /** * Returns the size of the file item. * * @return The size of the file item, in bytes. */ long getSize(); /** * Returns the contents of the file item as an array of bytes. * * @return The contents of the file item as an array of bytes. */ byte[] get(); /** * Returns the contents of the file item as a String, using the specified * encoding. This method uses {@link #get()} to retrieve the * contents of the item. * * @param encoding The character encoding to use. * * @return The contents of the item, as a string. * * @throws UnsupportedEncodingException if the requested character * encoding is not available. */ String getString(String encoding) throws UnsupportedEncodingException; /** * Returns the contents of the file item as a String, using the default * character encoding. This method uses {@link #get()} to retrieve the * contents of the item. * * @return The contents of the item, as a string. */ String getString(); /** * A convenience method to write an uploaded item to disk. The client code * is not concerned with whether or not the item is stored in memory, or on * disk in a temporary location. They just want to write the uploaded item * to a file. *

    * This method is not guaranteed to succeed if called more than once for * the same item. This allows a particular implementation to use, for * example, file renaming, where possible, rather than copying all of the * underlying data, thus gaining a significant performance benefit. * * @param file The File into which the uploaded item should * be stored. * * @throws Exception if an error occurs. */ void write(File file) throws Exception; /** * Deletes the underlying storage for a file item, including deleting any * associated temporary disk file. Although this storage will be deleted * automatically when the FileItem instance is garbage * collected, this method can be used to ensure that this is done at an * earlier time, thus preserving system resources. */ void delete(); /** * Returns the name of the field in the multipart form corresponding to * this file item. * * @return The name of the form field. */ String getFieldName(); /** * Sets the field name used to reference this file item. * * @param name The name of the form field. */ void setFieldName(String name); /** * Determines whether or not a FileItem instance represents * a simple form field. * * @return true if the instance represents a simple form * field; false if it represents an uploaded file. */ boolean isFormField(); /** * Specifies whether or not a FileItem instance represents * a simple form field. * * @param state true if the instance represents a simple form * field; false if it represents an uploaded file. */ void setFormField(boolean state); /** * Returns an {@link java.io.OutputStream OutputStream} that can * be used for storing the contents of the file. * * @return An {@link java.io.OutputStream OutputStream} that can be used * for storing the contensts of the file. * * @throws IOException if an error occurs. */ OutputStream getOutputStream() throws IOException; } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java0000644000175100017510000000541712271447131027311 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.util.Iterator; /** *

    This class provides support for accessing the headers for a file or form * item that was received within a multipart/form-data POST * request.

    * * @since 1.2.1 */ public interface FileItemHeaders { /** * Returns the value of the specified part header as a String. * * If the part did not include a header of the specified name, this method * return null. If there are multiple headers with the same * name, this method returns the first header in the item. The header * name is case insensitive. * * @param name a String specifying the header name * @return a String containing the value of the requested * header, or null if the item does not have a header * of that name */ String getHeader(String name); /** *

    * Returns all the values of the specified item header as an * Iterator of String objects. *

    *

    * If the item did not include any headers of the specified name, this * method returns an empty Iterator. The header name is * case insensitive. *

    * * @param name a String specifying the header name * @return an Iterator containing the values of the * requested header. If the item does not have any headers of * that name, return an empty Iterator */ Iterator getHeaders(String name); /** *

    * Returns an Iterator of all the header names. *

    * * @return an Iterator containing all of the names of * headers provided with this file item. If the item does not have * any headers return an empty Iterator */ Iterator getHeaderNames(); } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java0000644000175100017510000012376312274670043027146 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream; import org.apache.tomcat.util.http.fileupload.util.Closeable; import org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl; import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream; import org.apache.tomcat.util.http.fileupload.util.Streams; /** *

    High level API for processing file uploads.

    * *

    This class handles multiple files per single HTML widget, sent using * multipart/mixed encoding type, as specified by * RFC 1867. Use {@link * #parseRequest(RequestContext)} to acquire a list of {@link * org.apache.tomcat.util.http.fileupload.FileItem}s associated with a given HTML * widget.

    * *

    How the data for individual parts is stored is determined by the factory * used to create them; a given part may be in memory, on disk, or somewhere * else.

    */ public abstract class FileUploadBase { // ---------------------------------------------------------- Class methods private static final Charset CHARSET_ISO_8859_1 = Charset.forName("ISO-8859-1"); /** *

    Utility method that determines whether the request contains multipart * content.

    * *

    NOTE:This method will be moved to the * ServletFileUpload class after the FileUpload 1.1 release. * Unfortunately, since this method is static, it is not possible to * provide its replacement until this method is removed.

    * * @param ctx The request context to be evaluated. Must be non-null. * * @return true if the request is multipart; * false otherwise. */ public static final boolean isMultipartContent(RequestContext ctx) { String contentType = ctx.getContentType(); if (contentType == null) { return false; } if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) { return true; } return false; } // ----------------------------------------------------- Manifest constants /** * HTTP content type header name. */ public static final String CONTENT_TYPE = "Content-type"; /** * HTTP content disposition header name. */ public static final String CONTENT_DISPOSITION = "Content-disposition"; /** * HTTP content length header name. */ public static final String CONTENT_LENGTH = "Content-length"; /** * Content-disposition value for form data. */ public static final String FORM_DATA = "form-data"; /** * Content-disposition value for file attachment. */ public static final String ATTACHMENT = "attachment"; /** * Part of HTTP content type header. */ public static final String MULTIPART = "multipart/"; /** * HTTP content type header for multipart forms. */ public static final String MULTIPART_FORM_DATA = "multipart/form-data"; /** * HTTP content type header for multiple uploads. */ public static final String MULTIPART_MIXED = "multipart/mixed"; // ----------------------------------------------------------- Data members /** * The maximum size permitted for the complete request, as opposed to * {@link #fileSizeMax}. A value of -1 indicates no maximum. */ private long sizeMax = -1; /** * The maximum size permitted for a single uploaded file, as opposed * to {@link #sizeMax}. A value of -1 indicates no maximum. */ private long fileSizeMax = -1; /** * The content encoding to use when reading part headers. */ private String headerEncoding; /** * The progress listener. */ private ProgressListener listener; // ----------------------------------------------------- Property accessors /** * Returns the factory class used when creating file items. * * @return The factory class for new file items. */ public abstract FileItemFactory getFileItemFactory(); /** * Sets the factory class to use when creating file items. * * @param factory The factory class for new file items. */ public abstract void setFileItemFactory(FileItemFactory factory); /** * Returns the maximum allowed size of a complete request, as opposed * to {@link #getFileSizeMax()}. * * @return The maximum allowed size, in bytes. The default value of * -1 indicates, that there is no limit. * * @see #setSizeMax(long) * */ public long getSizeMax() { return sizeMax; } /** * Sets the maximum allowed size of a complete request, as opposed * to {@link #setFileSizeMax(long)}. * * @param sizeMax The maximum allowed size, in bytes. The default value of * -1 indicates, that there is no limit. * * @see #getSizeMax() * */ public void setSizeMax(long sizeMax) { this.sizeMax = sizeMax; } /** * Returns the maximum allowed size of a single uploaded file, * as opposed to {@link #getSizeMax()}. * * @see #setFileSizeMax(long) * @return Maximum size of a single uploaded file. */ public long getFileSizeMax() { return fileSizeMax; } /** * Sets the maximum allowed size of a single uploaded file, * as opposed to {@link #getSizeMax()}. * * @see #getFileSizeMax() * @param fileSizeMax Maximum size of a single uploaded file. */ public void setFileSizeMax(long fileSizeMax) { this.fileSizeMax = fileSizeMax; } /** * Retrieves the character encoding used when reading the headers of an * individual part. When not specified, or null, the request * encoding is used. If that is also not specified, or null, * the platform default encoding is used. * * @return The encoding used to read part headers. */ public String getHeaderEncoding() { return headerEncoding; } /** * Specifies the character encoding to be used when reading the headers of * individual part. When not specified, or null, the request * encoding is used. If that is also not specified, or null, * the platform default encoding is used. * * @param encoding The encoding used to read part headers. */ public void setHeaderEncoding(String encoding) { headerEncoding = encoding; } // --------------------------------------------------------- Public methods /** * Processes an RFC 1867 * compliant multipart/form-data stream. * * @param ctx The context for the request to be parsed. * * @return An iterator to instances of FileItemStream * parsed from the request, in the order that they were * transmitted. * * @throws FileUploadException if there are problems reading/parsing * the request or storing files. * @throws IOException An I/O error occurred. This may be a network * error while communicating with the client or a problem while * storing the uploaded content. */ public FileItemIterator getItemIterator(RequestContext ctx) throws FileUploadException, IOException { try { return new FileItemIteratorImpl(ctx); } catch (FileUploadIOException e) { // unwrap encapsulated SizeException throw (FileUploadException) e.getCause(); } } /** * Processes an RFC 1867 * compliant multipart/form-data stream. * * @param ctx The context for the request to be parsed. * * @return A list of FileItem instances parsed from the * request, in the order that they were transmitted. * * @throws FileUploadException if there are problems reading/parsing * the request or storing files. */ public List parseRequest(RequestContext ctx) throws FileUploadException { List items = new ArrayList(); boolean successful = false; try { FileItemIterator iter = getItemIterator(ctx); FileItemFactory fac = getFileItemFactory(); if (fac == null) { throw new NullPointerException("No FileItemFactory has been set."); } while (iter.hasNext()) { final FileItemStream item = iter.next(); // Don't use getName() here to prevent an InvalidFileNameException. final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name; FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName); items.add(fileItem); try { Streams.copy(item.openStream(), fileItem.getOutputStream(), true); } catch (FileUploadIOException e) { throw (FileUploadException) e.getCause(); } catch (IOException e) { throw new IOFileUploadException(String.format("Processing of %s request failed. %s", MULTIPART_FORM_DATA, e.getMessage()), e); } final FileItemHeaders fih = item.getHeaders(); fileItem.setHeaders(fih); } successful = true; return items; } catch (FileUploadIOException e) { throw (FileUploadException) e.getCause(); } catch (IOException e) { throw new FileUploadException(e.getMessage(), e); } finally { if (!successful) { for (FileItem fileItem : items) { try { fileItem.delete(); } catch (Exception e) { // ignore it } } } } } /** * Processes an RFC 1867 * compliant multipart/form-data stream. * * @param ctx The context for the request to be parsed. * * @return A map of FileItem instances parsed from the request. * * @throws FileUploadException if there are problems reading/parsing * the request or storing files. * * @since 1.3 */ public Map> parseParameterMap(RequestContext ctx) throws FileUploadException { final List items = parseRequest(ctx); final Map> itemsMap = new HashMap>(items.size()); for (FileItem fileItem : items) { String fieldName = fileItem.getFieldName(); List mappedItems = itemsMap.get(fieldName); if (mappedItems == null) { mappedItems = new ArrayList(); itemsMap.put(fieldName, mappedItems); } mappedItems.add(fileItem); } return itemsMap; } // ------------------------------------------------------ Protected methods /** * Retrieves the boundary from the Content-type header. * * @param contentType The value of the content type header from which to * extract the boundary value. * * @return The boundary, as a byte array. */ protected byte[] getBoundary(String contentType) { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = parser.parse(contentType, new char[] {';', ','}); String boundaryStr = params.get("boundary"); if (boundaryStr == null) { return null; } byte[] boundary; boundary = boundaryStr.getBytes(CHARSET_ISO_8859_1); return boundary; } /** * Retrieves the file name from the Content-disposition * header. * * @param headers The HTTP headers object. * * @return The file name for the current encapsulation. */ protected String getFileName(FileItemHeaders headers) { return getFileName(headers.getHeader(CONTENT_DISPOSITION)); } /** * Returns the given content-disposition headers file name. * @param pContentDisposition The content-disposition headers value. * @return The file name */ private String getFileName(String pContentDisposition) { String fileName = null; if (pContentDisposition != null) { String cdl = pContentDisposition.toLowerCase(Locale.ENGLISH); if (cdl.startsWith(FORM_DATA) || cdl.startsWith(ATTACHMENT)) { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = parser.parse(pContentDisposition, ';'); if (params.containsKey("filename")) { fileName = params.get("filename"); if (fileName != null) { fileName = fileName.trim(); } else { // Even if there is no value, the parameter is present, // so we return an empty file name rather than no file // name. fileName = ""; } } } } return fileName; } /** * Retrieves the field name from the Content-disposition * header. * * @param headers A Map containing the HTTP request headers. * * @return The field name for the current encapsulation. */ protected String getFieldName(FileItemHeaders headers) { return getFieldName(headers.getHeader(CONTENT_DISPOSITION)); } /** * Returns the field name, which is given by the content-disposition * header. * @param pContentDisposition The content-dispositions header value. * @return The field jake */ private String getFieldName(String pContentDisposition) { String fieldName = null; if (pContentDisposition != null && pContentDisposition.toLowerCase(Locale.ENGLISH).startsWith(FORM_DATA)) { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = parser.parse(pContentDisposition, ';'); fieldName = params.get("name"); if (fieldName != null) { fieldName = fieldName.trim(); } } return fieldName; } /** *

    Parses the header-part and returns as key/value * pairs. * *

    If there are multiple headers of the same names, the name * will map to a comma-separated list containing the values. * * @param headerPart The header-part of the current * encapsulation. * * @return A Map containing the parsed HTTP request headers. */ protected FileItemHeaders getParsedHeaders(String headerPart) { final int len = headerPart.length(); FileItemHeadersImpl headers = newFileItemHeaders(); int start = 0; for (;;) { int end = parseEndOfLine(headerPart, start); if (start == end) { break; } StringBuilder header = new StringBuilder(headerPart.substring(start, end)); start = end + 2; while (start < len) { int nonWs = start; while (nonWs < len) { char c = headerPart.charAt(nonWs); if (c != ' ' && c != '\t') { break; } ++nonWs; } if (nonWs == start) { break; } // Continuation line found end = parseEndOfLine(headerPart, nonWs); header.append(" ").append(headerPart.substring(nonWs, end)); start = end + 2; } parseHeaderLine(headers, header.toString()); } return headers; } /** * Creates a new instance of {@link FileItemHeaders}. * @return The new instance. */ protected FileItemHeadersImpl newFileItemHeaders() { return new FileItemHeadersImpl(); } /** * Skips bytes until the end of the current line. * @param headerPart The headers, which are being parsed. * @param end Index of the last byte, which has yet been * processed. * @return Index of the \r\n sequence, which indicates * end of line. */ private int parseEndOfLine(String headerPart, int end) { int index = end; for (;;) { int offset = headerPart.indexOf('\r', index); if (offset == -1 || offset + 1 >= headerPart.length()) { throw new IllegalStateException( "Expected headers to be terminated by an empty line."); } if (headerPart.charAt(offset + 1) == '\n') { return offset; } index = offset + 1; } } /** * Reads the next header line. * @param headers String with all headers. * @param header Map where to store the current header. */ private void parseHeaderLine(FileItemHeadersImpl headers, String header) { final int colonOffset = header.indexOf(':'); if (colonOffset == -1) { // This header line is malformed, skip it. return; } String headerName = header.substring(0, colonOffset).trim(); String headerValue = header.substring(header.indexOf(':') + 1).trim(); headers.addHeader(headerName, headerValue); } /** * The iterator, which is returned by * {@link FileUploadBase#getItemIterator(RequestContext)}. */ private class FileItemIteratorImpl implements FileItemIterator { /** * Default implementation of {@link FileItemStream}. */ class FileItemStreamImpl implements FileItemStream { /** * The file items content type. */ private final String contentType; /** * The file items field name. */ private final String fieldName; /** * The file items file name. */ private final String name; /** * Whether the file item is a form field. */ private final boolean formField; /** * The file items input stream. */ private final InputStream stream; /** * Whether the file item was already opened. */ private boolean opened; /** * The headers, if any. */ private FileItemHeaders headers; /** * Creates a new instance. * * @param pName The items file name, or null. * @param pFieldName The items field name. * @param pContentType The items content type, or null. * @param pFormField Whether the item is a form field. * @param pContentLength The items content length, if known, or -1 * @throws IOException Creating the file item failed. */ FileItemStreamImpl(String pName, String pFieldName, String pContentType, boolean pFormField, long pContentLength) throws IOException { name = pName; fieldName = pFieldName; contentType = pContentType; formField = pFormField; final ItemInputStream itemStream = multi.newInputStream(); InputStream istream = itemStream; if (fileSizeMax != -1) { if (pContentLength != -1 && pContentLength > fileSizeMax) { FileSizeLimitExceededException e = new FileSizeLimitExceededException( String.format("The field %s exceeds its maximum permitted size of %s bytes.", fieldName, Long.valueOf(fileSizeMax)), pContentLength, fileSizeMax); e.setFileName(pName); e.setFieldName(pFieldName); throw new FileUploadIOException(e); } istream = new LimitedInputStream(istream, fileSizeMax) { @Override protected void raiseError(long pSizeMax, long pCount) throws IOException { itemStream.close(true); FileSizeLimitExceededException e = new FileSizeLimitExceededException( String.format("The field %s exceeds its maximum permitted size of %s bytes.", fieldName, Long.valueOf(pSizeMax)), pCount, pSizeMax); e.setFieldName(fieldName); e.setFileName(name); throw new FileUploadIOException(e); } }; } stream = istream; } /** * Returns the items content type, or null. * * @return Content type, if known, or null. */ @Override public String getContentType() { return contentType; } /** * Returns the items field name. * * @return Field name. */ @Override public String getFieldName() { return fieldName; } /** * Returns the items file name. * * @return File name, if known, or null. * @throws InvalidFileNameException The file name contains a NUL character, * which might be an indicator of a security attack. If you intend to * use the file name anyways, catch the exception and use * InvalidFileNameException#getName(). */ @Override public String getName() { return Streams.checkFileName(name); } /** * Returns, whether this is a form field. * * @return True, if the item is a form field, * otherwise false. */ @Override public boolean isFormField() { return formField; } /** * Returns an input stream, which may be used to * read the items contents. * * @return Opened input stream. * @throws IOException An I/O error occurred. */ @Override public InputStream openStream() throws IOException { if (opened) { throw new IllegalStateException( "The stream was already opened."); } if (((Closeable) stream).isClosed()) { throw new FileItemStream.ItemSkippedException(); } return stream; } /** * Closes the file item. * * @throws IOException An I/O error occurred. */ void close() throws IOException { stream.close(); } /** * Returns the file item headers. * * @return The items header object */ @Override public FileItemHeaders getHeaders() { return headers; } /** * Sets the file item headers. * * @param pHeaders The items header object */ @Override public void setHeaders(FileItemHeaders pHeaders) { headers = pHeaders; } } /** * The multi part stream to process. */ private final MultipartStream multi; /** * The notifier, which used for triggering the * {@link ProgressListener}. */ private final MultipartStream.ProgressNotifier notifier; /** * The boundary, which separates the various parts. */ private final byte[] boundary; /** * The item, which we currently process. */ private FileItemStreamImpl currentItem; /** * The current items field name. */ private String currentFieldName; /** * Whether we are currently skipping the preamble. */ private boolean skipPreamble; /** * Whether the current item may still be read. */ private boolean itemValid; /** * Whether we have seen the end of the file. */ private boolean eof; /** * Creates a new instance. * * @param ctx The request context. * @throws FileUploadException An error occurred while * parsing the request. * @throws IOException An I/O error occurred. */ FileItemIteratorImpl(RequestContext ctx) throws FileUploadException, IOException { if (ctx == null) { throw new NullPointerException("ctx parameter"); } String contentType = ctx.getContentType(); if ((null == contentType) || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) { throw new InvalidContentTypeException(String.format( "the request doesn't contain a %s or %s stream, content type header is %s", MULTIPART_FORM_DATA, MULTIPART_MIXED, contentType)); } InputStream input = ctx.getInputStream(); final long requestSize = ((UploadContext) ctx).contentLength(); if (sizeMax >= 0) { if (requestSize != -1 && requestSize > sizeMax) { throw new SizeLimitExceededException(String.format( "the request was rejected because its size (%s) exceeds the configured maximum (%s)", Long.valueOf(requestSize), Long.valueOf(sizeMax)), requestSize, sizeMax); } input = new LimitedInputStream(input, sizeMax) { @Override protected void raiseError(long pSizeMax, long pCount) throws IOException { FileUploadException ex = new SizeLimitExceededException( String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)", Long.valueOf(pCount), Long.valueOf(pSizeMax)), pCount, pSizeMax); throw new FileUploadIOException(ex); } }; } String charEncoding = headerEncoding; if (charEncoding == null) { charEncoding = ctx.getCharacterEncoding(); } boundary = getBoundary(contentType); if (boundary == null) { throw new FileUploadException("the request was rejected because no multipart boundary was found"); } notifier = new MultipartStream.ProgressNotifier(listener, requestSize); try { multi = new MultipartStream(input, boundary, notifier); } catch (IllegalArgumentException iae) { throw new InvalidContentTypeException(String.format( "The boundary specified in the %s header is too long", CONTENT_TYPE), iae); } multi.setHeaderEncoding(charEncoding); skipPreamble = true; findNextItem(); } /** * Called for finding the next item, if any. * * @return True, if an next item was found, otherwise false. * @throws IOException An I/O error occurred. */ private boolean findNextItem() throws IOException { if (eof) { return false; } if (currentItem != null) { currentItem.close(); currentItem = null; } for (;;) { boolean nextPart; if (skipPreamble) { nextPart = multi.skipPreamble(); } else { nextPart = multi.readBoundary(); } if (!nextPart) { if (currentFieldName == null) { // Outer multipart terminated -> No more data eof = true; return false; } // Inner multipart terminated -> Return to parsing the outer multi.setBoundary(boundary); currentFieldName = null; continue; } FileItemHeaders headers = getParsedHeaders(multi.readHeaders()); if (currentFieldName == null) { // We're parsing the outer multipart String fieldName = getFieldName(headers); if (fieldName != null) { String subContentType = headers.getHeader(CONTENT_TYPE); if (subContentType != null && subContentType.toLowerCase(Locale.ENGLISH) .startsWith(MULTIPART_MIXED)) { currentFieldName = fieldName; // Multiple files associated with this field name byte[] subBoundary = getBoundary(subContentType); multi.setBoundary(subBoundary); skipPreamble = true; continue; } String fileName = getFileName(headers); currentItem = new FileItemStreamImpl(fileName, fieldName, headers.getHeader(CONTENT_TYPE), fileName == null, getContentLength(headers)); currentItem.setHeaders(headers); notifier.noteItem(); itemValid = true; return true; } } else { String fileName = getFileName(headers); if (fileName != null) { currentItem = new FileItemStreamImpl(fileName, currentFieldName, headers.getHeader(CONTENT_TYPE), false, getContentLength(headers)); currentItem.setHeaders(headers); notifier.noteItem(); itemValid = true; return true; } } multi.discardBodyData(); } } private long getContentLength(FileItemHeaders pHeaders) { try { return Long.parseLong(pHeaders.getHeader(CONTENT_LENGTH)); } catch (Exception e) { return -1; } } /** * Returns, whether another instance of {@link FileItemStream} * is available. * * @throws FileUploadException Parsing or processing the * file item failed. * @throws IOException Reading the file item failed. * @return True, if one or more additional file items * are available, otherwise false. */ @Override public boolean hasNext() throws FileUploadException, IOException { if (eof) { return false; } if (itemValid) { return true; } try { return findNextItem(); } catch (FileUploadIOException e) { // unwrap encapsulated SizeException throw (FileUploadException) e.getCause(); } } /** * Returns the next available {@link FileItemStream}. * * @throws java.util.NoSuchElementException No more items are * available. Use {@link #hasNext()} to prevent this exception. * @throws FileUploadException Parsing or processing the * file item failed. * @throws IOException Reading the file item failed. * @return FileItemStream instance, which provides * access to the next file item. */ @Override public FileItemStream next() throws FileUploadException, IOException { if (eof || (!itemValid && !hasNext())) { throw new NoSuchElementException(); } itemValid = false; return currentItem; } } /** * This exception is thrown for hiding an inner * {@link FileUploadException} in an {@link IOException}. */ public static class FileUploadIOException extends IOException { private static final long serialVersionUID = -3082868232248803474L; public FileUploadIOException() { super(); } public FileUploadIOException(String message, Throwable cause) { super(message, cause); } public FileUploadIOException(String message) { super(message); } public FileUploadIOException(Throwable cause) { super(cause); } } /** * Thrown to indicate that the request is not a multipart request. */ public static class InvalidContentTypeException extends FileUploadException { /** * The exceptions UID, for serializing an instance. */ private static final long serialVersionUID = -9073026332015646668L; /** * Constructs a InvalidContentTypeException with no * detail message. */ public InvalidContentTypeException() { super(); } /** * Constructs an InvalidContentTypeException with * the specified detail message. * * @param message The detail message. */ public InvalidContentTypeException(String message) { super(message); } public InvalidContentTypeException(String msg, Throwable cause) { super(msg, cause); } } /** * Thrown to indicate an IOException. */ public static class IOFileUploadException extends FileUploadException { private static final long serialVersionUID = -5858565745868986701L; public IOFileUploadException() { super(); } public IOFileUploadException(String message, Throwable cause) { super(message, cause); } public IOFileUploadException(String message) { super(message); } public IOFileUploadException(Throwable cause) { super(cause); } } /** * This exception is thrown, if a requests permitted size * is exceeded. */ public abstract static class SizeException extends FileUploadException { /** * Serial version UID, being used, if serialized. */ private static final long serialVersionUID = -8776225574705254126L; /** * The actual size of the request. */ private final long actual; /** * The maximum permitted size of the request. */ private final long permitted; /** * Creates a new instance. * * @param message The detail message. * @param actual The actual number of bytes in the request. * @param permitted The requests size limit, in bytes. */ protected SizeException(String message, long actual, long permitted) { super(message); this.actual = actual; this.permitted = permitted; } /** * Retrieves the actual size of the request. * * @return The actual size of the request. * @since 1.3 */ public long getActualSize() { return actual; } /** * Retrieves the permitted size of the request. * * @return The permitted size of the request. * @since 1.3 */ public long getPermittedSize() { return permitted; } } /** * Thrown to indicate that the request size exceeds the configured maximum. */ public static class SizeLimitExceededException extends SizeException { /** * The exceptions UID, for serializing an instance. */ private static final long serialVersionUID = -2474893167098052828L; /** * Constructs a SizeExceededException with * the specified detail message, and actual and permitted sizes. * * @param message The detail message. * @param actual The actual request size. * @param permitted The maximum permitted request size. */ public SizeLimitExceededException(String message, long actual, long permitted) { super(message, actual, permitted); } } /** * Thrown to indicate that A files size exceeds the configured maximum. */ public static class FileSizeLimitExceededException extends SizeException { /** * The exceptions UID, for serializing an instance. */ private static final long serialVersionUID = 8150776562029630058L; /** * File name of the item, which caused the exception. */ private String fileName; /** * Field name of the item, which caused the exception. */ private String fieldName; /** * Constructs a SizeExceededException with * the specified detail message, and actual and permitted sizes. * * @param message The detail message. * @param actual The actual request size. * @param permitted The maximum permitted request size. */ public FileSizeLimitExceededException(String message, long actual, long permitted) { super(message, actual, permitted); } /** * Returns the file name of the item, which caused the * exception. * * @return File name, if known, or null. */ public String getFileName() { return fileName; } /** * Sets the file name of the item, which caused the * exception. * * @param pFileName the file name of the item, which caused the exception. */ public void setFileName(String pFileName) { fileName = pFileName; } /** * Returns the field name of the item, which caused the * exception. * * @return Field name, if known, or null. */ public String getFieldName() { return fieldName; } /** * Sets the field name of the item, which caused the * exception. * * @param pFieldName the field name of the item, * which caused the exception. */ public void setFieldName(String pFieldName) { fieldName = pFieldName; } } /** * Returns the progress listener. * * @return The progress listener, if any, or null. */ public ProgressListener getProgressListener() { return listener; } /** * Sets the progress listener. * * @param pListener The progress listener, if any. Defaults to null. */ public void setProgressListener(ProgressListener pListener) { listener = pListener; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/0000755000175100017510000000000012301126367024421 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java0000644000175100017510000001266212271447131031057 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.util; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /** * An input stream, which limits its data size. This stream is * used, if the content length is unknown. */ public abstract class LimitedInputStream extends FilterInputStream implements Closeable { /** * The maximum size of an item, in bytes. */ private final long sizeMax; /** * The current number of bytes. */ private long count; /** * Whether this stream is already closed. */ private boolean closed; /** * Creates a new instance. * * @param pIn The input stream, which shall be limited. * @param pSizeMax The limit; no more than this number of bytes * shall be returned by the source stream. */ public LimitedInputStream(InputStream pIn, long pSizeMax) { super(pIn); sizeMax = pSizeMax; } /** * Called to indicate, that the input streams limit has * been exceeded. * * @param pSizeMax The input streams limit, in bytes. * @param pCount The actual number of bytes. * @throws IOException The called method is expected * to raise an IOException. */ protected abstract void raiseError(long pSizeMax, long pCount) throws IOException; /** * Called to check, whether the input streams * limit is reached. * * @throws IOException The given limit is exceeded. */ private void checkLimit() throws IOException { if (count > sizeMax) { raiseError(sizeMax, count); } } /** * Reads the next byte of data from this input stream. The value * byte is returned as an int in the range * 0 to 255. If no byte is available * because the end of the stream has been reached, the value * -1 is returned. This method blocks until input data * is available, the end of the stream is detected, or an exception * is thrown. *

    * This method * simply performs in.read() and returns the result. * * @return the next byte of data, or -1 if the end of the * stream is reached. * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override public int read() throws IOException { int res = super.read(); if (res != -1) { count++; checkLimit(); } return res; } /** * Reads up to len bytes of data from this input stream * into an array of bytes. If len is not zero, the method * blocks until some input is available; otherwise, no * bytes are read and 0 is returned. *

    * This method simply performs in.read(b, off, len) * and returns the result. * * @param b the buffer into which the data is read. * @param off The start offset in the destination array * b. * @param len the maximum number of bytes read. * @return the total number of bytes read into the buffer, or * -1 if there is no more data because the end of * the stream has been reached. * @exception NullPointerException If b is null. * @exception IndexOutOfBoundsException If off is negative, * len is negative, or len is greater than * b.length - off * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override public int read(byte[] b, int off, int len) throws IOException { int res = super.read(b, off, len); if (res > 0) { count += res; checkLimit(); } return res; } /** * Returns, whether this stream is already closed. * * @return True, if the stream is closed, otherwise false. * @throws IOException An I/O error occurred. */ @Override public boolean isClosed() throws IOException { return closed; } /** * Closes this input stream and releases any system resources * associated with the stream. * This * method simply performs in.close(). * * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override public void close() throws IOException { closed = true; super.close(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/Streams.java0000644000175100017510000001627112271447131026712 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.tomcat.util.http.fileupload.InvalidFileNameException; /** * Utility class for working with streams. */ public final class Streams { /** * Private constructor, to prevent instantiation. * This class has only static methods. */ private Streams() { // Does nothing } /** * Default buffer size for use in * {@link #copy(InputStream, OutputStream, boolean)}. */ private static final int DEFAULT_BUFFER_SIZE = 8192; /** * Copies the contents of the given {@link InputStream} * to the given {@link OutputStream}. Shortcut for *

         *   copy(pInputStream, pOutputStream, new byte[8192]);
         * 
    * * @param pInputStream The input stream, which is being read. * It is guaranteed, that {@link InputStream#close()} is called * on the stream. * @param pOutputStream The output stream, to which data should * be written. May be null, in which case the input streams * contents are simply discarded. * @param pClose True guarantees, that {@link OutputStream#close()} * is called on the stream. False indicates, that only * {@link OutputStream#flush()} should be called finally. * * @return Number of bytes, which have been copied. * @throws IOException An I/O error occurred. */ public static long copy(InputStream pInputStream, OutputStream pOutputStream, boolean pClose) throws IOException { return copy(pInputStream, pOutputStream, pClose, new byte[DEFAULT_BUFFER_SIZE]); } /** * Copies the contents of the given {@link InputStream} * to the given {@link OutputStream}. * * @param pIn The input stream, which is being read. * It is guaranteed, that {@link InputStream#close()} is called * on the stream. * @param pOut The output stream, to which data should * be written. May be null, in which case the input streams * contents are simply discarded. * @param pClose True guarantees, that {@link OutputStream#close()} * is called on the stream. False indicates, that only * {@link OutputStream#flush()} should be called finally. * @param pBuffer Temporary buffer, which is to be used for * copying data. * @return Number of bytes, which have been copied. * @throws IOException An I/O error occurred. */ public static long copy(InputStream pIn, OutputStream pOut, boolean pClose, byte[] pBuffer) throws IOException { OutputStream out = pOut; InputStream in = pIn; try { long total = 0; for (;;) { int res = in.read(pBuffer); if (res == -1) { break; } if (res > 0) { total += res; if (out != null) { out.write(pBuffer, 0, res); } } } if (out != null) { if (pClose) { out.close(); } else { out.flush(); } out = null; } in.close(); in = null; return total; } finally { if (in != null) { try { in.close(); } catch (IOException ioe) { /* Ignore me */ } } if (pClose && out != null) { try { out.close(); } catch (IOException ioe) { /* Ignore me */ } } } } /** * This convenience method allows to read a * {@link org.apache.tomcat.util.http.fileupload.FileItemStream}'s * content into a string. The platform's default character encoding * is used for converting bytes into characters. * * @param pStream The input stream to read. * @see #asString(InputStream, String) * @return The streams contents, as a string. * @throws IOException An I/O error occurred. */ public static String asString(InputStream pStream) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); copy(pStream, baos, true); return baos.toString(); } /** * This convenience method allows to read a * {@link org.apache.tomcat.util.http.fileupload.FileItemStream}'s * content into a string, using the given character encoding. * * @param pStream The input stream to read. * @param pEncoding The character encoding, typically "UTF-8". * @see #asString(InputStream) * @return The streams contents, as a string. * @throws IOException An I/O error occurred. */ public static String asString(InputStream pStream, String pEncoding) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); copy(pStream, baos, true); return baos.toString(pEncoding); } /** * Checks, whether the given file name is valid in the sense, * that it doesn't contain any NUL characters. If the file name * is valid, it will be returned without any modifications. Otherwise, * an {@link InvalidFileNameException} is raised. * * @param pFileName The file name to check * @return Unmodified file name, if valid. * @throws InvalidFileNameException The file name was found to be invalid. */ public static String checkFileName(String pFileName) { if (pFileName != null && pFileName.indexOf('\u0000') != -1) { // pFileName.replace("\u0000", "\\0") final StringBuilder sb = new StringBuilder(); for (int i = 0; i < pFileName.length(); i++) { char c = pFileName.charAt(i); switch (c) { case 0: sb.append("\\0"); break; default: sb.append(c); break; } } throw new InvalidFileNameException(pFileName, "Invalid file name: " + sb); } return pFileName; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java0000644000175100017510000000250112271447131027154 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.util; import java.io.IOException; /** * Interface of an object, which may be closed. */ public interface Closeable { /** * Closes the object. * * @throws IOException An I/O error occurred. */ void close() throws IOException; /** * Returns, whether the object is already closed. * * @return True, if the object is closed, otherwise false. * @throws IOException An I/O error occurred. */ boolean isClosed() throws IOException; } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/mime/0000755000175100017510000000000012301126367025350 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java0000644000175100017510000000240512271447131031146 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.util.mime; /** * @since 1.3 */ final class ParseException extends Exception { /** * The UID to use when serializing this instance. */ private static final long serialVersionUID = 5355281266579392077L; /** * Constructs a new exception with the specified detail message. * * @param message the detail message. */ public ParseException(String message) { super(message); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/mime/package-info.java0000644000175100017510000000202712271447131030541 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** * MIME decoder implementation, imported and retailed from * Apache Geronimo. */ package org.apache.tomcat.util.http.fileupload.util.mime; tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java0000644000175100017510000001004412271447131032603 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.util.mime; import java.io.IOException; import java.io.OutputStream; /** * @since 1.3 */ final class QuotedPrintableDecoder { /** * The shift value required to create the upper nibble * from the first of 2 byte values converted from ascii hex. */ private static final int UPPER_NIBBLE_SHIFT = Byte.SIZE / 2; /** * Hidden constructor, this class must not be instantiated. */ private QuotedPrintableDecoder() { // do nothing } /** * Decode the encoded byte data writing it to the given output stream. * * @param data The array of byte data to decode. * @param out The output stream used to return the decoded data. * * @return the number of bytes produced. * @exception IOException */ public static int decode(byte[] data, OutputStream out) throws IOException { int off = 0; int length = data.length; int endOffset = off + length; int bytesWritten = 0; while (off < endOffset) { byte ch = data[off++]; // space characters were translated to '_' on encode, so we need to translate them back. if (ch == '_') { out.write(' '); } else if (ch == '=') { // we found an encoded character. Reduce the 3 char sequence to one. // but first, make sure we have two characters to work with. if (off + 1 >= endOffset) { throw new IOException("Invalid quoted printable encoding; truncated escape sequence"); } byte b1 = data[off++]; byte b2 = data[off++]; // we've found an encoded carriage return. The next char needs to be a newline if (b1 == '\r') { if (b2 != '\n') { throw new IOException("Invalid quoted printable encoding; CR must be followed by LF"); } // this was a soft linebreak inserted by the encoding. We just toss this away // on decode. } else { // this is a hex pair we need to convert back to a single byte. int c1 = hexToBinary(b1); int c2 = hexToBinary(b2); out.write((c1 << UPPER_NIBBLE_SHIFT) | c2); // 3 bytes in, one byte out bytesWritten++; } } else { // simple character, just write it out. out.write(ch); bytesWritten++; } } return bytesWritten; } /** * Convert a hex digit to the binary value it represents. * * @param b the ascii hex byte to convert (0-0, A-F, a-f) * @return the int value of the hex byte, 0-15 * @throws IOException if the byte is not a valid hex digit. */ private static int hexToBinary(final byte b) throws IOException { // CHECKSTYLE IGNORE MagicNumber FOR NEXT 1 LINE final int i = Character.digit((char) b, 16); if (i == -1) { throw new IOException("Invalid quoted printable encoding: not a valid hex digit: " + b); } return i; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java0000644000175100017510000002531612271447131030476 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.util.mime; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apache.tomcat.util.codec.binary.Base64; /** * Utility class to decode MIME texts. * * @since 1.3 */ public final class MimeUtility { /** * The {@code US-ASCII} charset identifier constant. */ private static final String US_ASCII_CHARSET = "US-ASCII"; /** * The marker to indicate text is encoded with BASE64 algorithm. */ private static final String BASE64_ENCODING_MARKER = "B"; /** * The marker to indicate text is encoded with QuotedPrintable algorithm. */ private static final String QUOTEDPRINTABLE_ENCODING_MARKER = "Q"; /** * If the text contains any encoded tokens, those tokens will be marked with "=?". */ private static final String ENCODED_TOKEN_MARKER = "=?"; /** * If the text contains any encoded tokens, those tokens will terminate with "=?". */ private static final String ENCODED_TOKEN_FINISHER = "?="; /** * The linear whitespace chars sequence. */ private static final String LINEAR_WHITESPACE = " \t\r\n"; /** * Mappings between MIME and Java charset. */ private static final Map MIME2JAVA = new HashMap(); static { MIME2JAVA.put("iso-2022-cn", "ISO2022CN"); MIME2JAVA.put("iso-2022-kr", "ISO2022KR"); MIME2JAVA.put("utf-8", "UTF8"); MIME2JAVA.put("utf8", "UTF8"); MIME2JAVA.put("ja_jp.iso2022-7", "ISO2022JP"); MIME2JAVA.put("ja_jp.eucjp", "EUCJIS"); MIME2JAVA.put("euc-kr", "KSC5601"); MIME2JAVA.put("euckr", "KSC5601"); MIME2JAVA.put("us-ascii", "ISO-8859-1"); MIME2JAVA.put("x-us-ascii", "ISO-8859-1"); } /** * Hidden constructor, this class must not be instantiated. */ private MimeUtility() { // do nothing } /** * Decode a string of text obtained from a mail header into * its proper form. The text generally will consist of a * string of tokens, some of which may be encoded using * base64 encoding. * * @param text The text to decode. * * @return The decoded text string. * @throws UnsupportedEncodingException if the detected encoding in the input text is not supported. */ public static String decodeText(String text) throws UnsupportedEncodingException { // if the text contains any encoded tokens, those tokens will be marked with "=?". If the // source string doesn't contain that sequent, no decoding is required. if (text.indexOf(ENCODED_TOKEN_MARKER) < 0) { return text; } int offset = 0; int endOffset = text.length(); int startWhiteSpace = -1; int endWhiteSpace = -1; StringBuilder decodedText = new StringBuilder(text.length()); boolean previousTokenEncoded = false; while (offset < endOffset) { char ch = text.charAt(offset); // is this a whitespace character? if (LINEAR_WHITESPACE.indexOf(ch) != -1) { // whitespace found startWhiteSpace = offset; while (offset < endOffset) { // step over the white space characters. ch = text.charAt(offset); if (LINEAR_WHITESPACE.indexOf(ch) != -1) { // whitespace found offset++; } else { // record the location of the first non lwsp and drop down to process the // token characters. endWhiteSpace = offset; break; } } } else { // we have a word token. We need to scan over the word and then try to parse it. int wordStart = offset; while (offset < endOffset) { // step over the non white space characters. ch = text.charAt(offset); if (LINEAR_WHITESPACE.indexOf(ch) == -1) { // not white space offset++; } else { break; } //NB: Trailing whitespace on these header strings will just be discarded. } // pull out the word token. String word = text.substring(wordStart, offset); // is the token encoded? decode the word if (word.startsWith(ENCODED_TOKEN_MARKER)) { try { // if this gives a parsing failure, treat it like a non-encoded word. String decodedWord = decodeWord(word); // are any whitespace characters significant? Append 'em if we've got 'em. if (!previousTokenEncoded && startWhiteSpace != -1) { decodedText.append(text.substring(startWhiteSpace, endWhiteSpace)); startWhiteSpace = -1; } // this is definitely a decoded token. previousTokenEncoded = true; // and add this to the text. decodedText.append(decodedWord); // we continue parsing from here...we allow parsing errors to fall through // and get handled as normal text. continue; } catch (ParseException e) { // just ignore it, skip to next word } } // this is a normal token, so it doesn't matter what the previous token was. Add the white space // if we have it. if (startWhiteSpace != -1) { decodedText.append(text.substring(startWhiteSpace, endWhiteSpace)); startWhiteSpace = -1; } // this is not a decoded token. previousTokenEncoded = false; decodedText.append(word); } } return decodedText.toString(); } /** * Parse a string using the RFC 2047 rules for an "encoded-word" * type. This encoding has the syntax: * * encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" * * @param word The possibly encoded word value. * * @return The decoded word. * @throws ParseException * @throws UnsupportedEncodingException */ private static String decodeWord(String word) throws ParseException, UnsupportedEncodingException { // encoded words start with the characters "=?". If this not an encoded word, we throw a // ParseException for the caller. if (!word.startsWith(ENCODED_TOKEN_MARKER)) { throw new ParseException("Invalid RFC 2047 encoded-word: " + word); } int charsetPos = word.indexOf('?', 2); if (charsetPos == -1) { throw new ParseException("Missing charset in RFC 2047 encoded-word: " + word); } // pull out the character set information (this is the MIME name at this point). String charset = word.substring(2, charsetPos).toLowerCase(); // now pull out the encoding token the same way. int encodingPos = word.indexOf('?', charsetPos + 1); if (encodingPos == -1) { throw new ParseException("Missing encoding in RFC 2047 encoded-word: " + word); } String encoding = word.substring(charsetPos + 1, encodingPos); // and finally the encoded text. int encodedTextPos = word.indexOf(ENCODED_TOKEN_FINISHER, encodingPos + 1); if (encodedTextPos == -1) { throw new ParseException("Missing encoded text in RFC 2047 encoded-word: " + word); } String encodedText = word.substring(encodingPos + 1, encodedTextPos); // seems a bit silly to encode a null string, but easy to deal with. if (encodedText.length() == 0) { return ""; } try { // the decoder writes directly to an output stream. ByteArrayOutputStream out = new ByteArrayOutputStream(encodedText.length()); byte[] decodedData; // Base64 encoded? if (encoding.equals(BASE64_ENCODING_MARKER)) { decodedData = Base64.decodeBase64(encodedText); } else if (encoding.equals(QUOTEDPRINTABLE_ENCODING_MARKER)) { // maybe quoted printable. byte[] encodedData = encodedText.getBytes(US_ASCII_CHARSET); QuotedPrintableDecoder.decode(encodedData, out); decodedData = out.toByteArray(); } else { throw new UnsupportedEncodingException("Unknown RFC 2047 encoding: " + encoding); } // Convert decoded byte data into a string. return new String(decodedData, javaCharset(charset)); } catch (IOException e) { throw new UnsupportedEncodingException("Invalid RFC 2047 encoding"); } } /** * Translate a MIME standard character set name into the Java * equivalent. * * @param charset The MIME standard name. * * @return The Java equivalent for this name. */ private static String javaCharset(String charset) { // nothing in, nothing out. if (charset == null) { return null; } String mappedCharset = MIME2JAVA.get(charset.toLowerCase(Locale.ENGLISH)); // if there is no mapping, then the original name is used. Many of the MIME character set // names map directly back into Java. The reverse isn't necessarily true. if (mappedCharset == null) { return charset; } return mappedCharset; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java0000644000175100017510000000620312271447131031102 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload.util; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.tomcat.util.http.fileupload.FileItemHeaders; /** * Default implementation of the {@link FileItemHeaders} interface. * * @since 1.2.1 */ public class FileItemHeadersImpl implements FileItemHeaders, Serializable { /** * Serial version UID, being used, if serialized. */ private static final long serialVersionUID = -4455695752627032559L; /** * Map of String keys to a List of * String instances. */ private final Map> headerNameToValueListMap = new LinkedHashMap>(); /** * {@inheritDoc} */ @Override public String getHeader(String name) { String nameLower = name.toLowerCase(Locale.ENGLISH); List headerValueList = headerNameToValueListMap.get(nameLower); if (null == headerValueList) { return null; } return headerValueList.get(0); } /** * {@inheritDoc} */ @Override public Iterator getHeaderNames() { return headerNameToValueListMap.keySet().iterator(); } /** * {@inheritDoc} */ @Override public Iterator getHeaders(String name) { String nameLower = name.toLowerCase(Locale.ENGLISH); List headerValueList = headerNameToValueListMap.get(nameLower); if (null == headerValueList) { headerValueList = Collections.emptyList(); } return headerValueList.iterator(); } /** * Method to add header values to this instance. * * @param name name of this header * @param value value of this header */ public synchronized void addHeader(String name, String value) { String nameLower = name.toLowerCase(Locale.ENGLISH); List headerValueList = headerNameToValueListMap.get(nameLower); if (null == headerValueList) { headerValueList = new ArrayList(); headerNameToValueListMap.put(nameLower, headerValueList); } headerValueList.add(value); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/util/package-info.java0000644000175100017510000000201212271447131027604 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** * This package contains various IO related utility classes * or methods, which are basically reusable and not necessarily * restricted to the scope of a file upload. */ package org.apache.tomcat.util.http.fileupload.util; tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java0000644000175100017510000001670512271447131030155 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.File; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; /** * Keeps track of files awaiting deletion, and deletes them when an associated * marker object is reclaimed by the garbage collector. *

    * This utility creates a background thread to handle file deletion. * Each file to be deleted is registered with a handler object. * When the handler object is garbage collected, the file is deleted. *

    * In an environment with multiple class loaders (a servlet container, for * example), you should consider stopping the background thread if it is no * longer needed. This is done by invoking the method * {@link #exitWhenFinished}, typically in * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar. */ public class FileCleaningTracker { /** * Queue of Tracker instances being watched. */ private final ReferenceQueue q = new ReferenceQueue(); /** * Collection of Tracker instances in existence. */ private final Collection trackers = Collections.synchronizedSet(new HashSet()); // synchronized /** * Collection of File paths that failed to delete. */ private final List deleteFailures = Collections.synchronizedList(new ArrayList()); /** * Whether to terminate the thread when the tracking is complete. */ private volatile boolean exitWhenFinished = false; /** * The thread that will clean up registered files. */ private Thread reaper; //----------------------------------------------------------------------- /** * Track the specified file, using the provided marker, deleting the file * when the marker instance is garbage collected. * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. * * @param file the file to be tracked, not null * @param marker the marker object used to track the file, not null * @throws NullPointerException if the file is null */ public void track(File file, Object marker) { track(file, marker, (FileDeleteStrategy) null); } /** * Track the specified file, using the provided marker, deleting the file * when the marker instance is garbage collected. * The speified deletion strategy is used. * * @param file the file to be tracked, not null * @param marker the marker object used to track the file, not null * @param deleteStrategy the strategy to delete the file, null means normal * @throws NullPointerException if the file is null */ public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) { if (file == null) { throw new NullPointerException("The file must not be null"); } addTracker(file.getPath(), marker, deleteStrategy); } /** * Adds a tracker to the list of trackers. * * @param path the full path to the file to be tracked, not null * @param marker the marker object used to track the file, not null * @param deleteStrategy the strategy to delete the file, null means normal */ private synchronized void addTracker(String path, Object marker, FileDeleteStrategy deleteStrategy) { // synchronized block protects reaper if (exitWhenFinished) { throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called"); } if (reaper == null) { reaper = new Reaper(); reaper.start(); } trackers.add(new Tracker(path, deleteStrategy, marker, q)); } //----------------------------------------------------------------------- /** * The reaper thread. */ private final class Reaper extends Thread { /** Construct a new Reaper */ Reaper() { super("File Reaper"); setPriority(Thread.MAX_PRIORITY); setDaemon(true); } /** * Run the reaper thread that will delete files as their associated * marker objects are reclaimed by the garbage collector. */ @Override public void run() { // thread exits when exitWhenFinished is true and there are no more tracked objects while (exitWhenFinished == false || trackers.size() > 0) { try { // Wait for a tracker to remove. Tracker tracker = (Tracker) q.remove(); // cannot return null trackers.remove(tracker); if (!tracker.delete()) { deleteFailures.add(tracker.getPath()); } tracker.clear(); } catch (InterruptedException e) { continue; } } } } //----------------------------------------------------------------------- /** * Inner class which acts as the reference for a file pending deletion. */ private static final class Tracker extends PhantomReference { /** * The full path to the file being tracked. */ private final String path; /** * The strategy for deleting files. */ private final FileDeleteStrategy deleteStrategy; /** * Constructs an instance of this class from the supplied parameters. * * @param path the full path to the file to be tracked, not null * @param deleteStrategy the strategy to delete the file, null means normal * @param marker the marker object used to track the file, not null * @param queue the queue on to which the tracker will be pushed, not null */ Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue queue) { super(marker, queue); this.path = path; this.deleteStrategy = deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy; } /** * Return the path. * * @return the path */ public String getPath() { return path; } /** * Deletes the file associated with this tracker instance. * * @return {@code true} if the file was deleted successfully; * {@code false} otherwise. */ public boolean delete() { return deleteStrategy.deleteQuietly(new File(path)); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java0000644000175100017510000001544512271447131031236 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; /** * An output stream which will retain data in memory until a specified * threshold is reached, and only then commit it to disk. If the stream is * closed before the threshold is reached, the data will not be written to * disk at all. *

    * This class originated in FileUpload processing. In this use case, you do * not know in advance the size of the file being uploaded. If the file is small * you want to store it in memory (for speed), but if the file is large you want * to store it to file (to avoid memory issues). */ public class DeferredFileOutputStream extends ThresholdingOutputStream { // ----------------------------------------------------------- Data members /** * The output stream to which data will be written prior to the theshold * being reached. */ private ByteArrayOutputStream memoryOutputStream; /** * The output stream to which data will be written at any given time. This * will always be one of memoryOutputStream or * diskOutputStream. */ private OutputStream currentOutputStream; /** * The file to which output will be directed if the threshold is exceeded. */ private File outputFile; /** * The temporary file prefix. */ private final String prefix; /** * The temporary file suffix. */ private final String suffix; /** * The directory to use for temporary files. */ private final File directory; // ----------------------------------------------------------- Constructors /** * Constructs an instance of this class which will trigger an event at the * specified threshold, and save data to a file beyond that point. * * @param threshold The number of bytes at which to trigger an event. * @param outputFile The file to which data is saved beyond the threshold. */ public DeferredFileOutputStream(int threshold, File outputFile) { this(threshold, outputFile, null, null, null); } /** * Constructs an instance of this class which will trigger an event at the * specified threshold, and save data either to a file beyond that point. * * @param threshold The number of bytes at which to trigger an event. * @param outputFile The file to which data is saved beyond the threshold. * @param prefix Prefix to use for the temporary file. * @param suffix Suffix to use for the temporary file. * @param directory Temporary file directory. */ private DeferredFileOutputStream(int threshold, File outputFile, String prefix, String suffix, File directory) { super(threshold); this.outputFile = outputFile; memoryOutputStream = new ByteArrayOutputStream(); currentOutputStream = memoryOutputStream; this.prefix = prefix; this.suffix = suffix; this.directory = directory; } // --------------------------------------- ThresholdingOutputStream methods /** * Returns the current output stream. This may be memory based or disk * based, depending on the current state with respect to the threshold. * * @return The underlying output stream. * * @exception IOException if an error occurs. */ @Override protected OutputStream getStream() throws IOException { return currentOutputStream; } /** * Switches the underlying output stream from a memory based stream to one * that is backed by disk. This is the point at which we realise that too * much data is being written to keep in memory, so we elect to switch to * disk-based storage. * * @exception IOException if an error occurs. */ @Override protected void thresholdReached() throws IOException { if (prefix != null) { outputFile = File.createTempFile(prefix, suffix, directory); } FileOutputStream fos = new FileOutputStream(outputFile); memoryOutputStream.writeTo(fos); currentOutputStream = fos; memoryOutputStream = null; } // --------------------------------------------------------- Public methods /** * Determines whether or not the data for this output stream has been * retained in memory. * * @return {@code true} if the data is available in memory; * {@code false} otherwise. */ public boolean isInMemory() { return !isThresholdExceeded(); } /** * Returns the data for this output stream as an array of bytes, assuming * that the data has been retained in memory. If the data was written to * disk, this method returns {@code null}. * * @return The data for this output stream, or {@code null} if no such * data is available. */ public byte[] getData() { if (memoryOutputStream != null) { return memoryOutputStream.toByteArray(); } return null; } /** * Returns either the output file specified in the constructor or * the temporary file created or null. *

    * If the constructor specifying the file is used then it returns that * same output file, even when threshold has not been reached. *

    * If constructor specifying a temporary file prefix/suffix is used * then the temporary file created once the threshold is reached is returned * If the threshold was not reached then {@code null} is returned. * * @return The file for this output stream, or {@code null} if no such * file exists. */ public File getFile() { return outputFile; } /** * Closes underlying output stream, and mark this as closed * * @exception IOException if an error occurs. */ @Override public void close() throws IOException { super.close(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/FileDeleteStrategy.java0000644000175100017510000001124212271447131030035 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.File; import java.io.IOException; /** * Strategy for deleting files. *

    * There is more than one way to delete a file. * You may want to limit access to certain directories, to only delete * directories if they are empty, or maybe to force deletion. *

    * This class captures the strategy to use and is designed for user subclassing. * * @since 1.3 */ public class FileDeleteStrategy { /** * The singleton instance for normal file deletion, which does not permit * the deletion of directories that are not empty. */ public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal"); /** The name of the strategy. */ private final String name; //----------------------------------------------------------------------- /** * Restricted constructor. * * @param name the name by which the strategy is known */ protected FileDeleteStrategy(String name) { this.name = name; } //----------------------------------------------------------------------- /** * Deletes the file object, which may be a file or a directory. * All IOExceptions are caught and false returned instead. * If the file does not exist or is null, true is returned. *

    * Subclass writers should override {@link #doDelete(File)}, not this method. * * @param fileToDelete the file to delete, null returns true * @return true if the file was deleted, or there was no such file */ public boolean deleteQuietly(File fileToDelete) { if (fileToDelete == null || fileToDelete.exists() == false) { return true; } try { return doDelete(fileToDelete); } catch (IOException ex) { return false; } } /** * Actually deletes the file object, which may be a file or a directory. *

    * This method is designed for subclasses to override. * The implementation may return either false or an IOException * when deletion fails. The {@link #deleteQuietly(File)} method will handle * either response appropriately. * A check has been made to ensure that the file will exist. *

    * This implementation uses {@link File#delete()}. * * @param fileToDelete the file to delete, exists, not null * @return true if the file was deleteds * @throws NullPointerException if the file is null * @throws IOException if an error occurs during file deletion */ protected boolean doDelete(File fileToDelete) throws IOException { return fileToDelete.delete(); } //----------------------------------------------------------------------- /** * Gets a string describing the delete strategy. * * @return a string describing the delete strategy */ @Override public String toString() { return "FileDeleteStrategy[" + name + "]"; } //----------------------------------------------------------------------- /** * Force file deletion strategy. */ static class ForceFileDeleteStrategy extends FileDeleteStrategy { /** Default Constructor */ ForceFileDeleteStrategy() { super("Force"); } /** * Deletes the file object. *

    * This implementation uses FileUtils.forceDelete() * if the file exists. * * @param fileToDelete the file to delete, not null * @return Always returns {@code true} * @throws NullPointerException if the file is null * @throws IOException if an error occurs during file deletion */ @Override protected boolean doDelete(File fileToDelete) throws IOException { FileUtils.forceDelete(fileToDelete); return true; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java0000644000175100017510000000411712271447131031161 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; /** * This exception is thrown in case of an invalid file name. * A file name is invalid, if it contains a NUL character. * Attackers might use this to circumvent security checks: * For example, a malicious user might upload a file with the name * "foo.exe\0.png". This file name might pass security checks (i.e. * checks for the extension ".png"), while, depending on the underlying * C library, it might create a file named "foo.exe", as the NUL * character is the string terminator in C. */ public class InvalidFileNameException extends RuntimeException { /** * Serial version UID, being used, if the exception * is serialized. */ private static final long serialVersionUID = 7922042602454350470L; /** * The file name causing the exception. */ private final String name; /** * Creates a new instance. * * @param pName The file name causing the exception. * @param pMessage A human readable error message. */ public InvalidFileNameException(String pName, String pMessage) { super(pMessage); name = pName; } /** * Returns the invalid file name. * * @return the invalid file name. */ public String getName() { return name; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java0000644000175100017510000002411712271447131027412 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.fileupload; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apache.tomcat.util.http.fileupload.util.mime.MimeUtility; /** * A simple parser intended to parse sequences of name/value pairs. * * Parameter values are expected to be enclosed in quotes if they * contain unsafe characters, such as '=' characters or separators. * Parameter values are optional and can be omitted. * *

    * param1 = value; param2 = "anything goes; really"; param3 *

    */ public class ParameterParser { /** * String to be parsed. */ private char[] chars = null; /** * Current position in the string. */ private int pos = 0; /** * Maximum position in the string. */ private int len = 0; /** * Start of a token. */ private int i1 = 0; /** * End of a token. */ private int i2 = 0; /** * Whether names stored in the map should be converted to lower case. */ private boolean lowerCaseNames = false; /** * Default ParameterParser constructor. */ public ParameterParser() { super(); } /** * Are there any characters left to parse? * * @return true if there are unparsed characters, * false otherwise. */ private boolean hasChar() { return this.pos < this.len; } /** * A helper method to process the parsed token. This method removes * leading and trailing blanks as well as enclosing quotation marks, * when necessary. * * @param quoted true if quotation marks are expected, * false otherwise. * @return the token */ private String getToken(boolean quoted) { // Trim leading white spaces while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) { i1++; } // Trim trailing white spaces while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) { i2--; } // Strip away quotation marks if necessary if (quoted && ((i2 - i1) >= 2) && (chars[i1] == '"') && (chars[i2 - 1] == '"')) { i1++; i2--; } String result = null; if (i2 > i1) { result = new String(chars, i1, i2 - i1); } return result; } /** * Tests if the given character is present in the array of characters. * * @param ch the character to test for presense in the array of characters * @param charray the array of characters to test against * * @return true if the character is present in the array of * characters, false otherwise. */ private boolean isOneOf(char ch, final char[] charray) { boolean result = false; for (int i = 0; i < charray.length; i++) { if (ch == charray[i]) { result = true; break; } } return result; } /** * Parses out a token until any of the given terminators * is encountered. * * @param terminators the array of terminating characters. Any of these * characters when encountered signify the end of the token * * @return the token */ private String parseToken(final char[] terminators) { char ch; i1 = pos; i2 = pos; while (hasChar()) { ch = chars[pos]; if (isOneOf(ch, terminators)) { break; } i2++; pos++; } return getToken(false); } /** * Parses out a token until any of the given terminators * is encountered outside the quotation marks. * * @param terminators the array of terminating characters. Any of these * characters when encountered outside the quotation marks signify the end * of the token * * @return the token */ private String parseQuotedToken(final char[] terminators) { char ch; i1 = pos; i2 = pos; boolean quoted = false; boolean charEscaped = false; while (hasChar()) { ch = chars[pos]; if (!quoted && isOneOf(ch, terminators)) { break; } if (!charEscaped && ch == '"') { quoted = !quoted; } charEscaped = (!charEscaped && ch == '\\'); i2++; pos++; } return getToken(true); } /** * Returns true if parameter names are to be converted to lower * case when name/value pairs are parsed. * * @return true if parameter names are to be * converted to lower case when name/value pairs are parsed. * Otherwise returns false */ public boolean isLowerCaseNames() { return this.lowerCaseNames; } /** * Sets the flag if parameter names are to be converted to lower case when * name/value pairs are parsed. * * @param b true if parameter names are to be * converted to lower case when name/value pairs are parsed. * false otherwise. */ public void setLowerCaseNames(boolean b) { this.lowerCaseNames = b; } /** * Extracts a map of name/value pairs from the given string. Names are * expected to be unique. Multiple separators may be specified and * the earliest found in the input string is used. * * @param str the string that contains a sequence of name/value pairs * @param separators the name/value pairs separators * * @return a map of name/value pairs */ public Map parse(final String str, char[] separators) { if (separators == null || separators.length == 0) { return new HashMap(); } char separator = separators[0]; if (str != null) { int idx = str.length(); for (int i = 0; i < separators.length; i++) { int tmp = str.indexOf(separators[i]); if (tmp != -1 && tmp < idx) { idx = tmp; separator = separators[i]; } } } return parse(str, separator); } /** * Extracts a map of name/value pairs from the given string. Names are * expected to be unique. * * @param str the string that contains a sequence of name/value pairs * @param separator the name/value pairs separator * * @return a map of name/value pairs */ public Map parse(final String str, char separator) { if (str == null) { return new HashMap(); } return parse(str.toCharArray(), separator); } /** * Extracts a map of name/value pairs from the given array of * characters. Names are expected to be unique. * * @param chars the array of characters that contains a sequence of * name/value pairs * @param separator the name/value pairs separator * * @return a map of name/value pairs */ public Map parse(final char[] chars, char separator) { if (chars == null) { return new HashMap(); } return parse(chars, 0, chars.length, separator); } /** * Extracts a map of name/value pairs from the given array of * characters. Names are expected to be unique. * * @param chars the array of characters that contains a sequence of * name/value pairs * @param offset - the initial offset. * @param length - the length. * @param separator the name/value pairs separator * * @return a map of name/value pairs */ public Map parse( final char[] chars, int offset, int length, char separator) { if (chars == null) { return new HashMap(); } HashMap params = new HashMap(); this.chars = chars; this.pos = offset; this.len = length; String paramName = null; String paramValue = null; while (hasChar()) { paramName = parseToken(new char[] { '=', separator }); paramValue = null; if (hasChar() && (chars[pos] == '=')) { pos++; // skip '=' paramValue = parseQuotedToken(new char[] { separator }); if (paramValue != null) { try { paramValue = MimeUtility.decodeText(paramValue); } catch (UnsupportedEncodingException e) { // let's keep the original value in this case } } } if (hasChar() && (chars[pos] == separator)) { pos++; // skip separator } if ((paramName != null) && (paramName.length() > 0)) { if (this.lowerCaseNames) { paramName = paramName.toLowerCase(Locale.ENGLISH); } params.put(paramName, paramValue); } } return params; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/mapper/0000755000175100017510000000000012301126367022604 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/http/mapper/MappingData.java0000644000175100017510000000342312271452644025644 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.mapper; import org.apache.tomcat.util.buf.MessageBytes; /** * Mapping data. * * @author Remy Maucherat */ public class MappingData { public Object host = null; public Object context = null; public Object[] contexts = null; public Object wrapper = null; public boolean jspWildCard = false; public MessageBytes contextPath = MessageBytes.newInstance(); public MessageBytes requestPath = MessageBytes.newInstance(); public MessageBytes wrapperPath = MessageBytes.newInstance(); public MessageBytes pathInfo = MessageBytes.newInstance(); public MessageBytes redirectPath = MessageBytes.newInstance(); public void recycle() { host = null; context = null; contexts = null; wrapper = null; jspWildCard = false; contextPath.recycle(); requestPath.recycle(); wrapperPath.recycle(); pathInfo.recycle(); redirectPath.recycle(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/mapper/Mapper.java0000644000175100017510000015007712271452644024713 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.mapper; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.apache.tomcat.util.buf.Ascii; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.res.StringManager; /** * Mapper, which implements the servlet API mapping rules (which are derived * from the HTTP rules). * * @author Remy Maucherat */ public final class Mapper { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(Mapper.class); protected static final StringManager sm = StringManager.getManager(Mapper.class.getPackage().getName()); // ----------------------------------------------------- Instance Variables /** * Array containing the virtual hosts definitions. */ protected Host[] hosts = new Host[0]; /** * Default host name. */ protected String defaultHostName = null; /** * Context associated with this wrapper, used for wrapper mapping. */ protected ContextVersion context = new ContextVersion(); // --------------------------------------------------------- Public Methods /** * Set default host. * * @param defaultHostName Default host name */ public void setDefaultHostName(String defaultHostName) { this.defaultHostName = defaultHostName; } /** * Add a new host to the mapper. * * @param name Virtual host name * @param host Host object */ public synchronized void addHost(String name, String[] aliases, Object host) { Host[] newHosts = new Host[hosts.length + 1]; Host newHost = new Host(); ContextList contextList = new ContextList(); newHost.name = name; newHost.contextList = contextList; newHost.object = host; if (insertMap(hosts, newHosts, newHost)) { hosts = newHosts; } for (int i = 0; i < aliases.length; i++) { newHosts = new Host[hosts.length + 1]; newHost = new Host(); newHost.name = aliases[i]; newHost.contextList = contextList; newHost.object = host; if (insertMap(hosts, newHosts, newHost)) { hosts = newHosts; } } } /** * Remove a host from the mapper. * * @param name Virtual host name */ public synchronized void removeHost(String name) { // Find and remove the old host int pos = find(hosts, name); if (pos < 0) { return; } Object host = hosts[pos].object; Host[] newHosts = new Host[hosts.length - 1]; if (removeMap(hosts, newHosts, name)) { hosts = newHosts; } // Remove all aliases (they will map to the same host object) for (int i = 0; i < newHosts.length; i++) { if (newHosts[i].object == host) { Host[] newHosts2 = new Host[hosts.length - 1]; if (removeMap(hosts, newHosts2, newHosts[i].name)) { hosts = newHosts2; } } } } /** * Add an alias to an existing host. * @param name The name of the host * @param alias The alias to add */ public synchronized void addHostAlias(String name, String alias) { int pos = find(hosts, name); if (pos < 0) { // Should not be adding an alias for a host that doesn't exist but // just in case... return; } Host realHost = hosts[pos]; Host[] newHosts = new Host[hosts.length + 1]; Host newHost = new Host(); newHost.name = alias; newHost.contextList = realHost.contextList; newHost.object = realHost.object; if (insertMap(hosts, newHosts, newHost)) { hosts = newHosts; } } /** * Remove a host alias * @param alias The alias to remove */ public synchronized void removeHostAlias(String alias) { // Find and remove the alias int pos = find(hosts, alias); if (pos < 0) { return; } Host[] newHosts = new Host[hosts.length - 1]; if (removeMap(hosts, newHosts, alias)) { hosts = newHosts; } } /** * Set context, used for wrapper mapping (request dispatcher). * * @param welcomeResources Welcome files defined for this context * @param resources Static resources of the context */ public void setContext(String path, String[] welcomeResources, javax.naming.Context resources) { context.path = path; context.welcomeResources = welcomeResources; context.resources = resources; } /** * Add a new Context to an existing Host. * * @param hostName Virtual host name this context belongs to * @param host Host object * @param path Context path * @param version Context version * @param context Context object * @param welcomeResources Welcome files defined for this context * @param resources Static resources of the context */ public void addContextVersion(String hostName, Object host, String path, String version, Object context, String[] welcomeResources, javax.naming.Context resources) { Host[] hosts = this.hosts; int pos = find(hosts, hostName); if( pos <0 ) { addHost(hostName, new String[0], host); hosts = this.hosts; pos = find(hosts, hostName); } if (pos < 0) { log.error("No host found: " + hostName); } Host mappedHost = hosts[pos]; if (mappedHost.name.equals(hostName)) { int slashCount = slashCount(path); synchronized (mappedHost) { Context[] contexts = mappedHost.contextList.contexts; // Update nesting if (slashCount > mappedHost.contextList.nesting) { mappedHost.contextList.nesting = slashCount; } int pos2 = find(contexts, path); if (pos2 < 0 || !path.equals(contexts[pos2].name)) { Context newContext = new Context(); newContext.name = path; Context[] newContexts = new Context[contexts.length + 1]; if (insertMap(contexts, newContexts, newContext)) { mappedHost.contextList.contexts = newContexts; } pos2 = find(newContexts, path); } Context mappedContext = mappedHost.contextList.contexts[pos2]; ContextVersion[] contextVersions = mappedContext.versions; ContextVersion[] newContextVersions = new ContextVersion[contextVersions.length + 1]; ContextVersion newContextVersion = new ContextVersion(); newContextVersion.path = path; newContextVersion.name = version; newContextVersion.object = context; newContextVersion.welcomeResources = welcomeResources; newContextVersion.resources = resources; if (insertMap(contextVersions, newContextVersions, newContextVersion)) { mappedContext.versions = newContextVersions; } } } } /** * Remove a context from an existing host. * * @param hostName Virtual host name this context belongs to * @param path Context path * @param version Context version */ public void removeContextVersion(String hostName, String path, String version) { Host[] hosts = this.hosts; int pos = find(hosts, hostName); if (pos < 0) { return; } Host host = hosts[pos]; if (host.name.equals(hostName)) { synchronized (host) { Context[] contexts = host.contextList.contexts; if (contexts.length == 0 ){ return; } int pos2 = find(contexts, path); if (pos2 < 0 || !path.equals(contexts[pos2].name)) { return; } Context context = contexts[pos2]; ContextVersion[] contextVersions = context.versions; ContextVersion[] newContextVersions = new ContextVersion[contextVersions.length - 1]; if (removeMap(contextVersions, newContextVersions, version)) { context.versions = newContextVersions; if (context.versions.length == 0) { // Remove the context Context[] newContexts = new Context[contexts.length -1]; if (removeMap(contexts, newContexts, path)) { host.contextList.contexts = newContexts; // Recalculate nesting host.contextList.nesting = 0; for (int i = 0; i < newContexts.length; i++) { int slashCount = slashCount(newContexts[i].name); if (slashCount > host.contextList.nesting) { host.contextList.nesting = slashCount; } } } } } } } } public void addWrapper(String hostName, String contextPath, String version, String path, Object wrapper, boolean jspWildCard, boolean resourceOnly) { Host[] hosts = this.hosts; int pos = find(hosts, hostName); if (pos < 0) { return; } Host host = hosts[pos]; if (host.name.equals(hostName)) { Context[] contexts = host.contextList.contexts; int pos2 = find(contexts, contextPath); if (pos2 < 0) { log.error("No context found: " + contextPath ); return; } Context context = contexts[pos2]; if (context.name.equals(contextPath)) { ContextVersion[] contextVersions = context.versions; int pos3 = find(contextVersions, version); if( pos3<0 ) { log.error("No context version found: " + contextPath + " " + version); return; } ContextVersion contextVersion = contextVersions[pos3]; if (contextVersion.name.equals(version)) { addWrapper(contextVersion, path, wrapper, jspWildCard, resourceOnly); } } } } public void addWrapper(String path, Object wrapper, boolean jspWildCard, boolean resourceOnly) { addWrapper(context, path, wrapper, jspWildCard, resourceOnly); } /** * Adds a wrapper to the given context. * * @param context The context to which to add the wrapper * @param path Wrapper mapping * @param wrapper The Wrapper object * @param jspWildCard true if the wrapper corresponds to the JspServlet * @param resourceOnly true if this wrapper always expects a physical * resource to be present (such as a JSP) * and the mapping path contains a wildcard; false otherwise */ protected void addWrapper(ContextVersion context, String path, Object wrapper, boolean jspWildCard, boolean resourceOnly) { synchronized (context) { Wrapper newWrapper = new Wrapper(); newWrapper.object = wrapper; newWrapper.jspWildCard = jspWildCard; newWrapper.resourceOnly = resourceOnly; if (path.endsWith("/*")) { // Wildcard wrapper newWrapper.name = path.substring(0, path.length() - 2); Wrapper[] oldWrappers = context.wildcardWrappers; Wrapper[] newWrappers = new Wrapper[oldWrappers.length + 1]; if (insertMap(oldWrappers, newWrappers, newWrapper)) { context.wildcardWrappers = newWrappers; int slashCount = slashCount(newWrapper.name); if (slashCount > context.nesting) { context.nesting = slashCount; } } } else if (path.startsWith("*.")) { // Extension wrapper newWrapper.name = path.substring(2); Wrapper[] oldWrappers = context.extensionWrappers; Wrapper[] newWrappers = new Wrapper[oldWrappers.length + 1]; if (insertMap(oldWrappers, newWrappers, newWrapper)) { context.extensionWrappers = newWrappers; } } else if (path.equals("/")) { // Default wrapper newWrapper.name = ""; context.defaultWrapper = newWrapper; } else { // Exact wrapper if (path.length() == 0) { // Special case for the Context Root mapping which is // treated as an exact match newWrapper.name = "/"; } else { newWrapper.name = path; } Wrapper[] oldWrappers = context.exactWrappers; Wrapper[] newWrappers = new Wrapper[oldWrappers.length + 1]; if (insertMap(oldWrappers, newWrappers, newWrapper)) { context.exactWrappers = newWrappers; } } } } /** * Remove a wrapper from the context associated with this wrapper. * * @param path Wrapper mapping */ public void removeWrapper(String path) { removeWrapper(context, path); } /** * Remove a wrapper from an existing context. * * @param hostName Virtual host name this wrapper belongs to * @param contextPath Context path this wrapper belongs to * @param path Wrapper mapping */ public void removeWrapper (String hostName, String contextPath, String version, String path) { Host[] hosts = this.hosts; int pos = find(hosts, hostName); if (pos < 0) { return; } Host host = hosts[pos]; if (host.name.equals(hostName)) { Context[] contexts = host.contextList.contexts; int pos2 = find(contexts, contextPath); if (pos2 < 0) { return; } Context context = contexts[pos2]; if (context.name.equals(contextPath)) { ContextVersion[] contextVersions = context.versions; int pos3 = find(contextVersions, version); if( pos3<0 ) { return; } ContextVersion contextVersion = contextVersions[pos3]; if (contextVersion.name.equals(version)) { removeWrapper(contextVersion, path); } } } } protected void removeWrapper(ContextVersion context, String path) { if (log.isDebugEnabled()) { log.debug(sm.getString("mapper.removeWrapper", context.name, path)); } synchronized (context) { if (path.endsWith("/*")) { // Wildcard wrapper String name = path.substring(0, path.length() - 2); Wrapper[] oldWrappers = context.wildcardWrappers; if (oldWrappers.length == 0) { return; } Wrapper[] newWrappers = new Wrapper[oldWrappers.length - 1]; if (removeMap(oldWrappers, newWrappers, name)) { // Recalculate nesting context.nesting = 0; for (int i = 0; i < newWrappers.length; i++) { int slashCount = slashCount(newWrappers[i].name); if (slashCount > context.nesting) { context.nesting = slashCount; } } context.wildcardWrappers = newWrappers; } } else if (path.startsWith("*.")) { // Extension wrapper String name = path.substring(2); Wrapper[] oldWrappers = context.extensionWrappers; if (oldWrappers.length == 0) { return; } Wrapper[] newWrappers = new Wrapper[oldWrappers.length - 1]; if (removeMap(oldWrappers, newWrappers, name)) { context.extensionWrappers = newWrappers; } } else if (path.equals("/")) { // Default wrapper context.defaultWrapper = null; } else { // Exact wrapper String name; if (path.length() == 0) { // Special case for the Context Root mapping which is // treated as an exact match name = "/"; } else { name = path; } Wrapper[] oldWrappers = context.exactWrappers; if (oldWrappers.length == 0) { return; } Wrapper[] newWrappers = new Wrapper[oldWrappers.length - 1]; if (removeMap(oldWrappers, newWrappers, name)) { context.exactWrappers = newWrappers; } } } } /** * Add a welcome file to the given context. * * @param hostName * @param contextPath * @param welcomeFile */ public void addWelcomeFile(String hostName, String contextPath, String version, String welcomeFile) { Host[] hosts = this.hosts; int pos = find(hosts, hostName); if (pos < 0) { return; } Host host = hosts[pos]; if (host.name.equals(hostName)) { Context[] contexts = host.contextList.contexts; int pos2 = find(contexts, contextPath); if (pos2 < 0) { log.error("No context found: " + contextPath ); return; } Context context = contexts[pos2]; if (context.name.equals(contextPath)) { ContextVersion[] contextVersions = context.versions; int pos3 = find(contextVersions, version); if( pos3<0 ) { log.error("No context version found: " + contextPath + " " + version); return; } ContextVersion contextVersion = contextVersions[pos3]; if (contextVersion.name.equals(version)) { int len = contextVersion.welcomeResources.length + 1; String[] newWelcomeResources = new String[len]; System.arraycopy(contextVersion.welcomeResources, 0, newWelcomeResources, 0, len - 1); newWelcomeResources[len - 1] = welcomeFile; contextVersion.welcomeResources = newWelcomeResources; } } } } /** * Remove a welcome file from the given context. * * @param hostName * @param contextPath * @param welcomeFile */ public void removeWelcomeFile(String hostName, String contextPath, String version, String welcomeFile) { Host[] hosts = this.hosts; int pos = find(hosts, hostName); if (pos < 0) { return; } Host host = hosts[pos]; if (host.name.equals(hostName)) { Context[] contexts = host.contextList.contexts; int pos2 = find(contexts, contextPath); if (pos2 < 0) { log.error("No context found: " + contextPath ); return; } Context context = contexts[pos2]; if (context.name.equals(contextPath)) { ContextVersion[] contextVersions = context.versions; int pos3 = find(contextVersions, version); if( pos3<0 ) { log.error("No context version found: " + contextPath + " " + version); return; } ContextVersion contextVersion = contextVersions[pos3]; if (contextVersion.name.equals(version)) { int match = -1; for (int i = 0; i < contextVersion.welcomeResources.length; i++) { if (welcomeFile.equals(contextVersion.welcomeResources[i])) { match = i; break; } } if (match > -1) { int len = contextVersion.welcomeResources.length - 1; String[] newWelcomeResources = new String[len]; System.arraycopy(contextVersion.welcomeResources, 0, newWelcomeResources, 0, match); if (match < len) { System.arraycopy(contextVersion.welcomeResources, match + 1, newWelcomeResources, match, len - match); } contextVersion.welcomeResources = newWelcomeResources; } } } } } /** * Clear the welcome files for the given context. * * @param hostName * @param contextPath */ public void clearWelcomeFiles(String hostName, String contextPath, String version) { Host[] hosts = this.hosts; int pos = find(hosts, hostName); if (pos < 0) { return; } Host host = hosts[pos]; if (host.name.equals(hostName)) { Context[] contexts = host.contextList.contexts; int pos2 = find(contexts, contextPath); if (pos2 < 0) { log.error("No context found: " + contextPath ); return; } Context context = contexts[pos2]; if (context.name.equals(contextPath)) { ContextVersion[] contextVersions = context.versions; int pos3 = find(contextVersions, version); if( pos3<0 ) { log.error("No context version found: " + contextPath + " " + version); return; } ContextVersion contextVersion = contextVersions[pos3]; if (contextVersion.name.equals(version)) { contextVersion.welcomeResources = new String[0]; } } } } /** * Map the specified host name and URI, mutating the given mapping data. * * @param host Virtual host name * @param uri URI * @param mappingData This structure will contain the result of the mapping * operation */ public void map(MessageBytes host, MessageBytes uri, String version, MappingData mappingData) throws Exception { if (host.isNull()) { host.getCharChunk().append(defaultHostName); } host.toChars(); uri.toChars(); internalMap(host.getCharChunk(), uri.getCharChunk(), version, mappingData); } /** * Map the specified URI relative to the context, * mutating the given mapping data. * * @param uri URI * @param mappingData This structure will contain the result of the mapping * operation */ public void map(MessageBytes uri, MappingData mappingData) throws Exception { uri.toChars(); CharChunk uricc = uri.getCharChunk(); uricc.setLimit(-1); internalMapWrapper(context, uricc, mappingData); } // -------------------------------------------------------- Private Methods /** * Map the specified URI. */ private final void internalMap(CharChunk host, CharChunk uri, String version, MappingData mappingData) throws Exception { uri.setLimit(-1); Context[] contexts = null; Context context = null; ContextVersion contextVersion = null; int nesting = 0; // Virtual host mapping if (mappingData.host == null) { Host[] hosts = this.hosts; int pos = findIgnoreCase(hosts, host); if ((pos != -1) && (host.equalsIgnoreCase(hosts[pos].name))) { mappingData.host = hosts[pos].object; contexts = hosts[pos].contextList.contexts; nesting = hosts[pos].contextList.nesting; } else { if (defaultHostName == null) { return; } pos = find(hosts, defaultHostName); if ((pos != -1) && (defaultHostName.equals(hosts[pos].name))) { mappingData.host = hosts[pos].object; contexts = hosts[pos].contextList.contexts; nesting = hosts[pos].contextList.nesting; } else { return; } } } // Context mapping if (mappingData.context == null) { int pos = find(contexts, uri); if (pos == -1) { return; } int lastSlash = -1; int uriEnd = uri.getEnd(); int length = -1; boolean found = false; while (pos >= 0) { if (uri.startsWith(contexts[pos].name)) { length = contexts[pos].name.length(); if (uri.getLength() == length) { found = true; break; } else if (uri.startsWithIgnoreCase("/", length)) { found = true; break; } } if (lastSlash == -1) { lastSlash = nthSlash(uri, nesting + 1); } else { lastSlash = lastSlash(uri); } uri.setEnd(lastSlash); pos = find(contexts, uri); } uri.setEnd(uriEnd); if (!found) { if (contexts[0].name.equals("")) { context = contexts[0]; } } else { context = contexts[pos]; } if (context != null) { mappingData.contextPath.setString(context.name); } } if (context != null) { ContextVersion[] contextVersions = context.versions; int versionCount = contextVersions.length; if (versionCount > 1) { Object[] contextObjects = new Object[contextVersions.length]; for (int i = 0; i < contextObjects.length; i++) { contextObjects[i] = contextVersions[i].object; } mappingData.contexts = contextObjects; } if (version == null) { // Return the latest version contextVersion = contextVersions[versionCount - 1]; } else { int pos = find(contextVersions, version); if (pos < 0 || !contextVersions[pos].name.equals(version)) { // Return the latest version contextVersion = contextVersions[versionCount - 1]; } else { contextVersion = contextVersions[pos]; } } mappingData.context = contextVersion.object; } // Wrapper mapping if ((contextVersion != null) && (mappingData.wrapper == null)) { internalMapWrapper(contextVersion, uri, mappingData); } } /** * Wrapper mapping. */ private final void internalMapWrapper(ContextVersion contextVersion, CharChunk path, MappingData mappingData) throws Exception { int pathOffset = path.getOffset(); int pathEnd = path.getEnd(); int servletPath = pathOffset; boolean noServletPath = false; int length = contextVersion.path.length(); if (length != (pathEnd - pathOffset)) { servletPath = pathOffset + length; } else { noServletPath = true; path.append('/'); pathOffset = path.getOffset(); pathEnd = path.getEnd(); servletPath = pathOffset+length; } path.setOffset(servletPath); // Rule 1 -- Exact Match Wrapper[] exactWrappers = contextVersion.exactWrappers; internalMapExactWrapper(exactWrappers, path, mappingData); // Rule 2 -- Prefix Match boolean checkJspWelcomeFiles = false; Wrapper[] wildcardWrappers = contextVersion.wildcardWrappers; if (mappingData.wrapper == null) { internalMapWildcardWrapper(wildcardWrappers, contextVersion.nesting, path, mappingData); if (mappingData.wrapper != null && mappingData.jspWildCard) { char[] buf = path.getBuffer(); if (buf[pathEnd - 1] == '/') { /* * Path ending in '/' was mapped to JSP servlet based on * wildcard match (e.g., as specified in url-pattern of a * jsp-property-group. * Force the context's welcome files, which are interpreted * as JSP files (since they match the url-pattern), to be * considered. See Bugzilla 27664. */ mappingData.wrapper = null; checkJspWelcomeFiles = true; } else { // See Bugzilla 27704 mappingData.wrapperPath.setChars(buf, path.getStart(), path.getLength()); mappingData.pathInfo.recycle(); } } } if(mappingData.wrapper == null && noServletPath) { // The path is empty, redirect to "/" mappingData.redirectPath.setChars (path.getBuffer(), pathOffset, pathEnd-pathOffset); path.setEnd(pathEnd - 1); return; } // Rule 3 -- Extension Match Wrapper[] extensionWrappers = contextVersion.extensionWrappers; if (mappingData.wrapper == null && !checkJspWelcomeFiles) { internalMapExtensionWrapper(extensionWrappers, path, mappingData, true); } // Rule 4 -- Welcome resources processing for servlets if (mappingData.wrapper == null) { boolean checkWelcomeFiles = checkJspWelcomeFiles; if (!checkWelcomeFiles) { char[] buf = path.getBuffer(); checkWelcomeFiles = (buf[pathEnd - 1] == '/'); } if (checkWelcomeFiles) { for (int i = 0; (i < contextVersion.welcomeResources.length) && (mappingData.wrapper == null); i++) { path.setOffset(pathOffset); path.setEnd(pathEnd); path.append(contextVersion.welcomeResources[i], 0, contextVersion.welcomeResources[i].length()); path.setOffset(servletPath); // Rule 4a -- Welcome resources processing for exact macth internalMapExactWrapper(exactWrappers, path, mappingData); // Rule 4b -- Welcome resources processing for prefix match if (mappingData.wrapper == null) { internalMapWildcardWrapper (wildcardWrappers, contextVersion.nesting, path, mappingData); } // Rule 4c -- Welcome resources processing // for physical folder if (mappingData.wrapper == null && contextVersion.resources != null) { Object file = null; String pathStr = path.toString(); try { file = contextVersion.resources.lookup(pathStr); } catch(NamingException nex) { // Swallow not found, since this is normal } if (file != null && !(file instanceof DirContext) ) { internalMapExtensionWrapper(extensionWrappers, path, mappingData, true); if (mappingData.wrapper == null && contextVersion.defaultWrapper != null) { mappingData.wrapper = contextVersion.defaultWrapper.object; mappingData.requestPath.setChars (path.getBuffer(), path.getStart(), path.getLength()); mappingData.wrapperPath.setChars (path.getBuffer(), path.getStart(), path.getLength()); mappingData.requestPath.setString(pathStr); mappingData.wrapperPath.setString(pathStr); } } } } path.setOffset(servletPath); path.setEnd(pathEnd); } } /* welcome file processing - take 2 * Now that we have looked for welcome files with a physical * backing, now look for an extension mapping listed * but may not have a physical backing to it. This is for * the case of index.jsf, index.do, etc. * A watered down version of rule 4 */ if (mappingData.wrapper == null) { boolean checkWelcomeFiles = checkJspWelcomeFiles; if (!checkWelcomeFiles) { char[] buf = path.getBuffer(); checkWelcomeFiles = (buf[pathEnd - 1] == '/'); } if (checkWelcomeFiles) { for (int i = 0; (i < contextVersion.welcomeResources.length) && (mappingData.wrapper == null); i++) { path.setOffset(pathOffset); path.setEnd(pathEnd); path.append(contextVersion.welcomeResources[i], 0, contextVersion.welcomeResources[i].length()); path.setOffset(servletPath); internalMapExtensionWrapper(extensionWrappers, path, mappingData, false); } path.setOffset(servletPath); path.setEnd(pathEnd); } } // Rule 7 -- Default servlet if (mappingData.wrapper == null && !checkJspWelcomeFiles) { if (contextVersion.defaultWrapper != null) { mappingData.wrapper = contextVersion.defaultWrapper.object; mappingData.requestPath.setChars (path.getBuffer(), path.getStart(), path.getLength()); mappingData.wrapperPath.setChars (path.getBuffer(), path.getStart(), path.getLength()); } // Redirection to a folder char[] buf = path.getBuffer(); if (contextVersion.resources != null && buf[pathEnd -1 ] != '/') { Object file = null; String pathStr = path.toString(); try { file = contextVersion.resources.lookup(pathStr); } catch(NamingException nex) { // Swallow, since someone else handles the 404 } if (file != null && file instanceof DirContext) { // Note: this mutates the path: do not do any processing // after this (since we set the redirectPath, there // shouldn't be any) path.setOffset(pathOffset); path.append('/'); mappingData.redirectPath.setChars (path.getBuffer(), path.getStart(), path.getLength()); } else { mappingData.requestPath.setString(pathStr); mappingData.wrapperPath.setString(pathStr); } } } path.setOffset(pathOffset); path.setEnd(pathEnd); } /** * Exact mapping. */ private final void internalMapExactWrapper (Wrapper[] wrappers, CharChunk path, MappingData mappingData) { int pos = find(wrappers, path); if ((pos != -1) && (path.equals(wrappers[pos].name))) { mappingData.requestPath.setString(wrappers[pos].name); mappingData.wrapper = wrappers[pos].object; if (path.equals("/")) { // Special handling for Context Root mapped servlet mappingData.pathInfo.setString("/"); mappingData.wrapperPath.setString(""); // This seems wrong but it is what the spec says... mappingData.contextPath.setString(""); } else { mappingData.wrapperPath.setString(wrappers[pos].name); } } } /** * Wildcard mapping. */ private final void internalMapWildcardWrapper (Wrapper[] wrappers, int nesting, CharChunk path, MappingData mappingData) { int pathEnd = path.getEnd(); int lastSlash = -1; int length = -1; int pos = find(wrappers, path); if (pos != -1) { boolean found = false; while (pos >= 0) { if (path.startsWith(wrappers[pos].name)) { length = wrappers[pos].name.length(); if (path.getLength() == length) { found = true; break; } else if (path.startsWithIgnoreCase("/", length)) { found = true; break; } } if (lastSlash == -1) { lastSlash = nthSlash(path, nesting + 1); } else { lastSlash = lastSlash(path); } path.setEnd(lastSlash); pos = find(wrappers, path); } path.setEnd(pathEnd); if (found) { mappingData.wrapperPath.setString(wrappers[pos].name); if (path.getLength() > length) { mappingData.pathInfo.setChars (path.getBuffer(), path.getOffset() + length, path.getLength() - length); } mappingData.requestPath.setChars (path.getBuffer(), path.getOffset(), path.getLength()); mappingData.wrapper = wrappers[pos].object; mappingData.jspWildCard = wrappers[pos].jspWildCard; } } } /** * Extension mappings. * * @param wrappers Set of wrappers to check for matches * @param path Path to map * @param mappingData Mapping data for result * @param resourceExpected Is this mapping expecting to find a resource */ private final void internalMapExtensionWrapper(Wrapper[] wrappers, CharChunk path, MappingData mappingData, boolean resourceExpected) { char[] buf = path.getBuffer(); int pathEnd = path.getEnd(); int servletPath = path.getOffset(); int slash = -1; for (int i = pathEnd - 1; i >= servletPath; i--) { if (buf[i] == '/') { slash = i; break; } } if (slash >= 0) { int period = -1; for (int i = pathEnd - 1; i > slash; i--) { if (buf[i] == '.') { period = i; break; } } if (period >= 0) { path.setOffset(period + 1); path.setEnd(pathEnd); int pos = find(wrappers, path); if ((pos != -1) && (path.equals(wrappers[pos].name)) && (resourceExpected || !wrappers[pos].resourceOnly)) { mappingData.wrapperPath.setChars (buf, servletPath, pathEnd - servletPath); mappingData.requestPath.setChars (buf, servletPath, pathEnd - servletPath); mappingData.wrapper = wrappers[pos].object; } path.setOffset(servletPath); path.setEnd(pathEnd); } } } /** * Find a map element given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ private static final int find(MapElement[] map, CharChunk name) { return find(map, name, name.getStart(), name.getEnd()); } /** * Find a map element given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ private static final int find(MapElement[] map, CharChunk name, int start, int end) { int a = 0; int b = map.length - 1; // Special cases: -1 and 0 if (b == -1) { return -1; } if (compare(name, start, end, map[0].name) < 0 ) { return -1; } if (b == 0) { return 0; } int i = 0; while (true) { i = (b + a) / 2; int result = compare(name, start, end, map[i].name); if (result == 1) { a = i; } else if (result == 0) { return i; } else { b = i; } if ((b - a) == 1) { int result2 = compare(name, start, end, map[b].name); if (result2 < 0) { return a; } else { return b; } } } } /** * Find a map element given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ private static final int findIgnoreCase(MapElement[] map, CharChunk name) { return findIgnoreCase(map, name, name.getStart(), name.getEnd()); } /** * Find a map element given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ private static final int findIgnoreCase(MapElement[] map, CharChunk name, int start, int end) { int a = 0; int b = map.length - 1; // Special cases: -1 and 0 if (b == -1) { return -1; } if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) { return -1; } if (b == 0) { return 0; } int i = 0; while (true) { i = (b + a) / 2; int result = compareIgnoreCase(name, start, end, map[i].name); if (result == 1) { a = i; } else if (result == 0) { return i; } else { b = i; } if ((b - a) == 1) { int result2 = compareIgnoreCase(name, start, end, map[b].name); if (result2 < 0) { return a; } else { return b; } } } } /** * Find a map element given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ private static final int find(MapElement[] map, String name) { int a = 0; int b = map.length - 1; // Special cases: -1 and 0 if (b == -1) { return -1; } if (name.compareTo(map[0].name) < 0) { return -1; } if (b == 0) { return 0; } int i = 0; while (true) { i = (b + a) / 2; int result = name.compareTo(map[i].name); if (result > 0) { a = i; } else if (result == 0) { return i; } else { b = i; } if ((b - a) == 1) { int result2 = name.compareTo(map[b].name); if (result2 < 0) { return a; } else { return b; } } } } /** * Compare given char chunk with String. * Return -1, 0 or +1 if inferior, equal, or superior to the String. */ private static final int compare(CharChunk name, int start, int end, String compareTo) { int result = 0; char[] c = name.getBuffer(); int len = compareTo.length(); if ((end - start) < len) { len = end - start; } for (int i = 0; (i < len) && (result == 0); i++) { if (c[i + start] > compareTo.charAt(i)) { result = 1; } else if (c[i + start] < compareTo.charAt(i)) { result = -1; } } if (result == 0) { if (compareTo.length() > (end - start)) { result = -1; } else if (compareTo.length() < (end - start)) { result = 1; } } return result; } /** * Compare given char chunk with String ignoring case. * Return -1, 0 or +1 if inferior, equal, or superior to the String. */ private static final int compareIgnoreCase(CharChunk name, int start, int end, String compareTo) { int result = 0; char[] c = name.getBuffer(); int len = compareTo.length(); if ((end - start) < len) { len = end - start; } for (int i = 0; (i < len) && (result == 0); i++) { if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) { result = 1; } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) { result = -1; } } if (result == 0) { if (compareTo.length() > (end - start)) { result = -1; } else if (compareTo.length() < (end - start)) { result = 1; } } return result; } /** * Find the position of the last slash in the given char chunk. */ private static final int lastSlash(CharChunk name) { char[] c = name.getBuffer(); int end = name.getEnd(); int start = name.getStart(); int pos = end; while (pos > start) { if (c[--pos] == '/') { break; } } return (pos); } /** * Find the position of the nth slash, in the given char chunk. */ private static final int nthSlash(CharChunk name, int n) { char[] c = name.getBuffer(); int end = name.getEnd(); int start = name.getStart(); int pos = start; int count = 0; while (pos < end) { if ((c[pos++] == '/') && ((++count) == n)) { pos--; break; } } return (pos); } /** * Return the slash count in a given string. */ private static final int slashCount(String name) { int pos = -1; int count = 0; while ((pos = name.indexOf('/', pos + 1)) != -1) { count++; } return count; } /** * Insert into the right place in a sorted MapElement array, and prevent * duplicates. */ private static final boolean insertMap (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) { int pos = find(oldMap, newElement.name); if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) { return false; } System.arraycopy(oldMap, 0, newMap, 0, pos + 1); newMap[pos + 1] = newElement; System.arraycopy (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1); return true; } /** * Insert into the right place in a sorted MapElement array. */ private static final boolean removeMap (MapElement[] oldMap, MapElement[] newMap, String name) { int pos = find(oldMap, name); if ((pos != -1) && (name.equals(oldMap[pos].name))) { System.arraycopy(oldMap, 0, newMap, 0, pos); System.arraycopy(oldMap, pos + 1, newMap, pos, oldMap.length - pos - 1); return true; } return false; } // ------------------------------------------------- MapElement Inner Class protected abstract static class MapElement { public String name = null; public Object object = null; } // ------------------------------------------------------- Host Inner Class protected static final class Host extends MapElement { public ContextList contextList = null; } // ------------------------------------------------ ContextList Inner Class protected static final class ContextList { public Context[] contexts = new Context[0]; public int nesting = 0; } // ---------------------------------------------------- Context Inner Class protected static final class Context extends MapElement { public ContextVersion[] versions = new ContextVersion[0]; } protected static final class ContextVersion extends MapElement { public String path = null; public String[] welcomeResources = new String[0]; public javax.naming.Context resources = null; public Wrapper defaultWrapper = null; public Wrapper[] exactWrappers = new Wrapper[0]; public Wrapper[] wildcardWrappers = new Wrapper[0]; public Wrapper[] extensionWrappers = new Wrapper[0]; public int nesting = 0; } // ---------------------------------------------------- Wrapper Inner Class protected static class Wrapper extends MapElement { public boolean jspWildCard = false; public boolean resourceOnly = false; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/mapper/LocalStrings.properties0000644000175100017510000000152611352435051027330 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. mapper.removeWrapper=Removing wrapper from Context [{0}] with path [{1}]tomcat7-7.0.52/java/org/apache/tomcat/util/http/Cookies.java0000644000175100017510000004440212271452644023571 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; import java.io.PrintWriter; import java.io.StringWriter; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.log.UserDataHelper; import org.apache.tomcat.util.res.StringManager; /** * A collection of cookies - reusable and tuned for server side performance. * Based on RFC2965 ( and 2109 ) * * This class is not synchronized. * * @author Costin Manolache * @author kevin seguin */ public final class Cookies { private static final Log log = LogFactory.getLog(Cookies.class); private static final UserDataHelper userDataLog = new UserDataHelper(log); protected static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.http"); // expected average number of cookies per request public static final int INITIAL_SIZE=4; ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE]; int cookieCount=0; boolean unprocessed=true; MimeHeaders headers; /** * Construct a new cookie collection, that will extract * the information from headers. * * @param headers Cookies are lazy-evaluated and will extract the * information from the provided headers. */ public Cookies(MimeHeaders headers) { this.headers=headers; } /** * Recycle. */ public void recycle() { for( int i=0; i< cookieCount; i++ ) { if( scookies[i]!=null ) { scookies[i].recycle(); } } cookieCount=0; unprocessed=true; } /** * EXPENSIVE!!! only for debugging. */ @Override public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.println("=== Cookies ==="); int count = getCookieCount(); for (int i = 0; i < count; ++i) { pw.println(getCookie(i).toString()); } return sw.toString(); } // -------------------- Indexed access -------------------- public ServerCookie getCookie( int idx ) { if( unprocessed ) { getCookieCount(); // will also update the cookies } return scookies[idx]; } public int getCookieCount() { if( unprocessed ) { unprocessed=false; processCookies(headers); } return cookieCount; } // -------------------- Adding cookies -------------------- /** Register a new, initialized cookie. Cookies are recycled, and * most of the time an existing ServerCookie object is returned. * The caller can set the name/value and attributes for the cookie */ private ServerCookie addCookie() { if( cookieCount >= scookies.length ) { ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount]; System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount); scookies=scookiesTmp; } ServerCookie c = scookies[cookieCount]; if( c==null ) { c= new ServerCookie(); scookies[cookieCount]=c; } cookieCount++; return c; } // code from CookieTools /** Add all Cookie found in the headers of a request. */ public void processCookies( MimeHeaders headers ) { if( headers==null ) { return;// nothing to process } // process each "cookie" header int pos=0; while( pos>=0 ) { // Cookie2: version ? not needed pos=headers.findHeader( "Cookie", pos ); // no more cookie headers headers if( pos<0 ) { break; } MessageBytes cookieValue=headers.getValue( pos ); if( cookieValue==null || cookieValue.isNull() ) { pos++; continue; } if( cookieValue.getType() != MessageBytes.T_BYTES ) { Exception e = new Exception(); log.warn("Cookies: Parsing cookie as String. Expected bytes.", e); cookieValue.toBytes(); } if(log.isDebugEnabled()) { log.debug("Cookies: Parsing b[]: " + cookieValue.toString()); } ByteChunk bc=cookieValue.getByteChunk(); processCookieHeader( bc.getBytes(), bc.getOffset(), bc.getLength()); pos++;// search from the next position } } // XXX will be refactored soon! private static boolean equals( String s, byte b[], int start, int end) { int blen = end-start; if (b == null || blen != s.length()) { return false; } int boff = start; for (int i = 0; i < blen; i++) { if (b[boff++] != s.charAt(i)) { return false; } } return true; } /** * Returns true if the byte is a whitespace character as * defined in RFC2619 * JVK */ private static final boolean isWhiteSpace(final byte c) { // This switch statement is slightly slower // for my vm than the if statement. // Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-164) /* switch (c) { case ' ':; case '\t':; case '\n':; case '\r':; case '\f':; return true; default:; return false; } */ if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f') { return true; } else { return false; } } /** * Unescapes any double quotes in the given cookie value. * * @param bc The cookie value to modify */ private static void unescapeDoubleQuotes(ByteChunk bc) { if (bc == null || bc.getLength() == 0 || bc.indexOf('"', 0) == -1) { return; } int src = bc.getStart(); int end = bc.getEnd(); int dest = src; byte[] buffer = bc.getBuffer(); while (src < end) { if (buffer[src] == '\\' && src < end && buffer[src+1] == '"') { src++; } buffer[dest] = buffer[src]; dest ++; src ++; } bc.setEnd(dest); } /** * Parses a cookie header after the initial "Cookie:" * [WS][$]token[WS]=[WS](token|QV)[;|,] * RFC 2965 * JVK */ protected final void processCookieHeader(byte bytes[], int off, int len){ if( len<=0 || bytes==null ) { return; } int end=off+len; int pos=off; int nameStart=0; int nameEnd=0; int valueStart=0; int valueEnd=0; int version = 0; ServerCookie sc=null; boolean isSpecial; boolean isQuoted; while (pos < end) { isSpecial = false; isQuoted = false; // Skip whitespace and non-token characters (separators) while (pos < end && (CookieSupport.isHttpSeparator((char) bytes[pos]) && !CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 || CookieSupport.isV0Separator((char) bytes[pos]) || isWhiteSpace(bytes[pos]))) {pos++; } if (pos >= end) { return; } // Detect Special cookies if (bytes[pos] == '$') { isSpecial = true; pos++; } // Get the cookie/attribute name. This must be a token valueEnd = valueStart = nameStart = pos; pos = nameEnd = getTokenEndPosition(bytes,pos,end,version,true); // Skip whitespace while (pos < end && isWhiteSpace(bytes[pos])) {pos++; } // Check for an '=' -- This could also be a name-only // cookie at the end of the cookie header, so if we // are past the end of the header, but we have a name // skip to the name-only part. if (pos < (end - 1) && bytes[pos] == '=') { // Skip whitespace do { pos++; } while (pos < end && isWhiteSpace(bytes[pos])); if (pos >= end) { return; } // Determine what type of value this is, quoted value, // token, name-only with an '=', or other (bad) switch (bytes[pos]) { case '"': // Quoted Value isQuoted = true; valueStart=pos + 1; // strip " // getQuotedValue returns the position before // at the last quote. This must be dealt with // when the bytes are copied into the cookie valueEnd=getQuotedValueEndPosition(bytes, valueStart, end); // We need pos to advance pos = valueEnd; // Handles cases where the quoted value is // unterminated and at the end of the header, // e.g. [myname="value] if (pos >= end) { return; } break; case ';': case ',': // Name-only cookie with an '=' after the name token // This may not be RFC compliant valueStart = valueEnd = -1; // The position is OK (On a delimiter) break; default: if (version == 0 && !CookieSupport.isV0Separator((char)bytes[pos]) && CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 || !CookieSupport.isHttpSeparator((char)bytes[pos]) || bytes[pos] == '=' && CookieSupport.ALLOW_EQUALS_IN_VALUE) { // Token valueStart=pos; // getToken returns the position at the delimiter // or other non-token character valueEnd=getTokenEndPosition(bytes, valueStart, end, version, false); // We need pos to advance pos = valueEnd; } else { // INVALID COOKIE, advance to next delimiter // The starting character of the cookie value was // not valid. UserDataHelper.Mode logMode = userDataLog.getNextMode(); if (logMode != null) { String message = sm.getString( "cookies.invalidCookieToken"); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString( "cookies.fallToDebug"); //$FALL-THROUGH$ case INFO: log.info(message); break; case DEBUG: log.debug(message); } } while (pos < end && bytes[pos] != ';' && bytes[pos] != ',') {pos++; } pos++; // Make sure no special avpairs can be attributed to // the previous cookie by setting the current cookie // to null sc = null; continue; } } } else { // Name only cookie valueStart = valueEnd = -1; pos = nameEnd; } // We should have an avpair or name-only cookie at this // point. Perform some basic checks to make sure we are // in a good state. // Skip whitespace while (pos < end && isWhiteSpace(bytes[pos])) {pos++; } // Make sure that after the cookie we have a separator. This // is only important if this is not the last cookie pair while (pos < end && bytes[pos] != ';' && bytes[pos] != ',') { pos++; } pos++; // All checks passed. Add the cookie, start with the // special avpairs first if (isSpecial) { isSpecial = false; // $Version must be the first avpair in the cookie header // (sc must be null) if (equals( "Version", bytes, nameStart, nameEnd) && sc == null) { // Set version if( bytes[valueStart] =='1' && valueEnd == (valueStart+1)) { version=1; } else { // unknown version (Versioning is not very strict) } continue; } // We need an active cookie for Path/Port/etc. if (sc == null) { continue; } // Domain is more common, so it goes first if (equals( "Domain", bytes, nameStart, nameEnd)) { sc.getDomain().setBytes( bytes, valueStart, valueEnd-valueStart); continue; } if (equals( "Path", bytes, nameStart, nameEnd)) { sc.getPath().setBytes( bytes, valueStart, valueEnd-valueStart); continue; } // v2 cookie attributes - skip them if (equals( "Port", bytes, nameStart, nameEnd)) { continue; } if (equals( "CommentURL", bytes, nameStart, nameEnd)) { continue; } // Unknown cookie, complain UserDataHelper.Mode logMode = userDataLog.getNextMode(); if (logMode != null) { String message = sm.getString("cookies.invalidSpecial"); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString("cookies.fallToDebug"); //$FALL-THROUGH$ case INFO: log.info(message); break; case DEBUG: log.debug(message); } } } else { // Normal Cookie if (valueStart == -1 && !CookieSupport.ALLOW_NAME_ONLY) { // Skip name only cookies if not supported continue; } sc = addCookie(); sc.setVersion( version ); sc.getName().setBytes( bytes, nameStart, nameEnd-nameStart); if (valueStart != -1) { // Normal AVPair sc.getValue().setBytes( bytes, valueStart, valueEnd-valueStart); if (isQuoted) { // We know this is a byte value so this is safe unescapeDoubleQuotes(sc.getValue().getByteChunk()); } } else { // Name Only sc.getValue().setString(""); } continue; } } } /** * Given the starting position of a token, this gets the end of the * token, with no separator characters in between. * JVK */ private static final int getTokenEndPosition(byte bytes[], int off, int end, int version, boolean isName){ int pos = off; while (pos < end && (!CookieSupport.isHttpSeparator((char)bytes[pos]) || version == 0 && CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && bytes[pos] != '=' && !CookieSupport.isV0Separator((char)bytes[pos]) || !isName && bytes[pos] == '=' && CookieSupport.ALLOW_EQUALS_IN_VALUE)) { pos++; } if (pos > end) { return end; } return pos; } /** * Given a starting position after an initial quote character, this gets * the position of the end quote. This escapes anything after a '\' char * JVK RFC 2616 */ private static final int getQuotedValueEndPosition(byte bytes[], int off, int end){ int pos = off; while (pos < end) { if (bytes[pos] == '"') { return pos; } else if (bytes[pos] == '\\' && pos < (end - 1)) { pos+=2; } else { pos++; } } // Error, we have reached the end of the header w/o a end quote return end; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/ContentType.java0000644000175100017510000000634512271452644024455 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; /** * Useful methods for Content-Type processing * * @author James Duncan Davidson [duncan@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author Harish Prabandham * @author costin@eng.sun.com */ public class ContentType { /** * Parse the character encoding from the specified content type header. * If the content type is null, or there is no explicit character encoding, * null is returned. * * @param contentType a content type header */ public static String getCharsetFromContentType(String contentType) { if (contentType == null) { return (null); } int start = contentType.indexOf("charset="); if (start < 0) { return (null); } String encoding = contentType.substring(start + 8); int end = encoding.indexOf(';'); if (end >= 0) { encoding = encoding.substring(0, end); } encoding = encoding.trim(); if ((encoding.length() > 2) && (encoding.startsWith("\"")) && (encoding.endsWith("\""))) { encoding = encoding.substring(1, encoding.length() - 1); } return (encoding.trim()); } /** * Returns true if the given content type contains a charset component, * false otherwise. * * @param type Content type * @return true if the given content type contains a charset component, * false otherwise */ public static boolean hasCharset(String type) { boolean hasCharset = false; int len = type.length(); int index = type.indexOf(';'); while (index != -1) { index++; while (index < len && Character.isSpace(type.charAt(index))) { index++; } if (index+8 < len && type.charAt(index) == 'c' && type.charAt(index+1) == 'h' && type.charAt(index+2) == 'a' && type.charAt(index+3) == 'r' && type.charAt(index+4) == 's' && type.charAt(index+5) == 'e' && type.charAt(index+6) == 't' && type.charAt(index+7) == '=') { hasCharset = true; break; } index = type.indexOf(';', index); } return hasCharset; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/package.html0000644000175100017510000000212012271452644023602 0ustar locutuslocutus util.http Special utils for handling HTTP-specific entities - headers, parameters, cookies, etc. The utils are not specific to tomcat, but use util.MessageBytes. tomcat7-7.0.52/java/org/apache/tomcat/util/http/FastHttpDateFormat.java0000644000175100017510000001406612271452644025704 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; /** * Utility class to generate HTTP dates. * * @author Remy Maucherat */ public final class FastHttpDateFormat { // -------------------------------------------------------------- Variables private static final int CACHE_SIZE = Integer.parseInt(System.getProperty("org.apache.tomcat.util.http.FastHttpDateFormat.CACHE_SIZE", "1000")); /** * HTTP date format. */ private static final SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); /** * The set of SimpleDateFormat formats to use in getDateHeader(). */ private static final SimpleDateFormat formats[] = { new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) }; private static final TimeZone gmtZone = TimeZone.getTimeZone("GMT"); /** * GMT timezone - all HTTP dates are on GMT */ static { format.setTimeZone(gmtZone); formats[0].setTimeZone(gmtZone); formats[1].setTimeZone(gmtZone); formats[2].setTimeZone(gmtZone); } /** * Instant on which the currentDate object was generated. */ private static volatile long currentDateGenerated = 0L; /** * Current formatted date. */ private static String currentDate = null; /** * Formatter cache. */ private static final ConcurrentHashMap formatCache = new ConcurrentHashMap(CACHE_SIZE); /** * Parser cache. */ private static final ConcurrentHashMap parseCache = new ConcurrentHashMap(CACHE_SIZE); // --------------------------------------------------------- Public Methods /** * Get the current date in HTTP format. */ public static final String getCurrentDate() { long now = System.currentTimeMillis(); if ((now - currentDateGenerated) > 1000) { synchronized (format) { if ((now - currentDateGenerated) > 1000) { currentDate = format.format(new Date(now)); currentDateGenerated = now; } } } return currentDate; } /** * Get the HTTP format of the specified date. */ public static final String formatDate (long value, DateFormat threadLocalformat) { Long longValue = new Long(value); String cachedDate = formatCache.get(longValue); if (cachedDate != null) { return cachedDate; } String newDate = null; Date dateValue = new Date(value); if (threadLocalformat != null) { newDate = threadLocalformat.format(dateValue); updateFormatCache(longValue, newDate); } else { synchronized (formatCache) { synchronized (format) { newDate = format.format(dateValue); } updateFormatCache(longValue, newDate); } } return newDate; } /** * Try to parse the given date as a HTTP date. */ public static final long parseDate(String value, DateFormat[] threadLocalformats) { Long cachedDate = parseCache.get(value); if (cachedDate != null) { return cachedDate.longValue(); } Long date = null; if (threadLocalformats != null) { date = internalParseDate(value, threadLocalformats); updateParseCache(value, date); } else { synchronized (parseCache) { date = internalParseDate(value, formats); updateParseCache(value, date); } } if (date == null) { return (-1L); } return date.longValue(); } /** * Parse date with given formatters. */ private static final Long internalParseDate (String value, DateFormat[] formats) { Date date = null; for (int i = 0; (date == null) && (i < formats.length); i++) { try { date = formats[i].parse(value); } catch (ParseException e) { // Ignore } } if (date == null) { return null; } return new Long(date.getTime()); } /** * Update cache. */ private static void updateFormatCache(Long key, String value) { if (value == null) { return; } if (formatCache.size() > CACHE_SIZE) { formatCache.clear(); } formatCache.put(key, value); } /** * Update cache. */ private static void updateParseCache(String key, Long value) { if (value == null) { return; } if (parseCache.size() > CACHE_SIZE) { parseCache.clear(); } parseCache.put(key, value); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/parser/0000755000175100017510000000000012301126367022614 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/http/parser/MediaType.java0000644000175100017510000001041412121347427025342 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.parser; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; public class MediaType { private final String type; private final String subtype; private final LinkedHashMap parameters; private final String charset; private volatile String noCharset; private volatile String withCharset; protected MediaType(String type, String subtype, LinkedHashMap parameters) { this.type = type; this.subtype = subtype; this.parameters = parameters; String cs = parameters.get("charset"); if (cs != null && cs.length() > 0 && cs.charAt(0) == '"') { cs = HttpParser.unquote(cs); } this.charset = cs; } public String getType() { return type; } public String getSubtype() { return subtype; } public String getCharset() { return charset; } public int getParameterCount() { return parameters.size(); } public String getParameterValue(String parameter) { return parameters.get(parameter.toLowerCase(Locale.ENGLISH)); } @Override public String toString() { if (withCharset == null) { synchronized (this) { if (withCharset == null) { StringBuilder result = new StringBuilder(); result.append(type); result.append('/'); result.append(subtype); for (Map.Entry entry : parameters.entrySet()) { String value = entry.getValue(); if (value == null || value.length() == 0) { continue; } result.append(';'); // Workaround for Adobe Read 9 plug-in on IE bug // Can be removed after 26 June 2013 (EOL of Reader 9) // See BZ 53814 result.append(' '); result.append(entry.getKey()); result.append('='); result.append(value); } withCharset = result.toString(); } } } return withCharset; } public String toStringNoCharset() { if (noCharset == null) { synchronized (this) { if (noCharset == null) { StringBuilder result = new StringBuilder(); result.append(type); result.append('/'); result.append(subtype); for (Map.Entry entry : parameters.entrySet()) { if (entry.getKey().equalsIgnoreCase("charset")) { continue; } result.append(';'); // Workaround for Adobe Read 9 plug-in on IE bug // Can be removed after 26 June 2013 (EOL of Reader 9) // See BZ 53814 result.append(' '); result.append(entry.getKey()); result.append('='); result.append(entry.getValue()); } noCharset = result.toString(); } } } return noCharset; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/parser/HttpParser.java0000644000175100017510000004064512204715631025564 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.parser; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; /** * HTTP header value parser implementation. Parsing HTTP headers as per RFC2616 * is not always as simple as it first appears. For headers that only use tokens * the simple approach will normally be sufficient. However, for the other * headers, while simple code meets 99.9% of cases, there are often some edge * cases that make things far more complicated. * * The purpose of this parser is to let the parser worry about the edge cases. * It provides tolerant (where safe to do so) parsing of HTTP header values * assuming that wrapped header lines have already been unwrapped. (The Tomcat * header processing code does the unwrapping.) * * Provides parsing of the following HTTP header values as per RFC 2616: * - Authorization for DIGEST authentication * - MediaType (used for Content-Type header) * * Support for additional headers will be provided as required. */ public class HttpParser { @SuppressWarnings("unused") // Unused due to buggy client implementations private static final Integer FIELD_TYPE_TOKEN = Integer.valueOf(0); private static final Integer FIELD_TYPE_QUOTED_STRING = Integer.valueOf(1); private static final Integer FIELD_TYPE_TOKEN_OR_QUOTED_STRING = Integer.valueOf(2); private static final Integer FIELD_TYPE_LHEX = Integer.valueOf(3); private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(4); private static final Map fieldTypes = new HashMap(); // Arrays used by isToken(), isHex() private static final boolean isToken[] = new boolean[128]; private static final boolean isHex[] = new boolean[128]; static { // Digest field types. // Note: These are more relaxed than RFC2617. This adheres to the // recommendation of RFC2616 that servers are tolerant of buggy // clients when they can be so without ambiguity. fieldTypes.put("username", FIELD_TYPE_QUOTED_STRING); fieldTypes.put("realm", FIELD_TYPE_QUOTED_STRING); fieldTypes.put("nonce", FIELD_TYPE_QUOTED_STRING); fieldTypes.put("digest-uri", FIELD_TYPE_QUOTED_STRING); // RFC2617 says response is <">32LHEX<">. 32LHEX will also be accepted fieldTypes.put("response", FIELD_TYPE_LHEX); // RFC2617 says algorithm is token. <">token<"> will also be accepted fieldTypes.put("algorithm", FIELD_TYPE_QUOTED_TOKEN); fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING); fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING); // RFC2617 says qop is token. <">token<"> will also be accepted fieldTypes.put("qop", FIELD_TYPE_QUOTED_TOKEN); // RFC2617 says nc is 8LHEX. <">8LHEX<"> will also be accepted fieldTypes.put("nc", FIELD_TYPE_LHEX); // Setup the flag arrays for (int i = 0; i < 128; i++) { if (i < 32) { isToken[i] = false; } else if (i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || i == '{' || i == '}' || i == ' ' || i == '\t') { isToken[i] = false; } else { isToken[i] = true; } if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' || i >= 'a' && i <= 'f') { isHex[i] = true; } else { isHex[i] = false; } } } /** * Parses an HTTP Authorization header for DIGEST authentication as per RFC * 2617 section 3.2.2. * * @param input The header value to parse * * @return A map of directives and values as {@link String}s or * null if a parsing error occurs. Although the * values returned are {@link String}s they will have been * validated to ensure that they conform to RFC 2617. * * @throws IllegalArgumentException If the header does not conform to RFC * 2617 * @throws IOException If an error occurs while reading the input */ public static Map parseAuthorizationDigest ( StringReader input) throws IllegalArgumentException, IOException { Map result = new HashMap(); if (skipConstant(input, "Digest") != SkipConstantResult.FOUND) { return null; } // All field names are valid tokens String field = readToken(input); if (field == null) { return null; } while (!field.equals("")) { if (skipConstant(input, "=") != SkipConstantResult.FOUND) { return null; } String value = null; Integer type = fieldTypes.get(field.toLowerCase(Locale.ENGLISH)); if (type == null) { // auth-param = token "=" ( token | quoted-string ) type = FIELD_TYPE_TOKEN_OR_QUOTED_STRING; } switch (type.intValue()) { case 0: // FIELD_TYPE_TOKEN value = readToken(input); break; case 1: // FIELD_TYPE_QUOTED_STRING value = readQuotedString(input, false); break; case 2: // FIELD_TYPE_TOKEN_OR_QUOTED_STRING value = readTokenOrQuotedString(input, false); break; case 3: // FIELD_TYPE_LHEX value = readLhex(input); break; case 4: // FIELD_TYPE_QUOTED_TOKEN value = readQuotedToken(input); break; default: // Error throw new IllegalArgumentException( "TODO i18n: Unsupported type"); } if (value == null) { return null; } result.put(field, value); if (skipConstant(input, ",") == SkipConstantResult.NOT_FOUND) { return null; } field = readToken(input); if (field == null) { return null; } } return result; } public static MediaType parseMediaType(StringReader input) throws IOException { // Type (required) String type = readToken(input); if (type == null || type.length() == 0) { return null; } if (skipConstant(input, "/") == SkipConstantResult.NOT_FOUND) { return null; } // Subtype (required) String subtype = readToken(input); if (subtype == null || subtype.length() == 0) { return null; } LinkedHashMap parameters = new LinkedHashMap(); SkipConstantResult lookForSemiColon = skipConstant(input, ";"); if (lookForSemiColon == SkipConstantResult.NOT_FOUND) { return null; } while (lookForSemiColon == SkipConstantResult.FOUND) { String attribute = readToken(input); String value = ""; if (skipConstant(input, "=") == SkipConstantResult.FOUND) { value = readTokenOrQuotedString(input, true); } if (attribute != null) { parameters.put(attribute.toLowerCase(Locale.ENGLISH), value); } lookForSemiColon = skipConstant(input, ";"); if (lookForSemiColon == SkipConstantResult.NOT_FOUND) { return null; } } return new MediaType(type, subtype, parameters); } public static String unquote(String input) { if (input == null || input.length() < 2 || input.charAt(0) != '"') { return input; } StringBuilder result = new StringBuilder(); for (int i = 1 ; i < (input.length() - 1); i++) { char c = input.charAt(i); if (input.charAt(i) == '\\') { i++; result.append(input.charAt(i)); } else { result.append(c); } } return result.toString(); } private static boolean isToken(int c) { // Fast for correct values, slower for incorrect ones try { return isToken[c]; } catch (ArrayIndexOutOfBoundsException ex) { return false; } } private static boolean isHex(int c) { // Fast for correct values, slower for incorrect ones try { return isHex[c]; } catch (ArrayIndexOutOfBoundsException ex) { return false; } } // Skip any LWS and return the next char private static int skipLws(StringReader input, boolean withReset) throws IOException { if (withReset) { input.mark(1); } int c = input.read(); while (c == 32 || c == 9 || c == 10 || c == 13) { if (withReset) { input.mark(1); } c = input.read(); } if (withReset) { input.reset(); } return c; } private static SkipConstantResult skipConstant(StringReader input, String constant) throws IOException { int len = constant.length(); int c = skipLws(input, false); for (int i = 0; i < len; i++) { if (i == 0 && c == -1) { return SkipConstantResult.EOF; } if (c != constant.charAt(i)) { input.skip(-(i + 1)); return SkipConstantResult.NOT_FOUND; } if (i != (len - 1)) { c = input.read(); } } return SkipConstantResult.FOUND; } /** * @return the token if one was found, the empty string if no data was * available to read or null if data other than a * token was found */ private static String readToken(StringReader input) throws IOException { StringBuilder result = new StringBuilder(); int c = skipLws(input, false); while (c != -1 && isToken(c)) { result.append((char) c); c = input.read(); } // Skip back so non-token character is available for next read input.skip(-1); if (c != -1 && result.length() == 0) { return null; } else { return result.toString(); } } /** * @return the quoted string if one was found, null if data other than a * quoted string was found or null if the end of data was reached * before the quoted string was terminated */ private static String readQuotedString(StringReader input, boolean returnQuoted) throws IOException { int c = skipLws(input, false); if (c != '"') { return null; } StringBuilder result = new StringBuilder(); if (returnQuoted) { result.append('\"'); } c = input.read(); while (c != '"') { if (c == -1) { return null; } else if (c == '\\') { c = input.read(); if (returnQuoted) { result.append('\\'); } result.append(c); } else { result.append((char) c); } c = input.read(); } if (returnQuoted) { result.append('\"'); } return result.toString(); } private static String readTokenOrQuotedString(StringReader input, boolean returnQuoted) throws IOException { // Go back so first non-LWS character is available to be read again int c = skipLws(input, true); if (c == '"') { return readQuotedString(input, returnQuoted); } else { return readToken(input); } } /** * Token can be read unambiguously with or without surrounding quotes so * this parsing method for token permits optional surrounding double quotes. * This is not defined in any RFC. It is a special case to handle data from * buggy clients (known buggy clients for DIGEST auth include Microsoft IE 8 * & 9, Apple Safari for OSX and iOS) that add quotes to values that * should be tokens. * * @return the token if one was found, null if data other than a token or * quoted token was found or null if the end of data was reached * before a quoted token was terminated */ private static String readQuotedToken(StringReader input) throws IOException { StringBuilder result = new StringBuilder(); boolean quoted = false; int c = skipLws(input, false); if (c == '"') { quoted = true; } else if (c == -1 || !isToken(c)) { return null; } else { result.append((char) c); } c = input.read(); while (c != -1 && isToken(c)) { result.append((char) c); c = input.read(); } if (quoted) { if (c != '"') { return null; } } else { // Skip back so non-token character is available for next read input.skip(-1); } if (c != -1 && result.length() == 0) { return null; } else { return result.toString(); } } /** * LHEX can be read unambiguously with or without surrounding quotes so this * parsing method for LHEX permits optional surrounding double quotes. Some * buggy clients (libwww-perl for DIGEST auth) are known to send quoted LHEX * when the specification requires just LHEX. * *

    * LHEX are, literally, lower-case hexadecimal digits. This implementation * allows for upper-case digits as well, converting the returned value to * lower-case. * * @return the sequence of LHEX (minus any surrounding quotes) if any was * found, or null if data other LHEX was found */ private static String readLhex(StringReader input) throws IOException { StringBuilder result = new StringBuilder(); boolean quoted = false; int c = skipLws(input, false); if (c == '"') { quoted = true; } else if (c == -1 || !isHex(c)) { return null; } else { if ('A' <= c && c <= 'F') { c -= ('A' - 'a'); } result.append((char) c); } c = input.read(); while (c != -1 && isHex(c)) { if ('A' <= c && c <= 'F') { c -= ('A' - 'a'); } result.append((char) c); c = input.read(); } if (quoted) { if (c != '"') { return null; } } else { // Skip back so non-hex character is available for next read input.skip(-1); } if (c != -1 && result.length() == 0) { return null; } else { return result.toString(); } } private static enum SkipConstantResult { FOUND, NOT_FOUND, EOF } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/parser/MediaTypeCache.java0000644000175100017510000000435212045302316026263 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http.parser; import java.io.IOException; import java.io.StringReader; import org.apache.tomcat.util.collections.ConcurrentCache; /** * Caches the results of parsing content-type headers. */ public class MediaTypeCache { private final ConcurrentCache cache; public MediaTypeCache(int size) { cache = new ConcurrentCache(size); } /** * Looks in the cache and returns the cached value if one is present. If no * match exists in the cache, a new parser is created, the input parsed and * the results placed in the cache and returned to the user. * * @param input The content-type header value to parse * @return The results are provided as a two element String array. The * first element is the media type less the charset and * the second element is the charset */ public String[] parse(String input) { String[] result = cache.get(input); if (result != null) { return result; } MediaType m = null; try { m = HttpParser.parseMediaType(new StringReader(input)); } catch (IOException e) { // Ignore - return null } if (m != null) { result = new String[] {m.toStringNoCharset(), m.getCharset()}; cache.put(input, result); } return result; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/CookieSupport.java0000644000175100017510000001771011656667222025013 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; /** * Static constants for this package. */ public final class CookieSupport { // --------------------------------------------------------------- Constants /** * If set to true, we parse cookies strictly according to the servlet, * cookie and HTTP specs by default. */ public static final boolean STRICT_SERVLET_COMPLIANCE; /** * If true, cookie values are allowed to contain an equals character without * being quoted. */ public static final boolean ALLOW_EQUALS_IN_VALUE; /** * If true, separators that are not explicitly dis-allowed by the v0 cookie * spec but are disallowed by the HTTP spec will be allowed in v0 cookie * names and values. These characters are: \"()/:<=>?@[\\]{} Note that the * inclusion of / depends on the value of {@link #FWD_SLASH_IS_SEPARATOR}. */ public static final boolean ALLOW_HTTP_SEPARATORS_IN_V0; /** * If set to false, we don't use the IE6/7 Max-Age/Expires work around. * Default is usually true. If STRICT_SERVLET_COMPLIANCE==true then default * is false. Explicitly setting always takes priority. */ public static final boolean ALWAYS_ADD_EXPIRES; /** * If set to true, the / character will be treated as a * separator. Default is usually false. If STRICT_SERVLET_COMPLIANCE==true * then default is true. Explicitly setting always takes priority. */ public static final boolean FWD_SLASH_IS_SEPARATOR; /** * If true, name only cookies will be permitted. */ public static final boolean ALLOW_NAME_ONLY; /** * The list of separators that apply to version 0 cookies. To quote the * spec, these are comma, semi-colon and white-space. The HTTP spec * definition of linear white space is [CRLF] 1*( SP | HT ) */ private static final char[] V0_SEPARATORS = {',', ';', ' ', '\t'}; private static final boolean[] V0_SEPARATOR_FLAGS = new boolean[128]; /** * The list of separators that apply to version 1 cookies. This may or may * not include '/' depending on the setting of * {@link #FWD_SLASH_IS_SEPARATOR}. */ private static final char[] HTTP_SEPARATORS; private static final boolean[] HTTP_SEPARATOR_FLAGS = new boolean[128]; static { STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty( "org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false")).booleanValue(); ALLOW_EQUALS_IN_VALUE = Boolean.valueOf(System.getProperty( "org.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE", "false")).booleanValue(); ALLOW_HTTP_SEPARATORS_IN_V0 = Boolean.valueOf(System.getProperty( "org.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0", "false")).booleanValue(); String alwaysAddExpires = System.getProperty( "org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES"); if (alwaysAddExpires == null) { ALWAYS_ADD_EXPIRES = !STRICT_SERVLET_COMPLIANCE; } else { ALWAYS_ADD_EXPIRES = Boolean.valueOf(alwaysAddExpires).booleanValue(); } String fwdSlashIsSeparator = System.getProperty( "org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR"); if (fwdSlashIsSeparator == null) { FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE; } else { FWD_SLASH_IS_SEPARATOR = Boolean.valueOf(fwdSlashIsSeparator).booleanValue(); } ALLOW_NAME_ONLY = Boolean.valueOf(System.getProperty( "org.apache.tomcat.util.http.ServerCookie.ALLOW_NAME_ONLY", "false")).booleanValue(); /* Excluding the '/' char by default violates the RFC, but it looks like a lot of people put '/' in unquoted values: '/': ; //47 '\t':9 ' ':32 '\"':34 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60 '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125 */ if (CookieSupport.FWD_SLASH_IS_SEPARATOR) { HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' }; } else { HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' }; } for (int i = 0; i < 128; i++) { V0_SEPARATOR_FLAGS[i] = false; HTTP_SEPARATOR_FLAGS[i] = false; } for (int i = 0; i < V0_SEPARATORS.length; i++) { V0_SEPARATOR_FLAGS[V0_SEPARATORS[i]] = true; } for (int i = 0; i < HTTP_SEPARATORS.length; i++) { HTTP_SEPARATOR_FLAGS[HTTP_SEPARATORS[i]] = true; } } // ----------------------------------------------------------------- Methods /** * Returns true if the byte is a separator as defined by V0 of the cookie * spec. */ public static final boolean isV0Separator(final char c) { if (c < 0x20 || c >= 0x7f) { if (c != 0x09) { throw new IllegalArgumentException( "Control character in cookie value or attribute."); } } return V0_SEPARATOR_FLAGS[c]; } public static boolean isV0Token(String value) { if( value==null) { return false; } int i = 0; int len = value.length(); if (alreadyQuoted(value)) { i++; len--; } for (; i < len; i++) { char c = value.charAt(i); if (isV0Separator(c)) { return true; } } return false; } /** * Returns true if the byte is a separator as defined by V1 of the cookie * spec, RFC2109. * @throws IllegalArgumentException if a control character was supplied as * input */ public static final boolean isHttpSeparator(final char c) { if (c < 0x20 || c >= 0x7f) { if (c != 0x09) { throw new IllegalArgumentException( "Control character in cookie value or attribute."); } } return HTTP_SEPARATOR_FLAGS[c]; } public static boolean isHttpToken(String value) { if( value==null) { return false; } int i = 0; int len = value.length(); if (alreadyQuoted(value)) { i++; len--; } for (; i < len; i++) { char c = value.charAt(i); if (isHttpSeparator(c)) { return true; } } return false; } public static boolean alreadyQuoted (String value) { if (value==null || value.length() < 2) { return false; } return (value.charAt(0)=='\"' && value.charAt(value.length()-1)=='\"'); } // ------------------------------------------------------------- Constructor private CookieSupport() { // Utility class. Don't allow instances to be created. } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/LocalStrings.properties0000644000175100017510000000506111766405123026050 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. parameters.bytes=Start processing with input [{0}] parameters.copyFail=Failed to create copy of original parameter values for debug logging purposes parameters.decodeFail.debug=Character decoding failed. Parameter [{0}] with value [{1}] has been ignored. parameters.decodeFail.info=Character decoding failed. Parameter [{0}] with value [{1}] has been ignored. Note that the name and value quoted here may be corrupted due to the failed decoding. Use debug level logging to see the original, non-corrupted values. parameters.emptyChunk=Empty parameter chunk ignored parameters.invalidChunk=Invalid chunk starting at byte [{0}] and ending at byte [{1}] with a value of [{2}] ignored parameters.maxCountFail=More than the maximum number of request parameters (GET plus POST) for a single request ([{0}]) were detected. Any parameters beyond this limit have been ignored. To change this limit, set the maxParameterCount attribute on the Connector. parameters.maxCountFail.fallToDebug=\n Note: further occurrences of this error will be logged at DEBUG level. parameters.multipleDecodingFail=Character decoding failed. A total of [{0}] failures were detected but only the first was logged. Enable debug level logging for this logger to log all failures. parameters.noequal=Parameter starting at position [{0}] and ending at position [{1}] with a value of [{0}] was not followed by an '=' character parameters.fallToDebug=\n Note: further occurrences of Parameter errors will be logged at DEBUG level. cookies.invalidCookieToken=Cookies: Invalid cookie. Value not a token or quoted value cookies.invalidSpecial=Cookies: Unknown Special Cookie cookies.fallToDebug=\n Note: further occurrences of Cookie errors will be logged at DEBUG level. headers.maxCountFail=More than the maximum allowed number of headers ([{0}]) were detected. tomcat7-7.0.52/java/org/apache/tomcat/util/http/ServerCookie.java0000644000175100017510000002474312271452644024603 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; import java.io.Serializable; import java.text.DateFormat; import java.text.FieldPosition; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import org.apache.tomcat.util.buf.MessageBytes; /** * Server-side cookie representation. * Allows recycling and uses MessageBytes as low-level * representation ( and thus the byte-> char conversion can be delayed * until we know the charset ). * * Tomcat.core uses this recyclable object to represent cookies, * and the facade will convert it to the external representation. */ public class ServerCookie implements Serializable { private static final long serialVersionUID = 1L; // Version 0 (Netscape) attributes private final MessageBytes name=MessageBytes.newInstance(); private final MessageBytes value=MessageBytes.newInstance(); // Expires - Not stored explicitly. Generated from Max-Age (see V1) private final MessageBytes path=MessageBytes.newInstance(); private final MessageBytes domain=MessageBytes.newInstance(); private boolean secure; // Version 1 (RFC2109) attributes private final MessageBytes comment=MessageBytes.newInstance(); private int maxAge = -1; private int version = 0; // Other fields private static final String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; private static final ThreadLocal OLD_COOKIE_FORMAT = new ThreadLocal() { @Override protected DateFormat initialValue() { DateFormat df = new SimpleDateFormat(OLD_COOKIE_PATTERN, Locale.US); df.setTimeZone(TimeZone.getTimeZone("GMT")); return df; } }; private static final String ancientDate; static { ancientDate = OLD_COOKIE_FORMAT.get().format(new Date(10000)); } // Note: Servlet Spec =< 3.0 only refers to Netscape and RFC2109, // not RFC2965 // Version 2 (RFC2965) attributes that would need to be added to support // v2 cookies // CommentURL // Discard - implied by maxAge <0 // Port public ServerCookie() { // NOOP } public void recycle() { path.recycle(); name.recycle(); value.recycle(); comment.recycle(); maxAge=-1; path.recycle(); domain.recycle(); version=0; secure=false; } public MessageBytes getComment() { return comment; } public MessageBytes getDomain() { return domain; } public void setMaxAge(int expiry) { maxAge = expiry; } public int getMaxAge() { return maxAge; } public MessageBytes getPath() { return path; } public void setSecure(boolean flag) { secure = flag; } public boolean getSecure() { return secure; } public MessageBytes getName() { return name; } public MessageBytes getValue() { return value; } public int getVersion() { return version; } public void setVersion(int v) { version = v; } // -------------------- utils -------------------- @Override public String toString() { return "Cookie " + getName() + "=" + getValue() + " ; " + getVersion() + " " + getPath() + " " + getDomain(); } // -------------------- Cookie parsing tools public static void appendCookieValue( StringBuffer headerBuf, int version, String name, String value, String path, String domain, String comment, int maxAge, boolean isSecure, boolean isHttpOnly) { StringBuffer buf = new StringBuffer(); // Servlet implementation checks name buf.append( name ); buf.append("="); // Servlet implementation does not check anything else /* * The spec allows some latitude on when to send the version attribute * with a Set-Cookie header. To be nice to clients, we'll make sure the * version attribute is first. That means checking the various things * that can cause us to switch to a v1 cookie first. * * Note that by checking for tokens we will also throw an exception if a * control character is encountered. */ // Start by using the version we were asked for int newVersion = version; // If it is v0, check if we need to switch if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(value) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(value))) { // HTTP token in value - need to use v1 newVersion = 1; } if (newVersion == 0 && comment != null) { // Using a comment makes it a v1 cookie newVersion = 1; } if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(path) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(path))) { // HTTP token in path - need to use v1 newVersion = 1; } if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(domain) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(domain))) { // HTTP token in domain - need to use v1 newVersion = 1; } // Now build the cookie header // Value maybeQuote(buf, value); // Add version 1 specific information if (newVersion == 1) { // Version=1 ... required buf.append ("; Version=1"); // Comment=comment if ( comment!=null ) { buf.append ("; Comment="); maybeQuote(buf, comment); } } // Add domain information, if present if (domain!=null) { buf.append("; Domain="); maybeQuote(buf, domain); } // Max-Age=secs ... or use old "Expires" format if (maxAge >= 0) { if (newVersion > 0) { buf.append ("; Max-Age="); buf.append (maxAge); } // IE6, IE7 and possibly other browsers don't understand Max-Age. // They do understand Expires, even with V1 cookies! if (newVersion == 0 || CookieSupport.ALWAYS_ADD_EXPIRES) { // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format ) buf.append ("; Expires="); // To expire immediately we need to set the time in past if (maxAge == 0) { buf.append( ancientDate ); } else { OLD_COOKIE_FORMAT.get().format( new Date(System.currentTimeMillis() + maxAge*1000L), buf, new FieldPosition(0)); } } } // Path=path if (path!=null) { buf.append ("; Path="); maybeQuote(buf, path); } // Secure if (isSecure) { buf.append ("; Secure"); } // HttpOnly if (isHttpOnly) { buf.append("; HttpOnly"); } headerBuf.append(buf); } /** * Quotes values if required. * @param buf * @param value */ private static void maybeQuote (StringBuffer buf, String value) { if (value==null || value.length()==0) { buf.append("\"\""); } else if (CookieSupport.alreadyQuoted(value)) { buf.append('"'); buf.append(escapeDoubleQuotes(value,1,value.length()-1)); buf.append('"'); } else if (CookieSupport.isHttpToken(value) && !CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 || CookieSupport.isV0Token(value) && CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0) { buf.append('"'); buf.append(escapeDoubleQuotes(value,0,value.length())); buf.append('"'); } else { buf.append(value); } } /** * Escapes any double quotes in the given string. * * @param s the input string * @param beginIndex start index inclusive * @param endIndex exclusive * @return The (possibly) escaped string */ private static String escapeDoubleQuotes(String s, int beginIndex, int endIndex) { if (s == null || s.length() == 0 || s.indexOf('"') == -1) { return s; } StringBuffer b = new StringBuffer(); for (int i = beginIndex; i < endIndex; i++) { char c = s.charAt(i); if (c == '\\' ) { b.append(c); //ignore the character after an escape, just append it if (++i>=endIndex) { throw new IllegalArgumentException("Invalid escape character in cookie value."); } b.append(s.charAt(i)); } else if (c == '"') { b.append('\\').append('"'); } else { b.append(c); } } return b.toString(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/Parameters.java0000644000175100017510000004334312271452644024303 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.Map; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.buf.UDecoder; import org.apache.tomcat.util.log.UserDataHelper; import org.apache.tomcat.util.res.StringManager; /** * * @author Costin Manolache */ public final class Parameters { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(Parameters.class ); private static final UserDataHelper userDataLog = new UserDataHelper(log); private static final UserDataHelper maxParamCountLog = new UserDataHelper(log); protected static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.http"); private final Map> paramHashValues = new LinkedHashMap>(); private boolean didQueryParameters=false; MessageBytes queryMB; UDecoder urlDec; MessageBytes decodedQuery=MessageBytes.newInstance(); String encoding=null; String queryStringEncoding=null; private int limit = -1; private int parameterCount = 0; /** * Is set to true if there were failures during parameter * parsing. */ private boolean parseFailed = false; public Parameters() { // NO-OP } public void setQuery( MessageBytes queryMB ) { this.queryMB=queryMB; } public void setLimit(int limit) { this.limit = limit; } public String getEncoding() { return encoding; } public void setEncoding( String s ) { encoding=s; if(log.isDebugEnabled()) { log.debug( "Set encoding to " + s ); } } public void setQueryStringEncoding( String s ) { queryStringEncoding=s; if(log.isDebugEnabled()) { log.debug( "Set query string encoding to " + s ); } } public boolean isParseFailed() { return parseFailed; } public void setParseFailed(boolean parseFailed) { this.parseFailed = parseFailed; } public void recycle() { parameterCount = 0; paramHashValues.clear(); didQueryParameters=false; encoding=null; decodedQuery.recycle(); parseFailed = false; } // -------------------- Data access -------------------- // Access to the current name/values, no side effect ( processing ). // You must explicitly call handleQueryParameters and the post methods. @Deprecated public void addParameterValues(String key, String[] newValues) { if (key == null) { return; } ArrayList values = paramHashValues.get(key); if (values == null) { values = new ArrayList(newValues.length); paramHashValues.put(key, values); } else { values.ensureCapacity(values.size() + newValues.length); } for (String newValue : newValues) { values.add(newValue); } } public String[] getParameterValues(String name) { handleQueryParameters(); // no "facade" ArrayList values = paramHashValues.get(name); if (values == null) { return null; } return values.toArray(new String[values.size()]); } public Enumeration getParameterNames() { handleQueryParameters(); return Collections.enumeration(paramHashValues.keySet()); } public String getParameter(String name ) { handleQueryParameters(); ArrayList values = paramHashValues.get(name); if (values != null) { if(values.size() == 0) { return ""; } return values.get(0); } else { return null; } } // -------------------- Processing -------------------- /** Process the query string into parameters */ public void handleQueryParameters() { if( didQueryParameters ) { return; } didQueryParameters=true; if( queryMB==null || queryMB.isNull() ) { return; } if(log.isDebugEnabled()) { log.debug("Decoding query " + decodedQuery + " " + queryStringEncoding); } try { decodedQuery.duplicate( queryMB ); } catch (IOException e) { // Can't happen, as decodedQuery can't overflow e.printStackTrace(); } processParameters( decodedQuery, queryStringEncoding ); } public void addParameter( String key, String value ) throws IllegalStateException { if( key==null ) { return; } parameterCount ++; if (limit > -1 && parameterCount > limit) { // Processing this parameter will push us over the limit. ISE is // what Request.parseParts() uses for requests that are too big parseFailed = true; throw new IllegalStateException(sm.getString( "parameters.maxCountFail", Integer.valueOf(limit))); } ArrayList values = paramHashValues.get(key); if (values == null) { values = new ArrayList(1); paramHashValues.put(key, values); } values.add(value); } public void setURLDecoder( UDecoder u ) { urlDec=u; } // -------------------- Parameter parsing -------------------- // we are called from a single thread - we can do it the hard way // if needed ByteChunk tmpName=new ByteChunk(); ByteChunk tmpValue=new ByteChunk(); private final ByteChunk origName=new ByteChunk(); private final ByteChunk origValue=new ByteChunk(); CharChunk tmpNameC=new CharChunk(1024); public static final String DEFAULT_ENCODING = "ISO-8859-1"; private static final Charset DEFAULT_CHARSET = Charset.forName(DEFAULT_ENCODING); public void processParameters( byte bytes[], int start, int len ) { processParameters(bytes, start, len, getCharset(encoding)); } private void processParameters(byte bytes[], int start, int len, Charset charset) { if(log.isDebugEnabled()) { log.debug(sm.getString("parameters.bytes", new String(bytes, start, len, DEFAULT_CHARSET))); } int decodeFailCount = 0; int pos = start; int end = start + len; while(pos < end) { int nameStart = pos; int nameEnd = -1; int valueStart = -1; int valueEnd = -1; boolean parsingName = true; boolean decodeName = false; boolean decodeValue = false; boolean parameterComplete = false; do { switch(bytes[pos]) { case '=': if (parsingName) { // Name finished. Value starts from next character nameEnd = pos; parsingName = false; valueStart = ++pos; } else { // Equals character in value pos++; } break; case '&': if (parsingName) { // Name finished. No value. nameEnd = pos; } else { // Value finished valueEnd = pos; } parameterComplete = true; pos++; break; case '%': case '+': // Decoding required if (parsingName) { decodeName = true; } else { decodeValue = true; } pos ++; break; default: pos ++; break; } } while (!parameterComplete && pos < end); if (pos == end) { if (nameEnd == -1) { nameEnd = pos; } else if (valueStart > -1 && valueEnd == -1){ valueEnd = pos; } } if (log.isDebugEnabled() && valueStart == -1) { log.debug(sm.getString("parameters.noequal", Integer.valueOf(nameStart), Integer.valueOf(nameEnd), new String(bytes, nameStart, nameEnd-nameStart, DEFAULT_CHARSET))); } if (nameEnd <= nameStart ) { if (valueStart == -1) { // && if (log.isDebugEnabled()) { log.debug(sm.getString("parameters.emptyChunk")); } // Do not flag as error continue; } // &=foo& UserDataHelper.Mode logMode = userDataLog.getNextMode(); if (logMode != null) { String extract; if (valueEnd > nameStart) { extract = new String(bytes, nameStart, valueEnd - nameStart, DEFAULT_CHARSET); } else { extract = ""; } String message = sm.getString("parameters.invalidChunk", Integer.valueOf(nameStart), Integer.valueOf(valueEnd), extract); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString("parameters.fallToDebug"); //$FALL-THROUGH$ case INFO: log.info(message); break; case DEBUG: log.debug(message); } } parseFailed = true; continue; // invalid chunk - it's better to ignore } tmpName.setBytes(bytes, nameStart, nameEnd - nameStart); if (valueStart >= 0) { tmpValue.setBytes(bytes, valueStart, valueEnd - valueStart); } else { tmpValue.setBytes(bytes, 0, 0); } // Take copies as if anything goes wrong originals will be // corrupted. This means original values can be logged. // For performance - only done for debug if (log.isDebugEnabled()) { try { origName.append(bytes, nameStart, nameEnd - nameStart); if (valueStart >= 0) { origValue.append(bytes, valueStart, valueEnd - valueStart); } else { origValue.append(bytes, 0, 0); } } catch (IOException ioe) { // Should never happen... log.error(sm.getString("parameters.copyFail"), ioe); } } try { String name; String value; if (decodeName) { urlDecode(tmpName); } tmpName.setCharset(charset); name = tmpName.toString(); if (valueStart >= 0) { if (decodeValue) { urlDecode(tmpValue); } tmpValue.setCharset(charset); value = tmpValue.toString(); } else { value = ""; } try { addParameter(name, value); } catch (IllegalStateException ise) { // Hitting limit stops processing further params but does // not cause request to fail. parseFailed = true; UserDataHelper.Mode logMode = maxParamCountLog.getNextMode(); if (logMode != null) { String message = ise.getMessage(); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString( "parameters.maxCountFail.fallToDebug"); //$FALL-THROUGH$ case INFO: log.info(message); break; case DEBUG: log.debug(message); } } break; } } catch (IOException e) { parseFailed = true; decodeFailCount++; if (decodeFailCount == 1 || log.isDebugEnabled()) { if (log.isDebugEnabled()) { log.debug(sm.getString("parameters.decodeFail.debug", origName.toString(), origValue.toString()), e); } else if (log.isInfoEnabled()) { UserDataHelper.Mode logMode = userDataLog.getNextMode(); if (logMode != null) { String message = sm.getString( "parameters.decodeFail.info", tmpName.toString(), tmpValue.toString()); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString("parameters.fallToDebug"); //$FALL-THROUGH$ case INFO: log.info(message); break; case DEBUG: log.debug(message); } } } } } tmpName.recycle(); tmpValue.recycle(); // Only recycle copies if we used them if (log.isDebugEnabled()) { origName.recycle(); origValue.recycle(); } } if (decodeFailCount > 1 && !log.isDebugEnabled()) { UserDataHelper.Mode logMode = userDataLog.getNextMode(); if (logMode != null) { String message = sm.getString( "parameters.multipleDecodingFail", Integer.valueOf(decodeFailCount)); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString("parameters.fallToDebug"); //$FALL-THROUGH$ case INFO: log.info(message); break; case DEBUG: log.debug(message); } } } } private void urlDecode(ByteChunk bc) throws IOException { if( urlDec==null ) { urlDec=new UDecoder(); } urlDec.convert(bc, true); } public void processParameters( MessageBytes data, String encoding ) { if( data==null || data.isNull() || data.getLength() <= 0 ) { return; } if( data.getType() != MessageBytes.T_BYTES ) { data.toBytes(); } ByteChunk bc=data.getByteChunk(); processParameters( bc.getBytes(), bc.getOffset(), bc.getLength(), getCharset(encoding)); } private Charset getCharset(String encoding) { if (encoding == null) { return DEFAULT_CHARSET; } try { return B2CConverter.getCharset(encoding); } catch (UnsupportedEncodingException e) { return DEFAULT_CHARSET; } } /** * Debug purpose */ public String paramsAsString() { StringBuilder sb = new StringBuilder(); for (Map.Entry> e : paramHashValues.entrySet()) { sb.append(e.getKey()).append('='); ArrayList values = e.getValue(); for (String value : values) { sb.append(value).append(','); } sb.append('\n'); } return sb.toString(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/RequestUtil.java0000644000175100017510000000673411712214520024455 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; public class RequestUtil { private RequestUtil() { // Hide default constructor as this is a utility class } /** * Normalize a relative URI path that may have relative values ("/./", * "/../", and so on ) it it. WARNING - This method is * useful only for normalizing application-generated paths. It does not * try to perform security checks for malicious input. * * @param path Relative path to be normalized */ public static String normalize(String path) { return normalize(path, true); } /** * Normalize a relative URI path that may have relative values ("/./", * "/../", and so on ) it it. WARNING - This method is * useful only for normalizing application-generated paths. It does not * try to perform security checks for malicious input. * * @param path Relative path to be normalized * @param replaceBackSlash Should '\\' be replaced with '/' */ public static String normalize(String path, boolean replaceBackSlash) { if (path == null) return null; // Create a place for the normalized path String normalized = path; if (replaceBackSlash && normalized.indexOf('\\') >= 0) normalized = normalized.replace('\\', '/'); if (normalized.equals("/.")) return "/"; // Add a leading "/" if necessary if (!normalized.startsWith("/")) normalized = "/" + normalized; // Resolve occurrences of "//" in the normalized path while (true) { int index = normalized.indexOf("//"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 1); } // Resolve occurrences of "/./" in the normalized path while (true) { int index = normalized.indexOf("/./"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 2); } // Resolve occurrences of "/../" in the normalized path while (true) { int index = normalized.indexOf("/../"); if (index < 0) break; if (index == 0) return (null); // Trying to go outside our context int index2 = normalized.lastIndexOf('/', index - 1); normalized = normalized.substring(0, index2) + normalized.substring(index + 3); } // Return the normalized path that we have completed return (normalized); } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/MimeHeaders.java0000644000175100017510000003620312271452644024360 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Enumeration; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.res.StringManager; /* XXX XXX XXX Need a major rewrite !!!! */ /** * This class is used to contain standard internet message headers, * used for SMTP (RFC822) and HTTP (RFC2068) messages as well as for * MIME (RFC 2045) applications such as transferring typed data and * grouping related items in multipart message bodies. * *

    Message headers, as specified in RFC822, include a field name * and a field body. Order has no semantic significance, and several * fields with the same name may exist. However, most fields do not * (and should not) exist more than once in a header. * *

    Many kinds of field body must conform to a specified syntax, * including the standard parenthesized comment syntax. This class * supports only two simple syntaxes, for dates and integers. * *

    When processing headers, care must be taken to handle the case of * multiple same-name fields correctly. The values of such fields are * only available as strings. They may be accessed by index (treating * the header as an array of fields), or by name (returning an array * of string values). */ /* Headers are first parsed and stored in the order they are received. This is based on the fact that most servlets will not directly access all headers, and most headers are single-valued. ( the alternative - a hash or similar data structure - will add an overhead that is not needed in most cases ) Apache seems to be using a similar method for storing and manipulating headers. Future enhancements: - hash the headers the first time a header is requested ( i.e. if the servlet needs direct access to headers). - scan "common" values ( length, cookies, etc ) during the parse ( addHeader hook ) */ /** * Memory-efficient repository for Mime Headers. When the object is recycled, it * will keep the allocated headers[] and all the MimeHeaderField - no GC is generated. * * For input headers it is possible to use the MessageByte for Fields - so no GC * will be generated. * * The only garbage is generated when using the String for header names/values - * this can't be avoided when the servlet calls header methods, but is easy * to avoid inside tomcat. The goal is to use _only_ MessageByte-based Fields, * and reduce to 0 the memory overhead of tomcat. * * TODO: * XXX one-buffer parsing - for http ( other protocols don't need that ) * XXX remove unused methods * XXX External enumerations, with 0 GC. * XXX use HeaderName ID * * * @author dac@eng.sun.com * @author James Todd [gonzo@eng.sun.com] * @author Costin Manolache * @author kevin seguin */ public class MimeHeaders { /** Initial size - should be == average number of headers per request * XXX make it configurable ( fine-tuning of web-apps ) */ public static final int DEFAULT_HEADER_SIZE=8; private static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.http"); /** * The header fields. */ private MimeHeaderField[] headers = new MimeHeaderField[DEFAULT_HEADER_SIZE]; /** * The current number of header fields. */ private int count; /** * The limit on the number of header fields. */ private int limit = -1; /** * Creates a new MimeHeaders object using a default buffer size. */ public MimeHeaders() { // NO-OP } /** * Set limit on the number of header fields. */ public void setLimit(int limit) { this.limit = limit; if (limit > 0 && headers.length > limit && count < limit) { // shrink header list array MimeHeaderField tmp[] = new MimeHeaderField[limit]; System.arraycopy(headers, 0, tmp, 0, count); headers = tmp; } } /** * Clears all header fields. */ // [seguin] added for consistency -- most other objects have recycle(). public void recycle() { clear(); } /** * Clears all header fields. */ public void clear() { for (int i = 0; i < count; i++) { headers[i].recycle(); } count = 0; } /** * EXPENSIVE!!! only for debugging. */ @Override public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.println("=== MimeHeaders ==="); Enumeration e = names(); while (e.hasMoreElements()) { String n = e.nextElement(); Enumeration ev = values(n); while (ev.hasMoreElements()) { pw.print(n); pw.print(" = "); pw.println(ev.nextElement()); } } return sw.toString(); } // -------------------- Idx access to headers ---------- /** * Returns the current number of header fields. */ public int size() { return count; } /** * Returns the Nth header name, or null if there is no such header. * This may be used to iterate through all header fields. */ public MessageBytes getName(int n) { return n >= 0 && n < count ? headers[n].getName() : null; } /** * Returns the Nth header value, or null if there is no such header. * This may be used to iterate through all header fields. */ public MessageBytes getValue(int n) { return n >= 0 && n < count ? headers[n].getValue() : null; } /** Find the index of a header with the given name. */ public int findHeader( String name, int starting ) { // We can use a hash - but it's not clear how much // benefit you can get - there is an overhead // and the number of headers is small (4-5 ?) // Another problem is that we'll pay the overhead // of constructing the hashtable // A custom search tree may be better for (int i = starting; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { return i; } } return -1; } // -------------------- -------------------- /** * Returns an enumeration of strings representing the header field names. * Field names may appear multiple times in this enumeration, indicating * that multiple fields with that name exist in this header. */ public Enumeration names() { return new NamesEnumerator(this); } public Enumeration values(String name) { return new ValuesEnumerator(this, name); } // -------------------- Adding headers -------------------- /** * Adds a partially constructed field to the header. This * field has not had its name or value initialized. */ private MimeHeaderField createHeader() { if (limit > -1 && count >= limit) { throw new IllegalStateException(sm.getString( "headers.maxCountFail", Integer.valueOf(limit))); } MimeHeaderField mh; int len = headers.length; if (count >= len) { // expand header list array int newLength = count * 2; if (limit > 0 && newLength > limit) { newLength = limit; } MimeHeaderField tmp[] = new MimeHeaderField[newLength]; System.arraycopy(headers, 0, tmp, 0, len); headers = tmp; } if ((mh = headers[count]) == null) { headers[count] = mh = new MimeHeaderField(); } count++; return mh; } /** Create a new named header , return the MessageBytes container for the new value */ public MessageBytes addValue( String name ) { MimeHeaderField mh = createHeader(); mh.getName().setString(name); return mh.getValue(); } /** Create a new named header using un-translated byte[]. The conversion to chars can be delayed until encoding is known. */ public MessageBytes addValue(byte b[], int startN, int len) { MimeHeaderField mhf=createHeader(); mhf.getName().setBytes(b, startN, len); return mhf.getValue(); } /** Create a new named header using translated char[]. */ public MessageBytes addValue(char c[], int startN, int len) { MimeHeaderField mhf=createHeader(); mhf.getName().setChars(c, startN, len); return mhf.getValue(); } /** Allow "set" operations - return a MessageBytes container for the header value ( existing header or new if this . */ public MessageBytes setValue( String name ) { for ( int i = 0; i < count; i++ ) { if(headers[i].getName().equalsIgnoreCase(name)) { for ( int j=i+1; j < count; j++ ) { if(headers[j].getName().equalsIgnoreCase(name)) { removeHeader(j--); } } return headers[i].getValue(); } } MimeHeaderField mh = createHeader(); mh.getName().setString(name); return mh.getValue(); } //-------------------- Getting headers -------------------- /** * Finds and returns a header field with the given name. If no such * field exists, null is returned. If more than one such field is * in the header, an arbitrary one is returned. */ public MessageBytes getValue(String name) { for (int i = 0; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { return headers[i].getValue(); } } return null; } /** * Finds and returns a unique header field with the given name. If no such * field exists, null is returned. If the specified header field is not * unique then an {@link IllegalArgumentException} is thrown. */ public MessageBytes getUniqueValue(String name) { MessageBytes result = null; for (int i = 0; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { if (result == null) { result = headers[i].getValue(); } else { throw new IllegalArgumentException(); } } } return result; } // bad shortcut - it'll convert to string ( too early probably, // encoding is guessed very late ) public String getHeader(String name) { MessageBytes mh = getValue(name); return mh != null ? mh.toString() : null; } // -------------------- Removing -------------------- /** * Removes a header field with the specified name. Does nothing * if such a field could not be found. * @param name the name of the header field to be removed */ public void removeHeader(String name) { // XXX // warning: rather sticky code; heavily tuned for (int i = 0; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { removeHeader(i--); } } } /** * reset and swap with last header * @param idx the index of the header to remove. */ private void removeHeader(int idx) { MimeHeaderField mh = headers[idx]; mh.recycle(); headers[idx] = headers[count - 1]; headers[count - 1] = mh; count--; } } /** Enumerate the distinct header names. Each nextElement() is O(n) ( a comparison is done with all previous elements ). This is less frequent than add() - we want to keep add O(1). */ class NamesEnumerator implements Enumeration { int pos; int size; String next; MimeHeaders headers; public NamesEnumerator(MimeHeaders headers) { this.headers=headers; pos=0; size = headers.size(); findNext(); } private void findNext() { next=null; for(; pos< size; pos++ ) { next=headers.getName( pos ).toString(); for( int j=0; j { int pos; int size; MessageBytes next; MimeHeaders headers; String name; ValuesEnumerator(MimeHeaders headers, String name) { this.name=name; this.headers=headers; pos=0; size = headers.size(); findNext(); } private void findNext() { next=null; for(; pos< size; pos++ ) { MessageBytes n1=headers.getName( pos ); if( n1.equalsIgnoreCase( name )) { next=headers.getValue( pos ); break; } } pos++; } @Override public boolean hasMoreElements() { return next!=null; } @Override public String nextElement() { MessageBytes current=next; findNext(); return current.toString(); } } class MimeHeaderField { // multiple headers with same name - a linked list will // speed up name enumerations and search ( both cpu and // GC) MimeHeaderField next; MimeHeaderField prev; protected final MessageBytes nameB = MessageBytes.newInstance(); protected final MessageBytes valueB = MessageBytes.newInstance(); /** * Creates a new, uninitialized header field. */ public MimeHeaderField() { // NO-OP } public void recycle() { nameB.recycle(); valueB.recycle(); next=null; } public MessageBytes getName() { return nameB; } public MessageBytes getValue() { return valueB; } } tomcat7-7.0.52/java/org/apache/tomcat/util/http/HttpMessages.java0000644000175100017510000001340312271452644024601 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.http; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.tomcat.util.res.StringManager; /** * Handle (internationalized) HTTP messages. * * @author James Duncan Davidson [duncan@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author Harish Prabandham * @author costin@eng.sun.com */ public class HttpMessages { private static final Map instances = new ConcurrentHashMap(); private static final HttpMessages DEFAULT = new HttpMessages( StringManager.getManager("org.apache.tomcat.util.http.res", Locale.getDefault())); // XXX move message resources in this package private final StringManager sm; private String st_200 = null; private String st_302 = null; private String st_400 = null; private String st_404 = null; private HttpMessages(StringManager sm) { this.sm = sm; } /** Get the status string associated with a status code. * No I18N - return the messages defined in the HTTP spec. * ( the user isn't supposed to see them, this is the last * thing to translate) * * Common messages are cached. * */ public String getMessage(int status) { // method from Response. // Does HTTP requires/allow international messages or // are pre-defined? The user doesn't see them most of the time switch( status ) { case 200: if(st_200 == null ) { st_200 = sm.getString("sc.200"); } return st_200; case 302: if(st_302 == null ) { st_302 = sm.getString("sc.302"); } return st_302; case 400: if(st_400 == null ) { st_400 = sm.getString("sc.400"); } return st_400; case 404: if(st_404 == null ) { st_404 = sm.getString("sc.404"); } return st_404; } return sm.getString("sc."+ status); } public static HttpMessages getInstance(Locale locale) { HttpMessages result = instances.get(locale); if (result == null) { StringManager sm = StringManager.getManager( "org.apache.tomcat.util.http.res", locale); if (Locale.getDefault().equals(sm.getLocale())) { result = DEFAULT; } else { result = new HttpMessages(sm); } instances.put(locale, result); } return result; } /** * Filter the specified message string for characters that are sensitive * in HTML. This avoids potential attacks caused by including JavaScript * codes in the request URL that is often reported in error messages. * * @param message The message string to be filtered */ public static String filter(String message) { if (message == null) { return (null); } char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); } /** * Is the provided message safe to use in an HTTP header. Safe messages must * meet the requirements of RFC2616 - i.e. must consist only of TEXT. * * @param msg The message to test * @return true if the message is safe to use in an HTTP * header else false */ public static boolean isSafeInHttpHeader(String msg) { // Nulls are fine. It is up to the calling code to address any NPE // concerns if (msg == null) { return true; } // Reason-Phrase is defined as * // TEXT is defined as any OCTET except CTLs, but including LWS // OCTET is defined as an 8-bit sequence of data // CTL is defined as octets 0-31 and 127 // LWS, if we exclude CR LF pairs, is defined as SP or HT (32, 9) final int len = msg.length(); for (int i = 0; i < len; i++) { char c = msg.charAt(i); if (32 <= c && c <= 126 || 128 <= c && c <= 255 || c == 9) { continue; } return false; } return true; } } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/0000755000175100017510000000000012301126367021416 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/codec/BinaryEncoder.java0000644000175100017510000000252412271446130025007 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec; /** * Defines common encoding methods for byte array encoders. */ public interface BinaryEncoder extends Encoder { /** * Encodes a byte array and return the encoded data as a byte array. * * @param source * Data to be encoded * @return A byte array containing the encoded data * @throws EncoderException * thrown if the Encoder encounters a failure condition during the encoding process. */ byte[] encode(byte[] source) throws EncoderException; } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/Decoder.java0000644000175100017510000000373712271446130023637 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec; /** * Provides the highest level of abstraction for Decoders. *

    * This is the sister interface of {@link Encoder}. All Decoders implement this common generic interface. * Allows a user to pass a generic Object to any Decoder implementation in the codec package. *

    * One of the two interfaces at the center of the codec package. */ public interface Decoder { /** * Decodes an "encoded" Object and returns a "decoded" Object. Note that the implementation of this interface will * try to cast the Object parameter to the specific type expected by a particular Decoder implementation. If a * {@link ClassCastException} occurs this decode method will throw a DecoderException. * * @param source * the object to decode * @return a 'decoded" object * @throws DecoderException * a decoder exception can be thrown for any number of reasons. Some good candidates are that the * parameter passed to this method is null, a param cannot be cast to the appropriate type for a * specific encoder. */ Object decode(Object source) throws DecoderException; } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/Encoder.java0000644000175100017510000000326512271446130023645 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec; /** * Provides the highest level of abstraction for Encoders. *

    * This is the sister interface of {@link Decoder}. Every implementation of Encoder provides this * common generic interface which allows a user to pass a generic Object to any Encoder implementation * in the codec package. */ public interface Encoder { /** * Encodes an "Object" and returns the encoded content as an Object. The Objects here may just be * byte[] or Strings depending on the implementation used. * * @param source * An object to encode * @return An "encoded" Object * @throws EncoderException * An encoder exception is thrown if the encoder experiences a failure condition during the encoding * process. */ Object encode(Object source) throws EncoderException; } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/binary/0000755000175100017510000000000012301126367022702 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/codec/binary/Base64.java0000644000175100017510000010130612271446130024571 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec.binary; import java.math.BigInteger; /** * Provides Base64 encoding and decoding as defined by RFC 2045. * *

    * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein. *

    *

    * The class can be parameterized in the following manner with various constructors: *

      *
    • URL-safe mode: Default off.
    • *
    • Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of * 4 in the encoded data. *
    • Line separator: Default is CRLF ("\r\n")
    • *
    *

    *

    * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only * encode/decode character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, * UTF-8, etc). *

    *

    * This class is thread-safe. *

    * * @see RFC 2045 * @since 1.0 */ public class Base64 extends BaseNCodec { /** * BASE32 characters are 6 bits in length. * They are formed by taking a block of 3 octets to form a 24-bit string, * which is converted into 4 BASE64 characters. */ private static final int BITS_PER_ENCODED_BYTE = 6; private static final int BYTES_PER_UNENCODED_BLOCK = 3; private static final int BYTES_PER_ENCODED_BLOCK = 4; /** * Chunk separator per RFC 2045 section 2.1. * *

    * N.B. The next major release may break compatibility and make this field private. *

    * * @see RFC 2045 section 2.1 */ static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; /** * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" * equivalents as specified in Table 1 of RFC 2045. * * Thanks to "commons" project in ws.apache.org for this code. * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ */ private static final byte[] STANDARD_ENCODE_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; /** * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and / * changed to - and _ to make the encoded Base64 results more URL-SAFE. * This table is only used when the Base64's mode is set to URL-SAFE. */ private static final byte[] URL_SAFE_ENCODE_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' }; /** * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified * in Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64 * alphabet but fall within the bounds of the array are translated to -1. * * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit). * * Thanks to "commons" project in ws.apache.org for this code. * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ */ private static final byte[] DECODE_TABLE = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; /** * Base64 uses 6-bit fields. */ /** Mask used to extract 6 bits, used when encoding */ private static final int MASK_6BITS = 0x3f; // The static final fields above are used for the original static byte[] methods on Base64. // The private member fields below are used with the new streaming approach, which requires // some state be preserved between calls of encode() and decode(). /** * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch * between the two modes. */ private final byte[] encodeTable; // Only one decode table currently; keep for consistency with Base32 code private final byte[] decodeTable = DECODE_TABLE; /** * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. */ private final byte[] lineSeparator; /** * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. * decodeSize = 3 + lineSeparator.length; */ private final int decodeSize; /** * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. * encodeSize = 4 + lineSeparator.length; */ private final int encodeSize; /** * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

    * When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE. *

    * *

    * When decoding all variants are supported. *

    */ public Base64() { this(0); } /** * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. *

    * When encoding the line length is 76, the line separator is CRLF, and the encoding table is * STANDARD_ENCODE_TABLE. *

    * *

    * When decoding all variants are supported. *

    * * @param urlSafe * if {@code true}, URL-safe encoding is used. In most cases this should be set to {@code false}. * @since 1.4 */ public Base64(final boolean urlSafe) { this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe); } /** * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

    * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is * STANDARD_ENCODE_TABLE. *

    *

    * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. *

    *

    * When decoding all variants are supported. *

    * * @param lineLength * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when * decoding. * @since 1.4 */ public Base64(final int lineLength) { this(lineLength, CHUNK_SEPARATOR); } /** * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

    * When encoding the line length and line separator are given in the constructor, and the encoding table is * STANDARD_ENCODE_TABLE. *

    *

    * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. *

    *

    * When decoding all variants are supported. *

    * * @param lineLength * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when * decoding. * @param lineSeparator * Each line of encoded data will end with this sequence of bytes. * @throws IllegalArgumentException * Thrown when the provided lineSeparator included some base64 characters. * @since 1.4 */ public Base64(final int lineLength, final byte[] lineSeparator) { this(lineLength, lineSeparator, false); } /** * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. *

    * When encoding the line length and line separator are given in the constructor, and the encoding table is * STANDARD_ENCODE_TABLE. *

    *

    * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. *

    *

    * When decoding all variants are supported. *

    * * @param lineLength * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when * decoding. * @param lineSeparator * Each line of encoded data will end with this sequence of bytes. * @param urlSafe * Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode * operations. Decoding seamlessly handles both modes. * Note: no padding is added when using the URL-safe alphabet. * @throws IllegalArgumentException * The provided lineSeparator included some base64 characters. That's not going to work! * @since 1.4 */ public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) { super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, lineSeparator == null ? 0 : lineSeparator.length); // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0 // @see test case Base64Test.testConstructors() if (lineSeparator != null) { if (containsAlphabetOrPad(lineSeparator)) { final String sep = StringUtils.newStringUtf8(lineSeparator); throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]"); } if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length; this.lineSeparator = new byte[lineSeparator.length]; System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length); } else { this.encodeSize = BYTES_PER_ENCODED_BLOCK; this.lineSeparator = null; } } else { this.encodeSize = BYTES_PER_ENCODED_BLOCK; this.lineSeparator = null; } this.decodeSize = this.encodeSize - 1; this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; } /** * Returns our current encode mode. True if we're URL-SAFE, false otherwise. * * @return true if we're in URL-SAFE mode, false otherwise. * @since 1.4 */ public boolean isUrlSafe() { return this.encodeTable == URL_SAFE_ENCODE_TABLE; } /** *

    * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, to flush last * remaining bytes (if not multiple of 3). *

    *

    Note: no padding is added when encoding using the URL-safe alphabet.

    *

    * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ *

    * * @param in * byte[] array of binary data to base64 encode. * @param inPos * Position to start reading data from. * @param inAvail * Amount of bytes available from input for encoding. * @param context * the context to be used */ @Override void encode(final byte[] in, int inPos, final int inAvail, final Context context) { if (context.eof) { return; } // inAvail < 0 is how we're informed of EOF in the underlying data we're // encoding. if (inAvail < 0) { context.eof = true; if (0 == context.modulus && lineLength == 0) { return; // no leftovers to process and not using chunking } final byte[] buffer = ensureBufferSize(encodeSize, context); final int savedPos = context.pos; switch (context.modulus) { // 0-2 case 0 : // nothing to do here break; case 1 : // 8 bits = 6 + 2 // top 6 bits: buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS]; // remaining 2: buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS]; // URL-SAFE skips the padding to further reduce size. if (encodeTable == STANDARD_ENCODE_TABLE) { buffer[context.pos++] = PAD; buffer[context.pos++] = PAD; } break; case 2 : // 16 bits = 6 + 6 + 4 buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS]; buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS]; buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS]; // URL-SAFE skips the padding to further reduce size. if (encodeTable == STANDARD_ENCODE_TABLE) { buffer[context.pos++] = PAD; } break; default: throw new IllegalStateException("Impossible modulus "+context.modulus); } context.currentLinePos += context.pos - savedPos; // keep track of current line position // if currentPos == 0 we are at the start of a line, so don't add CRLF if (lineLength > 0 && context.currentLinePos > 0) { System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); context.pos += lineSeparator.length; } } else { for (int i = 0; i < inAvail; i++) { final byte[] buffer = ensureBufferSize(encodeSize, context); context.modulus = (context.modulus+1) % BYTES_PER_UNENCODED_BLOCK; int b = in[inPos++]; if (b < 0) { b += 256; } context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS]; buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS]; buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS]; buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS]; context.currentLinePos += BYTES_PER_ENCODED_BLOCK; if (lineLength > 0 && lineLength <= context.currentLinePos) { System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length); context.pos += lineSeparator.length; context.currentLinePos = 0; } } } } } /** *

    * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1" * call is not necessary when decoding, but it doesn't hurt, either. *

    *

    * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in, * garbage-out philosophy: it will not check the provided data for validity. *

    *

    * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ *

    * * @param in * byte[] array of ascii data to base64 decode. * @param inPos * Position to start reading data from. * @param inAvail * Amount of bytes available from input for encoding. * @param context * the context to be used */ @Override void decode(final byte[] in, int inPos, final int inAvail, final Context context) { if (context.eof) { return; } if (inAvail < 0) { context.eof = true; } for (int i = 0; i < inAvail; i++) { final byte[] buffer = ensureBufferSize(decodeSize, context); final byte b = in[inPos++]; if (b == PAD) { // We're done. context.eof = true; break; } else { if (b >= 0 && b < DECODE_TABLE.length) { final int result = DECODE_TABLE[b]; if (result >= 0) { context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK; context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result; if (context.modulus == 0) { buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS); buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS); } } } } } // Two forms of EOF as far as base64 decoder is concerned: actual // EOF (-1) and first time '=' character is encountered in stream. // This approach makes the '=' padding characters completely optional. if (context.eof && context.modulus != 0) { final byte[] buffer = ensureBufferSize(decodeSize, context); // We have some spare bits remaining // Output all whole multiples of 8 bits and ignore the rest switch (context.modulus) { // case 0 : // impossible, as excluded above case 1 : // 6 bits - ignore entirely // TODO not currently tested; perhaps it is impossible? break; case 2 : // 12 bits = 8 + 4 context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); break; case 3 : // 18 bits = 8 + 8 + 2 context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS); buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); break; default: throw new IllegalStateException("Impossible modulus "+context.modulus); } } } /** * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the * method treats whitespace as valid. * * @param arrayOctet * byte array to test * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; * {@code false}, otherwise * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0. */ @Deprecated public static boolean isArrayByteBase64(final byte[] arrayOctet) { return isBase64(arrayOctet); } /** * Returns whether or not the octet is in the base 64 alphabet. * * @param octet * The value to test * @return {@code true} if the value is defined in the the base 64 alphabet, {@code false} otherwise. * @since 1.4 */ public static boolean isBase64(final byte octet) { return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1); } /** * Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the * method treats whitespace as valid. * * @param base64 * String to test * @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if * the String is empty; {@code false}, otherwise * @since 1.5 */ public static boolean isBase64(final String base64) { return isBase64(StringUtils.getBytesUtf8(base64)); } /** * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the * method treats whitespace as valid. * * @param arrayOctet * byte array to test * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; * {@code false}, otherwise * @since 1.5 */ public static boolean isBase64(final byte[] arrayOctet) { for (int i = 0; i < arrayOctet.length; i++) { if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) { return false; } } return true; } /** * Encodes binary data using the base64 algorithm but does not chunk the output. * * @param binaryData * binary data to encode * @return byte[] containing Base64 characters in their UTF-8 representation. */ public static byte[] encodeBase64(final byte[] binaryData) { return encodeBase64(binaryData, false); } /** * Encodes binary data using the base64 algorithm but does not chunk the output. * * NOTE: We changed the behaviour of this method from multi-line chunking (commons-codec-1.4) to * single-line non-chunking (commons-codec-1.5). * * @param binaryData * binary data to encode * @return String containing Base64 characters. * @since 1.4 (NOTE: 1.4 chunked the output, whereas 1.5 does not). */ public static String encodeBase64String(final byte[] binaryData) { return StringUtils.newStringUtf8(encodeBase64(binaryData, false)); } /** * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The * url-safe variation emits - and _ instead of + and / characters. * Note: no padding is added. * @param binaryData * binary data to encode * @return byte[] containing Base64 characters in their UTF-8 representation. * @since 1.4 */ public static byte[] encodeBase64URLSafe(final byte[] binaryData) { return encodeBase64(binaryData, false, true); } /** * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The * url-safe variation emits - and _ instead of + and / characters. * Note: no padding is added. * @param binaryData * binary data to encode * @return String containing Base64 characters * @since 1.4 */ public static String encodeBase64URLSafeString(final byte[] binaryData) { return StringUtils.newStringUtf8(encodeBase64(binaryData, false, true)); } /** * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks * * @param binaryData * binary data to encode * @return Base64 characters chunked in 76 character blocks */ public static byte[] encodeBase64Chunked(final byte[] binaryData) { return encodeBase64(binaryData, true); } /** * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. * * @param binaryData * Array containing binary data to encode. * @param isChunked * if {@code true} this encoder will chunk the base64 output into 76 character blocks * @return Base64-encoded data. * @throws IllegalArgumentException * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} */ public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) { return encodeBase64(binaryData, isChunked, false); } /** * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. * * @param binaryData * Array containing binary data to encode. * @param isChunked * if {@code true} this encoder will chunk the base64 output into 76 character blocks * @param urlSafe * if {@code true} this encoder will emit - and _ instead of the usual + and / characters. * Note: no padding is added when encoding using the URL-safe alphabet. * @return Base64-encoded data. * @throws IllegalArgumentException * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} * @since 1.4 */ public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) { return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE); } /** * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. * * @param binaryData * Array containing binary data to encode. * @param isChunked * if {@code true} this encoder will chunk the base64 output into 76 character blocks * @param urlSafe * if {@code true} this encoder will emit - and _ instead of the usual + and / characters. * Note: no padding is added when encoding using the URL-safe alphabet. * @param maxResultSize * The maximum result size to accept. * @return Base64-encoded data. * @throws IllegalArgumentException * Thrown when the input array needs an output array bigger than maxResultSize * @since 1.4 */ public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe, final int maxResultSize) { if (binaryData == null || binaryData.length == 0) { return binaryData; } // Create this so can use the super-class method // Also ensures that the same roundings are performed by the ctor and the code final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); final long len = b64.getEncodedLength(binaryData); if (len > maxResultSize) { throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + len + ") than the specified maximum size of " + maxResultSize); } return b64.encode(binaryData); } /** * Decodes a Base64 String into octets * * @param base64String * String containing Base64 data * @return Array containing decoded data. * @since 1.4 */ public static byte[] decodeBase64(final String base64String) { return new Base64().decode(base64String); } /** * Decodes Base64 data into octets * * @param base64Data * Byte array containing Base64 data * @return Array containing decoded data. */ public static byte[] decodeBase64(final byte[] base64Data) { return decodeBase64(base64Data, 0, base64Data.length); } public static byte[] decodeBase64( final byte[] base64Data, final int off, final int len) { return new Base64().decode(base64Data, off, len); } // Implementation of the Encoder Interface // Implementation of integer encoding used for crypto /** * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature * * @param pArray * a byte array containing base64 character data * @return A BigInteger * @since 1.4 */ public static BigInteger decodeInteger(final byte[] pArray) { return new BigInteger(1, decodeBase64(pArray)); } /** * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature * * @param bigInt * a BigInteger * @return A byte array containing base64 character data * @throws NullPointerException * if null is passed in * @since 1.4 */ public static byte[] encodeInteger(final BigInteger bigInt) { if (bigInt == null) { throw new NullPointerException("encodeInteger called with null parameter"); } return encodeBase64(toIntegerBytes(bigInt), false); } /** * Returns a byte-array representation of a BigInteger without sign bit. * * @param bigInt * BigInteger to be converted * @return a byte array representation of the BigInteger parameter */ static byte[] toIntegerBytes(final BigInteger bigInt) { int bitlen = bigInt.bitLength(); // round bitlen bitlen = ((bitlen + 7) >> 3) << 3; final byte[] bigBytes = bigInt.toByteArray(); if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { return bigBytes; } // set up params for copying everything but sign bit int startSrc = 0; int len = bigBytes.length; // if bigInt is exactly byte-aligned, just skip signbit in copy if ((bigInt.bitLength() % 8) == 0) { startSrc = 1; len--; } final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec final byte[] resizedBytes = new byte[bitlen / 8]; System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); return resizedBytes; } /** * Returns whether or not the octet is in the Base64 alphabet. * * @param octet * The value to test * @return {@code true} if the value is defined in the the Base64 alphabet {@code false} otherwise. */ @Override protected boolean isInAlphabet(final byte octet) { return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1; } } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/binary/package.html0000644000175100017510000000154512271446130025167 0ustar locutuslocutus Base64, Base32, Binary, and Hexadecimal String encoding and decoding. tomcat7-7.0.52/java/org/apache/tomcat/util/codec/binary/StringUtils.java0000644000175100017510000000676412271446130026050 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec.binary; import java.nio.charset.Charset; import org.apache.tomcat.util.buf.B2CConverter; /** * Converts String to and from bytes using the encodings required by the Java specification. These encodings are * specified in * Standard charsets. * *

    This class is immutable and thread-safe.

    * * @see Standard charsets * @since 1.4 */ public class StringUtils { /** * Calls {@link String#getBytes(Charset)} * * @param string * The string to encode (if null, return null). * @param charset * The {@link Charset} to encode the {@code String} * @return the encoded bytes */ private static byte[] getBytes(final String string, final Charset charset) { if (string == null) { return null; } return string.getBytes(charset); } /** * Encodes the given string into a sequence of bytes using the UTF-8 charset, storing the result into a new byte * array. * * @param string * the String to encode, may be {@code null} * @return encoded bytes, or {@code null} if the input string was {@code null} * @see Standard charsets */ public static byte[] getBytesUtf8(final String string) { return getBytes(string, B2CConverter.UTF_8); } /** * Constructs a new String by decoding the specified array of bytes using the given charset. * * @param bytes * The bytes to be decoded into characters * @param charset * The {@link Charset} to encode the {@code String} * @return A new String decoded from the specified array of bytes using the given charset, * or {@code null} if the input byte array was {@code null}. */ private static String newString(final byte[] bytes, final Charset charset) { return bytes == null ? null : new String(bytes, charset); } /** * Constructs a new String by decoding the specified array of bytes using the UTF-8 charset. * * @param bytes * The bytes to be decoded into characters * @return A new String decoded from the specified array of bytes using the UTF-8 charset, * or {@code null} if the input byte array was {@code null}. */ public static String newStringUtf8(final byte[] bytes) { return newString(bytes, B2CConverter.UTF_8); } } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java0000644000175100017510000004376412271446130025510 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec.binary; import org.apache.tomcat.util.codec.BinaryDecoder; import org.apache.tomcat.util.codec.BinaryEncoder; import org.apache.tomcat.util.codec.DecoderException; import org.apache.tomcat.util.codec.EncoderException; /** * Abstract superclass for Base-N encoders and decoders. * *

    * This class is thread-safe. *

    */ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { /** * Holds thread context so classes can be thread-safe. * * This class is not itself thread-safe; each thread must allocate its own copy. * * @since 1.7 */ static class Context { /** * Place holder for the bytes we're dealing with for our based logic. * Bitwise operations store and extract the encoding or decoding from this variable. */ int ibitWorkArea; /** * Place holder for the bytes we're dealing with for our based logic. * Bitwise operations store and extract the encoding or decoding from this variable. */ long lbitWorkArea; /** * Buffer for streaming. */ byte[] buffer; /** * Position where next character should be written in the buffer. */ int pos; /** * Position where next character should be read from the buffer. */ int readPos; /** * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless, * and must be thrown away. */ boolean eof; /** * Variable tracks how many characters have been written to the current line. Only used when encoding. We use * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0). */ int currentLinePos; /** * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This * variable helps track that. */ int modulus; Context() { } /** * Returns a String useful for debugging (especially within a debugger.) * * @return a String useful for debugging. */ @SuppressWarnings("boxing") // OK to ignore boxing here @Override public String toString() { return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " + "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), buffer, currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos); } } /** * EOF * * @since 1.7 */ static final int EOF = -1; /** * MIME chunk size per RFC 2045 section 6.8. * *

    * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any * equal signs. *

    * * @see RFC 2045 section 6.8 */ public static final int MIME_CHUNK_SIZE = 76; /** * PEM chunk size per RFC 1421 section 4.3.2.4. * *

    * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any * equal signs. *

    * * @see RFC 1421 section 4.3.2.4 */ public static final int PEM_CHUNK_SIZE = 64; private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2; /** * Defines the default buffer size - currently {@value} * - must be large enough for at least one encoded block+separator */ private static final int DEFAULT_BUFFER_SIZE = 128; /** Mask used to extract 8 bits, used in decoding bytes */ protected static final int MASK_8BITS = 0xff; /** * Byte used to pad output. */ protected static final byte PAD_DEFAULT = '='; // Allow static access to default protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */ private final int unencodedBlockSize; /** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */ private final int encodedBlockSize; /** * Chunksize for encoding. Not used when decoding. * A value of zero or less implies no chunking of the encoded data. * Rounded down to nearest multiple of encodedBlockSize. */ protected final int lineLength; /** * Size of chunk separator. Not used unless {@link #lineLength} > 0. */ private final int chunkSeparatorLength; /** * Note lineLength is rounded down to the nearest multiple of {@link #encodedBlockSize} * If chunkSeparatorLength is zero, then chunking is disabled. * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) * @param lineLength if > 0, use chunking with a length lineLength * @param chunkSeparatorLength the chunk separator length, if relevant */ protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, final int lineLength, final int chunkSeparatorLength) { this.unencodedBlockSize = unencodedBlockSize; this.encodedBlockSize = encodedBlockSize; final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0; this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0; this.chunkSeparatorLength = chunkSeparatorLength; } /** * Returns true if this object has buffered data for reading. * * @param context the context to be used * @return true if there is data still available for reading. */ boolean hasData(final Context context) { // package protected for access from I/O streams return context.buffer != null; } /** * Returns the amount of buffered data available for reading. * * @param context the context to be used * @return The amount of buffered data available for reading. */ int available(final Context context) { // package protected for access from I/O streams return context.buffer != null ? context.pos - context.readPos : 0; } /** * Get the default buffer size. Can be overridden. * * @return {@link #DEFAULT_BUFFER_SIZE} */ protected int getDefaultBufferSize() { return DEFAULT_BUFFER_SIZE; } /** * Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}. * @param context the context to be used */ private byte[] resizeBuffer(final Context context) { if (context.buffer == null) { context.buffer = new byte[getDefaultBufferSize()]; context.pos = 0; context.readPos = 0; } else { final byte[] b = new byte[context.buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR]; System.arraycopy(context.buffer, 0, b, 0, context.buffer.length); context.buffer = b; } return context.buffer; } /** * Ensure that the buffer has room for size bytes * * @param size minimum spare space required * @param context the context to be used */ protected byte[] ensureBufferSize(final int size, final Context context){ if ((context.buffer == null) || (context.buffer.length < context.pos + size)){ return resizeBuffer(context); } return context.buffer; } /** * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail * bytes. Returns how many bytes were actually extracted. *

    * Package protected for access from I/O streams. * * @param b * byte[] array to extract the buffered data into. * @param bPos * position in byte[] array to start extraction at. * @param bAvail * amount of bytes we're allowed to extract. We may extract fewer (if fewer are available). * @param context * the context to be used * @return The number of bytes successfully extracted into the provided byte[] array. */ int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) { if (context.buffer != null) { final int len = Math.min(available(context), bAvail); System.arraycopy(context.buffer, context.readPos, b, bPos, len); context.readPos += len; if (context.readPos >= context.pos) { context.buffer = null; // so hasData() will return false, and this method can return -1 } return len; } return context.eof ? EOF : 0; } /** * Checks if a byte value is whitespace or not. * Whitespace is taken to mean: space, tab, CR, LF * @param byteToCheck * the byte to check * @return true if byte is whitespace, false otherwise */ protected static boolean isWhiteSpace(final byte byteToCheck) { switch (byteToCheck) { case ' ' : case '\n' : case '\r' : case '\t' : return true; default : return false; } } /** * Encodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of * the Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[]. * * @param obj * Object to encode * @return An object (of type byte[]) containing the Base-N encoded data which corresponds to the byte[] supplied. * @throws EncoderException * if the parameter supplied is not of type byte[] */ @Override public Object encode(final Object obj) throws EncoderException { if (!(obj instanceof byte[])) { throw new EncoderException("Parameter supplied to Base-N encode is not a byte[]"); } return encode((byte[]) obj); } /** * Encodes a byte[] containing binary data, into a String containing characters in the Base-N alphabet. * Uses UTF8 encoding. * * @param pArray * a byte array containing binary data * @return A String containing only Base-N character data */ public String encodeToString(final byte[] pArray) { return StringUtils.newStringUtf8(encode(pArray)); } /** * Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet. * Uses UTF8 encoding. * * @param pArray a byte array containing binary data * @return String containing only character data in the appropriate alphabet. */ public String encodeAsString(final byte[] pArray){ return StringUtils.newStringUtf8(encode(pArray)); } /** * Decodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of * the Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String. * * @param obj * Object to decode * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String * supplied. * @throws DecoderException * if the parameter supplied is not of type byte[] */ @Override public Object decode(final Object obj) throws DecoderException { if (obj instanceof byte[]) { return decode((byte[]) obj); } else if (obj instanceof String) { return decode((String) obj); } else { throw new DecoderException("Parameter supplied to Base-N decode is not a byte[] or a String"); } } /** * Decodes a String containing characters in the Base-N alphabet. * * @param pArray * A String containing Base-N character data * @return a byte array containing binary data */ public byte[] decode(final String pArray) { return decode(StringUtils.getBytesUtf8(pArray)); } /** * Decodes a byte[] containing characters in the Base-N alphabet. * * @param pArray * A byte array containing Base-N character data * @return a byte array containing binary data */ @Override public byte[] decode(final byte[] pArray) { return decode(pArray, 0, pArray.length); } public byte[] decode(final byte[] pArray, final int off, final int len) { if (pArray == null || len == 0) { return new byte[0]; } final Context context = new Context(); decode(pArray, off, len, context); decode(pArray, off, EOF, context); // Notify decoder of EOF. final byte[] result = new byte[context.pos]; readResults(result, 0, result.length, context); return result; } /** * Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet. * * @param pArray * a byte array containing binary data * @return A byte array containing only the basen alphabetic character data */ @Override public byte[] encode(final byte[] pArray) { if (pArray == null || pArray.length == 0) { return pArray; } final Context context = new Context(); encode(pArray, 0, pArray.length, context); encode(pArray, 0, EOF, context); // Notify encoder of EOF. final byte[] buf = new byte[context.pos - context.readPos]; readResults(buf, 0, buf.length, context); return buf; } // package protected for access from I/O streams abstract void encode(byte[] pArray, int i, int length, Context context); // package protected for access from I/O streams abstract void decode(byte[] pArray, int i, int length, Context context); /** * Returns whether or not the octet is in the current alphabet. * Does not allow whitespace or pad. * * @param value The value to test * * @return {@code true} if the value is defined in the current alphabet, {@code false} otherwise. */ protected abstract boolean isInAlphabet(byte value); /** * Tests a given byte array to see if it contains only valid characters within the alphabet. * The method optionally treats whitespace and pad as valid. * * @param arrayOctet byte array to test * @param allowWSPad if {@code true}, then whitespace and PAD are also allowed * * @return {@code true} if all bytes are valid characters in the alphabet or if the byte array is empty; * {@code false}, otherwise */ public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) { for (int i = 0; i < arrayOctet.length; i++) { if (!isInAlphabet(arrayOctet[i]) && (!allowWSPad || (arrayOctet[i] != PAD) && !isWhiteSpace(arrayOctet[i]))) { return false; } } return true; } /** * Tests a given String to see if it contains only valid characters within the alphabet. * The method treats whitespace and PAD as valid. * * @param basen String to test * @return {@code true} if all characters in the String are valid characters in the alphabet or if * the String is empty; {@code false}, otherwise * @see #isInAlphabet(byte[], boolean) */ public boolean isInAlphabet(final String basen) { return isInAlphabet(StringUtils.getBytesUtf8(basen), true); } /** * Tests a given byte array to see if it contains any characters within the alphabet or PAD. * * Intended for use in checking line-ending arrays * * @param arrayOctet * byte array to test * @return {@code true} if any byte is a valid character in the alphabet or PAD; {@code false} otherwise */ protected boolean containsAlphabetOrPad(final byte[] arrayOctet) { if (arrayOctet == null) { return false; } for (final byte element : arrayOctet) { if (PAD == element || isInAlphabet(element)) { return true; } } return false; } /** * Calculates the amount of space needed to encode the supplied array. * * @param pArray byte[] array which will later be encoded * * @return amount of space needed to encoded the supplied array. * Returns a long since a max-len array will require > Integer.MAX_VALUE */ public long getEncodedLength(final byte[] pArray) { // Calculate non-chunked size - rounded up to allow for padding // cast to long is needed to avoid possibility of overflow long len = ((pArray.length + unencodedBlockSize-1) / unencodedBlockSize) * (long) encodedBlockSize; if (lineLength > 0) { // We're using chunking // Round up to nearest multiple len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength; } return len; } } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/BinaryDecoder.java0000644000175100017510000000262312271446130024775 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec; /** * Defines common decoding methods for byte array decoders. */ public interface BinaryDecoder extends Decoder { /** * Decodes a byte array and returns the results as a byte array. * * @param source * A byte array which has been encoded with the appropriate encoder * @return a byte array that contains decoded content * @throws DecoderException * A decoder exception is thrown if a Decoder encounters a failure condition during the decode process. */ byte[] decode(byte[] source) throws DecoderException; } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/EncoderException.java0000644000175100017510000000666112271446130025527 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec; /** * Thrown when there is a failure condition during the encoding process. This exception is thrown when an * {@link Encoder} encounters a encoding specific exception such as invalid data, inability to calculate a checksum, * characters outside of the expected range. */ public class EncoderException extends Exception { /** * Declares the Serial Version Uid. * * @see Always Declare Serial Version Uid */ private static final long serialVersionUID = 1L; /** * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause}. * * @since 1.4 */ public EncoderException() { super(); } /** * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently * be initialized by a call to {@link #initCause}. * * @param message * a useful message relating to the encoder specific error. */ public EncoderException(final String message) { super(message); } /** * Constructs a new exception with the specified detail message and cause. * *

    * Note that the detail message associated with cause is not automatically incorporated into this * exception's detail message. *

    * * @param message * The detail message which is saved for later retrieval by the {@link #getMessage()} method. * @param cause * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} * value is permitted, and indicates that the cause is nonexistent or unknown. * @since 1.4 */ public EncoderException(final String message, final Throwable cause) { super(message, cause); } /** * Constructs a new exception with the specified cause and a detail message of (cause==null ? * null : cause.toString()) (which typically contains the class and detail message of cause). * This constructor is useful for exceptions that are little more than wrappers for other throwables. * * @param cause * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} * value is permitted, and indicates that the cause is nonexistent or unknown. * @since 1.4 */ public EncoderException(final Throwable cause) { super(cause); } } tomcat7-7.0.52/java/org/apache/tomcat/util/codec/DecoderException.java0000644000175100017510000000663412271446130025515 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.codec; /** * Thrown when there is a failure condition during the decoding process. This exception is thrown when a {@link Decoder} * encounters a decoding specific exception such as invalid data, or characters outside of the expected range. */ public class DecoderException extends Exception { /** * Declares the Serial Version Uid. * * @see Always Declare Serial Version Uid */ private static final long serialVersionUID = 1L; /** * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause}. * * @since 1.4 */ public DecoderException() { super(); } /** * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently * be initialized by a call to {@link #initCause}. * * @param message * The detail message which is saved for later retrieval by the {@link #getMessage()} method. */ public DecoderException(final String message) { super(message); } /** * Constructs a new exception with the specified detail message and cause. *

    * Note that the detail message associated with cause is not automatically incorporated into this * exception's detail message. * * @param message * The detail message which is saved for later retrieval by the {@link #getMessage()} method. * @param cause * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} * value is permitted, and indicates that the cause is nonexistent or unknown. * @since 1.4 */ public DecoderException(final String message, final Throwable cause) { super(message, cause); } /** * Constructs a new exception with the specified cause and a detail message of (cause==null ? * null : cause.toString()) (which typically contains the class and detail message of cause). * This constructor is useful for exceptions that are little more than wrappers for other throwables. * * @param cause * The cause which is saved for later retrieval by the {@link #getCause()} method. A {@code null} * value is permitted, and indicates that the cause is nonexistent or unknown. * @since 1.4 */ public DecoderException(final Throwable cause) { super(cause); } } tomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/0000755000175100017510000000000012301126367022517 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/LocalStrings_es.properties0000644000175100017510000000164112247712303027732 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. xmlErrorHandler.error = Error no fatal [{0}] reportado por el proceso [{1}]. xmlErrorHandler.warning = Aviso [{0}] reportado por el proceso [{1}]. tomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/LocalResolver.java0000644000175100017510000001244012251313004026125 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.descriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.Map; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.ext.EntityResolver2; /** * A resolver for locally cached XML resources. */ public class LocalResolver implements EntityResolver2 { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private final Map publicIds; private final Map systemIds; private final boolean blockExternal; /** * Constructor providing mappings of public and system identifiers to local * resources. Each map contains a mapping from a well-known identifier to a * URL for a local resource path. * * @param publicIds mapping of well-known public identifiers to local * resources * @param systemIds mapping of well-known system identifiers to local * resources * @param blockExternal are external resources blocked that are not * well-known */ public LocalResolver(Map publicIds, Map systemIds, boolean blockExternal) { this.publicIds = publicIds; this.systemIds = systemIds; this.blockExternal = blockExternal; } @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { return resolveEntity(null, publicId, null, systemId); } @Override public InputSource resolveEntity(String name, String publicId, String base, String systemId) throws SAXException, IOException { // First try resolving using the publicId String resolved = publicIds.get(publicId); if (resolved != null) { InputSource is = new InputSource(resolved); is.setPublicId(publicId); return is; } // If there is no systemId, can't try anything else if (systemId == null) { throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity", name, publicId, systemId, base)); } // Try resolving with the supplied systemId resolved = systemIds.get(systemId); if (resolved != null) { InputSource is = new InputSource(resolved); is.setPublicId(publicId); return is; } // Resolve the supplied systemId against the base URI systemUri; try { if (base == null) { systemUri = new URI(systemId); } else { // Can't use URI.resolve() because "jar:..." URLs are not valid // hierarchical URIs so resolve() does not work. new URL() // delegates to the jar: stream handler and it manages to figure // it out. URI baseUri = new URI(base); systemUri = new URL(baseUri.toURL(), systemId).toURI(); } systemUri = systemUri.normalize(); } catch (URISyntaxException e) { // May be caused by a | being used instead of a : in an absolute // file URI on Windows. if (blockExternal) { // Absolute paths aren't allowed so block it throw new MalformedURLException(e.getMessage()); } else { // See if the URLHandler can resolve it return new InputSource(systemId); } } if (systemUri.isAbsolute()) { // Try the resolved systemId resolved = systemIds.get(systemUri.toString()); if (resolved != null) { InputSource is = new InputSource(resolved); is.setPublicId(publicId); return is; } if (!blockExternal) { InputSource is = new InputSource(systemUri.toString()); is.setPublicId(publicId); return is; } } throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity", name, publicId, systemId, base)); } @Override public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException { return null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/XmlIdentifiers.java0000644000175100017510000000644112276431250026316 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.descriptor; /** * Defines constants for well-known Public and System identifiers documented by * the Servlet and JSP specifications. */ public final class XmlIdentifiers { // from W3C public static final String XML_2001_XSD = "http://www.w3.org/2001/xml.xsd"; public static final String DATATYPES_PUBLIC = "datatypes"; public static final String XSD_10_PUBLIC = "-//W3C//DTD XMLSCHEMA 200102//EN"; // from J2EE 1.2 public static final String WEB_22_PUBLIC = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"; public static final String WEB_22_SYSTEM = "http://java.sun.com/dtd/web-app_2_2.dtd"; public static final String TLD_11_PUBLIC = "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"; public static final String TLD_11_SYSTEM = "http://java.sun.com/dtd/web-jsptaglibrary_1_1.dtd"; // from J2EE 1.3 public static final String WEB_23_PUBLIC = "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"; public static final String WEB_23_SYSTEM = "http://java.sun.com/dtd/web-app_2_3.dtd"; public static final String TLD_12_PUBLIC = "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"; public static final String TLD_12_SYSTEM = "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"; // from J2EE 1.4 public static final String JAVAEE_1_4_NS = "http://java.sun.com/xml/ns/j2ee"; public static final String WEB_24_XSD = JAVAEE_1_4_NS + "/web-app_2_4.xsd"; public static final String TLD_20_XSD = JAVAEE_1_4_NS + "/web-jsptaglibrary_2_0.xsd"; public static final String WEBSERVICES_11_XSD = "http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd"; // from JavaEE 5 public static final String JAVAEE_5_NS = "http://java.sun.com/xml/ns/javaee"; public static final String WEB_25_XSD = JAVAEE_5_NS + "/web-app_2_5.xsd"; public static final String TLD_21_XSD = JAVAEE_5_NS + "/web-jsptaglibrary_2_1.xsd"; public static final String WEBSERVICES_12_XSD = JAVAEE_5_NS + "javaee_web_services_1_2.xsd"; // from JavaEE 6 public static final String JAVAEE_6_NS = JAVAEE_5_NS; public static final String WEB_30_XSD = JAVAEE_6_NS + "/web-app_3_0.xsd"; public static final String WEB_FRAGMENT_30_XSD = JAVAEE_6_NS + "/web-fragment_3_0.xsd"; public static final String WEBSERVICES_13_XSD = JAVAEE_6_NS + "/javaee_web_services_1_3.xsd"; private XmlIdentifiers() { } }tomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/DigesterFactory.java0000644000175100017510000001260112271446130026457 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.descriptor; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSet; import org.xml.sax.ext.EntityResolver2; /** * Wrapper class around the Digester that hide Digester's initialization * details. */ public class DigesterFactory { /** * Mapping of well-known public IDs used by the Servlet API to the matching * local resource. */ public static final Map SERVLET_API_PUBLIC_IDS; /** * Mapping of well-known system IDs used by the Servlet API to the matching * local resource. */ public static final Map SERVLET_API_SYSTEM_IDS; static { Map publicIds = new HashMap(); Map systemIds = new HashMap(); // W3C publicIds.put(XmlIdentifiers.XSD_10_PUBLIC, idFor("XMLSchema.dtd")); publicIds.put(XmlIdentifiers.DATATYPES_PUBLIC, idFor("datatypes.dtd")); systemIds.put(XmlIdentifiers.XML_2001_XSD, idFor("xml.xsd")); // from J2EE 1.2 publicIds.put(XmlIdentifiers.WEB_22_PUBLIC, idFor("web-app_2_2.dtd")); publicIds.put(XmlIdentifiers.TLD_11_PUBLIC, idFor("web-jsptaglibrary_1_1.dtd")); // from J2EE 1.3 publicIds.put(XmlIdentifiers.WEB_23_PUBLIC, idFor("web-app_2_3.dtd")); publicIds.put(XmlIdentifiers.TLD_12_PUBLIC, idFor("web-jsptaglibrary_1_2.dtd")); // from J2EE 1.4 systemIds.put("http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd", idFor("j2ee_web_services_1_1.xsd")); systemIds.put("http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd", idFor("j2ee_web_services_client_1_1.xsd")); systemIds.put(XmlIdentifiers.WEB_24_XSD, idFor("web-app_2_4.xsd")); systemIds.put(XmlIdentifiers.TLD_20_XSD, idFor("web-jsptaglibrary_2_0.xsd")); addSelf(systemIds, "j2ee_1_4.xsd"); addSelf(systemIds, "jsp_2_0.xsd"); // from JavaEE 5 systemIds.put(XmlIdentifiers.WEB_25_XSD, idFor("web-app_2_5.xsd")); systemIds.put(XmlIdentifiers.TLD_21_XSD, idFor("web-jsptaglibrary_2_1.xsd")); addSelf(systemIds, "javaee_5.xsd"); addSelf(systemIds, "jsp_2_1.xsd"); addSelf(systemIds, "javaee_web_services_1_2.xsd"); addSelf(systemIds, "javaee_web_services_client_1_2.xsd"); // from JavaEE 6 systemIds.put(XmlIdentifiers.WEB_30_XSD, idFor("web-app_3_0.xsd")); systemIds.put(XmlIdentifiers.WEB_FRAGMENT_30_XSD, idFor("web-fragment_3_0.xsd")); addSelf(systemIds, "web-common_3_0.xsd"); addSelf(systemIds, "javaee_6.xsd"); addSelf(systemIds, "jsp_2_2.xsd"); addSelf(systemIds, "javaee_web_services_1_3.xsd"); addSelf(systemIds, "javaee_web_services_client_1_3.xsd"); SERVLET_API_PUBLIC_IDS = Collections.unmodifiableMap(publicIds); SERVLET_API_SYSTEM_IDS = Collections.unmodifiableMap(systemIds); } private static void addSelf(Map ids, String id) { String systemId = idFor(id); ids.put(systemId, systemId); ids.put(id, systemId); } private static String idFor(String url) { URL id = ServletContext.class.getResource("resources/" + url); if (id == null) { id = ServletContext.class.getResource("jsp/resources/" + url); } return id.toExternalForm(); } /** * Create a Digester parser. * @param xmlValidation turn on/off xml validation * @param xmlNamespaceAware turn on/off namespace validation * @param rule an instance of RuleSet used for parsing the xml. * @param blockExternal turn on/off the blocking of external resources */ public static Digester newDigester(boolean xmlValidation, boolean xmlNamespaceAware, RuleSet rule, boolean blockExternal) { Digester digester = new Digester(); digester.setNamespaceAware(xmlNamespaceAware); digester.setValidating(xmlValidation); digester.setUseContextClassLoader(true); EntityResolver2 resolver = new LocalResolver(SERVLET_API_PUBLIC_IDS, SERVLET_API_SYSTEM_IDS, blockExternal); digester.setEntityResolver(resolver); if (rule != null) { digester.addRuleSet(rule); } return digester; } } tomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/XmlErrorHandler.java0000644000175100017510000000503112263541066026435 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.descriptor; import java.util.ArrayList; import java.util.List; import org.apache.juli.logging.Log; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class XmlErrorHandler implements ErrorHandler { private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); private final List errors = new ArrayList(); private final List warnings = new ArrayList(); @Override public void error(SAXParseException exception) throws SAXException { // Collect non-fatal errors errors.add(exception); } @Override public void fatalError(SAXParseException exception) throws SAXException { // Re-throw fatal errors throw exception; } @Override public void warning(SAXParseException exception) throws SAXException { // Collect warnings warnings.add(exception); } public List getErrors() { // Internal use only - don't worry about immutability return errors; } public List getWarnings() { // Internal use only - don't worry about immutability return warnings; } public void logFindings(Log log, String source) { for (SAXParseException e : getWarnings()) { log.warn(sm.getString( "xmlErrorHandler.warning", e.getMessage(), source)); } for (SAXParseException e : getErrors()) { log.warn(sm.getString( "xmlErrorHandler.error", e.getMessage(), source)); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/Constants.java0000644000175100017510000000171612247712303025343 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.descriptor; public class Constants { public static final String PACKAGE_NAME = Constants.class.getPackage().getName(); } tomcat7-7.0.52/java/org/apache/tomcat/util/descriptor/LocalStrings.properties0000644000175100017510000000205612251313004027232 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. localResolver.unresolvedEntity=Could not resolve XML resource [{0}] with public ID [{1}], system ID [{2}] and base URI [{3}] to a known, local entity. xmlErrorHandler.error=Non-fatal error [{0}] reported processing [{1}]. xmlErrorHandler.warning=Warning [{0}] reported processing [{1}]. tomcat7-7.0.52/java/org/apache/tomcat/util/digester/0000755000175100017510000000000012301126367022147 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/digester/SetPropertyRule.java0000644000175100017510000001212612271452077026152 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.apache.tomcat.util.IntrospectionUtils; import org.xml.sax.Attributes; /** * Rule implementation that sets an individual property on the object at the * top of the stack, based on attributes with specified names. */ public class SetPropertyRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "set property" rule with the specified name and value * attributes. * * @param digester The digester with which this rule is associated * @param name Name of the attribute that will contain the name of the * property to be set * @param value Name of the attribute that will contain the value to which * the property should be set * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetPropertyRule(String name, String value)} instead. */ @Deprecated public SetPropertyRule(Digester digester, String name, String value) { this(name, value); } /** * Construct a "set property" rule with the specified name and value * attributes. * * @param name Name of the attribute that will contain the name of the * property to be set * @param value Name of the attribute that will contain the value to which * the property should be set */ public SetPropertyRule(String name, String value) { this.name = name; this.value = value; } // ----------------------------------------------------- Instance Variables /** * The attribute that will contain the property name. */ protected String name = null; /** * The attribute that will contain the property value. */ protected String value = null; // --------------------------------------------------------- Public Methods /** * Process the beginning of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param theName the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list for this element * * @exception NoSuchMethodException if the bean does not * have a writable property of the specified name */ @Override public void begin(String namespace, String theName, Attributes attributes) throws Exception { // Identify the actual property name and value to be used String actualName = null; String actualValue = null; for (int i = 0; i < attributes.getLength(); i++) { String name = attributes.getLocalName(i); if ("".equals(name)) { name = attributes.getQName(i); } String value = attributes.getValue(i); if (name.equals(this.name)) { actualName = value; } else if (name.equals(this.value)) { actualValue = value; } } // Get a reference to the top object Object top = digester.peek(); // Log some debugging information if (digester.log.isDebugEnabled()) { digester.log.debug("[SetPropertyRule]{" + digester.match + "} Set " + top.getClass().getName() + " property " + actualName + " to " + actualValue); } // Set the property (with conversion as necessary) if (!digester.isFakeAttribute(top, actualName) && !IntrospectionUtils.setProperty(top, actualName, actualValue) && digester.getRulesValidation()) { digester.log.warn("[SetPropertyRule]{" + digester.match + "} Setting property '" + name + "' to '" + value + "' did not find a matching property."); } } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SetPropertyRule["); sb.append("name="); sb.append(name); sb.append(", value="); sb.append(value); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/SetNextRule.java0000644000175100017510000001614112271452077025245 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.apache.tomcat.util.IntrospectionUtils; /** *

    Rule implementation that calls a method on the (top-1) (parent) * object, passing the top object (child) as an argument. It is * commonly used to establish parent-child relationships.

    * *

    This rule now supports more flexible method matching by default. * It is possible that this may break (some) code * written against release 1.1.1 or earlier. * See {@link #isExactMatch()} for more details.

    */ public class SetNextRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "set next" rule with the specified method name. The * method's argument type is assumed to be the class of the * child object. * * @param digester The associated Digester * @param methodName Method name of the parent method to call * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetNextRule(String methodName)} instead. */ @Deprecated public SetNextRule(Digester digester, String methodName) { this(methodName); } /** * Construct a "set next" rule with the specified method name. * * @param digester The associated Digester * @param methodName Method name of the parent method to call * @param paramType Java class of the parent method's argument * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetNextRule(String methodName,String paramType)} instead. */ @Deprecated public SetNextRule(Digester digester, String methodName, String paramType) { this(methodName, paramType); } /** * Construct a "set next" rule with the specified method name. The * method's argument type is assumed to be the class of the * child object. * * @param methodName Method name of the parent method to call */ public SetNextRule(String methodName) { this(methodName, null); } /** * Construct a "set next" rule with the specified method name. * * @param methodName Method name of the parent method to call * @param paramType Java class of the parent method's argument * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) */ public SetNextRule(String methodName, String paramType) { this.methodName = methodName; this.paramType = paramType; } // ----------------------------------------------------- Instance Variables /** * The method name to call on the parent object. */ protected String methodName = null; /** * The Java class name of the parameter type expected by the method. */ protected String paramType = null; /** * Should we use exact matching. Default is no. */ protected boolean useExactMatch = false; // --------------------------------------------------------- Public Methods /** *

    Is exact matching being used.

    * *

    This rule uses org.apache.commons.beanutils.MethodUtils * to introspect the relevant objects so that the right method can be called. * Originally, MethodUtils.invokeExactMethod was used. * This matches methods very strictly * and so may not find a matching method when one exists. * This is still the behaviour when exact matching is enabled.

    * *

    When exact matching is disabled, MethodUtils.invokeMethod is used. * This method finds more methods but is less precise when there are several methods * with correct signatures. * So, if you want to choose an exact signature you might need to enable this property.

    * *

    The default setting is to disable exact matches.

    * * @return true iff exact matching is enabled * @since Digester Release 1.1.1 */ public boolean isExactMatch() { return useExactMatch; } /** *

    Set whether exact matching is enabled.

    * *

    See {@link #isExactMatch()}.

    * * @param useExactMatch should this rule use exact method matching * @since Digester Release 1.1.1 */ public void setExactMatch(boolean useExactMatch) { this.useExactMatch = useExactMatch; } /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { // Identify the objects to be used Object child = digester.peek(0); Object parent = digester.peek(1); if (digester.log.isDebugEnabled()) { if (parent == null) { digester.log.debug("[SetNextRule]{" + digester.match + "} Call [NULL PARENT]." + methodName + "(" + child + ")"); } else { digester.log.debug("[SetNextRule]{" + digester.match + "} Call " + parent.getClass().getName() + "." + methodName + "(" + child + ")"); } } // Call the specified method IntrospectionUtils.callMethod1(parent, methodName, child, paramType, digester.getClassLoader()); } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SetNextRule["); sb.append("methodName="); sb.append(methodName); sb.append(", paramType="); sb.append(paramType); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/Rules.java0000644000175100017510000000674012271452077024121 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.util.List; /** * Public interface defining a collection of Rule instances (and corresponding * matching patterns) plus an implementation of a matching policy that selects * the rules that match a particular pattern of nested elements discovered * during parsing. */ public interface Rules { // ------------------------------------------------------------- Properties /** * Return the Digester instance with which this Rules instance is * associated. */ public Digester getDigester(); /** * Set the Digester instance with which this Rules instance is associated. * * @param digester The newly associated Digester instance */ public void setDigester(Digester digester); /** * Return the namespace URI that will be applied to all subsequently * added Rule objects. */ public String getNamespaceURI(); /** * Set the namespace URI that will be applied to all subsequently * added Rule objects. * * @param namespaceURI Namespace URI that must match on all * subsequently added rules, or null for matching * regardless of the current namespace URI */ public void setNamespaceURI(String namespaceURI); // --------------------------------------------------------- Public Methods /** * Register a new Rule instance matching the specified pattern. * * @param pattern Nesting pattern to be matched for this Rule * @param rule Rule instance to be registered */ public void add(String pattern, Rule rule); /** * Clear all existing Rule instance registrations. */ public void clear(); /** * Return a List of all registered Rule instances that match the specified * nesting pattern, or a zero-length List if there are no matches. If more * than one Rule instance matches, they must be returned * in the order originally registered through the add() * method. * * @param namespaceURI Namespace URI for which to select matching rules, * or null to match regardless of namespace URI * @param pattern Nesting pattern to be matched */ public List match(String namespaceURI, String pattern); /** * Return a List of all registered Rule instances, or a zero-length List * if there are no registered Rule instances. If more than one Rule * instance has been registered, they must be returned * in the order originally registered through the add() * method. */ public List rules(); } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/SetRootRule.java0000644000175100017510000001613012271452077025250 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.apache.tomcat.util.IntrospectionUtils; /** *

    Rule implementation that calls a method on the root object on the stack, * passing the top object (child) as an argument. * It is important to remember that this rule acts on end.

    * *

    This rule now supports more flexible method matching by default. * It is possible that this may break (some) code * written against release 1.1.1 or earlier. * See {@link #isExactMatch()} for more details.

    */ public class SetRootRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "set root" rule with the specified method name. The * method's argument type is assumed to be the class of the * child object. * * @param digester The associated Digester * @param methodName Method name of the parent method to call * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetRootRule(String methodName)} instead. */ @Deprecated public SetRootRule(Digester digester, String methodName) { this(methodName); } /** * Construct a "set root" rule with the specified method name. * * @param digester The associated Digester * @param methodName Method name of the parent method to call * @param paramType Java class of the parent method's argument * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetRootRule(String methodName,String paramType)} instead. */ @Deprecated public SetRootRule(Digester digester, String methodName, String paramType) { this(methodName, paramType); } /** * Construct a "set root" rule with the specified method name. The * method's argument type is assumed to be the class of the * child object. * * @param methodName Method name of the parent method to call */ public SetRootRule(String methodName) { this(methodName, null); } /** * Construct a "set root" rule with the specified method name. * * @param methodName Method name of the parent method to call * @param paramType Java class of the parent method's argument * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) */ public SetRootRule(String methodName, String paramType) { this.methodName = methodName; this.paramType = paramType; } // ----------------------------------------------------- Instance Variables /** * The method name to call on the parent object. */ protected String methodName = null; /** * The Java class name of the parameter type expected by the method. */ protected String paramType = null; /** * Should we use exact matching. Default is no. */ protected boolean useExactMatch = false; // --------------------------------------------------------- Public Methods /** *

    Is exact matching being used.

    * *

    This rule uses org.apache.commons.beanutils.MethodUtils * to introspect the relevant objects so that the right method can be called. * Originally, MethodUtils.invokeExactMethod was used. * This matches methods very strictly * and so may not find a matching method when one exists. * This is still the behaviour when exact matching is enabled.

    * *

    When exact matching is disabled, MethodUtils.invokeMethod is used. * This method finds more methods but is less precise when there are several methods * with correct signatures. * So, if you want to choose an exact signature you might need to enable this property.

    * *

    The default setting is to disable exact matches.

    * * @return true iff exact matching is enabled * @since Digester Release 1.1.1 */ public boolean isExactMatch() { return useExactMatch; } /** *

    Set whether exact matching is enabled.

    * *

    See {@link #isExactMatch()}.

    * * @param useExactMatch should this rule use exact method matching * @since Digester Release 1.1.1 */ public void setExactMatch(boolean useExactMatch) { this.useExactMatch = useExactMatch; } /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { // Identify the objects to be used Object child = digester.peek(0); Object parent = digester.root; if (digester.log.isDebugEnabled()) { if (parent == null) { digester.log.debug("[SetRootRule]{" + digester.match + "} Call [NULL ROOT]." + methodName + "(" + child + ")"); } else { digester.log.debug("[SetRootRule]{" + digester.match + "} Call " + parent.getClass().getName() + "." + methodName + "(" + child + ")"); } } // Call the specified method IntrospectionUtils.callMethod1(parent, methodName, child, paramType, digester.getClassLoader()); } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SetRootRule["); sb.append("methodName="); sb.append(methodName); sb.append(", paramType="); sb.append(paramType); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/Rule.java0000644000175100017510000001516012271452077023732 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.xml.sax.Attributes; /** * Concrete implementations of this class implement actions to be taken when * a corresponding nested pattern of XML elements has been matched. */ public abstract class Rule { // ----------------------------------------------------------- Constructors /** *

    Base constructor. * Now the digester will be set when the rule is added.

    */ public Rule() {} // ----------------------------------------------------- Instance Variables /** * The Digester with which this Rule is associated. */ protected Digester digester = null; /** * The namespace URI for which this Rule is relevant, if any. */ protected String namespaceURI = null; // ------------------------------------------------------------- Properties /** * Return the Digester with which this Rule is associated. */ public Digester getDigester() { return (this.digester); } /** * Set the Digester with which this Rule is associated. */ public void setDigester(Digester digester) { this.digester = digester; } /** * Return the namespace URI for which this Rule is relevant, if any. */ public String getNamespaceURI() { return (this.namespaceURI); } /** * Set the namespace URI for which this Rule is relevant, if any. * * @param namespaceURI Namespace URI for which this Rule is relevant, * or null to match independent of namespace. */ public void setNamespaceURI(String namespaceURI) { this.namespaceURI = namespaceURI; } // --------------------------------------------------------- Public Methods /** * This method is called when the beginning of a matching XML element * is encountered. * * @param attributes The attribute list of this element * @deprecated Use the {@link #begin(String,String,Attributes) begin} * method with namespace and name * parameters instead. */ @Deprecated public void begin(Attributes attributes) throws Exception { // The default implementation does nothing } /** * This method is called when the beginning of a matching XML element * is encountered. The default implementation delegates to the deprecated * method {@link #begin(Attributes) begin} without the * namespace and name parameters, to retain * backwards compatibility. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list of this element * @since Digester 1.4 */ public void begin(String namespace, String name, Attributes attributes) throws Exception { begin(attributes); } /** * This method is called when the body of a matching XML element * is encountered. If the element has no body, this method is * not called at all. * * @param text The text of the body of this element * @deprecated Use the {@link #body(String,String,String) body} method * with namespace and name parameters * instead. */ @Deprecated public void body(String text) throws Exception { // The default implementation does nothing } /** * This method is called when the body of a matching XML element is * encountered. If the element has no body, this method is not called at * all. The default implementation delegates to the deprecated method * {@link #body(String) body} without the namespace and * name parameters, to retain backwards compatibility. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param text The text of the body of this element * @since Digester 1.4 */ public void body(String namespace, String name, String text) throws Exception { body(text); } /** * This method is called when the end of a matching XML element * is encountered. * * @deprecated Use the {@link #end(String,String) end} method with * namespace and name parameters instead. */ @Deprecated public void end() throws Exception { // The default implementation does nothing } /** * This method is called when the end of a matching XML element * is encountered. The default implementation delegates to the deprecated * method {@link #end end} without the * namespace and name parameters, to retain * backwards compatibility. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @since Digester 1.4 */ public void end(String namespace, String name) throws Exception { end(); } /** * This method is called after all parsing methods have been * called, to allow Rules to remove temporary data. */ public void finish() throws Exception { // The default implementation does nothing } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/ObjectCreateRule.java0000644000175100017510000001267712271452077026217 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.xml.sax.Attributes; /** * Rule implementation that creates a new object and pushes it * onto the object stack. When the element is complete, the * object will be popped */ public class ObjectCreateRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct an object create rule with the specified class name. * * @param className Java class name of the object to be created */ public ObjectCreateRule(String className) { this(className, (String) null); } /** * Construct an object create rule with the specified class. * * @param clazz Java class name of the object to be created */ public ObjectCreateRule(Class clazz) { this(clazz.getName(), (String) null); } /** * Construct an object create rule with the specified class name and an * optional attribute name containing an override. * * @param className Java class name of the object to be created * @param attributeName Attribute name which, if present, contains an * override of the class name to create */ public ObjectCreateRule(String className, String attributeName) { this.className = className; this.attributeName = attributeName; } /** * Construct an object create rule with the specified class and an * optional attribute name containing an override. * * @param attributeName Attribute name which, if present, contains an * @param clazz Java class name of the object to be created * override of the class name to create */ public ObjectCreateRule(String attributeName, Class clazz) { this(clazz.getName(), attributeName); } // ----------------------------------------------------- Instance Variables /** * The attribute containing an override class name if it is present. */ protected String attributeName = null; /** * The Java class name of the object to be created. */ protected String className = null; // --------------------------------------------------------- Public Methods /** * Process the beginning of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { // Identify the name of the class to instantiate String realClassName = className; if (attributeName != null) { String value = attributes.getValue(attributeName); if (value != null) { realClassName = value; } } if (digester.log.isDebugEnabled()) { digester.log.debug("[ObjectCreateRule]{" + digester.match + "}New " + realClassName); } if (realClassName == null) { throw new NullPointerException("No class name specified for " + namespace + " " + name); } // Instantiate the new object and push it on the context stack Class clazz = digester.getClassLoader().loadClass(realClassName); Object instance = clazz.newInstance(); digester.push(instance); } /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { Object top = digester.pop(); if (digester.log.isDebugEnabled()) { digester.log.debug("[ObjectCreateRule]{" + digester.match + "} Pop " + top.getClass().getName()); } } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ObjectCreateRule["); sb.append("className="); sb.append(className); sb.append(", attributeName="); sb.append(attributeName); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/RulesBase.java0000644000175100017510000002076412271452077024716 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; /** *

    Default implementation of the Rules interface that supports * the standard rule matching behavior. This class can also be used as a * base class for specialized Rules implementations.

    * *

    The matching policies implemented by this class support two different * types of pattern matching rules:

    *
      *
    • Exact Match - A pattern "a/b/c" exactly matches a * <c> element, nested inside a <b> * element, which is nested inside an <a> element.
    • *
    • Tail Match - A pattern "*/a/b" matches a * <b> element, nested inside an <a> * element, no matter how deeply the pair is nested.
    • *
    */ public class RulesBase implements Rules { // ----------------------------------------------------- Instance Variables /** * The set of registered Rule instances, keyed by the matching pattern. * Each value is a List containing the Rules for that pattern, in the * order that they were originally registered. */ protected HashMap> cache = new HashMap>(); /** * The Digester instance with which this Rules instance is associated. */ protected Digester digester = null; /** * The namespace URI for which subsequently added Rule * objects are relevant, or null for matching independent * of namespaces. */ protected String namespaceURI = null; /** * The set of registered Rule instances, in the order that they were * originally registered. */ protected ArrayList rules = new ArrayList(); // ------------------------------------------------------------- Properties /** * Return the Digester instance with which this Rules instance is * associated. */ @Override public Digester getDigester() { return (this.digester); } /** * Set the Digester instance with which this Rules instance is associated. * * @param digester The newly associated Digester instance */ @Override public void setDigester(Digester digester) { this.digester = digester; Iterator items = rules.iterator(); while (items.hasNext()) { Rule item = items.next(); item.setDigester(digester); } } /** * Return the namespace URI that will be applied to all subsequently * added Rule objects. */ @Override public String getNamespaceURI() { return (this.namespaceURI); } /** * Set the namespace URI that will be applied to all subsequently * added Rule objects. * * @param namespaceURI Namespace URI that must match on all * subsequently added rules, or null for matching * regardless of the current namespace URI */ @Override public void setNamespaceURI(String namespaceURI) { this.namespaceURI = namespaceURI; } // --------------------------------------------------------- Public Methods /** * Register a new Rule instance matching the specified pattern. * * @param pattern Nesting pattern to be matched for this Rule * @param rule Rule instance to be registered */ @Override public void add(String pattern, Rule rule) { // to help users who accidently add '/' to the end of their patterns int patternLength = pattern.length(); if (patternLength>1 && pattern.endsWith("/")) { pattern = pattern.substring(0, patternLength-1); } List list = cache.get(pattern); if (list == null) { list = new ArrayList(); cache.put(pattern, list); } list.add(rule); rules.add(rule); if (this.digester != null) { rule.setDigester(this.digester); } if (this.namespaceURI != null) { rule.setNamespaceURI(this.namespaceURI); } } /** * Clear all existing Rule instance registrations. */ @Override public void clear() { cache.clear(); rules.clear(); } /** * Return a List of all registered Rule instances that match the specified * nesting pattern, or a zero-length List if there are no matches. If more * than one Rule instance matches, they must be returned * in the order originally registered through the add() * method. * * @param namespaceURI Namespace URI for which to select matching rules, * or null to match regardless of namespace URI * @param pattern Nesting pattern to be matched */ @Override public List match(String namespaceURI, String pattern) { // List rulesList = (List) this.cache.get(pattern); List rulesList = lookup(namespaceURI, pattern); if ((rulesList == null) || (rulesList.size() < 1)) { // Find the longest key, ie more discriminant String longKey = ""; Iterator keys = this.cache.keySet().iterator(); while (keys.hasNext()) { String key = keys.next(); if (key.startsWith("*/")) { if (pattern.equals(key.substring(2)) || pattern.endsWith(key.substring(1))) { if (key.length() > longKey.length()) { // rulesList = (List) this.cache.get(key); rulesList = lookup(namespaceURI, key); longKey = key; } } } } } if (rulesList == null) { rulesList = new ArrayList(); } return (rulesList); } /** * Return a List of all registered Rule instances, or a zero-length List * if there are no registered Rule instances. If more than one Rule * instance has been registered, they must be returned * in the order originally registered through the add() * method. */ @Override public List rules() { return (this.rules); } // ------------------------------------------------------ Protected Methods /** * Return a List of Rule instances for the specified pattern that also * match the specified namespace URI (if any). If there are no such * rules, return null. * * @param namespaceURI Namespace URI to match, or null to * select matching rules regardless of namespace URI * @param pattern Pattern to be matched */ protected List lookup(String namespaceURI, String pattern) { // Optimize when no namespace URI is specified List list = this.cache.get(pattern); if (list == null) { return (null); } if ((namespaceURI == null) || (namespaceURI.length() == 0)) { return (list); } // Select only Rules that match on the specified namespace URI ArrayList results = new ArrayList(); Iterator items = list.iterator(); while (items.hasNext()) { Rule item = items.next(); if ((namespaceURI.equals(item.getNamespaceURI())) || (item.getNamespaceURI() == null)) { results.add(item); } } return (results); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/CallMethodRule.java0000644000175100017510000005222412271452077025671 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.apache.tomcat.util.IntrospectionUtils; import org.xml.sax.Attributes; /** *

    Rule implementation that calls a method on an object on the stack * (normally the top/parent object), passing arguments collected from * subsequent CallParamRule rules or from the body of this * element.

    * *

    By using {@link #CallMethodRule(String methodName)} * a method call can be made to a method which accepts no * arguments.

    * *

    Incompatible method parameter types are converted * using org.apache.commons.beanutils.ConvertUtils. *

    * *

    This rule now uses * * org.apache.commons.beanutils.MethodUtils#invokeMethod * by default. * This increases the kinds of methods successfully and allows primitives * to be matched by passing in wrapper classes. * There are rare cases when org.apache.commons.beanutils.MethodUtils#invokeExactMethod * (the old default) is required. * This method is much stricter in its reflection. * Setting the UseExactMatch to true reverts to the use of this * method.

    * *

    Note that the target method is invoked when the end of * the tag the CallMethodRule fired on is encountered, not when the * last parameter becomes available. This implies that rules which fire on * tags nested within the one associated with the CallMethodRule will * fire before the CallMethodRule invokes the target method. This behaviour is * not configurable.

    * *

    Note also that if a CallMethodRule is expecting exactly one parameter * and that parameter is not available (eg CallParamRule is used with an * attribute name but the attribute does not exist) then the method will * not be invoked. If a CallMethodRule is expecting more than one parameter, * then it is always invoked, regardless of whether the parameters were * available or not (missing parameters are passed as null values).

    */ public class CallMethodRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "call method" rule with the specified method name. The * parameter types (if any) default to java.lang.String. * * @param methodName Method name of the parent method to call * @param paramCount The number of parameters to collect, or * zero for a single argument from the body of this element. */ public CallMethodRule(String methodName, int paramCount) { this(0, methodName, paramCount); } /** * Construct a "call method" rule with the specified method name. The * parameter types (if any) default to java.lang.String. * * @param targetOffset location of the target object. Positive numbers are * relative to the top of the digester object stack. Negative numbers * are relative to the bottom of the stack. Zero implies the top * object on the stack. * @param methodName Method name of the parent method to call * @param paramCount The number of parameters to collect, or * zero for a single argument from the body of this element. */ public CallMethodRule(int targetOffset, String methodName, int paramCount) { this.targetOffset = targetOffset; this.methodName = methodName; this.paramCount = paramCount; if (paramCount == 0) { this.paramTypes = new Class[] { String.class }; } else { this.paramTypes = new Class[paramCount]; for (int i = 0; i < this.paramTypes.length; i++) { this.paramTypes[i] = String.class; } } } /** * Construct a "call method" rule with the specified method name. * The method should accept no parameters. * * @param methodName Method name of the parent method to call */ public CallMethodRule(String methodName) { this(0, methodName, 0, (Class[]) null); } /** * Construct a "call method" rule with the specified method name. * The method should accept no parameters. * * @param targetOffset location of the target object. Positive numbers are * relative to the top of the digester object stack. Negative numbers * are relative to the bottom of the stack. Zero implies the top * object on the stack. * @param methodName Method name of the parent method to call */ public CallMethodRule(int targetOffset, String methodName) { this(targetOffset, methodName, 0, (Class[]) null); } /** * Construct a "call method" rule with the specified method name and * parameter types. If paramCount is set to zero the rule * will use the body of this element as the single argument of the * method, unless paramTypes is null or empty, in this * case the rule will call the specified method with no arguments. * * @param methodName Method name of the parent method to call * @param paramCount The number of parameters to collect, or * zero for a single argument from the body of this element * @param paramTypes The Java class names of the arguments * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) */ public CallMethodRule( String methodName, int paramCount, String paramTypes[]) { this(0, methodName, paramCount, paramTypes); } /** * Construct a "call method" rule with the specified method name and * parameter types. If paramCount is set to zero the rule * will use the body of this element as the single argument of the * method, unless paramTypes is null or empty, in this * case the rule will call the specified method with no arguments. * * @param targetOffset location of the target object. Positive numbers are * relative to the top of the digester object stack. Negative numbers * are relative to the bottom of the stack. Zero implies the top * object on the stack. * @param methodName Method name of the parent method to call * @param paramCount The number of parameters to collect, or * zero for a single argument from the body of this element * @param paramTypes The Java class names of the arguments * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) */ public CallMethodRule( int targetOffset, String methodName, int paramCount, String paramTypes[]) { this.targetOffset = targetOffset; this.methodName = methodName; this.paramCount = paramCount; if (paramTypes == null) { this.paramTypes = new Class[paramCount]; for (int i = 0; i < this.paramTypes.length; i++) { this.paramTypes[i] = "abc".getClass(); } } else { // copy the parameter class names into an array // the classes will be loaded when the digester is set this.paramClassNames = new String[paramTypes.length]; for (int i = 0; i < this.paramClassNames.length; i++) { this.paramClassNames[i] = paramTypes[i]; } } } /** * Construct a "call method" rule with the specified method name and * parameter types. If paramCount is set to zero the rule * will use the body of this element as the single argument of the * method, unless paramTypes is null or empty, in this * case the rule will call the specified method with no arguments. * * @param methodName Method name of the parent method to call * @param paramCount The number of parameters to collect, or * zero for a single argument from the body of this element * @param paramTypes The Java classes that represent the * parameter types of the method arguments * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean.TYPE * for a boolean parameter) */ public CallMethodRule( String methodName, int paramCount, Class paramTypes[]) { this(0, methodName, paramCount, paramTypes); } /** * Construct a "call method" rule with the specified method name and * parameter types. If paramCount is set to zero the rule * will use the body of this element as the single argument of the * method, unless paramTypes is null or empty, in this * case the rule will call the specified method with no arguments. * * @param targetOffset location of the target object. Positive numbers are * relative to the top of the digester object stack. Negative numbers * are relative to the bottom of the stack. Zero implies the top * object on the stack. * @param methodName Method name of the parent method to call * @param paramCount The number of parameters to collect, or * zero for a single argument from the body of this element * @param paramTypes The Java classes that represent the * parameter types of the method arguments * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean.TYPE * for a boolean parameter) */ public CallMethodRule( int targetOffset, String methodName, int paramCount, Class paramTypes[]) { this.targetOffset = targetOffset; this.methodName = methodName; this.paramCount = paramCount; if (paramTypes == null) { this.paramTypes = new Class[paramCount]; for (int i = 0; i < this.paramTypes.length; i++) { this.paramTypes[i] = "abc".getClass(); } } else { this.paramTypes = new Class[paramTypes.length]; for (int i = 0; i < this.paramTypes.length; i++) { this.paramTypes[i] = paramTypes[i]; } } } // ----------------------------------------------------- Instance Variables /** * The body text collected from this element. */ protected String bodyText = null; /** * location of the target object for the call, relative to the * top of the digester object stack. The default value of zero * means the target object is the one on top of the stack. */ protected int targetOffset = 0; /** * The method name to call on the parent object. */ protected String methodName = null; /** * The number of parameters to collect from MethodParam rules. * If this value is zero, a single parameter will be collected from the * body of this element. */ protected int paramCount = 0; /** * The parameter types of the parameters to be collected. */ protected Class paramTypes[] = null; /** * The names of the classes of the parameters to be collected. * This attribute allows creation of the classes to be postponed until the digester is set. */ protected String paramClassNames[] = null; /** * Should MethodUtils.invokeExactMethod be used for reflection. */ protected boolean useExactMatch = false; // --------------------------------------------------------- Public Methods /** * Should MethodUtils.invokeExactMethod * be used for the reflection. */ public boolean getUseExactMatch() { return useExactMatch; } /** * Set whether MethodUtils.invokeExactMethod * should be used for the reflection. */ public void setUseExactMatch(boolean useExactMatch) { this.useExactMatch = useExactMatch; } /** * Set the associated digester. * If needed, this class loads the parameter classes from their names. */ @Override public void setDigester(Digester digester) { // call superclass super.setDigester(digester); // if necessary, load parameter classes if (this.paramClassNames != null) { this.paramTypes = new Class[paramClassNames.length]; for (int i = 0; i < this.paramClassNames.length; i++) { try { this.paramTypes[i] = digester.getClassLoader().loadClass(this.paramClassNames[i]); } catch (ClassNotFoundException e) { // use the digester log digester.getLogger().error("(CallMethodRule) Cannot load class " + this.paramClassNames[i], e); this.paramTypes[i] = null; // Will cause NPE later } } } } /** * Process the start of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { // Push an array to capture the parameter values if necessary if (paramCount > 0) { Object parameters[] = new Object[paramCount]; for (int i = 0; i < parameters.length; i++) { parameters[i] = null; } digester.pushParams(parameters); } } /** * Process the body text of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param bodyText The body text of this element */ @Override public void body(String namespace, String name, String bodyText) throws Exception { if (paramCount == 0) { this.bodyText = bodyText.trim(); } } /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { // Retrieve or construct the parameter values array Object parameters[] = null; if (paramCount > 0) { parameters = (Object[]) digester.popParams(); if (digester.log.isTraceEnabled()) { for (int i=0,size=parameters.length;i= 0) { target = digester.peek(targetOffset); } else { target = digester.peek( digester.getCount() + targetOffset ); } if (target == null) { StringBuilder sb = new StringBuilder(); sb.append("[CallMethodRule]{"); sb.append(digester.match); sb.append("} Call target is null ("); sb.append("targetOffset="); sb.append(targetOffset); sb.append(",stackdepth="); sb.append(digester.getCount()); sb.append(")"); throw new org.xml.sax.SAXException(sb.toString()); } // Invoke the required method on the top object if (digester.log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("[CallMethodRule]{"); sb.append(digester.match); sb.append("} Call "); sb.append(target.getClass().getName()); sb.append("."); sb.append(methodName); sb.append("("); for (int i = 0; i < paramValues.length; i++) { if (i > 0) { sb.append(","); } if (paramValues[i] == null) { sb.append("null"); } else { sb.append(paramValues[i].toString()); } sb.append("/"); if (paramTypes[i] == null) { sb.append("null"); } else { sb.append(paramTypes[i].getName()); } } sb.append(")"); digester.log.debug(sb.toString()); } Object result = IntrospectionUtils.callMethodN(target, methodName, paramValues, paramTypes); processMethodCallResult(result); } /** * Clean up after parsing is complete. */ @Override public void finish() throws Exception { bodyText = null; } /** * Subclasses may override this method to perform additional processing of the * invoked method's result. * * @param result the Object returned by the method invoked, possibly null */ protected void processMethodCallResult(Object result) { // do nothing } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("CallMethodRule["); sb.append("methodName="); sb.append(methodName); sb.append(", paramCount="); sb.append(paramCount); sb.append(", paramTypes={"); if (paramTypes != null) { for (int i = 0; i < paramTypes.length; i++) { if (i > 0) { sb.append(", "); } sb.append(paramTypes[i].getName()); } } sb.append("}"); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java0000644000175100017510000000443612271452077030736 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.xml.sax.Attributes; /** *

    Abstract base class for ObjectCreationFactory * implementations.

    */ public abstract class AbstractObjectCreationFactory implements ObjectCreationFactory { // ----------------------------------------------------- Instance Variables /** * The associated Digester instance that was set up by * {@link FactoryCreateRule} upon initialization. */ private Digester digester = null; // --------------------------------------------------------- Public Methods /** *

    Factory method called by {@link FactoryCreateRule} to supply an * object based on the element's attributes. * * @param attributes the element's attributes * * @throws Exception any exception thrown will be propagated upwards */ @Override public abstract Object createObject(Attributes attributes) throws Exception; /** *

    Returns the {@link Digester} that was set by the * {@link FactoryCreateRule} upon initialization. */ @Override public Digester getDigester() { return (this.digester); } /** *

    Set the {@link Digester} to allow the implementation to do logging, * classloading based on the digester's classloader, etc. * * @param digester parent Digester object */ @Override public void setDigester(Digester digester) { this.digester = digester; } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/XercesParser.java0000644000175100017510000001423312271452077025431 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.lang.reflect.Method; import java.util.Properties; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; /** * Create a SAXParser based on the underlying Xerces version. * Currently, Xerces 2.3 and up doesn't implement schema validation the same way * 2.1 was. In other to support schema validation in a portable way between * parser, some features/properties need to be set. * * @since 1.6 */ public class XercesParser{ /** * The Log to which all SAX event related logging calls will be made. */ private static final Log log = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax"); /** * The JAXP 1.2 property required to set up the schema location. */ private static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; /** * The JAXP 1.2 property to set up the schemaLanguage used. */ protected static String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; /** * Xerces dynamic validation property */ protected static String XERCES_DYNAMIC = "http://apache.org/xml/features/validation/dynamic"; /** * Xerces schema validation property */ protected static String XERCES_SCHEMA = "http://apache.org/xml/features/validation/schema"; /** * A float representing the underlying Xerces version */ protected static float version; /** * The current Xerces version. */ protected static String versionNumber = null; /** * Return the current Xerces version. * @return the current Xerces version. */ private static String getXercesVersion() { // If for some reason we can't get the version, set it to 1.0. String versionNumber = "1.0"; try{ // Use reflection to avoid a build dependency with Xerces. Class versionClass = Class.forName("org.apache.xerces.impl.Version"); // Will return Xerces-J 2.x.0 Method method = versionClass.getMethod("getVersion", (Class[]) null); String version = (String)method.invoke(null, (Object[]) null); versionNumber = version.substring( "Xerces-J".length() , version.lastIndexOf(".") ); } catch (Exception ex){ // Do nothing. } return versionNumber; } /** * Create a SAXParser based on the underlying * Xerces version. * @param properties parser specific properties/features * @return an XML Schema/DTD enabled SAXParser */ public static SAXParser newSAXParser(Properties properties) throws ParserConfigurationException, SAXException, SAXNotSupportedException { SAXParserFactory factory = (SAXParserFactory)properties.get("SAXParserFactory"); if (versionNumber == null){ versionNumber = getXercesVersion(); version = new Float( versionNumber ).floatValue(); } // Note: 2.2 is completely broken (with XML Schema). if (version > 2.1) { configureXerces(factory); return factory.newSAXParser(); } else { SAXParser parser = factory.newSAXParser(); configureOldXerces(parser,properties); return parser; } } /** * Configure schema validation as recommended by the JAXP 1.2 spec. * The properties object may contains information about * the schema local and language. * @param properties parser optional info */ private static void configureOldXerces(SAXParser parser, Properties properties) throws ParserConfigurationException, SAXNotSupportedException { String schemaLocation = (String)properties.get("schemaLocation"); String schemaLanguage = (String)properties.get("schemaLanguage"); try{ if (schemaLocation != null) { parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); } } catch (SAXNotRecognizedException e){ log.info(parser.getClass().getName() + ": " + e.getMessage() + " not supported."); } } /** * Configure schema validation as recommended by the Xerces spec. * Both DTD and Schema validation will be enabled simultaneously. * @param factory SAXParserFactory to be configured */ private static void configureXerces(SAXParserFactory factory) throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException { factory.setFeature(XERCES_DYNAMIC, true); factory.setFeature(XERCES_SCHEMA, true); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java0000644000175100017510000000444312271452077030314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.util.Properties; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; /** * Creates a SAXParser based on the underlying parser. * Allows logical properties depending on logical parser versions * to be set. * * @since 1.6 */ public class ParserFeatureSetterFactory{ /** * true is Xerces is used. */ private static boolean isXercesUsed; static { try{ // Use reflection to avoid a build dependency with Xerces. Class.forName("org.apache.xerces.impl.Version"); isXercesUsed = true; } catch (Exception ex){ isXercesUsed = false; } } /** * Create a new SAXParser * @param properties (logical) properties to be set on parser * @return a SAXParser configured based on the underlying * parser implementation. */ public static SAXParser newSAXParser(Properties properties) throws ParserConfigurationException, SAXException, SAXNotRecognizedException, SAXNotSupportedException { if (isXercesUsed){ return XercesParser.newSAXParser(properties); } else { return GenericParser.newSAXParser(properties); } } }tomcat7-7.0.52/java/org/apache/tomcat/util/digester/package.html0000644000175100017510000016566612271452077024462 0ustar locutuslocutus Package Documentation for org.apache.commons.digester Package The Digester package provides for rules-based processing of arbitrary XML documents.

    Introduction

    In many application environments that deal with XML-formatted data, it is useful to be able to process an XML document in an "event driven" manner, where particular Java objects are created (or methods of existing objects are invoked) when particular patterns of nested XML elements have been recognized. Developers familiar with the Simple API for XML Parsing (SAX) approach to processing XML documents will recognize that the Digester provides a higher level, more developer-friendly interface to SAX events, because most of the details of navigating the XML element hierarchy are hidden -- allowing the developer to focus on the processing to be performed.

    In order to use a Digester, the following basic steps are required:

    • Create a new instance of the org.apache.commons.digester.Digester class. Previously created Digester instances may be safely reused, as long as you have completed any previously requested parse, and you do not try to utilize a particular Digester instance from more than one thread at a time.
    • Set any desired configuration properties that will customize the operation of the Digester when you next initiate a parse operation.
    • Optionally, push any desired initial object(s) onto the Digester's object stack.
    • Register all of the element matching patterns for which you wish to have processing rules fired when this pattern is recognized in an input document. You may register as many rules as you like for any particular pattern. If there is more than one rule for a given pattern, the rules will be executed in the order that they were listed.
    • Call the digester.parse() method, passing a reference to the XML document to be parsed in one of a variety of forms. See the Digester.parse() documentation for details. Note that you will need to be prepared to catch any IOException or SAXException that is thrown by the parser, or any runtime expression that is thrown by one of the processing rules.

    For example code, see the usage examples, and the FAQ .

    Digester Configuration Properties

    A org.apache.commons.digester.Digester instance contains several configuration properties that can be used to customize its operation. These properties must be configured before you call one of the parse() variants, in order for them to take effect on that parse.

    Property Description
    classLoader You can optionally specify the class loader that will be used to load classes when required by the ObjectCreateRule and FactoryCreateRule rules. If not specified, application classes will be loaded from the thread's context class loader (if the useContextClassLoader property is set to true) or the same class loader that was used to load the Digester class itself.
    errorHandler You can optionally specify a SAX ErrorHandler that is notified when parsing errors occur. By default, any parsing errors that are encountered are logged, but Digester will continue processing as well.
    namespaceAware A boolean that is set to true to perform parsing in a manner that is aware of XML namespaces. Among other things, this setting affects how elements are matched to processing rules. See Namespace Aware Parsing for more information.
    ruleNamespaceURI The public URI of the namespace for which all subsequently added rules are associated, or null for adding rules that are not associated with any namespace. See Namespace Aware Parsing for more information.
    rules The Rules component that actually performs matching of Rule instances against the current element nesting pattern is pluggable. By default, Digester includes a Rules implementation that behaves as described in this document. See Pluggable Rules Processing for more information.
    useContextClassLoader A boolean that is set to true if you want application classes required by FactoryCreateRule and ObjectCreateRule to be loaded from the context class loader of the current thread. By default, classes will be loaded from the class loader that loaded this Digester class. NOTE - This property is ignored if you set a value for the classLoader property; that class loader will be used unconditionally.
    validating A boolean that is set to true if you wish to validate the XML document against a Document Type Definition (DTD) that is specified in its DOCTYPE declaration. The default value of false requests a parse that only detects "well formed" XML documents, rather than "valid" ones.

    In addition to the scalar properties defined above, you can also register a local copy of a Document Type Definition (DTD) that is referenced in a DOCTYPE declaration. Such a registration tells the XML parser that, whenever it encounters a DOCTYPE declaration with the specified public identifier, it should utilize the actual DTD content at the registered system identifier (a URL), rather than the one in the DOCTYPE declaration.

    For example, the Struts framework controller servlet uses the following registration in order to tell Struts to use a local copy of the DTD for the Struts configuration file. This allows usage of Struts in environments that are not connected to the Internet, and speeds up processing even at Internet connected sites (because it avoids the need to go across the network).

        URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
        digester.register
          ("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
           url.toString());
    

    As a side note, the system identifier used in this example is the path that would be passed to java.lang.ClassLoader.getResource() or java.lang.ClassLoader.getResourceAsStream(). The actual DTD resource is loaded through the same class loader that loads all of the Struts classes -- typically from the struts.jar file.

    The Object Stack

    One very common use of org.apache.commons.digester.Digester technology is to dynamically construct a tree of Java objects, whose internal organization, as well as the details of property settings on these objects, are configured based on the contents of the XML document. In fact, the primary reason that the Digester package was created (it was originally part of Struts, and then moved to the Commons project because it was recognized as being generally useful) was to facilitate the way that the Struts controller servlet configures itself based on the contents of your application's struts-config.xml file.

    To facilitate this usage, the Digester exposes a stack that can be manipulated by processing rules that are fired when element matching patterns are satisfied. The usual stack-related operations are made available, including the following:

    • clear() - Clear the current contents of the object stack.
    • peek() - Return a reference to the top object on the stack, without removing it.
    • pop() - Remove the top object from the stack and return it.
    • push() - Push a new object onto the top of the stack.

    A typical design pattern, then, is to fire a rule that creates a new object and pushes it on the stack when the beginning of a particular XML element is encountered. The object will remain there while the nested content of this element is processed, and it will be popped off when the end of the element is encountered. As we will see, the standard "object create" processing rule supports exactly this functionalility in a very convenient way.

    Several potential issues with this design pattern are addressed by other features of the Digester functionality:

    • How do I relate the objects being created to each other? - The Digester supports standard processing rules that pass the top object on the stack as an argument to a named method on the next-to-top object on the stack (or vice versa). This rule makes it easy to establish parent-child relationships between these objects. One-to-one and one-to-many relationships are both easy to construct.
    • How do I retain a reference to the first object that was created? As you review the description of what the "object create" processing rule does, it would appear that the first object you create (i.e. the object created by the outermost XML element you process) will disappear from the stack by the time that XML parsing is completed, because the end of the element would have been encountered. However, Digester will maintain a reference to the very first object ever pushed onto the object stack, and will return it to you as the return value from the parse() call. Alternatively, you can push a reference to some application object onto the stack before calling parse(), and arrange that a parent-child relationship be created (by appropriate processing rules) between this manually pushed object and the ones that are dynamically created. In this way, the pushed object will retain a reference to the dynamically created objects (and therefore all of their children), and will be returned to you after the parse finishes as well.

    Element Matching Patterns

    A primary feature of the org.apache.commons.digester.Digester parser is that the Digester automatically navigates the element hierarchy of the XML document you are parsing for you, without requiring any developer attention to this process. Instead, you focus on deciding what functions you would like to have performed whenver a certain arrangement of nested elements is encountered in the XML document being parsed. The mechanism for specifying such arrangements are called element matching patterns.

    A very simple element matching pattern is a simple string like "a". This pattern is matched whenever an <a> top-level element is encountered in the XML document, no matter how many times it occurs. Note that nested <a> elements will not match this pattern -- we will describe means to support this kind of matching later.

    The next step up in matching pattern complexity is "a/b". This pattern will be matched when a <b> element is found nested inside a top-level <a> element. Again, this match can occur as many times as desired, depending on the content of the XML document being parsed. You can use multiple slashes to define a hierarchy of any desired depth that will be matched appropriately.

    For example, assume you have registered processing rules that match patterns "a", "a/b", and "a/b/c". For an input XML document with the following contents, the indicated patterns will be matched when the corresponding element is parsed:

      <a>         -- Matches pattern "a"
        <b>       -- Matches pattern "a/b"
          <c/>    -- Matches pattern "a/b/c"
          <c/>    -- Matches pattern "a/b/c"
        </b>
        <b>       -- Matches pattern "a/b"
          <c/>    -- Matches pattern "a/b/c"
          <c/>    -- Matches pattern "a/b/c"
          <c/>    -- Matches pattern "a/b/c"
        </b>
      </a>
    

    It is also possible to match a particular XML element, no matter how it is nested (or not nested) in the XML document, by using the "*" wildcard character in your matching pattern strings. For example, an element matching pattern of "*/a" will match an <a> element at any nesting position within the document.

    It is quite possible that, when a particular XML element is being parsed, the pattern for more than one registered processing rule will be matched either because you registered more than one processing rule with the same matching pattern, or because one more more exact pattern matches and wildcard pattern matches are satisfied by the same element.

    When this occurs, the corresponding processing rules will all be fired in order. begin (and body) method calls are executed in the order that the Rules where initially registered with the Digester, whilst end method calls are execute in reverse order. In other words - the order is first in, last out.

    Processing Rules

    The previous section documented how you identify when you wish to have certain actions take place. The purpose of processing rules is to define what should happen when the patterns are matched.

    Formally, a processing rule is a Java class that subclasses the org.apache.commons.digester.Rule interface. Each Rule implements one or more of the following event methods that are called at well-defined times when the matching patterns corresponding to this rule trigger it:

    • begin() - Called when the beginning of the matched XML element is encountered. A data structure containing all of the attributes corresponding to this element are passed as well.
    • body() - Called when nested content (that is not itself XML elements) of the matched element is encountered. Any leading or trailing whitespace will have been removed as part of the parsing process.
    • end() - Called when the ending of the matched XML element is encountered. If nested XML elements that matched other processing rules was included in the body of this element, the appropriate processing rules for the matched rules will have already been completed before this method is called.
    • finish() - Called when the parse has been completed, to give each rule a chance to clean up any temporary data they might have created and cached.

    As you are configuring your digester, you can call the addRule() method to register a specific element matching pattern, along with an instance of a Rule class that will have its event handling methods called at the appropriate times, as described above. This mechanism allows you to create Rule implementation classes dynamically, to implement any desired application specific functionality.

    In addition, a set of processing rule implementation classes are provided, which deal with many common programming scenarios. These classes include the following:

    • ObjectCreateRule - When the begin() method is called, this rule instantiates a new instance of a specified Java class, and pushes it on the stack. The class name to be used is defaulted according to a parameter passed to this rule's constructor, but can optionally be overridden by a classname passed via the specified attribute to the XML element being processed. When the end() method is called, the top object on the stack (presumably, the one we added in the begin() method) will be popped, and any reference to it (within the Digester) will be discarded.
    • FactoryCreateRule - A variation of ObjectCreateRule that is useful when the Java class with which you wish to create an object instance does not have a no-arguments constructor, or where you wish to perform other setup processing before the object is handed over to the Digester.
    • SetPropertiesRule - When the begin() method is called, the digester uses the standard Java Reflection API to identify any JavaBeans property setter methods (on the object at the top of the digester's stack) who have property names that match the attributes specified on this XML element, and then call them individually, passing the corresponding attribute values. These natural mappings can be overridden. This allows (for example) a class attribute to be mapped correctly. It is recommended that this feature should not be overused - in most cases, it's better to use the standard BeanInfo mechanism. A very common idiom is to define an object create rule, followed by a set properties rule, with the same element matching pattern. This causes the creation of a new Java object, followed by "configuration" of that object's properties based on the attributes of the same XML element that created this object.
    • SetPropertyRule - When the begin() method is called, the digester calls a specified property setter (where the property itself is named by an attribute) with a specified value (where the value is named by another attribute), on the object at the top of the digester's stack. This is useful when your XML file conforms to a particular DTD, and you wish to configure a particular property that does not have a corresponding attribute in the DTD.
    • SetNextRule - When the end() method is called, the digester analyzes the next-to-top element on the stack, looking for a property setter method for a specified property. It then calls this method, passing the object at the top of the stack as an argument. This rule is commonly used to establish one-to-many relationships between the two objects, with the method name commonly being something like "addChild".
    • SetTopRule - When the end() method is called, the digester analyzes the top element on the stack, looking for a property setter method for a specified property. It then calls this method, passing the next-to-top object on the stack as an argument. This rule would be used as an alternative to a SetNextRule, with a typical method name "setParent", if the API supported by your object classes prefers this approach.
    • CallMethodRule - This rule sets up a method call to a named method of the top object on the digester's stack, which will actually take place when the end() method is called. You configure this rule by specifying the name of the method to be called, the number of arguments it takes, and (optionally) the Java class name(s) defining the type(s) of the method's arguments. The actual parameter values, if any, will typically be accumulated from the body content of nested elements within the element that triggered this rule, using the CallParamRule discussed next.
    • CallParamRule - This rule identifies the source of a particular numbered (zero-relative) parameter for a CallMethodRule within which we are nested. You can specify that the parameter value be taken from a particular named attribute, or from the nested body content of this element.
    • NodeCreateRule - A specialized rule that converts part of the tree into a DOM Node and then pushes it onto the stack.

    You can create instances of the standard Rule classes and register them by calling digester.addRule(), as described above. However, because their usage is so common, shorthand registration methods are defined for each of the standard rules, directly on the Digester class. For example, the following code sequence:

        Rule rule = new SetNextRule(digester, "addChild",
                                    "com.mycompany.mypackage.MyChildClass");
        digester.addRule("a/b/c", rule);
    

    can be replaced by:

        digester.addSetNext("a/b/c", "addChild",
                            "com.mycompany.mypackage.MyChildClass");
    

    Logging

    Logging is a vital tool for debugging Digester rulesets. Digester can log copious amounts of debugging information. So, you need to know how logging works before you start using Digester seriously.

    Two main logs are used by Digester:

    • SAX-related messages are logged to org.apache.commons.digester.Digester.sax. This log gives information about the basic SAX events received by Digester.
    • org.apache.commons.digester.Digester is used for everything else. You'll probably want to have this log turned up during debugging but turned down during production due to the high message volume.

    Usage Examples

    Creating a Simple Object Tree

    Let's assume that you have two simple JavaBeans, Foo and Bar, with the following method signatures:

      package mypackage;
      public class Foo {
        public void addBar(Bar bar);
        public Bar findBar(int id);
        public Iterator getBars();
        public String getName();
        public void setName(String name);
      }
    
      public mypackage;
      public class Bar {
        public int getId();
        public void setId(int id);
        public String getTitle();
        public void setTitle(String title);
      }
    

    and you wish to use Digester to parse the following XML document:

      <foo name="The Parent">
        <bar id="123" title="The First Child"/>
        <bar id="456" title="The Second Child"/>
      </foo>
    

    A simple approach will be to use the following Digester in the following way to set up the parsing rules, and then process an input file containing this document:

      Digester digester = new Digester();
      digester.setValidating(false);
      digester.addObjectCreate("foo", "mypackage.Foo");
      digester.addSetProperties("foo");
      digester.addObjectCreate("foo/bar", "mypackage.Bar");
      digester.addSetProperties("foo/bar");
      digester.addSetNext("foo/bar", "addBar", "mypackage.Bar");
      Foo foo = (Foo) digester.parse();
    

    In order, these rules do the following tasks:

    1. When the outermost <foo> element is encountered, create a new instance of mypackage.Foo and push it on to the object stack. At the end of the <foo> element, this object will be popped off of the stack.
    2. Cause properties of the top object on the stack (i.e. the Foo object that was just created and pushed) to be set based on the values of the attributes of this XML element.
    3. When a nested <bar> element is encountered, create a new instance of mypackage.Bar and push it on to the object stack. At the end of the <bar> element, this object will be popped off of the stack (i.e. after the remaining rules matching foo/bar are processed).
    4. Cause properties of the top object on the stack (i.e. the Bar object that was just created and pushed) to be set based on the values of the attributes of this XML element. Note that type conversions are automatically performed (such as String to int for the id property), for all converters registered with the ConvertUtils class from commons-beanutils package.
    5. Cause the addBar method of the next-to-top element on the object stack (which is why this is called the "set next" rule) to be called, passing the element that is on the top of the stack, which must be of type mypackage.Bar. This is the rule that causes the parent/child relationship to be created.

    Once the parse is completed, the first object that was ever pushed on to the stack (the Foo object in this case) is returned to you. It will have had its properties set, and all of its child Bar objects created for you.

    Processing A Struts Configuration File

    As stated earlier, the primary reason that the Digester package was created is because the Struts controller servlet itself needed a robust, flexible, easy to extend mechanism for processing the contents of the struts-config.xml configuration that describes nearly every aspect of a Struts-based application. Because of this, the controller servlet contains a comprehensive, real world, example of how the Digester can be employed for this type of a use case. See the initDigester() method of class org.apache.struts.action.ActionServlet for the code that creates and configures the Digester to be used, and the initMapping() method for where the parsing actually takes place.

    (Struts binary and source distributions can be acquired at http://struts.apache.org/.)

    The following discussion highlights a few of the matching patterns and processing rules that are configured, to illustrate the use of some of the Digester features. First, let's look at how the Digester instance is created and initialized:

        Digester digester = new Digester();
        digester.push(this); // Push controller servlet onto the stack
        digester.setValidating(true);
    

    We see that a new Digester instance is created, and is configured to use a validating parser. Validation will occur against the struts-config_1_0.dtd DTD that is included with Struts (as discussed earlier). In order to provide a means of tracking the configured objects, the controller servlet instance itself will be added to the digester's stack.

        digester.addObjectCreate("struts-config/global-forwards/forward",
                                 forwardClass, "className");
        digester.addSetProperties("struts-config/global-forwards/forward");
        digester.addSetNext("struts-config/global-forwards/forward",
                            "addForward",
                            "org.apache.struts.action.ActionForward");
        digester.addSetProperty
          ("struts-config/global-forwards/forward/set-property",
           "property", "value");
    

    The rules created by these lines are used to process the global forward declarations. When a <forward> element is encountered, the following actions take place:

    • A new object instance is created -- the ActionForward instance that will represent this definition. The Java class name defaults to that specified as an initialization parameter (which we have stored in the String variable forwardClass), but can be overridden by using the "className" attribute (if it is present in the XML element we are currently parsing). The new ActionForward instance is pushed onto the stack.
    • The properties of the ActionForward instance (at the top of the stack) are configured based on the attributes of the <forward> element.
    • Nested occurrences of the <set-property> element cause calls to additional property setter methods to occur. This is required only if you have provided a custom implementation of the ActionForward class with additional properties that are not included in the DTD.
    • The addForward() method of the next-to-top object on the stack (i.e. the controller servlet itself) will be called, passing the object at the top of the stack (i.e. the ActionForward instance) as an argument. This causes the global forward to be registered, and as a result of this it will be remembered even after the stack is popped.
    • At the end of the <forward> element, the top element (i.e. the ActionForward instance) will be popped off the stack.

    Later on, the digester is actually executed as follows:

        InputStream input =
          getServletContext().getResourceAsStream(config);
        ...
        try {
            digester.parse(input);
            input.close();
        } catch (SAXException e) {
            ... deal with the problem ...
        }
    

    As a result of the call to parse(), all of the configuration information that was defined in the struts-config.xml file is now represented as collections of objects cached within the Struts controller servlet, as well as being exposed as servlet context attributes.

    Parsing Body Text In XML Files

    The Digester module also allows you to process the nested body text in an XML file, not just the elements and attributes that are encountered. The following example is based on an assumed need to parse the web application deployment descriptor (/WEB-INF/web.xml) for the current web application, and record the configuration information for a particular servlet. To record this information, assume the existence of a bean class with the following method signatures (among others):

      package com.mycompany;
      public class ServletBean {
        public void setServletName(String servletName);
        public void setServletClass(String servletClass);
        public void addInitParam(String name, String value);
      }
    

    We are going to process the web.xml file that declares the controller servlet in a typical Struts-based application (abridged for brevity in this example):

      <web-app>
        ...
        <servlet>
          <servlet-name>action</servlet-name>
          <servlet-class>org.apache.struts.action.ActionServlet<servlet-class>
          <init-param>
            <param-name>application</param-name>
            <param-value>org.apache.struts.example.ApplicationResources<param-value>
          </init-param>
          <init-param>
            <param-name>config</param-name>
            <param-value>/WEB-INF/struts-config.xml<param-value>
          </init-param>
        </servlet>
        ...
      </web-app>
    

    Next, lets define some Digester processing rules for this input file:

      digester.addObjectCreate("web-app/servlet",
                               "com.mycompany.ServletBean");
      digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
      digester.addCallMethod("web-app/servlet/servlet-class",
                             "setServletClass", 0);
      digester.addCallMethod("web-app/servlet/init-param",
                             "addInitParam", 2);
      digester.addCallParam("web-app/servlet/init-param/param-name", 0);
      digester.addCallParam("web-app/servlet/init-param/param-value", 1);
    

    Now, as elements are parsed, the following processing occurs:

    • <servlet> - A new com.mycompany.ServletBean object is created, and pushed on to the object stack.
    • <servlet-name> - The setServletName() method of the top object on the stack (our ServletBean) is called, passing the body content of this element as a single parameter.
    • <servlet-class> - The setServletClass() method of the top object on the stack (our ServletBean) is called, passing the body content of this element as a single parameter.
    • <init-param> - A call to the addInitParam method of the top object on the stack (our ServletBean) is set up, but it is not called yet. The call will be expecting two String parameters, which must be set up by subsequent call parameter rules.
    • <param-name> - The body content of this element is assigned as the first (zero-relative) argument to the call we are setting up.
    • <param-value> - The body content of this element is assigned as the second (zero-relative) argument to the call we are setting up.
    • </init-param> - The call to addInitParam() that we have set up is now executed, which will cause a new name-value combination to be recorded in our bean.
    • <init-param> - The same set of processing rules are fired again, causing a second call to addInitParam() with the second parameter's name and value.
    • </servlet> - The element on the top of the object stack (which should be the ServletBean we pushed earlier) is popped off the object stack.

    Namespace Aware Parsing

    For digesting XML documents that do not use XML namespaces, the default behavior of Digester, as described above, is generally sufficient. However, if the document you are processing uses namespaces, it is often convenient to have sets of Rule instances that are only matched on elements that use the prefix of a particular namespace. This approach, for example, makes it possible to deal with element names that are the same in different namespaces, but where you want to perform different processing for each namespace.

    Digester does not provide full support for namespaces, but does provide sufficient to accomplish most tasks. Enabling digester's namespace support is done by following these steps:

    1. Tell Digester that you will be doing namespace aware parsing, by adding this statement in your initalization of the Digester's properties:
          digester.setNamespaceAware(true);
          
    2. Declare the public namespace URI of the namespace with which following rules will be associated. Note that you do not make any assumptions about the prefix - the XML document author is free to pick whatever prefix they want:
          digester.setRuleNamespaceURI("http://www.mycompany.com/MyNamespace");
          
    3. Add the rules that correspond to this namespace, in the usual way, by calling methods like addObjectCreate() or addSetProperties(). In the matching patterns you specify, use only the local name portion of the elements (i.e. the part after the prefix and associated colon (":") character:
          digester.addObjectCreate("foo/bar", "com.mycompany.MyFoo");
          digester.addSetProperties("foo/bar");
          
    4. Repeat the previous two steps for each additional public namespace URI that should be recognized on this Digester run.

    Now, consider that you might wish to digest the following document, using the rules that were set up in the steps above:

    <m:foo
       xmlns:m="http://www.mycompany.com/MyNamespace"
       xmlns:y="http://www.yourcompany.com/YourNamespace">
    
      <m:bar name="My Name" value="My Value"/>
    
      <y:bar id="123" product="Product Description"/>L
    
    </x:foo>
    

    Note that your object create and set properties rules will be fired for the first occurrence of the bar element, but not the second one. This is because we declared that our rules only matched for the particular namespace we are interested in. Any elements in the document that are associated with other namespaces (or no namespaces at all) will not be processed. In this way, you can easily create rules that digest only the portions of a compound document that they understand, without placing any restrictions on what other content is present in the document.

    You might also want to look at Encapsulated Rule Sets if you wish to reuse a particular set of rules, associated with a particular namespace, in more than one application context.

    Using Namespace Prefixes In Pattern Matching

    Using rules with namespaces is very useful when you have orthogonal rulesets. One ruleset applies to a namespace and is independent of other rulesets applying to other namespaces. However, if your rule logic requires mixed namespaces, then matching namespace prefix patterns might be a better strategy.

    When you set the NamespaceAware property to false, digester uses the qualified element name (which includes the namespace prefix) rather than the local name as the patten component for the element. This means that your pattern matches can include namespace prefixes as well as element names. So, rather than create namespace-aware rules, create pattern matches including the namespace prefixes.

    For example, (with NamespaceAware false), the pattern 'foo:bar' will match a top level element named 'bar' in the namespace with (local) prefix 'foo'.

    Limitations of Digester Namespace support

    Digester does not provide general "xpath-compliant" matching; only the namespace attached to the last element in the match path is involved in the matching process. Namespaces attached to parent elements are ignored for matching purposes.

    Pluggable Rules Processing

    By default, Digester selects the rules that match a particular pattern of nested elements as described under Element Matching Patterns. If you prefer to use different selection policies, however, you can create your own implementation of the org.apache.commons.digester.Rules interface, or subclass the corresponding convenience base class org.apache.commons.digester.RulesBase. Your implementation of the match() method will be called when the processing for a particular element is started or ended, and you must return a List of the rules that are relevant for the current nesting pattern. The order of the rules you return is significant, and should match the order in which rules were initally added.

    Your policy for rule selection should generally be sensitive to whether Namespace Aware Parsing is taking place. In general, if namespaceAware is true, you should select only rules that:

    • Are registered for the public namespace URI that corresponds to the prefix being used on this element.
    • Match on the "local name" portion of the element (so that the document creator can use any prefix that they like).

    ExtendedBaseRules

    ExtendedBaseRules, adds some additional expression syntax for pattern matching to the default mechanism, but it also executes more slowly. See the JavaDocs for more details on the new pattern matching syntax, and suggestions on when this implementation should be used. To use it, simply do the following as part of your Digester initialization:

      Digester digester = ...
      ...
      digester.setRules(new ExtendedBaseRules());
      ...
    

    RegexRules

    RegexRules is an advanced Rules implementation which does not build on the default pattern matching rules. It uses a pluggable RegexMatcher implementation to test if a path matches the pattern for a Rule. All matching rules are returned (note that this behaviour differs from longest matching rule of the default pattern matching rules). See the Java Docs for more details.

    Example usage:

      Digester digester = ...
      ...
      digester.setRules(new RegexRules(new SimpleRegexMatcher()));
      ...
    
    RegexMatchers

    Digester ships only with one RegexMatcher implementation: SimpleRegexMatcher. This implementation is unsophisticated and lacks many good features lacking in more power Regex libraries. There are some good reasons why this approach was adopted. The first is that SimpleRegexMatcher is simple, it is easy to write and runs quickly. The second has to do with the way that RegexRules is intended to be used.

    There are many good regex libraries available. (For example Jakarta ORO, Jakarta Regex, GNU Regex and Java 1.4 Regex) Not only do different people have different personal tastes when it comes to regular expression matching but these products all offer different functionality and different strengths.

    The pluggable RegexMatcher is a thin bridge designed to adapt other Regex systems. This allows any Regex library the user desires to be plugged in and used just by creating one class. Digester does not (currently) ship with bridges to the major regex (to allow the dependencies required by Digester to be kept to a minimum).

    WithDefaultsRulesWrapper

    WithDefaultsRulesWrapper allows default Rule instances to be added to any existing Rules implementation. These default Rule instances will be returned for any match for which the wrapped implementation does not return any matches.

    For example,

        Rule alpha;
        ...
        WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
        rules.addDefault(alpha);
        ...
        digester.setRules(rules);
        ...
    
    when a pattern does not match any other rule, then rule alpha will be called.

    WithDefaultsRulesWrapper follows the Decorator pattern.

    Encapsulated Rule Sets

    All of the examples above have described a scenario where the rules to be processed are registered with a Digester instance immediately after it is created. However, this approach makes it difficult to reuse the same set of rules in more than one application environment. Ideally, one could package a set of rules into a single class, which could be easily loaded and registered with a Digester instance in one easy step.

    The RuleSet interface (and the convenience base class RuleSetBase) make it possible to do this. In addition, the rule instances registered with a particular RuleSet can optionally be associated with a particular namespace, as described under Namespace Aware Processing.

    An example of creating a RuleSet might be something like this:

    public class MyRuleSet extends RuleSetBase {
    
      public MyRuleSet() {
        this("");
      }
    
      public MyRuleSet(String prefix) {
        super();
        this.prefix = prefix;
        this.namespaceURI = "http://www.mycompany.com/MyNamespace";
      }
    
      protected String prefix = null;
    
      public void addRuleInstances(Digester digester) {
        digester.addObjectCreate(prefix + "foo/bar",
          "com.mycompany.MyFoo");
        digester.addSetProperties(prefix + "foo/bar");
      }
    
    }
    

    You might use this RuleSet as follow to initialize a Digester instance:

      Digester digester = new Digester();
      ... configure Digester properties ...
      digester.addRuleSet(new MyRuleSet("baz/"));
    

    A couple of interesting notes about this approach:

    • The application that is using these rules does not need to know anything about the fact that the RuleSet being used is associated with a particular namespace URI. That knowledge is emedded inside the RuleSet class itself.
    • If desired, you could make a set of rules work for more than one namespace URI by providing constructors on the RuleSet to allow this to be specified dynamically.
    • The MyRuleSet example above illustrates another technique that increases reusability -- you can specify (as an argument to the constructor) the leading portion of the matching pattern to be used. In this way, you can construct a Digester that recognizes the same set of nested elements at different nesting levels within an XML document.

    Using Named Stacks For Inter-Rule Communication

    Digester is based on Rule instances working together to process xml. For anything other than the most trival processing, communication between Rule instances is necessary. Since Rule instances are processed in sequence, this usually means storing an Object somewhere where later instances can retrieve it.

    Digester is based on SAX. The most natural data structure to use with SAX based xml processing is the stack. This allows more powerful processes to be specified more simply since the pushing and popping of objects can mimic the nested structure of the xml.

    Digester uses two basic stacks: one for the main beans and the other for parameters for method calls. These are inadequate for complex processing where many different Rule instances need to communicate through different channels.

    In this case, it is recommended that named stacks are used. In addition to the two basic stacks, Digester allows rules to use an unlimited number of other stacks referred two by an identifying string (the name). (That's where the term named stack comes from.) These stacks are accessed through calls to:

    Note: all stack names beginning with org.apache.commons.digester are reserved for future use by the Digester component. It is also recommended that users choose stack names perfixed by the name of their own domain to avoid conflicts with other Rule implementations.

    Registering DTDs

    Brief (But Still Too Long) Introduction To System and Public Identifiers

    A definition for an external entity comes in one of two forms:

    1. SYSTEM system-identifier
    2. PUBLIC public-identifier system-identifier

    The system-identifier is an URI from which the resource can be obtained (either directly or indirectly). Many valid URIs may identify the same resource. The public-identifier is an additional free identifier which may be used (by the parser) to locate the resource.

    In practice, the weakness with a system-identifier is that most parsers will attempt to interprete this URI as an URL, try to download the resource directly from the URL and stop the parsing if this download fails. So, this means that almost always the URI will have to be an URL from which the declaration can be downloaded.

    URLs may be local or remote but if the URL is chosen to be local, it is likely only to function correctly on a small number of machines (which are configured precisely to allow the xml to be parsed). This is usually unsatisfactory and so a universally accessable URL is preferred. This usually means an internet URL.

    To recap, in practice the system-identifier will (most likely) be an internet URL. Unfortunately downloading from an internet URL is not only slow but unreliable (since successfully downloading a document from the internet relies on the client being connect to the internet and the server being able to satisfy the request).

    The public-identifier is a freely defined name but (in practice) it is strongly recommended that a unique, readable and open format is used (for reasons that should become clear later). A Formal Public Identifier (FPI) is a very common choice. This public identifier is often used to provide a unique and location independent key which can be used to subsistute local resources for remote ones (hint: this is why ;).

    By using the second (PUBLIC) form combined with some form of local catalog (which matches public-identifiers to local resources) and where the public-identifier is a unique name and the system-identifier is an internet URL, the practical disadvantages of specifying just a system-identifier can be avoided. Those external entities which have been store locally (on the machine parsing the document) can be identified and used. Only when no local copy exists is it necessary to download the document from the internet URL. This naming scheme is recommended when using Digester.

    External Entity Resolution Using Digester

    SAX factors out the resolution of external entities into an EntityResolver. Digester supports the use of custom EntityResolver but ships with a simple internal implementation. This implementation allows local URLs to be easily associated with public-identifiers.

    For example:

        digester.register("-//Example Dot Com //DTD Sample Example//EN", "assets/sample.dtd");
    

    will make digester return the relative file path assets/sample.dtd whenever an external entity with public id -//Example Dot Com //DTD Sample Example//EN is needed.

    Note: This is a simple (but useful) implementation. Greater sophistication requires a custom EntityResolver.

    Troubleshooting

    Debugging Exceptions

    Digester is based on SAX. Digestion throws two kinds of Exception:

    • java.io.IOException
    • org.xml.sax.SAXException

    The first is rarely thrown and indicates the kind of fundemental IO exception that developers know all about. The second is thrown by SAX parsers when the processing of the XML cannot be completed. So, to diagnose the cause a certain familiarity with the way that SAX error handling works is very useful.

    Diagnosing SAX Exceptions

    This is a short, potted guide to SAX error handling strategies. It's not intended as a proper guide to error handling in SAX.

    When a SAX parser encounters a problem with the xml (well, ok - sometime after it encounters a problem) it will throw a SAXParseException. This is a subclass of SAXException and contains a bit of extra information about what exactly when wrong - and more importantly, where it went wrong. If you catch an exception of this sort, you can be sure that the problem is with the XML and not Digester or your rules. It is usually a good idea to catch this exception and log the extra information to help with diagnosing the reason for the failure.

    General SAXException instances may wrap a causal exception. When exceptions are throw by Digester each of these will be wrapped into a SAXException and rethrown. So, catch these and examine the wrapped exception to diagnose what went wrong.

    Frequently Asked Questions

    Known Limitations

    Accessing Public Methods In A Default Access Superclass

    There is an issue when invoking public methods contained in a default access superclass. Reflection locates these methods fine and correctly assigns them as public. However, an IllegalAccessException is thrown if the method is invoked.

    MethodUtils contains a workaround for this situation. It will attempt to call setAccessible on this method. If this call succeeds, then the method can be invoked as normal. This call will only succeed when the application has sufficient security privilages. If this call fails then a warning will be logged and the method may fail.

    Digester uses MethodUtils and so there may be an issue accessing methods of this kind from a high security environment. If you think that you might be experiencing this problem, please ask on the mailing list.

    tomcat7-7.0.52/java/org/apache/tomcat/util/digester/Digester.java0000644000175100017510000025121212271452077024571 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; import java.util.EmptyStackException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.IntrospectionUtils; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.ext.DefaultHandler2; import org.xml.sax.helpers.AttributesImpl; /** *

    A Digester processes an XML input stream by matching a * series of element nesting patterns to execute Rules that have been added * prior to the start of parsing. This package was inspired by the * XmlMapper class that was part of Tomcat 3.0 and 3.1, * but is organized somewhat differently.

    * *

    See the Digester * Developer Guide for more information.

    * *

    IMPLEMENTATION NOTE - A single Digester instance may * only be used within the context of a single thread at a time, and a call * to parse() must be completed before another can be initiated * even from the same thread.

    * *

    IMPLEMENTATION NOTE - A bug in Xerces 2.0.2 prevents * the support of XML schema. You need Xerces 2.1/2.3 and up to make * this class working with XML schema

    */ public class Digester extends DefaultHandler2 { // ---------------------------------------------------------- Static Fields private static class SystemPropertySource implements IntrospectionUtils.PropertySource { @Override public String getProperty( String key ) { return System.getProperty(key); } } protected static IntrospectionUtils.PropertySource source[] = new IntrospectionUtils.PropertySource[] { new SystemPropertySource() }; static { String className = System.getProperty("org.apache.tomcat.util.digester.PROPERTY_SOURCE"); if (className!=null) { IntrospectionUtils.PropertySource[] sources = new IntrospectionUtils.PropertySource[2]; sources[1] = source[0]; ClassLoader[] cls = new ClassLoader[] {Digester.class.getClassLoader(),Thread.currentThread().getContextClassLoader()}; boolean initialized = false; for (int i=0; i clazz = Class.forName(className,true,cls[i]); IntrospectionUtils.PropertySource src = (IntrospectionUtils.PropertySource)clazz.newInstance(); sources[0] = src; initialized = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); LogFactory.getLog("org.apache.tomcat.util.digester.Digester"). error("Unable to load property source["+className+"].",t); } } if (initialized) source = sources; } } // --------------------------------------------------------- Constructors /** * Construct a new Digester with default properties. */ public Digester() { super(); } /** * Construct a new Digester, allowing a SAXParser to be passed in. This * allows Digester to be used in environments which are unfriendly to * JAXP1.1 (such as WebLogic 6.0). Thanks for the request to change go to * James House (james@interobjective.com). This may help in places where * you are able to load JAXP 1.1 classes yourself. */ public Digester(SAXParser parser) { super(); this.parser = parser; } /** * Construct a new Digester, allowing an XMLReader to be passed in. This * allows Digester to be used in environments which are unfriendly to * JAXP1.1 (such as WebLogic 6.0). Note that if you use this option you * have to configure namespace and validation support yourself, as these * properties only affect the SAXParser and empty constructor. */ public Digester(XMLReader reader) { super(); this.reader = reader; } // --------------------------------------------------- Instance Variables /** * The body text of the current element. */ protected StringBuilder bodyText = new StringBuilder(); /** * The stack of body text string buffers for surrounding elements. */ protected ArrayStack bodyTexts = new ArrayStack(); /** * Stack whose elements are List objects, each containing a list of * Rule objects as returned from Rules.getMatch(). As each xml element * in the input is entered, the matching rules are pushed onto this * stack. After the end tag is reached, the matches are popped again. * The depth of is stack is therefore exactly the same as the current * "nesting" level of the input xml. * * @since 1.6 */ protected ArrayStack> matches = new ArrayStack>(10); /** * The class loader to use for instantiating application objects. * If not specified, the context class loader, or the class loader * used to load Digester itself, is used, based on the value of the * useContextClassLoader variable. */ protected ClassLoader classLoader = null; /** * Has this Digester been configured yet. */ protected boolean configured = false; /** * The EntityResolver used by the SAX parser. By default it use this class */ protected EntityResolver entityResolver; /** * The URLs of entityValidator that have been registered, keyed by the public * identifier that corresponds. */ protected HashMap entityValidator = new HashMap(); /** * The application-supplied error handler that is notified when parsing * warnings, errors, or fatal errors occur. */ protected ErrorHandler errorHandler = null; /** * The SAXParserFactory that is created the first time we need it. */ protected SAXParserFactory factory = null; /** * The Locator associated with our parser. */ protected Locator locator = null; /** * The current match pattern for nested element processing. */ protected String match = ""; /** * Do we want a "namespace aware" parser. */ protected boolean namespaceAware = false; /** * Registered namespaces we are currently processing. The key is the * namespace prefix that was declared in the document. The value is an * ArrayStack of the namespace URIs this prefix has been mapped to -- * the top Stack element is the most current one. (This architecture * is required because documents can declare nested uses of the same * prefix for different Namespace URIs). */ protected HashMap> namespaces = new HashMap>(); /** * The parameters stack being utilized by CallMethodRule and * CallParamRule rules. */ protected ArrayStack params = new ArrayStack(); /** * The SAXParser we will use to parse the input stream. */ protected SAXParser parser = null; /** * The public identifier of the DTD we are currently parsing under * (if any). */ protected String publicId = null; /** * The XMLReader used to parse digester rules. */ protected XMLReader reader = null; /** * The "root" element of the stack (in other words, the last object * that was popped. */ protected Object root = null; /** * The Rules implementation containing our collection of * Rule instances and associated matching policy. If not * established before the first rule is added, a default implementation * will be provided. */ protected Rules rules = null; /** * The object stack being constructed. */ protected ArrayStack stack = new ArrayStack(); /** * Do we want to use the Context ClassLoader when loading classes * for instantiating new objects. Default is false. */ protected boolean useContextClassLoader = false; /** * Do we want to use a validating parser. */ protected boolean validating = false; /** * Warn on missing attributes and elements. */ protected boolean rulesValidation = false; /** * Fake attributes map (attributes are often used for object creation). */ protected Map, List> fakeAttributes = null; /** * The Log to which most logging calls will be made. */ protected Log log = LogFactory.getLog("org.apache.tomcat.util.digester.Digester"); /** * The Log to which all SAX event related logging calls will be made. */ protected Log saxLog = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax"); /** Stacks used for interrule communication, indexed by name String */ private HashMap> stacksByName = new HashMap>(); // ------------------------------------------------------------- Properties /** * Return the currently mapped namespace URI for the specified prefix, * if any; otherwise return null. These mappings come and * go dynamically as the document is parsed. * * @param prefix Prefix to look up */ public String findNamespaceURI(String prefix) { ArrayStack stack = namespaces.get(prefix); if (stack == null) { return (null); } try { return stack.peek(); } catch (EmptyStackException e) { return (null); } } /** * Return the class loader to be used for instantiating application objects * when required. This is determined based upon the following rules: *
      *
    • The class loader set by setClassLoader(), if any
    • *
    • The thread context class loader, if it exists and the * useContextClassLoader property is set to true
    • *
    • The class loader used to load the Digester class itself. *
    */ public ClassLoader getClassLoader() { if (this.classLoader != null) { return (this.classLoader); } if (this.useContextClassLoader) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader != null) { return (classLoader); } } return (this.getClass().getClassLoader()); } /** * Set the class loader to be used for instantiating application objects * when required. * * @param classLoader The new class loader to use, or null * to revert to the standard rules */ public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } /** * Return the current depth of the element stack. */ public int getCount() { return (stack.size()); } /** * Return the name of the XML element that is currently being processed. */ public String getCurrentElementName() { String elementName = match; int lastSlash = elementName.lastIndexOf('/'); if (lastSlash >= 0) { elementName = elementName.substring(lastSlash + 1); } return (elementName); } /** * Return the error handler for this Digester. */ public ErrorHandler getErrorHandler() { return (this.errorHandler); } /** * Set the error handler for this Digester. * * @param errorHandler The new error handler */ public void setErrorHandler(ErrorHandler errorHandler) { this.errorHandler = errorHandler; } /** * Return the SAXParserFactory we will use, creating one if necessary. * @throws ParserConfigurationException * @throws SAXNotSupportedException * @throws SAXNotRecognizedException */ public SAXParserFactory getFactory() throws SAXNotRecognizedException, SAXNotSupportedException, ParserConfigurationException { if (factory == null) { factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(namespaceAware); // Preserve xmlns attributes if (namespaceAware) { factory.setFeature( "http://xml.org/sax/features/namespace-prefixes", true); } factory.setValidating(validating); if (validating) { // Enable DTD validation factory.setFeature( "http://xml.org/sax/features/validation", true); // Enable schema validation factory.setFeature( "http://apache.org/xml/features/validation/schema", true); } } return (factory); } /** * Returns a flag indicating whether the requested feature is supported * by the underlying implementation of org.xml.sax.XMLReader. * See * for information about the standard SAX2 feature flags. * * @param feature Name of the feature to inquire about * * @exception ParserConfigurationException if a parser configuration error * occurs * @exception SAXNotRecognizedException if the property name is * not recognized * @exception SAXNotSupportedException if the property name is * recognized but not supported */ public boolean getFeature(String feature) throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException { return (getFactory().getFeature(feature)); } /** * Sets a flag indicating whether the requested feature is supported * by the underlying implementation of org.xml.sax.XMLReader. * See * for information about the standard SAX2 feature flags. In order to be * effective, this method must be called before the * getParser() method is called for the first time, either * directly or indirectly. * * @param feature Name of the feature to set the status for * @param value The new value for this feature * * @exception ParserConfigurationException if a parser configuration error * occurs * @exception SAXNotRecognizedException if the property name is * not recognized * @exception SAXNotSupportedException if the property name is * recognized but not supported */ public void setFeature(String feature, boolean value) throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException { getFactory().setFeature(feature, value); } /** * Return the current Logger associated with this instance of the Digester */ public Log getLogger() { return log; } /** * Set the current logger for this Digester. */ public void setLogger(Log log) { this.log = log; } /** * Gets the logger used for logging SAX-related information. * Note the output is finely grained. * * @since 1.6 */ public Log getSAXLogger() { return saxLog; } /** * Sets the logger used for logging SAX-related information. * Note the output is finely grained. * @param saxLog Log, not null * * @since 1.6 */ public void setSAXLogger(Log saxLog) { this.saxLog = saxLog; } /** * Return the current rule match path */ public String getMatch() { return match; } /** * Return the "namespace aware" flag for parsers we create. */ public boolean getNamespaceAware() { return (this.namespaceAware); } /** * Set the "namespace aware" flag for parsers we create. * * @param namespaceAware The new "namespace aware" flag */ public void setNamespaceAware(boolean namespaceAware) { this.namespaceAware = namespaceAware; } /** * Set the public id of the current file being parse. * @param publicId the DTD/Schema public's id. */ public void setPublicId(String publicId){ this.publicId = publicId; } /** * Return the public identifier of the DTD we are currently * parsing under, if any. */ public String getPublicId() { return (this.publicId); } /** * Return the namespace URI that will be applied to all subsequently * added Rule objects. */ public String getRuleNamespaceURI() { return (getRules().getNamespaceURI()); } /** * Set the namespace URI that will be applied to all subsequently * added Rule objects. * * @param ruleNamespaceURI Namespace URI that must match on all * subsequently added rules, or null for matching * regardless of the current namespace URI */ public void setRuleNamespaceURI(String ruleNamespaceURI) { getRules().setNamespaceURI(ruleNamespaceURI); } /** * Return the SAXParser we will use to parse the input stream. If there * is a problem creating the parser, return null. */ public SAXParser getParser() { // Return the parser we already created (if any) if (parser != null) { return (parser); } // Create a new parser try { parser = getFactory().newSAXParser(); } catch (Exception e) { log.error("Digester.getParser: ", e); return (null); } return (parser); } /** * Return the current value of the specified property for the underlying * XMLReader implementation. * See * for information about the standard SAX2 properties. * * @param property Property name to be retrieved * * @exception SAXNotRecognizedException if the property name is * not recognized * @exception SAXNotSupportedException if the property name is * recognized but not supported */ public Object getProperty(String property) throws SAXNotRecognizedException, SAXNotSupportedException { return (getParser().getProperty(property)); } /** * Set the current value of the specified property for the underlying * XMLReader implementation. * See * for information about the standard SAX2 properties. * * @param property Property name to be set * @param value Property value to be set * * @exception SAXNotRecognizedException if the property name is * not recognized * @exception SAXNotSupportedException if the property name is * recognized but not supported */ public void setProperty(String property, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { getParser().setProperty(property, value); } /** * Return the Rules implementation object containing our * rules collection and associated matching policy. If none has been * established, a default implementation will be created and returned. */ public Rules getRules() { if (this.rules == null) { this.rules = new RulesBase(); this.rules.setDigester(this); } return (this.rules); } /** * Set the Rules implementation object containing our * rules collection and associated matching policy. * * @param rules New Rules implementation */ public void setRules(Rules rules) { this.rules = rules; this.rules.setDigester(this); } /** * Return the boolean as to whether the context classloader should be used. */ public boolean getUseContextClassLoader() { return useContextClassLoader; } /** * Determine whether to use the Context ClassLoader (the one found by * calling Thread.currentThread().getContextClassLoader()) * to resolve/load classes that are defined in various rules. If not * using Context ClassLoader, then the class-loading defaults to * using the calling-class' ClassLoader. * * @param use determines whether to use Context ClassLoader. */ public void setUseContextClassLoader(boolean use) { useContextClassLoader = use; } /** * Return the validating parser flag. */ public boolean getValidating() { return (this.validating); } /** * Set the validating parser flag. This must be called before * parse() is called the first time. * * @param validating The new validating parser flag. */ public void setValidating(boolean validating) { this.validating = validating; } /** * Return the rules validation flag. */ public boolean getRulesValidation() { return (this.rulesValidation); } /** * Set the rules validation flag. This must be called before * parse() is called the first time. * * @param rulesValidation The new rules validation flag. */ public void setRulesValidation(boolean rulesValidation) { this.rulesValidation = rulesValidation; } /** * Return the fake attributes list. */ public Map, List> getFakeAttributes() { return (this.fakeAttributes); } /** * Determine if an attribute is a fake attribute. */ public boolean isFakeAttribute(Object object, String name) { if (fakeAttributes == null) { return false; } List result = fakeAttributes.get(object.getClass()); if (result == null) { result = fakeAttributes.get(Object.class); } if (result == null) { return false; } else { return result.contains(name); } } /** * Set the fake attributes. * * @param fakeAttributes The new fake attributes. */ public void setFakeAttributes(Map, List> fakeAttributes) { this.fakeAttributes = fakeAttributes; } /** * Return the XMLReader to be used for parsing the input document. * * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a * parser that contains a schema with a DTD. * @exception SAXException if no XMLReader can be instantiated */ public XMLReader getXMLReader() throws SAXException { if (reader == null){ reader = getParser().getXMLReader(); } reader.setDTDHandler(this); reader.setContentHandler(this); if (entityResolver == null){ reader.setEntityResolver(this); } else { reader.setEntityResolver(entityResolver); } reader.setProperty( "http://xml.org/sax/properties/lexical-handler", this); reader.setErrorHandler(this); return reader; } // ------------------------------------------------- ContentHandler Methods /** * Process notification of character data received from the body of * an XML element. * * @param buffer The characters from the XML document * @param start Starting offset into the buffer * @param length Number of characters from the buffer * * @exception SAXException if a parsing error is to be reported */ @Override public void characters(char buffer[], int start, int length) throws SAXException { if (saxLog.isDebugEnabled()) { saxLog.debug("characters(" + new String(buffer, start, length) + ")"); } bodyText.append(buffer, start, length); } /** * Process notification of the end of the document being reached. * * @exception SAXException if a parsing error is to be reported */ @Override public void endDocument() throws SAXException { if (saxLog.isDebugEnabled()) { if (getCount() > 1) { saxLog.debug("endDocument(): " + getCount() + " elements left"); } else { saxLog.debug("endDocument()"); } } while (getCount() > 1) { pop(); } // Fire "finish" events for all defined rules Iterator rules = getRules().rules().iterator(); while (rules.hasNext()) { Rule rule = rules.next(); try { rule.finish(); } catch (Exception e) { log.error("Finish event threw exception", e); throw createSAXException(e); } catch (Error e) { log.error("Finish event threw error", e); throw e; } } // Perform final cleanup clear(); } /** * Process notification of the end of an XML element being reached. * * @param namespaceURI - The Namespace URI, or the empty string if the * element has no Namespace URI or if Namespace processing is not * being performed. * @param localName - The local name (without prefix), or the empty * string if Namespace processing is not being performed. * @param qName - The qualified XML 1.0 name (with prefix), or the * empty string if qualified names are not available. * @exception SAXException if a parsing error is to be reported */ @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { boolean debug = log.isDebugEnabled(); if (debug) { if (saxLog.isDebugEnabled()) { saxLog.debug("endElement(" + namespaceURI + "," + localName + "," + qName + ")"); } log.debug(" match='" + match + "'"); log.debug(" bodyText='" + bodyText + "'"); } // Parse system properties bodyText = updateBodyText(bodyText); // the actual element name is either in localName or qName, depending // on whether the parser is namespace aware String name = localName; if ((name == null) || (name.length() < 1)) { name = qName; } // Fire "body" events for all relevant rules List rules = matches.pop(); if ((rules != null) && (rules.size() > 0)) { String bodyText = this.bodyText.toString(); for (int i = 0; i < rules.size(); i++) { try { Rule rule = rules.get(i); if (debug) { log.debug(" Fire body() for " + rule); } rule.body(namespaceURI, name, bodyText); } catch (Exception e) { log.error("Body event threw exception", e); throw createSAXException(e); } catch (Error e) { log.error("Body event threw error", e); throw e; } } } else { if (debug) { log.debug(" No rules found matching '" + match + "'."); } if (rulesValidation) { log.warn(" No rules found matching '" + match + "'."); } } // Recover the body text from the surrounding element bodyText = bodyTexts.pop(); if (debug) { log.debug(" Popping body text '" + bodyText.toString() + "'"); } // Fire "end" events for all relevant rules in reverse order if (rules != null) { for (int i = 0; i < rules.size(); i++) { int j = (rules.size() - i) - 1; try { Rule rule = rules.get(j); if (debug) { log.debug(" Fire end() for " + rule); } rule.end(namespaceURI, name); } catch (Exception e) { log.error("End event threw exception", e); throw createSAXException(e); } catch (Error e) { log.error("End event threw error", e); throw e; } } } // Recover the previous match expression int slash = match.lastIndexOf('/'); if (slash >= 0) { match = match.substring(0, slash); } else { match = ""; } } /** * Process notification that a namespace prefix is going out of scope. * * @param prefix Prefix that is going out of scope * * @exception SAXException if a parsing error is to be reported */ @Override public void endPrefixMapping(String prefix) throws SAXException { if (saxLog.isDebugEnabled()) { saxLog.debug("endPrefixMapping(" + prefix + ")"); } // Deregister this prefix mapping ArrayStack stack = namespaces.get(prefix); if (stack == null) { return; } try { stack.pop(); if (stack.empty()) namespaces.remove(prefix); } catch (EmptyStackException e) { throw createSAXException("endPrefixMapping popped too many times"); } } /** * Process notification of ignorable whitespace received from the body of * an XML element. * * @param buffer The characters from the XML document * @param start Starting offset into the buffer * @param len Number of characters from the buffer * * @exception SAXException if a parsing error is to be reported */ @Override public void ignorableWhitespace(char buffer[], int start, int len) throws SAXException { if (saxLog.isDebugEnabled()) { saxLog.debug("ignorableWhitespace(" + new String(buffer, start, len) + ")"); } // No processing required } /** * Process notification of a processing instruction that was encountered. * * @param target The processing instruction target * @param data The processing instruction data (if any) * * @exception SAXException if a parsing error is to be reported */ @Override public void processingInstruction(String target, String data) throws SAXException { if (saxLog.isDebugEnabled()) { saxLog.debug("processingInstruction('" + target + "','" + data + "')"); } // No processing is required } /** * Gets the document locator associated with our parser. * * @return the Locator supplied by the document parser */ public Locator getDocumentLocator() { return locator; } /** * Sets the document locator associated with our parser. * * @param locator The new locator */ @Override public void setDocumentLocator(Locator locator) { if (saxLog.isDebugEnabled()) { saxLog.debug("setDocumentLocator(" + locator + ")"); } this.locator = locator; } /** * Process notification of a skipped entity. * * @param name Name of the skipped entity * * @exception SAXException if a parsing error is to be reported */ @Override public void skippedEntity(String name) throws SAXException { if (saxLog.isDebugEnabled()) { saxLog.debug("skippedEntity(" + name + ")"); } // No processing required } /** * Process notification of the beginning of the document being reached. * * @exception SAXException if a parsing error is to be reported */ @Override public void startDocument() throws SAXException { if (saxLog.isDebugEnabled()) { saxLog.debug("startDocument()"); } // ensure that the digester is properly configured, as // the digester could be used as a SAX ContentHandler // rather than via the parse() methods. configure(); } /** * Process notification of the start of an XML element being reached. * * @param namespaceURI The Namespace URI, or the empty string if the element * has no Namespace URI or if Namespace processing is not being performed. * @param localName The local name (without prefix), or the empty * string if Namespace processing is not being performed. * @param qName The qualified name (with prefix), or the empty * string if qualified names are not available.\ * @param list The attributes attached to the element. If there are * no attributes, it shall be an empty Attributes object. * @exception SAXException if a parsing error is to be reported */ @Override public void startElement(String namespaceURI, String localName, String qName, Attributes list) throws SAXException { boolean debug = log.isDebugEnabled(); if (saxLog.isDebugEnabled()) { saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + qName + ")"); } // Parse system properties list = updateAttributes(list); // Save the body text accumulated for our surrounding element bodyTexts.push(bodyText); if (debug) { log.debug(" Pushing body text '" + bodyText.toString() + "'"); } bodyText = new StringBuilder(); // the actual element name is either in localName or qName, depending // on whether the parser is namespace aware String name = localName; if ((name == null) || (name.length() < 1)) { name = qName; } // Compute the current matching rule StringBuilder sb = new StringBuilder(match); if (match.length() > 0) { sb.append('/'); } sb.append(name); match = sb.toString(); if (debug) { log.debug(" New match='" + match + "'"); } // Fire "begin" events for all relevant rules List rules = getRules().match(namespaceURI, match); matches.push(rules); if ((rules != null) && (rules.size() > 0)) { for (int i = 0; i < rules.size(); i++) { try { Rule rule = rules.get(i); if (debug) { log.debug(" Fire begin() for " + rule); } rule.begin(namespaceURI, name, list); } catch (Exception e) { log.error("Begin event threw exception", e); throw createSAXException(e); } catch (Error e) { log.error("Begin event threw error", e); throw e; } } } else { if (debug) { log.debug(" No rules found matching '" + match + "'."); } } } /** * Process notification that a namespace prefix is coming in to scope. * * @param prefix Prefix that is being declared * @param namespaceURI Corresponding namespace URI being mapped to * * @exception SAXException if a parsing error is to be reported */ @Override public void startPrefixMapping(String prefix, String namespaceURI) throws SAXException { if (saxLog.isDebugEnabled()) { saxLog.debug("startPrefixMapping(" + prefix + "," + namespaceURI + ")"); } // Register this prefix mapping ArrayStack stack = namespaces.get(prefix); if (stack == null) { stack = new ArrayStack(); namespaces.put(prefix, stack); } stack.push(namespaceURI); } // ----------------------------------------------------- DTDHandler Methods /** * Receive notification of a notation declaration event. * * @param name The notation name * @param publicId The public identifier (if any) * @param systemId The system identifier (if any) */ @Override public void notationDecl(String name, String publicId, String systemId) { if (saxLog.isDebugEnabled()) { saxLog.debug("notationDecl(" + name + "," + publicId + "," + systemId + ")"); } } /** * Receive notification of an unparsed entity declaration event. * * @param name The unparsed entity name * @param publicId The public identifier (if any) * @param systemId The system identifier (if any) * @param notation The name of the associated notation */ @Override public void unparsedEntityDecl(String name, String publicId, String systemId, String notation) { if (saxLog.isDebugEnabled()) { saxLog.debug("unparsedEntityDecl(" + name + "," + publicId + "," + systemId + "," + notation + ")"); } } // ----------------------------------------------- EntityResolver Methods /** * Set the EntityResolver used by SAX when resolving * public id and system id. * This must be called before the first call to parse(). * @param entityResolver a class that implement the EntityResolver interface. */ public void setEntityResolver(EntityResolver entityResolver){ this.entityResolver = entityResolver; } /** * Return the Entity Resolver used by the SAX parser. * @return Return the Entity Resolver used by the SAX parser. */ public EntityResolver getEntityResolver(){ return entityResolver; } @Override public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException { if (saxLog.isDebugEnabled()) { saxLog.debug("resolveEntity('" + publicId + "', '" + systemId + "', '" + baseURI + "')"); } // Has this system identifier been registered? String entityURL = null; if (publicId != null) { entityURL = entityValidator.get(publicId); } if (entityURL == null) { if (systemId == null) { // cannot resolve if (log.isDebugEnabled()) { log.debug(" Cannot resolve entity: '" + publicId + "'"); } return (null); } else { // try to resolve using system ID if (log.isDebugEnabled()) { log.debug(" Trying to resolve using system ID '" + systemId + "'"); } entityURL = systemId; // resolve systemId against baseURI if it is not absolute if (baseURI != null) { try { URI uri = new URI(systemId); if (!uri.isAbsolute()) { entityURL = new URI(baseURI).resolve(uri).toString(); } } catch (URISyntaxException e) { if (log.isDebugEnabled()) { log.debug("Invalid URI '" + baseURI + "' or '" + systemId + "'"); } } } } } // Return an input source to our alternative URL if (log.isDebugEnabled()) { log.debug(" Resolving to alternate DTD '" + entityURL + "'"); } try { return (new InputSource(entityURL)); } catch (Exception e) { throw createSAXException(e); } } // ----------------------------------------------- LexicalHandler Methods @Override public void startDTD(String name, String publicId, String systemId) throws SAXException { setPublicId(publicId); } // ------------------------------------------------- ErrorHandler Methods /** * Forward notification of a parsing error to the application supplied * error handler (if any). * * @param exception The error information * * @exception SAXException if a parsing exception occurs */ @Override public void error(SAXParseException exception) throws SAXException { log.error("Parse Error at line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + ": " + exception.getMessage(), exception); if (errorHandler != null) { errorHandler.error(exception); } } /** * Forward notification of a fatal parsing error to the application * supplied error handler (if any). * * @param exception The fatal error information * * @exception SAXException if a parsing exception occurs */ @Override public void fatalError(SAXParseException exception) throws SAXException { log.error("Parse Fatal Error at line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + ": " + exception.getMessage(), exception); if (errorHandler != null) { errorHandler.fatalError(exception); } } /** * Forward notification of a parse warning to the application supplied * error handler (if any). * * @param exception The warning information * * @exception SAXException if a parsing exception occurs */ @Override public void warning(SAXParseException exception) throws SAXException { if (errorHandler != null) { log.warn("Parse Warning Error at line " + exception.getLineNumber() + " column " + exception.getColumnNumber() + ": " + exception.getMessage(), exception); errorHandler.warning(exception); } } // ------------------------------------------------------- Public Methods /** * Parse the content of the specified file using this Digester. Returns * the root element from the object stack (if any). * * @param file File containing the XML data to be parsed * * @exception IOException if an input/output error occurs * @exception SAXException if a parsing exception occurs */ public Object parse(File file) throws IOException, SAXException { configure(); InputSource input = new InputSource(new FileInputStream(file)); input.setSystemId("file://" + file.getAbsolutePath()); getXMLReader().parse(input); return (root); } /** * Parse the content of the specified input source using this Digester. * Returns the root element from the object stack (if any). * * @param input Input source containing the XML data to be parsed * * @exception IOException if an input/output error occurs * @exception SAXException if a parsing exception occurs */ public Object parse(InputSource input) throws IOException, SAXException { configure(); getXMLReader().parse(input); return (root); } /** * Parse the content of the specified input stream using this Digester. * Returns the root element from the object stack (if any). * * @param input Input stream containing the XML data to be parsed * * @exception IOException if an input/output error occurs * @exception SAXException if a parsing exception occurs */ public Object parse(InputStream input) throws IOException, SAXException { configure(); InputSource is = new InputSource(input); getXMLReader().parse(is); return (root); } /** * Parse the content of the specified reader using this Digester. * Returns the root element from the object stack (if any). * * @param reader Reader containing the XML data to be parsed * * @exception IOException if an input/output error occurs * @exception SAXException if a parsing exception occurs */ public Object parse(Reader reader) throws IOException, SAXException { configure(); InputSource is = new InputSource(reader); getXMLReader().parse(is); return (root); } /** * Parse the content of the specified URI using this Digester. * Returns the root element from the object stack (if any). * * @param uri URI containing the XML data to be parsed * * @exception IOException if an input/output error occurs * @exception SAXException if a parsing exception occurs */ public Object parse(String uri) throws IOException, SAXException { configure(); InputSource is = new InputSource(uri); getXMLReader().parse(is); return (root); } /** *

    Register the specified DTD URL for the specified public identifier. * This must be called before the first call to parse(). *

    * Digester contains an internal EntityResolver * implementation. This maps PUBLICID's to URLs * (from which the resource will be loaded). A common use case for this * method is to register local URLs (possibly computed at runtime by a * classloader) for DTDs. This allows the performance advantage of using * a local version without having to ensure every SYSTEM * URI on every processed xml document is local. This implementation provides * only basic functionality. If more sophisticated features are required, * using {@link #setEntityResolver} to set a custom resolver is recommended. *

    * Note: This method will have no effect when a custom * EntityResolver has been set. (Setting a custom * EntityResolver overrides the internal implementation.) *

    * @param publicId Public identifier of the DTD to be resolved * @param entityURL The URL to use for reading this DTD */ public void register(String publicId, String entityURL) { if (log.isDebugEnabled()) { log.debug("register('" + publicId + "', '" + entityURL + "'"); } entityValidator.put(publicId, entityURL); } // --------------------------------------------------------- Rule Methods /** *

    Register a new Rule matching the specified pattern. * This method sets the Digester property on the rule.

    * * @param pattern Element matching pattern * @param rule Rule to be registered */ public void addRule(String pattern, Rule rule) { rule.setDigester(this); getRules().add(pattern, rule); } /** * Register a set of Rule instances defined in a RuleSet. * * @param ruleSet The RuleSet instance to configure from */ public void addRuleSet(RuleSet ruleSet) { String oldNamespaceURI = getRuleNamespaceURI(); String newNamespaceURI = ruleSet.getNamespaceURI(); if (log.isDebugEnabled()) { if (newNamespaceURI == null) { log.debug("addRuleSet() with no namespace URI"); } else { log.debug("addRuleSet() with namespace URI " + newNamespaceURI); } } setRuleNamespaceURI(newNamespaceURI); ruleSet.addRuleInstances(this); setRuleNamespaceURI(oldNamespaceURI); } /** * Add an "call method" rule for a method which accepts no arguments. * * @param pattern Element matching pattern * @param methodName Method name to be called * @see CallMethodRule */ public void addCallMethod(String pattern, String methodName) { addRule( pattern, new CallMethodRule(methodName)); } /** * Add an "call method" rule for the specified parameters. * * @param pattern Element matching pattern * @param methodName Method name to be called * @param paramCount Number of expected parameters (or zero * for a single parameter from the body of this element) * @see CallMethodRule */ public void addCallMethod(String pattern, String methodName, int paramCount) { addRule(pattern, new CallMethodRule(methodName, paramCount)); } /** * Add an "call method" rule for the specified parameters. * If paramCount is set to zero the rule will use * the body of the matched element as the single argument of the * method, unless paramTypes is null or empty, in this * case the rule will call the specified method with no arguments. * * @param pattern Element matching pattern * @param methodName Method name to be called * @param paramCount Number of expected parameters (or zero * for a single parameter from the body of this element) * @param paramTypes Set of Java class names for the types * of the expected parameters * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) * @see CallMethodRule */ public void addCallMethod(String pattern, String methodName, int paramCount, String paramTypes[]) { addRule(pattern, new CallMethodRule( methodName, paramCount, paramTypes)); } /** * Add an "call method" rule for the specified parameters. * If paramCount is set to zero the rule will use * the body of the matched element as the single argument of the * method, unless paramTypes is null or empty, in this * case the rule will call the specified method with no arguments. * * @param pattern Element matching pattern * @param methodName Method name to be called * @param paramCount Number of expected parameters (or zero * for a single parameter from the body of this element) * @param paramTypes The Java class names of the arguments * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) * @see CallMethodRule */ public void addCallMethod(String pattern, String methodName, int paramCount, Class paramTypes[]) { addRule(pattern, new CallMethodRule( methodName, paramCount, paramTypes)); } /** * Add a "call parameter" rule for the specified parameters. * * @param pattern Element matching pattern * @param paramIndex Zero-relative parameter index to set * (from the body of this element) * @see CallParamRule */ public void addCallParam(String pattern, int paramIndex) { addRule(pattern, new CallParamRule(paramIndex)); } /** * Add a "call parameter" rule for the specified parameters. * * @param pattern Element matching pattern * @param paramIndex Zero-relative parameter index to set * (from the specified attribute) * @param attributeName Attribute whose value is used as the * parameter value * @see CallParamRule */ public void addCallParam(String pattern, int paramIndex, String attributeName) { addRule(pattern, new CallParamRule(paramIndex, attributeName)); } /** * Add a "call parameter" rule. * This will either take a parameter from the stack * or from the current element body text. * * @param paramIndex The zero-relative parameter number * @param fromStack Should the call parameter be taken from the top of the stack? * @see CallParamRule */ public void addCallParam(String pattern, int paramIndex, boolean fromStack) { addRule(pattern, new CallParamRule(paramIndex, fromStack)); } /** * Add a "call parameter" rule that sets a parameter from the stack. * This takes a parameter from the given position on the stack. * * @param paramIndex The zero-relative parameter number * @param stackIndex set the call parameter to the stackIndex'th object down the stack, * where 0 is the top of the stack, 1 the next element down and so on * @see CallMethodRule */ public void addCallParam(String pattern, int paramIndex, int stackIndex) { addRule(pattern, new CallParamRule(paramIndex, stackIndex)); } /** * Add a "call parameter" rule that sets a parameter from the current * Digester matching path. * This is sometimes useful when using rules that support wildcards. * * @param pattern the pattern that this rule should match * @param paramIndex The zero-relative parameter number * @see CallMethodRule */ public void addCallParamPath(String pattern,int paramIndex) { addRule(pattern, new PathCallParamRule(paramIndex)); } /** * Add a "call parameter" rule that sets a parameter from a * caller-provided object. This can be used to pass constants such as * strings to methods; it can also be used to pass mutable objects, * providing ways for objects to do things like "register" themselves * with some shared object. *

    * Note that when attempting to locate a matching method to invoke, * the true type of the paramObj is used, so that despite the paramObj * being passed in here as type Object, the target method can declare * its parameters as being the true type of the object (or some ancestor * type, according to the usual type-conversion rules). * * @param paramIndex The zero-relative parameter number * @param paramObj Any arbitrary object to be passed to the target * method. * @see CallMethodRule * * @since 1.6 */ public void addObjectParam(String pattern, int paramIndex, Object paramObj) { addRule(pattern, new ObjectParamRule(paramIndex, paramObj)); } /** * Add a "factory create" rule for the specified parameters. * Exceptions thrown during the object creation process will be propagated. * * @param pattern Element matching pattern * @param className Java class name of the object creation factory class * @see FactoryCreateRule */ public void addFactoryCreate(String pattern, String className) { addFactoryCreate(pattern, className, false); } /** * Add a "factory create" rule for the specified parameters. * Exceptions thrown during the object creation process will be propagated. * * @param pattern Element matching pattern * @param clazz Java class of the object creation factory class * @see FactoryCreateRule */ public void addFactoryCreate(String pattern, Class clazz) { addFactoryCreate(pattern, clazz, false); } /** * Add a "factory create" rule for the specified parameters. * Exceptions thrown during the object creation process will be propagated. * * @param pattern Element matching pattern * @param className Java class name of the object creation factory class * @param attributeName Attribute name which, if present, overrides the * value specified by className * @see FactoryCreateRule */ public void addFactoryCreate(String pattern, String className, String attributeName) { addFactoryCreate(pattern, className, attributeName, false); } /** * Add a "factory create" rule for the specified parameters. * Exceptions thrown during the object creation process will be propagated. * * @param pattern Element matching pattern * @param clazz Java class of the object creation factory class * @param attributeName Attribute name which, if present, overrides the * value specified by className * @see FactoryCreateRule */ public void addFactoryCreate(String pattern, Class clazz, String attributeName) { addFactoryCreate(pattern, clazz, attributeName, false); } /** * Add a "factory create" rule for the specified parameters. * Exceptions thrown during the object creation process will be propagated. * * @param pattern Element matching pattern * @param creationFactory Previously instantiated ObjectCreationFactory * to be utilized * @see FactoryCreateRule */ public void addFactoryCreate(String pattern, ObjectCreationFactory creationFactory) { addFactoryCreate(pattern, creationFactory, false); } /** * Add a "factory create" rule for the specified parameters. * * @param pattern Element matching pattern * @param className Java class name of the object creation factory class * @param ignoreCreateExceptions when true any exceptions thrown during * object creation will be ignored. * @see FactoryCreateRule */ public void addFactoryCreate( String pattern, String className, boolean ignoreCreateExceptions) { addRule( pattern, new FactoryCreateRule(className, ignoreCreateExceptions)); } /** * Add a "factory create" rule for the specified parameters. * * @param pattern Element matching pattern * @param clazz Java class of the object creation factory class * @param ignoreCreateExceptions when true any exceptions thrown during * object creation will be ignored. * @see FactoryCreateRule */ public void addFactoryCreate( String pattern, Class clazz, boolean ignoreCreateExceptions) { addRule( pattern, new FactoryCreateRule(clazz, ignoreCreateExceptions)); } /** * Add a "factory create" rule for the specified parameters. * * @param pattern Element matching pattern * @param className Java class name of the object creation factory class * @param attributeName Attribute name which, if present, overrides the * value specified by className * @param ignoreCreateExceptions when true any exceptions thrown during * object creation will be ignored. * @see FactoryCreateRule */ public void addFactoryCreate( String pattern, String className, String attributeName, boolean ignoreCreateExceptions) { addRule( pattern, new FactoryCreateRule(className, attributeName, ignoreCreateExceptions)); } /** * Add a "factory create" rule for the specified parameters. * * @param pattern Element matching pattern * @param clazz Java class of the object creation factory class * @param attributeName Attribute name which, if present, overrides the * value specified by className * @param ignoreCreateExceptions when true any exceptions thrown during * object creation will be ignored. * @see FactoryCreateRule */ public void addFactoryCreate( String pattern, Class clazz, String attributeName, boolean ignoreCreateExceptions) { addRule( pattern, new FactoryCreateRule(clazz, attributeName, ignoreCreateExceptions)); } /** * Add a "factory create" rule for the specified parameters. * * @param pattern Element matching pattern * @param creationFactory Previously instantiated ObjectCreationFactory * to be utilized * @param ignoreCreateExceptions when true any exceptions thrown during * object creation will be ignored. * @see FactoryCreateRule */ public void addFactoryCreate(String pattern, ObjectCreationFactory creationFactory, boolean ignoreCreateExceptions) { creationFactory.setDigester(this); addRule(pattern, new FactoryCreateRule(creationFactory, ignoreCreateExceptions)); } /** * Add an "object create" rule for the specified parameters. * * @param pattern Element matching pattern * @param className Java class name to be created * @see ObjectCreateRule */ public void addObjectCreate(String pattern, String className) { addRule(pattern, new ObjectCreateRule(className)); } /** * Add an "object create" rule for the specified parameters. * * @param pattern Element matching pattern * @param clazz Java class to be created * @see ObjectCreateRule */ public void addObjectCreate(String pattern, Class clazz) { addRule(pattern, new ObjectCreateRule(clazz)); } /** * Add an "object create" rule for the specified parameters. * * @param pattern Element matching pattern * @param className Default Java class name to be created * @param attributeName Attribute name that optionally overrides * the default Java class name to be created * @see ObjectCreateRule */ public void addObjectCreate(String pattern, String className, String attributeName) { addRule(pattern, new ObjectCreateRule(className, attributeName)); } /** * Add an "object create" rule for the specified parameters. * * @param pattern Element matching pattern * @param attributeName Attribute name that optionally overrides * @param clazz Default Java class to be created * the default Java class name to be created * @see ObjectCreateRule */ public void addObjectCreate(String pattern, String attributeName, Class clazz) { addRule(pattern, new ObjectCreateRule(attributeName, clazz)); } /** * Add a "set next" rule for the specified parameters. * * @param pattern Element matching pattern * @param methodName Method name to call on the parent element * @see SetNextRule */ public void addSetNext(String pattern, String methodName) { addRule(pattern, new SetNextRule(methodName)); } /** * Add a "set next" rule for the specified parameters. * * @param pattern Element matching pattern * @param methodName Method name to call on the parent element * @param paramType Java class name of the expected parameter type * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) * @see SetNextRule */ public void addSetNext(String pattern, String methodName, String paramType) { addRule(pattern, new SetNextRule(methodName, paramType)); } /** * Add {@link SetRootRule} with the specified parameters. * * @param pattern Element matching pattern * @param methodName Method name to call on the root object * @see SetRootRule */ public void addSetRoot(String pattern, String methodName) { addRule(pattern, new SetRootRule(methodName)); } /** * Add {@link SetRootRule} with the specified parameters. * * @param pattern Element matching pattern * @param methodName Method name to call on the root object * @param paramType Java class name of the expected parameter type * @see SetRootRule */ public void addSetRoot(String pattern, String methodName, String paramType) { addRule(pattern, new SetRootRule(methodName, paramType)); } /** * Add a "set properties" rule for the specified parameters. * * @param pattern Element matching pattern * @see SetPropertiesRule */ public void addSetProperties(String pattern) { addRule(pattern, new SetPropertiesRule()); } /** * Add a "set properties" rule with a single overridden parameter. * See {@link SetPropertiesRule#SetPropertiesRule(String attributeName, String propertyName)} * * @param pattern Element matching pattern * @param attributeName map this attribute * @param propertyName to this property * @see SetPropertiesRule */ public void addSetProperties( String pattern, String attributeName, String propertyName) { addRule(pattern, new SetPropertiesRule(attributeName, propertyName)); } /** * Add a "set properties" rule with overridden parameters. * See {@link SetPropertiesRule#SetPropertiesRule(String [] attributeNames, String [] propertyNames)} * * @param pattern Element matching pattern * @param attributeNames names of attributes with custom mappings * @param propertyNames property names these attributes map to * @see SetPropertiesRule */ public void addSetProperties( String pattern, String [] attributeNames, String [] propertyNames) { addRule(pattern, new SetPropertiesRule(attributeNames, propertyNames)); } /** * Add a "set property" rule for the specified parameters. * * @param pattern Element matching pattern * @param name Attribute name containing the property name to be set * @param value Attribute name containing the property value to set * @see SetPropertyRule */ public void addSetProperty(String pattern, String name, String value) { addRule(pattern, new SetPropertyRule(name, value)); } /** * Add a "set top" rule for the specified parameters. * * @param pattern Element matching pattern * @param methodName Method name to call on the parent element * @see SetTopRule */ public void addSetTop(String pattern, String methodName) { addRule(pattern, new SetTopRule(methodName)); } /** * Add a "set top" rule for the specified parameters. * * @param pattern Element matching pattern * @param methodName Method name to call on the parent element * @param paramType Java class name of the expected parameter type * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) * @see SetTopRule */ public void addSetTop(String pattern, String methodName, String paramType) { addRule(pattern, new SetTopRule(methodName, paramType)); } // --------------------------------------------------- Object Stack Methods /** * Clear the current contents of the object stack. *

    * Calling this method might allow another document of the same type * to be correctly parsed. However this method was not intended for this * purpose. In general, a separate Digester object should be created for * each document to be parsed. */ public void clear() { match = ""; bodyTexts.clear(); params.clear(); publicId = null; stack.clear(); log = null; saxLog = null; configured = false; } public void reset() { root = null; setErrorHandler(null); clear(); } /** * Return the top object on the stack without removing it. If there are * no objects on the stack, return null. */ public Object peek() { try { return (stack.peek()); } catch (EmptyStackException e) { log.warn("Empty stack (returning null)"); return (null); } } /** * Return the n'th object down the stack, where 0 is the top element * and [getCount()-1] is the bottom element. If the specified index * is out of range, return null. * * @param n Index of the desired element, where 0 is the top of the stack, * 1 is the next element down, and so on. */ public Object peek(int n) { try { return (stack.peek(n)); } catch (EmptyStackException e) { log.warn("Empty stack (returning null)"); return (null); } } /** * Pop the top object off of the stack, and return it. If there are * no objects on the stack, return null. */ public Object pop() { try { return (stack.pop()); } catch (EmptyStackException e) { log.warn("Empty stack (returning null)"); return (null); } } /** * Push a new object onto the top of the object stack. * * @param object The new object */ public void push(Object object) { if (stack.size() == 0) { root = object; } stack.push(object); } /** * Pushes the given object onto the stack with the given name. * If no stack already exists with the given name then one will be created. * * @param stackName the name of the stack onto which the object should be pushed * @param value the Object to be pushed onto the named stack. * * @since 1.6 */ public void push(String stackName, Object value) { ArrayStack namedStack = stacksByName.get(stackName); if (namedStack == null) { namedStack = new ArrayStack(); stacksByName.put(stackName, namedStack); } namedStack.push(value); } /** *

    Pops (gets and removes) the top object from the stack with the given name.

    * *

    Note: a stack is considered empty * if no objects have been pushed onto it yet.

    * * @param stackName the name of the stack from which the top value is to be popped * @return the top Object on the stack or or null if the stack is either * empty or has not been created yet * @throws EmptyStackException if the named stack is empty * * @since 1.6 */ public Object pop(String stackName) { Object result = null; ArrayStack namedStack = stacksByName.get(stackName); if (namedStack == null) { if (log.isDebugEnabled()) { log.debug("Stack '" + stackName + "' is empty"); } throw new EmptyStackException(); } else { result = namedStack.pop(); } return result; } /** *

    Gets the top object from the stack with the given name. * This method does not remove the object from the stack. *

    *

    Note: a stack is considered empty * if no objects have been pushed onto it yet.

    * * @param stackName the name of the stack to be peeked * @return the top Object on the stack or null if the stack is either * empty or has not been created yet * @throws EmptyStackException if the named stack is empty * * @since 1.6 */ public Object peek(String stackName) { Object result = null; ArrayStack namedStack = stacksByName.get(stackName); if (namedStack == null ) { if (log.isDebugEnabled()) { log.debug("Stack '" + stackName + "' is empty"); } throw new EmptyStackException(); } else { result = namedStack.peek(); } return result; } /** *

    Is the stack with the given name empty?

    *

    Note: a stack is considered empty * if no objects have been pushed onto it yet.

    * @param stackName the name of the stack whose emptiness * should be evaluated * @return true if the given stack if empty * * @since 1.6 */ public boolean isEmpty(String stackName) { boolean result = true; ArrayStack namedStack = stacksByName.get(stackName); if (namedStack != null ) { result = namedStack.isEmpty(); } return result; } /** * When the Digester is being used as a SAXContentHandler, * this method allows you to access the root object that has been * created after parsing. * * @return the root object that has been created after parsing * or null if the digester has not parsed any XML yet. */ public Object getRoot() { return root; } // ------------------------------------------------ Parameter Stack Methods // ------------------------------------------------------ Protected Methods /** *

    * Provide a hook for lazy configuration of this Digester * instance. The default implementation does nothing, but subclasses * can override as needed. *

    * *

    * Note This method may be called more than once. * Once only initialization code should be placed in {@link #initialize} * or the code should take responsibility by checking and setting the * {@link #configured} flag. *

    */ protected void configure() { // Do not configure more than once if (configured) { return; } log = LogFactory.getLog("org.apache.tomcat.util.digester.Digester"); saxLog = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax"); // Perform lazy configuration as needed initialize(); // call hook method for subclasses that want to be initialized once only // Nothing else required by default // Set the configuration flag to avoid repeating configured = true; } /** *

    * Provides a hook for lazy initialization of this Digester * instance. * The default implementation does nothing, but subclasses * can override as needed. * Digester (by default) only calls this method once. *

    * *

    * Note This method will be called by {@link #configure} * only when the {@link #configured} flag is false. * Subclasses that override configure or who set configured * may find that this method may be called more than once. *

    * * @since 1.6 */ protected void initialize() { // Perform lazy initialization as needed // Nothing required by default } // -------------------------------------------------------- Package Methods /** * Return the set of DTD URL registrations, keyed by public identifier. */ Map getRegistrations() { return (entityValidator); } /** *

    Return the top object on the parameters stack without removing it. If there are * no objects on the stack, return null.

    * *

    The parameters stack is used to store CallMethodRule parameters. * See {@link #params}.

    */ public Object peekParams() { try { return (params.peek()); } catch (EmptyStackException e) { log.warn("Empty stack (returning null)"); return (null); } } /** *

    Return the n'th object down the parameters stack, where 0 is the top element * and [getCount()-1] is the bottom element. If the specified index * is out of range, return null.

    * *

    The parameters stack is used to store CallMethodRule parameters. * See {@link #params}.

    * * @param n Index of the desired element, where 0 is the top of the stack, * 1 is the next element down, and so on. */ public Object peekParams(int n) { try { return (params.peek(n)); } catch (EmptyStackException e) { log.warn("Empty stack (returning null)"); return (null); } } /** *

    Pop the top object off of the parameters stack, and return it. If there are * no objects on the stack, return null.

    * *

    The parameters stack is used to store CallMethodRule parameters. * See {@link #params}.

    */ public Object popParams() { try { if (log.isTraceEnabled()) { log.trace("Popping params"); } return (params.pop()); } catch (EmptyStackException e) { log.warn("Empty stack (returning null)"); return (null); } } /** *

    Push a new object onto the top of the parameters stack.

    * *

    The parameters stack is used to store CallMethodRule parameters. * See {@link #params}.

    * * @param object The new object */ public void pushParams(Object object) { if (log.isTraceEnabled()) { log.trace("Pushing params"); } params.push(object); } /** * Create a SAX exception which also understands about the location in * the digester file where the exception occurs * * @return the new exception */ public SAXException createSAXException(String message, Exception e) { if ((e != null) && (e instanceof InvocationTargetException)) { Throwable t = e.getCause(); if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } if (t instanceof Exception) { e = (Exception) t; } } if (locator != null) { String error = "Error at (" + locator.getLineNumber() + ", " + locator.getColumnNumber() + ") : " + message; if (e != null) { return new SAXParseException(error, locator, e); } else { return new SAXParseException(error, locator); } } log.error("No Locator!"); if (e != null) { return new SAXException(message, e); } else { return new SAXException(message); } } /** * Create a SAX exception which also understands about the location in * the digester file where the exception occurs * * @return the new exception */ public SAXException createSAXException(Exception e) { if (e instanceof InvocationTargetException) { Throwable t = e.getCause(); if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } if (t instanceof Exception) { e = (Exception) t; } } return createSAXException(e.getMessage(), e); } /** * Create a SAX exception which also understands about the location in * the digester file where the exception occurs * * @return the new exception */ public SAXException createSAXException(String message) { return createSAXException(message, null); } // ------------------------------------------------------- Private Methods /** * Returns an attributes list which contains all the attributes * passed in, with any text of form "${xxx}" in an attribute value * replaced by the appropriate value from the system property. */ private Attributes updateAttributes(Attributes list) { if (list.getLength() == 0) { return list; } AttributesImpl newAttrs = new AttributesImpl(list); int nAttributes = newAttrs.getLength(); for (int i = 0; i < nAttributes; ++i) { String value = newAttrs.getValue(i); try { String newValue = IntrospectionUtils.replaceProperties(value, null, source); if (value != newValue) { newAttrs.setValue(i, newValue); } } catch (Exception e) { // ignore - let the attribute have its original value } } return newAttrs; } /** * Return a new StringBuilder containing the same contents as the * input buffer, except that data of form ${varname} have been * replaced by the value of that var as defined in the system property. */ private StringBuilder updateBodyText(StringBuilder bodyText) { String in = bodyText.toString(); String out; try { out = IntrospectionUtils.replaceProperties(in, null, source); } catch(Exception e) { return bodyText; // return unchanged data } if (out == in) { // No substitutions required. Don't waste memory creating // a new buffer return bodyText; } else { return new StringBuilder(out); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java0000644000175100017510000000403312271452077027243 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.xml.sax.Attributes; /** *

    Interface for use with {@link FactoryCreateRule}. * The rule calls {@link #createObject} to create an object * to be pushed onto the Digester stack * whenever it is matched.

    * *

    {@link AbstractObjectCreationFactory} is an abstract * implementation suitable for creating anonymous * ObjectCreationFactory implementations. */ public interface ObjectCreationFactory { /** *

    Factory method called by {@link FactoryCreateRule} to supply an * object based on the element's attributes. * * @param attributes the element's attributes * * @throws Exception any exception thrown will be propagated upwards */ public Object createObject(Attributes attributes) throws Exception; /** *

    Returns the {@link Digester} that was set by the * {@link FactoryCreateRule} upon initialization. */ public Digester getDigester(); /** *

    Set the {@link Digester} to allow the implementation to do logging, * classloading based on the digester's classloader, etc. * * @param digester parent Digester object */ public void setDigester(Digester digester); } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/GenericParser.java0000644000175100017510000000600712271452077025554 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.util.Properties; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; /** * Create a SAXParser configured to support XML Schema and DTD. * * @since 1.6 */ public class GenericParser{ /** * The Log to which all SAX event related logging calls will be made. */ private static final Log log = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax"); /** * The JAXP 1.2 property required to set up the schema location. */ private static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; /** * The JAXP 1.2 property to set up the schemaLanguage used. */ protected static String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; /** * Create a SAXParser configured to support XML Schema and DTD * @param properties parser specific properties/features * @return an XML Schema/DTD enabled SAXParser */ public static SAXParser newSAXParser(Properties properties) throws ParserConfigurationException, SAXException, SAXNotRecognizedException{ SAXParserFactory factory = (SAXParserFactory)properties.get("SAXParserFactory"); SAXParser parser = factory.newSAXParser(); String schemaLocation = (String)properties.get("schemaLocation"); String schemaLanguage = (String)properties.get("schemaLanguage"); try{ if (schemaLocation != null) { parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); } } catch (SAXNotRecognizedException e){ log.info(parser.getClass().getName() + ": " + e.getMessage() + " not supported."); } return parser; } }tomcat7-7.0.52/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java0000644000175100017510000001266412271452077030010 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** *

    Rules Decorator that returns default rules * when no matches are returned by the wrapped implementation.

    * *

    This allows default Rule instances to be added to any * existing Rules implementation. These default Rule * instances will be returned for any match for which the wrapped * implementation does not return any matches.

    *

    For example, *

     *   Rule alpha;
     *   ...
     *   WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
     *   rules.addDefault(alpha);
     *   ...
     *   digester.setRules(rules);
     *   ...
     * 
    * when a pattern does not match any other rule, then rule alpha will be called. *

    *

    WithDefaultsRulesWrapper follows the Decorator pattern.

    * * @since 1.6 */ public class WithDefaultsRulesWrapper implements Rules { // --------------------------------------------------------- Fields /** The Rules implementation that this class wraps. */ private Rules wrappedRules; /** Rules to be fired when the wrapped implementations returns none. */ private List defaultRules = new ArrayList(); /** All rules (preserves order in which they were originally added) */ private List allRules = new ArrayList(); // --------------------------------------------------------- Constructor /** * Base constructor. * * @param wrappedRules the wrapped Rules implementation, not null * @throws IllegalArgumentException when wrappedRules is null */ public WithDefaultsRulesWrapper(Rules wrappedRules) { if (wrappedRules == null) { throw new IllegalArgumentException("Wrapped rules must not be null"); } this.wrappedRules = wrappedRules; } // --------------------------------------------------------- Properties /** Gets digester using these Rules */ @Override public Digester getDigester() { return wrappedRules.getDigester(); } /** Sets digester using these Rules */ @Override public void setDigester(Digester digester) { wrappedRules.setDigester(digester); Iterator it = defaultRules.iterator(); while (it.hasNext()) { Rule rule = it.next(); rule.setDigester(digester); } } /** Gets namespace to apply to Rule's added */ @Override public String getNamespaceURI() { return wrappedRules.getNamespaceURI(); } /** Sets namespace to apply to Rule's added subsequently */ @Override public void setNamespaceURI(String namespaceURI) { wrappedRules.setNamespaceURI(namespaceURI); } /** Gets Rule's which will be fired when the wrapped implementation returns no matches */ public List getDefaults() { return defaultRules; } // --------------------------------------------------------- Public Methods /** * Return list of rules matching given pattern. * If wrapped implementation returns any matches return those. * Otherwise, return default matches. */ @Override public List match(String namespaceURI, String pattern) { List matches = wrappedRules.match(namespaceURI, pattern); if (matches == null || matches.isEmpty()) { // a little bit of defensive programming return new ArrayList(defaultRules); } // otherwise return matches; } /** Adds a rule to be fired when wrapped implementation returns no matches */ public void addDefault(Rule rule) { // set up rule if (wrappedRules.getDigester() != null) { rule.setDigester(wrappedRules.getDigester()); } if (wrappedRules.getNamespaceURI() != null) { rule.setNamespaceURI(wrappedRules.getNamespaceURI()); } defaultRules.add(rule); allRules.add(rule); } /** Gets all rules */ @Override public List rules() { return allRules; } /** Clears all Rule's */ @Override public void clear() { wrappedRules.clear(); allRules.clear(); defaultRules.clear(); } /** * Adds a Rule to be fired on given pattern. * Pattern matching is delegated to wrapped implementation. */ @Override public void add(String pattern, Rule rule) { wrappedRules.add(pattern, rule); allRules.add(rule); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/ObjectParamRule.java0000644000175100017510000001011312271452077026033 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.xml.sax.Attributes; /** *

    Rule implementation that saves a parameter for use by a surrounding * CallMethodRule.

    * *

    This parameter may be: *

      *
    • an arbitrary Object defined programatically, assigned when the element pattern associated with the Rule is matched * See {@link #ObjectParamRule(int paramIndex, Object param)} *
    • an arbitrary Object defined programatically, assigned if the element pattern AND specified attribute name are matched * See {@link #ObjectParamRule(int paramIndex, String attributeName, Object param)} *
    *

    * * @since 1.4 */ public class ObjectParamRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "call parameter" rule that will save the given Object as * the parameter value. * * @param paramIndex The zero-relative parameter number * @param param the parameter to pass along */ public ObjectParamRule(int paramIndex, Object param) { this(paramIndex, null, param); } /** * Construct a "call parameter" rule that will save the given Object as * the parameter value, provided that the specified attribute exists. * * @param paramIndex The zero-relative parameter number * @param attributeName The name of the attribute to match * @param param the parameter to pass along */ public ObjectParamRule(int paramIndex, String attributeName, Object param) { this.paramIndex = paramIndex; this.attributeName = attributeName; this.param = param; } // ----------------------------------------------------- Instance Variables /** * The attribute which we are attempting to match */ protected String attributeName = null; /** * The zero-relative index of the parameter we are saving. */ protected int paramIndex = 0; /** * The parameter we wish to pass to the method call */ protected Object param = null; // --------------------------------------------------------- Public Methods /** * Process the start of this element. * * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { Object anAttribute = null; Object parameters[] = (Object[]) digester.peekParams(); if (attributeName != null) { anAttribute = attributes.getValue(attributeName); if(anAttribute != null) { parameters[paramIndex] = param; } // note -- if attributeName != null and anAttribute == null, this rule // will pass null as its parameter! }else{ parameters[paramIndex] = param; } } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ObjectParamRule["); sb.append("paramIndex="); sb.append(paramIndex); sb.append(", attributeName="); sb.append(attributeName); sb.append(", param="); sb.append(param); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/ArrayStack.java0000644000175100017510000001104512271452077025065 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import java.util.ArrayList; import java.util.EmptyStackException; /** *

    Imported copy of the ArrayStack class from * Commons Collections, which was the only direct dependency from Digester.

    * *

    WARNNG - This class is public solely to allow it to be * used from subpackages of org.apache.commons.digester. * It should not be considered part of the public API of Commons Digester. * If you want to use such a class yourself, you should use the one from * Commons Collections directly.

    * *

    An implementation of the {@link java.util.Stack} API that is based on an * ArrayList instead of a Vector, so it is not * synchronized to protect against multi-threaded access. The implementation * is therefore operates faster in environments where you do not need to * worry about multiple thread contention.

    * *

    Unlike Stack, ArrayStack accepts null entries. *

    * * @see java.util.Stack * @since Digester 1.6 (from Commons Collections 1.0) */ public class ArrayStack extends ArrayList { /** Ensure serialization compatibility */ private static final long serialVersionUID = 2130079159931574599L; /** * Constructs a new empty ArrayStack. The initial size * is controlled by ArrayList and is currently 10. */ public ArrayStack() { super(); } /** * Constructs a new empty ArrayStack with an initial size. * * @param initialSize the initial size to use * @throws IllegalArgumentException if the specified initial size * is negative */ public ArrayStack(int initialSize) { super(initialSize); } /** * Return true if this stack is currently empty. *

    * This method exists for compatibility with java.util.Stack. * New users of this class should use isEmpty instead. * * @return true if the stack is currently empty */ public boolean empty() { return isEmpty(); } /** * Returns the top item off of this stack without removing it. * * @return the top item on the stack * @throws EmptyStackException if the stack is empty */ public E peek() throws EmptyStackException { int n = size(); if (n <= 0) { throw new EmptyStackException(); } else { return get(n - 1); } } /** * Returns the n'th item down (zero-relative) from the top of this * stack without removing it. * * @param n the number of items down to go * @return the n'th item on the stack, zero relative * @throws EmptyStackException if there are not enough items on the * stack to satisfy this request */ public E peek(int n) throws EmptyStackException { int m = (size() - n) - 1; if (m < 0) { throw new EmptyStackException(); } else { return get(m); } } /** * Pops the top item off of this stack and return it. * * @return the top item on the stack * @throws EmptyStackException if the stack is empty */ public E pop() throws EmptyStackException { int n = size(); if (n <= 0) { throw new EmptyStackException(); } else { return remove(n - 1); } } /** * Pushes a new item onto the top of this stack. The pushed item is also * returned. This is equivalent to calling add. * * @param item the item to be added * @return the item just pushed */ public E push(E item) { add(item); return item; } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/RuleSetBase.java0000644000175100017510000000423412271452077025201 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; /** *

    Convenience base class that implements the {@link RuleSet} interface. * Concrete implementations should list all of their actual rule creation * logic in the addRuleSet() implementation.

    */ public abstract class RuleSetBase implements RuleSet { // ----------------------------------------------------- Instance Variables /** * The namespace URI that all Rule instances created by this RuleSet * will be associated with. */ protected String namespaceURI = null; // ------------------------------------------------------------- Properties /** * Return the namespace URI that will be applied to all Rule instances * created from this RuleSet. */ @Override public String getNamespaceURI() { return (this.namespaceURI); } // --------------------------------------------------------- Public Methods /** * Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance. * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public abstract void addRuleInstances(Digester digester); } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/FactoryCreateRule.java0000644000175100017510000003316512271452077026413 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.xml.sax.Attributes; /** *

    Rule implementation that uses an {@link ObjectCreationFactory} to create * a new object which it pushes onto the object stack. When the element is * complete, the object will be popped.

    * *

    This rule is intended in situations where the element's attributes are * needed before the object can be created. A common scenario is for the * ObjectCreationFactory implementation to use the attributes as parameters * in a call to either a factory method or to a non-empty constructor. */ public class FactoryCreateRule extends Rule { // ----------------------------------------------------------- Fields /** Should exceptions thrown by the factory be ignored? */ private boolean ignoreCreateExceptions; /** Stock to manage */ private ArrayStack exceptionIgnoredStack; // ----------------------------------------------------------- Constructors /** *

    Construct a factory create rule that will use the specified * class name to create an {@link ObjectCreationFactory} which will * then be used to create an object and push it on the stack.

    * *

    Exceptions thrown during the object creation process will be propagated.

    * * @param className Java class name of the object creation factory class */ public FactoryCreateRule(String className) { this(className, false); } /** *

    Construct a factory create rule that will use the specified * class to create an {@link ObjectCreationFactory} which will * then be used to create an object and push it on the stack.

    * *

    Exceptions thrown during the object creation process will be propagated.

    * * @param clazz Java class name of the object creation factory class */ public FactoryCreateRule(Class clazz) { this(clazz, false); } /** *

    Construct a factory create rule that will use the specified * class name (possibly overridden by the specified attribute if present) * to create an {@link ObjectCreationFactory}, which will then be used * to instantiate an object instance and push it onto the stack.

    * *

    Exceptions thrown during the object creation process will be propagated.

    * * @param className Default Java class name of the factory class * @param attributeName Attribute name which, if present, contains an * override of the class name of the object creation factory to create. */ public FactoryCreateRule(String className, String attributeName) { this(className, attributeName, false); } /** *

    Construct a factory create rule that will use the specified * class (possibly overridden by the specified attribute if present) * to create an {@link ObjectCreationFactory}, which will then be used * to instantiate an object instance and push it onto the stack.

    * *

    Exceptions thrown during the object creation process will be propagated.

    * * @param clazz Default Java class name of the factory class * @param attributeName Attribute name which, if present, contains an * override of the class name of the object creation factory to create. */ public FactoryCreateRule(Class clazz, String attributeName) { this(clazz, attributeName, false); } /** *

    Construct a factory create rule using the given, already instantiated, * {@link ObjectCreationFactory}.

    * *

    Exceptions thrown during the object creation process will be propagated.

    * * @param creationFactory called on to create the object. */ public FactoryCreateRule(ObjectCreationFactory creationFactory) { this(creationFactory, false); } /** * Construct a factory create rule that will use the specified * class name to create an {@link ObjectCreationFactory} which will * then be used to create an object and push it on the stack. * * @param className Java class name of the object creation factory class * @param ignoreCreateExceptions if true, exceptions thrown by the object * creation factory * will be ignored. */ public FactoryCreateRule(String className, boolean ignoreCreateExceptions) { this(className, null, ignoreCreateExceptions); } /** * Construct a factory create rule that will use the specified * class to create an {@link ObjectCreationFactory} which will * then be used to create an object and push it on the stack. * * @param clazz Java class name of the object creation factory class * @param ignoreCreateExceptions if true, exceptions thrown by the * object creation factory * will be ignored. */ public FactoryCreateRule(Class clazz, boolean ignoreCreateExceptions) { this(clazz, null, ignoreCreateExceptions); } /** * Construct a factory create rule that will use the specified * class name (possibly overridden by the specified attribute if present) * to create an {@link ObjectCreationFactory}, which will then be used * to instantiate an object instance and push it onto the stack. * * @param className Default Java class name of the factory class * @param attributeName Attribute name which, if present, contains an * override of the class name of the object creation factory to create. * @param ignoreCreateExceptions if true, exceptions thrown by the object * creation factory will be ignored. */ public FactoryCreateRule( String className, String attributeName, boolean ignoreCreateExceptions) { this.className = className; this.attributeName = attributeName; this.ignoreCreateExceptions = ignoreCreateExceptions; } /** * Construct a factory create rule that will use the specified * class (possibly overridden by the specified attribute if present) * to create an {@link ObjectCreationFactory}, which will then be used * to instantiate an object instance and push it onto the stack. * * @param clazz Default Java class name of the factory class * @param attributeName Attribute name which, if present, contains an * override of the class name of the object creation factory to create. * @param ignoreCreateExceptions if true, exceptions thrown by the object * creation factory will be ignored. */ public FactoryCreateRule( Class clazz, String attributeName, boolean ignoreCreateExceptions) { this(clazz.getName(), attributeName, ignoreCreateExceptions); } /** * Construct a factory create rule using the given, already instantiated, * {@link ObjectCreationFactory}. * * @param creationFactory called on to create the object. * @param ignoreCreateExceptions if true, exceptions thrown by the object * creation factory will be ignored. */ public FactoryCreateRule( ObjectCreationFactory creationFactory, boolean ignoreCreateExceptions) { this.creationFactory = creationFactory; this.ignoreCreateExceptions = ignoreCreateExceptions; } // ----------------------------------------------------- Instance Variables /** * The attribute containing an override class name if it is present. */ protected String attributeName = null; /** * The Java class name of the ObjectCreationFactory to be created. * This class must have a no-arguments constructor. */ protected String className = null; /** * The object creation factory we will use to instantiate objects * as required based on the attributes specified in the matched XML * element. */ protected ObjectCreationFactory creationFactory = null; // --------------------------------------------------------- Public Methods /** * Process the beginning of this element. * * @param attributes The attribute list of this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (ignoreCreateExceptions) { if (exceptionIgnoredStack == null) { exceptionIgnoredStack = new ArrayStack(); } try { Object instance = getFactory(attributes).createObject(attributes); if (digester.log.isDebugEnabled()) { digester.log.debug("[FactoryCreateRule]{" + digester.match + "} New " + instance.getClass().getName()); } digester.push(instance); exceptionIgnoredStack.push(Boolean.FALSE); } catch (Exception e) { // log message and error if (digester.log.isInfoEnabled()) { digester.log.info("[FactoryCreateRule] Create exception ignored: " + ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage())); if (digester.log.isDebugEnabled()) { digester.log.debug("[FactoryCreateRule] Ignored exception:", e); } } exceptionIgnoredStack.push(Boolean.TRUE); } } else { Object instance = getFactory(attributes).createObject(attributes); if (digester.log.isDebugEnabled()) { digester.log.debug("[FactoryCreateRule]{" + digester.match + "} New " + instance.getClass().getName()); } digester.push(instance); } } /** * Process the end of this element. */ @Override public void end(String namespace, String name) throws Exception { // check if object was created // this only happens if an exception was thrown and we're ignoring them if ( ignoreCreateExceptions && exceptionIgnoredStack != null && !(exceptionIgnoredStack.empty())) { if ((exceptionIgnoredStack.pop()).booleanValue()) { // creation exception was ignored // nothing was put onto the stack if (digester.log.isTraceEnabled()) { digester.log.trace("[FactoryCreateRule] No creation so no push so no pop"); } return; } } Object top = digester.pop(); if (digester.log.isDebugEnabled()) { digester.log.debug("[FactoryCreateRule]{" + digester.match + "} Pop " + top.getClass().getName()); } } /** * Clean up after parsing is complete. */ @Override public void finish() throws Exception { if (attributeName != null) { creationFactory = null; } } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("FactoryCreateRule["); sb.append("className="); sb.append(className); sb.append(", attributeName="); sb.append(attributeName); if (creationFactory != null) { sb.append(", creationFactory="); sb.append(creationFactory); } sb.append("]"); return (sb.toString()); } // ------------------------------------------------------ Protected Methods /** * Return an instance of our associated object creation factory, * creating one if necessary. * * @param attributes Attributes passed to our factory creation element * * @exception Exception if any error occurs */ protected ObjectCreationFactory getFactory(Attributes attributes) throws Exception { if (creationFactory == null) { String realClassName = className; if (attributeName != null) { String value = attributes.getValue(attributeName); if (value != null) { realClassName = value; } } if (digester.log.isDebugEnabled()) { digester.log.debug("[FactoryCreateRule]{" + digester.match + "} New factory " + realClassName); } Class clazz = digester.getClassLoader().loadClass(realClassName); creationFactory = (ObjectCreationFactory) clazz.newInstance(); creationFactory.setDigester(digester); } return (creationFactory); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/RuleSet.java0000644000175100017510000000463112271452077024407 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; /** *

    Public interface defining a shorthand means of configuring a complete * set of related Rule definitions, possibly associated with * a particular namespace URI, in one operation. To use an instance of a * class that implements this interface:

    *
      *
    • Create a concrete implementation of this interface.
    • *
    • Optionally, you can configure a RuleSet to be relevant * only for a particular namespace URI by configuring the value to be * returned by getNamespaceURI().
    • *
    • As you are configuring your Digester instance, call * digester.addRuleSet() and pass the RuleSet instance.
    • *
    • Digester will call the addRuleInstances() method of * your RuleSet to configure the necessary rules.
    • *
    */ public interface RuleSet { // ------------------------------------------------------------- Properties /** * Return the namespace URI that will be applied to all Rule instances * created from this RuleSet. */ public String getNamespaceURI(); // --------------------------------------------------------- Public Methods /** * Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance. * * @param digester Digester instance to which the new Rule instances * should be added. */ public void addRuleInstances(Digester digester); } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/PathCallParamRule.java0000644000175100017510000000554512271452077026332 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.xml.sax.Attributes; /** *

    Rule implementation that saves a parameter containing the * Digester matching path for use by a surrounding * CallMethodRule. This Rule is most useful when making * extensive use of wildcards in rule patterns.

    * * @since 1.6 */ public class PathCallParamRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "call parameter" rule that will save the body text of this * element as the parameter value. * * @param paramIndex The zero-relative parameter number */ public PathCallParamRule(int paramIndex) { this.paramIndex = paramIndex; } // ----------------------------------------------------- Instance Variables /** * The zero-relative index of the parameter we are saving. */ protected int paramIndex = 0; // --------------------------------------------------------- Public Methods /** * Process the start of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { String param = getDigester().getMatch(); if(param != null) { Object parameters[] = (Object[]) digester.peekParams(); parameters[paramIndex] = param; } } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("PathCallParamRule["); sb.append("paramIndex="); sb.append(paramIndex); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/SetPropertiesRule.java0000644000175100017510000002331112271452077026460 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.apache.tomcat.util.IntrospectionUtils; import org.xml.sax.Attributes; /** *

    Rule implementation that sets properties on the object at the top of the * stack, based on attributes with corresponding names.

    * *

    This rule supports custom mapping of attribute names to property names. * The default mapping for particular attributes can be overridden by using * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}. * This allows attributes to be mapped to properties with different names. * Certain attributes can also be marked to be ignored.

    */ public class SetPropertiesRule extends Rule { // ----------------------------------------------------------- Constructors /** * Default constructor sets only the the associated Digester. * * @param digester The digester with which this rule is associated * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetPropertiesRule()} instead. */ @Deprecated public SetPropertiesRule(Digester digester) { this(); } /** * Base constructor. */ public SetPropertiesRule() { // nothing to set up } /** *

    Convenience constructor overrides the mapping for just one property.

    * *

    For details about how this works, see * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}.

    * * @param attributeName map this attribute * @param propertyName to a property with this name */ public SetPropertiesRule(String attributeName, String propertyName) { attributeNames = new String[1]; attributeNames[0] = attributeName; propertyNames = new String[1]; propertyNames[0] = propertyName; } /** *

    Constructor allows attribute->property mapping to be overridden.

    * *

    Two arrays are passed in. * One contains the attribute names and the other the property names. * The attribute name / property name pairs are match by position * In order words, the first string in the attribute name list matches * to the first string in the property name list and so on.

    * *

    If a property name is null or the attribute name has no matching * property name, then this indicates that the attribute should be ignored.

    * *
    Example One
    *

    The following constructs a rule that maps the alt-city * attribute to the city property and the alt-state * to the state property. * All other attributes are mapped as usual using exact name matching. *

         *      SetPropertiesRule(
         *                new String[] {"alt-city", "alt-state"}, 
         *                new String[] {"city", "state"});
         * 
    * *
    Example Two
    *

    The following constructs a rule that maps the class * attribute to the className property. * The attribute ignore-me is not mapped. * All other attributes are mapped as usual using exact name matching. *

         *      SetPropertiesRule(
         *                new String[] {"class", "ignore-me"}, 
         *                new String[] {"className"});
         * 
    * * @param attributeNames names of attributes to map * @param propertyNames names of properties mapped to */ public SetPropertiesRule(String[] attributeNames, String[] propertyNames) { // create local copies this.attributeNames = new String[attributeNames.length]; for (int i=0, size=attributeNames.length; iproperty mapping */ private String [] attributeNames; /** * Property names used to override natural attribute->property mapping */ private String [] propertyNames; // --------------------------------------------------------- Public Methods /** * Process the beginning of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param theName the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String theName, Attributes attributes) throws Exception { // Populate the corresponding properties of the top object Object top = digester.peek(); if (digester.log.isDebugEnabled()) { if (top != null) { digester.log.debug("[SetPropertiesRule]{" + digester.match + "} Set " + top.getClass().getName() + " properties"); } else { digester.log.debug("[SetPropertiesRule]{" + digester.match + "} Set NULL properties"); } } // set up variables for custom names mappings int attNamesLength = 0; if (attributeNames != null) { attNamesLength = attributeNames.length; } int propNamesLength = 0; if (propertyNames != null) { propNamesLength = propertyNames.length; } for (int i = 0; i < attributes.getLength(); i++) { String name = attributes.getLocalName(i); if ("".equals(name)) { name = attributes.getQName(i); } String value = attributes.getValue(i); // we'll now check for custom mappings for (int n = 0; nAdd an additional attribute name to property name mapping. * This is intended to be used from the xml rules. */ public void addAlias(String attributeName, String propertyName) { // this is a bit tricky. // we'll need to resize the array. // probably should be synchronized but digester's not thread safe anyway if (attributeNames == null) { attributeNames = new String[1]; attributeNames[0] = attributeName; propertyNames = new String[1]; propertyNames[0] = propertyName; } else { int length = attributeNames.length; String [] tempAttributes = new String[length + 1]; for (int i=0; iRule implementation that saves a parameter for use by a surrounding * CallMethodRule.

    * *

    This parameter may be: *

      *
    • from an attribute of the current element * See {@link #CallParamRule(int paramIndex, String attributeName)} *
    • from current the element body * See {@link #CallParamRule(int paramIndex)} *
    • from the top object on the stack. * See {@link #CallParamRule(int paramIndex, boolean fromStack)} *
    • the current path being processed (separate Rule). * See {@link PathCallParamRule} *
    *

    */ public class CallParamRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "call parameter" rule that will save the body text of this * element as the parameter value. * * @param paramIndex The zero-relative parameter number */ public CallParamRule(int paramIndex) { this(paramIndex, null); } /** * Construct a "call parameter" rule that will save the value of the * specified attribute as the parameter value. * * @param paramIndex The zero-relative parameter number * @param attributeName The name of the attribute to save */ public CallParamRule(int paramIndex, String attributeName) { this.paramIndex = paramIndex; this.attributeName = attributeName; } /** * Construct a "call parameter" rule. * * @param paramIndex The zero-relative parameter number * @param fromStack should this parameter be taken from the top of the stack? */ public CallParamRule(int paramIndex, boolean fromStack) { this.paramIndex = paramIndex; this.fromStack = fromStack; } /** * Constructs a "call parameter" rule which sets a parameter from the stack. * If the stack contains too few objects, then the parameter will be set to null. * * @param paramIndex The zero-relative parameter number * @param stackIndex the index of the object which will be passed as a parameter. * The zeroth object is the top of the stack, 1 is the next object down and so on. */ public CallParamRule(int paramIndex, int stackIndex) { this.paramIndex = paramIndex; this.fromStack = true; this.stackIndex = stackIndex; } // ----------------------------------------------------- Instance Variables /** * The attribute from which to save the parameter value */ protected String attributeName = null; /** * The zero-relative index of the parameter we are saving. */ protected int paramIndex = 0; /** * Is the parameter to be set from the stack? */ protected boolean fromStack = false; /** * The position of the object from the top of the stack */ protected int stackIndex = 0; /** * Stack is used to allow nested body text to be processed. * Lazy creation. */ protected ArrayStack bodyTextStack; // --------------------------------------------------------- Public Methods /** * Process the start of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { Object param = null; if (attributeName != null) { param = attributes.getValue(attributeName); } else if(fromStack) { param = digester.peek(stackIndex); if (digester.log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("[CallParamRule]{"); sb.append(digester.match); sb.append("} Save from stack; from stack?").append(fromStack); sb.append("; object=").append(param); digester.log.debug(sb.toString()); } } // Have to save the param object to the param stack frame here. // Can't wait until end(). Otherwise, the object will be lost. // We can't save the object as instance variables, as // the instance variables will be overwritten // if this CallParamRule is reused in subsequent nesting. if(param != null) { Object parameters[] = (Object[]) digester.peekParams(); parameters[paramIndex] = param; } } /** * Process the body text of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param bodyText The body text of this element */ @Override public void body(String namespace, String name, String bodyText) throws Exception { if (attributeName == null && !fromStack) { // We must wait to set the parameter until end // so that we can make sure that the right set of parameters // is at the top of the stack if (bodyTextStack == null) { bodyTextStack = new ArrayStack(); } bodyTextStack.push(bodyText.trim()); } } /** * Process any body texts now. */ @Override public void end(String namespace, String name) { if (bodyTextStack != null && !bodyTextStack.empty()) { // what we do now is push one parameter onto the top set of parameters Object parameters[] = (Object[]) digester.peekParams(); parameters[paramIndex] = bodyTextStack.pop(); } } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("CallParamRule["); sb.append("paramIndex="); sb.append(paramIndex); sb.append(", attributeName="); sb.append(attributeName); sb.append(", from stack="); sb.append(fromStack); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/NodeCreateRule.java0000644000175100017510000003621712271452077025672 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; /** * A rule implementation that creates a DOM * {@link org.w3c.dom.Node Node} containing the XML at the element that matched * the rule. Two concrete types of nodes can be created by this rule: *
      *
    • the default is to create an {@link org.w3c.dom.Element Element} node. * The created element will correspond to the element that matched the rule, * containing all XML content underneath that element.
    • *
    • alternatively, this rule can create nodes of type * {@link org.w3c.dom.DocumentFragment DocumentFragment}, which will contain * only the XML content under the element the rule was triggered on.
    • *
    * The created node will be normalized, meaning it will not contain text nodes * that only contain white space characters. * * *

    The created Node will be pushed on Digester's object stack * when done. To use it in the context of another DOM * {@link org.w3c.dom.Document Document}, it must be imported first, using the * Document method * {@link org.w3c.dom.Document#importNode(org.w3c.dom.Node, boolean) importNode()}. *

    * *

    Important Note: This is implemented by replacing the SAX * {@link org.xml.sax.ContentHandler ContentHandler} in the parser used by * Digester, and resetting it when the matched element is closed. As a side * effect, rules that would match XML nodes under the element that matches * a NodeCreateRule will never be triggered by Digester, which * usually is the behavior one would expect.

    * *

    Note that the current implementation does not set the namespace prefixes * in the exported nodes. The (usually more important) namespace URIs are set, * of course.

    * * @since Digester 1.4 */ public class NodeCreateRule extends Rule { // ---------------------------------------------------------- Inner Classes /** * The SAX content handler that does all the actual work of assembling the * DOM node tree from the SAX events. */ private class NodeBuilder extends DefaultHandler { // ------------------------------------------------------- Constructors /** * Constructor. * *

    Stores the content handler currently used by Digester so it can * be reset when done, and initializes the DOM objects needed to * build the node.

    * * @param doc the document to use to create nodes * @param root the root node * @throws ParserConfigurationException if the DocumentBuilderFactory * could not be instantiated * @throws SAXException if the XMLReader could not be instantiated by * Digester (should not happen) */ public NodeBuilder(Document doc, Node root) throws ParserConfigurationException, SAXException { this.doc = doc; this.root = root; this.top = root; oldContentHandler = digester.getXMLReader().getContentHandler(); } // ------------------------------------------------- Instance Variables /** * The content handler used by Digester before it was set to this * content handler. */ protected ContentHandler oldContentHandler = null; /** * Depth of the current node, relative to the element where the content * handler was put into action. */ protected int depth = 0; /** * A DOM Document used to create the various Node instances. */ protected Document doc = null; /** * The DOM node that will be pushed on Digester's stack. */ protected Node root = null; /** * The current top DOM mode. */ protected Node top = null; // --------------------------------------------- ContentHandler Methods /** * Appends a {@link org.w3c.dom.Text Text} node to the current node. * * @param ch the characters from the XML document * @param start the start position in the array * @param length the number of characters to read from the array * @throws SAXException if the DOM implementation throws an exception */ @Override public void characters(char[] ch, int start, int length) throws SAXException { try { String str = new String(ch, start, length); if (str.trim().length() > 0) { top.appendChild(doc.createTextNode(str)); } } catch (DOMException e) { throw new SAXException(e.getMessage(), e); } } /** * Checks whether control needs to be returned to Digester. * * @param namespaceURI the namespace URI * @param localName the local name * @param qName the qualified (prefixed) name * @throws SAXException if the DOM implementation throws an exception */ @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { try { if (depth == 0) { getDigester().getXMLReader().setContentHandler( oldContentHandler); getDigester().push(root); getDigester().endElement(namespaceURI, localName, qName); } top = top.getParentNode(); depth--; } catch (DOMException e) { throw new SAXException(e.getMessage(), e); } } /** * Adds a new * {@link org.w3c.dom.ProcessingInstruction ProcessingInstruction} to * the current node. * * @param target the processing instruction target * @param data the processing instruction data, or null if none was * supplied * @throws SAXException if the DOM implementation throws an exception */ @Override public void processingInstruction(String target, String data) throws SAXException { try { top.appendChild(doc.createProcessingInstruction(target, data)); } catch (DOMException e) { throw new SAXException(e.getMessage(), e); } } /** * Adds a new child {@link org.w3c.dom.Element Element} to the current * node. * * @param namespaceURI the namespace URI * @param localName the local name * @param qName the qualified (prefixed) name * @param atts the list of attributes * @throws SAXException if the DOM implementation throws an exception */ @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { try { Node previousTop = top; if ((localName == null) || (localName.length() == 0)) { top = doc.createElement(qName); } else { top = doc.createElementNS(namespaceURI, localName); } for (int i = 0; i < atts.getLength(); i++) { Attr attr = null; if ((atts.getLocalName(i) == null) || (atts.getLocalName(i).length() == 0)) { attr = doc.createAttribute(atts.getQName(i)); attr.setNodeValue(atts.getValue(i)); ((Element)top).setAttributeNode(attr); } else { attr = doc.createAttributeNS(atts.getURI(i), atts.getLocalName(i)); attr.setNodeValue(atts.getValue(i)); ((Element)top).setAttributeNodeNS(attr); } } previousTop.appendChild(top); depth++; } catch (DOMException e) { throw new SAXException(e.getMessage(), e); } } } // ----------------------------------------------------------- Constructors /** * Default constructor. Creates an instance of this rule that will create a * DOM {@link org.w3c.dom.Element Element}. */ public NodeCreateRule() throws ParserConfigurationException { this(Node.ELEMENT_NODE); } /** * Constructor. Creates an instance of this rule that will create a DOM * {@link org.w3c.dom.Element Element}, but lets you specify the JAXP * DocumentBuilder that should be used when constructing the * node tree. * * @param documentBuilder the JAXP DocumentBuilder to use */ public NodeCreateRule(DocumentBuilder documentBuilder) { this(Node.ELEMENT_NODE, documentBuilder); } /** * Constructor. Creates an instance of this rule that will create either a * DOM {@link org.w3c.dom.Element Element} or a DOM * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the * value of the nodeType parameter. * * @param nodeType the type of node to create, which can be either * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} * @throws IllegalArgumentException if the node type is not supported */ public NodeCreateRule(int nodeType) throws ParserConfigurationException { this(nodeType, DocumentBuilderFactory.newInstance().newDocumentBuilder()); } /** * Constructor. Creates an instance of this rule that will create either a * DOM {@link org.w3c.dom.Element Element} or a DOM * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the * value of the nodeType parameter. This constructor lets you * specify the JAXP DocumentBuilder that should be used when * constructing the node tree. * * @param nodeType the type of node to create, which can be either * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} * @param documentBuilder the JAXP DocumentBuilder to use * @throws IllegalArgumentException if the node type is not supported */ public NodeCreateRule(int nodeType, DocumentBuilder documentBuilder) { if (!((nodeType == Node.DOCUMENT_FRAGMENT_NODE) || (nodeType == Node.ELEMENT_NODE))) { throw new IllegalArgumentException( "Can only create nodes of type DocumentFragment and Element"); } this.nodeType = nodeType; this.documentBuilder = documentBuilder; } // ----------------------------------------------------- Instance Variables /** * The JAXP DocumentBuilder to use. */ private DocumentBuilder documentBuilder = null; /** * The type of the node that should be created. Must be one of the * constants defined in {@link org.w3c.dom.Node Node}, but currently only * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} and * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} * are allowed values. */ private int nodeType = Node.ELEMENT_NODE; // ----------------------------------------------------------- Rule Methods /** * Implemented to replace the content handler currently in use by a * NodeBuilder. * * @param namespaceURI the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list of this element * @throws Exception indicates a JAXP configuration problem */ @Override public void begin(String namespaceURI, String name, Attributes attributes) throws Exception { XMLReader xmlReader = getDigester().getXMLReader(); Document doc = documentBuilder.newDocument(); NodeBuilder builder = null; if (nodeType == Node.ELEMENT_NODE) { Element element = null; if (getDigester().getNamespaceAware()) { element = doc.createElementNS(namespaceURI, name); for (int i = 0; i < attributes.getLength(); i++) { element.setAttributeNS(attributes.getURI(i), attributes.getLocalName(i), attributes.getValue(i)); } } else { element = doc.createElement(name); for (int i = 0; i < attributes.getLength(); i++) { element.setAttribute(attributes.getQName(i), attributes.getValue(i)); } } builder = new NodeBuilder(doc, element); } else { builder = new NodeBuilder(doc, doc.createDocumentFragment()); } xmlReader.setContentHandler(builder); } /** * Pop the Node off the top of the stack. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { digester.pop(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/digester/SetTopRule.java0000644000175100017510000001614512271452077025075 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.digester; import org.apache.tomcat.util.IntrospectionUtils; /** *

    Rule implementation that calls a "set parent" method on the top (child) * object, passing the (top-1) (parent) object as an argument.

    * *

    This rule now supports more flexible method matching by default. * It is possible that this may break (some) code * written against release 1.1.1 or earlier. * See {@link #isExactMatch()} for more details.

    */ public class SetTopRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "set parent" rule with the specified method name. The * "set parent" method's argument type is assumed to be the class of the * parent object. * * @param digester The associated Digester * @param methodName Method name of the "set parent" method to call * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetTopRule(String methodName)} instead. */ @Deprecated public SetTopRule(Digester digester, String methodName) { this(methodName); } /** * Construct a "set parent" rule with the specified method name. * * @param digester The associated Digester * @param methodName Method name of the "set parent" method to call * @param paramType Java class of the "set parent" method's argument * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) * * @deprecated The digester instance is now set in the {@link Digester#addRule} method. * Use {@link #SetTopRule(String methodName, String paramType)} instead. */ @Deprecated public SetTopRule(Digester digester, String methodName, String paramType) { this(methodName, paramType); } /** * Construct a "set parent" rule with the specified method name. The * "set parent" method's argument type is assumed to be the class of the * parent object. * * @param methodName Method name of the "set parent" method to call */ public SetTopRule(String methodName) { this(methodName, null); } /** * Construct a "set parent" rule with the specified method name. * * @param methodName Method name of the "set parent" method to call * @param paramType Java class of the "set parent" method's argument * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) */ public SetTopRule(String methodName, String paramType) { this.methodName = methodName; this.paramType = paramType; } // ----------------------------------------------------- Instance Variables /** * The method name to call on the child object. */ protected String methodName = null; /** * The Java class name of the parameter type expected by the method. */ protected String paramType = null; /** * Should we use exact matching. Default is no. */ protected boolean useExactMatch = false; // --------------------------------------------------------- Public Methods /** *

    Is exact matching being used.

    * *

    This rule uses org.apache.commons.beanutils.MethodUtils * to introspect the relevant objects so that the right method can be called. * Originally, MethodUtils.invokeExactMethod was used. * This matches methods very strictly * and so may not find a matching method when one exists. * This is still the behaviour when exact matching is enabled.

    * *

    When exact matching is disabled, MethodUtils.invokeMethod is used. * This method finds more methods but is less precise when there are several methods * with correct signatures. * So, if you want to choose an exact signature you might need to enable this property.

    * *

    The default setting is to disable exact matches.

    * * @return true iff exact matching is enabled * @since Digester Release 1.1.1 */ public boolean isExactMatch() { return useExactMatch; } /** *

    Set whether exact matching is enabled.

    * *

    See {@link #isExactMatch()}.

    * * @param useExactMatch should this rule use exact method matching * @since Digester Release 1.1.1 */ public void setExactMatch(boolean useExactMatch) { this.useExactMatch = useExactMatch; } /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { // Identify the objects to be used Object child = digester.peek(0); Object parent = digester.peek(1); if (digester.log.isDebugEnabled()) { if (child == null) { digester.log.debug("[SetTopRule]{" + digester.match + "} Call [NULL CHILD]." + methodName + "(" + parent + ")"); } else { digester.log.debug("[SetTopRule]{" + digester.match + "} Call " + child.getClass().getName() + "." + methodName + "(" + parent + ")"); } } // Call the specified method IntrospectionUtils.callMethod1(child, methodName, parent, paramType, digester.getClassLoader()); } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SetTopRule["); sb.append("methodName="); sb.append(methodName); sb.append(", paramType="); sb.append(paramType); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/0000755000175100017510000000000012301126366021126 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/net/res/0000755000175100017510000000000012301126366021717 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties0000644000175100017510000000632512271452644027145 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # net resources endpoint.err.fatal = Punto Final (Endpoint) {0} parado debido a excepci\u00F3n\: {1} endpoint.err.nonfatal = El Punto Final (Endpoint) {0} ignor\u00F3 excepci\u00F3n\: {1} endpoint.warn.reinit = Reinicializando ServerSocket endpoint.warn.restart = Rearrancando punto final (endpoint) endpoint.warn.security = Punto Final (Endpoint) {0} con excepci\u00F3n de seguridad\: {1} endpoint.err.socket = Error de conector causado por m\u00E1quina remota {0} endpoint.err.handshake = Acuerdo fallido endpoint.err.unexpected = Error inesperado al procesar conector endpoint.warn.nullSocket = Conector nulo devuelto por aceptaci\u00F3n endpoint.debug.unlock = Excepci\u00F3n cogida intentando desbloquear aceptaci\u00F3n en puerto {0} endpoint.err.close = Excepci\u00F3n cogida intentando cerrar conector endpoint.noProcessor = No hay procesadores - \u00A1hilo de trabajadir muerto\! endpoint.info.maxThreads = El m\u00E1ximo n\u00FAmero de hilos ({0}) creados para el conector con direcci\u00F3n {1} y puerto {2} endpoint.init.bind = Ligado de conector fall\u00F3\: [{0}] {1} endpoint.init.listen = Escucha de conector fall\u00F3\: [{0}] {1} endpoint.init.notavail = APR no disponible endpoint.accept.fail = Aceptaci\u00F3n de conector fall\u00F3 endpoint.launch.fail = No pude lanzar nuevo ejecutable endpoint.poll.limitedpollsize = No pude crear encuestador de medida espec\u00EDfica de {0} endpoint.poll.initfail = Fall\u00F3 la creaci\u00F3n del encuestador endpoint.poll.fail = Fallo cr\u00EDtico de encuestador (reiniciando encuestador)\: [{0}] {1} endpoint.poll.error = Error inesperado de encuestador endpoint.process.fail = Error reservando procesador de conector endpoint.sendfile.error = Error inesperado de env\u00EDo de fichero endpoint.sendfile.addfail = Fallo en Sednfile\: [{0}] {1} endpoint.sendfile.nosupport = Desactivando sendfile ya que o la versi\u00F3n APR o el sistema no lo soportan endpoint.warn.noInsecureReneg = La renegociaci\u00F3n segura no est\u00E1 soportada por la biblioteca SSL {0} endpoint.warn.unlockAcceptorFailed = El hilo aceptador [{0}] fall\u00F3 al desbloquear. Forzando apagado de enchufe (socket). endpoint.debug.channelCloseFail = No puede cerrar el canal endpoint.debug.socketCloseFail = No pude cerrar el enchufe (socket) endpoint.apr.noSslCertFile = El atribiuto del conector SSLCertificateFile debe de ser definido al usar SSL con APR endpoint.apr.invalidSslProtocol = Se ha proporcionado un valor inv\u00E1lido [{0}] para el atributo SSLProtocol tomcat7-7.0.52/java/org/apache/tomcat/util/net/res/LocalStrings.properties0000644000175100017510000000757412271452644026465 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # net resources endpoint.err.close=Caught exception trying to close socket endpoint.err.handshake=Handshake failed endpoint.err.unexpected=Unexpected error processing socket endpoint.warn.noExector=Failed to process socket [{0}] in state [{1}] because the executor had already been shutdown endpoint.warn.noDisableCompression='Disable compression' option is not supported by the SSL library {0} endpoint.warn.noHonorCipherOrder='Honor cipher order' option is not supported by the SSL library {0} endpoint.warn.noInsecureReneg=Secure re-negotiation is not supported by the SSL library {0} endpoint.warn.unlockAcceptorFailed=Acceptor thread [{0}] failed to unlock. Forcing hard socket shutdown. endpoint.warn.executorShutdown=The executor associated with thread pool [{0}] has not fully shutdown. Some application threads may still be running. endpoint.debug.channelCloseFail=Failed to close channel endpoint.debug.destroySocket=Destroying socket [{0}] endpoint.debug.pollerAdd=Add to addList socket [{0}], timeout [{1}], flags [{2}] endpoint.debug.pollerAddDo=Add to poller socket [{0}] endpoint.debug.pollerProcess=Processing socket [{0}] for event(s) [{1}] endpoint.debug.pollerRemove=Attempting to remove [{0}] from poller endpoint.debug.pollerRemoved=Removed [{0}] from poller endpoint.debug.socket=socket [{0}] endpoint.debug.socketCloseFail=Failed to close socket endpoint.debug.socketTimeout=Timing out [{0}] endpoint.debug.unlock=Caught exception trying to unlock accept on port {0} endpoint.err.close=Caught exception trying to close socket endpoint.init.bind=Socket bind failed: [{0}] {1} endpoint.init.listen=Socket listen failed: [{0}] {1} endpoint.init.notavail=APR not available endpoint.accept.fail=Socket accept failed endpoint.launch.fail=Failed to launch new runnable endpoint.poll.limitedpollsize=Failed to create poller with specified size of {0} endpoint.poll.initfail=Poller creation failed endpoint.poll.fail=Critical poller failure (restarting poller): [{0}] {1} endpoint.poll.error=Unexpected poller error endpoint.process.fail=Error allocating socket processor endpoint.sendfile.error=Unexpected sendfile error endpoint.sendfile.addfail=Sendfile failure: [{0}] {1} endpoint.timeout.err=Error processing socket timeout endpoint.apr.failSslContextMake=Unable to create SSLContext. Check that SSLEngine is enabled in the AprLifecycleListener, the AprLifecycleListener has initialised correctly and that a valid SSLProtocol has been specified endpoint.apr.invalidSslProtocol=An invalid value [{0}] was provided for the SSLProtocol attribute endpoint.apr.noSslCertFile=Connector attribute SSLCertificateFile must be defined when using SSL with APR endpoint.apr.pollAddInvalid=Invalid attempted to add a socket [{0}] to the poller endpoint.apr.pollError=Poller failed with error [{0}] : [{1}] endpoint.apr.pollUnknownEvent=A socket was returned from the poller with an unrecognized event [{0}] endpoint.apr.remoteport=APR socket [{0}] opened with remote port [{1}] endpoint.nio.selectorCloseFail=Failed to close selector when closing the poller endpoint.warn.noExector=Failed to process socket [{0}] in state [{1}] because the executor had already been shutdown tomcat7-7.0.52/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties0000644000175100017510000000263612271452644027131 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # net resources endpoint.err.fatal=\u4f8b\u5916\u306e\u305f\u3081\u306b\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3\u3057\u307e\u3059: {1} endpoint.err.nonfatal=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u4f8b\u5916\u3092\u7121\u8996\u3057\u307e\u3057\u305f: {1} endpoint.warn.reinit=ServerSocket\u3092\u518d\u521d\u671f\u5316\u3057\u307e\u3059 endpoint.warn.restart=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u518d\u8d77\u52d5\u3057\u307e\u3059 endpoint.warn.security=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u4f8b\u5916\u3067\u3059: {1} tomcat7-7.0.52/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties0000644000175100017510000000210712271452644027137 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # net resources endpoint.err.fatal=Le point de contact {0} a \u00e9t\u00e9 \u00e9teint suite \u00e0 l''exception{1} endpoint.err.nonfatal=Le point de contact {0} a ignor\u00e9 l''exception: {1} endpoint.warn.reinit=R\u00e9initialisation du ServerSocket endpoint.warn.restart=Red\u00e9marrage du point de contact tomcat7-7.0.52/java/org/apache/tomcat/util/net/NioChannel.java0000644000175100017510000001467512271452644024033 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import org.apache.tomcat.util.net.NioEndpoint.Poller; import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; /** * * Base class for a SocketChannel wrapper used by the endpoint. * This way, logic for a SSL socket channel remains the same as for * a non SSL, making sure we don't need to code for any exception cases. * * @author Filip Hanik * @version 1.0 */ public class NioChannel implements ByteChannel{ protected static ByteBuffer emptyBuf = ByteBuffer.allocate(0); protected SocketChannel sc = null; protected ApplicationBufferHandler bufHandler; protected Poller poller; protected boolean sendFile = false; public NioChannel(SocketChannel channel, ApplicationBufferHandler bufHandler) throws IOException { this.sc = channel; this.bufHandler = bufHandler; } public void reset() throws IOException { bufHandler.getReadBuffer().clear(); bufHandler.getWriteBuffer().clear(); this.sendFile = false; } public int getBufferSize() { if ( bufHandler == null ) return 0; int size = 0; size += bufHandler.getReadBuffer()!=null?bufHandler.getReadBuffer().capacity():0; size += bufHandler.getWriteBuffer()!=null?bufHandler.getWriteBuffer().capacity():0; return size; } /** * Returns true if the network buffer has been flushed out and is empty. * * @param block Unused. May be used when overridden * @param s Unused. May be used when overridden * @param timeout Unused. May be used when overridden * @return Always returns true since there is no network buffer * in the regular channel * @throws IOException */ public boolean flush(boolean block, Selector s, long timeout) throws IOException { return true; } /** * Closes this channel. * * @throws IOException If an I/O error occurs * TODO Implement this java.nio.channels.Channel method */ @Override public void close() throws IOException { getIOChannel().socket().close(); getIOChannel().close(); } public void close(boolean force) throws IOException { if (isOpen() || force ) close(); } /** * Tells whether or not this channel is open. * * @return true if, and only if, this channel is open * TODO Implement this java.nio.channels.Channel method */ @Override public boolean isOpen() { return sc.isOpen(); } /** * Writes a sequence of bytes to this channel from the given buffer. * * @param src The buffer from which bytes are to be retrieved * @return The number of bytes written, possibly zero * @throws IOException If some other I/O error occurs * TODO Implement this java.nio.channels.WritableByteChannel method */ @Override public int write(ByteBuffer src) throws IOException { return sc.write(src); } /** * Reads a sequence of bytes from this channel into the given buffer. * * @param dst The buffer into which bytes are to be transferred * @return The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream * @throws IOException If some other I/O error occurs * TODO Implement this java.nio.channels.ReadableByteChannel method */ @Override public int read(ByteBuffer dst) throws IOException { return sc.read(dst); } public Object getAttachment(boolean remove) { Poller pol = getPoller(); Selector sel = pol!=null?pol.getSelector():null; SelectionKey key = sel!=null?getIOChannel().keyFor(sel):null; Object att = key!=null?key.attachment():null; if (key != null && att != null && remove ) key.attach(null); return att; } /** * getBufHandler * * @return ApplicationBufferHandler * TODO Implement this org.apache.tomcat.util.net.SecureNioChannel method */ public ApplicationBufferHandler getBufHandler() { return bufHandler; } public Poller getPoller() { return poller; } /** * getIOChannel * * @return SocketChannel * TODO Implement this org.apache.tomcat.util.net.SecureNioChannel method */ public SocketChannel getIOChannel() { return sc; } /** * isClosing * * @return boolean * TODO Implement this org.apache.tomcat.util.net.SecureNioChannel method */ public boolean isClosing() { return false; } /** * isInitHandshakeComplete * * @return boolean */ public boolean isHandshakeComplete() { return true; } public int handshake(boolean read, boolean write) throws IOException { return 0; } public void setPoller(Poller poller) { this.poller = poller; } public void setIOChannel(SocketChannel IOChannel) { this.sc = IOChannel; } @Override public String toString() { return super.toString()+":"+this.sc.toString(); } public int getOutboundRemaining() { return 0; } /** * Return true if the buffer wrote data * @throws IOException */ public boolean flushOutbound() throws IOException { return false; } public boolean isSendFile() { return sendFile; } public void setSendFile(boolean s) { this.sendFile = s; } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/SSLSupport.java0000644000175100017510000001037512271452644024044 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.IOException; /** * Defines an interface to interact with SSL sessions. */ public interface SSLSupport { /** * The Request attribute key for the cipher suite. */ public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; /** * The Request attribute key for the key size. */ public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; /** * The Request attribute key for the client certificate chain. */ public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; /** * The Request attribute key for the session id. * This one is a Tomcat extension to the Servlet spec. */ public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session_id"; /** * The request attribute key for the session manager. * This one is a Tomcat extension to the Servlet spec. */ public static final String SESSION_MGR = "javax.servlet.request.ssl_session_mgr"; /** * A mapping table to determine the number of effective bits in the key * when using a cipher suite containing the specified cipher name. The * underlying data came from the TLS Specification (RFC 2246), Appendix C. */ static final CipherData ciphers[] = { new CipherData("_WITH_NULL_", 0), new CipherData("_WITH_IDEA_CBC_", 128), new CipherData("_WITH_RC2_CBC_40_", 40), new CipherData("_WITH_RC4_40_", 40), new CipherData("_WITH_RC4_128_", 128), new CipherData("_WITH_DES40_CBC_", 40), new CipherData("_WITH_DES_CBC_", 56), new CipherData("_WITH_3DES_EDE_CBC_", 168), new CipherData("_WITH_AES_128_CBC_", 128), new CipherData("_WITH_AES_256_CBC_", 256) }; /** * The cipher suite being used on this connection. */ public String getCipherSuite() throws IOException; /** * The client certificate chain (if any). */ public Object[] getPeerCertificateChain() throws IOException; /** * The client certificate chain (if any). * @param force If true, then re-negotiate the * connection if necessary. */ public Object[] getPeerCertificateChain(boolean force) throws IOException; /** * Get the keysize. * * What we're supposed to put here is ill-defined by the * Servlet spec (S 4.7 again). There are at least 4 potential * values that might go here: * * (a) The size of the encryption key * (b) The size of the MAC key * (c) The size of the key-exchange key * (d) The size of the signature key used by the server * * Unfortunately, all of these values are nonsensical. **/ public Integer getKeySize() throws IOException; /** * The current session Id. */ public String getSessionId() throws IOException; /** * Simple data class that represents the cipher being used, along with the * corresponding effective key size. The specified phrase must appear in the * name of the cipher suite to be recognized. */ final class CipherData { public String phrase = null; public int keySize = 0; public CipherData(String phrase, int keySize) { this.phrase = phrase; this.keySize = keySize; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/SSLSessionManager.java0000644000175100017510000000207412271452644025303 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; /** * Defines an interface used to manage SSL sessions. The manager operates on a * single session. */ public interface SSLSessionManager { /** * Invalidate the SSL session */ public void invalidateSession(); } tomcat7-7.0.52/java/org/apache/tomcat/util/net/NioBlockingSelector.java0000644000175100017510000004135112271452644025703 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.EOFException; import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; public class NioBlockingSelector { private static final Log log = LogFactory.getLog(NioBlockingSelector.class); private static int threadCounter = 0; protected Selector sharedSelector; protected BlockPoller poller; public NioBlockingSelector() { } public void open(Selector selector) { sharedSelector = selector; poller = new BlockPoller(); poller.selector = sharedSelector; poller.setDaemon(true); poller.setName("NioBlockingSelector.BlockPoller-"+(++threadCounter)); poller.start(); } public void close() { if (poller!=null) { poller.disable(); poller.interrupt(); poller = null; } } /** * Performs a blocking write using the bytebuffer for data to be written * If the selector parameter is null, then it will perform a busy write that could * take up a lot of CPU cycles. * @param buf ByteBuffer - the buffer containing the data, we will write as long as (buf.hasRemaining()==true) * @param socket SocketChannel - the socket to write data to * @param writeTimeout long - the timeout for this write operation in milliseconds, -1 means no timeout * @return int - returns the number of bytes written * @throws EOFException if write returns -1 * @throws SocketTimeoutException if the write times out * @throws IOException if an IO Exception occurs in the underlying socket logic */ public int write(ByteBuffer buf, NioChannel socket, long writeTimeout) throws IOException { SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector()); if ( key == null ) throw new IOException("Key no longer registered"); KeyReference reference = new KeyReference(); KeyAttachment att = (KeyAttachment) key.attachment(); int written = 0; boolean timedout = false; int keycount = 1; //assume we can write long time = System.currentTimeMillis(); //start the timeout timer try { while ( (!timedout) && buf.hasRemaining()) { if (keycount > 0) { //only write if we were registered for a write int cnt = socket.write(buf); //write the data if (cnt == -1) throw new EOFException(); written += cnt; if (cnt > 0) { time = System.currentTimeMillis(); //reset our timeout timer continue; //we successfully wrote, try again without a selector } } try { if ( att.getWriteLatch()==null || att.getWriteLatch().getCount()==0) att.startWriteLatch(1); poller.add(att,SelectionKey.OP_WRITE,reference); if (writeTimeout < 0) { att.awaitWriteLatch(Long.MAX_VALUE,TimeUnit.MILLISECONDS); } else { att.awaitWriteLatch(writeTimeout,TimeUnit.MILLISECONDS); } }catch (InterruptedException ignore) { Thread.interrupted(); } if ( att.getWriteLatch()!=null && att.getWriteLatch().getCount()> 0) { //we got interrupted, but we haven't received notification from the poller. keycount = 0; }else { //latch countdown has happened keycount = 1; att.resetWriteLatch(); } if (writeTimeout > 0 && (keycount == 0)) timedout = (System.currentTimeMillis() - time) >= writeTimeout; } //while if (timedout) throw new SocketTimeoutException(); } finally { poller.remove(att,SelectionKey.OP_WRITE); if (timedout && reference.key!=null) { poller.cancelKey(reference.key); } reference.key = null; } return written; } /** * Performs a blocking read using the bytebuffer for data to be read * If the selector parameter is null, then it will perform a busy read that could * take up a lot of CPU cycles. * @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out * @param socket SocketChannel - the socket to write data to * @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout * @return int - returns the number of bytes read * @throws EOFException if read returns -1 * @throws SocketTimeoutException if the read times out * @throws IOException if an IO Exception occurs in the underlying socket logic */ public int read(ByteBuffer buf, NioChannel socket, long readTimeout) throws IOException { SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector()); if ( key == null ) throw new IOException("Key no longer registered"); KeyReference reference = new KeyReference(); KeyAttachment att = (KeyAttachment) key.attachment(); int read = 0; boolean timedout = false; int keycount = 1; //assume we can read long time = System.currentTimeMillis(); //start the timeout timer try { while(!timedout) { if (keycount > 0) { //only read if we were registered for a read read = socket.read(buf); if (read == -1) throw new EOFException(); if (read > 0) break; } try { if ( att.getReadLatch()==null || att.getReadLatch().getCount()==0) att.startReadLatch(1); poller.add(att,SelectionKey.OP_READ, reference); if (readTimeout < 0) { att.awaitReadLatch(Long.MAX_VALUE, TimeUnit.MILLISECONDS); } else { att.awaitReadLatch(readTimeout, TimeUnit.MILLISECONDS); } }catch (InterruptedException ignore) { Thread.interrupted(); } if ( att.getReadLatch()!=null && att.getReadLatch().getCount()> 0) { //we got interrupted, but we haven't received notification from the poller. keycount = 0; }else { //latch countdown has happened keycount = 1; att.resetReadLatch(); } if (readTimeout >= 0 && (keycount == 0)) timedout = (System.currentTimeMillis() - time) >= readTimeout; } //while if (timedout) throw new SocketTimeoutException(); } finally { poller.remove(att,SelectionKey.OP_READ); if (timedout && reference.key!=null) { poller.cancelKey(reference.key); } reference.key = null; } return read; } protected static class BlockPoller extends Thread { protected volatile boolean run = true; protected Selector selector = null; protected ConcurrentLinkedQueue events = new ConcurrentLinkedQueue(); public void disable() { run = false; selector.wakeup();} protected AtomicInteger wakeupCounter = new AtomicInteger(0); public void cancelKey(final SelectionKey key) { Runnable r = new Runnable() { @Override public void run() { key.cancel(); } }; events.offer(r); wakeup(); } public void wakeup() { if (wakeupCounter.addAndGet(1)==0) selector.wakeup(); } public void cancel(SelectionKey sk, KeyAttachment key, int ops){ if (sk!=null) { sk.cancel(); sk.attach(null); if (SelectionKey.OP_WRITE==(ops&SelectionKey.OP_WRITE)) countDown(key.getWriteLatch()); if (SelectionKey.OP_READ==(ops&SelectionKey.OP_READ))countDown(key.getReadLatch()); } } public void add(final KeyAttachment key, final int ops, final KeyReference ref) { Runnable r = new Runnable() { @Override public void run() { if ( key == null ) return; NioChannel nch = key.getChannel(); if ( nch == null ) return; SocketChannel ch = nch.getIOChannel(); if ( ch == null ) return; SelectionKey sk = ch.keyFor(selector); try { if (sk == null) { sk = ch.register(selector, ops, key); ref.key = sk; } else if (!sk.isValid()) { cancel(sk,key,ops); } else { sk.interestOps(sk.interestOps() | ops); } }catch (CancelledKeyException cx) { cancel(sk,key,ops); }catch (ClosedChannelException cx) { cancel(sk,key,ops); } } }; events.offer(r); wakeup(); } public void remove(final KeyAttachment key, final int ops) { Runnable r = new Runnable() { @Override public void run() { if ( key == null ) return; NioChannel nch = key.getChannel(); if ( nch == null ) return; SocketChannel ch = nch.getIOChannel(); if ( ch == null ) return; SelectionKey sk = ch.keyFor(selector); try { if (sk == null) { if (SelectionKey.OP_WRITE==(ops&SelectionKey.OP_WRITE)) countDown(key.getWriteLatch()); if (SelectionKey.OP_READ==(ops&SelectionKey.OP_READ))countDown(key.getReadLatch()); } else { if (sk.isValid()) { sk.interestOps(sk.interestOps() & (~ops)); if (SelectionKey.OP_WRITE==(ops&SelectionKey.OP_WRITE)) countDown(key.getWriteLatch()); if (SelectionKey.OP_READ==(ops&SelectionKey.OP_READ))countDown(key.getReadLatch()); if (sk.interestOps()==0) { sk.cancel(); sk.attach(null); } }else { sk.cancel(); sk.attach(null); } } }catch (CancelledKeyException cx) { if (sk!=null) { sk.cancel(); sk.attach(null); } } } }; events.offer(r); wakeup(); } public boolean events() { boolean result = false; Runnable r = null; result = (events.size() > 0); while ( (r = events.poll()) != null ) { r.run(); result = true; } return result; } @Override public void run() { while (run) { try { events(); int keyCount = 0; try { int i = wakeupCounter.get(); if (i>0) keyCount = selector.selectNow(); else { wakeupCounter.set(-1); keyCount = selector.select(1000); } wakeupCounter.set(0); if (!run) break; }catch ( NullPointerException x ) { //sun bug 5076772 on windows JDK 1.5 if (selector==null) throw x; if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x); continue; } catch ( CancelledKeyException x ) { //sun bug 5076772 on windows JDK 1.5 if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x); continue; } catch (Throwable x) { ExceptionUtils.handleThrowable(x); log.error("",x); continue; } Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; // Walk through the collection of ready keys and dispatch // any active event. while (run && iterator != null && iterator.hasNext()) { SelectionKey sk = iterator.next(); KeyAttachment attachment = (KeyAttachment)sk.attachment(); try { attachment.access(); iterator.remove(); sk.interestOps(sk.interestOps() & (~sk.readyOps())); if ( sk.isReadable() ) { countDown(attachment.getReadLatch()); } if (sk.isWritable()) { countDown(attachment.getWriteLatch()); } }catch (CancelledKeyException ckx) { sk.cancel(); countDown(attachment.getReadLatch()); countDown(attachment.getWriteLatch()); } }//while }catch ( Throwable t ) { log.error("",t); } } events.clear(); try { selector.selectNow();//cancel all remaining keys }catch( Exception ignore ) { if (log.isDebugEnabled())log.debug("",ignore); } try { selector.close();//Close the connector }catch( Exception ignore ) { if (log.isDebugEnabled())log.debug("",ignore); } } public void countDown(CountDownLatch latch) { if ( latch == null ) return; latch.countDown(); } } public static class KeyReference { SelectionKey key = null; @Override public void finalize() { if (key!=null && key.isValid()) { log.warn("Possible key leak, cancelling key in the finalizer."); try {key.cancel();}catch (Exception ignore){} } key = null; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/0000755000175100017510000000000012301126366022072 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/res/0000755000175100017510000000000012301126366022663 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties0000644000175100017510000000264312271452644030110 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. jsse.alias_no_key_entry = El nombre de Alias {0} no identifica una entrada de clave jsse.keystore_load_failed = No pude cargar almac\u00E9n de claves de tipo {0} con ruta {1} debido a {2} jsse.invalid_ssl_conf = La configuraci\u00F3n SSL no es v\u00E1lida debido a {0} jsse.invalid_truststore_password = La clave del almac\u00E9n de confianza suministrada no se pudo usar para desbloquear y/o validar el almac\u00E9n de confianza. Reintentando acceder el almac\u00E9n de confianza con una clave nula que se saltar\u00E1 la validaci\u00F3n. jsse.invalidTrustManagerClassName = El trustManagerClassName suministrado [{0}] no implementa javax.net.ssl.TrustManager tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties0000644000175100017510000000437112271452644027421 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. jsse.alias_no_key_entry=Alias name {0} does not identify a key entry jsse.keystore_load_failed=Failed to load keystore type {0} with path {1} due to {2} jsse.invalid_ssl_conf=SSL configuration is invalid due to {0} jsse.invalid_truststore_password=The provided trust store password could not be used to unlock and/or validate the trust store. Retrying to access the trust store with a null password which will skip validation. jsse.invalidTrustManagerClassName=The trustManagerClassName provided [{0}] does not implement javax.net.ssl.TrustManager jsse.requested_ciphers_not_supported=None of the ciphers specified are supported by the SSL engine : {0} jsse.enableable_ciphers=Specified SSL ciphers that are supported and enableable are : {0} jsse.unsupported_ciphers=Some specified SSL ciphers are not supported by the SSL engine : {0} jsse.requested_protocols_not_supported=None of the SSL protocols specified are supported by the SSL engine : {0} jsse.enableable_protocols=Specified SSL protocols that are supported and enableable are : {0} jsse.unsupported_protocols=Some specified SSL protocols are not supported by the SSL engine : {0} jsseSupport.clientCertError=Error trying to obtain a certificate from the client jseeSupport.certTranslationError=Error translating certificate [{0}] jsseSupport.noCertWant=No client certificate sent for want jsseSupport.serverRenegDisabled=SSL server initiated renegotiation is disabled, closing connection jsseSupport.unexpectedData=Unexpected data read from input streamtomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties0000644000175100017510000000162312271452644030070 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. jsse.alias_no_key_entry=\u5225\u540d {0} \u306f\u30ad\u30fc\u30a8\u30f3\u30c8\u30ea\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093 tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties0000644000175100017510000000154012271452644030103 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. jsse.alias_no_key_entry=Le nom alias {0} n''identifie pas une entr\u00e9e de clef tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/NioX509KeyManager.java0000644000175100017510000000556712271452644026040 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net.jsse; import java.net.Socket; import java.security.Principal; import java.security.PrivateKey; import java.security.cert.X509Certificate; import javax.net.ssl.SSLEngine; import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509KeyManager; public class NioX509KeyManager extends X509ExtendedKeyManager { private X509KeyManager delegate; private String serverKeyAlias; /** * Constructor. * * @param mgr The X509KeyManager used as a delegate * @param serverKeyAlias The alias name of the server's keypair and * supporting certificate chain */ public NioX509KeyManager(X509KeyManager mgr, String serverKeyAlias) { this.delegate = mgr; this.serverKeyAlias = serverKeyAlias; } @Override public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { return delegate.chooseClientAlias(keyType, issuers, socket); } @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { if (serverKeyAlias != null) { return serverKeyAlias; } return delegate.chooseServerAlias(keyType, issuers, socket); } @Override public X509Certificate[] getCertificateChain(String alias) { return delegate.getCertificateChain(alias); } @Override public String[] getClientAliases(String keyType, Principal[] issuers) { return delegate.getClientAliases(keyType, issuers); } @Override public PrivateKey getPrivateKey(String alias) { return delegate.getPrivateKey(alias); } @Override public String[] getServerAliases(String keyType, Principal[] issuers) { return delegate.getServerAliases(keyType, issuers); } @Override public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { if (serverKeyAlias!=null) { return serverKeyAlias; } return super.chooseEngineServerAlias(keyType, issuers, engine); } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java0000644000175100017510000001457312271452644025466 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net.jsse; import java.net.Socket; import java.security.Principal; import java.security.PrivateKey; import java.security.cert.X509Certificate; import javax.net.ssl.SSLEngine; import javax.net.ssl.X509ExtendedKeyManager; import javax.net.ssl.X509KeyManager; /** * X509KeyManager which allows selection of a specific keypair and certificate * chain (identified by their keystore alias name) to be used by the server to * authenticate itself to SSL clients. * * @author Jan Luehe */ public final class JSSEKeyManager extends X509ExtendedKeyManager { private X509KeyManager delegate; private String serverKeyAlias; /** * Constructor. * * @param mgr The X509KeyManager used as a delegate * @param serverKeyAlias The alias name of the server's keypair and * supporting certificate chain */ public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) { super(); this.delegate = mgr; this.serverKeyAlias = serverKeyAlias; } /** * Choose an alias to authenticate the client side of a secure socket, * given the public key type and the list of certificate issuer authorities * recognized by the peer (if any). * * @param keyType The key algorithm type name(s), ordered with the * most-preferred key type first * @param issuers The list of acceptable CA issuer subject names, or null * if it does not matter which issuers are used * @param socket The socket to be used for this connection. This parameter * can be null, in which case this method will return the most generic * alias to use * * @return The alias name for the desired key, or null if there are no * matches */ @Override public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { return delegate.chooseClientAlias(keyType, issuers, socket); } /** * Returns this key manager's server key alias that was provided in the * constructor. * * @param keyType Ignored * @param issuers Ignored * @param socket Ignored * * @return Alias name for the desired key */ @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { return serverKeyAlias; } /** * Returns the certificate chain associated with the given alias. * * @param alias The alias name * * @return Certificate chain (ordered with the user's certificate first * and the root certificate authority last), or null if the alias can't be * found */ @Override public X509Certificate[] getCertificateChain(String alias) { return delegate.getCertificateChain(alias); } /** * Get the matching aliases for authenticating the client side of a secure * socket, given the public key type and the list of certificate issuer * authorities recognized by the peer (if any). * * @param keyType The key algorithm type name * @param issuers The list of acceptable CA issuer subject names, or null * if it does not matter which issuers are used * * @return Array of the matching alias names, or null if there were no * matches */ @Override public String[] getClientAliases(String keyType, Principal[] issuers) { return delegate.getClientAliases(keyType, issuers); } /** * Get the matching aliases for authenticating the server side of a secure * socket, given the public key type and the list of certificate issuer * authorities recognized by the peer (if any). * * @param keyType The key algorithm type name * @param issuers The list of acceptable CA issuer subject names, or null * if it does not matter which issuers are used * * @return Array of the matching alias names, or null if there were no * matches */ @Override public String[] getServerAliases(String keyType, Principal[] issuers) { return delegate.getServerAliases(keyType, issuers); } /** * Returns the key associated with the given alias. * * @param alias The alias name * * @return The requested key, or null if the alias can't be found */ @Override public PrivateKey getPrivateKey(String alias) { return delegate.getPrivateKey(alias); } /** * Choose an alias to authenticate the client side of a secure socket, * given the public key type and the list of certificate issuer authorities * recognized by the peer (if any). * * @param keyType The key algorithm type name(s), ordered with the * most-preferred key type first * @param issuers The list of acceptable CA issuer subject names, or null * if it does not matter which issuers are used * @param engine Ignored * * @return The alias name for the desired key, or null if there are no * matches */ @Override public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { return delegate.chooseClientAlias(keyType, issuers, null); } /** * Returns this key manager's server key alias that was provided in the * constructor. * * @param keyType Ignored * @param issuers Ignored * @param engine Ignored * * @return Alias name for the desired key */ @Override public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { return serverKeyAlias; } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/JSSESupport.java0000644000175100017510000002231112271452644025104 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net.jsse; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.SocketException; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.util.Map; import java.util.WeakHashMap; import javax.net.ssl.HandshakeCompletedEvent; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.security.cert.X509Certificate; import org.apache.tomcat.util.net.SSLSessionManager; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.res.StringManager; /** JSSESupport Concrete implementation class for JSSE Support classes. This will only work with JDK 1.2 and up since it depends on JDK 1.2's certificate support @author EKR @author Craig R. McClanahan @author Filip Hanik Parts cribbed from JSSECertCompat Parts cribbed from CertificatesValve */ class JSSESupport implements SSLSupport, SSLSessionManager { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(JSSESupport.class); private static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.net.jsse.res"); private static final Map keySizeCache = new WeakHashMap(); protected SSLSocket ssl; protected SSLSession session; Listener listener = new Listener(); JSSESupport(SSLSocket sock){ ssl=sock; session = sock.getSession(); sock.addHandshakeCompletedListener(listener); } JSSESupport(SSLSession session) { this.session = session; } @Override public String getCipherSuite() throws IOException { // Look up the current SSLSession if (session == null) return null; return session.getCipherSuite(); } @Override public Object[] getPeerCertificateChain() throws IOException { return getPeerCertificateChain(false); } protected java.security.cert.X509Certificate [] getX509Certificates( SSLSession session) { Certificate [] certs=null; try { certs = session.getPeerCertificates(); } catch( Throwable t ) { log.debug(sm.getString("jsseSupport.clientCertError"), t); return null; } if( certs==null ) return null; java.security.cert.X509Certificate [] x509Certs = new java.security.cert.X509Certificate[certs.length]; for(int i=0; i < certs.length; i++) { if (certs[i] instanceof java.security.cert.X509Certificate ) { // always currently true with the JSSE 1.1.x x509Certs[i] = (java.security.cert.X509Certificate) certs[i]; } else { try { byte [] buffer = certs[i].getEncoded(); CertificateFactory cf = CertificateFactory.getInstance("X.509"); ByteArrayInputStream stream = new ByteArrayInputStream(buffer); x509Certs[i] = (java.security.cert.X509Certificate) cf.generateCertificate(stream); } catch(Exception ex) { log.info(sm.getString( "jseeSupport.certTranslationError", certs[i]), ex); return null; } } if(log.isTraceEnabled()) log.trace("Cert #" + i + " = " + x509Certs[i]); } if(x509Certs.length < 1) return null; return x509Certs; } @Override public Object[] getPeerCertificateChain(boolean force) throws IOException { // Look up the current SSLSession if (session == null) return null; // Convert JSSE's certificate format to the ones we need X509Certificate [] jsseCerts = null; try { jsseCerts = session.getPeerCertificateChain(); } catch(Exception bex) { // ignore. } if (jsseCerts == null) jsseCerts = new X509Certificate[0]; if(jsseCerts.length <= 0 && force && ssl != null) { session.invalidate(); handShake(); session = ssl.getSession(); } return getX509Certificates(session); } protected void handShake() throws IOException { if( ssl.getWantClientAuth() ) { log.debug(sm.getString("jsseSupport.noCertWant")); } else { ssl.setNeedClientAuth(true); } if (ssl.getEnabledCipherSuites().length == 0) { // Handshake is never going to be successful. // Assume this is because handshakes are disabled log.warn(sm.getString("jsseSupport.serverRenegDisabled")); session.invalidate(); ssl.close(); return; } InputStream in = ssl.getInputStream(); int oldTimeout = ssl.getSoTimeout(); ssl.setSoTimeout(1000); byte[] b = new byte[1]; listener.reset(); ssl.startHandshake(); int maxTries = 60; // 60 * 1000 = example 1 minute time out for (int i = 0; i < maxTries; i++) { if (log.isTraceEnabled()) log.trace("Reading for try #" + i); try { int read = in.read(b); if (read > 0) { // Shouldn't happen as all input should have been swallowed // before trying to do the handshake. If it does, something // went wrong so lets bomb out now. throw new SSLException( sm.getString("jsseSupport.unexpectedData")); } } catch(SSLException sslex) { log.info(sm.getString("jsseSupport.clientCertError"), sslex); throw sslex; } catch (IOException e) { // ignore - presumably the timeout } if (listener.completed) { break; } } ssl.setSoTimeout(oldTimeout); if (listener.completed == false) { throw new SocketException("SSL Cert handshake timeout"); } } /** * Copied from org.apache.catalina.valves.CertificateValve */ @Override public Integer getKeySize() throws IOException { // Look up the current SSLSession SSLSupport.CipherData c_aux[]=ciphers; if (session == null) return null; Integer keySize = null; synchronized(keySizeCache) { keySize = keySizeCache.get(session); } if (keySize == null) { int size = 0; String cipherSuite = session.getCipherSuite(); for (int i = 0; i < c_aux.length; i++) { if (cipherSuite.indexOf(c_aux[i].phrase) >= 0) { size = c_aux[i].keySize; break; } } keySize = Integer.valueOf(size); synchronized(keySizeCache) { keySizeCache.put(session, keySize); } } return keySize; } @Override public String getSessionId() throws IOException { // Look up the current SSLSession if (session == null) return null; // Expose ssl_session (getId) byte [] ssl_session = session.getId(); if ( ssl_session == null) return null; StringBuilder buf=new StringBuilder(); for(int x=0; x2) digit=digit.substring(digit.length()-2); buf.append(digit); } return buf.toString(); } private static class Listener implements HandshakeCompletedListener { volatile boolean completed = false; @Override public void handshakeCompleted(HandshakeCompletedEvent event) { completed = true; } void reset() { completed = false; } } /** * Invalidate the session this support object is associated with. */ @Override public void invalidateSession() { session.invalidate(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java0000644000175100017510000000363612271452644026426 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net.jsse; import java.net.Socket; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SSLImplementation; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SSLUtil; import org.apache.tomcat.util.net.ServerSocketFactory; /* JSSEImplementation: Concrete implementation class for JSSE @author EKR */ public class JSSEImplementation extends SSLImplementation { @Override public String getImplementationName(){ return "JSSE"; } @Override public ServerSocketFactory getServerSocketFactory(AbstractEndpoint endpoint) { return new JSSESocketFactory(endpoint); } @Override public SSLSupport getSSLSupport(Socket s) { return new JSSESupport((SSLSocket) s); } @Override public SSLSupport getSSLSupport(SSLSession session) { return new JSSESupport(session); } @Override public SSLUtil getSSLUtil(AbstractEndpoint endpoint) { return new JSSESocketFactory(endpoint); } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java0000644000175100017510000007023512271452644026220 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net.jsse; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CRL; import java.security.cert.CRLException; import java.security.cert.CertPathParameters; import java.security.cert.CertStore; import java.security.cert.CertStoreParameters; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.PKIXBuilderParameters; import java.security.cert.X509CertSelector; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Locale; import javax.net.ssl.CertPathTrustManagerParameters; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509KeyManager; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.Constants; import org.apache.tomcat.util.net.SSLUtil; import org.apache.tomcat.util.net.ServerSocketFactory; import org.apache.tomcat.util.res.StringManager; /** * SSL server socket factory. It requires a valid RSA key and * JSSE.
    * keytool -genkey -alias tomcat -keyalg RSA
    * Use "changeit" as password (this is the default we use). * * @author Harish Prabandham * @author Costin Manolache * @author Stefan Freyr Stefansson * @author EKR -- renamed to JSSESocketFactory * @author Jan Luehe * @author Bill Barker */ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(JSSESocketFactory.class); private static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.net.jsse.res"); private static final boolean RFC_5746_SUPPORTED; private static final String[] DEFAULT_SERVER_PROTOCOLS; private static final String[] DEFAULT_SERVER_CIPHER_SUITES; // Defaults - made public where re-used private static final String defaultProtocol = "TLS"; private static final String defaultKeystoreType = "JKS"; private static final String defaultKeystoreFile = System.getProperty("user.home") + "/.keystore"; private static final int defaultSessionCacheSize = 0; private static final int defaultSessionTimeout = 86400; private static final String ALLOW_ALL_SUPPORTED_CIPHERS = "ALL"; public static final String DEFAULT_KEY_PASS = "changeit"; static { boolean result = false; SSLContext context; String[] ciphers = null; String[] protocols = null; try { context = SSLContext.getInstance("TLS"); context.init(null, null, null); SSLServerSocketFactory ssf = context.getServerSocketFactory(); String supportedCiphers[] = ssf.getSupportedCipherSuites(); for (String cipher : supportedCiphers) { if ("TLS_EMPTY_RENEGOTIATION_INFO_SCSV".equals(cipher)) { result = true; break; } } // There is no API to obtain the default server protocols and cipher // suites. Having inspected the OpenJDK code there the same results // can be achieved via the standard API but there is no guarantee // that every JVM implementation determines the defaults the same // way. Therefore the defaults are determined by creating a server // socket and requested the configured values. SSLServerSocket socket = (SSLServerSocket) ssf.createServerSocket(); ciphers = socket.getEnabledCipherSuites(); protocols = socket.getEnabledProtocols(); } catch (NoSuchAlgorithmException e) { // Assume no RFC 5746 support } catch (KeyManagementException e) { // Assume no RFC 5746 support } catch (IOException e) { // Unable to determine default ciphers/protocols so use none } RFC_5746_SUPPORTED = result; DEFAULT_SERVER_CIPHER_SUITES = ciphers; DEFAULT_SERVER_PROTOCOLS = protocols; } private AbstractEndpoint endpoint; protected SSLServerSocketFactory sslProxy = null; protected String[] enabledCiphers; protected String[] enabledProtocols; protected boolean allowUnsafeLegacyRenegotiation = false; /** * Flag to state that we require client authentication. */ protected boolean requireClientAuth = false; /** * Flag to state that we would like client authentication. */ protected boolean wantClientAuth = false; public JSSESocketFactory (AbstractEndpoint endpoint) { this.endpoint = endpoint; } @Override public ServerSocket createSocket (int port) throws IOException { init(); ServerSocket socket = sslProxy.createServerSocket(port); initServerSocket(socket); return socket; } @Override public ServerSocket createSocket (int port, int backlog) throws IOException { init(); ServerSocket socket = sslProxy.createServerSocket(port, backlog); initServerSocket(socket); return socket; } @Override public ServerSocket createSocket (int port, int backlog, InetAddress ifAddress) throws IOException { init(); ServerSocket socket = sslProxy.createServerSocket(port, backlog, ifAddress); initServerSocket(socket); return socket; } @Override public Socket acceptSocket(ServerSocket socket) throws IOException { SSLSocket asock = null; try { asock = (SSLSocket)socket.accept(); } catch (SSLException e){ throw new SocketException("SSL handshake error" + e.toString()); } return asock; } @Override public void handshake(Socket sock) throws IOException { // We do getSession instead of startHandshake() so we can call this multiple times SSLSession session = ((SSLSocket)sock).getSession(); if (session.getCipherSuite().equals("SSL_NULL_WITH_NULL_NULL")) throw new IOException("SSL handshake failed. Ciper suite in SSL Session is SSL_NULL_WITH_NULL_NULL"); if (!allowUnsafeLegacyRenegotiation && !RFC_5746_SUPPORTED) { // Prevent further handshakes by removing all cipher suites ((SSLSocket) sock).setEnabledCipherSuites(new String[0]); } } @Override public String[] getEnableableCiphers(SSLContext context) { String requestedCiphersStr = endpoint.getCiphers(); if (ALLOW_ALL_SUPPORTED_CIPHERS.equals(requestedCiphersStr)) { return context.getSupportedSSLParameters().getCipherSuites(); } if ((requestedCiphersStr == null) || (requestedCiphersStr.trim().length() == 0)) { return DEFAULT_SERVER_CIPHER_SUITES; } List requestedCiphers = new ArrayList(); for (String rc : requestedCiphersStr.split(",")) { final String cipher = rc.trim(); if (cipher.length() > 0) { requestedCiphers.add(cipher); } } if (requestedCiphers.isEmpty()) { return DEFAULT_SERVER_CIPHER_SUITES; } List ciphers = new ArrayList(requestedCiphers); ciphers.retainAll(Arrays.asList(context.getSupportedSSLParameters() .getCipherSuites())); if (ciphers.isEmpty()) { log.warn(sm.getString("jsse.requested_ciphers_not_supported", requestedCiphersStr)); } if (log.isDebugEnabled()) { log.debug(sm.getString("jsse.enableable_ciphers", ciphers)); if (ciphers.size() != requestedCiphers.size()) { List skipped = new ArrayList(requestedCiphers); skipped.removeAll(ciphers); log.debug(sm.getString("jsse.unsupported_ciphers", skipped)); } } return ciphers.toArray(new String[ciphers.size()]); } /* * Gets the SSL server's keystore password. */ protected String getKeystorePassword() { String keystorePass = endpoint.getKeystorePass(); if (keystorePass == null) { keystorePass = endpoint.getKeyPass(); } if (keystorePass == null) { keystorePass = DEFAULT_KEY_PASS; } return keystorePass; } /* * Gets the SSL server's keystore. */ protected KeyStore getKeystore(String type, String provider, String pass) throws IOException { String keystoreFile = endpoint.getKeystoreFile(); if (keystoreFile == null) keystoreFile = defaultKeystoreFile; return getStore(type, provider, keystoreFile, pass); } /* * Gets the SSL server's truststore. */ protected KeyStore getTrustStore(String keystoreType, String keystoreProvider) throws IOException { KeyStore trustStore = null; String truststoreFile = endpoint.getTruststoreFile(); if(truststoreFile == null) { truststoreFile = System.getProperty("javax.net.ssl.trustStore"); } if(log.isDebugEnabled()) { log.debug("Truststore = " + truststoreFile); } String truststorePassword = endpoint.getTruststorePass(); if( truststorePassword == null) { truststorePassword = System.getProperty("javax.net.ssl.trustStorePassword"); } if(log.isDebugEnabled()) { log.debug("TrustPass = " + truststorePassword); } String truststoreType = endpoint.getTruststoreType(); if( truststoreType == null) { truststoreType = System.getProperty("javax.net.ssl.trustStoreType"); } if(truststoreType == null) { truststoreType = keystoreType; } if(log.isDebugEnabled()) { log.debug("trustType = " + truststoreType); } String truststoreProvider = endpoint.getTruststoreProvider(); if( truststoreProvider == null) { truststoreProvider = System.getProperty("javax.net.ssl.trustStoreProvider"); } if (truststoreProvider == null) { truststoreProvider = keystoreProvider; } if(log.isDebugEnabled()) { log.debug("trustProvider = " + truststoreProvider); } if (truststoreFile != null){ try { trustStore = getStore(truststoreType, truststoreProvider, truststoreFile, truststorePassword); } catch (IOException ioe) { Throwable cause = ioe.getCause(); if (cause instanceof UnrecoverableKeyException) { // Log a warning we had a password issue log.warn(sm.getString("jsse.invalid_truststore_password"), cause); // Re-try trustStore = getStore(truststoreType, truststoreProvider, truststoreFile, null); } else { // Something else went wrong - re-throw throw ioe; } } } return trustStore; } /* * Gets the key- or truststore with the specified type, path, and password. */ private KeyStore getStore(String type, String provider, String path, String pass) throws IOException { KeyStore ks = null; InputStream istream = null; try { if (provider == null) { ks = KeyStore.getInstance(type); } else { ks = KeyStore.getInstance(type, provider); } if(!("PKCS11".equalsIgnoreCase(type) || "".equalsIgnoreCase(path))) { File keyStoreFile = new File(path); if (!keyStoreFile.isAbsolute()) { keyStoreFile = new File(System.getProperty( Constants.CATALINA_BASE_PROP), path); } istream = new FileInputStream(keyStoreFile); } char[] storePass = null; if (pass != null && !"".equals(pass)) { storePass = pass.toCharArray(); } ks.load(istream, storePass); } catch (FileNotFoundException fnfe) { log.error(sm.getString("jsse.keystore_load_failed", type, path, fnfe.getMessage()), fnfe); throw fnfe; } catch (IOException ioe) { // May be expected when working with a trust store // Re-throw. Caller will catch and log as required throw ioe; } catch(Exception ex) { String msg = sm.getString("jsse.keystore_load_failed", type, path, ex.getMessage()); log.error(msg, ex); throw new IOException(msg); } finally { if (istream != null) { try { istream.close(); } catch (IOException ioe) { // Do nothing } } } return ks; } /** * Reads the keystore and initializes the SSL socket factory. */ void init() throws IOException { try { String clientAuthStr = endpoint.getClientAuth(); if("true".equalsIgnoreCase(clientAuthStr) || "yes".equalsIgnoreCase(clientAuthStr)) { requireClientAuth = true; } else if("want".equalsIgnoreCase(clientAuthStr)) { wantClientAuth = true; } SSLContext context = createSSLContext(); context.init(getKeyManagers(), getTrustManagers(), null); // Configure SSL session cache SSLSessionContext sessionContext = context.getServerSessionContext(); if (sessionContext != null) { configureSessionContext(sessionContext); } // create proxy sslProxy = context.getServerSocketFactory(); // Determine which cipher suites to enable enabledCiphers = getEnableableCiphers(context); enabledProtocols = getEnableableProtocols(context); allowUnsafeLegacyRenegotiation = "true".equals( endpoint.getAllowUnsafeLegacyRenegotiation()); // Check the SSL config is OK checkConfig(); } catch(Exception e) { if( e instanceof IOException ) throw (IOException)e; throw new IOException(e.getMessage(), e); } } @Override public SSLContext createSSLContext() throws Exception { // SSL protocol variant (e.g., TLS, SSL v3, etc.) String protocol = endpoint.getSslProtocol(); if (protocol == null) { protocol = defaultProtocol; } SSLContext context = SSLContext.getInstance(protocol); return context; } @Override public KeyManager[] getKeyManagers() throws Exception { String keystoreType = endpoint.getKeystoreType(); if (keystoreType == null) { keystoreType = defaultKeystoreType; } String algorithm = endpoint.getAlgorithm(); if (algorithm == null) { algorithm = KeyManagerFactory.getDefaultAlgorithm(); } return getKeyManagers(keystoreType, endpoint.getKeystoreProvider(), algorithm, endpoint.getKeyAlias()); } @Override public TrustManager[] getTrustManagers() throws Exception { String truststoreType = endpoint.getTruststoreType(); if (truststoreType == null) { truststoreType = System.getProperty("javax.net.ssl.trustStoreType"); } if (truststoreType == null) { truststoreType = endpoint.getKeystoreType(); } if (truststoreType == null) { truststoreType = defaultKeystoreType; } String algorithm = endpoint.getTruststoreAlgorithm(); if (algorithm == null) { algorithm = TrustManagerFactory.getDefaultAlgorithm(); } return getTrustManagers(truststoreType, endpoint.getKeystoreProvider(), algorithm); } @Override public void configureSessionContext(SSLSessionContext sslSessionContext) { int sessionCacheSize; if (endpoint.getSessionCacheSize() != null) { sessionCacheSize = Integer.parseInt( endpoint.getSessionCacheSize()); } else { sessionCacheSize = defaultSessionCacheSize; } int sessionTimeout; if (endpoint.getSessionTimeout() != null) { sessionTimeout = Integer.parseInt(endpoint.getSessionTimeout()); } else { sessionTimeout = defaultSessionTimeout; } sslSessionContext.setSessionCacheSize(sessionCacheSize); sslSessionContext.setSessionTimeout(sessionTimeout); } /** * Gets the initialized key managers. */ protected KeyManager[] getKeyManagers(String keystoreType, String keystoreProvider, String algorithm, String keyAlias) throws Exception { KeyManager[] kms = null; String keystorePass = getKeystorePassword(); KeyStore ks = getKeystore(keystoreType, keystoreProvider, keystorePass); if (keyAlias != null && !ks.isKeyEntry(keyAlias)) { throw new IOException( sm.getString("jsse.alias_no_key_entry", keyAlias)); } KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); String keyPass = endpoint.getKeyPass(); if (keyPass == null) { keyPass = keystorePass; } kmf.init(ks, keyPass.toCharArray()); kms = kmf.getKeyManagers(); if (keyAlias != null) { String alias = keyAlias; if (JSSESocketFactory.defaultKeystoreType.equals(keystoreType)) { alias = alias.toLowerCase(Locale.ENGLISH); } for(int i=0; i 0) { ClassLoader classLoader = getClass().getClassLoader(); Class clazz = classLoader.loadClass(className); if(!(TrustManager.class.isAssignableFrom(clazz))){ throw new InstantiationException(sm.getString( "jsse.invalidTrustManagerClassName", className)); } Object trustManagerObject = clazz.newInstance(); TrustManager trustManager = (TrustManager) trustManagerObject; return new TrustManager[]{ trustManager }; } TrustManager[] tms = null; KeyStore trustStore = getTrustStore(keystoreType, keystoreProvider); if (trustStore != null || endpoint.getTrustManagerClassName() != null) { if (crlf == null) { TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); tmf.init(trustStore); tms = tmf.getTrustManagers(); } else { TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); CertPathParameters params = getParameters(algorithm, crlf, trustStore); ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(params); tmf.init(mfp); tms = tmf.getTrustManagers(); } } return tms; } /** * Return the initialization parameters for the TrustManager. * Currently, only the default PKIX is supported. * * @param algorithm The algorithm to get parameters for. * @param crlf The path to the CRL file. * @param trustStore The configured TrustStore. * @return The parameters including the CRLs and TrustStore. */ protected CertPathParameters getParameters(String algorithm, String crlf, KeyStore trustStore) throws Exception { CertPathParameters params = null; if("PKIX".equalsIgnoreCase(algorithm)) { PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore, new X509CertSelector()); Collection crls = getCRLs(crlf); CertStoreParameters csp = new CollectionCertStoreParameters(crls); CertStore store = CertStore.getInstance("Collection", csp); xparams.addCertStore(store); xparams.setRevocationEnabled(true); String trustLength = endpoint.getTrustMaxCertLength(); if(trustLength != null) { try { xparams.setMaxPathLength(Integer.parseInt(trustLength)); } catch(Exception ex) { log.warn("Bad maxCertLength: "+trustLength); } } params = xparams; } else { throw new CRLException("CRLs not supported for type: "+algorithm); } return params; } /** * Load the collection of CRLs. * */ protected Collection getCRLs(String crlf) throws IOException, CRLException, CertificateException { File crlFile = new File(crlf); if( !crlFile.isAbsolute() ) { crlFile = new File( System.getProperty(Constants.CATALINA_BASE_PROP), crlf); } Collection crls = null; InputStream is = null; try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); is = new FileInputStream(crlFile); crls = cf.generateCRLs(is); } catch(IOException iex) { throw iex; } catch(CRLException crle) { throw crle; } catch(CertificateException ce) { throw ce; } finally { if(is != null) { try{ is.close(); } catch(Exception ex) { // Ignore } } } return crls; } @Override public String[] getEnableableProtocols(SSLContext context) { String[] requestedProtocols = endpoint.getSslEnabledProtocolsArray(); if ((requestedProtocols == null) || (requestedProtocols.length == 0)) { return DEFAULT_SERVER_PROTOCOLS; } List protocols = new ArrayList( Arrays.asList(requestedProtocols)); protocols.retainAll(Arrays.asList(context.getSupportedSSLParameters() .getProtocols())); if (protocols.isEmpty()) { log.warn(sm.getString("jsse.requested_protocols_not_supported", Arrays.asList(requestedProtocols))); } if (log.isDebugEnabled()) { log.debug(sm.getString("jsse.enableable_protocols", protocols)); if (protocols.size() != requestedProtocols.length) { List skipped = new ArrayList( Arrays.asList(requestedProtocols)); skipped.removeAll(protocols); log.debug(sm.getString("jsse.unsupported_protocols", skipped)); } } return protocols.toArray(new String[protocols.size()]); } /** * Configure Client authentication for this version of JSSE. The * JSSE included in Java 1.4 supports the 'want' value. Prior * versions of JSSE will treat 'want' as 'false'. * @param socket the SSLServerSocket */ protected void configureClientAuth(SSLServerSocket socket){ if (wantClientAuth){ socket.setWantClientAuth(wantClientAuth); } else { socket.setNeedClientAuth(requireClientAuth); } } /** * Configures the given SSL server socket with the requested cipher suites, * protocol versions, and need for client authentication */ private void initServerSocket(ServerSocket ssocket) { SSLServerSocket socket = (SSLServerSocket) ssocket; socket.setEnabledCipherSuites(enabledCiphers); socket.setEnabledProtocols(enabledProtocols); // we don't know if client auth is needed - // after parsing the request we may re-handshake configureClientAuth(socket); } /** * Checks that the certificate is compatible with the enabled cipher suites. * If we don't check now, the JIoEndpoint can enter a nasty logging loop. * See bug 45528. */ private void checkConfig() throws IOException { // Create an unbound server socket ServerSocket socket = sslProxy.createServerSocket(); initServerSocket(socket); try { // Set the timeout to 1ms as all we care about is if it throws an // SSLException on accept. socket.setSoTimeout(1); socket.accept(); // Will never get here - no client can connect to an unbound port } catch (SSLException ssle) { // SSL configuration is invalid. Possibly cert doesn't match ciphers IOException ioe = new IOException(sm.getString( "jsse.invalid_ssl_conf", ssle.getMessage())); ioe.initCause(ssle); throw ioe; } catch (Exception e) { /* * Possible ways of getting here * socket.accept() throws a SecurityException * socket.setSoTimeout() throws a SocketException * socket.accept() throws some other exception (after a JDK change) * In these cases the test won't work so carry on - essentially * the behaviour before this patch * socket.accept() throws a SocketTimeoutException * In this case all is well so carry on */ } finally { // Should be open here but just in case if (!socket.isClosed()) { socket.close(); } } } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/AbstractEndpoint.java0000644000175100017510000007722712270263406025256 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.File; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.StringTokenizer; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import javax.net.ssl.KeyManagerFactory; import org.apache.juli.logging.Log; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Acceptor.AcceptorState; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.threads.LimitLatch; import org.apache.tomcat.util.threads.ResizableExecutor; import org.apache.tomcat.util.threads.TaskQueue; import org.apache.tomcat.util.threads.TaskThreadFactory; import org.apache.tomcat.util.threads.ThreadPoolExecutor; /** * * @author fhanik * @author Mladen Turk * @author Remy Maucherat */ public abstract class AbstractEndpoint { // -------------------------------------------------------------- Constants protected static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.net.res"); public static interface Handler { /** * Different types of socket states to react upon. */ public enum SocketState { // TODO Add a new state to the AsyncStateMachine and remove // ASYNC_END (if possible) OPEN, CLOSED, LONG, ASYNC_END, SENDFILE, UPGRADING_TOMCAT, UPGRADING, UPGRADED } /** * Obtain the GlobalRequestProcessor associated with the handler. */ public Object getGlobal(); /** * Recycle resources associated with the handler. */ public void recycle(); } protected enum BindState { UNBOUND, BOUND_ON_INIT, BOUND_ON_START } public abstract static class Acceptor implements Runnable { public enum AcceptorState { NEW, RUNNING, PAUSED, ENDED } protected volatile AcceptorState state = AcceptorState.NEW; public final AcceptorState getState() { return state; } private String threadName; protected final void setThreadName(final String threadName) { this.threadName = threadName; } protected final String getThreadName() { return threadName; } } private static final int INITIAL_ERROR_DELAY = 50; private static final int MAX_ERROR_DELAY = 1600; // ----------------------------------------------------------------- Fields /** * Running state of the endpoint. */ protected volatile boolean running = false; /** * Will be set to true whenever the endpoint is paused. */ protected volatile boolean paused = false; /** * Are we using an internal executor */ protected volatile boolean internalExecutor = false; /** * counter for nr of connections handled by an endpoint */ private volatile LimitLatch connectionLimitLatch = null; /** * Socket properties */ protected SocketProperties socketProperties = new SocketProperties(); public SocketProperties getSocketProperties() { return socketProperties; } /** * Threads used to accept new connections and pass them to worker threads. */ protected Acceptor[] acceptors; // ----------------------------------------------------------------- Properties /** * Time to wait for the internal executor (if used) to terminate when the * endpoint is stopped in milliseconds. Defaults to 5000 (5 seconds). */ private long executorTerminationTimeoutMillis = 5000; public long getExecutorTerminationTimeoutMillis() { return executorTerminationTimeoutMillis; } public void setExecutorTerminationTimeoutMillis( long executorTerminationTimeoutMillis) { this.executorTerminationTimeoutMillis = executorTerminationTimeoutMillis; } /** * Acceptor thread count. */ protected int acceptorThreadCount = 0; public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; } public int getAcceptorThreadCount() { return acceptorThreadCount; } /** * Priority of the acceptor threads. */ protected int acceptorThreadPriority = Thread.NORM_PRIORITY; public void setAcceptorThreadPriority(int acceptorThreadPriority) { this.acceptorThreadPriority = acceptorThreadPriority; } public int getAcceptorThreadPriority() { return acceptorThreadPriority; } private int maxConnections = 10000; public void setMaxConnections(int maxCon) { this.maxConnections = maxCon; LimitLatch latch = this.connectionLimitLatch; if (latch != null) { // Update the latch that enforces this if (maxCon == -1) { releaseConnectionLatch(); } else { latch.setLimit(maxCon); } } else if (maxCon > 0) { initializeConnectionLatch(); } } public int getMaxConnections() { return this.maxConnections; } /** * Return the current count of connections handled by this endpoint, if the * connections are counted (which happens when the maximum count of * connections is limited), or -1 if they are not. This * property is added here so that this value can be inspected through JMX. * It is visible on "ThreadPool" MBean. * *

    The count is incremented by the Acceptor before it tries to accept a * new connection. Until the limit is reached and thus the count cannot be * incremented, this value is more by 1 (the count of acceptors) than the * actual count of connections that are being served. * * @return The count */ public long getConnectionCount() { LimitLatch latch = connectionLimitLatch; if (latch != null) { return latch.getCount(); } return -1; } /** * External Executor based thread pool. */ private Executor executor = null; public void setExecutor(Executor executor) { this.executor = executor; this.internalExecutor = (executor==null); } public Executor getExecutor() { return executor; } /** * Server socket port. */ private int port; public int getPort() { return port; } public void setPort(int port ) { this.port=port; } public abstract int getLocalPort(); /** * Address for the server socket. */ private InetAddress address; public InetAddress getAddress() { return address; } public void setAddress(InetAddress address) { this.address = address; } /** * Allows the server developer to specify the backlog that * should be used for server sockets. By default, this value * is 100. */ private int backlog = 100; public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; } public int getBacklog() { return backlog; } /** * Controls when the Endpoint binds the port. true, the default * binds the port on {@link #init()} and unbinds it on {@link #destroy()}. * If set to false the port is bound on {@link #start()} and * unbound on {@link #stop()}. */ private boolean bindOnInit = true; public boolean getBindOnInit() { return bindOnInit; } public void setBindOnInit(boolean b) { this.bindOnInit = b; } private BindState bindState = BindState.UNBOUND; /** * Keepalive timeout, if not set the soTimeout is used. */ private Integer keepAliveTimeout = null; public int getKeepAliveTimeout() { if (keepAliveTimeout == null) { return getSoTimeout(); } else { return keepAliveTimeout.intValue(); } } public void setKeepAliveTimeout(int keepAliveTimeout) { this.keepAliveTimeout = Integer.valueOf(keepAliveTimeout); } /** * Socket TCP no delay. */ public boolean getTcpNoDelay() { return socketProperties.getTcpNoDelay();} public void setTcpNoDelay(boolean tcpNoDelay) { socketProperties.setTcpNoDelay(tcpNoDelay); } /** * Socket linger. */ public int getSoLinger() { return socketProperties.getSoLingerTime(); } public void setSoLinger(int soLinger) { socketProperties.setSoLingerTime(soLinger); socketProperties.setSoLingerOn(soLinger>=0); } /** * Socket timeout. */ public int getSoTimeout() { return socketProperties.getSoTimeout(); } public void setSoTimeout(int soTimeout) { socketProperties.setSoTimeout(soTimeout); } /** * SSL engine. */ private boolean SSLEnabled = false; public boolean isSSLEnabled() { return SSLEnabled; } public void setSSLEnabled(boolean SSLEnabled) { this.SSLEnabled = SSLEnabled; } private int minSpareThreads = 10; public int getMinSpareThreads() { return Math.min(minSpareThreads,getMaxThreads()); } public void setMinSpareThreads(int minSpareThreads) { this.minSpareThreads = minSpareThreads; if (running && executor!=null) { if (executor instanceof java.util.concurrent.ThreadPoolExecutor) { ((java.util.concurrent.ThreadPoolExecutor)executor).setCorePoolSize(minSpareThreads); } else if (executor instanceof ResizableExecutor) { ((ResizableExecutor)executor).resizePool(minSpareThreads, maxThreads); } } } /** * Maximum amount of worker threads. */ private int maxThreads = 200; public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; if (running && executor!=null) { if (executor instanceof java.util.concurrent.ThreadPoolExecutor) { ((java.util.concurrent.ThreadPoolExecutor)executor).setMaximumPoolSize(maxThreads); } else if (executor instanceof ResizableExecutor) { ((ResizableExecutor)executor).resizePool(minSpareThreads, maxThreads); } } } public int getMaxThreads() { return getMaxThreadsExecutor(running); } protected int getMaxThreadsExecutor(boolean useExecutor) { if (useExecutor && executor != null) { if (executor instanceof java.util.concurrent.ThreadPoolExecutor) { return ((java.util.concurrent.ThreadPoolExecutor)executor).getMaximumPoolSize(); } else if (executor instanceof ResizableExecutor) { return ((ResizableExecutor)executor).getMaxThreads(); } else { return -1; } } else { return maxThreads; } } /** * Max keep alive requests */ private int maxKeepAliveRequests=100; // as in Apache HTTPD server public int getMaxKeepAliveRequests() { return maxKeepAliveRequests; } public void setMaxKeepAliveRequests(int maxKeepAliveRequests) { this.maxKeepAliveRequests = maxKeepAliveRequests; } /** * The maximum number of headers in a request that are allowed. * 100 by default. A value of less than 0 means no limit. */ private int maxHeaderCount = 100; // as in Apache HTTPD server public int getMaxHeaderCount() { return maxHeaderCount; } public void setMaxHeaderCount(int maxHeaderCount) { this.maxHeaderCount = maxHeaderCount; } /** * Name of the thread pool, which will be used for naming child threads. */ private String name = "TP"; public void setName(String name) { this.name = name; } public String getName() { return name; } /** * The default is true - the created threads will be * in daemon mode. If set to false, the control thread * will not be daemon - and will keep the process alive. */ private boolean daemon = true; public void setDaemon(boolean b) { daemon = b; } public boolean getDaemon() { return daemon; } /** * Priority of the worker threads. */ protected int threadPriority = Thread.NORM_PRIORITY; public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } public int getThreadPriority() { return threadPriority; } protected abstract boolean getDeferAccept(); /** * Attributes provide a way for configuration to be passed to sub-components * without the {@link org.apache.coyote.ProtocolHandler} being aware of the * properties available on those sub-components. One example of such a * sub-component is the * {@link org.apache.tomcat.util.net.ServerSocketFactory}. */ protected HashMap attributes = new HashMap(); /** * Generic property setter called when a property for which a specific * setter already exists within the * {@link org.apache.coyote.ProtocolHandler} needs to be made available to * sub-components. The specific setter will call this method to populate the * attributes. */ public void setAttribute(String name, Object value) { if (getLog().isTraceEnabled()) { getLog().trace(sm.getString("abstractProtocolHandler.setAttribute", name, value)); } attributes.put(name, value); } /** * Used by sub-components to retrieve configuration information. */ public Object getAttribute(String key) { Object value = attributes.get(key); if (getLog().isTraceEnabled()) { getLog().trace(sm.getString("abstractProtocolHandler.getAttribute", key, value)); } return value; } public boolean setProperty(String name, String value) { setAttribute(name, value); final String socketName = "socket."; try { if (name.startsWith(socketName)) { return IntrospectionUtils.setProperty(socketProperties, name.substring(socketName.length()), value); } else { return IntrospectionUtils.setProperty(this,name,value,false); } }catch ( Exception x ) { getLog().error("Unable to set attribute \""+name+"\" to \""+value+"\"",x); return false; } } public String getProperty(String name) { return (String) getAttribute(name); } /** * Return the amount of threads that are managed by the pool. * * @return the amount of threads that are managed by the pool */ public int getCurrentThreadCount() { if (executor!=null) { if (executor instanceof ThreadPoolExecutor) { return ((ThreadPoolExecutor)executor).getPoolSize(); } else if (executor instanceof ResizableExecutor) { return ((ResizableExecutor)executor).getPoolSize(); } else { return -1; } } else { return -2; } } /** * Return the amount of threads that are in use * * @return the amount of threads that are in use */ public int getCurrentThreadsBusy() { if (executor!=null) { if (executor instanceof ThreadPoolExecutor) { return ((ThreadPoolExecutor)executor).getActiveCount(); } else if (executor instanceof ResizableExecutor) { return ((ResizableExecutor)executor).getActiveCount(); } else { return -1; } } else { return -2; } } public boolean isRunning() { return running; } public boolean isPaused() { return paused; } public void createExecutor() { internalExecutor = true; TaskQueue taskqueue = new TaskQueue(); TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority()); executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf); taskqueue.setParent( (ThreadPoolExecutor) executor); } public void shutdownExecutor() { if ( executor!=null && internalExecutor ) { if ( executor instanceof ThreadPoolExecutor ) { //this is our internal one, so we need to shut it down ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor; tpe.shutdownNow(); long timeout = getExecutorTerminationTimeoutMillis(); if (timeout > 0) { try { tpe.awaitTermination(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { // Ignore } if (tpe.isTerminating()) { getLog().warn(sm.getString("endpoint.warn.executorShutdown", getName())); } } TaskQueue queue = (TaskQueue) tpe.getQueue(); queue.setParent(null); } executor = null; } } /** * Unlock the server socket accept using a bogus connection. */ protected void unlockAccept() { // Only try to unlock the acceptor if it is necessary boolean unlockRequired = false; for (Acceptor acceptor : acceptors) { if (acceptor.getState() == AcceptorState.RUNNING) { unlockRequired = true; break; } } if (!unlockRequired) { return; } java.net.Socket s = null; InetSocketAddress saddr = null; try { // Need to create a connection to unlock the accept(); if (address == null) { saddr = new InetSocketAddress("localhost", getLocalPort()); } else { saddr = new InetSocketAddress(address, getLocalPort()); } s = new java.net.Socket(); int stmo = 2 * 1000; int utmo = 2 * 1000; if (getSocketProperties().getSoTimeout() > stmo) stmo = getSocketProperties().getSoTimeout(); if (getSocketProperties().getUnlockTimeout() > utmo) utmo = getSocketProperties().getUnlockTimeout(); s.setSoTimeout(stmo); // TODO Consider hard-coding to s.setSoLinger(true,0) s.setSoLinger(getSocketProperties().getSoLingerOn(),getSocketProperties().getSoLingerTime()); if (getLog().isDebugEnabled()) { getLog().debug("About to unlock socket for:"+saddr); } s.connect(saddr,utmo); if (getDeferAccept()) { /* * In the case of a deferred accept / accept filters we need to * send data to wake up the accept. Send OPTIONS * to bypass * even BSD accept filters. The Acceptor will discard it. */ OutputStreamWriter sw; sw = new OutputStreamWriter(s.getOutputStream(), "ISO-8859-1"); sw.write("OPTIONS * HTTP/1.0\r\n" + "User-Agent: Tomcat wakeup connection\r\n\r\n"); sw.flush(); } if (getLog().isDebugEnabled()) { getLog().debug("Socket unlock completed for:"+saddr); } // Wait for upto 1000ms acceptor threads to unlock long waitLeft = 1000; for (Acceptor acceptor : acceptors) { while (waitLeft > 0 && acceptor.getState() == AcceptorState.RUNNING) { Thread.sleep(50); waitLeft -= 50; } } } catch(Exception e) { if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("endpoint.debug.unlock", "" + getPort()), e); } } finally { if (s != null) { try { s.close(); } catch (Exception e) { // Ignore } } } } // ------------------------------------------------------- Lifecycle methods /* * NOTE: There is no maintenance of state or checking for valid transitions * within this class other than ensuring that bind/unbind are called in the * right place. It is expected that the calling code will maintain state and * prevent invalid state transitions. */ public abstract void bind() throws Exception; public abstract void unbind() throws Exception; public abstract void startInternal() throws Exception; public abstract void stopInternal() throws Exception; public final void init() throws Exception { if (bindOnInit) { bind(); bindState = BindState.BOUND_ON_INIT; } } public final void start() throws Exception { if (bindState == BindState.UNBOUND) { bind(); bindState = BindState.BOUND_ON_START; } startInternal(); } protected final void startAcceptorThreads() { int count = getAcceptorThreadCount(); acceptors = new Acceptor[count]; for (int i = 0; i < count; i++) { acceptors[i] = createAcceptor(); String threadName = getName() + "-Acceptor-" + i; acceptors[i].setThreadName(threadName); Thread t = new Thread(acceptors[i], threadName); t.setPriority(getAcceptorThreadPriority()); t.setDaemon(getDaemon()); t.start(); } } /** * Hook to allow Endpoints to provide a specific Acceptor implementation. */ protected abstract Acceptor createAcceptor(); /** * Pause the endpoint, which will stop it accepting new connections. */ public void pause() { if (running && !paused) { paused = true; unlockAccept(); } } /** * Resume the endpoint, which will make it start accepting new connections * again. */ public void resume() { if (running) { paused = false; } } public final void stop() throws Exception { stopInternal(); if (bindState == BindState.BOUND_ON_START) { unbind(); bindState = BindState.UNBOUND; } } public final void destroy() throws Exception { if (bindState == BindState.BOUND_ON_INIT) { unbind(); bindState = BindState.UNBOUND; } } public String adjustRelativePath(String path, String relativeTo) { // Empty or null path can't point to anything useful. The assumption is // that the value is deliberately empty / null so leave it that way. if (path == null || path.length() == 0) { return path; } String newPath = path; File f = new File(newPath); if ( !f.isAbsolute()) { newPath = relativeTo + File.separator + newPath; f = new File(newPath); } if (!f.exists()) { getLog().warn("configured file:["+newPath+"] does not exist."); } return newPath; } protected abstract Log getLog(); // Flags to indicate optional feature support // Some of these are always hard-coded, some are hard-coded to false (i.e. // the endpoint does not support them) and some are configurable. public abstract boolean getUseSendfile(); public abstract boolean getUseComet(); public abstract boolean getUseCometTimeout(); public abstract boolean getUsePolling(); protected LimitLatch initializeConnectionLatch() { if (maxConnections==-1) return null; if (connectionLimitLatch==null) { connectionLimitLatch = new LimitLatch(getMaxConnections()); } return connectionLimitLatch; } protected void releaseConnectionLatch() { LimitLatch latch = connectionLimitLatch; if (latch!=null) latch.releaseAll(); connectionLimitLatch = null; } protected void countUpOrAwaitConnection() throws InterruptedException { if (maxConnections==-1) return; LimitLatch latch = connectionLimitLatch; if (latch!=null) latch.countUpOrAwait(); } protected long countDownConnection() { if (maxConnections==-1) return -1; LimitLatch latch = connectionLimitLatch; if (latch!=null) { long result = latch.countDown(); if (result<0) { getLog().warn("Incorrect connection count, multiple socket.close called on the same socket." ); } return result; } else return -1; } /** * Provides a common approach for sub-classes to handle exceptions where a * delay is required to prevent a Thread from entering a tight loop which * will consume CPU and may also trigger large amounts of logging. For * example, this can happen with the Acceptor thread if the ulimit for open * files is reached. * * @param currentErrorDelay The current delay being applied on failure * @return The delay to apply on the next failure */ protected int handleExceptionWithDelay(int currentErrorDelay) { // Don't delay on first exception if (currentErrorDelay > 0) { try { Thread.sleep(currentErrorDelay); } catch (InterruptedException e) { // Ignore } } // On subsequent exceptions, start the delay at 50ms, doubling the delay // on every subsequent exception until the delay reaches 1.6 seconds. if (currentErrorDelay == 0) { return INITIAL_ERROR_DELAY; } else if (currentErrorDelay < MAX_ERROR_DELAY) { return currentErrorDelay * 2; } else { return MAX_ERROR_DELAY; } } // -------------------- SSL related properties -------------------- private String algorithm = KeyManagerFactory.getDefaultAlgorithm(); public String getAlgorithm() { return algorithm;} public void setAlgorithm(String s ) { this.algorithm = s;} private String clientAuth = "false"; public String getClientAuth() { return clientAuth;} public void setClientAuth(String s ) { this.clientAuth = s;} private String keystoreFile = System.getProperty("user.home")+"/.keystore"; public String getKeystoreFile() { return keystoreFile;} public void setKeystoreFile(String s ) { keystoreFile = adjustRelativePath(s, System.getProperty(Constants.CATALINA_BASE_PROP)); } private String keystorePass = null; public String getKeystorePass() { return keystorePass;} public void setKeystorePass(String s ) { this.keystorePass = s;} private String keystoreType = "JKS"; public String getKeystoreType() { return keystoreType;} public void setKeystoreType(String s ) { this.keystoreType = s;} private String keystoreProvider = null; public String getKeystoreProvider() { return keystoreProvider;} public void setKeystoreProvider(String s ) { this.keystoreProvider = s;} private String sslProtocol = "TLS"; public String getSslProtocol() { return sslProtocol;} public void setSslProtocol(String s) { sslProtocol = s;} private String ciphers = null; public String getCiphers() { return ciphers;} public void setCiphers(String s) { ciphers = s; } private String keyAlias = null; public String getKeyAlias() { return keyAlias;} public void setKeyAlias(String s ) { keyAlias = s;} private String keyPass = null; public String getKeyPass() { return keyPass;} public void setKeyPass(String s ) { this.keyPass = s;} private String truststoreFile = System.getProperty("javax.net.ssl.trustStore"); public String getTruststoreFile() {return truststoreFile;} public void setTruststoreFile(String s) { truststoreFile = adjustRelativePath(s, System.getProperty(Constants.CATALINA_BASE_PROP)); } private String truststorePass = System.getProperty("javax.net.ssl.trustStorePassword"); public String getTruststorePass() {return truststorePass;} public void setTruststorePass(String truststorePass) { this.truststorePass = truststorePass; } private String truststoreType = System.getProperty("javax.net.ssl.trustStoreType"); public String getTruststoreType() {return truststoreType;} public void setTruststoreType(String truststoreType) { this.truststoreType = truststoreType; } private String truststoreProvider = null; public String getTruststoreProvider() {return truststoreProvider;} public void setTruststoreProvider(String truststoreProvider) { this.truststoreProvider = truststoreProvider; } private String truststoreAlgorithm = null; public String getTruststoreAlgorithm() {return truststoreAlgorithm;} public void setTruststoreAlgorithm(String truststoreAlgorithm) { this.truststoreAlgorithm = truststoreAlgorithm; } private String trustManagerClassName = null; public String getTrustManagerClassName() {return trustManagerClassName;} public void setTrustManagerClassName(String trustManagerClassName) { this.trustManagerClassName = trustManagerClassName; } private String crlFile = null; public String getCrlFile() {return crlFile;} public void setCrlFile(String crlFile) { this.crlFile = crlFile; } private String trustMaxCertLength = null; public String getTrustMaxCertLength() {return trustMaxCertLength;} public void setTrustMaxCertLength(String trustMaxCertLength) { this.trustMaxCertLength = trustMaxCertLength; } private String sessionCacheSize = null; public String getSessionCacheSize() { return sessionCacheSize;} public void setSessionCacheSize(String s) { sessionCacheSize = s;} private String sessionTimeout = "86400"; public String getSessionTimeout() { return sessionTimeout;} public void setSessionTimeout(String s) { sessionTimeout = s;} private String allowUnsafeLegacyRenegotiation = null; public String getAllowUnsafeLegacyRenegotiation() { return allowUnsafeLegacyRenegotiation; } public void setAllowUnsafeLegacyRenegotiation(String s) { allowUnsafeLegacyRenegotiation = s; } private String[] sslEnabledProtocolsarr = new String[0]; public String[] getSslEnabledProtocolsArray() { return this.sslEnabledProtocolsarr; } public void setSslEnabledProtocols(String s) { if (s == null) { this.sslEnabledProtocolsarr = new String[0]; } else { ArrayList sslEnabledProtocols = new ArrayList(); StringTokenizer t = new StringTokenizer(s,","); while (t.hasMoreTokens()) { String p = t.nextToken().trim(); if (p.length() > 0) { sslEnabledProtocols.add(p); } } sslEnabledProtocolsarr = sslEnabledProtocols.toArray( new String[sslEnabledProtocols.size()]); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/AprEndpoint.java0000644000175100017510000027573012271452644024241 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.Address; import org.apache.tomcat.jni.Error; import org.apache.tomcat.jni.File; import org.apache.tomcat.jni.Library; import org.apache.tomcat.jni.OS; import org.apache.tomcat.jni.Poll; import org.apache.tomcat.jni.Pool; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; import org.apache.tomcat.jni.SSLSocket; import org.apache.tomcat.jni.Sockaddr; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Acceptor.AcceptorState; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; /** * APR tailored thread pool, providing the following services: *

      *
    • Socket acceptor thread
    • *
    • Socket poller thread
    • *
    • Sendfile thread
    • *
    • Worker threads pool
    • *
    * * When switching to Java 5, there's an opportunity to use the virtual * machine's thread pool. * * @author Mladen Turk * @author Remy Maucherat */ public class AprEndpoint extends AbstractEndpoint { // -------------------------------------------------------------- Constants private static final Log log = LogFactory.getLog(AprEndpoint.class); // ----------------------------------------------------------------- Fields /** * Root APR memory pool. */ protected long rootPool = 0; /** * Server socket "pointer". */ protected long serverSock = 0; /** * APR memory pool for the server socket. */ protected long serverSockPool = 0; /** * SSL context. */ protected long sslContext = 0; protected ConcurrentLinkedQueue> waitingRequests = new ConcurrentLinkedQueue>(); private final Map connections = new ConcurrentHashMap(); // ------------------------------------------------------------ Constructor public AprEndpoint() { // Need to override the default for maxConnections to align it with what // was pollerSize (before the two were merged) setMaxConnections(8 * 1024); } // ------------------------------------------------------------- Properties /** * Defer accept. */ protected boolean deferAccept = true; public void setDeferAccept(boolean deferAccept) { this.deferAccept = deferAccept; } @Override public boolean getDeferAccept() { return deferAccept; } /** * Size of the sendfile (= concurrent files which can be served). */ protected int sendfileSize = 1 * 1024; public void setSendfileSize(int sendfileSize) { this.sendfileSize = sendfileSize; } public int getSendfileSize() { return sendfileSize; } /** * Handling of accepted sockets. */ protected Handler handler = null; public void setHandler(Handler handler ) { this.handler = handler; } public Handler getHandler() { return handler; } /** * Poll interval, in microseconds. The smaller the value, the more CPU the poller * will use, but the more responsive to activity it will be. */ protected int pollTime = 2000; public int getPollTime() { return pollTime; } public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } } /** * Use sendfile for sending static files. */ protected boolean useSendfile = Library.APR_HAS_SENDFILE; public void setUseSendfile(boolean useSendfile) { this.useSendfile = useSendfile; } @Override public boolean getUseSendfile() { return useSendfile; } /** * Allow comet request handling. */ protected boolean useComet = true; public void setUseComet(boolean useComet) { this.useComet = useComet; } @Override public boolean getUseComet() { return useComet; } @Override public boolean getUseCometTimeout() { return false; } // Not supported @Override public boolean getUsePolling() { return true; } // Always supported /** * Sendfile thread count. */ protected int sendfileThreadCount = 0; public void setSendfileThreadCount(int sendfileThreadCount) { this.sendfileThreadCount = sendfileThreadCount; } public int getSendfileThreadCount() { return sendfileThreadCount; } /** * The socket poller. */ protected Poller poller = null; public Poller getPoller() { return poller; } /** * The socket poller. */ protected AsyncTimeout asyncTimeout = null; public AsyncTimeout getAsyncTimeout() { return asyncTimeout; } /** * The static file sender. */ protected Sendfile sendfile = null; public Sendfile getSendfile() { return sendfile; } /** * SSL protocols. */ protected String SSLProtocol = "all"; public String getSSLProtocol() { return SSLProtocol; } public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; } /** * SSL password (if a cert is encrypted, and no password has been provided, a callback * will ask for a password). */ protected String SSLPassword = null; public String getSSLPassword() { return SSLPassword; } public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; } /** * SSL cipher suite. */ protected String SSLCipherSuite = "ALL"; public String getSSLCipherSuite() { return SSLCipherSuite; } public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; } /** * SSL certificate file. */ protected String SSLCertificateFile = null; public String getSSLCertificateFile() { return SSLCertificateFile; } public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; } /** * SSL certificate key file. */ protected String SSLCertificateKeyFile = null; public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; } public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; } /** * SSL certificate chain file. */ protected String SSLCertificateChainFile = null; public String getSSLCertificateChainFile() { return SSLCertificateChainFile; } public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; } /** * SSL CA certificate path. */ protected String SSLCACertificatePath = null; public String getSSLCACertificatePath() { return SSLCACertificatePath; } public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; } /** * SSL CA certificate file. */ protected String SSLCACertificateFile = null; public String getSSLCACertificateFile() { return SSLCACertificateFile; } public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; } /** * SSL CA revocation path. */ protected String SSLCARevocationPath = null; public String getSSLCARevocationPath() { return SSLCARevocationPath; } public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; } /** * SSL CA revocation file. */ protected String SSLCARevocationFile = null; public String getSSLCARevocationFile() { return SSLCARevocationFile; } public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; } /** * SSL verify client. */ protected String SSLVerifyClient = "none"; public String getSSLVerifyClient() { return SSLVerifyClient; } public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; } /** * SSL verify depth. */ protected int SSLVerifyDepth = 10; public int getSSLVerifyDepth() { return SSLVerifyDepth; } public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } /** * SSL allow insecure renegotiation for the the client that does not * support the secure renegotiation. */ protected boolean SSLInsecureRenegotiation = false; public void setSSLInsecureRenegotiation(boolean SSLInsecureRenegotiation) { this.SSLInsecureRenegotiation = SSLInsecureRenegotiation; } public boolean getSSLInsecureRenegotiation() { return SSLInsecureRenegotiation; } protected boolean SSLHonorCipherOrder = false; /** * Set to true to enforce the server's cipher order * instead of the default which is to allow the client to choose a * preferred cipher. */ public void setSSLHonorCipherOrder(boolean SSLHonorCipherOrder) { this.SSLHonorCipherOrder = SSLHonorCipherOrder; } public boolean getSSLHonorCipherOrder() { return SSLHonorCipherOrder; } /** * Disables compression of the SSL stream. This thwarts CRIME attack * and possibly improves performance by not compressing uncompressible * content such as JPEG, etc. */ protected boolean SSLDisableCompression = false; /** * Set to true to disable SSL compression. This thwarts CRIME * attack. */ public void setSSLDisableCompression(boolean SSLDisableCompression) { this.SSLDisableCompression = SSLDisableCompression; } public boolean getSSLDisableCompression() { return SSLDisableCompression; } /** * Port in use. */ @Override public int getLocalPort() { long s = serverSock; if (s == 0) { return -1; } else { long sa; try { sa = Address.get(Socket.APR_LOCAL, s); Sockaddr addr = Address.getInfo(sa); return addr.port; } catch (Exception e) { return -1; } } } // --------------------------------------------------------- Public Methods /** * Number of keepalive sockets. */ public int getKeepAliveCount() { if (poller == null) { return 0; } return poller.getConnectionCount(); } /** * Number of sendfile sockets. */ public int getSendfileCount() { if (sendfile == null) { return 0; } return sendfile.getSendfileCount(); } // ----------------------------------------------- Public Lifecycle Methods /** * Initialize the endpoint. */ @Override public void bind() throws Exception { // Create the root APR memory pool try { rootPool = Pool.create(0); } catch (UnsatisfiedLinkError e) { throw new Exception(sm.getString("endpoint.init.notavail")); } // Create the pool for the server socket serverSockPool = Pool.create(rootPool); // Create the APR address that will be bound String addressStr = null; if (getAddress() != null) { addressStr = getAddress().getHostAddress(); } int family = Socket.APR_INET; if (Library.APR_HAVE_IPV6) { if (addressStr == null) { if (!OS.IS_BSD && !OS.IS_WIN32 && !OS.IS_WIN64) family = Socket.APR_UNSPEC; } else if (addressStr.indexOf(':') >= 0) { family = Socket.APR_UNSPEC; } } long inetAddress = Address.info(addressStr, family, getPort(), 0, rootPool); // Create the APR server socket serverSock = Socket.create(Address.getInfo(inetAddress).family, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, rootPool); if (OS.IS_UNIX) { Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); } // Deal with the firewalls that tend to drop the inactive sockets Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1); // Bind the server socket int ret = Socket.bind(serverSock, inetAddress); if (ret != 0) { throw new Exception(sm.getString("endpoint.init.bind", "" + ret, Error.strerror(ret))); } // Start listening on the server socket ret = Socket.listen(serverSock, getBacklog()); if (ret != 0) { throw new Exception(sm.getString("endpoint.init.listen", "" + ret, Error.strerror(ret))); } if (OS.IS_WIN32 || OS.IS_WIN64) { // On Windows set the reuseaddr flag after the bind/listen Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); } // Sendfile usage on systems which don't support it cause major problems if (useSendfile && !Library.APR_HAS_SENDFILE) { useSendfile = false; } // Initialize thread count default for acceptor if (acceptorThreadCount == 0) { // FIXME: Doesn't seem to work that well with multiple accept threads acceptorThreadCount = 1; } // Delay accepting of new connections until data is available // Only Linux kernels 2.4 + have that implemented // on other platforms this call is noop and will return APR_ENOTIMPL. if (deferAccept) { if (Socket.optSet(serverSock, Socket.APR_TCP_DEFER_ACCEPT, 1) == Status.APR_ENOTIMPL) { deferAccept = false; } } // Initialize SSL if needed if (isSSLEnabled()) { if (SSLCertificateFile == null) { // This is required throw new Exception(sm.getString("endpoint.apr.noSslCertFile")); } // SSL protocol int value = SSL.SSL_PROTOCOL_NONE; if (SSLProtocol == null || SSLProtocol.length() == 0) { value = SSL.SSL_PROTOCOL_ALL; } else { for (String protocol : SSLProtocol.split("\\+")) { protocol = protocol.trim(); if ("SSLv2".equalsIgnoreCase(protocol)) { value |= SSL.SSL_PROTOCOL_SSLV2; } else if ("SSLv3".equalsIgnoreCase(protocol)) { value |= SSL.SSL_PROTOCOL_SSLV3; } else if ("TLSv1".equalsIgnoreCase(protocol)) { value |= SSL.SSL_PROTOCOL_TLSV1; } else if ("all".equalsIgnoreCase(protocol)) { value |= SSL.SSL_PROTOCOL_ALL; } else { // Protocol not recognized, fail to start as it is safer than // continuing with the default which might enable more than the // is required throw new Exception(sm.getString( "endpoint.apr.invalidSslProtocol", SSLProtocol)); } } } // Create SSL Context try { sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER); } catch (Exception e) { // If the sslEngine is disabled on the AprLifecycleListener // there will be an Exception here but there is no way to check // the AprLifecycleListener settings from here throw new Exception( sm.getString("endpoint.apr.failSslContextMake"), e); } if (SSLInsecureRenegotiation) { boolean legacyRenegSupported = false; try { legacyRenegSupported = SSL.hasOp(SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); if (legacyRenegSupported) SSLContext.setOptions(sslContext, SSL.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); } catch (UnsatisfiedLinkError e) { // Ignore } if (!legacyRenegSupported) { // OpenSSL does not support unsafe legacy renegotiation. log.warn(sm.getString("endpoint.warn.noInsecureReneg", SSL.versionString())); } } // Set cipher order: client (default) or server if (SSLHonorCipherOrder) { boolean orderCiphersSupported = false; try { orderCiphersSupported = SSL.hasOp(SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); if (orderCiphersSupported) SSLContext.setOptions(sslContext, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE); } catch (UnsatisfiedLinkError e) { // Ignore } if (!orderCiphersSupported) { // OpenSSL does not support ciphers ordering. log.warn(sm.getString("endpoint.warn.noHonorCipherOrder", SSL.versionString())); } } // Disable compression if requested if (SSLDisableCompression) { boolean disableCompressionSupported = false; try { disableCompressionSupported = SSL.hasOp(SSL.SSL_OP_NO_COMPRESSION); if (disableCompressionSupported) SSLContext.setOptions(sslContext, SSL.SSL_OP_NO_COMPRESSION); } catch (UnsatisfiedLinkError e) { // Ignore } if (!disableCompressionSupported) { // OpenSSL does not support ciphers ordering. log.warn(sm.getString("endpoint.warn.noDisableCompression", SSL.versionString())); } } // List the ciphers that the client is permitted to negotiate SSLContext.setCipherSuite(sslContext, SSLCipherSuite); // Load Server key and certificate SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA); // Set certificate chain file SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false); // Support Client Certificates SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath); // Set revocation SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath); // Client certificate verification value = SSL.SSL_CVERIFY_NONE; if ("optional".equalsIgnoreCase(SSLVerifyClient)) { value = SSL.SSL_CVERIFY_OPTIONAL; } else if ("require".equalsIgnoreCase(SSLVerifyClient)) { value = SSL.SSL_CVERIFY_REQUIRE; } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) { value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA; } SSLContext.setVerify(sslContext, value, SSLVerifyDepth); // For now, sendfile is not supported with SSL useSendfile = false; } } /** * Start the APR endpoint, creating acceptor, poller and sendfile threads. */ @Override public void startInternal() throws Exception { if (!running) { running = true; paused = false; // Create worker collection if (getExecutor() == null) { createExecutor(); } initializeConnectionLatch(); // Start poller thread poller = new Poller(); poller.init(); Thread pollerThread = new Thread(poller, getName() + "-Poller"); pollerThread.setPriority(threadPriority); pollerThread.setDaemon(true); pollerThread.start(); // Start sendfile thread if (useSendfile) { sendfile = new Sendfile(); sendfile.init(); Thread sendfileThread = new Thread(sendfile, getName() + "-Sendfile"); sendfileThread.setPriority(threadPriority); sendfileThread.setDaemon(true); sendfileThread.start(); } startAcceptorThreads(); // Start async timeout thread asyncTimeout = new AsyncTimeout(); Thread timeoutThread = new Thread(asyncTimeout, getName() + "-AsyncTimeout"); timeoutThread.setPriority(threadPriority); timeoutThread.setDaemon(true); timeoutThread.start(); } } /** * Stop the endpoint. This will cause all processing threads to stop. */ @Override public void stopInternal() { releaseConnectionLatch(); if (!paused) { pause(); } if (running) { running = false; poller.stop(); asyncTimeout.stop(); unlockAccept(); for (AbstractEndpoint.Acceptor acceptor : acceptors) { long waitLeft = 10000; while (waitLeft > 0 && acceptor.getState() != AcceptorState.ENDED && serverSock != 0) { try { Thread.sleep(50); } catch (InterruptedException e) { // Ignore } waitLeft -= 50; } if (waitLeft == 0) { log.warn(sm.getString("endpoint.warn.unlockAcceptorFailed", acceptor.getThreadName())); // If the Acceptor is still running force // the hard socket close. if (serverSock != 0) { Socket.shutdown(serverSock, Socket.APR_SHUTDOWN_READ); serverSock = 0; } } } try { poller.destroy(); } catch (Exception e) { // Ignore } poller = null; connections.clear(); if (useSendfile) { try { sendfile.destroy(); } catch (Exception e) { // Ignore } sendfile = null; } } shutdownExecutor(); } /** * Deallocate APR memory pools, and close server socket. */ @Override public void unbind() throws Exception { if (running) { stop(); } // Destroy pool if it was initialised if (serverSockPool != 0) { Pool.destroy(serverSockPool); serverSockPool = 0; } // Close server socket if it was initialised if (serverSock != 0) { Socket.close(serverSock); serverSock = 0; } sslContext = 0; // Close all APR memory pools and resources if initialised if (rootPool != 0) { Pool.destroy(rootPool); rootPool = 0; } handler.recycle(); } // ------------------------------------------------------ Protected Methods @Override protected AbstractEndpoint.Acceptor createAcceptor() { return new Acceptor(); } /** * Process the specified connection. */ protected boolean setSocketOptions(long socket) { // Process the connection int step = 1; try { // 1: Set socket options: timeout, linger, etc if (socketProperties.getSoLingerOn() && socketProperties.getSoLingerTime() >= 0) Socket.optSet(socket, Socket.APR_SO_LINGER, socketProperties.getSoLingerTime()); if (socketProperties.getTcpNoDelay()) Socket.optSet(socket, Socket.APR_TCP_NODELAY, (socketProperties.getTcpNoDelay() ? 1 : 0)); Socket.timeoutSet(socket, socketProperties.getSoTimeout() * 1000); // 2: SSL handshake step = 2; if (sslContext != 0) { SSLSocket.attach(sslContext, socket); if (SSLSocket.handshake(socket) != 0) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError()); } return false; } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (log.isDebugEnabled()) { if (step == 2) { log.debug(sm.getString("endpoint.err.handshake"), t); } else { log.debug(sm.getString("endpoint.err.unexpected"), t); } } // Tell to close the socket return false; } return true; } /** * Allocate a new poller of the specified size. */ protected long allocatePoller(int size, long pool, int timeout) { try { return Poll.create(size, pool, 0, timeout * 1000); } catch (Error e) { if (Status.APR_STATUS_IS_EINVAL(e.getError())) { log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size)); return 0; } else { log.error(sm.getString("endpoint.poll.initfail"), e); return -1; } } } /** * Process given socket. This is called when the socket has been * accepted. */ protected boolean processSocketWithOptions(long socket) { try { // During shutdown, executor may be null - avoid NPE if (running) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.socket", Long.valueOf(socket))); } AprSocketWrapper wrapper = new AprSocketWrapper(Long.valueOf(socket)); wrapper.setKeepAliveLeft(getMaxKeepAliveRequests()); wrapper.setSecure(isSSLEnabled()); connections.put(Long.valueOf(socket), wrapper); getExecutor().execute(new SocketWithOptionsProcessor(wrapper)); } } catch (RejectedExecutionException x) { log.warn("Socket processing request was rejected for:"+socket,x); return false; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } /** * Process given socket. Called in non-comet mode, typically keep alive * or upgraded protocol. */ public boolean processSocket(long socket, SocketStatus status) { try { Executor executor = getExecutor(); if (executor == null) { log.warn(sm.getString("endpoint.warn.noExector", Long.valueOf(socket), null)); } else { SocketWrapper wrapper = connections.get(Long.valueOf(socket)); // Make sure connection hasn't been closed if (wrapper != null) { executor.execute(new SocketProcessor(wrapper, status)); } } } catch (RejectedExecutionException x) { log.warn("Socket processing request was rejected for:"+socket,x); return false; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } public boolean processSocketAsync(SocketWrapper socket, SocketStatus status) { try { synchronized (socket) { if (waitingRequests.remove(socket)) { SocketProcessor proc = new SocketProcessor(socket, status); ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { //threads should not be created by the webapp classloader if (Constants.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( getClass().getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader( getClass().getClassLoader()); } Executor executor = getExecutor(); if (executor == null) { log.warn(sm.getString("endpoint.warn.noExector", socket, status)); return false; } else { executor.execute(proc); } } finally { if (Constants.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl(loader); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(loader); } } } } } catch (RejectedExecutionException x) { log.warn("Socket processing request was rejected for: "+socket, x); return false; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } private void closeSocket(long socket) { // If not running the socket will be destroyed by // parent pool or acceptor socket. // In any case disable double free which would cause JVM core. connections.remove(Long.valueOf(socket)); // While the connector is running, destroySocket() will call // countDownConnection(). Once the connector is stopped, the latch is // removed so it does not matter that destroySocket() does not call // countDownConnection() in that case Poller poller = this.poller; if (poller != null) { if (!poller.close(socket)) { destroySocket(socket); } } } /* * This method should only be called if there is no chance that the socket * is currently being used by the Poller. It is generally a bad idea to call * this directly from a known error condition. */ private void destroySocket(long socket) { connections.remove(Long.valueOf(socket)); if (log.isDebugEnabled()) { String msg = sm.getString("endpoint.debug.destroySocket", Long.valueOf(socket)); if (log.isTraceEnabled()) { log.trace(msg, new Exception()); } else { log.debug(msg); } } // Be VERY careful if you call this method directly. If it is called // twice for the same socket the JVM will core. Currently this is only // called from Poller.closePollset() to ensure kept alive connections // are closed when calling stop() followed by start(). if (socket != 0) { Socket.destroy(socket); countDownConnection(); } } @Override protected Log getLog() { return log; } // --------------------------------------------------- Acceptor Inner Class /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ protected class Acceptor extends AbstractEndpoint.Acceptor { private final Log log = LogFactory.getLog(AprEndpoint.Acceptor.class); @Override public void run() { int errorDelay = 0; // Loop until we receive a shutdown command while (running) { // Loop if endpoint is paused while (paused && running) { state = AcceptorState.PAUSED; try { Thread.sleep(50); } catch (InterruptedException e) { // Ignore } } if (!running) { break; } state = AcceptorState.RUNNING; try { //if we have reached max connections, wait countUpOrAwaitConnection(); long socket = 0; try { // Accept the next incoming connection from the server // socket socket = Socket.accept(serverSock); if (log.isDebugEnabled()) { long sa = Address.get(Socket.APR_REMOTE, socket); Sockaddr addr = Address.getInfo(sa); log.debug(sm.getString("endpoint.apr.remoteport", Long.valueOf(socket), Long.valueOf(addr.port))); } } catch (Exception e) { //we didn't get a socket countDownConnection(); // Introduce delay if necessary errorDelay = handleExceptionWithDelay(errorDelay); // re-throw throw e; } // Successful accept, reset the error delay errorDelay = 0; if (running && !paused) { // Hand this socket off to an appropriate processor if (!processSocketWithOptions(socket)) { // Close socket right away closeSocket(socket); } } else { // Close socket right away // No code path could have added the socket to the // Poller so use destroySocket() destroySocket(socket); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (running) { String msg = sm.getString("endpoint.accept.fail"); if (t instanceof Error) { Error e = (Error) t; if (e.getError() == 233) { // Not an error on HP-UX so log as a warning // so it can be filtered out on that platform // See bug 50273 log.warn(msg, t); } else { log.error(msg, t); } } else { log.error(msg, t); } } } // The processor will recycle itself when it finishes } state = AcceptorState.ENDED; } } /** * Async timeout thread */ protected class AsyncTimeout implements Runnable { private volatile boolean asyncTimeoutRunning = true; /** * The background thread that checks async requests and fires the * timeout if there has been no activity. */ @Override public void run() { // Loop until we receive a shutdown command while (asyncTimeoutRunning) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } long now = System.currentTimeMillis(); Iterator> sockets = waitingRequests.iterator(); while (sockets.hasNext()) { SocketWrapper socket = sockets.next(); if (socket.async) { long access = socket.getLastAccess(); if (socket.getTimeout() > 0 && (now-access)>socket.getTimeout()) { processSocketAsync(socket,SocketStatus.TIMEOUT); } } } // Loop if endpoint is paused while (paused && asyncTimeoutRunning) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } } } protected void stop() { asyncTimeoutRunning = false; } } // -------------------------------------------------- SocketInfo Inner Class public static class SocketInfo { public long socket; public int timeout; public int flags; public boolean read() { return (flags & Poll.APR_POLLIN) == Poll.APR_POLLIN; } public boolean write() { return (flags & Poll.APR_POLLOUT) == Poll.APR_POLLOUT; } public static int merge(int flag1, int flag2) { return ((flag1 & Poll.APR_POLLIN) | (flag2 & Poll.APR_POLLIN)) | ((flag1 & Poll.APR_POLLOUT) | (flag2 & Poll.APR_POLLOUT)); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Socket: ["); sb.append(socket); sb.append("], timeout: ["); sb.append(timeout); sb.append("], flags: ["); sb.append(flags); return sb.toString(); } } // ---------------------------------------------- SocketTimeouts Inner Class public class SocketTimeouts { protected int size; protected long[] sockets; protected long[] timeouts; protected int pos = 0; public SocketTimeouts(int size) { this.size = 0; sockets = new long[size]; timeouts = new long[size]; } public void add(long socket, long timeout) { sockets[size] = socket; timeouts[size] = timeout; size++; } /** * Removes the specified socket from the poller. * * @return The configured timeout for the socket or zero if the socket * was not in the list of socket timeouts */ public long remove(long socket) { long result = 0; for (int i = 0; i < size; i++) { if (sockets[i] == socket) { result = timeouts[i]; sockets[i] = sockets[size - 1]; timeouts[i] = timeouts[size - 1]; size--; break; } } return result; } public long check(long date) { while (pos < size) { if (date >= timeouts[pos]) { long result = sockets[pos]; sockets[pos] = sockets[size - 1]; timeouts[pos] = timeouts[size - 1]; size--; return result; } pos++; } pos = 0; return 0; } } // -------------------------------------------------- SocketList Inner Class public class SocketList { protected int size; protected int pos; protected long[] sockets; protected int[] timeouts; protected int[] flags; protected SocketInfo info = new SocketInfo(); public SocketList(int size) { this.size = 0; pos = 0; sockets = new long[size]; timeouts = new int[size]; flags = new int[size]; } public int size() { return this.size; } public SocketInfo get() { if (pos == size) { return null; } else { info.socket = sockets[pos]; info.timeout = timeouts[pos]; info.flags = flags[pos]; pos++; return info; } } public void clear() { size = 0; pos = 0; } public boolean add(long socket, int timeout, int flag) { if (size == sockets.length) { return false; } else { for (int i = 0; i < size; i++) { if (sockets[i] == socket) { flags[i] = SocketInfo.merge(flags[i], flag); return true; } } sockets[size] = socket; timeouts[size] = timeout; flags[size] = flag; size++; return true; } } public boolean remove(long socket) { for (int i = 0; i < size; i++) { if (sockets[i] == socket) { sockets[i] = sockets[size - 1]; timeouts[i] = timeouts[size - 1]; flags[size] = flags[size -1]; size--; return true; } } return false; } public void duplicate(SocketList copy) { copy.size = size; copy.pos = pos; System.arraycopy(sockets, 0, copy.sockets, 0, size); System.arraycopy(timeouts, 0, copy.timeouts, 0, size); System.arraycopy(flags, 0, copy.flags, 0, size); } } // ------------------------------------------------------ Poller Inner Class public class Poller implements Runnable { /** * Pointers to the pollers. */ protected long[] pollers = null; /** * Actual poller size. */ protected int actualPollerSize = 0; /** * Amount of spots left in the poller. */ protected int[] pollerSpace = null; /** * Amount of low level pollers in use by this poller. */ protected int pollerCount; /** * Timeout value for the poll call. */ protected int pollerTime; /** * Variable poller timeout that adjusts depending on how many poll sets * are in use so that the total poll time across all poll sets remains * equal to pollTime. */ private int nextPollerTime; /** * Root pool. */ protected long pool = 0; /** * Socket descriptors. */ protected long[] desc; /** * List of sockets to be added to the poller. */ protected SocketList addList = null; /** * List of sockets to be closed. */ private SocketList closeList = null; /** * Structure used for storing timeouts. */ protected SocketTimeouts timeouts = null; /** * Last run of maintain. Maintain will run usually every 5s. */ protected long lastMaintain = System.currentTimeMillis(); /** * The number of connections currently inside this Poller. The correct * operation of the Poller depends on this figure being correct. If it * is not, it is possible that the Poller will enter a wait loop where * it waits for the next connection to be added to the Poller before it * calls poll when it should still be polling existing connections. * Although not necessary at the time of writing this comment, it has * been implemented as an AtomicInteger to ensure that it remains * thread-safe. */ private AtomicInteger connectionCount = new AtomicInteger(0); public int getConnectionCount() { return connectionCount.get(); } private volatile boolean pollerRunning = true; /** * Create the poller. With some versions of APR, the maximum poller size * will be 62 (recompiling APR is necessary to remove this limitation). */ protected void init() { pool = Pool.create(serverSockPool); // Single poller by default int defaultPollerSize = getMaxConnections(); if ((OS.IS_WIN32 || OS.IS_WIN64) && (defaultPollerSize > 1024)) { // The maximum per poller to get reasonable performance is 1024 // Adjust poller size so that it won't reach the limit. This is // a limitation of XP / Server 2003 that has been fixed in // Vista / Server 2008 onwards. actualPollerSize = 1024; } else { actualPollerSize = defaultPollerSize; } timeouts = new SocketTimeouts(defaultPollerSize); // At the moment, setting the timeout is useless, but it could get // used again as the normal poller could be faster using maintain. // It might not be worth bothering though. long pollset = allocatePoller(actualPollerSize, pool, -1); if (pollset == 0 && actualPollerSize > 1024) { actualPollerSize = 1024; pollset = allocatePoller(actualPollerSize, pool, -1); } if (pollset == 0) { actualPollerSize = 62; pollset = allocatePoller(actualPollerSize, pool, -1); } pollerCount = defaultPollerSize / actualPollerSize; pollerTime = pollTime / pollerCount; nextPollerTime = pollerTime; pollers = new long[pollerCount]; pollers[0] = pollset; for (int i = 1; i < pollerCount; i++) { pollers[i] = allocatePoller(actualPollerSize, pool, -1); } pollerSpace = new int[pollerCount]; for (int i = 0; i < pollerCount; i++) { pollerSpace[i] = actualPollerSize; } desc = new long[actualPollerSize * 2]; connectionCount.set(0); addList = new SocketList(defaultPollerSize); closeList = new SocketList(defaultPollerSize); } /* * This method is synchronized so that it is not possible for a socket * to be added to the Poller's addList once this method has completed. */ protected synchronized void stop() { pollerRunning = false; } /** * Destroy the poller. */ protected void destroy() { // Wait for pollerTime before doing anything, so that the poller // threads exit, otherwise parallel destruction of sockets which are // still in the poller can cause problems try { synchronized (this) { this.notify(); this.wait(pollTime / 1000); } } catch (InterruptedException e) { // Ignore } // Close all sockets in the add queue SocketInfo info = addList.get(); while (info != null) { boolean comet = connections.get(Long.valueOf(info.socket)).isComet(); if (!comet || (comet && !processSocket( info.socket, SocketStatus.STOP))) { // Poller isn't running at this point so use destroySocket() // directly destroySocket(info.socket); } info = addList.get(); } addList.clear(); // Close all sockets still in the poller for (int i = 0; i < pollerCount; i++) { int rv = Poll.pollset(pollers[i], desc); if (rv > 0) { for (int n = 0; n < rv; n++) { boolean comet = connections.get( Long.valueOf(desc[n*2+1])).isComet(); if (!comet || (comet && !processSocket( desc[n*2+1], SocketStatus.STOP))) { destroySocket(desc[n*2+1]); } } } } Pool.destroy(pool); connectionCount.set(0); } /** * Add specified socket and associated pool to the poller. The socket * will be added to a temporary array, and polled first after a maximum * amount of time equal to pollTime (in most cases, latency will be much * lower, however). Note: If both read and write are false, the socket * will only be checked for timeout; if the socket was already present * in the poller, a callback event will be generated and the socket will * be removed from the poller. * * @param socket to add to the poller * @param timeout to use for this connection * @param read to do read polling * @param write to do write polling */ public void add(long socket, int timeout, boolean read, boolean write) { add(socket, timeout, (read ? Poll.APR_POLLIN : 0) | (write ? Poll.APR_POLLOUT : 0)); } private void add(long socket, int timeout, int flags) { if (log.isDebugEnabled()) { String msg = sm.getString("endpoint.debug.pollerAdd", Long.valueOf(socket), Integer.valueOf(timeout), Integer.valueOf(flags)); if (log.isTraceEnabled()) { log.trace(msg, new Exception()); } else { log.debug(msg); } } if (timeout <= 0) { // Always put a timeout in timeout = Integer.MAX_VALUE; } boolean ok = false; synchronized (this) { // Add socket to the list. Newly added sockets will wait // at most for pollTime before being polled. Don't add the // socket once the poller has stopped but destroy it straight // away if (pollerRunning && addList.add(socket, timeout, flags)) { ok = true; this.notify(); } } if (!ok) { // Can't do anything: close the socket right away boolean comet = connections.get( Long.valueOf(socket)).isComet(); if (!comet || (comet && !processSocket( socket, SocketStatus.ERROR))) { closeSocket(socket); } } } /** * Add specified socket to one of the pollers. Must only be called from * {@link Poller#run()}. */ protected boolean addToPoller(long socket, int events) { int rv = -1; for (int i = 0; i < pollers.length; i++) { if (pollerSpace[i] > 0) { rv = Poll.add(pollers[i], socket, events); if (rv == Status.APR_SUCCESS) { pollerSpace[i]--; connectionCount.incrementAndGet(); return true; } } } return false; } protected boolean close(long socket) { if (!pollerRunning) { return false; } synchronized (this) { if (!pollerRunning) { return false; } closeList.add(socket, 0, 0); this.notify(); return true; } } /** * Remove specified socket from the pollers. Must only be called from * {@link Poller#run()}. */ private boolean removeFromPoller(long socket) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.pollerRemove", Long.valueOf(socket))); } int rv = -1; for (int i = 0; i < pollers.length; i++) { if (pollerSpace[i] < actualPollerSize) { rv = Poll.remove(pollers[i], socket); if (rv != Status.APR_NOTFOUND) { pollerSpace[i]++; connectionCount.decrementAndGet(); if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.pollerRemoved", Long.valueOf(socket))); } break; } } } timeouts.remove(socket); return (rv == Status.APR_SUCCESS); } /** * Timeout checks. */ protected void maintain() { long date = System.currentTimeMillis(); // Maintain runs at most once every 5s, although it will likely get // called more if ((date - lastMaintain) < 5000L) { return; } else { lastMaintain = date; } long socket = timeouts.check(date); while (socket != 0) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.socketTimeout", Long.valueOf(socket))); } removeFromPoller(socket); boolean comet = connections.get( Long.valueOf(socket)).isComet(); if (!comet || (comet && !processSocket( socket, SocketStatus.TIMEOUT))) { destroySocket(socket); } socket = timeouts.check(date); } } /** * Displays the list of sockets in the pollers. */ @Override public String toString() { StringBuffer buf = new StringBuffer(); buf.append("Poller"); long[] res = new long[actualPollerSize * 2]; for (int i = 0; i < pollers.length; i++) { int count = Poll.pollset(pollers[i], res); buf.append(" [ "); for (int j = 0; j < count; j++) { buf.append(desc[2*j+1]).append(" "); } buf.append("]"); } return buf.toString(); } /** * The background thread that listens for incoming TCP/IP connections * and hands them off to an appropriate processor. */ @Override public void run() { int maintain = 0; SocketList localAddList = new SocketList(getMaxConnections()); SocketList localCloseList = new SocketList(getMaxConnections()); // Loop until we receive a shutdown command while (pollerRunning) { // Loop if endpoint is paused while (pollerRunning && paused) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } // Check timeouts if the poller is empty while (pollerRunning && connectionCount.get() < 1 && addList.size() < 1 && closeList.size() < 1) { // Reset maintain time. try { if (getSoTimeout() > 0 && pollerRunning) { maintain(); } synchronized (this) { this.wait(10000); } } catch (InterruptedException e) { // Ignore } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().warn(sm.getString("endpoint.timeout.err")); } } // Don't add or poll if the poller has been stopped if (!pollerRunning) { break; } try { // Duplicate the add and remove lists so that the syncs are // minimised if (closeList.size() > 0) { synchronized (this) { // Duplicate to another list, so that the syncing is // minimal closeList.duplicate(localCloseList); closeList.clear(); } } else { localCloseList.clear(); } if (addList.size() > 0) { synchronized (this) { // Duplicate to another list, so that the syncing is // minimal addList.duplicate(localAddList); addList.clear(); } } else { localAddList.clear(); } // Remove sockets if (localCloseList.size() > 0) { SocketInfo info = localCloseList.get(); while (info != null) { localAddList.remove(info.socket); removeFromPoller(info.socket); destroySocket(info.socket); info = localCloseList.get(); } } // Add sockets which are waiting to the poller if (localAddList.size() > 0) { SocketInfo info = localAddList.get(); while (info != null) { if (log.isDebugEnabled()) { log.debug(sm.getString( "endpoint.debug.pollerAddDo", Long.valueOf(info.socket))); } timeouts.remove(info.socket); AprSocketWrapper wrapper = connections.get( Long.valueOf(info.socket)); if (wrapper == null) { continue; } if (info.read() || info.write()) { boolean comet = wrapper.isComet(); if (comet || wrapper.pollerFlags != 0) { removeFromPoller(info.socket); } wrapper.pollerFlags = wrapper.pollerFlags | (info.read() ? Poll.APR_POLLIN : 0) | (info.write() ? Poll.APR_POLLOUT : 0); if (!addToPoller(info.socket, wrapper.pollerFlags)) { // Can't do anything: close the socket right // away if (!comet || (comet && !processSocket( info.socket, SocketStatus.ERROR))) { closeSocket(info.socket); } } else { timeouts.add(info.socket, System.currentTimeMillis() + info.timeout); } } else { // Should never happen. closeSocket(info.socket); getLog().warn(sm.getString( "endpoint.apr.pollAddInvalid", info)); } info = localAddList.get(); } } // Poll for the specified interval for (int i = 0; i < pollers.length; i++) { // Flags to ask to reallocate the pool boolean reset = false; //ArrayList skip = null; int rv = 0; // Iterate on each pollers, but no need to poll empty pollers if (pollerSpace[i] < actualPollerSize) { rv = Poll.poll(pollers[i], nextPollerTime, desc, true); // Reset the nextPollerTime nextPollerTime = pollerTime; } else { // Skipping an empty poll set means skipping a wait // time of pollerTime microseconds. If most of the // poll sets are skipped then this loop will be // tighter than expected which could lead to higher // than expected CPU usage. Extending the // nextPollerTime ensures that this loop always // takes about the same time to execute. nextPollerTime += pollerTime; } if (rv > 0) { pollerSpace[i] += rv; connectionCount.addAndGet(-rv); for (int n = 0; n < rv; n++) { long timeout = timeouts.remove(desc[n*2+1]); AprSocketWrapper wrapper = connections.get( Long.valueOf(desc[n*2+1])); if (getLog().isDebugEnabled()) { log.debug(sm.getString( "endpoint.debug.pollerProcess", Long.valueOf(desc[n*2+1]), Long.valueOf(desc[n*2]))); } wrapper.pollerFlags = wrapper.pollerFlags & ~((int) desc[n*2]); // Check for failed sockets and hand this socket off to a worker if (wrapper.isComet()) { // Event processes either a read or a write depending on what the poller returns if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR) || ((desc[n*2] & Poll.APR_POLLNVAL) == Poll.APR_POLLNVAL)) { if (!processSocket(desc[n*2+1], SocketStatus.ERROR)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else if ((desc[n*2] & Poll.APR_POLLIN) == Poll.APR_POLLIN) { if (wrapper.pollerFlags != 0) { add(desc[n*2+1], 1, wrapper.pollerFlags); } if (!processSocket(desc[n*2+1], SocketStatus.OPEN_READ)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else if ((desc[n*2] & Poll.APR_POLLOUT) == Poll.APR_POLLOUT) { if (wrapper.pollerFlags != 0) { add(desc[n*2+1], 1, wrapper.pollerFlags); } if (!processSocket(desc[n*2+1], SocketStatus.OPEN_WRITE)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else { // Unknown event getLog().warn(sm.getString( "endpoint.apr.pollUnknownEvent", Long.valueOf(desc[n*2]))); if (!processSocket(desc[n*2+1], SocketStatus.ERROR)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } } else if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR) || ((desc[n*2] & Poll.APR_POLLNVAL) == Poll.APR_POLLNVAL)) { if (wrapper.isUpgraded()) { // Using non-blocking IO. Need to trigger error handling. // Poller may return error codes plus the flags it was // waiting for or it may just return an error code. By // signalling read/write is possible, a read/write will be // attempted, fail and that will trigger an exception the // application will see. // Check the return flags first, followed by what the socket // was registered for if ((desc[n*2] & Poll.APR_POLLIN) == Poll.APR_POLLIN) { // Error probably occurred during a non-blocking read if (!processSocket(desc[n*2+1], SocketStatus.OPEN_READ)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else if ((desc[n*2] & Poll.APR_POLLOUT) == Poll.APR_POLLOUT) { // Error probably occurred during a non-blocking write if (!processSocket(desc[n*2+1], SocketStatus.OPEN_WRITE)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else if ((wrapper.pollerFlags & Poll.APR_POLLIN) == Poll.APR_POLLIN) { // Can't tell what was happening when the error occurred but the // socket is registered for non-blocking read so use that if (!processSocket(desc[n*2+1], SocketStatus.OPEN_READ)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else if ((wrapper.pollerFlags & Poll.APR_POLLOUT) == Poll.APR_POLLOUT) { // Can't tell what was happening when the error occurred but the // socket is registered for non-blocking write so use that if (!processSocket(desc[n*2+1], SocketStatus.OPEN_WRITE)) { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else { // Close socket and clear pool closeSocket(desc[n*2+1]); } } else if (((desc[n*2] & Poll.APR_POLLIN) == Poll.APR_POLLIN) || ((desc[n*2] & Poll.APR_POLLOUT) == Poll.APR_POLLOUT)) { boolean error = false; if (((desc[n*2] & Poll.APR_POLLIN) == Poll.APR_POLLIN) && !processSocket(desc[n*2+1], SocketStatus.OPEN_READ)) { error = true; // Close socket and clear pool closeSocket(desc[n*2+1]); } if (!error && ((desc[n*2] & Poll.APR_POLLOUT) == Poll.APR_POLLOUT) && !processSocket(desc[n*2+1], SocketStatus.OPEN_WRITE)) { // Close socket and clear pool error = true; closeSocket(desc[n*2+1]); } if (!error && wrapper.pollerFlags != 0) { // If socket was registered for multiple events but // only some of the occurred, re-register for the // remaining events. // timeout is the value of System.currentTimeMillis() that // was set as the point that the socket will timeout. When // adding to the poller, the timeout from now in // milliseconds is required. // So first, subtract the current timestamp if (timeout > 0) { timeout = timeout - System.currentTimeMillis(); } // If the socket should have already expired by now, // re-add it with a very short timeout if (timeout <= 0) { timeout = 1; } // Should be impossible but just in case since timeout will // be cast to an int. if (timeout > Integer.MAX_VALUE) { timeout = Integer.MAX_VALUE; } add(desc[n*2+1], (int) timeout, wrapper.pollerFlags); } } else { // Unknown event getLog().warn(sm.getString( "endpoint.apr.pollUnknownEvent", Long.valueOf(desc[n*2]))); // Close socket and clear pool closeSocket(desc[n*2+1]); } } } else if (rv < 0) { int errn = -rv; // Any non timeup or interrupted error is critical if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { if (errn > Status.APR_OS_START_USERERR) { errn -= Status.APR_OS_START_USERERR; } getLog().error(sm.getString( "endpoint.apr.pollError", Integer.valueOf(errn), Error.strerror(errn))); // Destroy and reallocate the poller reset = true; } } if (reset) { // Reallocate the current poller int count = Poll.pollset(pollers[i], desc); long newPoller = allocatePoller(actualPollerSize, pool, -1); // Don't restore connections for now, since I have not tested it pollerSpace[i] = actualPollerSize; connectionCount.addAndGet(-count); Poll.destroy(pollers[i]); pollers[i] = newPoller; } } // Process socket timeouts if (getSoTimeout() > 0 && maintain++ > 1000 && pollerRunning) { // This works and uses only one timeout mechanism for everything, but the // non event poller might be a bit faster by using the old maintain. maintain = 0; maintain(); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (maintain == 0) { getLog().warn(sm.getString("endpoint.timeout.error"), t); } else { getLog().warn(sm.getString("endpoint.poll.error"), t); } } } synchronized (this) { this.notifyAll(); } } } // ----------------------------------------------- SendfileData Inner Class /** * SendfileData class. */ public static class SendfileData { // File public String fileName; public long fd; public long fdpool; // Range information public long start; public long end; // Socket and socket pool public long socket; // Position public long pos; // KeepAlive flag public boolean keepAlive; } // --------------------------------------------------- Sendfile Inner Class public class Sendfile implements Runnable { protected long sendfilePollset = 0; protected long pool = 0; protected long[] desc; protected HashMap sendfileData; protected int sendfileCount; public int getSendfileCount() { return sendfileCount; } protected ArrayList addS; private volatile boolean sendfileRunning = true; /** * Create the sendfile poller. With some versions of APR, the maximum * poller size will be 62 (recompiling APR is necessary to remove this * limitation). */ protected void init() { pool = Pool.create(serverSockPool); int size = sendfileSize; if (size <= 0) { size = (OS.IS_WIN32 || OS.IS_WIN64) ? (1 * 1024) : (16 * 1024); } sendfilePollset = allocatePoller(size, pool, getSoTimeout()); if (sendfilePollset == 0 && size > 1024) { size = 1024; sendfilePollset = allocatePoller(size, pool, getSoTimeout()); } if (sendfilePollset == 0) { size = 62; sendfilePollset = allocatePoller(size, pool, getSoTimeout()); } desc = new long[size * 2]; sendfileData = new HashMap(size); addS = new ArrayList(); } /** * Destroy the poller. */ protected void destroy() { sendfileRunning = false; // Wait for polltime before doing anything, so that the poller threads // exit, otherwise parallel destruction of sockets which are still // in the poller can cause problems try { synchronized (this) { this.notify(); this.wait(pollTime / 1000); } } catch (InterruptedException e) { // Ignore } // Close any socket remaining in the add queue for (int i = (addS.size() - 1); i >= 0; i--) { SendfileData data = addS.get(i); closeSocket(data.socket); } // Close all sockets still in the poller int rv = Poll.pollset(sendfilePollset, desc); if (rv > 0) { for (int n = 0; n < rv; n++) { closeSocket(desc[n*2+1]); } } Pool.destroy(pool); sendfileData.clear(); } /** * Add the sendfile data to the sendfile poller. Note that in most cases, * the initial non blocking calls to sendfile will return right away, and * will be handled asynchronously inside the kernel. As a result, * the poller will never be used. * * @param data containing the reference to the data which should be snet * @return true if all the data has been sent right away, and false * otherwise */ public boolean add(SendfileData data) { // Initialize fd from data given try { data.fdpool = Socket.pool(data.socket); data.fd = File.open (data.fileName, File.APR_FOPEN_READ | File.APR_FOPEN_SENDFILE_ENABLED | File.APR_FOPEN_BINARY, 0, data.fdpool); data.pos = data.start; // Set the socket to nonblocking mode Socket.timeoutSet(data.socket, 0); while (true) { long nw = Socket.sendfilen(data.socket, data.fd, data.pos, data.end - data.pos, 0); if (nw < 0) { if (!(-nw == Status.EAGAIN)) { Pool.destroy(data.fdpool); data.socket = 0; return false; } else { // Break the loop and add the socket to poller. break; } } else { data.pos = data.pos + nw; if (data.pos >= data.end) { // Entire file has been sent Pool.destroy(data.fdpool); // Set back socket to blocking mode Socket.timeoutSet( data.socket, getSoTimeout() * 1000); return true; } } } } catch (Exception e) { log.warn(sm.getString("endpoint.sendfile.error"), e); return false; } // Add socket to the list. Newly added sockets will wait // at most for pollTime before being polled synchronized (this) { addS.add(data); this.notify(); } return false; } /** * Remove socket from the poller. * * @param data the sendfile data which should be removed */ protected void remove(SendfileData data) { int rv = Poll.remove(sendfilePollset, data.socket); if (rv == Status.APR_SUCCESS) { sendfileCount--; } sendfileData.remove(new Long(data.socket)); } /** * The background thread that listens for incoming TCP/IP connections * and hands them off to an appropriate processor. */ @Override public void run() { long maintainTime = 0; // Loop until we receive a shutdown command while (sendfileRunning) { // Loop if endpoint is paused while (sendfileRunning && paused) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } // Loop if poller is empty while (sendfileRunning && sendfileCount < 1 && addS.size() < 1) { // Reset maintain time. maintainTime = 0; try { synchronized (this) { this.wait(); } } catch (InterruptedException e) { // Ignore } } // Don't add or poll if the poller has been stopped if (!sendfileRunning) { break; } try { // Add socket to the poller if (addS.size() > 0) { synchronized (this) { for (int i = (addS.size() - 1); i >= 0; i--) { SendfileData data = addS.get(i); int rv = Poll.add(sendfilePollset, data.socket, Poll.APR_POLLOUT); if (rv == Status.APR_SUCCESS) { sendfileData.put(new Long(data.socket), data); sendfileCount++; } else { getLog().warn(sm.getString( "endpoint.sendfile.addfail", Integer.valueOf(rv), Error.strerror(rv))); // Can't do anything: close the socket right away closeSocket(data.socket); } } addS.clear(); } } maintainTime += pollTime; // Pool for the specified interval int rv = Poll.poll(sendfilePollset, pollTime, desc, false); if (rv > 0) { for (int n = 0; n < rv; n++) { // Get the sendfile state SendfileData state = sendfileData.get(new Long(desc[n*2+1])); // Problem events if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)) { // Close socket and clear pool remove(state); // Destroy file descriptor pool, which should close the file // Close the socket, as the response would be incomplete closeSocket(state.socket); continue; } // Write some data using sendfile long nw = Socket.sendfilen(state.socket, state.fd, state.pos, state.end - state.pos, 0); if (nw < 0) { // Close socket and clear pool remove(state); // Close the socket, as the response would be incomplete // This will close the file too. closeSocket(state.socket); continue; } state.pos = state.pos + nw; if (state.pos >= state.end) { remove(state); if (state.keepAlive) { // Destroy file descriptor pool, which should close the file Pool.destroy(state.fdpool); Socket.timeoutSet(state.socket, getSoTimeout() * 1000); // If all done put the socket back in the // poller for processing of further requests getPoller().add( state.socket, getKeepAliveTimeout(), true, false); } else { // Close the socket since this is // the end of not keep-alive request. closeSocket(state.socket); } } } } else if (rv < 0) { int errn = -rv; /* Any non timeup or interrupted error is critical */ if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { if (errn > Status.APR_OS_START_USERERR) { errn -= Status.APR_OS_START_USERERR; } getLog().error(sm.getString( "Unexpected poller error", Integer.valueOf(errn), Error.strerror(errn))); // Handle poll critical failure synchronized (this) { destroy(); init(); } continue; } } // Call maintain for the sendfile poller if (getSoTimeout() > 0 && maintainTime > 1000000L && sendfileRunning) { rv = Poll.maintain(sendfilePollset, desc, false); maintainTime = 0; if (rv > 0) { for (int n = 0; n < rv; n++) { // Get the sendfile state SendfileData state = sendfileData.get(new Long(desc[n])); // Close socket and clear pool remove(state); // Destroy file descriptor pool, which should close the file // Close the socket, as the response would be incomplete closeSocket(state.socket); } } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().error(sm.getString("endpoint.poll.error"), t); } } synchronized (this) { this.notifyAll(); } } } // ------------------------------------------------ Handler Inner Interface /** * Bare bones interface used for socket processing. Per thread data is to be * stored in the ThreadWithAttributes extra folders, or alternately in * thread local fields. */ public interface Handler extends AbstractEndpoint.Handler { public SocketState process(SocketWrapper socket, SocketStatus status); } // --------------------------------- SocketWithOptionsProcessor Inner Class /** * This class is the equivalent of the Worker, but will simply use in an * external Executor thread pool. This will also set the socket options * and do the handshake. * * This is called after an accept(). */ protected class SocketWithOptionsProcessor implements Runnable { protected SocketWrapper socket = null; public SocketWithOptionsProcessor(SocketWrapper socket) { this.socket = socket; } @Override public void run() { synchronized (socket) { if (!deferAccept) { if (setSocketOptions(socket.getSocket().longValue())) { getPoller().add(socket.getSocket().longValue(), getSoTimeout(), true, false); } else { // Close socket and pool closeSocket(socket.getSocket().longValue()); socket = null; } } else { // Process the request from this socket if (!setSocketOptions(socket.getSocket().longValue())) { // Close socket and pool closeSocket(socket.getSocket().longValue()); socket = null; return; } // Process the request from this socket Handler.SocketState state = handler.process(socket, SocketStatus.OPEN_READ); if (state == Handler.SocketState.CLOSED) { // Close socket and pool closeSocket(socket.getSocket().longValue()); socket = null; } else if (state == Handler.SocketState.LONG) { socket.access(); if (socket.async) { waitingRequests.add(socket); } } } } } } // -------------------------------------------- SocketProcessor Inner Class /** * This class is the equivalent of the Worker, but will simply use in an * external Executor thread pool. */ protected class SocketProcessor implements Runnable { private final SocketWrapper socket; private final SocketStatus status; public SocketProcessor(SocketWrapper socket, SocketStatus status) { this.socket = socket; if (status == null) { // Should never happen throw new NullPointerException(); } this.status = status; } @Override public void run() { // Upgraded connections need to allow multiple threads to access the // connection at the same time to enable blocking IO to be used when // Servlet 3.1 NIO has been configured if (socket.isUpgraded() && SocketStatus.OPEN_WRITE == status) { synchronized (socket.getWriteThreadLock()) { doRun(); } } else { synchronized (socket) { doRun(); } } } private void doRun() { // Process the request from this socket if (socket.getSocket() == null) { // Closed in another thread return; } SocketState state = handler.process(socket, status); if (state == Handler.SocketState.CLOSED) { // Close socket and pool closeSocket(socket.getSocket().longValue()); socket.socket = null; } else if (state == Handler.SocketState.LONG) { socket.access(); if (socket.async) { waitingRequests.add(socket); } } else if (state == Handler.SocketState.ASYNC_END) { socket.access(); SocketProcessor proc = new SocketProcessor(socket, SocketStatus.OPEN_READ); getExecutor().execute(proc); } } } private static class AprSocketWrapper extends SocketWrapper { // This field should only be used by Poller#run() private int pollerFlags = 0; public AprSocketWrapper(Long socket) { super(socket); } } private static class PrivilegedSetTccl implements PrivilegedAction { private ClassLoader cl; PrivilegedSetTccl(ClassLoader cl) { this.cl = cl; } @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); return null; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/SocketProperties.java0000644000175100017510000002702112271452644025307 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; /** * Properties that can be set in the <Connector> element * in server.xml. All properties are prefixed with "socket." * and are currently only working for the Nio connector * * @author Filip Hanik */ public class SocketProperties { /** * Enable/disable key cache, this bounded cache stores * KeyAttachment objects to reduce GC * Default is 500 * -1 is unlimited * 0 is disabled */ protected int keyCache = 500; /** * Enable/disable socket processor cache, this bounded cache stores * SocketProcessor objects to reduce GC * Default is 500 * -1 is unlimited * 0 is disabled */ protected int processorCache = 500; /** * Enable/disable poller event cache, this bounded cache stores * PollerEvent objects to reduce GC for the poller * Default is 500 * -1 is unlimited * 0 is disabled * >0 the max number of objects to keep in cache. */ protected int eventCache = 500; /** * Enable/disable direct buffers for the network buffers * Default value is enabled */ protected boolean directBuffer = false; /** * Socket receive buffer size in bytes (SO_RCVBUF). * JVM default used if not set. */ protected Integer rxBufSize = null; /** * Socket send buffer size in bytes (SO_SNDBUF). * JVM default used if not set. */ protected Integer txBufSize = null; /** * The application read buffer size in bytes. * Default value is rxBufSize */ protected int appReadBufSize = 8192; /** * The application write buffer size in bytes * Default value is txBufSize */ protected int appWriteBufSize = 8192; /** * NioChannel pool size for the endpoint, * this value is how many channels * -1 means unlimited cached, 0 means no cache * Default value is 500 */ protected int bufferPool = 500; /** * Buffer pool size in bytes to be cached * -1 means unlimited, 0 means no cache * Default value is 100MB (1024*1024*100 bytes) */ protected int bufferPoolSize = 1024*1024*100; /** * TCP_NO_DELAY option. JVM default used if not set. */ protected Boolean tcpNoDelay = Boolean.TRUE; /** * SO_KEEPALIVE option. JVM default used if not set. */ protected Boolean soKeepAlive = null; /** * OOBINLINE option. JVM default used if not set. */ protected Boolean ooBInline = null; /** * SO_REUSEADDR option. JVM default used if not set. */ protected Boolean soReuseAddress = null; /** * SO_LINGER option, paired with the soLingerTime value. * JVM defaults used unless both attributes are set. */ protected Boolean soLingerOn = null; /** * SO_LINGER option, paired with the soLingerOn value. * JVM defaults used unless both attributes are set. */ protected Integer soLingerTime = null; /** * SO_TIMEOUT option. default is 20000. */ protected Integer soTimeout = new Integer(20000); /** * Performance preferences according to * http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int) * All three performance attributes must be set or the JVM defaults will be * used. */ protected Integer performanceConnectionTime = null; /** * Performance preferences according to * http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int) * All three performance attributes must be set or the JVM defaults will be * used. */ protected Integer performanceLatency = null; /** * Performance preferences according to * http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#setPerformancePreferences(int,%20int,%20int) * All three performance attributes must be set or the JVM defaults will be * used. */ protected Integer performanceBandwidth = null; /** * The minimum frequency of the timeout interval to avoid excess load from * the poller during high traffic */ protected long timeoutInterval = 1000; /** * Timeout in milliseconds for an unlock to take place. */ protected int unlockTimeout = 250; public void setProperties(Socket socket) throws SocketException{ if (rxBufSize != null) socket.setReceiveBufferSize(rxBufSize.intValue()); if (txBufSize != null) socket.setSendBufferSize(txBufSize.intValue()); if (ooBInline !=null) socket.setOOBInline(ooBInline.booleanValue()); if (soKeepAlive != null) socket.setKeepAlive(soKeepAlive.booleanValue()); if (performanceConnectionTime != null && performanceLatency != null && performanceBandwidth != null) socket.setPerformancePreferences( performanceConnectionTime.intValue(), performanceLatency.intValue(), performanceBandwidth.intValue()); if (soReuseAddress != null) socket.setReuseAddress(soReuseAddress.booleanValue()); if (soLingerOn != null && soLingerTime != null) socket.setSoLinger(soLingerOn.booleanValue(), soLingerTime.intValue()); if (soTimeout != null && soTimeout.intValue() >= 0) socket.setSoTimeout(soTimeout.intValue()); if (tcpNoDelay != null) socket.setTcpNoDelay(tcpNoDelay.booleanValue()); } public void setProperties(ServerSocket socket) throws SocketException{ if (rxBufSize != null) socket.setReceiveBufferSize(rxBufSize.intValue()); if (performanceConnectionTime != null && performanceLatency != null && performanceBandwidth != null) socket.setPerformancePreferences( performanceConnectionTime.intValue(), performanceLatency.intValue(), performanceBandwidth.intValue()); if (soReuseAddress != null) socket.setReuseAddress(soReuseAddress.booleanValue()); if (soTimeout != null && soTimeout.intValue() >= 0) socket.setSoTimeout(soTimeout.intValue()); } public boolean getDirectBuffer() { return directBuffer; } public boolean getOoBInline() { return ooBInline.booleanValue(); } public int getPerformanceBandwidth() { return performanceBandwidth.intValue(); } public int getPerformanceConnectionTime() { return performanceConnectionTime.intValue(); } public int getPerformanceLatency() { return performanceLatency.intValue(); } public int getRxBufSize() { return rxBufSize.intValue(); } public boolean getSoKeepAlive() { return soKeepAlive.booleanValue(); } public boolean getSoLingerOn() { return soLingerOn.booleanValue(); } public int getSoLingerTime() { return soLingerTime.intValue(); } public boolean getSoReuseAddress() { return soReuseAddress.booleanValue(); } public int getSoTimeout() { return soTimeout.intValue(); } public boolean getTcpNoDelay() { return tcpNoDelay.booleanValue(); } public int getTxBufSize() { return txBufSize.intValue(); } public int getBufferPool() { return bufferPool; } public int getBufferPoolSize() { return bufferPoolSize; } public int getEventCache() { return eventCache; } public int getKeyCache() { return keyCache; } public int getAppReadBufSize() { return appReadBufSize; } public int getAppWriteBufSize() { return appWriteBufSize; } public int getProcessorCache() { return processorCache; } public long getTimeoutInterval() { return timeoutInterval; } public int getDirectBufferPool() { return bufferPool; } public void setPerformanceConnectionTime(int performanceConnectionTime) { this.performanceConnectionTime = Integer.valueOf(performanceConnectionTime); } public void setTxBufSize(int txBufSize) { this.txBufSize = Integer.valueOf(txBufSize); } public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = Boolean.valueOf(tcpNoDelay); } public void setSoTimeout(int soTimeout) { this.soTimeout = Integer.valueOf(soTimeout); } public void setSoReuseAddress(boolean soReuseAddress) { this.soReuseAddress = Boolean.valueOf(soReuseAddress); } public void setSoLingerTime(int soLingerTime) { this.soLingerTime = Integer.valueOf(soLingerTime); } public void setSoKeepAlive(boolean soKeepAlive) { this.soKeepAlive = Boolean.valueOf(soKeepAlive); } public void setRxBufSize(int rxBufSize) { this.rxBufSize = Integer.valueOf(rxBufSize); } public void setPerformanceLatency(int performanceLatency) { this.performanceLatency = Integer.valueOf(performanceLatency); } public void setPerformanceBandwidth(int performanceBandwidth) { this.performanceBandwidth = Integer.valueOf(performanceBandwidth); } public void setOoBInline(boolean ooBInline) { this.ooBInline = Boolean.valueOf(ooBInline); } public void setDirectBuffer(boolean directBuffer) { this.directBuffer = directBuffer; } public void setSoLingerOn(boolean soLingerOn) { this.soLingerOn = Boolean.valueOf(soLingerOn); } public void setBufferPool(int bufferPool) { this.bufferPool = bufferPool; } public void setBufferPoolSize(int bufferPoolSize) { this.bufferPoolSize = bufferPoolSize; } public void setEventCache(int eventCache) { this.eventCache = eventCache; } public void setKeyCache(int keyCache) { this.keyCache = keyCache; } public void setAppReadBufSize(int appReadBufSize) { this.appReadBufSize = appReadBufSize; } public void setAppWriteBufSize(int appWriteBufSize) { this.appWriteBufSize = appWriteBufSize; } public void setProcessorCache(int processorCache) { this.processorCache = processorCache; } public void setTimeoutInterval(long timeoutInterval) { this.timeoutInterval = timeoutInterval; } public void setDirectBufferPool(int directBufferPool) { this.bufferPool = directBufferPool; } public int getUnlockTimeout() { return unlockTimeout; } public void setUnlockTimeout(int unlockTimeout) { this.unlockTimeout = unlockTimeout; } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/NioSelectorPool.java0000644000175100017510000003140212271452644025060 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.EOFException; import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * * Thread safe non blocking selector pool * @author Filip Hanik * @version 1.0 * @since 6.0 */ public class NioSelectorPool { public NioSelectorPool() { } private static final Log log = LogFactory.getLog(NioSelectorPool.class); protected static final boolean SHARED = Boolean.valueOf(System.getProperty("org.apache.tomcat.util.net.NioSelectorShared", "true")).booleanValue(); protected NioBlockingSelector blockingSelector; protected volatile Selector SHARED_SELECTOR; protected int maxSelectors = 200; protected long sharedSelectorTimeout = 30000; protected int maxSpareSelectors = -1; protected boolean enabled = true; protected AtomicInteger active = new AtomicInteger(0); protected AtomicInteger spare = new AtomicInteger(0); protected ConcurrentLinkedQueue selectors = new ConcurrentLinkedQueue(); protected Selector getSharedSelector() throws IOException { if (SHARED && SHARED_SELECTOR == null) { synchronized ( NioSelectorPool.class ) { if ( SHARED_SELECTOR == null ) { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 SHARED_SELECTOR = Selector.open(); } log.info("Using a shared selector for servlet write/read"); } } } return SHARED_SELECTOR; } public Selector get() throws IOException{ if ( SHARED ) { return getSharedSelector(); } if ( (!enabled) || active.incrementAndGet() >= maxSelectors ) { if ( enabled ) active.decrementAndGet(); return null; } Selector s = null; try { s = selectors.size()>0?selectors.poll():null; if (s == null) { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 s = Selector.open(); } } else spare.decrementAndGet(); }catch (NoSuchElementException x ) { try { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 s = Selector.open(); } } catch (IOException iox) { } } finally { if ( s == null ) active.decrementAndGet();//we were unable to find a selector } return s; } public void put(Selector s) throws IOException { if ( SHARED ) return; if ( enabled ) active.decrementAndGet(); if ( enabled && (maxSpareSelectors==-1 || spare.get() < Math.min(maxSpareSelectors,maxSelectors)) ) { spare.incrementAndGet(); selectors.offer(s); } else s.close(); } public void close() throws IOException { enabled = false; Selector s; while ( (s = selectors.poll()) != null ) s.close(); spare.set(0); active.set(0); if (blockingSelector!=null) { blockingSelector.close(); } if ( SHARED && getSharedSelector()!=null ) { getSharedSelector().close(); SHARED_SELECTOR = null; } } public void open() throws IOException { enabled = true; getSharedSelector(); if (SHARED) { blockingSelector = new NioBlockingSelector(); blockingSelector.open(getSharedSelector()); } } /** * Performs a blocking write using the bytebuffer for data to be written and a selector to block. * If the selector parameter is null, then it will perform a busy write that could * take up a lot of CPU cycles. * @param buf ByteBuffer - the buffer containing the data, we will write as long as (buf.hasRemaining()==true) * @param socket SocketChannel - the socket to write data to * @param selector Selector - the selector to use for blocking, if null then a busy write will be initiated * @param writeTimeout long - the timeout for this write operation in milliseconds, -1 means no timeout * @return int - returns the number of bytes written * @throws EOFException if write returns -1 * @throws SocketTimeoutException if the write times out * @throws IOException if an IO Exception occurs in the underlying socket logic */ public int write(ByteBuffer buf, NioChannel socket, Selector selector, long writeTimeout) throws IOException { return write(buf,socket,selector,writeTimeout,true); } public int write(ByteBuffer buf, NioChannel socket, Selector selector, long writeTimeout, boolean block) throws IOException { if ( SHARED && block ) { return blockingSelector.write(buf,socket,writeTimeout); } SelectionKey key = null; int written = 0; boolean timedout = false; int keycount = 1; //assume we can write long time = System.currentTimeMillis(); //start the timeout timer try { while ( (!timedout) && buf.hasRemaining() ) { int cnt = 0; if ( keycount > 0 ) { //only write if we were registered for a write cnt = socket.write(buf); //write the data if (cnt == -1) throw new EOFException(); written += cnt; if (cnt > 0) { time = System.currentTimeMillis(); //reset our timeout timer continue; //we successfully wrote, try again without a selector } if (cnt==0 && (!block)) break; //don't block } if ( selector != null ) { //register OP_WRITE to the selector if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_WRITE); else key.interestOps(SelectionKey.OP_WRITE); keycount = selector.select(writeTimeout); } if (writeTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=writeTimeout; }//while if ( timedout ) throw new SocketTimeoutException(); } finally { if (key != null) { key.cancel(); if (selector != null) selector.selectNow();//removes the key from this selector } } return written; } /** * Performs a blocking read using the bytebuffer for data to be read and a selector to block. * If the selector parameter is null, then it will perform a busy read that could * take up a lot of CPU cycles. * @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out * @param socket SocketChannel - the socket to write data to * @param selector Selector - the selector to use for blocking, if null then a busy read will be initiated * @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout * @return int - returns the number of bytes read * @throws EOFException if read returns -1 * @throws SocketTimeoutException if the read times out * @throws IOException if an IO Exception occurs in the underlying socket logic */ public int read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout) throws IOException { return read(buf,socket,selector,readTimeout,true); } /** * Performs a read using the bytebuffer for data to be read and a selector to register for events should * you have the block=true. * If the selector parameter is null, then it will perform a busy read that could * take up a lot of CPU cycles. * @param buf ByteBuffer - the buffer containing the data, we will read as until we have read at least one byte or we timed out * @param socket SocketChannel - the socket to write data to * @param selector Selector - the selector to use for blocking, if null then a busy read will be initiated * @param readTimeout long - the timeout for this read operation in milliseconds, -1 means no timeout * @param block - true if you want to block until data becomes available or timeout time has been reached * @return int - returns the number of bytes read * @throws EOFException if read returns -1 * @throws SocketTimeoutException if the read times out * @throws IOException if an IO Exception occurs in the underlying socket logic */ public int read(ByteBuffer buf, NioChannel socket, Selector selector, long readTimeout, boolean block) throws IOException { if ( SHARED && block ) { return blockingSelector.read(buf,socket,readTimeout); } SelectionKey key = null; int read = 0; boolean timedout = false; int keycount = 1; //assume we can write long time = System.currentTimeMillis(); //start the timeout timer try { while ( (!timedout) ) { int cnt = 0; if ( keycount > 0 ) { //only read if we were registered for a read cnt = socket.read(buf); if (cnt == -1) throw new EOFException(); read += cnt; if (cnt > 0) continue; //read some more if (cnt==0 && (read>0 || (!block) ) ) break; //we are done reading } if ( selector != null ) {//perform a blocking read //register OP_WRITE to the selector if (key==null) key = socket.getIOChannel().register(selector, SelectionKey.OP_READ); else key.interestOps(SelectionKey.OP_READ); keycount = selector.select(readTimeout); } if (readTimeout > 0 && (selector == null || keycount == 0) ) timedout = (System.currentTimeMillis()-time)>=readTimeout; }//while if ( timedout ) throw new SocketTimeoutException(); } finally { if (key != null) { key.cancel(); if (selector != null) selector.selectNow();//removes the key from this selector } } return read; } public void setMaxSelectors(int maxSelectors) { this.maxSelectors = maxSelectors; } public void setMaxSpareSelectors(int maxSpareSelectors) { this.maxSpareSelectors = maxSpareSelectors; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public void setSharedSelectorTimeout(long sharedSelectorTimeout) { this.sharedSelectorTimeout = sharedSelectorTimeout; } public int getMaxSelectors() { return maxSelectors; } public int getMaxSpareSelectors() { return maxSpareSelectors; } public boolean isEnabled() { return enabled; } public long getSharedSelectorTimeout() { return sharedSelectorTimeout; } public ConcurrentLinkedQueue getSelectors() { return selectors; } public AtomicInteger getSpare() { return spare; } }tomcat7-7.0.52/java/org/apache/tomcat/util/net/NioEndpoint.java0000644000175100017510000020702512271452644024234 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.FileChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.WritableByteChannel; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.X509KeyManager; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; import org.apache.tomcat.util.net.jsse.NioX509KeyManager; /** * NIO tailored thread pool, providing the following services: *
      *
    • Socket acceptor thread
    • *
    • Socket poller thread
    • *
    • Worker threads pool
    • *
    * * When switching to Java 5, there's an opportunity to use the virtual * machine's thread pool. * * @author Mladen Turk * @author Remy Maucherat * @author Filip Hanik */ public class NioEndpoint extends AbstractEndpoint { // -------------------------------------------------------------- Constants private static final Log log = LogFactory.getLog(NioEndpoint.class); public static final int OP_REGISTER = 0x100; //register interest op public static final int OP_CALLBACK = 0x200; //callback interest op // ----------------------------------------------------------------- Fields protected NioSelectorPool selectorPool = new NioSelectorPool(); /** * Server socket "pointer". */ protected ServerSocketChannel serverSock = null; /** * use send file */ protected boolean useSendfile = true; /** * The size of the OOM parachute. */ protected int oomParachute = 1024*1024; /** * The oom parachute, when an OOM error happens, * will release the data, giving the JVM instantly * a chunk of data to be able to recover with. */ protected byte[] oomParachuteData = null; /** * Make sure this string has already been allocated */ protected static final String oomParachuteMsg = "SEVERE:Memory usage is low, parachute is non existent, your system may start failing."; /** * Keep track of OOM warning messages. */ long lastParachuteCheck = System.currentTimeMillis(); /** * */ protected volatile CountDownLatch stopLatch = null; /** * Cache for SocketProcessor objects */ protected ConcurrentLinkedQueue processorCache = new ConcurrentLinkedQueue() { private static final long serialVersionUID = 1L; protected AtomicInteger size = new AtomicInteger(0); @Override public boolean offer(SocketProcessor sc) { sc.reset(null,null); boolean offer = socketProperties.getProcessorCache()==-1?true:size.get() keyCache = new ConcurrentLinkedQueue() { private static final long serialVersionUID = 1L; protected AtomicInteger size = new AtomicInteger(0); @Override public boolean offer(KeyAttachment ka) { ka.reset(); boolean offer = socketProperties.getKeyCache()==-1?true:size.get() eventCache = new ConcurrentLinkedQueue() { private static final long serialVersionUID = 1L; protected AtomicInteger size = new AtomicInteger(0); @Override public boolean offer(PollerEvent pe) { pe.reset(); boolean offer = socketProperties.getEventCache()==-1?true:size.get() nioChannels = new ConcurrentLinkedQueue() { private static final long serialVersionUID = 1L; protected AtomicInteger size = new AtomicInteger(0); protected AtomicInteger bytes = new AtomicInteger(0); @Override public boolean offer(NioChannel socket) { boolean offer = socketProperties.getBufferPool()==-1?true:size.get()10000) { try { log.fatal(oomParachuteMsg); }catch (Throwable t) { ExceptionUtils.handleThrowable(t); System.err.println(oomParachuteMsg); } lastParachuteCheck = System.currentTimeMillis(); } } protected boolean reclaimParachute(boolean force) { if ( oomParachuteData != null ) return true; if ( oomParachute > 0 && ( force || (Runtime.getRuntime().freeMemory() > (oomParachute*2))) ) oomParachuteData = new byte[oomParachute]; return oomParachuteData != null; } protected void releaseCaches() { this.keyCache.clear(); this.nioChannels.clear(); this.processorCache.clear(); if ( handler != null ) handler.recycle(); } // --------------------------------------------------------- Public Methods /** * Number of keepalive sockets. */ public int getKeepAliveCount() { if (pollers == null) { return 0; } else { int sum = 0; for (int i=0; i0) reclaimParachute(true); selectorPool.open(); } public KeyManager[] wrap(KeyManager[] managers) { if (managers==null) return null; KeyManager[] result = new KeyManager[managers.length]; for (int i=0; i events = new ConcurrentLinkedQueue(); protected volatile boolean close = false; protected long nextExpiration = 0;//optimize expiration handling protected AtomicLong wakeupCounter = new AtomicLong(0l); protected volatile int keyCount = 0; public Poller() throws IOException { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 this.selector = Selector.open(); } } public int getKeyCount() { return keyCount; } public Selector getSelector() { return selector;} /** * Destroy the poller. */ protected void destroy() { // Wait for polltime before doing anything, so that the poller threads // exit, otherwise parallel closure of sockets which are still // in the poller can cause problems close = true; selector.wakeup(); } /** * Only used in this class. Will be made private in Tomcat 8.0.x * @deprecated */ @Deprecated public void addEvent(Runnable event) { events.offer(event); if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup(); } /** * Unused. Will be removed in Tomcat 8.0.x * @deprecated */ @Deprecated public void cometInterest(NioChannel socket) { KeyAttachment att = (KeyAttachment)socket.getAttachment(false); add(socket,att.getCometOps()); if ( (att.getCometOps()&OP_CALLBACK) == OP_CALLBACK ) { nextExpiration = 0; //force the check for faster callback selector.wakeup(); } } /** * Add specified socket and associated pool to the poller. The socket will * be added to a temporary array, and polled first after a maximum amount * of time equal to pollTime (in most cases, latency will be much lower, * however). * * @param socket to add to the poller */ public void add(final NioChannel socket) { add(socket,SelectionKey.OP_READ); } public void add(final NioChannel socket, final int interestOps) { PollerEvent r = eventCache.poll(); if ( r==null) r = new PollerEvent(socket,null,interestOps); else r.reset(socket,null,interestOps); addEvent(r); if (close) { processSocket(socket, SocketStatus.STOP, false); } } /** * Processes events in the event queue of the Poller. * * @return true if some events were processed, * false if queue was empty */ public boolean events() { boolean result = false; Runnable r = null; while ( (r = events.poll()) != null ) { result = true; try { r.run(); if ( r instanceof PollerEvent ) { ((PollerEvent)r).reset(); eventCache.offer((PollerEvent)r); } } catch ( Throwable x ) { log.error("",x); } } return result; } public void register(final NioChannel socket) { socket.setPoller(this); KeyAttachment key = keyCache.poll(); final KeyAttachment ka = key!=null?key:new KeyAttachment(socket); ka.reset(this,socket,getSocketProperties().getSoTimeout()); ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests()); ka.setSecure(isSSLEnabled()); PollerEvent r = eventCache.poll(); ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into. if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER); else r.reset(socket,ka,OP_REGISTER); addEvent(r); } public void cancelledKey(SelectionKey key, SocketStatus status, boolean dispatch) { try { if ( key == null ) return;//nothing to do KeyAttachment ka = (KeyAttachment) key.attachment(); if (ka != null && ka.isComet() && status != null) { //the comet event takes care of clean up //processSocket(ka.getChannel(), status, dispatch); ka.setComet(false);//to avoid a loop if (status == SocketStatus.TIMEOUT ) { if (processSocket(ka.getChannel(), status, true)) { return; // don't close on comet timeout } } else { processSocket(ka.getChannel(), status, false); //don't dispatch if the lines below are cancelling the key } } key.attach(null); if (ka!=null) handler.release(ka); else handler.release((SocketChannel)key.channel()); if (key.isValid()) key.cancel(); if (key.channel().isOpen()) { try { key.channel().close(); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString( "endpoint.debug.channelCloseFail"), e); } } } try { if (ka!=null) { ka.getSocket().close(true); } } catch (Exception e){ if (log.isDebugEnabled()) { log.debug(sm.getString( "endpoint.debug.socketCloseFail"), e); } } try { if (ka != null && ka.getSendfileData() != null && ka.getSendfileData().fchannel != null && ka.getSendfileData().fchannel.isOpen()) { ka.getSendfileData().fchannel.close(); } } catch (Exception ignore) { } if (ka!=null) { ka.reset(); countDownConnection(); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); if (log.isDebugEnabled()) log.error("",e); } } /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ @Override public void run() { // Loop until destroy() is called while (true) { try { // Loop if endpoint is paused while (paused && (!close) ) { try { Thread.sleep(100); } catch (InterruptedException e) { // Ignore } } boolean hasEvents = false; // Time to terminate? if (close) { events(); timeout(0, false); try { selector.close(); } catch (IOException ioe) { log.error(sm.getString( "endpoint.nio.selectorCloseFail"), ioe); } break; } else { hasEvents = events(); } try { if ( !close ) { if (wakeupCounter.getAndSet(-1) > 0) { //if we are here, means we have other stuff to do //do a non blocking select keyCount = selector.selectNow(); } else { keyCount = selector.select(selectorTimeout); } wakeupCounter.set(0); } if (close) { events(); timeout(0, false); try { selector.close(); } catch (IOException ioe) { log.error(sm.getString( "endpoint.nio.selectorCloseFail"), ioe); } break; } } catch ( NullPointerException x ) { //sun bug 5076772 on windows JDK 1.5 if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x); if ( wakeupCounter == null || selector == null ) throw x; continue; } catch ( CancelledKeyException x ) { //sun bug 5076772 on windows JDK 1.5 if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x); if ( wakeupCounter == null || selector == null ) throw x; continue; } catch (Throwable x) { ExceptionUtils.handleThrowable(x); log.error("",x); continue; } //either we timed out or we woke up, process events first if ( keyCount == 0 ) hasEvents = (hasEvents | events()); Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; // Walk through the collection of ready keys and dispatch // any active event. while (iterator != null && iterator.hasNext()) { SelectionKey sk = iterator.next(); KeyAttachment attachment = (KeyAttachment)sk.attachment(); // Attachment may be null if another thread has called // cancelledKey() if (attachment == null) { iterator.remove(); } else { attachment.access(); iterator.remove(); processKey(sk, attachment); } }//while //process timeouts timeout(keyCount,hasEvents); if ( oomParachute > 0 && oomParachuteData == null ) checkParachute(); } catch (OutOfMemoryError oom) { try { oomParachuteData = null; releaseCaches(); log.error("", oom); }catch ( Throwable oomt ) { try { System.err.println(oomParachuteMsg); oomt.printStackTrace(); }catch (Throwable letsHopeWeDontGetHere){ ExceptionUtils.handleThrowable(letsHopeWeDontGetHere); } } } }//while synchronized (this) { this.notifyAll(); } stopLatch.countDown(); } protected boolean processKey(SelectionKey sk, KeyAttachment attachment) { boolean result = true; try { if ( close ) { cancelledKey(sk, SocketStatus.STOP, attachment.comet); } else if ( sk.isValid() && attachment != null ) { attachment.access();//make sure we don't time out valid sockets sk.attach(attachment);//cant remember why this is here NioChannel channel = attachment.getChannel(); if (sk.isReadable() || sk.isWritable() ) { if ( attachment.getSendfileData() != null ) { processSendfile(sk,attachment, false); } else { if ( isWorkerAvailable() ) { unreg(sk, attachment, sk.readyOps()); boolean closeSocket = false; // Read goes before write if (sk.isReadable()) { if (!processSocket(channel, SocketStatus.OPEN_READ, true)) { closeSocket = true; } } if (!closeSocket && sk.isWritable()) { if (!processSocket(channel, SocketStatus.OPEN_WRITE, true)) { closeSocket = true; } } if (closeSocket) { cancelledKey(sk,SocketStatus.DISCONNECT,false); } } else { result = false; } } } } else { //invalid key cancelledKey(sk, SocketStatus.ERROR,false); } } catch ( CancelledKeyException ckx ) { cancelledKey(sk, SocketStatus.ERROR,false); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("",t); } return result; } /** * @deprecated Replaced by processSendfile(sk, attachment, event) */ @Deprecated public boolean processSendfile(SelectionKey sk, KeyAttachment attachment, @SuppressWarnings("unused") boolean reg, boolean event) { return processSendfile(sk, attachment, event); } public boolean processSendfile(SelectionKey sk, KeyAttachment attachment, boolean event) { NioChannel sc = null; try { unreg(sk, attachment, sk.readyOps()); SendfileData sd = attachment.getSendfileData(); if (log.isTraceEnabled()) { log.trace("Processing send file for: " + sd.fileName); } //setup the file channel if ( sd.fchannel == null ) { File f = new File(sd.fileName); if ( !f.exists() ) { cancelledKey(sk,SocketStatus.ERROR,false); return false; } @SuppressWarnings("resource") // Closed when channel is closed FileInputStream fis = new FileInputStream(f); sd.fchannel = fis.getChannel(); } //configure output channel sc = attachment.getChannel(); sc.setSendFile(true); //ssl channel is slightly different WritableByteChannel wc = ((sc instanceof SecureNioChannel)?sc:sc.getIOChannel()); //we still have data in the buffer if (sc.getOutboundRemaining()>0) { if (sc.flushOutbound()) { attachment.access(); } } else { long written = sd.fchannel.transferTo(sd.pos,sd.length,wc); if ( written > 0 ) { sd.pos += written; sd.length -= written; attachment.access(); } else { // Unusual not to be able to transfer any bytes // Check the length was set correctly if (sd.fchannel.size() <= sd.pos) { throw new IOException("Sendfile configured to " + "send more data than was available"); } } } if ( sd.length <= 0 && sc.getOutboundRemaining()<=0) { if (log.isDebugEnabled()) { log.debug("Send file complete for: "+sd.fileName); } attachment.setSendfileData(null); try { sd.fchannel.close(); } catch (Exception ignore) { } if ( sd.keepAlive ) { if (log.isDebugEnabled()) { log.debug("Connection is keep alive, registering back for OP_READ"); } if (event) { this.add(attachment.getChannel(),SelectionKey.OP_READ); } else { reg(sk,attachment,SelectionKey.OP_READ); } } else { if (log.isDebugEnabled()) { log.debug("Send file connection is being closed"); } cancelledKey(sk,SocketStatus.STOP,false); return false; } } else { if (log.isDebugEnabled()) { log.debug("OP_WRITE for sendfile: " + sd.fileName); } if (event) { add(attachment.getChannel(),SelectionKey.OP_WRITE); } else { reg(sk,attachment,SelectionKey.OP_WRITE); } } }catch ( IOException x ) { if ( log.isDebugEnabled() ) log.debug("Unable to complete sendfile request:", x); cancelledKey(sk,SocketStatus.ERROR,false); return false; }catch ( Throwable t ) { log.error("",t); cancelledKey(sk, SocketStatus.ERROR, false); return false; }finally { if (sc!=null) sc.setSendFile(false); } return true; } protected void unreg(SelectionKey sk, KeyAttachment attachment, int readyOps) { //this is a must, so that we don't have multiple threads messing with the socket reg(sk,attachment,sk.interestOps()& (~readyOps)); } protected void reg(SelectionKey sk, KeyAttachment attachment, int intops) { sk.interestOps(intops); attachment.interestOps(intops); attachment.setCometOps(intops); } protected void timeout(int keyCount, boolean hasEvents) { long now = System.currentTimeMillis(); // This method is called on every loop of the Poller. Don't process // timeouts on every loop of the Poller since that would create too // much load and timeouts can afford to wait a few seconds. // However, do process timeouts if any of the following are true: // - the selector simply timed out (suggests there isn't much load) // - the nextExpiration time has passed // - the server socket is being closed if ((keyCount > 0 || hasEvents) && (now < nextExpiration) && !close) { return; } //timeout Set keys = selector.keys(); int keycount = 0; for (Iterator iter = keys.iterator(); iter.hasNext();) { SelectionKey key = iter.next(); keycount++; try { KeyAttachment ka = (KeyAttachment) key.attachment(); if ( ka == null ) { cancelledKey(key, SocketStatus.ERROR,false); //we don't support any keys without attachments } else if ( ka.getError() ) { cancelledKey(key, SocketStatus.ERROR,true);//TODO this is not yet being used } else if (ka.isComet() && ka.getCometNotify() ) { ka.setCometNotify(false); reg(key,ka,0);//avoid multiple calls, this gets reregistered after invocation //if (!processSocket(ka.getChannel(), SocketStatus.OPEN_CALLBACK)) processSocket(ka.getChannel(), SocketStatus.DISCONNECT); if (!processSocket(ka.getChannel(), SocketStatus.OPEN_READ, true)) processSocket(ka.getChannel(), SocketStatus.DISCONNECT, true); } else if ((ka.interestOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ || (ka.interestOps()&SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) { //only timeout sockets that we are waiting for a read from long delta = now - ka.getLastAccess(); long timeout = ka.getTimeout(); boolean isTimedout = timeout > 0 && delta > timeout; if ( close ) { key.interestOps(0); ka.interestOps(0); //avoid duplicate stop calls processKey(key,ka); } else if (isTimedout) { key.interestOps(0); ka.interestOps(0); //avoid duplicate timeout calls cancelledKey(key, SocketStatus.TIMEOUT,true); } } else if (ka.isAsync() || ka.isComet()) { if (close) { key.interestOps(0); ka.interestOps(0); //avoid duplicate stop calls processKey(key,ka); } else if (!ka.isAsync() || ka.getTimeout() > 0) { // Async requests with a timeout of 0 or less never timeout long delta = now - ka.getLastAccess(); long timeout = (ka.getTimeout()==-1)?((long) socketProperties.getSoTimeout()):(ka.getTimeout()); boolean isTimedout = delta > timeout; if (isTimedout) { // Prevent subsequent timeouts if the timeout event takes a while to process ka.access(Long.MAX_VALUE); processSocket(ka.getChannel(), SocketStatus.TIMEOUT, true); } } }//end if }catch ( CancelledKeyException ckx ) { cancelledKey(key, SocketStatus.ERROR,false); } }//for long prevExp = nextExpiration; //for logging purposes only nextExpiration = System.currentTimeMillis() + socketProperties.getTimeoutInterval(); if (log.isTraceEnabled()) { log.trace("timeout completed: keys processed=" + keycount + "; now=" + now + "; nextExpiration=" + prevExp + "; keyCount=" + keyCount + "; hasEvents=" + hasEvents + "; eval=" + ((now < prevExp) && (keyCount>0 || hasEvents) && (!close) )); } } } // ----------------------------------------------------- Key Attachment Class public static class KeyAttachment extends SocketWrapper { public KeyAttachment(NioChannel channel) { super(channel); } public void reset(Poller poller, NioChannel channel, long soTimeout) { super.reset(channel, soTimeout); cometNotify = false; cometOps = SelectionKey.OP_READ; interestOps = 0; this.poller = poller; lastRegistered = 0; sendfileData = null; if (readLatch != null) { try { for (int i = 0; i < (int) readLatch.getCount(); i++) { readLatch.countDown(); } } catch (Exception ignore) { } } readLatch = null; sendfileData = null; if (writeLatch != null) { try { for (int i = 0; i < (int) writeLatch.getCount(); i++) { writeLatch.countDown(); } } catch (Exception ignore) { } } writeLatch = null; setWriteTimeout(soTimeout); } public void reset() { reset(null,null,-1); } public Poller getPoller() { return poller;} public void setPoller(Poller poller){this.poller = poller;} public void setCometNotify(boolean notify) { this.cometNotify = notify; } public boolean getCometNotify() { return cometNotify; } /** * @deprecated Unused (value is set but never read) - will be removed in * Tomcat 8 */ @Deprecated public void setCometOps(int ops) { this.cometOps = ops; } /** * @deprecated Unused - will be removed in Tomcat 8 */ @Deprecated public int getCometOps() { return cometOps; } public NioChannel getChannel() { return getSocket();} public void setChannel(NioChannel channel) { this.socket = channel;} protected Poller poller = null; protected int interestOps = 0; public int interestOps() { return interestOps;} public int interestOps(int ops) { this.interestOps = ops; return ops; } public CountDownLatch getReadLatch() { return readLatch; } public CountDownLatch getWriteLatch() { return writeLatch; } protected CountDownLatch resetLatch(CountDownLatch latch) { if ( latch==null || latch.getCount() == 0 ) return null; else throw new IllegalStateException("Latch must be at count 0"); } public void resetReadLatch() { readLatch = resetLatch(readLatch); } public void resetWriteLatch() { writeLatch = resetLatch(writeLatch); } protected CountDownLatch startLatch(CountDownLatch latch, int cnt) { if ( latch == null || latch.getCount() == 0 ) { return new CountDownLatch(cnt); } else throw new IllegalStateException("Latch must be at count 0 or null."); } public void startReadLatch(int cnt) { readLatch = startLatch(readLatch,cnt);} public void startWriteLatch(int cnt) { writeLatch = startLatch(writeLatch,cnt);} protected void awaitLatch(CountDownLatch latch, long timeout, TimeUnit unit) throws InterruptedException { if ( latch == null ) throw new IllegalStateException("Latch cannot be null"); latch.await(timeout,unit); } public void awaitReadLatch(long timeout, TimeUnit unit) throws InterruptedException { awaitLatch(readLatch,timeout,unit);} public void awaitWriteLatch(long timeout, TimeUnit unit) throws InterruptedException { awaitLatch(writeLatch,timeout,unit);} /** * @deprecated Unused - will be removed in Tomcat 8 */ @Deprecated public long getLastRegistered() { return lastRegistered; } /** * @deprecated Unused - will be removed in Tomcat 8 */ @Deprecated public void setLastRegistered(long reg) { lastRegistered = reg; } public void setSendfileData(SendfileData sf) { this.sendfileData = sf;} public SendfileData getSendfileData() { return this.sendfileData;} public void setWriteTimeout(long writeTimeout) { this.writeTimeout = writeTimeout; } public long getWriteTimeout() {return this.writeTimeout;} protected boolean comet = false; protected int cometOps = SelectionKey.OP_READ; protected boolean cometNotify = false; protected CountDownLatch readLatch = null; protected CountDownLatch writeLatch = null; protected SendfileData sendfileData = null; private long writeTimeout = -1; } // ------------------------------------------------ Application Buffer Handler public static class NioBufferHandler implements ApplicationBufferHandler { protected ByteBuffer readbuf = null; protected ByteBuffer writebuf = null; public NioBufferHandler(int readsize, int writesize, boolean direct) { if ( direct ) { readbuf = ByteBuffer.allocateDirect(readsize); writebuf = ByteBuffer.allocateDirect(writesize); }else { readbuf = ByteBuffer.allocate(readsize); writebuf = ByteBuffer.allocate(writesize); } } @Override public ByteBuffer expand(ByteBuffer buffer, int remaining) {return buffer;} @Override public ByteBuffer getReadBuffer() {return readbuf;} @Override public ByteBuffer getWriteBuffer() {return writebuf;} } // ------------------------------------------------ Handler Inner Interface /** * Bare bones interface used for socket processing. Per thread data is to be * stored in the ThreadWithAttributes extra folders, or alternately in * thread local fields. */ public interface Handler extends AbstractEndpoint.Handler { public SocketState process(SocketWrapper socket, SocketStatus status); public void release(SocketWrapper socket); public void release(SocketChannel socket); public SSLImplementation getSslImplementation(); } // ---------------------------------------------- SocketProcessor Inner Class /** * This class is the equivalent of the Worker, but will simply use in an * external Executor thread pool. */ protected class SocketProcessor implements Runnable { protected NioChannel socket = null; protected SocketStatus status = null; public SocketProcessor(NioChannel socket, SocketStatus status) { reset(socket,status); } public void reset(NioChannel socket, SocketStatus status) { this.socket = socket; this.status = status; } @Override public void run() { SelectionKey key = socket.getIOChannel().keyFor( socket.getPoller().getSelector()); KeyAttachment ka = null; if (key != null) { ka = (KeyAttachment)key.attachment(); } // Upgraded connections need to allow multiple threads to access the // connection at the same time to enable blocking IO to be used when // NIO has been configured if (ka != null && ka.isUpgraded() && SocketStatus.OPEN_WRITE == status) { synchronized (ka.getWriteThreadLock()) { doRun(key, ka); } } else { synchronized (socket) { doRun(key, ka); } } } private void doRun(SelectionKey key, KeyAttachment ka) { boolean launch = false; try { int handshake = -1; try { if (key != null) { // For STOP there is no point trying to handshake as the // Poller has been stopped. if (socket.isHandshakeComplete() || status == SocketStatus.STOP) { handshake = 0; } else { handshake = socket.handshake( key.isReadable(), key.isWritable()); // The handshake process reads/writes from/to the // socket. status may therefore be OPEN_WRITE once // the handshake completes. However, the handshake // happens when the socket is opened so the status // must always be OPEN_READ after it completes. It // is OK to always set this as it is only used if // the handshake completes. status = SocketStatus.OPEN_READ; } } }catch ( IOException x ) { handshake = -1; if ( log.isDebugEnabled() ) log.debug("Error during SSL handshake",x); }catch ( CancelledKeyException ckx ) { handshake = -1; } if ( handshake == 0 ) { SocketState state = SocketState.OPEN; // Process the request from this socket if (status == null) { state = handler.process(ka, SocketStatus.OPEN_READ); } else { state = handler.process(ka, status); } if (state == SocketState.CLOSED) { // Close socket and pool try { if (ka!=null) ka.setComet(false); socket.getPoller().cancelledKey(key, SocketStatus.ERROR, false); if (running && !paused) { nioChannels.offer(socket); } socket = null; if (running && !paused && ka!=null) { keyCache.offer(ka); } ka = null; } catch ( Exception x ) { log.error("",x); } } } else if (handshake == -1 ) { if (key != null) { socket.getPoller().cancelledKey(key, SocketStatus.DISCONNECT, false); } nioChannels.offer(socket); socket = null; if ( ka!=null ) keyCache.offer(ka); ka = null; } else { ka.getPoller().add(socket, handshake); } }catch(CancelledKeyException cx) { socket.getPoller().cancelledKey(key,null,false); } catch (OutOfMemoryError oom) { try { oomParachuteData = null; log.error("", oom); if (socket != null) { socket.getPoller().cancelledKey(key,SocketStatus.ERROR, false); } releaseCaches(); }catch ( Throwable oomt ) { try { System.err.println(oomParachuteMsg); oomt.printStackTrace(); }catch (Throwable letsHopeWeDontGetHere){ ExceptionUtils.handleThrowable(letsHopeWeDontGetHere); } } } catch (VirtualMachineError vme) { ExceptionUtils.handleThrowable(vme); }catch ( Throwable t ) { log.error("",t); if (socket != null) { socket.getPoller().cancelledKey(key,SocketStatus.ERROR,false); } } finally { if (launch) { try { getExecutor().execute(new SocketProcessor(socket, SocketStatus.OPEN_READ)); } catch (NullPointerException npe) { if (running) { log.error(sm.getString("endpoint.launch.fail"), npe); } } } socket = null; status = null; //return to cache if (running && !paused) { processorCache.offer(this); } } } } // ----------------------------------------------- SendfileData Inner Class /** * SendfileData class. */ public static class SendfileData { // File public String fileName; public FileChannel fchannel; public long pos; public long length; // KeepAlive flag public boolean keepAlive; } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/Constants.java0000644000175100017510000000227211500764705023755 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; public class Constants { /** * Name of the system property containing * the tomcat instance installation path */ public static final String CATALINA_BASE_PROP = "catalina.base"; /** * Has security been turned on? */ public static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); } tomcat7-7.0.52/java/org/apache/tomcat/util/net/URL.java0000644000175100017510000005330412271452644022447 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.Serializable; import java.net.MalformedURLException; import java.util.Locale; /** *

    URL is designed to provide public APIs for parsing * and synthesizing Uniform Resource Locators as similar as possible to the * APIs of java.net.URL, but without the ability to open a * stream or connection. One of the consequences of this is that you can * construct URLs for protocols for which a URLStreamHandler is not * available (such as an "https" URL when JSSE is not installed).

    * *

    WARNING - This class assumes that the string * representation of a URL conforms to the spec argument * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax": *

     *   <scheme>//<authority><path>?<query>#<fragment>
     * 

    * *

    FIXME - This class really ought to end up in a Commons * package someplace.

    * * @author Craig R. McClanahan */ public final class URL implements Serializable { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Create a URL object from the specified String representation. * * @param spec String representation of the URL * * @exception MalformedURLException if the string representation * cannot be parsed successfully */ public URL(String spec) throws MalformedURLException { this(null, spec); } /** * Create a URL object by parsing a string representation relative * to a specified context. Based on logic from JDK 1.3.1's * java.net.URL. * * @param context URL against which the relative representation * is resolved * @param spec String representation of the URL (usually relative) * * @exception MalformedURLException if the string representation * cannot be parsed successfully */ public URL(URL context, String spec) throws MalformedURLException { String original = spec; int i, limit, c; int start = 0; String newProtocol = null; boolean aRef = false; try { // Eliminate leading and trailing whitespace limit = spec.length(); while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) { limit--; } while ((start < limit) && (spec.charAt(start) <= ' ')) { start++; } // If the string representation starts with "url:", skip it if (spec.regionMatches(true, start, "url:", 0, 4)) { start += 4; } // Is this a ref relative to the context URL? if ((start < spec.length()) && (spec.charAt(start) == '#')) { aRef = true; } // Parse out the new protocol for (i = start; !aRef && (i < limit) ; i++) { c = spec.charAt(i); if (c == ':') { String s = spec.substring(start, i).toLowerCase(Locale.ENGLISH); // Assume all protocols are valid newProtocol = s; start = i + 1; break; } else if( c == '#' ) { aRef = true; } else if( !isSchemeChar((char)c) ) { break; } } // Only use our context if the protocols match protocol = newProtocol; if ((context != null) && ((newProtocol == null) || newProtocol.equalsIgnoreCase(context.getProtocol()))) { // If the context is a hierarchical URL scheme and the spec // contains a matching scheme then maintain backwards // compatibility and treat it as if the spec didn't contain // the scheme; see 5.2.3 of RFC2396 if ((context.getPath() != null) && (context.getPath().startsWith("/"))) newProtocol = null; if (newProtocol == null) { protocol = context.getProtocol(); authority = context.getAuthority(); userInfo = context.getUserInfo(); host = context.getHost(); port = context.getPort(); file = context.getFile(); int question = file.lastIndexOf("?"); if (question < 0) path = file; else path = file.substring(0, question); } } if (protocol == null) throw new MalformedURLException("no protocol: " + original); // Parse out any ref portion of the spec i = spec.indexOf('#', start); if (i >= 0) { ref = spec.substring(i + 1, limit); limit = i; } // Parse the remainder of the spec in a protocol-specific fashion parse(spec, start, limit); if (context != null) normalize(); } catch (MalformedURLException e) { throw e; } catch (Exception e) { throw new MalformedURLException(e.toString()); } } /** * Create a URL object from the specified components. The default port * number for the specified protocol will be used. * * @param protocol Name of the protocol to use * @param host Name of the host addressed by this protocol * @param file Filename on the specified host * * @exception MalformedURLException is never thrown, but present for * compatible APIs * * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated public URL(String protocol, String host, String file) throws MalformedURLException { this(protocol, host, -1, file); } /** * Create a URL object from the specified components. Specifying a port * number of -1 indicates that the URL should use the default port for * that protocol. Based on logic from JDK 1.3.1's * java.net.URL. * * @param protocol Name of the protocol to use * @param host Name of the host addressed by this protocol * @param port Port number, or -1 for the default port for this protocol * @param file Filename on the specified host * * @exception MalformedURLException is never thrown, but present for * compatible APIs * * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated public URL(String protocol, String host, int port, String file) throws MalformedURLException { this.protocol = protocol; this.host = host; this.port = port; int hash = file.indexOf('#'); this.file = hash < 0 ? file : file.substring(0, hash); this.ref = hash < 0 ? null : file.substring(hash + 1); int question = file.lastIndexOf('?'); if (question >= 0) { query = file.substring(question + 1); path = file.substring(0, question); } else path = file; if ((host != null) && (host.length() > 0)) authority = (port == -1) ? host : host + ":" + port; } // ----------------------------------------------------- Instance Variables /** * The authority part of the URL. */ private String authority = null; /** * The filename part of the URL. */ private String file = null; /** * The host name part of the URL. */ private String host = null; /** * The path part of the URL. */ private String path = null; /** * The port number part of the URL. */ private int port = -1; /** * The protocol name part of the URL. */ private String protocol = null; /** * The query part of the URL. */ private String query = null; /** * The reference part of the URL. */ private String ref = null; /** * The user info part of the URL. */ private String userInfo = null; // --------------------------------------------------------- Public Methods /** * Compare two URLs for equality. The result is true if and * only if the argument is not null, and is a URL object * that represents the same URL as this object. Two * URLs are equal if they have the same protocol and * reference the same host, the same port number on the host, * and the same file and anchor on the host. * * @param obj The URL to compare against */ @Override public boolean equals(Object obj) { if (!(obj instanceof URL)) return (false); URL other = (URL) obj; if (!sameFile(other)) return (false); return (compare(ref, other.getRef())); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((file == null) ? 0 : file.hashCode()); result = prime * result + ((host == null) ? 0 : host.hashCode()); result = prime * result + port; result = prime * result + ((protocol == null) ? 0 : protocol.hashCode()); result = prime * result + ((ref == null) ? 0 : ref.hashCode()); return result; } /** * Return the authority part of the URL. */ public String getAuthority() { return (this.authority); } /** * Return the filename part of the URL. NOTE - For * compatibility with java.net.URL, this value includes * the query string if there was one. For just the path portion, * call getPath() instead. */ public String getFile() { if (file == null) return (""); return (this.file); } /** * Return the host name part of the URL. */ public String getHost() { return (this.host); } /** * Return the path part of the URL. */ public String getPath() { if (this.path == null) return (""); return (this.path); } /** * Return the port number part of the URL. */ public int getPort() { return (this.port); } /** * Return the protocol name part of the URL. */ public String getProtocol() { return (this.protocol); } /** * Return the query part of the URL. */ public String getQuery() { return (this.query); } /** * Return the reference part of the URL. */ public String getRef() { return (this.ref); } /** * Return the user info part of the URL. */ public String getUserInfo() { return (this.userInfo); } /** * Normalize the path (and therefore file) * portions of this URL. *

    * NOTE - This method is not part of the public API * of java.net.URL, but is provided as a value added * service of this implementation. * * @exception MalformedURLException if a normalization error occurs, * such as trying to move about the hierarchical root */ public void normalize() throws MalformedURLException { // Special case for null path if (path == null) { if (query != null) file = "?" + query; else file = ""; return; } // Create a place for the normalized path String normalized = path; if (normalized.equals("/.")) { path = "/"; if (query != null) file = path + "?" + query; else file = path; return; } // Normalize the slashes and add leading slash if necessary if (normalized.indexOf('\\') >= 0) normalized = normalized.replace('\\', '/'); if (!normalized.startsWith("/")) normalized = "/" + normalized; // Resolve occurrences of "//" in the normalized path while (true) { int index = normalized.indexOf("//"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 1); } // Resolve occurrences of "/./" in the normalized path while (true) { int index = normalized.indexOf("/./"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 2); } // Resolve occurrences of "/../" in the normalized path while (true) { int index = normalized.indexOf("/../"); if (index < 0) break; if (index == 0) throw new MalformedURLException ("Invalid relative URL reference"); int index2 = normalized.lastIndexOf('/', index - 1); normalized = normalized.substring(0, index2) + normalized.substring(index + 3); } // Resolve occurrences of "/." at the end of the normalized path if (normalized.endsWith("/.")) normalized = normalized.substring(0, normalized.length() - 1); // Resolve occurrences of "/.." at the end of the normalized path if (normalized.endsWith("/..")) { int index = normalized.length() - 3; int index2 = normalized.lastIndexOf('/', index - 1); if (index2 < 0) throw new MalformedURLException ("Invalid relative URL reference"); normalized = normalized.substring(0, index2 + 1); } // Return the normalized path that we have completed path = normalized; if (query != null) file = path + "?" + query; else file = path; } /** * Compare two URLs, excluding the "ref" fields. Returns true * if this URL and the other argument both refer * to the same resource. The two URLs might not both contain * the same anchor. */ public boolean sameFile(URL other) { if (!compare(protocol, other.getProtocol())) return (false); if (!compare(host, other.getHost())) return (false); if (port != other.getPort()) return (false); if (!compare(file, other.getFile())) return (false); return (true); } /** * Return a string representation of this URL. This follow the rules in * RFC 2396, Section 5.2, Step 7. * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated public String toExternalForm() { StringBuilder sb = new StringBuilder(); if (protocol != null) { sb.append(protocol); sb.append(":"); } if (authority != null) { sb.append("//"); sb.append(authority); } if (path != null) sb.append(path); if (query != null) { sb.append('?'); sb.append(query); } if (ref != null) { sb.append('#'); sb.append(ref); } return (sb.toString()); } /** * Return a string representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("URL["); sb.append("authority="); sb.append(authority); sb.append(", file="); sb.append(file); sb.append(", host="); sb.append(host); sb.append(", port="); sb.append(port); sb.append(", protocol="); sb.append(protocol); sb.append(", query="); sb.append(query); sb.append(", ref="); sb.append(ref); sb.append(", userInfo="); sb.append(userInfo); sb.append("]"); return (sb.toString()); // return (toExternalForm()); } // -------------------------------------------------------- Private Methods /** * Compare to String values for equality, taking appropriate care if one * or both of the values are null. * * @param first First string * @param second Second string */ private boolean compare(String first, String second) { if (first == null) { if (second == null) return (true); else return (false); } else { if (second == null) return (false); else return (first.equals(second)); } } /** * Parse the specified portion of the string representation of a URL, * assuming that it has a format similar to that for http. * *

    FIXME - This algorithm can undoubtedly be optimized * for performance. However, that needs to wait until after sufficient * unit tests are implemented to guarantee correct behavior with no * regressions.

    * * @param spec String representation being parsed * @param start Starting offset, which will be just after the ':' (if * there is one) that determined the protocol name * @param limit Ending position, which will be the position of the '#' * (if there is one) that delimited the anchor * * @exception MalformedURLException if a parsing error occurs */ private void parse(String spec, int start, int limit) throws MalformedURLException { // Trim the query string (if any) off the tail end int question = spec.lastIndexOf('?', limit - 1); if ((question >= 0) && (question < limit)) { query = spec.substring(question + 1, limit); limit = question; } else { query = null; } // Parse the authority section if (spec.indexOf("//", start) == start) { int pathStart = spec.indexOf("/", start + 2); if ((pathStart >= 0) && (pathStart < limit)) { authority = spec.substring(start + 2, pathStart); start = pathStart; } else { authority = spec.substring(start + 2, limit); start = limit; } if (authority.length() > 0) { int at = authority.indexOf('@'); if( at >= 0 ) { userInfo = authority.substring(0,at); } int ipv6 = authority.indexOf('[',at+1); int hStart = at+1; if( ipv6 >= 0 ) { hStart = ipv6; ipv6 = authority.indexOf(']', ipv6); if( ipv6 < 0 ) { throw new MalformedURLException( "Closing ']' not found in IPV6 address: " + authority); } else { at = ipv6-1; } } int colon = authority.indexOf(':', at+1); if (colon >= 0) { try { port = Integer.parseInt(authority.substring(colon + 1)); } catch (NumberFormatException e) { throw new MalformedURLException(e.toString()); } host = authority.substring(hStart, colon); } else { host = authority.substring(hStart); port = -1; } } } // Parse the path section if (spec.indexOf("/", start) == start) { // Absolute path path = spec.substring(start, limit); if (query != null) file = path + "?" + query; else file = path; return; } // Resolve relative path against our context's file if (path == null) { if (query != null) file = "?" + query; else file = null; return; } if (!path.startsWith("/")) throw new MalformedURLException ("Base path does not start with '/'"); if (!path.endsWith("/")) path += "/../"; path += spec.substring(start, limit); if (query != null) file = path + "?" + query; else file = path; return; } /** * Determine if the character is allowed in the scheme of a URI. * See RFC 2396, Section 3.1 */ public static boolean isSchemeChar(char c) { return Character.isLetterOrDigit(c) || c == '+' || c == '-' || c == '.'; } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/ServerSocketFactory.java0000644000175100017510000000704012271452644025750 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; /** * The common interface through which the {@link JIoEndpoint} interacts with * both non-SSL and SSL sockets. */ public interface ServerSocketFactory { /** * Returns a server socket which uses all network interfaces on the host, * and is bound to a the specified port. The socket is configured with the * socket options (such as accept timeout) given to this factory. * * @param port * the port to listen to * @exception IOException * for networking errors * @exception InstantiationException * for construction errors */ ServerSocket createSocket(int port) throws IOException, InstantiationException; /** * Returns a server socket which uses all network interfaces on the host, is * bound to a the specified port, and uses the specified connection backlog. * The socket is configured with the socket options (such as accept timeout) * given to this factory. * * @param port * the port to listen to * @param backlog * how many connections are queued * @exception IOException * for networking errors * @exception InstantiationException * for construction errors */ ServerSocket createSocket(int port, int backlog) throws IOException, InstantiationException; /** * Returns a server socket which uses only the specified network interface * on the local host, is bound to a the specified port, and uses the * specified connection backlog. The socket is configured with the socket * options (such as accept timeout) given to this factory. * * @param port * the port to listen to * @param backlog * how many connections are queued * @param ifAddress * the network interface address to use * @exception IOException * for networking errors * @exception InstantiationException * for construction errors */ ServerSocket createSocket(int port, int backlog, InetAddress ifAddress) throws IOException, InstantiationException; /** * Wrapper function for accept(). This allows us to trap and translate * exceptions if necessary. * * @exception IOException */ Socket acceptSocket(ServerSocket socket) throws IOException; /** * Triggers the SSL handshake. This will be a no-op for non-SSL sockets. * * @exception IOException */ void handshake(Socket sock) throws IOException; } tomcat7-7.0.52/java/org/apache/tomcat/util/net/SocketWrapper.java0000644000175100017510000001203712276145206024572 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; public class SocketWrapper { protected volatile E socket; protected volatile long lastAccess = System.currentTimeMillis(); protected long timeout = -1; protected boolean error = false; protected long lastRegistered = 0; protected volatile int keepAliveLeft = 100; private boolean comet = false; protected boolean async = false; protected boolean keptAlive = false; private boolean upgraded = false; private boolean secure = false; /* * Used if block/non-blocking is set at the socket level. The client is * responsible for the thread-safe use of this field via the locks provided. */ private volatile boolean blockingStatus = true; private final Lock blockingStatusReadLock; private final WriteLock blockingStatusWriteLock; /* * In normal servlet processing only one thread is allowed to access the * socket at a time. That is controlled by a lock on the socket for both * read and writes). When HTTP upgrade is used, one read thread and one * write thread are allowed to access the socket concurrently. In this case * the lock on the socket is used for reads and the lock below is used for * writes. */ private final Object writeThreadLock = new Object(); public SocketWrapper(E socket) { this.socket = socket; ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); this.blockingStatusReadLock = lock.readLock(); this.blockingStatusWriteLock =lock.writeLock(); } public E getSocket() { return socket; } public boolean isComet() { return comet; } public void setComet(boolean comet) { this.comet = comet; } public boolean isAsync() { return async; } public void setAsync(boolean async) { this.async = async; } public boolean isUpgraded() { return upgraded; } public void setUpgraded(boolean upgraded) { this.upgraded = upgraded; } public boolean isSecure() { return secure; } public void setSecure(boolean secure) { this.secure = secure; } public long getLastAccess() { return lastAccess; } public void access() { // Async timeouts are based on the time between the call to startAsync() // and complete() / dispatch() so don't update the last access time // (that drives the timeout) on every read and write when using async // processing. if (!isAsync()) { access(System.currentTimeMillis()); } } public void access(long access) { lastAccess = access; } public void setTimeout(long timeout) {this.timeout = timeout;} public long getTimeout() {return this.timeout;} public boolean getError() { return error; } public void setError(boolean error) { this.error = error; } public void setKeepAliveLeft(int keepAliveLeft) { this.keepAliveLeft = keepAliveLeft;} public int decrementKeepAlive() { return (--keepAliveLeft);} public boolean isKeptAlive() {return keptAlive;} public void setKeptAlive(boolean keptAlive) {this.keptAlive = keptAlive;} public boolean getBlockingStatus() { return blockingStatus; } public void setBlockingStatus(boolean blockingStatus) { this.blockingStatus = blockingStatus; } public Lock getBlockingStatusReadLock() { return blockingStatusReadLock; } public WriteLock getBlockingStatusWriteLock() { return blockingStatusWriteLock; } public Object getWriteThreadLock() { return writeThreadLock; } public void reset(E socket, long timeout) { async = false; blockingStatus = true; comet = false; error = false; keepAliveLeft = 100; lastAccess = System.currentTimeMillis(); this.socket = socket; this.timeout = timeout; upgraded = false; } /** * Overridden for debug purposes. No guarantees are made about the format of * this message which may vary significantly between point releases. *

    * {@inheritDoc} */ @Override public String toString() { return super.toString() + ":" + String.valueOf(socket); } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/SocketStatus.java0000644000175100017510000000176112271452644024441 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; /** * Someone, please change the enum name. * * @author remm */ public enum SocketStatus { OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT, ERROR } tomcat7-7.0.52/java/org/apache/tomcat/util/net/JIoEndpoint.java0000644000175100017510000005266312271452644024176 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.IOException; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.RejectedExecutionException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; /** * Handle incoming TCP connections. * * This class implement a simple server model: one listener thread accepts on a socket and * creates a new worker thread for each incoming connection. * * More advanced Endpoints will reuse the threads, use queues, etc. * * @author James Duncan Davidson * @author Jason Hunter * @author James Todd * @author Costin Manolache * @author Gal Shachor * @author Yoav Shapira * @author Remy Maucherat */ public class JIoEndpoint extends AbstractEndpoint { // -------------------------------------------------------------- Constants private static final Log log = LogFactory.getLog(JIoEndpoint.class); // ----------------------------------------------------------------- Fields /** * Associated server socket. */ protected ServerSocket serverSocket = null; // ------------------------------------------------------------ Constructor public JIoEndpoint() { // Set maxConnections to zero so we can tell if the user has specified // their own value on the connector when we reach bind() setMaxConnections(0); // Reduce the executor timeout for BIO as threads in keep-alive will not // terminate when the executor interrupts them. setExecutorTerminationTimeoutMillis(0); } // ------------------------------------------------------------- Properties /** * Handling of accepted sockets. */ protected Handler handler = null; public void setHandler(Handler handler ) { this.handler = handler; } public Handler getHandler() { return handler; } /** * Server socket factory. */ protected ServerSocketFactory serverSocketFactory = null; public void setServerSocketFactory(ServerSocketFactory factory) { this.serverSocketFactory = factory; } public ServerSocketFactory getServerSocketFactory() { return serverSocketFactory; } /** * Port in use. */ @Override public int getLocalPort() { ServerSocket s = serverSocket; if (s == null) { return -1; } else { return s.getLocalPort(); } } /* * Optional feature support. */ @Override public boolean getUseSendfile() { return false; } // Not supported @Override public boolean getUseComet() { return false; } // Not supported @Override public boolean getUseCometTimeout() { return false; } // Not supported @Override public boolean getDeferAccept() { return false; } // Not supported @Override public boolean getUsePolling() { return false; } // Not supported // ------------------------------------------------ Handler Inner Interface /** * Bare bones interface used for socket processing. Per thread data is to be * stored in the ThreadWithAttributes extra folders, or alternately in * thread local fields. */ public interface Handler extends AbstractEndpoint.Handler { public SocketState process(SocketWrapper socket, SocketStatus status); public SSLImplementation getSslImplementation(); } /** * Async timeout thread */ protected class AsyncTimeout implements Runnable { /** * The background thread that checks async requests and fires the * timeout if there has been no activity. */ @Override public void run() { // Loop until we receive a shutdown command while (running) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } long now = System.currentTimeMillis(); Iterator> sockets = waitingRequests.iterator(); while (sockets.hasNext()) { SocketWrapper socket = sockets.next(); long access = socket.getLastAccess(); if (socket.getTimeout() > 0 && (now-access)>socket.getTimeout()) { processSocketAsync(socket,SocketStatus.TIMEOUT); } } // Loop if endpoint is paused while (paused && running) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } } } } // --------------------------------------------------- Acceptor Inner Class /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ protected class Acceptor extends AbstractEndpoint.Acceptor { @Override public void run() { int errorDelay = 0; // Loop until we receive a shutdown command while (running) { // Loop if endpoint is paused while (paused && running) { state = AcceptorState.PAUSED; try { Thread.sleep(50); } catch (InterruptedException e) { // Ignore } } if (!running) { break; } state = AcceptorState.RUNNING; try { //if we have reached max connections, wait countUpOrAwaitConnection(); Socket socket = null; try { // Accept the next incoming connection from the server // socket socket = serverSocketFactory.acceptSocket(serverSocket); } catch (IOException ioe) { countDownConnection(); // Introduce delay if necessary errorDelay = handleExceptionWithDelay(errorDelay); // re-throw throw ioe; } // Successful accept, reset the error delay errorDelay = 0; // Configure the socket if (running && !paused && setSocketOptions(socket)) { // Hand this socket off to an appropriate processor if (!processSocket(socket)) { countDownConnection(); // Close socket right away closeSocket(socket); } } else { countDownConnection(); // Close socket right away closeSocket(socket); } } catch (IOException x) { if (running) { log.error(sm.getString("endpoint.accept.fail"), x); } } catch (NullPointerException npe) { if (running) { log.error(sm.getString("endpoint.accept.fail"), npe); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("endpoint.accept.fail"), t); } } state = AcceptorState.ENDED; } } private void closeSocket(Socket socket) { try { socket.close(); } catch (IOException e) { // Ignore } } // ------------------------------------------- SocketProcessor Inner Class /** * This class is the equivalent of the Worker, but will simply use in an * external Executor thread pool. */ protected class SocketProcessor implements Runnable { protected SocketWrapper socket = null; protected SocketStatus status = null; public SocketProcessor(SocketWrapper socket) { if (socket==null) throw new NullPointerException(); this.socket = socket; } public SocketProcessor(SocketWrapper socket, SocketStatus status) { this(socket); this.status = status; } @Override public void run() { boolean launch = false; synchronized (socket) { try { SocketState state = SocketState.OPEN; try { // SSL handshake serverSocketFactory.handshake(socket.getSocket()); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.err.handshake"), t); } // Tell to close the socket state = SocketState.CLOSED; } if ((state != SocketState.CLOSED)) { if (status == null) { state = handler.process(socket, SocketStatus.OPEN_READ); } else { state = handler.process(socket,status); } } if (state == SocketState.CLOSED) { // Close socket if (log.isTraceEnabled()) { log.trace("Closing socket:"+socket); } countDownConnection(); try { socket.getSocket().close(); } catch (IOException e) { // Ignore } } else if (state == SocketState.OPEN || state == SocketState.UPGRADING || state == SocketState.UPGRADING_TOMCAT || state == SocketState.UPGRADED){ socket.setKeptAlive(true); socket.access(); launch = true; } else if (state == SocketState.LONG) { socket.access(); waitingRequests.add(socket); } } finally { if (launch) { try { getExecutor().execute(new SocketProcessor(socket, SocketStatus.OPEN_READ)); } catch (RejectedExecutionException x) { log.warn("Socket reprocessing request was rejected for:"+socket,x); try { //unable to handle connection at this time handler.process(socket, SocketStatus.DISCONNECT); } finally { countDownConnection(); } } catch (NullPointerException npe) { if (running) { log.error(sm.getString("endpoint.launch.fail"), npe); } } } } } socket = null; // Finish up this request } } // -------------------- Public methods -------------------- @Override public void bind() throws Exception { // Initialize thread count defaults for acceptor if (acceptorThreadCount == 0) { acceptorThreadCount = 1; } // Initialize maxConnections if (getMaxConnections() == 0) { // User hasn't set a value - use the default setMaxConnections(getMaxThreadsExecutor(true)); } if (serverSocketFactory == null) { if (isSSLEnabled()) { serverSocketFactory = handler.getSslImplementation().getServerSocketFactory(this); } else { serverSocketFactory = new DefaultServerSocketFactory(this); } } if (serverSocket == null) { try { if (getAddress() == null) { serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog()); } else { serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog(), getAddress()); } } catch (BindException orig) { String msg; if (getAddress() == null) msg = orig.getMessage() + " :" + getPort(); else msg = orig.getMessage() + " " + getAddress().toString() + ":" + getPort(); BindException be = new BindException(msg); be.initCause(orig); throw be; } } } @Override public void startInternal() throws Exception { if (!running) { running = true; paused = false; // Create worker collection if (getExecutor() == null) { createExecutor(); } initializeConnectionLatch(); startAcceptorThreads(); // Start async timeout thread Thread timeoutThread = new Thread(new AsyncTimeout(), getName() + "-AsyncTimeout"); timeoutThread.setPriority(threadPriority); timeoutThread.setDaemon(true); timeoutThread.start(); } } @Override public void stopInternal() { releaseConnectionLatch(); if (!paused) { pause(); } if (running) { running = false; unlockAccept(); } shutdownExecutor(); } /** * Deallocate APR memory pools, and close server socket. */ @Override public void unbind() throws Exception { if (running) { stop(); } if (serverSocket != null) { try { if (serverSocket != null) serverSocket.close(); } catch (Exception e) { log.error(sm.getString("endpoint.err.close"), e); } serverSocket = null; } handler.recycle(); } @Override protected AbstractEndpoint.Acceptor createAcceptor() { return new Acceptor(); } /** * Configure the socket. */ protected boolean setSocketOptions(Socket socket) { try { // 1: Set socket options: timeout, linger, etc socketProperties.setProperties(socket); } catch (SocketException s) { //error here is common if the client has reset the connection if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.err.unexpected"), s); } // Close the socket return false; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("endpoint.err.unexpected"), t); // Close the socket return false; } return true; } /** * Process a new connection from a new client. Wraps the socket so * keep-alive and other attributes can be tracked and then passes the socket * to the executor for processing. * * @param socket The socket associated with the client. * * @return true if the socket is passed to the * executor, false if something went wrong or * if the endpoint is shutting down. Returning * false is an indication to close the socket * immediately. */ protected boolean processSocket(Socket socket) { // Process the request from this socket try { SocketWrapper wrapper = new SocketWrapper(socket); wrapper.setKeepAliveLeft(getMaxKeepAliveRequests()); wrapper.setSecure(isSSLEnabled()); // During shutdown, executor may be null - avoid NPE if (!running) { return false; } getExecutor().execute(new SocketProcessor(wrapper)); } catch (RejectedExecutionException x) { log.warn("Socket processing request was rejected for:"+socket,x); return false; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } /** * Process an existing async connection. If processing is required, passes * the wrapped socket to an executor for processing. * * @param socket The socket associated with the client. * @param status Only OPEN and TIMEOUT are used. The others are used for * Comet requests that are not supported by the BIO (JIO) * Connector. * @return true if the socket is passed to the * executor, false if something went wrong. * Returning false is an indication to close * the socket immediately. */ public boolean processSocketAsync(SocketWrapper socket, SocketStatus status) { try { synchronized (socket) { if (waitingRequests.remove(socket)) { SocketProcessor proc = new SocketProcessor(socket,status); ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { //threads should not be created by the webapp classloader if (Constants.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( getClass().getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader( getClass().getClassLoader()); } // During shutdown, executor may be null - avoid NPE if (!running) { return false; } getExecutor().execute(proc); //TODO gotta catch RejectedExecutionException and properly handle it } finally { if (Constants.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl(loader); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(loader); } } } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } protected ConcurrentLinkedQueue> waitingRequests = new ConcurrentLinkedQueue>(); @Override protected Log getLog() { return log; } private static class PrivilegedSetTccl implements PrivilegedAction { private ClassLoader cl; PrivilegedSetTccl(ClassLoader cl) { this.cl = cl; } @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); return null; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/SecureNioChannel.java0000644000175100017510000005522312271452644025174 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.EOFException; import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLEngineResult.Status; /** * * Implementation of a secure socket channel * @author Filip Hanik * @version 1.0 */ public class SecureNioChannel extends NioChannel { protected ByteBuffer netInBuffer; protected ByteBuffer netOutBuffer; protected SSLEngine sslEngine; protected boolean handshakeComplete = false; protected HandshakeStatus handshakeStatus; //gets set by handshake protected boolean closed = false; protected boolean closing = false; protected NioSelectorPool pool; public SecureNioChannel(SocketChannel channel, SSLEngine engine, ApplicationBufferHandler bufHandler, NioSelectorPool pool) throws IOException { super(channel,bufHandler); this.sslEngine = engine; int appBufSize = sslEngine.getSession().getApplicationBufferSize(); int netBufSize = sslEngine.getSession().getPacketBufferSize(); //allocate network buffers - TODO, add in optional direct non-direct buffers if ( netInBuffer == null ) netInBuffer = ByteBuffer.allocateDirect(netBufSize); if ( netOutBuffer == null ) netOutBuffer = ByteBuffer.allocateDirect(netBufSize); //selector pool for blocking operations this.pool = pool; //ensure that the application has a large enough read/write buffers //by doing this, we should not encounter any buffer overflow errors bufHandler.expand(bufHandler.getReadBuffer(), appBufSize); bufHandler.expand(bufHandler.getWriteBuffer(), appBufSize); reset(); } public void reset(SSLEngine engine) throws IOException { this.sslEngine = engine; reset(); } @Override public void reset() throws IOException { super.reset(); netOutBuffer.position(0); netOutBuffer.limit(0); netInBuffer.position(0); netInBuffer.limit(0); handshakeComplete = false; closed = false; closing = false; //initiate handshake sslEngine.beginHandshake(); handshakeStatus = sslEngine.getHandshakeStatus(); } @Override public int getBufferSize() { int size = super.getBufferSize(); size += netInBuffer!=null?netInBuffer.capacity():0; size += netOutBuffer!=null?netOutBuffer.capacity():0; return size; } //=========================================================================================== // NIO SSL METHODS //=========================================================================================== /** * Flush the channel. * * @param block Should a blocking write be used? * @param s * @param timeout * @return true if the network buffer has been flushed out and * is empty else false * @throws IOException */ @Override public boolean flush(boolean block, Selector s, long timeout) throws IOException { if (!block) { flush(netOutBuffer); } else { pool.write(netOutBuffer, this, s, timeout,block); } return !netOutBuffer.hasRemaining(); } /** * Flushes the buffer to the network, non blocking * @param buf ByteBuffer * @return boolean true if the buffer has been emptied out, false otherwise * @throws IOException */ protected boolean flush(ByteBuffer buf) throws IOException { int remaining = buf.remaining(); if ( remaining > 0 ) { int written = sc.write(buf); return written >= remaining; }else { return true; } } /** * Performs SSL handshake, non blocking, but performs NEED_TASK on the same thread.
    * Hence, you should never call this method using your Acceptor thread, as you would slow down * your system significantly.
    * The return for this operation is 0 if the handshake is complete and a positive value if it is not complete. * In the event of a positive value coming back, reregister the selection key for the return values interestOps. * @param read boolean - true if the underlying channel is readable * @param write boolean - true if the underlying channel is writable * @return int - 0 if hand shake is complete, otherwise it returns a SelectionKey interestOps value * @throws IOException */ @Override public int handshake(boolean read, boolean write) throws IOException { if ( handshakeComplete ) return 0; //we have done our initial handshake if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still have data to write SSLEngineResult handshake = null; while (!handshakeComplete) { switch ( handshakeStatus ) { case NOT_HANDSHAKING: { //should never happen throw new IOException("NOT_HANDSHAKING during handshake"); } case FINISHED: { //we are complete if we have delivered the last package handshakeComplete = !netOutBuffer.hasRemaining(); //return 0 if we are complete, otherwise we still have data to write return handshakeComplete?0:SelectionKey.OP_WRITE; } case NEED_WRAP: { //perform the wrap function handshake = handshakeWrap(write); if ( handshake.getStatus() == Status.OK ){ if (handshakeStatus == HandshakeStatus.NEED_TASK) handshakeStatus = tasks(); } else { //wrap should always work with our buffers throw new IOException("Unexpected status:" + handshake.getStatus() + " during handshake WRAP."); } if ( handshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) { //should actually return OP_READ if we have NEED_UNWRAP return SelectionKey.OP_WRITE; } //fall down to NEED_UNWRAP on the same call, will result in a //BUFFER_UNDERFLOW if it needs data } //$FALL-THROUGH$ case NEED_UNWRAP: { //perform the unwrap function handshake = handshakeUnwrap(read); if ( handshake.getStatus() == Status.OK ) { if (handshakeStatus == HandshakeStatus.NEED_TASK) handshakeStatus = tasks(); } else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){ //read more data, reregister for OP_READ return SelectionKey.OP_READ; } else { throw new IOException("Invalid handshake status:"+handshakeStatus+" during handshake UNWRAP."); }//switch break; } case NEED_TASK: { handshakeStatus = tasks(); break; } default: throw new IllegalStateException("Invalid handshake status:"+handshakeStatus); }//switch }//while //return 0 if we are complete, otherwise reregister for any activity that //would cause this method to be called again. return handshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ); } /** * Force a blocking handshake to take place for this key. * This requires that both network and application buffers have been emptied out prior to this call taking place, or a * IOException will be thrown. * @param timeout - timeout in milliseconds for each socket operation * @throws IOException - if an IO exception occurs or if application or network buffers contain data * @throws SocketTimeoutException - if a socket operation timed out */ public void rehandshake(long timeout) throws IOException { //validate the network buffers are empty if (netInBuffer.position() > 0 && netInBuffer.position() 0 && netOutBuffer.position()0 && getBufHandler().getReadBuffer().position()0 && getBufHandler().getWriteBuffer().position()= timeout)) { throw new SocketTimeoutException("Handshake operation timed out."); } isReadable = key.isReadable(); isWriteable = key.isWritable(); } } } } catch (IOException x) { throw x; } catch (Exception cx) { IOException x = new IOException(cx); throw x; } finally { if (key!=null) try {key.cancel();} catch (Exception ignore) {} if (selector!=null) try {selector.close();} catch (Exception ignore) {} } } /** * Executes all the tasks needed on the same thread. * @return HandshakeStatus */ protected SSLEngineResult.HandshakeStatus tasks() { Runnable r = null; while ( (r = sslEngine.getDelegatedTask()) != null) { r.run(); } return sslEngine.getHandshakeStatus(); } /** * Performs the WRAP function * @param doWrite boolean * @return SSLEngineResult * @throws IOException */ protected SSLEngineResult handshakeWrap(boolean doWrite) throws IOException { //this should never be called with a network buffer that contains data //so we can clear it here. netOutBuffer.clear(); //perform the wrap SSLEngineResult result = sslEngine.wrap(bufHandler.getWriteBuffer(), netOutBuffer); //prepare the results to be written netOutBuffer.flip(); //set the status handshakeStatus = result.getHandshakeStatus(); //optimization, if we do have a writable channel, write it now if ( doWrite ) flush(netOutBuffer); return result; } /** * Perform handshake unwrap * @param doread boolean * @return SSLEngineResult * @throws IOException */ protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException { if (netInBuffer.position() == netInBuffer.limit()) { //clear the buffer if we have emptied it out on data netInBuffer.clear(); } if ( doread ) { //if we have data to read, read it int read = sc.read(netInBuffer); if (read == -1) throw new IOException("EOF encountered during handshake."); } SSLEngineResult result; boolean cont = false; //loop while we can perform pure SSLEngine data do { //prepare the buffer with the incoming data netInBuffer.flip(); //call unwrap result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer()); //compact the buffer, this is an optional method, wonder what would happen if we didn't netInBuffer.compact(); //read in the status handshakeStatus = result.getHandshakeStatus(); if ( result.getStatus() == SSLEngineResult.Status.OK && result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) { //execute tasks if we need to handshakeStatus = tasks(); } //perform another unwrap? cont = result.getStatus() == SSLEngineResult.Status.OK && handshakeStatus == HandshakeStatus.NEED_UNWRAP; }while ( cont ); return result; } /** * Sends a SSL close message, will not physically close the connection here.
    * To close the connection, you could do something like *

    
         *   close();
         *   while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
         *   if ( isOpen() ) close(true); //forces a close if you timed out
         * 
    * @throws IOException if an I/O error occurs * @throws IOException if there is data on the outgoing network buffer and we are unable to flush it * TODO Implement this java.io.Closeable method */ @Override public void close() throws IOException { if (closing) return; closing = true; sslEngine.closeOutbound(); if (!flush(netOutBuffer)) { throw new IOException("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead"); } //prep the buffer for the close message netOutBuffer.clear(); //perform the close, since we called sslEngine.closeOutbound SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer); //we should be in a close state if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) { throw new IOException("Invalid close state, will not send network data."); } //prepare the buffer for writing netOutBuffer.flip(); //if there is data to be written flush(netOutBuffer); //is the channel closed? closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP)); } /** * Force a close, can throw an IOException * @param force boolean * @throws IOException */ @Override public void close(boolean force) throws IOException { try { close(); }finally { if ( force || closed ) { closed = true; sc.socket().close(); sc.close(); } } } /** * Reads a sequence of bytes from this channel into the given buffer. * * @param dst The buffer into which bytes are to be transferred * @return The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream * @throws IOException If some other I/O error occurs * @throws IllegalArgumentException if the destination buffer is different than bufHandler.getReadBuffer() * TODO Implement this java.nio.channels.ReadableByteChannel method */ @Override public int read(ByteBuffer dst) throws IOException { //if we want to take advantage of the expand function, make sure we only use the ApplicationBufferHandler's buffers if ( dst != bufHandler.getReadBuffer() ) throw new IllegalArgumentException("You can only read using the application read buffer provided by the handler."); //are we in the middle of closing or closed? if ( closing || closed) return -1; //did we finish our handshake? if (!handshakeComplete) throw new IllegalStateException("Handshake incomplete, you must complete handshake before reading data."); //read from the network int netread = sc.read(netInBuffer); //did we reach EOF? if so send EOF up one layer. if (netread == -1) return -1; //the data read int read = 0; //the SSL engine result SSLEngineResult unwrap; do { //prepare the buffer netInBuffer.flip(); //unwrap the data unwrap = sslEngine.unwrap(netInBuffer, dst); //compact the buffer netInBuffer.compact(); if ( unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW ) { //we did receive some data, add it to our total read += unwrap.bytesProduced(); //perform any tasks if needed if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks(); //if we need more network data, then bail out for now. if ( unwrap.getStatus() == Status.BUFFER_UNDERFLOW ) break; }else if ( unwrap.getStatus()==Status.BUFFER_OVERFLOW && read>0 ) { //buffer overflow can happen, if we have read data, then //empty out the dst buffer before we do another read break; }else { //here we should trap BUFFER_OVERFLOW and call expand on the buffer //for now, throw an exception, as we initialized the buffers //in the constructor throw new IOException("Unable to unwrap data, invalid status: " + unwrap.getStatus()); } } while ( (netInBuffer.position() != 0)); //continue to unwrapping as long as the input buffer has stuff return (read); } /** * Writes a sequence of bytes to this channel from the given buffer. * * @param src The buffer from which bytes are to be retrieved * @return The number of bytes written, possibly zero * @throws IOException If some other I/O error occurs * TODO Implement this java.nio.channels.WritableByteChannel method */ @Override public int write(ByteBuffer src) throws IOException { if ( src == this.netOutBuffer ) { //we can get here through a recursive call //by using the NioBlockingSelector int written = sc.write(src); return written; } else { //make sure we can handle expand, and that we only use on buffer if ( (!this.isSendFile()) && (src != bufHandler.getWriteBuffer()) ) throw new IllegalArgumentException("You can only write using the application write buffer provided by the handler."); //are we closing or closed? if ( closing || closed) throw new IOException("Channel is in closing state."); //the number of bytes written int written = 0; if (!flush(netOutBuffer)) { //we haven't emptied out the buffer yet return written; } /* * The data buffer is empty, we can reuse the entire buffer. */ netOutBuffer.clear(); SSLEngineResult result = sslEngine.wrap(src, netOutBuffer); written = result.bytesConsumed(); netOutBuffer.flip(); if (result.getStatus() == Status.OK) { if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks(); } else { throw new IOException("Unable to wrap data, invalid engine state: " +result.getStatus()); } //force a flush flush(netOutBuffer); return written; } } @Override public int getOutboundRemaining() { return netOutBuffer.remaining(); } @Override public boolean flushOutbound() throws IOException { int remaining = netOutBuffer.remaining(); flush(netOutBuffer); int remaining2= netOutBuffer.remaining(); return remaining2 < remaining; } /** * Callback interface to be able to expand buffers * when buffer overflow exceptions happen */ public static interface ApplicationBufferHandler { public ByteBuffer expand(ByteBuffer buffer, int remaining); public ByteBuffer getReadBuffer(); public ByteBuffer getWriteBuffer(); } @Override public ApplicationBufferHandler getBufHandler() { return bufHandler; } @Override public boolean isHandshakeComplete() { return handshakeComplete; } @Override public boolean isClosing() { return closing; } public SSLEngine getSslEngine() { return sslEngine; } public ByteBuffer getEmptyBuf() { return emptyBuf; } public void setBufHandler(ApplicationBufferHandler bufHandler) { this.bufHandler = bufHandler; } @Override public SocketChannel getIOChannel() { return sc; } }tomcat7-7.0.52/java/org/apache/tomcat/util/net/SSLImplementation.java0000644000175100017510000000657612271452644025365 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.net.Socket; import javax.net.ssl.SSLSession; /* SSLImplementation: Abstract factory and base class for all SSL implementations. @author EKR */ public abstract class SSLImplementation { private static final org.apache.juli.logging.Log logger = org.apache.juli.logging.LogFactory .getLog(SSLImplementation.class); // The default implementations in our search path private static final String JSSEImplementationClass = "org.apache.tomcat.util.net.jsse.JSSEImplementation"; private static final String[] implementations = { JSSEImplementationClass }; public static SSLImplementation getInstance() throws ClassNotFoundException { for (int i = 0; i < implementations.length; i++) { try { SSLImplementation impl = getInstance(implementations[i]); return impl; } catch (Exception e) { if (logger.isTraceEnabled()) logger.trace("Error creating " + implementations[i], e); } } // If we can't instantiate any of these throw new ClassNotFoundException("Can't find any SSL implementation"); } public static SSLImplementation getInstance(String className) throws ClassNotFoundException { if (className == null) return getInstance(); try { // Workaround for the J2SE 1.4.x classloading problem (under // Solaris). // Class.forName(..) fails without creating class using new. // This is an ugly workaround. if (JSSEImplementationClass.equals(className)) { return new org.apache.tomcat.util.net.jsse.JSSEImplementation(); } Class clazz = Class.forName(className); return (SSLImplementation) clazz.newInstance(); } catch (Exception e) { if (logger.isDebugEnabled()) logger .debug("Error loading SSL Implementation " + className, e); throw new ClassNotFoundException( "Error loading SSL Implementation " + className + " :" + e.toString()); } } public abstract String getImplementationName(); public abstract ServerSocketFactory getServerSocketFactory( AbstractEndpoint endpoint); public abstract SSLSupport getSSLSupport(Socket sock); public abstract SSLSupport getSSLSupport(SSLSession session); public abstract SSLUtil getSSLUtil(AbstractEndpoint ep); } tomcat7-7.0.52/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java0000644000175100017510000000402312271452644027253 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; /** * Default server socket factory. Doesn't do much except give us * plain old server sockets. * * @author db@eng.sun.com * @author Harish Prabandham */ public class DefaultServerSocketFactory implements ServerSocketFactory { /** * * @param endpoint Unused in this implementation. */ public DefaultServerSocketFactory(AbstractEndpoint endpoint) { } @Override public ServerSocket createSocket (int port) throws IOException { return new ServerSocket (port); } @Override public ServerSocket createSocket (int port, int backlog) throws IOException { return new ServerSocket (port, backlog); } @Override public ServerSocket createSocket (int port, int backlog, InetAddress ifAddress) throws IOException { return new ServerSocket (port, backlog, ifAddress); } @Override public Socket acceptSocket(ServerSocket socket) throws IOException { return socket.accept(); } @Override public void handshake(Socket sock) throws IOException { // NOOP } } tomcat7-7.0.52/java/org/apache/tomcat/util/net/SSLUtil.java0000644000175100017510000000502112074742757023305 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.net; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.TrustManager; public interface SSLUtil { public SSLContext createSSLContext() throws Exception; public KeyManager[] getKeyManagers() throws Exception; public TrustManager[] getTrustManagers() throws Exception; public void configureSessionContext(SSLSessionContext sslSessionContext); /** * Determines the SSL cipher suites that can be enabled, based on the * configuration of the endpoint and the ciphers supported by the SSL * implementation. * * @param context An initialized context to obtain the supported ciphers from. * * @return Array of SSL cipher suites that may be enabled (which may be * empty if none of the specified ciphers are supported), or * the defaults for the underlying SSL implementation if * the endpoint configuration does not specify any ciphers. */ public String[] getEnableableCiphers(SSLContext context); /** * Determines the SSL protocol variants that can be enabled, based on the * configuration of the endpoint and the ciphers supported by the SSL * implementation. * * @param context An initialized context to obtain the supported protocols from. * * @return Array of SSL protocol variants that may be enabled (which may be * empty if none of the specified protocols are supported), or * the defaults for the underlying SSL implementation if * the endpoint configuration does not specify any protocols. */ public String[] getEnableableProtocols(SSLContext context); } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/0000755000175100017510000000000012301126367021115 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/buf/LocalStrings_es.properties0000644000175100017510000000156011703264612026331 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. b2cConverter.unknownEncoding = La codificaci\u00F3n de car\u00E1cter [{0}] no est\u00E1 soportada tomcat7-7.0.52/java/org/apache/tomcat/util/buf/UDecoder.java0000644000175100017510000002366312271446130023463 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.CharConversionException; import java.io.IOException; /** * All URL decoding happens here. This way we can reuse, review, optimize * without adding complexity to the buffers. * * The conversion will modify the original buffer. * * @author Costin Manolache */ public final class UDecoder { protected static final boolean ALLOW_ENCODED_SLASH = Boolean.valueOf(System.getProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "false")).booleanValue(); private static class DecodeException extends CharConversionException { private static final long serialVersionUID = 1L; public DecodeException(String s) { super(s); } @Override public synchronized Throwable fillInStackTrace() { // This class does not provide a stack trace return this; } } /** Unexpected end of data. */ private static final IOException EXCEPTION_EOF = new DecodeException("EOF"); /** %xx with not-hex digit */ private static final IOException EXCEPTION_NOT_HEX_DIGIT = new DecodeException( "isHexDigit"); /** %-encoded slash is forbidden in resource path */ private static final IOException EXCEPTION_SLASH = new DecodeException( "noSlash"); public UDecoder() { } /** URLDecode, will modify the source. Includes converting * '+' to ' '. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void convert( ByteChunk mb ) throws IOException { convert(mb, true); } /** URLDecode, will modify the source. */ public void convert( ByteChunk mb, boolean query ) throws IOException { int start=mb.getOffset(); byte buff[]=mb.getBytes(); int end=mb.getEnd(); int idx= ByteChunk.findByte( buff, start, end, (byte) '%' ); int idx2=-1; if( query ) { idx2= ByteChunk.findByte( buff, start, (idx >= 0 ? idx : end), (byte) '+' ); } if( idx<0 && idx2<0 ) { return; } // idx will be the smallest positive index ( first % or + ) if( (idx2 >= 0 && idx2 < idx) || idx < 0 ) { idx=idx2; } final boolean noSlash = !(ALLOW_ENCODED_SLASH || query); for( int j=idx; j= end ) { throw EXCEPTION_EOF; } byte b1= buff[j+1]; byte b2=buff[j+2]; if( !isHexDigit( b1 ) || ! isHexDigit(b2 )) { throw EXCEPTION_NOT_HEX_DIGIT; } j+=2; int res=x2c( b1, b2 ); if (noSlash && (res == '/')) { throw EXCEPTION_SLASH; } buff[idx]=(byte)res; } } mb.setEnd( idx ); return; } // -------------------- Additional methods -------------------- // XXX What do we do about charset ???? /** In-buffer processing - the buffer will be modified * Includes converting '+' to ' '. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void convert( CharChunk mb ) throws IOException { convert(mb, true); } /** In-buffer processing - the buffer will be modified */ public void convert( CharChunk mb, boolean query ) throws IOException { // log( "Converting a char chunk "); int start=mb.getOffset(); char buff[]=mb.getBuffer(); int cend=mb.getEnd(); int idx= CharChunk.indexOf( buff, start, cend, '%' ); int idx2=-1; if( query ) { idx2= CharChunk.indexOf( buff, start, (idx >= 0 ? idx : cend), '+' ); } if( idx<0 && idx2<0 ) { return; } // idx will be the smallest positive index ( first % or + ) if( (idx2 >= 0 && idx2 < idx) || idx < 0 ) { idx=idx2; } final boolean noSlash = !(ALLOW_ENCODED_SLASH || query); for( int j=idx; j= cend ) { // invalid throw EXCEPTION_EOF; } char b1= buff[j+1]; char b2=buff[j+2]; if( !isHexDigit( b1 ) || ! isHexDigit(b2 )) { throw EXCEPTION_NOT_HEX_DIGIT; } j+=2; int res=x2c( b1, b2 ); if (noSlash && (res == '/')) { throw EXCEPTION_SLASH; } buff[idx]=(char)res; } } mb.setEnd( idx ); } /** URLDecode, will modify the source * Includes converting '+' to ' '. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void convert(MessageBytes mb) throws IOException { convert(mb, true); } /** URLDecode, will modify the source */ public void convert(MessageBytes mb, boolean query) throws IOException { switch (mb.getType()) { case MessageBytes.T_STR: String strValue=mb.toString(); if( strValue==null ) { return; } try { mb.setString( convert( strValue, query )); } catch (RuntimeException ex) { throw new DecodeException(ex.getMessage()); } break; case MessageBytes.T_CHARS: CharChunk charC=mb.getCharChunk(); convert( charC, query ); break; case MessageBytes.T_BYTES: ByteChunk bytesC=mb.getByteChunk(); convert( bytesC, query ); break; } } // XXX Old code, needs to be replaced !!!! // /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public final String convert(String str) { return convert(str, true); } public final String convert(String str, boolean query) { if (str == null) { return null; } if( (!query || str.indexOf( '+' ) < 0) && str.indexOf( '%' ) < 0 ) { return str; } final boolean noSlash = !(ALLOW_ENCODED_SLASH || query); StringBuilder dec = new StringBuilder(); // decoded string output int strPos = 0; int strLen = str.length(); dec.ensureCapacity(str.length()); while (strPos < strLen) { int laPos; // lookahead position // look ahead to next URLencoded metacharacter, if any for (laPos = strPos; laPos < strLen; laPos++) { char laChar = str.charAt(laPos); if ((laChar == '+' && query) || (laChar == '%')) { break; } } // if there were non-metacharacters, copy them all as a block if (laPos > strPos) { dec.append(str.substring(strPos,laPos)); strPos = laPos; } // shortcut out of here if we're at the end of the string if (strPos >= strLen) { break; } // process next metacharacter char metaChar = str.charAt(strPos); if (metaChar == '+') { dec.append(' '); strPos++; continue; } else if (metaChar == '%') { // We throw the original exception - the super will deal with // it // try { char res = (char) Integer.parseInt( str.substring(strPos + 1, strPos + 3), 16); if (noSlash && (res == '/')) { throw new IllegalArgumentException("noSlash"); } dec.append(res); strPos += 3; } } return dec.toString(); } private static boolean isHexDigit( int c ) { return ( ( c>='0' && c<='9' ) || ( c>='a' && c<='f' ) || ( c>='A' && c<='F' )); } private static int x2c( byte b1, byte b2 ) { int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 : (b1 -'0'); digit*=16; digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 : (b2 -'0'); return digit; } private static int x2c( char b1, char b2 ) { int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 : (b1 -'0'); digit*=16; digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 : (b2 -'0'); return digit; } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/Utf8Decoder.java0000644000175100017510000003207212115353355024102 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; /** * Decodes bytes to UTF-8. Extracted from Apache Harmony and modified to reject * code points from U+D800 to U+DFFF as per RFC3629. The standard Java decoder * does not reject these. It has also been modified to reject code points * greater than U+10FFFF which the standard Java decoder rejects but the harmony * one does not. */ public class Utf8Decoder extends CharsetDecoder { // The next table contains information about UTF-8 charset and // correspondence of 1st byte to the length of sequence // For information please visit http://www.ietf.org/rfc/rfc3629.txt // // Please note, o means 0, actually. // ------------------------------------------------------------------- // 0 1 2 3 Value // ------------------------------------------------------------------- // oxxxxxxx 00000000 00000000 0xxxxxxx // 11oyyyyy 1oxxxxxx 00000000 00000yyy yyxxxxxx // 111ozzzz 1oyyyyyy 1oxxxxxx 00000000 zzzzyyyy yyxxxxxx // 1111ouuu 1ouuzzzz 1oyyyyyy 1oxxxxxx 000uuuuu zzzzyyyy yyxxxxxx private static final int remainingBytes[] = { // 1owwwwww -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 11oyyyyy -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 111ozzzz 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 1111ouuu 3, 3, 3, 3, 3, -1, -1, -1, // > 11110111 -1, -1, -1, -1, -1, -1, -1, -1}; private static final int remainingNumbers[] = {0, // 0 1 2 3 4224, // (01o00000b << 6)+(1o000000b) 401536, // (011o0000b << 12)+(1o000000b << 6)+(1o000000b) 29892736 // (0111o000b << 18)+(1o000000b << 12)+(1o000000b << // 6)+(1o000000b) }; private static final int lowerEncodingLimit[] = {-1, 0x80, 0x800, 0x10000}; public Utf8Decoder() { super(B2CConverter.UTF_8, 1.0f, 1.0f); } @Override protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { if (in.hasArray() && out.hasArray()) { return decodeHasArray(in, out); } return decodeNotHasArray(in, out); } private CoderResult decodeNotHasArray(ByteBuffer in, CharBuffer out) { int outRemaining = out.remaining(); int pos = in.position(); int limit = in.limit(); try { while (pos < limit) { if (outRemaining == 0) { return CoderResult.OVERFLOW; } int jchar = in.get(); if (jchar < 0) { jchar = jchar & 0x7F; int tail = remainingBytes[jchar]; if (tail == -1) { return CoderResult.malformedForLength(1); } if (limit - pos < 1 + tail) { // No early test for invalid sequences here as peeking // at the next byte is harder return CoderResult.UNDERFLOW; } int nextByte; for (int i = 0; i < tail; i++) { nextByte = in.get() & 0xFF; if ((nextByte & 0xC0) != 0x80) { return CoderResult.malformedForLength(1 + i); } jchar = (jchar << 6) + nextByte; } jchar -= remainingNumbers[tail]; if (jchar < lowerEncodingLimit[tail]) { // Should have been encoded in a fewer octets return CoderResult.malformedForLength(1); } pos += tail; } // Apache Tomcat added test if (jchar >= 0xD800 && jchar <= 0xDFFF) { return CoderResult.unmappableForLength(3); } // Apache Tomcat added test if (jchar > 0x10FFFF) { return CoderResult.unmappableForLength(4); } if (jchar <= 0xffff) { out.put((char) jchar); outRemaining--; } else { if (outRemaining < 2) { return CoderResult.OVERFLOW; } out.put((char) ((jchar >> 0xA) + 0xD7C0)); out.put((char) ((jchar & 0x3FF) + 0xDC00)); outRemaining -= 2; } pos++; } return CoderResult.UNDERFLOW; } finally { in.position(pos); } } private CoderResult decodeHasArray(ByteBuffer in, CharBuffer out) { int outRemaining = out.remaining(); int pos = in.position(); int limit = in.limit(); final byte[] bArr = in.array(); final char[] cArr = out.array(); final int inIndexLimit = limit + in.arrayOffset(); int inIndex = pos + in.arrayOffset(); int outIndex = out.position() + out.arrayOffset(); // if someone would change the limit in process, // he would face consequences for (; inIndex < inIndexLimit && outRemaining > 0; inIndex++) { int jchar = bArr[inIndex]; if (jchar < 0) { jchar = jchar & 0x7F; // If first byte is invalid, tail will be set to -1 int tail = remainingBytes[jchar]; if (tail == -1) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // Additional checks to detect invalid sequences ASAP // Checks derived from Unicode 6.2, Chapter 3, Table 3-7 // Check 2nd byte int tailAvailable = inIndexLimit - inIndex - 1; if (tailAvailable > 0) { // First byte C2..DF, second byte 80..BF if (jchar > 0x41 && jchar < 0x60 && (bArr[inIndex + 1] & 0xC0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // First byte E0, second byte A0..BF if (jchar == 0x60 && (bArr[inIndex + 1] & 0xE0) != 0xA0) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // First byte E1..EC, second byte 80..BF if (jchar > 0x60 && jchar < 0x6D && (bArr[inIndex + 1] & 0xC0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // First byte ED, second byte 80..9F if (jchar == 0x6D && (bArr[inIndex + 1] & 0xE0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // First byte EE..EF, second byte 80..BF if (jchar > 0x6D && jchar < 0x70 && (bArr[inIndex + 1] & 0xC0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // First byte F0, second byte 90..BF if (jchar == 0x70 && ((bArr[inIndex + 1] & 0xFF) < 0x90 || (bArr[inIndex + 1] & 0xFF) > 0xBF)) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // First byte F1..F3, second byte 80..BF if (jchar > 0x70 && jchar < 0x74 && (bArr[inIndex + 1] & 0xC0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } // First byte F4, second byte 80..8F if (jchar == 0x74 && (bArr[inIndex + 1] & 0xF0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } } // Check third byte if present and expected if (tailAvailable > 1 && tail > 1) { if ((bArr[inIndex + 2] & 0xC0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(2); } } // Check fourth byte if present and expected if (tailAvailable > 2 && tail > 2) { if ((bArr[inIndex + 3] & 0xC0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(3); } } if (tailAvailable < tail) { break; } for (int i = 0; i < tail; i++) { int nextByte = bArr[inIndex + i + 1] & 0xFF; if ((nextByte & 0xC0) != 0x80) { in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1 + i); } jchar = (jchar << 6) + nextByte; } jchar -= remainingNumbers[tail]; if (jchar < lowerEncodingLimit[tail]) { // Should have been encoded in fewer octets in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return CoderResult.malformedForLength(1); } inIndex += tail; } // Apache Tomcat added test if (jchar >= 0xD800 && jchar <= 0xDFFF) { return CoderResult.unmappableForLength(3); } // Apache Tomcat added test if (jchar > 0x10FFFF) { return CoderResult.unmappableForLength(4); } if (jchar <= 0xffff) { cArr[outIndex++] = (char) jchar; outRemaining--; } else { if (outRemaining < 2) { return CoderResult.OVERFLOW; } cArr[outIndex++] = (char) ((jchar >> 0xA) + 0xD7C0); cArr[outIndex++] = (char) ((jchar & 0x3FF) + 0xDC00); outRemaining -= 2; } } in.position(inIndex - in.arrayOffset()); out.position(outIndex - out.arrayOffset()); return (outRemaining == 0 && inIndex < inIndexLimit) ? CoderResult.OVERFLOW : CoderResult.UNDERFLOW; } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/UEncoder.java0000644000175100017510000001114412271446130023464 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.IOException; import java.util.BitSet; /** Efficient implementation for encoders. * This class is not thread safe - you need one encoder per thread. * The encoder will save and recycle the internal objects, avoiding * garbage. * * You can add extra characters that you want preserved, for example * while encoding a URL you can add "/". * * @author Costin Manolache */ public final class UEncoder { // Not static - the set may differ ( it's better than adding // an extra check for "/", "+", etc private BitSet safeChars=null; private C2BConverter c2b=null; private ByteChunk bb=null; private CharChunk cb=null; private CharChunk output=null; private String encoding="UTF8"; public UEncoder() { initSafeChars(); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void setEncoding( String s ) { encoding=s; } public void addSafeCharacter( char c ) { safeChars.set( c ); } /** * URL Encode string, using a specified encoding. * * @param s string to be encoded * @param start the beginning index, inclusive * @param end the ending index, exclusive * @throws IOException If an I/O error occurs */ public CharChunk encodeURL(String s, int start, int end) throws IOException { if (c2b == null) { bb = new ByteChunk(8); // small enough. cb = new CharChunk(2); // small enough. output = new CharChunk(64); // small enough. c2b = new C2BConverter(encoding); } else { bb.recycle(); cb.recycle(); output.recycle(); } for (int i = start; i < end; i++) { char c = s.charAt(i); if (safeChars.get(c)) { output.append(c); } else { cb.append(c); c2b.convert(cb, bb); // "surrogate" - UTF is _not_ 16 bit, but 21 !!!! // ( while UCS is 31 ). Amazing... if (c >= 0xD800 && c <= 0xDBFF) { if ((i+1) < end) { char d = s.charAt(i+1); if (d >= 0xDC00 && d <= 0xDFFF) { cb.append(d); c2b.convert(cb, bb); i++; } } } urlEncode(output, bb); cb.recycle(); bb.recycle(); } } return output; } protected void urlEncode(CharChunk out, ByteChunk bb) throws IOException { byte[] bytes = bb.getBuffer(); for (int j = bb.getStart(); j < bb.getEnd(); j++) { out.append('%'); char ch = Character.forDigit((bytes[j] >> 4) & 0xF, 16); out.append(ch); ch = Character.forDigit(bytes[j] & 0xF, 16); out.append(ch); } } // -------------------- Internal implementation -------------------- private void initSafeChars() { safeChars=new BitSet(128); int i; for (i = 'a'; i <= 'z'; i++) { safeChars.set(i); } for (i = 'A'; i <= 'Z'; i++) { safeChars.set(i); } for (i = '0'; i <= '9'; i++) { safeChars.set(i); } //safe safeChars.set('$'); safeChars.set('-'); safeChars.set('_'); safeChars.set('.'); // Dangerous: someone may treat this as " " // RFC1738 does allow it, it's not reserved // safeChars.set('+'); //extra safeChars.set('!'); safeChars.set('*'); safeChars.set('\''); safeChars.set('('); safeChars.set(')'); safeChars.set(','); } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/Utf8Encoder.java0000644000175100017510000002020212266314260024103 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; /** * Encodes characters as bytes using UTF-8. Extracted from Apache Harmony with * some minor bug fixes applied. */ public class Utf8Encoder extends CharsetEncoder { public Utf8Encoder() { super(B2CConverter.UTF_8, 1.1f, 4.0f); } @Override protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { if (in.hasArray() && out.hasArray()) { return encodeHasArray(in, out); } return encodeNotHasArray(in, out); } private CoderResult encodeHasArray(CharBuffer in, ByteBuffer out) { int outRemaining = out.remaining(); int pos = in.position(); int limit = in.limit(); byte[] bArr; char[] cArr; int x = pos; bArr = out.array(); cArr = in.array(); int outPos = out.position(); int rem = in.remaining(); for (x = pos; x < pos + rem; x++) { int jchar = (cArr[x] & 0xFFFF); if (jchar <= 0x7F) { if (outRemaining < 1) { in.position(x); out.position(outPos); return CoderResult.OVERFLOW; } bArr[outPos++] = (byte) (jchar & 0xFF); outRemaining--; } else if (jchar <= 0x7FF) { if (outRemaining < 2) { in.position(x); out.position(outPos); return CoderResult.OVERFLOW; } bArr[outPos++] = (byte) (0xC0 + ((jchar >> 6) & 0x1F)); bArr[outPos++] = (byte) (0x80 + (jchar & 0x3F)); outRemaining -= 2; } else if (jchar >= 0xD800 && jchar <= 0xDFFF) { // in has to have one byte more. if (limit <= x + 1) { in.position(x); out.position(outPos); return CoderResult.UNDERFLOW; } if (outRemaining < 4) { in.position(x); out.position(outPos); return CoderResult.OVERFLOW; } // The surrogate pair starts with a low-surrogate. if (jchar >= 0xDC00) { in.position(x); out.position(outPos); return CoderResult.malformedForLength(1); } int jchar2 = cArr[x + 1] & 0xFFFF; // The surrogate pair ends with a high-surrogate. if (jchar2 < 0xDC00) { in.position(x); out.position(outPos); return CoderResult.malformedForLength(1); } // Note, the Unicode scalar value n is defined // as follows: // n = (jchar-0xD800)*0x400+(jchar2-0xDC00)+0x10000 // Where jchar is a high-surrogate, // jchar2 is a low-surrogate. int n = (jchar << 10) + jchar2 + 0xFCA02400; bArr[outPos++] = (byte) (0xF0 + ((n >> 18) & 0x07)); bArr[outPos++] = (byte) (0x80 + ((n >> 12) & 0x3F)); bArr[outPos++] = (byte) (0x80 + ((n >> 6) & 0x3F)); bArr[outPos++] = (byte) (0x80 + (n & 0x3F)); outRemaining -= 4; x++; } else { if (outRemaining < 3) { in.position(x); out.position(outPos); return CoderResult.OVERFLOW; } bArr[outPos++] = (byte) (0xE0 + ((jchar >> 12) & 0x0F)); bArr[outPos++] = (byte) (0x80 + ((jchar >> 6) & 0x3F)); bArr[outPos++] = (byte) (0x80 + (jchar & 0x3F)); outRemaining -= 3; } if (outRemaining == 0) { in.position(x + 1); out.position(outPos); // If both input and output are exhausted, return UNDERFLOW if (x + 1 == limit) { return CoderResult.UNDERFLOW; } else { return CoderResult.OVERFLOW; } } } if (rem != 0) { in.position(x); out.position(outPos); } return CoderResult.UNDERFLOW; } private CoderResult encodeNotHasArray(CharBuffer in, ByteBuffer out) { int outRemaining = out.remaining(); int pos = in.position(); int limit = in.limit(); try { while (pos < limit) { if (outRemaining == 0) { return CoderResult.OVERFLOW; } int jchar = (in.get() & 0xFFFF); if (jchar <= 0x7F) { if (outRemaining < 1) { return CoderResult.OVERFLOW; } out.put((byte) jchar); outRemaining--; } else if (jchar <= 0x7FF) { if (outRemaining < 2) { return CoderResult.OVERFLOW; } out.put((byte) (0xC0 + ((jchar >> 6) & 0x1F))); out.put((byte) (0x80 + (jchar & 0x3F))); outRemaining -= 2; } else if (jchar >= 0xD800 && jchar <= 0xDFFF) { // in has to have one byte more. if (limit <= pos + 1) { return CoderResult.UNDERFLOW; } if (outRemaining < 4) { return CoderResult.OVERFLOW; } // The surrogate pair starts with a low-surrogate. if (jchar >= 0xDC00) { return CoderResult.malformedForLength(1); } int jchar2 = (in.get() & 0xFFFF); // The surrogate pair ends with a high-surrogate. if (jchar2 < 0xDC00) { return CoderResult.malformedForLength(1); } // Note, the Unicode scalar value n is defined // as follows: // n = (jchar-0xD800)*0x400+(jchar2-0xDC00)+0x10000 // Where jchar is a high-surrogate, // jchar2 is a low-surrogate. int n = (jchar << 10) + jchar2 + 0xFCA02400; out.put((byte) (0xF0 + ((n >> 18) & 0x07))); out.put((byte) (0x80 + ((n >> 12) & 0x3F))); out.put((byte) (0x80 + ((n >> 6) & 0x3F))); out.put((byte) (0x80 + (n & 0x3F))); outRemaining -= 4; pos++; } else { if (outRemaining < 3) { return CoderResult.OVERFLOW; } out.put((byte) (0xE0 + ((jchar >> 12) & 0x0F))); out.put((byte) (0x80 + ((jchar >> 6) & 0x3F))); out.put((byte) (0x80 + (jchar & 0x3F))); outRemaining -= 3; } pos++; } } finally { in.position(pos); } return CoderResult.UNDERFLOW; } }tomcat7-7.0.52/java/org/apache/tomcat/util/buf/package.html0000644000175100017510000000313412271446130023376 0ustar locutuslocutus

    Buffers and Encodings

    This package contains buffers and utils to perform encoding/decoding of buffers. That includes byte to char conversions, URL encodings, etc.

    Encoding is a critical operation for performance. There are few tricks in this package - the C2B and B2C converters are caching a ISReader/OSWriter and keep everything allocated to do the conversions in any VM without any garbage.

    This package must accomodate future extensions and additional converters ( most imporant: the nio.charset, which should be detected and used if available ). Also, we do have one hand-written UTF8Decoder, and other tuned encoders could be added.

    My benchmarks ( I'm costin :-) show only small differences between C2B, B2C and hand-written codders/decoders, so UTF8Decoder may be disabled.

    tomcat7-7.0.52/java/org/apache/tomcat/util/buf/B2CConverter.java0000644000175100017510000001644412271446130024226 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apache.tomcat.util.res.StringManager; /** * NIO based character decoder. */ public class B2CConverter { private static final StringManager sm = StringManager.getManager(Constants.Package); private static final Map encodingToCharsetCache = new HashMap(); public static final Charset ISO_8859_1; public static final Charset UTF_8; // Protected so unit tests can use it protected static final int LEFTOVER_SIZE = 9; static { for (Charset charset: Charset.availableCharsets().values()) { encodingToCharsetCache.put( charset.name().toLowerCase(Locale.ENGLISH), charset); for (String alias : charset.aliases()) { encodingToCharsetCache.put( alias.toLowerCase(Locale.ENGLISH), charset); } } Charset iso88591 = null; Charset utf8 = null; try { iso88591 = getCharset("ISO-8859-1"); utf8 = getCharset("UTF-8"); } catch (UnsupportedEncodingException e) { // Impossible. All JVMs must support these. e.printStackTrace(); } ISO_8859_1 = iso88591; UTF_8 = utf8; } public static Charset getCharset(String enc) throws UnsupportedEncodingException { // Encoding names should all be ASCII String lowerCaseEnc = enc.toLowerCase(Locale.ENGLISH); return getCharsetLower(lowerCaseEnc); } /** * Only to be used when it is known that the encoding name is in lower case. */ public static Charset getCharsetLower(String lowerCaseEnc) throws UnsupportedEncodingException { Charset charset = encodingToCharsetCache.get(lowerCaseEnc); if (charset == null) { // Pre-population of the cache means this must be invalid throw new UnsupportedEncodingException( sm.getString("b2cConverter.unknownEncoding", lowerCaseEnc)); } return charset; } private final CharsetDecoder decoder; private ByteBuffer bb = null; private CharBuffer cb = null; /** * Leftover buffer used for incomplete characters. */ private final ByteBuffer leftovers; public B2CConverter(String encoding) throws IOException { this(encoding, false); } public B2CConverter(String encoding, boolean replaceOnError) throws IOException { byte[] left = new byte[LEFTOVER_SIZE]; leftovers = ByteBuffer.wrap(left); CodingErrorAction action; if (replaceOnError) { action = CodingErrorAction.REPLACE; } else { action = CodingErrorAction.REPORT; } Charset charset = getCharset(encoding); // Special case. Use the Apache Harmony based UTF-8 decoder because it // - a) rejects invalid sequences that the JVM decoder does not // - b) fails faster for some invalid sequences if (charset.equals(UTF_8)) { decoder = new Utf8Decoder(); } else { decoder = charset.newDecoder(); } decoder.onMalformedInput(action); decoder.onUnmappableCharacter(action); } /** * Reset the decoder state. */ public void recycle() { decoder.reset(); leftovers.position(0); } /** * Convert the given bytes to characters. * * @param bc byte input * @param cc char output * @param endOfInput Is this all of the available data */ public void convert(ByteChunk bc, CharChunk cc, boolean endOfInput) throws IOException { if ((bb == null) || (bb.array() != bc.getBuffer())) { // Create a new byte buffer if anything changed bb = ByteBuffer.wrap(bc.getBuffer(), bc.getStart(), bc.getLength()); } else { // Initialize the byte buffer bb.limit(bc.getEnd()); bb.position(bc.getStart()); } if ((cb == null) || (cb.array() != cc.getBuffer())) { // Create a new char buffer if anything changed cb = CharBuffer.wrap(cc.getBuffer(), cc.getEnd(), cc.getBuffer().length - cc.getEnd()); } else { // Initialize the char buffer cb.limit(cc.getBuffer().length); cb.position(cc.getEnd()); } CoderResult result = null; // Parse leftover if any are present if (leftovers.position() > 0) { int pos = cb.position(); // Loop until one char is decoded or there is a decoder error do { leftovers.put(bc.substractB()); leftovers.flip(); result = decoder.decode(leftovers, cb, endOfInput); leftovers.position(leftovers.limit()); leftovers.limit(leftovers.array().length); } while (result.isUnderflow() && (cb.position() == pos)); if (result.isError() || result.isMalformed()) { result.throwException(); } bb.position(bc.getStart()); leftovers.position(0); } // Do the decoding and get the results into the byte chunk and the char // chunk result = decoder.decode(bb, cb, endOfInput); if (result.isError() || result.isMalformed()) { result.throwException(); } else if (result.isOverflow()) { // Propagate current positions to the byte chunk and char chunk, if // this continues the char buffer will get resized bc.setOffset(bb.position()); cc.setEnd(cb.position()); } else if (result.isUnderflow()) { // Propagate current positions to the byte chunk and char chunk bc.setOffset(bb.position()); cc.setEnd(cb.position()); // Put leftovers in the leftovers byte buffer if (bc.getLength() > 0) { leftovers.limit(leftovers.array().length); leftovers.position(bc.getLength()); bc.substract(leftovers.array(), 0, bc.getLength()); } } } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/MessageBytes.java0000644000175100017510000004446712271446130024371 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.IOException; import java.io.Serializable; import java.nio.charset.Charset; import java.util.Locale; /** * This class is used to represent a subarray of bytes in an HTTP message. * It represents all request/response elements. The byte/char conversions are * delayed and cached. Everything is recyclable. * * The object can represent a byte[], a char[], or a (sub) String. All * operations can be made in case sensitive mode or not. * * @author dac@eng.sun.com * @author James Todd [gonzo@eng.sun.com] * @author Costin Manolache */ public final class MessageBytes implements Cloneable, Serializable { private static final long serialVersionUID = 1L; // primary type ( whatever is set as original value ) private int type = T_NULL; public static final int T_NULL = 0; /** getType() is T_STR if the the object used to create the MessageBytes was a String */ public static final int T_STR = 1; /** getType() is T_STR if the the object used to create the MessageBytes was a byte[] */ public static final int T_BYTES = 2; /** getType() is T_STR if the the object used to create the MessageBytes was a char[] */ public static final int T_CHARS = 3; private int hashCode=0; // did we computed the hashcode ? private boolean hasHashCode=false; // Internal objects to represent array + offset, and specific methods private final ByteChunk byteC=new ByteChunk(); private final CharChunk charC=new CharChunk(); // String private String strValue; // true if a String value was computed. Probably not needed, // strValue!=null is the same private boolean hasStrValue=false; /** * Creates a new, uninitialized MessageBytes object. * Use static newInstance() in order to allow * future hooks. */ private MessageBytes() { } /** Construct a new MessageBytes instance */ public static MessageBytes newInstance() { return factory.newInstance(); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public MessageBytes getClone() { try { return (MessageBytes)this.clone(); } catch( Exception ex) { return null; } } public boolean isNull() { // should we check also hasStrValue ??? return byteC.isNull() && charC.isNull() && ! hasStrValue; // bytes==null && strValue==null; } /** * Resets the message bytes to an uninitialized (NULL) state. */ public void recycle() { type=T_NULL; byteC.recycle(); charC.recycle(); strValue=null; hasStrValue=false; hasHashCode=false; hasIntValue=false; hasLongValue=false; } /** * Sets the content to the specified subarray of bytes. * * @param b the bytes * @param off the start offset of the bytes * @param len the length of the bytes */ public void setBytes(byte[] b, int off, int len) { byteC.setBytes( b, off, len ); type=T_BYTES; hasStrValue=false; hasHashCode=false; hasIntValue=false; hasLongValue=false; } /** Set the encoding. If the object was constructed from bytes[]. any * previous conversion is reset. * If no encoding is set, we'll use 8859-1. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void setCharset(Charset charset) { if( !byteC.isNull() ) { // if the encoding changes we need to reset the conversion results charC.recycle(); hasStrValue=false; } byteC.setCharset(charset); } /** * Sets the content to be a char[] * * @param c the bytes * @param off the start offset of the bytes * @param len the length of the bytes */ public void setChars( char[] c, int off, int len ) { charC.setChars( c, off, len ); type=T_CHARS; hasStrValue=false; hasHashCode=false; hasIntValue=false; hasLongValue=false; } /** * Set the content to be a string */ public void setString( String s ) { strValue=s; hasHashCode=false; hasIntValue=false; hasLongValue=false; if (s == null) { hasStrValue=false; type=T_NULL; } else { hasStrValue=true; type=T_STR; } } // -------------------- Conversion and getters -------------------- /** Compute the string value */ @Override public String toString() { if( hasStrValue ) { return strValue; } switch (type) { case T_CHARS: strValue=charC.toString(); hasStrValue=true; return strValue; case T_BYTES: strValue=byteC.toString(); hasStrValue=true; return strValue; } return null; } //---------------------------------------- /** Return the type of the original content. Can be * T_STR, T_BYTES, T_CHARS or T_NULL */ public int getType() { return type; } /** * Returns the byte chunk, representing the byte[] and offset/length. * Valid only if T_BYTES or after a conversion was made. */ public ByteChunk getByteChunk() { return byteC; } /** * Returns the char chunk, representing the char[] and offset/length. * Valid only if T_CHARS or after a conversion was made. */ public CharChunk getCharChunk() { return charC; } /** * Returns the string value. * Valid only if T_STR or after a conversion was made. */ public String getString() { return strValue; } /** Do a char->byte conversion. */ public void toBytes() { if( ! byteC.isNull() ) { type=T_BYTES; return; } toString(); type=T_BYTES; byte bb[] = strValue.getBytes(Charset.defaultCharset()); byteC.setBytes(bb, 0, bb.length); } /** Convert to char[] and fill the CharChunk. * XXX Not optimized - it converts to String first. */ public void toChars() { if( ! charC.isNull() ) { type=T_CHARS; return; } // inefficient toString(); type=T_CHARS; char cc[]=strValue.toCharArray(); charC.setChars(cc, 0, cc.length); } /** * Returns the length of the original buffer. * Note that the length in bytes may be different from the length * in chars. */ public int getLength() { if(type==T_BYTES) { return byteC.getLength(); } if(type==T_CHARS) { return charC.getLength(); } if(type==T_STR) { return strValue.length(); } toString(); if( strValue==null ) { return 0; } return strValue.length(); } // -------------------- equals -------------------- /** * Compares the message bytes to the specified String object. * @param s the String to compare * @return true if the comparison succeeded, false otherwise */ public boolean equals(String s) { switch (type) { case T_STR: if (strValue == null) { return s == null; } return strValue.equals( s ); case T_CHARS: return charC.equals( s ); case T_BYTES: return byteC.equals( s ); default: return false; } } /** * Compares the message bytes to the specified String object. * @param s the String to compare * @return true if the comparison succeeded, false otherwise */ public boolean equalsIgnoreCase(String s) { switch (type) { case T_STR: if (strValue == null) { return s == null; } return strValue.equalsIgnoreCase( s ); case T_CHARS: return charC.equalsIgnoreCase( s ); case T_BYTES: return byteC.equalsIgnoreCase( s ); default: return false; } } @Override public boolean equals(Object obj) { if (obj instanceof MessageBytes) { return equals((MessageBytes) obj); } return false; } public boolean equals(MessageBytes mb) { switch (type) { case T_STR: return mb.equals( strValue ); } if( mb.type != T_CHARS && mb.type!= T_BYTES ) { // it's a string or int/date string value return equals( mb.toString() ); } // mb is either CHARS or BYTES. // this is either CHARS or BYTES // Deal with the 4 cases ( in fact 3, one is symmetric) if( mb.type == T_CHARS && type==T_CHARS ) { return charC.equals( mb.charC ); } if( mb.type==T_BYTES && type== T_BYTES ) { return byteC.equals( mb.byteC ); } if( mb.type== T_CHARS && type== T_BYTES ) { return byteC.equals( mb.charC ); } if( mb.type== T_BYTES && type== T_CHARS ) { return mb.byteC.equals( charC ); } // can't happen return true; } /** * Returns true if the message bytes starts with the specified string. * @param s the string * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public boolean startsWith(String s) { switch (type) { case T_STR: return strValue.startsWith( s ); case T_CHARS: return charC.startsWith( s ); case T_BYTES: return byteC.startsWith( s ); default: return false; } } /** * Returns true if the message bytes starts with the specified string. * @param s the string * @param pos The start position */ public boolean startsWithIgnoreCase(String s, int pos) { switch (type) { case T_STR: if( strValue==null ) { return false; } if( strValue.length() < pos + s.length() ) { return false; } for( int i=0; i 0) { int digit = current % 10; current = current / 10; buf[end++] = HexUtils.getHex(digit); } byteC.setOffset(0); byteC.setEnd(end); // Inverting buffer end--; if (i < 0) { start++; } while (end > start) { byte temp = buf[start]; buf[start] = buf[end]; buf[end] = temp; start++; end--; } intValue=i; hasStrValue=false; hasHashCode=false; hasIntValue=true; hasLongValue=false; type=T_BYTES; } /** Set the buffer to the representation of an long */ public void setLong(long l) { byteC.allocate(32, 64); long current = l; byte[] buf = byteC.getBuffer(); int start = 0; int end = 0; if (l == 0) { buf[end++] = (byte) '0'; } if (l < 0) { current = -l; buf[end++] = (byte) '-'; } while (current > 0) { int digit = (int) (current % 10); current = current / 10; buf[end++] = HexUtils.getHex(digit); } byteC.setOffset(0); byteC.setEnd(end); // Inverting buffer end--; if (l < 0) { start++; } while (end > start) { byte temp = buf[start]; buf[start] = buf[end]; buf[end] = temp; start++; end--; } longValue=l; hasStrValue=false; hasHashCode=false; hasIntValue=false; hasLongValue=true; type=T_BYTES; } // Used for headers conversion /** * Convert the buffer to an int, cache the value * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public int getInt() { if( hasIntValue ) { return intValue; } switch (type) { case T_BYTES: intValue=byteC.getInt(); break; default: intValue=Integer.parseInt(toString()); } hasIntValue=true; return intValue; } // Used for headers conversion /** Convert the buffer to an long, cache the value */ public long getLong() { if( hasLongValue ) { return longValue; } switch (type) { case T_BYTES: longValue=byteC.getLong(); break; default: longValue=Long.parseLong(toString()); } hasLongValue=true; return longValue; } // -------------------- Future may be different -------------------- private static MessageBytesFactory factory=new MessageBytesFactory(); /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static void setFactory( MessageBytesFactory mbf ) { factory=mbf; } public static class MessageBytesFactory { protected MessageBytesFactory() { } public MessageBytes newInstance() { return new MessageBytes(); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/StringCache.java0000644000175100017510000005371712271446130024166 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.Map.Entry; import java.util.TreeMap; /** * This class implements a String cache for ByteChunk and CharChunk. * * @author Remy Maucherat */ public class StringCache { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( StringCache.class ); // ------------------------------------------------------- Static Variables /** * Enabled ? */ protected static boolean byteEnabled = ("true".equals(System.getProperty( "tomcat.util.buf.StringCache.byte.enabled", "false"))); protected static boolean charEnabled = ("true".equals(System.getProperty( "tomcat.util.buf.StringCache.char.enabled", "false"))); protected static int trainThreshold = Integer.parseInt(System.getProperty( "tomcat.util.buf.StringCache.trainThreshold", "20000")); protected static int cacheSize = Integer.parseInt(System.getProperty( "tomcat.util.buf.StringCache.cacheSize", "200")); protected static int maxStringSize = Integer.parseInt(System.getProperty( "tomcat.util.buf.StringCache.maxStringSize", "128")); /** * Statistics hash map for byte chunk. */ protected static HashMap bcStats = new HashMap(cacheSize); /** * toString count for byte chunk. */ protected static int bcCount = 0; /** * Cache for byte chunk. */ protected static ByteEntry[] bcCache = null; /** * Statistics hash map for char chunk. */ protected static HashMap ccStats = new HashMap(cacheSize); /** * toString count for char chunk. */ protected static int ccCount = 0; /** * Cache for char chunk. */ protected static CharEntry[] ccCache = null; /** * Access count. */ protected static int accessCount = 0; /** * Hit count. */ protected static int hitCount = 0; // ------------------------------------------------------------ Properties /** * @return Returns the cacheSize. */ public int getCacheSize() { return cacheSize; } /** * @param cacheSize The cacheSize to set. */ public void setCacheSize(int cacheSize) { StringCache.cacheSize = cacheSize; } /** * @return Returns the enabled. */ public boolean getByteEnabled() { return byteEnabled; } /** * @param byteEnabled The enabled to set. */ public void setByteEnabled(boolean byteEnabled) { StringCache.byteEnabled = byteEnabled; } /** * @return Returns the enabled. */ public boolean getCharEnabled() { return charEnabled; } /** * @param charEnabled The enabled to set. */ public void setCharEnabled(boolean charEnabled) { StringCache.charEnabled = charEnabled; } /** * @return Returns the trainThreshold. */ public int getTrainThreshold() { return trainThreshold; } /** * @param trainThreshold The trainThreshold to set. */ public void setTrainThreshold(int trainThreshold) { StringCache.trainThreshold = trainThreshold; } /** * @return Returns the accessCount. */ public int getAccessCount() { return accessCount; } /** * @return Returns the hitCount. */ public int getHitCount() { return hitCount; } // -------------------------------------------------- Public Static Methods public void reset() { hitCount = 0; accessCount = 0; synchronized (bcStats) { bcCache = null; bcCount = 0; } synchronized (ccStats) { ccCache = null; ccCount = 0; } } public static String toString(ByteChunk bc) { // If the cache is null, then either caching is disabled, or we're // still training if (bcCache == null) { String value = bc.toStringInternal(); if (byteEnabled && (value.length() < maxStringSize)) { // If training, everything is synced synchronized (bcStats) { // If the cache has been generated on a previous invocation // while waiting for the lock, just return the toString // value we just calculated if (bcCache != null) { return value; } // Two cases: either we just exceeded the train count, in // which case the cache must be created, or we just update // the count for the string if (bcCount > trainThreshold) { long t1 = System.currentTimeMillis(); // Sort the entries according to occurrence TreeMap> tempMap = new TreeMap>(); for (Entry item : bcStats.entrySet()) { ByteEntry entry = item.getKey(); int[] countA = item.getValue(); Integer count = Integer.valueOf(countA[0]); // Add to the list for that count ArrayList list = tempMap.get(count); if (list == null) { // Create list list = new ArrayList(); tempMap.put(count, list); } list.add(entry); } // Allocate array of the right size int size = bcStats.size(); if (size > cacheSize) { size = cacheSize; } ByteEntry[] tempbcCache = new ByteEntry[size]; // Fill it up using an alphabetical order // and a dumb insert sort ByteChunk tempChunk = new ByteChunk(); int n = 0; while (n < size) { Object key = tempMap.lastKey(); ArrayList list = tempMap.get(key); for (int i = 0; i < list.size() && n < size; i++) { ByteEntry entry = list.get(i); tempChunk.setBytes(entry.name, 0, entry.name.length); int insertPos = findClosest(tempChunk, tempbcCache, n); if (insertPos == n) { tempbcCache[n + 1] = entry; } else { System.arraycopy(tempbcCache, insertPos + 1, tempbcCache, insertPos + 2, n - insertPos - 1); tempbcCache[insertPos + 1] = entry; } n++; } tempMap.remove(key); } bcCount = 0; bcStats.clear(); bcCache = tempbcCache; if (log.isDebugEnabled()) { long t2 = System.currentTimeMillis(); log.debug("ByteCache generation time: " + (t2 - t1) + "ms"); } } else { bcCount++; // Allocate new ByteEntry for the lookup ByteEntry entry = new ByteEntry(); entry.value = value; int[] count = bcStats.get(entry); if (count == null) { int end = bc.getEnd(); int start = bc.getStart(); // Create byte array and copy bytes entry.name = new byte[bc.getLength()]; System.arraycopy(bc.getBuffer(), start, entry.name, 0, end - start); // Set encoding entry.charset = bc.getCharset(); // Initialize occurrence count to one count = new int[1]; count[0] = 1; // Set in the stats hash map bcStats.put(entry, count); } else { count[0] = count[0] + 1; } } } } return value; } else { accessCount++; // Find the corresponding String String result = find(bc); if (result == null) { return bc.toStringInternal(); } // Note: We don't care about safety for the stats hitCount++; return result; } } public static String toString(CharChunk cc) { // If the cache is null, then either caching is disabled, or we're // still training if (ccCache == null) { String value = cc.toStringInternal(); if (charEnabled && (value.length() < maxStringSize)) { // If training, everything is synced synchronized (ccStats) { // If the cache has been generated on a previous invocation // while waiting for the lock, just return the toString // value we just calculated if (ccCache != null) { return value; } // Two cases: either we just exceeded the train count, in // which case the cache must be created, or we just update // the count for the string if (ccCount > trainThreshold) { long t1 = System.currentTimeMillis(); // Sort the entries according to occurrence TreeMap> tempMap = new TreeMap>(); for (Entry item : ccStats.entrySet()) { CharEntry entry = item.getKey(); int[] countA = item.getValue(); Integer count = Integer.valueOf(countA[0]); // Add to the list for that count ArrayList list = tempMap.get(count); if (list == null) { // Create list list = new ArrayList(); tempMap.put(count, list); } list.add(entry); } // Allocate array of the right size int size = ccStats.size(); if (size > cacheSize) { size = cacheSize; } CharEntry[] tempccCache = new CharEntry[size]; // Fill it up using an alphabetical order // and a dumb insert sort CharChunk tempChunk = new CharChunk(); int n = 0; while (n < size) { Object key = tempMap.lastKey(); ArrayList list = tempMap.get(key); for (int i = 0; i < list.size() && n < size; i++) { CharEntry entry = list.get(i); tempChunk.setChars(entry.name, 0, entry.name.length); int insertPos = findClosest(tempChunk, tempccCache, n); if (insertPos == n) { tempccCache[n + 1] = entry; } else { System.arraycopy(tempccCache, insertPos + 1, tempccCache, insertPos + 2, n - insertPos - 1); tempccCache[insertPos + 1] = entry; } n++; } tempMap.remove(key); } ccCount = 0; ccStats.clear(); ccCache = tempccCache; if (log.isDebugEnabled()) { long t2 = System.currentTimeMillis(); log.debug("CharCache generation time: " + (t2 - t1) + "ms"); } } else { ccCount++; // Allocate new CharEntry for the lookup CharEntry entry = new CharEntry(); entry.value = value; int[] count = ccStats.get(entry); if (count == null) { int end = cc.getEnd(); int start = cc.getStart(); // Create char array and copy chars entry.name = new char[cc.getLength()]; System.arraycopy(cc.getBuffer(), start, entry.name, 0, end - start); // Initialize occurrence count to one count = new int[1]; count[0] = 1; // Set in the stats hash map ccStats.put(entry, count); } else { count[0] = count[0] + 1; } } } } return value; } else { accessCount++; // Find the corresponding String String result = find(cc); if (result == null) { return cc.toStringInternal(); } // Note: We don't care about safety for the stats hitCount++; return result; } } // ----------------------------------------------------- Protected Methods /** * Compare given byte chunk with byte array. * Return -1, 0 or +1 if inferior, equal, or superior to the String. */ protected static final int compare(ByteChunk name, byte[] compareTo) { int result = 0; byte[] b = name.getBuffer(); int start = name.getStart(); int end = name.getEnd(); int len = compareTo.length; if ((end - start) < len) { len = end - start; } for (int i = 0; (i < len) && (result == 0); i++) { if (b[i + start] > compareTo[i]) { result = 1; } else if (b[i + start] < compareTo[i]) { result = -1; } } if (result == 0) { if (compareTo.length > (end - start)) { result = -1; } else if (compareTo.length < (end - start)) { result = 1; } } return result; } /** * Find an entry given its name in the cache and return the associated * String. */ protected static final String find(ByteChunk name) { int pos = findClosest(name, bcCache, bcCache.length); if ((pos < 0) || (compare(name, bcCache[pos].name) != 0) || !(name.getCharset().equals(bcCache[pos].charset))) { return null; } else { return bcCache[pos].value; } } /** * Find an entry given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ protected static final int findClosest(ByteChunk name, ByteEntry[] array, int len) { int a = 0; int b = len - 1; // Special cases: -1 and 0 if (b == -1) { return -1; } if (compare(name, array[0].name) < 0) { return -1; } if (b == 0) { return 0; } int i = 0; while (true) { i = (b + a) >>> 1; int result = compare(name, array[i].name); if (result == 1) { a = i; } else if (result == 0) { return i; } else { b = i; } if ((b - a) == 1) { int result2 = compare(name, array[b].name); if (result2 < 0) { return a; } else { return b; } } } } /** * Compare given char chunk with char array. * Return -1, 0 or +1 if inferior, equal, or superior to the String. */ protected static final int compare(CharChunk name, char[] compareTo) { int result = 0; char[] c = name.getBuffer(); int start = name.getStart(); int end = name.getEnd(); int len = compareTo.length; if ((end - start) < len) { len = end - start; } for (int i = 0; (i < len) && (result == 0); i++) { if (c[i + start] > compareTo[i]) { result = 1; } else if (c[i + start] < compareTo[i]) { result = -1; } } if (result == 0) { if (compareTo.length > (end - start)) { result = -1; } else if (compareTo.length < (end - start)) { result = 1; } } return result; } /** * Find an entry given its name in the cache and return the associated * String. */ protected static final String find(CharChunk name) { int pos = findClosest(name, ccCache, ccCache.length); if ((pos < 0) || (compare(name, ccCache[pos].name) != 0)) { return null; } else { return ccCache[pos].value; } } /** * Find an entry given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ protected static final int findClosest(CharChunk name, CharEntry[] array, int len) { int a = 0; int b = len - 1; // Special cases: -1 and 0 if (b == -1) { return -1; } if (compare(name, array[0].name) < 0 ) { return -1; } if (b == 0) { return 0; } int i = 0; while (true) { i = (b + a) >>> 1; int result = compare(name, array[i].name); if (result == 1) { a = i; } else if (result == 0) { return i; } else { b = i; } if ((b - a) == 1) { int result2 = compare(name, array[b].name); if (result2 < 0) { return a; } else { return b; } } } } // -------------------------------------------------- ByteEntry Inner Class public static class ByteEntry { public byte[] name = null; public Charset charset = null; public String value = null; @Override public String toString() { return value; } @Override public int hashCode() { return value.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof ByteEntry) { return value.equals(((ByteEntry) obj).value); } return false; } } // -------------------------------------------------- CharEntry Inner Class public static class CharEntry { public char[] name = null; public String value = null; @Override public String toString() { return value; } @Override public int hashCode() { return value.hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof CharEntry) { return value.equals(((CharEntry) obj).value); } return false; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/Ascii.java0000644000175100017510000001561712271446130023021 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; /** * This class implements some basic ASCII character handling functions. * * @author dac@eng.sun.com * @author James Todd [gonzo@eng.sun.com] */ public final class Ascii { /* * Character translation tables. */ private static final byte[] toUpper = new byte[256]; private static final byte[] toLower = new byte[256]; /* * Character type tables. */ private static final boolean[] isAlpha = new boolean[256]; private static final boolean[] isUpper = new boolean[256]; private static final boolean[] isLower = new boolean[256]; private static final boolean[] isWhite = new boolean[256]; private static final boolean[] isDigit = new boolean[256]; /* * Initialize character translation and type tables. */ static { for (int i = 0; i < 256; i++) { toUpper[i] = (byte)i; toLower[i] = (byte)i; } for (int lc = 'a'; lc <= 'z'; lc++) { int uc = lc + 'A' - 'a'; toUpper[lc] = (byte)uc; toLower[uc] = (byte)lc; isAlpha[lc] = true; isAlpha[uc] = true; isLower[lc] = true; isUpper[uc] = true; } isWhite[ ' '] = true; isWhite['\t'] = true; isWhite['\r'] = true; isWhite['\n'] = true; isWhite['\f'] = true; isWhite['\b'] = true; for (int d = '0'; d <= '9'; d++) { isDigit[d] = true; } } /** * Returns the upper case equivalent of the specified ASCII character. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static int toUpper(int c) { return toUpper[c & 0xff] & 0xff; } /** * Returns the lower case equivalent of the specified ASCII character. */ public static int toLower(int c) { return toLower[c & 0xff] & 0xff; } /** * Returns true if the specified ASCII character is upper or lower case. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static boolean isAlpha(int c) { return isAlpha[c & 0xff]; } /** * Returns true if the specified ASCII character is upper case. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static boolean isUpper(int c) { return isUpper[c & 0xff]; } /** * Returns true if the specified ASCII character is lower case. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static boolean isLower(int c) { return isLower[c & 0xff]; } /** * Returns true if the specified ASCII character is white space. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static boolean isWhite(int c) { return isWhite[c & 0xff]; } /** * Returns true if the specified ASCII character is a digit. */ public static boolean isDigit(int c) { return isDigit[c & 0xff]; } /** * Parses an unsigned integer from the specified subarray of bytes. * @param b the bytes to parse * @param off the start offset of the bytes * @param len the length of the bytes * @exception NumberFormatException if the integer format was invalid * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static int parseInt(byte[] b, int off, int len) throws NumberFormatException { int c; if (b == null || len <= 0 || !isDigit(c = b[off++])) { throw new NumberFormatException(); } int n = c - '0'; while (--len > 0) { if (!isDigit(c = b[off++])) { throw new NumberFormatException(); } n = n * 10 + c - '0'; } return n; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static int parseInt(char[] b, int off, int len) throws NumberFormatException { int c; if (b == null || len <= 0 || !isDigit(c = b[off++])) { throw new NumberFormatException(); } int n = c - '0'; while (--len > 0) { if (!isDigit(c = b[off++])) { throw new NumberFormatException(); } n = n * 10 + c - '0'; } return n; } /** * Parses an unsigned long from the specified subarray of bytes. * @param b the bytes to parse * @param off the start offset of the bytes * @param len the length of the bytes * @exception NumberFormatException if the long format was invalid */ public static long parseLong(byte[] b, int off, int len) throws NumberFormatException { int c; if (b == null || len <= 0 || !isDigit(c = b[off++])) { throw new NumberFormatException(); } long n = c - '0'; long m; while (--len > 0) { if (!isDigit(c = b[off++])) { throw new NumberFormatException(); } m = n * 10 + c - '0'; if (m < n) { // Overflow throw new NumberFormatException(); } else { n = m; } } return n; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static long parseLong(char[] b, int off, int len) throws NumberFormatException { int c; if (b == null || len <= 0 || !isDigit(c = b[off++])) { throw new NumberFormatException(); } long n = c - '0'; long m; while (--len > 0) { if (!isDigit(c = b[off++])) { throw new NumberFormatException(); } m = n * 10 + c - '0'; if (m < n) { // Overflow throw new NumberFormatException(); } else { n = m; } } return n; } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/Constants.java0000644000175100017510000000174411656666735023766 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; /** * String constants for the file package. */ public final class Constants { public static final String Package = "org.apache.tomcat.util.buf"; } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/LocalStrings.properties0000644000175100017510000000174311703372215025644 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. b2cConverter.unknownEncoding=The character encoding [{0}] is not supported c2bConverter.recycleFailed=Failed to recycle the C2B Converter. Creating new BufferedWriter, WriteConvertor and IntermediateOutputStream. tomcat7-7.0.52/java/org/apache/tomcat/util/buf/ByteChunk.java0000644000175100017510000006340312271446130023661 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.IOException; import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; /* * In a server it is very important to be able to operate on * the original byte[] without converting everything to chars. * Some protocols are ASCII only, and some allow different * non-UNICODE encodings. The encoding is not known beforehand, * and can even change during the execution of the protocol. * ( for example a multipart message may have parts with different * encoding ) * * For HTTP it is not very clear how the encoding of RequestURI * and mime values can be determined, but it is a great advantage * to be able to parse the request without converting to string. */ // TODO: This class could either extend ByteBuffer, or better a ByteBuffer // inside this way it could provide the search/etc on ByteBuffer, as a helper. /** * This class is used to represent a chunk of bytes, and * utilities to manipulate byte[]. * * The buffer can be modified and used for both input and output. * * There are 2 modes: The chunk can be associated with a sink - ByteInputChannel * or ByteOutputChannel, which will be used when the buffer is empty (on input) * or filled (on output). * For output, it can also grow. This operating mode is selected by calling * setLimit() or allocate(initial, limit) with limit != -1. * * Various search and append method are defined - similar with String and * StringBuffer, but operating on bytes. * * This is important because it allows processing the http headers directly on * the received bytes, without converting to chars and Strings until the strings * are needed. In addition, the charset is determined later, from headers or * user code. * * @author dac@sun.com * @author James Todd [gonzo@sun.com] * @author Costin Manolache * @author Remy Maucherat */ public final class ByteChunk implements Cloneable, Serializable { private static final long serialVersionUID = 1L; /** Input interface, used when the buffer is empty * * Same as java.nio.channel.ReadableByteChannel */ public static interface ByteInputChannel { /** * Read new bytes ( usually the internal conversion buffer ). * The implementation is allowed to ignore the parameters, * and mutate the chunk if it wishes to implement its own buffering. */ public int realReadBytes(byte cbuf[], int off, int len) throws IOException; } /** Same as java.nio.channel.WrittableByteChannel. */ public static interface ByteOutputChannel { /** * Send the bytes ( usually the internal conversion buffer ). * Expect 8k output if the buffer is full. */ public void realWriteBytes(byte cbuf[], int off, int len) throws IOException; } // -------------------- /** Default encoding used to convert to strings. It should be UTF8, as most standards seem to converge, but the servlet API requires 8859_1, and this object is used mostly for servlets. */ public static final Charset DEFAULT_CHARSET = B2CConverter.ISO_8859_1; // byte[] private byte[] buff; private int start=0; private int end; private Charset charset; private boolean isSet=false; // XXX // How much can it grow, when data is added private int limit=-1; private ByteInputChannel in = null; private ByteOutputChannel out = null; private boolean optimizedWrite=true; /** * Creates a new, uninitialized ByteChunk object. */ public ByteChunk() { // NO-OP } public ByteChunk( int initial ) { allocate( initial, -1 ); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public ByteChunk getClone() { try { return (ByteChunk)this.clone(); } catch( Exception ex) { return null; } } public boolean isNull() { return ! isSet; // buff==null; } /** * Resets the message buff to an uninitialized state. */ public void recycle() { // buff = null; charset=null; start=0; end=0; isSet=false; } public void reset() { buff=null; } // -------------------- Setup -------------------- public void allocate( int initial, int limit ) { if( buff==null || buff.length < initial ) { buff=new byte[initial]; } this.limit=limit; start=0; end=0; isSet=true; } /** * Sets the message bytes to the specified subarray of bytes. * * @param b the ascii bytes * @param off the start offset of the bytes * @param len the length of the bytes */ public void setBytes(byte[] b, int off, int len) { buff = b; start = off; end = start+ len; isSet=true; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void setOptimizedWrite(boolean optimizedWrite) { this.optimizedWrite = optimizedWrite; } public void setCharset(Charset charset) { this.charset = charset; } public Charset getCharset() { if (charset == null) { charset = DEFAULT_CHARSET; } return charset; } /** * Returns the message bytes. */ public byte[] getBytes() { return getBuffer(); } /** * Returns the message bytes. */ public byte[] getBuffer() { return buff; } /** * Returns the start offset of the bytes. * For output this is the end of the buffer. */ public int getStart() { return start; } public int getOffset() { return start; } public void setOffset(int off) { if (end < off ) { end=off; } start=off; } /** * Returns the length of the bytes. * XXX need to clean this up */ public int getLength() { return end-start; } /** Maximum amount of data in this buffer. * * If -1 or not set, the buffer will grow indefinitely. * Can be smaller than the current buffer size ( which will not shrink ). * When the limit is reached, the buffer will be flushed ( if out is set ) * or throw exception. */ public void setLimit(int limit) { this.limit=limit; } public int getLimit() { return limit; } /** * When the buffer is empty, read the data from the input channel. */ public void setByteInputChannel(ByteInputChannel in) { this.in = in; } /** When the buffer is full, write the data to the output channel. * Also used when large amount of data is appended. * * If not set, the buffer will grow to the limit. */ public void setByteOutputChannel(ByteOutputChannel out) { this.out=out; } public int getEnd() { return end; } public void setEnd( int i ) { end=i; } // -------------------- Adding data to the buffer -------------------- /** Append a char, by casting it to byte. This IS NOT intended for unicode. * * @param c * @throws IOException * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void append( char c ) throws IOException { append( (byte)c); } public void append( byte b ) throws IOException { makeSpace( 1 ); // couldn't make space if( limit >0 && end >= limit ) { flushBuffer(); } buff[end++]=b; } public void append( ByteChunk src ) throws IOException { append( src.getBytes(), src.getStart(), src.getLength()); } /** Add data to the buffer */ public void append( byte src[], int off, int len ) throws IOException { // will grow, up to limit makeSpace( len ); // if we don't have limit: makeSpace can grow as it wants if( limit < 0 ) { // assert: makeSpace made enough space System.arraycopy( src, off, buff, end, len ); end+=len; return; } // Optimize on a common case. // If the buffer is empty and the source is going to fill up all the // space in buffer, may as well write it directly to the output, // and avoid an extra copy if ( optimizedWrite && len == limit && end == start && out != null ) { out.realWriteBytes( src, off, len ); return; } // if we have limit and we're below if( len <= limit - end ) { // makeSpace will grow the buffer to the limit, // so we have space System.arraycopy( src, off, buff, end, len ); end+=len; return; } // need more space than we can afford, need to flush // buffer // the buffer is already at ( or bigger than ) limit // We chunk the data into slices fitting in the buffer limit, although // if the data is written directly if it doesn't fit int avail=limit-end; System.arraycopy(src, off, buff, end, avail); end += avail; flushBuffer(); int remain = len - avail; while (remain > (limit - end)) { out.realWriteBytes( src, (off + len) - remain, limit - end ); remain = remain - (limit - end); } System.arraycopy(src, (off + len) - remain, buff, end, remain); end += remain; } // -------------------- Removing data from the buffer -------------------- public int substract() throws IOException { if ((end - start) == 0) { if (in == null) { return -1; } int n = in.realReadBytes( buff, 0, buff.length ); if (n < 0) { return -1; } } return (buff[start++] & 0xFF); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public int substract(ByteChunk src) throws IOException { if ((end - start) == 0) { if (in == null) { return -1; } int n = in.realReadBytes( buff, 0, buff.length ); if (n < 0) { return -1; } } int len = getLength(); src.append(buff, start, len); start = end; return len; } public byte substractB() throws IOException { if ((end - start) == 0) { if (in == null) return -1; int n = in.realReadBytes( buff, 0, buff.length ); if (n < 0) return -1; } return (buff[start++]); } public int substract( byte src[], int off, int len ) throws IOException { if ((end - start) == 0) { if (in == null) { return -1; } int n = in.realReadBytes( buff, 0, buff.length ); if (n < 0) { return -1; } } int n = len; if (len > getLength()) { n = getLength(); } System.arraycopy(buff, start, src, off, n); start += n; return n; } /** * Send the buffer to the sink. Called by append() when the limit is * reached. You can also call it explicitly to force the data to be written. * * @throws IOException */ public void flushBuffer() throws IOException { //assert out!=null if( out==null ) { throw new IOException( "Buffer overflow, no sink " + limit + " " + buff.length ); } out.realWriteBytes( buff, start, end-start ); end=start; } /** * Make space for len chars. If len is small, allocate a reserve space too. * Never grow bigger than limit. */ public void makeSpace(int count) { byte[] tmp = null; int newSize; int desiredSize=end + count; // Can't grow above the limit if( limit > 0 && desiredSize > limit) { desiredSize=limit; } if( buff==null ) { if( desiredSize < 256 ) { desiredSize=256; // take a minimum } buff=new byte[desiredSize]; } // limit < buf.length ( the buffer is already big ) // or we already have space XXX if( desiredSize <= buff.length ) { return; } // grow in larger chunks if( desiredSize < 2 * buff.length ) { newSize= buff.length * 2; if( limit >0 && newSize > limit ) { newSize=limit; } tmp=new byte[newSize]; } else { newSize= buff.length * 2 + count ; if( limit > 0 && newSize > limit ) { newSize=limit; } tmp=new byte[newSize]; } System.arraycopy(buff, start, tmp, 0, end-start); buff = tmp; tmp = null; end=end-start; start=0; } // -------------------- Conversion and getters -------------------- @Override public String toString() { if (null == buff) { return null; } else if (end-start == 0) { return ""; } return StringCache.toString(this); } public String toStringInternal() { if (charset == null) { charset = DEFAULT_CHARSET; } // new String(byte[], int, int, Charset) takes a defensive copy of the // entire byte array. This is expensive if only a small subset of the // bytes will be used. The code below is from Apache Harmony. CharBuffer cb; cb = charset.decode(ByteBuffer.wrap(buff, start, end-start)); return new String(cb.array(), cb.arrayOffset(), cb.length()); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public int getInt() { return Ascii.parseInt(buff, start,end-start); } public long getLong() { return Ascii.parseLong(buff, start,end-start); } // -------------------- equals -------------------- /** * Compares the message bytes to the specified String object. * @param s the String to compare * @return true if the comparison succeeded, false otherwise */ public boolean equals(String s) { // XXX ENCODING - this only works if encoding is UTF8-compat // ( ok for tomcat, where we compare ascii - header names, etc )!!! byte[] b = buff; int blen = end-start; if (b == null || blen != s.length()) { return false; } int boff = start; for (int i = 0; i < blen; i++) { if (b[boff++] != s.charAt(i)) { return false; } } return true; } /** * Compares the message bytes to the specified String object. * @param s the String to compare * @return true if the comparison succeeded, false otherwise */ public boolean equalsIgnoreCase(String s) { byte[] b = buff; int blen = end-start; if (b == null || blen != s.length()) { return false; } int boff = start; for (int i = 0; i < blen; i++) { if (Ascii.toLower(b[boff++]) != Ascii.toLower(s.charAt(i))) { return false; } } return true; } public boolean equals( ByteChunk bb ) { return equals( bb.getBytes(), bb.getStart(), bb.getLength()); } public boolean equals( byte b2[], int off2, int len2) { byte b1[]=buff; if( b1==null && b2==null ) { return true; } int len=end-start; if ( len2 != len || b1==null || b2==null ) { return false; } int off1 = start; while ( len-- > 0) { if (b1[off1++] != b2[off2++]) { return false; } } return true; } public boolean equals( CharChunk cc ) { return equals( cc.getChars(), cc.getStart(), cc.getLength()); } public boolean equals( char c2[], int off2, int len2) { // XXX works only for enc compatible with ASCII/UTF !!! byte b1[]=buff; if( c2==null && b1==null ) { return true; } if (b1== null || c2==null || end-start != len2 ) { return false; } int off1 = start; int len=end-start; while ( len-- > 0) { if ( (char)b1[off1++] != c2[off2++]) { return false; } } return true; } /** * Returns true if the message bytes starts with the specified string. * @param s the string * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public boolean startsWith(String s) { // Works only if enc==UTF byte[] b = buff; int blen = s.length(); if (b == null || blen > end-start) { return false; } int boff = start; for (int i = 0; i < blen; i++) { if (b[boff++] != s.charAt(i)) { return false; } } return true; } /** * Returns true if the message bytes start with the specified byte array. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public boolean startsWith(byte[] b2) { byte[] b1 = buff; if (b1 == null && b2 == null) { return true; } int len = end - start; if (b1 == null || b2 == null || b2.length > len) { return false; } for (int i = start, j = 0; i < end && j < b2.length;) { if (b1[i++] != b2[j++]) { return false; } } return true; } /** * Returns true if the message bytes starts with the specified string. * @param s the string * @param pos The position */ public boolean startsWithIgnoreCase(String s, int pos) { byte[] b = buff; int len = s.length(); if (b == null || len+pos > end-start) { return false; } int off = start+pos; for (int i = 0; i < len; i++) { if (Ascii.toLower( b[off++] ) != Ascii.toLower( s.charAt(i))) { return false; } } return true; } public int indexOf( String src, int srcOff, int srcLen, int myOff ) { char first=src.charAt( srcOff ); // Look for first char int srcEnd = srcOff + srcLen; mainLoop: for( int i=myOff+start; i <= (end - srcLen); i++ ) { if( buff[i] != first ) { continue; } // found first char, now look for a match int myPos=i+1; for( int srcPos=srcOff + 1; srcPos< srcEnd;) { if( buff[myPos++] != src.charAt( srcPos++ )) { continue mainLoop; } } return i-start; // found it } return -1; } // -------------------- Hash code -------------------- // normal hash. public int hash() { return hashBytes( buff, start, end-start); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public int hashIgnoreCase() { return hashBytesIC( buff, start, end-start ); } private static int hashBytes( byte buff[], int start, int bytesLen ) { int max=start+bytesLen; byte bb[]=buff; int code=0; for (int i = start; i < max ; i++) { code = code * 37 + bb[i]; } return code; } private static int hashBytesIC( byte bytes[], int start, int bytesLen ) { int max=start+bytesLen; byte bb[]=bytes; int code=0; for (int i = start; i < max ; i++) { code = code * 37 + Ascii.toLower(bb[i]); } return code; } /** * Returns the first instance of the given character in this ByteChunk * starting at the specified byte. If the character is not found, -1 is * returned. *
    * NOTE: This only works for characters in the range 0-127. * * @param c The character * @param starting The start position * @return The position of the first instance of the character or * -1 if the character is not found. */ public int indexOf(char c, int starting) { int ret = indexOf(buff, start + starting, end, c); return (ret >= start) ? ret - start : -1; } /** * Returns the first instance of the given character in the given byte array * between the specified start and end. *
    * NOTE: This only works for characters in the range 0-127. * * @param bytes The byte array to search * @param start The point to start searching from in the byte array * @param end The point to stop searching in the byte array * @param c The character to search for * @return The position of the first instance of the character or -1 * if the character is not found. */ public static int indexOf(byte bytes[], int start, int end, char c) { int offset = start; while (offset < end) { byte b=bytes[offset]; if (b == c) { return offset; } offset++; } return -1; } /** * Returns the first instance of the given byte in the byte array between * the specified start and end. * * @param bytes The byte array to search * @param start The point to start searching from in the byte array * @param end The point to stop searching in the byte array * @param b The byte to search for * @return The position of the first instance of the byte or -1 if the * byte is not found. */ public static int findByte(byte bytes[], int start, int end, byte b) { int offset = start; while (offset < end) { if (bytes[offset] == b) { return offset; } offset++; } return -1; } /** * Returns the first instance of any of the given bytes in the byte array * between the specified start and end. * * @param bytes The byte array to search * @param start The point to start searching from in the byte array * @param end The point to stop searching in the byte array * @param b The array of bytes to search for * @return The position of the first instance of the byte or -1 if the * byte is not found. */ public static int findBytes(byte bytes[], int start, int end, byte b[]) { int blen = b.length; int offset = start; while (offset < end) { for (int i = 0; i < blen; i++) { if (bytes[offset] == b[i]) { return offset; } } offset++; } return -1; } /** * Returns the first instance of any byte that is not one of the given bytes * in the byte array between the specified start and end. * * @param bytes The byte array to search * @param start The point to start searching from in the byte array * @param end The point to stop searching in the byte array * @param b The list of bytes to search for * @return The position of the first instance a byte that is not * in the list of bytes to search for or -1 if no such byte * is found. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static int findNotBytes(byte bytes[], int start, int end, byte b[]) { int blen = b.length; int offset = start; boolean found; while (offset < end) { found = true; for (int i = 0; i < blen; i++) { if (bytes[offset] == b[i]) { found=false; break; } } if (found) { return offset; } offset++; } return -1; } /** * Convert specified String to a byte array. This ONLY WORKS for ascii, UTF * chars will be truncated. * * @param value to convert to byte array * @return the byte array value */ public static final byte[] convertToBytes(String value) { byte[] result = new byte[value.length()]; for (int i = 0; i < value.length(); i++) { result[i] = (byte) value.charAt(i); } return result; } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/CharChunk.java0000644000175100017510000005032512271446130023632 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.IOException; import java.io.Serializable; /** * Utilities to manipulate char chunks. While String is * the easiest way to manipulate chars ( search, substrings, etc), * it is known to not be the most efficient solution - Strings are * designed as immutable and secure objects. * * @author dac@sun.com * @author James Todd [gonzo@sun.com] * @author Costin Manolache * @author Remy Maucherat */ public final class CharChunk implements Cloneable, Serializable, CharSequence { private static final long serialVersionUID = 1L; // Input interface, used when the buffer is emptied. public static interface CharInputChannel { /** * Read new bytes ( usually the internal conversion buffer ). * The implementation is allowed to ignore the parameters, * and mutate the chunk if it wishes to implement its own buffering. */ public int realReadChars(char cbuf[], int off, int len) throws IOException; } /** * When we need more space we'll either * grow the buffer ( up to the limit ) or send it to a channel. */ public static interface CharOutputChannel { /** Send the bytes ( usually the internal conversion buffer ). * Expect 8k output if the buffer is full. */ public void realWriteChars(char cbuf[], int off, int len) throws IOException; } // -------------------- // char[] private char buff[]; private int start; private int end; private boolean isSet=false; // XXX // -1: grow indefinitely // maximum amount to be cached private int limit=-1; private CharInputChannel in = null; private CharOutputChannel out = null; private boolean optimizedWrite=true; /** * Creates a new, uninitialized CharChunk object. */ public CharChunk() { } public CharChunk(int size) { allocate( size, -1 ); } // -------------------- /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public CharChunk getClone() { try { return (CharChunk)this.clone(); } catch( Exception ex) { return null; } } public boolean isNull() { if( end > 0 ) { return false; } return !isSet; //XXX } /** * Resets the message bytes to an uninitialized state. */ public void recycle() { // buff=null; isSet=false; // XXX start=0; end=0; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void reset() { buff=null; } // -------------------- Setup -------------------- public void allocate( int initial, int limit ) { if( buff==null || buff.length < initial ) { buff=new char[initial]; } this.limit=limit; start=0; end=0; isSet=true; } public void setOptimizedWrite(boolean optimizedWrite) { this.optimizedWrite = optimizedWrite; } public void setChars( char[] c, int off, int len ) { buff=c; start=off; end=start + len; isSet=true; } /** Maximum amount of data in this buffer. * * If -1 or not set, the buffer will grow indefinitely. * Can be smaller than the current buffer size ( which will not shrink ). * When the limit is reached, the buffer will be flushed ( if out is set ) * or throw exception. */ public void setLimit(int limit) { this.limit=limit; } public int getLimit() { return limit; } /** * When the buffer is empty, read the data from the input channel. */ public void setCharInputChannel(CharInputChannel in) { this.in = in; } /** When the buffer is full, write the data to the output channel. * Also used when large amount of data is appended. * * If not set, the buffer will grow to the limit. */ public void setCharOutputChannel(CharOutputChannel out) { this.out=out; } // compat public char[] getChars() { return getBuffer(); } public char[] getBuffer() { return buff; } /** * Returns the start offset of the bytes. * For output this is the end of the buffer. */ public int getStart() { return start; } public int getOffset() { return start; } /** * Returns the start offset of the bytes. */ public void setOffset(int off) { start=off; } /** * Returns the length of the bytes. */ public int getLength() { return end-start; } public int getEnd() { return end; } public void setEnd( int i ) { end=i; } // -------------------- Adding data -------------------- public void append( char b ) throws IOException { makeSpace( 1 ); // couldn't make space if( limit >0 && end >= limit ) { flushBuffer(); } buff[end++]=b; } public void append( CharChunk src ) throws IOException { append( src.getBuffer(), src.getOffset(), src.getLength()); } /** Add data to the buffer */ public void append( char src[], int off, int len ) throws IOException { // will grow, up to limit makeSpace( len ); // if we don't have limit: makeSpace can grow as it wants if( limit < 0 ) { // assert: makeSpace made enough space System.arraycopy( src, off, buff, end, len ); end+=len; return; } // Optimize on a common case. // If the source is going to fill up all the space in buffer, may // as well write it directly to the output, and avoid an extra copy if ( optimizedWrite && len == limit && end == start && out != null ) { out.realWriteChars( src, off, len ); return; } // if we have limit and we're below if( len <= limit - end ) { // makeSpace will grow the buffer to the limit, // so we have space System.arraycopy( src, off, buff, end, len ); end+=len; return; } // need more space than we can afford, need to flush // buffer // the buffer is already at ( or bigger than ) limit // Optimization: // If len-avail < length ( i.e. after we fill the buffer with // what we can, the remaining will fit in the buffer ) we'll just // copy the first part, flush, then copy the second part - 1 write // and still have some space for more. We'll still have 2 writes, but // we write more on the first. if( len + end < 2 * limit ) { /* If the request length exceeds the size of the output buffer, flush the output buffer and then write the data directly. We can't avoid 2 writes, but we can write more on the second */ int avail=limit-end; System.arraycopy(src, off, buff, end, avail); end += avail; flushBuffer(); System.arraycopy(src, off+avail, buff, end, len - avail); end+= len - avail; } else { // len > buf.length + avail // long write - flush the buffer and write the rest // directly from source flushBuffer(); out.realWriteChars( src, off, len ); } } /** * Add data to the buffer. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public void append( StringBuilder sb ) throws IOException { int len=sb.length(); // will grow, up to limit makeSpace( len ); // if we don't have limit: makeSpace can grow as it wants if( limit < 0 ) { // assert: makeSpace made enough space sb.getChars(0, len, buff, end ); end+=len; return; } int off=0; int sbOff = off; int sbEnd = off + len; while (sbOff < sbEnd) { int d = min(limit - end, sbEnd - sbOff); sb.getChars( sbOff, sbOff+d, buff, end); sbOff += d; end += d; if (end >= limit) { flushBuffer(); } } } /** Append a string to the buffer */ public void append(String s) throws IOException { append(s, 0, s.length()); } /** Append a string to the buffer */ public void append(String s, int off, int len) throws IOException { if (s==null) { return; } // will grow, up to limit makeSpace( len ); // if we don't have limit: makeSpace can grow as it wants if( limit < 0 ) { // assert: makeSpace made enough space s.getChars(off, off+len, buff, end ); end+=len; return; } int sOff = off; int sEnd = off + len; while (sOff < sEnd) { int d = min(limit - end, sEnd - sOff); s.getChars( sOff, sOff+d, buff, end); sOff += d; end += d; if (end >= limit) { flushBuffer(); } } } // -------------------- Removing data from the buffer -------------------- public int substract() throws IOException { if ((end - start) == 0) { if (in == null) { return -1; } int n = in.realReadChars(buff, end, buff.length - end); if (n < 0) { return -1; } } return (buff[start++]); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public int substract(CharChunk src) throws IOException { if ((end - start) == 0) { if (in == null) { return -1; } int n = in.realReadChars( buff, end, buff.length - end); if (n < 0) { return -1; } } int len = getLength(); src.append(buff, start, len); start = end; return len; } public int substract( char src[], int off, int len ) throws IOException { if ((end - start) == 0) { if (in == null) { return -1; } int n = in.realReadChars( buff, end, buff.length - end); if (n < 0) { return -1; } } int n = len; if (len > getLength()) { n = getLength(); } System.arraycopy(buff, start, src, off, n); start += n; return n; } public void flushBuffer() throws IOException { //assert out!=null if( out==null ) { throw new IOException( "Buffer overflow, no sink " + limit + " " + buff.length ); } out.realWriteChars( buff, start, end - start ); end=start; } /** Make space for len chars. If len is small, allocate * a reserve space too. Never grow bigger than limit. */ public void makeSpace(int count) { char[] tmp = null; int newSize; int desiredSize=end + count; // Can't grow above the limit if( limit > 0 && desiredSize > limit) { desiredSize=limit; } if( buff==null ) { if( desiredSize < 256 ) { desiredSize=256; // take a minimum } buff=new char[desiredSize]; } // limit < buf.length ( the buffer is already big ) // or we already have space XXX if( desiredSize <= buff.length) { return; } // grow in larger chunks if( desiredSize < 2 * buff.length ) { newSize= buff.length * 2; if( limit >0 && newSize > limit ) { newSize=limit; } tmp=new char[newSize]; } else { newSize= buff.length * 2 + count ; if( limit > 0 && newSize > limit ) { newSize=limit; } tmp=new char[newSize]; } System.arraycopy(buff, 0, tmp, 0, end); buff = tmp; tmp = null; } // -------------------- Conversion and getters -------------------- @Override public String toString() { if (null == buff) { return null; } else if (end-start == 0) { return ""; } return StringCache.toString(this); } public String toStringInternal() { return new String(buff, start, end-start); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public int getInt() { return Ascii.parseInt(buff, start, end-start); } // -------------------- equals -------------------- /** * Compares the message bytes to the specified String object. * @param s the String to compare * @return true if the comparison succeeded, false otherwise */ public boolean equals(String s) { char[] c = buff; int len = end-start; if (c == null || len != s.length()) { return false; } int off = start; for (int i = 0; i < len; i++) { if (c[off++] != s.charAt(i)) { return false; } } return true; } /** * Compares the message bytes to the specified String object. * @param s the String to compare * @return true if the comparison succeeded, false otherwise */ public boolean equalsIgnoreCase(String s) { char[] c = buff; int len = end-start; if (c == null || len != s.length()) { return false; } int off = start; for (int i = 0; i < len; i++) { if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) { return false; } } return true; } public boolean equals(CharChunk cc) { return equals( cc.getChars(), cc.getOffset(), cc.getLength()); } public boolean equals(char b2[], int off2, int len2) { char b1[]=buff; if( b1==null && b2==null ) { return true; } if (b1== null || b2==null || end-start != len2) { return false; } int off1 = start; int len=end-start; while ( len-- > 0) { if (b1[off1++] != b2[off2++]) { return false; } } return true; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public boolean equals(byte b2[], int off2, int len2) { char b1[]=buff; if( b2==null && b1==null ) { return true; } if (b1== null || b2==null || end-start != len2) { return false; } int off1 = start; int len=end-start; while ( len-- > 0) { if ( b1[off1++] != (char)b2[off2++]) { return false; } } return true; } /** * Returns true if the message bytes starts with the specified string. * @param s the string */ public boolean startsWith(String s) { char[] c = buff; int len = s.length(); if (c == null || len > end-start) { return false; } int off = start; for (int i = 0; i < len; i++) { if (c[off++] != s.charAt(i)) { return false; } } return true; } /** * Returns true if the message bytes starts with the specified string. * @param s the string */ public boolean startsWithIgnoreCase(String s, int pos) { char[] c = buff; int len = s.length(); if (c == null || len+pos > end-start) { return false; } int off = start+pos; for (int i = 0; i < len; i++) { if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) { return false; } } return true; } /** * Returns true if the message bytes end with the specified string. * @param s the string */ public boolean endsWith(String s) { char[] c = buff; int len = s.length(); if (c == null || len > end-start) { return false; } int off = end - len; for (int i = 0; i < len; i++) { if (c[off++] != s.charAt(i)) { return false; } } return true; } // -------------------- Hash code -------------------- // normal hash. public int hash() { int code=0; for (int i = start; i < start + end-start; i++) { code = code * 37 + buff[i]; } return code; } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public int hashIgnoreCase() { int code=0; for (int i = start; i < end; i++) { code = code * 37 + Ascii.toLower(buff[i]); } return code; } public int indexOf(char c) { return indexOf( c, start); } /** * Returns true if the message bytes starts with the specified string. * @param c the character */ public int indexOf(char c, int starting) { int ret = indexOf( buff, start+starting, end, c ); return (ret >= start) ? ret - start : -1; } public static int indexOf( char chars[], int off, int cend, char qq ) { while( off < cend ) { char b=chars[off]; if( b==qq ) { return off; } off++; } return -1; } public int indexOf( String src, int srcOff, int srcLen, int myOff ) { char first=src.charAt( srcOff ); // Look for first char int srcEnd = srcOff + srcLen; for( int i=myOff+start; i <= (end - srcLen); i++ ) { if( buff[i] != first ) { continue; } // found first char, now look for a match int myPos=i+1; for( int srcPos=srcOff + 1; srcPos< srcEnd;) { if( buff[myPos++] != src.charAt( srcPos++ )) { break; } if( srcPos==srcEnd ) { return i-start; // found it } } } return -1; } // -------------------- utils private int min(int a, int b) { if (a < b) { return a; } return b; } // Char sequence impl @Override public char charAt(int index) { return buff[index + start]; } @Override public CharSequence subSequence(int start, int end) { try { CharChunk result = (CharChunk) this.clone(); result.setOffset(this.start + start); result.setEnd(this.start + end); return result; } catch (CloneNotSupportedException e) { // Cannot happen return null; } } @Override public int length() { return end - start; } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/C2BConverter.java0000644000175100017510000001120112271446130024210 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; /** * NIO based character encoder. */ public final class C2BConverter { protected CharsetEncoder encoder = null; protected ByteBuffer bb = null; protected CharBuffer cb = null; /** * Leftover buffer used for multi-characters characters. */ protected CharBuffer leftovers = null; public C2BConverter(String encoding) throws IOException { encoder = B2CConverter.getCharset(encoding).newEncoder(); // FIXME: See if unmappable/malformed behavior configuration is needed // in practice encoder.onUnmappableCharacter(CodingErrorAction.REPLACE) .onMalformedInput(CodingErrorAction.REPLACE); char[] left = new char[4]; leftovers = CharBuffer.wrap(left); } /** * Reset the encoder state. */ public void recycle() { encoder.reset(); leftovers.position(0); } public boolean isUndeflow() { return (leftovers.position() > 0); } /** * Convert the given characters to bytes. * * @param cc char input * @param bc byte output */ public void convert(CharChunk cc, ByteChunk bc) throws IOException { if ((bb == null) || (bb.array() != bc.getBuffer())) { // Create a new byte buffer if anything changed bb = ByteBuffer.wrap(bc.getBuffer(), bc.getEnd(), bc.getBuffer().length - bc.getEnd()); } else { // Initialize the byte buffer bb.limit(bc.getBuffer().length); bb.position(bc.getEnd()); } if ((cb == null) || (cb.array() != cc.getBuffer())) { // Create a new char buffer if anything changed cb = CharBuffer.wrap(cc.getBuffer(), cc.getStart(), cc.getLength()); } else { // Initialize the char buffer cb.limit(cc.getEnd()); cb.position(cc.getStart()); } CoderResult result = null; // Parse leftover if any are present if (leftovers.position() > 0) { int pos = bb.position(); // Loop until one char is encoded or there is a encoder error do { leftovers.put((char) cc.substract()); leftovers.flip(); result = encoder.encode(leftovers, bb, false); leftovers.position(leftovers.limit()); leftovers.limit(leftovers.array().length); } while (result.isUnderflow() && (bb.position() == pos)); if (result.isError() || result.isMalformed()) { result.throwException(); } cb.position(cc.getStart()); leftovers.position(0); } // Do the decoding and get the results into the byte chunk and the char // chunk result = encoder.encode(cb, bb, false); if (result.isError() || result.isMalformed()) { result.throwException(); } else if (result.isOverflow()) { // Propagate current positions to the byte chunk and char chunk bc.setEnd(bb.position()); cc.setOffset(cb.position()); } else if (result.isUnderflow()) { // Propagate current positions to the byte chunk and char chunk bc.setEnd(bb.position()); cc.setOffset(cb.position()); // Put leftovers in the leftovers char buffer if (cc.getLength() > 0) { leftovers.limit(leftovers.array().length); leftovers.position(cc.getLength()); cc.substract(leftovers.array(), 0, cc.getLength()); } } } } tomcat7-7.0.52/java/org/apache/tomcat/util/buf/HexUtils.java0000644000175100017510000000565012271446130023532 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.buf; /** * Tables useful when converting byte arrays to and from strings of hexadecimal * digits. * Code from Ajp11, from Apache's JServ. * * @author Craig R. McClanahan */ public final class HexUtils { // -------------------------------------------------------------- Constants /** * Table for HEX to DEC byte translation. */ private static final int[] DEC = { 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, }; /** * Table for DEC to HEX byte translation. */ private static final byte[] HEX = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' }; /** * Table for byte to hex string translation. */ private static final char[] hex = "0123456789abcdef".toCharArray(); // --------------------------------------------------------- Static Methods /** * Provide a mechanism for ensuring this class is loaded. * @deprecated Unused. Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static void load() { // Nothing to do } public static int getDec(int index){ // Fast for correct values, slower for incorrect ones try { return DEC[index - '0']; } catch (ArrayIndexOutOfBoundsException ex) { return -1; } } public static byte getHex(int index){ return HEX[index]; } public static String toHexString(byte[] bytes) { if(null == bytes) { return null; } StringBuilder sb = new StringBuilder(bytes.length << 1); for(int i=0; i> 4]) .append(hex[(bytes[i] & 0x0f)]) ; } return sb.toString(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/MutableInteger.java0000644000175100017510000000221412271452644024120 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util; /** * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated public class MutableInteger { protected int value = 0; public MutableInteger() {} public MutableInteger(int val) { this.value = val; } public int get() { return value;} public void set(int val) {this.value = val;} } tomcat7-7.0.52/java/org/apache/tomcat/util/threads/0000755000175100017510000000000012301126366021772 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/threads/res/0000755000175100017510000000000012301126366022563 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties0000644000175100017510000000163712271452644030012 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. threadPoolExecutor.threadStoppedToAvoidPotentialLeak = Parando hilo {0} para evita fallos potenciales de memoria tras haberse parado un contexto. tomcat7-7.0.52/java/org/apache/tomcat/util/threads/res/LocalStrings.properties0000644000175100017510000000162412271452644027317 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. threadPoolExecutor.threadStoppedToAvoidPotentialLeak=Stopping thread {0} to avoid potential memory leaks after a context was stopped. tomcat7-7.0.52/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties0000644000175100017510000000141612271452644027770 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. tomcat7-7.0.52/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties0000644000175100017510000000141612271452644030005 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. tomcat7-7.0.52/java/org/apache/tomcat/util/threads/LimitLatch.java0000644000175100017510000001175211750265702024702 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.threads; import java.util.Collection; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Shared latch that allows the latch to be acquired a limited number of times * after which all subsequent requests to acquire the latch will be placed in a * FIFO queue until one of the shares is returned. */ public class LimitLatch { private static final Log log = LogFactory.getLog(LimitLatch.class); private class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 1L; public Sync() { } @Override protected int tryAcquireShared(int ignored) { long newCount = count.incrementAndGet(); if (!released && newCount > limit) { // Limit exceeded count.decrementAndGet(); return -1; } else { return 1; } } @Override protected boolean tryReleaseShared(int arg) { count.decrementAndGet(); return true; } } private final Sync sync; private final AtomicLong count; private volatile long limit; private volatile boolean released = false; /** * Instantiates a LimitLatch object with an initial limit. * @param limit - maximum number of concurrent acquisitions of this latch */ public LimitLatch(long limit) { this.limit = limit; this.count = new AtomicLong(0); this.sync = new Sync(); } /** * Returns the current count for the latch * @return the current count for latch */ public long getCount() { return count.get(); } /** * Obtain the current limit. */ public long getLimit() { return limit; } /** * Sets a new limit. If the limit is decreased there may be a period where * more shares of the latch are acquired than the limit. In this case no * more shares of the latch will be issued until sufficient shares have been * returned to reduce the number of acquired shares of the latch to below * the new limit. If the limit is increased, threads currently in the queue * may not be issued one of the newly available shares until the next * request is made for a latch. * * @param limit The new limit */ public void setLimit(long limit) { this.limit = limit; } /** * Acquires a shared latch if one is available or waits for one if no shared * latch is current available. */ public void countUpOrAwait() throws InterruptedException { if (log.isDebugEnabled()) { log.debug("Counting up["+Thread.currentThread().getName()+"] latch="+getCount()); } sync.acquireSharedInterruptibly(1); } /** * Releases a shared latch, making it available for another thread to use. * @return the previous counter value */ public long countDown() { sync.releaseShared(0); long result = getCount(); if (log.isDebugEnabled()) { log.debug("Counting down["+Thread.currentThread().getName()+"] latch="+result); } return result; } /** * Releases all waiting threads and causes the {@link #limit} to be ignored * until {@link #reset()} is called. */ public boolean releaseAll() { released = true; return sync.releaseShared(0); } /** * Resets the latch and initializes the shared acquisition counter to zero. * @see #releaseAll() */ public void reset() { this.count.set(0); released = false; } /** * Returns true if there is at least one thread waiting to * acquire the shared lock, otherwise returns false. */ public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } /** * Provide access to the list of threads waiting to acquire this limited * shared latch. */ public Collection getQueuedThreads() { return sync.getQueuedThreads(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java0000644000175100017510000002357412271452644026437 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.threads; import java.lang.Thread.UncaughtExceptionHandler; import java.util.concurrent.BlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Same as a java.util.concurrent.ThreadPoolExecutor but implements a much more efficient * {@link #getSubmittedCount()} method, to be used to properly handle the work queue. * If a RejectedExecutionHandler is not specified a default one will be configured * and that one will always throw a RejectedExecutionException * @author fhanik * */ public class ThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor { /** * The string manager for this package. */ protected static final StringManager sm = StringManager .getManager("org.apache.tomcat.util.threads.res"); private static final Log log = LogFactory.getLog(ThreadPoolExecutor.class); /** * The number of tasks submitted but not yet finished. This includes tasks * in the queue and tasks that have been handed to a worker thread but the * latter did not start executing the task yet. * This number is always greater or equal to {@link #getActiveCount()}. */ private final AtomicInteger submittedCount = new AtomicInteger(0); private final AtomicLong lastContextStoppedTime = new AtomicLong(0L); /** * Most recent time in ms when a thread decided to kill itself to avoid * potential memory leaks. Useful to throttle the rate of renewals of * threads. */ private final AtomicLong lastTimeThreadKilledItself = new AtomicLong(0L); /** * Delay in ms between 2 threads being renewed. If negative, do not renew threads. */ private long threadRenewalDelay = Constants.DEFAULT_THREAD_RENEWAL_DELAY; public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, new RejectHandler()); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new RejectHandler()); } public long getThreadRenewalDelay() { return threadRenewalDelay; } public void setThreadRenewalDelay(long threadRenewalDelay) { this.threadRenewalDelay = threadRenewalDelay; } @Override protected void afterExecute(Runnable r, Throwable t) { submittedCount.decrementAndGet(); if (t == null) { stopCurrentThreadIfNeeded(); } } /** * If the current thread was started before the last time when a context was * stopped, an exception is thrown so that the current thread is stopped. */ protected void stopCurrentThreadIfNeeded() { if (currentThreadShouldBeStopped()) { long lastTime = lastTimeThreadKilledItself.longValue(); if (lastTime + threadRenewalDelay < System.currentTimeMillis()) { if (lastTimeThreadKilledItself.compareAndSet(lastTime, System.currentTimeMillis() + 1)) { // OK, it's really time to dispose of this thread final String msg = sm.getString( "threadPoolExecutor.threadStoppedToAvoidPotentialLeak", Thread.currentThread().getName()); Thread.currentThread().setUncaughtExceptionHandler( new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { // yes, swallow the exception log.debug(msg); } }); throw new RuntimeException(msg); } } } } protected boolean currentThreadShouldBeStopped() { if (threadRenewalDelay >= 0 && Thread.currentThread() instanceof TaskThread) { TaskThread currentTaskThread = (TaskThread) Thread.currentThread(); if (currentTaskThread.getCreationTime() < this.lastContextStoppedTime.longValue()) { return true; } } return false; } public int getSubmittedCount() { return submittedCount.get(); } /** * {@inheritDoc} */ @Override public void execute(Runnable command) { execute(command,0,TimeUnit.MILLISECONDS); } /** * Executes the given command at some time in the future. The command * may execute in a new thread, in a pooled thread, or in the calling * thread, at the discretion of the Executor implementation. * If no threads are available, it will be added to the work queue. * If the work queue is full, the system will wait for the specified * time and it throw a RejectedExecutionException if the queue is still * full after that. * * @param command the runnable task * @throws RejectedExecutionException if this task cannot be * accepted for execution - the queue is full * @throws NullPointerException if command or unit is null */ public void execute(Runnable command, long timeout, TimeUnit unit) { submittedCount.incrementAndGet(); try { super.execute(command); } catch (RejectedExecutionException rx) { if (super.getQueue() instanceof TaskQueue) { final TaskQueue queue = (TaskQueue)super.getQueue(); try { if (!queue.force(command, timeout, unit)) { submittedCount.decrementAndGet(); throw new RejectedExecutionException("Queue capacity is full."); } } catch (InterruptedException x) { submittedCount.decrementAndGet(); Thread.interrupted(); throw new RejectedExecutionException(x); } } else { submittedCount.decrementAndGet(); throw rx; } } } public void contextStopping() { this.lastContextStoppedTime.set(System.currentTimeMillis()); // save the current pool parameters to restore them later int savedCorePoolSize = this.getCorePoolSize(); TaskQueue taskQueue = getQueue() instanceof TaskQueue ? (TaskQueue) getQueue() : null; if (taskQueue != null) { // note by slaurent : quite oddly threadPoolExecutor.setCorePoolSize // checks that queue.remainingCapacity()==0. I did not understand // why, but to get the intended effect of waking up idle threads, I // temporarily fake this condition. taskQueue.setForcedRemainingCapacity(Integer.valueOf(0)); } // setCorePoolSize(0) wakes idle threads this.setCorePoolSize(0); // wait a little so that idle threads wake and poll the queue again, // this time always with a timeout (queue.poll() instead of // queue.take()) // even if we did not wait enough, TaskQueue.take() takes care of timing // out, so that we are sure that all threads of the pool are renewed in // a limited time, something like // (threadKeepAlive + longest request time) try { Thread.sleep(200L); } catch (InterruptedException e) { // yes, ignore } if (taskQueue != null) { // ok, restore the state of the queue and pool taskQueue.setForcedRemainingCapacity(null); } this.setCorePoolSize(savedCorePoolSize); } private static class RejectHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, java.util.concurrent.ThreadPoolExecutor executor) { throw new RejectedExecutionException(); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/threads/TaskQueue.java0000644000175100017510000001137212271452644024557 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.threads; import java.util.Collection; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; /** * As task queue specifically designed to run with a thread pool executor. * The task queue is optimised to properly utilize threads within * a thread pool executor. If you use a normal queue, the executor will spawn threads * when there are idle threads and you wont be able to force items unto the queue itself * @author fhanik * */ public class TaskQueue extends LinkedBlockingQueue { private static final long serialVersionUID = 1L; private ThreadPoolExecutor parent = null; // no need to be volatile, the one times when we change and read it occur in // a single thread (the one that did stop a context and fired listeners) private Integer forcedRemainingCapacity = null; public TaskQueue() { super(); } public TaskQueue(int capacity) { super(capacity); } public TaskQueue(Collection c) { super(c); } public void setParent(ThreadPoolExecutor tp) { parent = tp; } public boolean force(Runnable o) { if ( parent.isShutdown() ) throw new RejectedExecutionException("Executor not running, can't force a command into the queue"); return super.offer(o); //forces the item onto the queue, to be used if the task is rejected } public boolean force(Runnable o, long timeout, TimeUnit unit) throws InterruptedException { if ( parent.isShutdown() ) throw new RejectedExecutionException("Executor not running, can't force a command into the queue"); return super.offer(o,timeout,unit); //forces the item onto the queue, to be used if the task is rejected } @Override public boolean offer(Runnable o) { //we can't do any checks if (parent==null) return super.offer(o); //we are maxed out on threads, simply queue the object if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o); //we have idle threads, just add it to the queue if (parent.getSubmittedCount()<(parent.getPoolSize())) return super.offer(o); //if we have less threads than maximum force creation of a new thread if (parent.getPoolSize()InvocationTargetException
    and returns the throwable that is * wrapped by it, if there is any. * * @param t the Throwable to check * @return t or t.getCause() */ public static Throwable unwrapInvocationTargetException(Throwable t) { if (t instanceof InvocationTargetException && t.getCause() != null) { return t.getCause(); } return t; } } tomcat7-7.0.52/java/org/apache/tomcat/util/scan/0000755000175100017510000000000012301126367021265 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/scan/NonClosingJarInputStream.java0000644000175100017510000000334411656663416027053 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.scan; import java.io.IOException; import java.io.InputStream; import java.util.jar.JarInputStream; /** * When using a {@link JarInputStream} with an XML parser, the stream will be * closed by the parser. This causes problems if multiple entries from the JAR * need to be parsed. This implementation makes {{@link #close()} a NO-OP and * adds {@link #reallyClose()} that will close the stream. */ public class NonClosingJarInputStream extends JarInputStream { public NonClosingJarInputStream(InputStream in, boolean verify) throws IOException { super(in, verify); } public NonClosingJarInputStream(InputStream in) throws IOException { super(in); } @Override public void close() throws IOException { // Make this a NO-OP so that further entries can be read from the stream } public void reallyClose() throws IOException { super.close(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/scan/StandardJarScanner.java0000644000175100017510000002715712271452644025661 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.scan; import java.io.File; import java.io.IOException; import java.net.JarURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import javax.servlet.ServletContext; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; import org.apache.tomcat.util.file.Matcher; import org.apache.tomcat.util.res.StringManager; /** * The default {@link JarScanner} implementation scans the WEB-INF/lib directory * followed by the provided classloader and then works up the classloader * hierarchy. This implementation is sufficient to meet the requirements of the * Servlet 3.0 specification as well as to provide a number of Tomcat specific * extensions. The extensions are: *

      *
    • Scanning the classloader hierarchy (enabled by default)
    • *
    • Testing all files to see if they are JARs (disabled by default)
    • *
    • Testing all directories to see if they are exploded JARs * (disabled by default)
    • *
    * All of the extensions may be controlled via configuration. */ public class StandardJarScanner implements JarScanner { private static final Log log = LogFactory.getLog(StandardJarScanner.class); private static final Set defaultJarsToSkip = new HashSet(); /** * The string resources for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); static { String jarList = System.getProperty(Constants.SKIP_JARS_PROPERTY); if (jarList != null) { StringTokenizer tokenizer = new StringTokenizer(jarList, ","); while (tokenizer.hasMoreElements()) { defaultJarsToSkip.add(tokenizer.nextToken()); } } } /** * Controls the classpath scanning extension. */ private boolean scanClassPath = true; public boolean isScanClassPath() { return scanClassPath; } public void setScanClassPath(boolean scanClassPath) { this.scanClassPath = scanClassPath; } /** * Controls the testing all files to see of they are JAR files extension. */ private boolean scanAllFiles = false; public boolean isScanAllFiles() { return scanAllFiles; } public void setScanAllFiles(boolean scanAllFiles) { this.scanAllFiles = scanAllFiles; } /** * Controls the testing all directories to see of they are exploded JAR * files extension. */ private boolean scanAllDirectories = false; public boolean isScanAllDirectories() { return scanAllDirectories; } public void setScanAllDirectories(boolean scanAllDirectories) { this.scanAllDirectories = scanAllDirectories; } /** * Controls the testing of the bootstrap classpath which consists of the * runtime classes provided by the JVM and any installed system extensions. */ private boolean scanBootstrapClassPath = false; public boolean isScanBootstrapClassPath() { return scanBootstrapClassPath; } public void setScanBootstrapClassPath(boolean scanBootstrapClassPath) { this.scanBootstrapClassPath = scanBootstrapClassPath; } /** * Scan the provided ServletContext and classloader for JAR files. Each JAR * file found will be passed to the callback handler to be processed. * * @param context The ServletContext - used to locate and access * WEB-INF/lib * @param classloader The classloader - used to access JARs not in * WEB-INF/lib * @param callback The handler to process any JARs found * @param jarsToSkip List of JARs to ignore. If this list is null, a * default list will be read from the system property * defined by {@link Constants#SKIP_JARS_PROPERTY} */ @Override public void scan(ServletContext context, ClassLoader classloader, JarScannerCallback callback, Set jarsToSkip) { if (log.isTraceEnabled()) { log.trace(sm.getString("jarScan.webinflibStart")); } Set ignoredJars; if (jarsToSkip == null) { ignoredJars = defaultJarsToSkip; } else { ignoredJars = jarsToSkip; } Set ignoredJarsTokens = new HashSet(); for (String pattern: ignoredJars) { ignoredJarsTokens.add(Matcher.tokenizePathAsArray(pattern)); } // Scan WEB-INF/lib Set dirList = context.getResourcePaths(Constants.WEB_INF_LIB); if (dirList != null) { Iterator it = dirList.iterator(); while (it.hasNext()) { String path = it.next(); if (path.endsWith(Constants.JAR_EXT) && !Matcher.matchPath(ignoredJarsTokens, path.substring(path.lastIndexOf('/')+1))) { // Need to scan this JAR if (log.isDebugEnabled()) { log.debug(sm.getString("jarScan.webinflibJarScan", path)); } URL url = null; try { // File URLs are always faster to work with so use them // if available. String realPath = context.getRealPath(path); if (realPath == null) { url = context.getResource(path); } else { url = (new File(realPath)).toURI().toURL(); } process(callback, url); } catch (IOException e) { log.warn(sm.getString("jarScan.webinflibFail", url), e); } } else { if (log.isTraceEnabled()) { log.trace(sm.getString("jarScan.webinflibJarNoScan", path)); } } } } // Scan the classpath if (scanClassPath && classloader != null) { if (log.isTraceEnabled()) { log.trace(sm.getString("jarScan.classloaderStart")); } ClassLoader loader = classloader; ClassLoader stopLoader = null; if (!scanBootstrapClassPath) { // Stop when we reach the bootstrap class loader stopLoader = ClassLoader.getSystemClassLoader().getParent(); } while (loader != null && loader != stopLoader) { if (loader instanceof URLClassLoader) { URL[] urls = ((URLClassLoader) loader).getURLs(); for (int i=0; i entries; private JarEntry entry = null; public FileUrlJar(URL url) throws IOException { JarURLConnection jarConn = (JarURLConnection) url.openConnection(); jarConn.setUseCaches(false); jarFile = jarConn.getJarFile(); } @Override public boolean entryExists(String name) { ZipEntry entry = jarFile.getEntry(name); return entry != null; } @Override public InputStream getInputStream(String name) throws IOException { ZipEntry entry = jarFile.getEntry(name); if (entry == null) { return null; } else { return jarFile.getInputStream(entry); } } @Override public void close() { if (jarFile != null) { try { jarFile.close(); } catch (IOException e) { // Ignore } } } @Override public void nextEntry() { if (entries == null) { entries = jarFile.entries(); } if (entries.hasMoreElements()) { entry = entries.nextElement(); } else { entry = null; } } @Override public String getEntryName() { if (entry == null) { return null; } else { return entry.getName(); } } @Override public InputStream getEntryInputStream() throws IOException { if (entry == null) { return null; } else { return jarFile.getInputStream(entry); } } @Override public void reset() throws IOException { entries = null; entry = null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/scan/package.html0000644000175100017510000000177312271452644023564 0ustar locutuslocutus

    This package contains the common classes used to perform configuration scanning for Catalina and Jasper.

    tomcat7-7.0.52/java/org/apache/tomcat/util/scan/UrlJar.java0000644000175100017510000000666611656663416023362 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.scan; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.jar.JarEntry; /** * Implementation of {@link Jar} that is optimised for non-file based JAR URLs * (e.g. JNDI based URLs of the form jar:jndi:...). */ public class UrlJar implements Jar { private NonClosingJarInputStream jarInputStream = null; private URL url = null; private JarEntry entry = null; public UrlJar(URL url) throws IOException { this.url = url; this.jarInputStream = createJarInputStream(); } @Override public boolean entryExists(String name) throws IOException { JarEntry entry = jarInputStream.getNextJarEntry(); while (entry != null) { if (name.equals(entry.getName())) { break; } entry = jarInputStream.getNextJarEntry(); } return entry != null; } @Override public InputStream getInputStream(String name) throws IOException { JarEntry entry = jarInputStream.getNextJarEntry(); while (entry != null) { if (name.equals(entry.getName())) { break; } entry = jarInputStream.getNextJarEntry(); } if (entry == null) { return null; } else { return jarInputStream; } } @Override public void close() { if (jarInputStream != null) { try { jarInputStream.reallyClose(); } catch (IOException ioe) { // Ignore } } } private NonClosingJarInputStream createJarInputStream() throws IOException { JarURLConnection jarConn = (JarURLConnection) url.openConnection(); URL resourceURL = jarConn.getJarFileURL(); URLConnection resourceConn = resourceURL.openConnection(); resourceConn.setUseCaches(false); return new NonClosingJarInputStream(resourceConn.getInputStream()); } @Override public void nextEntry() { try { entry = jarInputStream.getNextJarEntry(); } catch (IOException ioe) { entry = null; } } @Override public String getEntryName() { if (entry == null) { return null; } else { return entry.getName(); } } @Override public InputStream getEntryInputStream() throws IOException { return jarInputStream; } @Override public void reset() throws IOException { close(); jarInputStream = createJarInputStream(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/scan/Constants.java0000644000175100017510000000264012271452644024114 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.scan; /** * String constants for the scan package. */ public final class Constants { public static final String Package = "org.apache.tomcat.util.scan"; /* System properties */ public static final String SKIP_JARS_PROPERTY = "tomcat.util.scan.DefaultJarScanner.jarsToSkip"; /* Commons strings */ public static final String JAR_EXT = ".jar"; public static final String WEB_INF_LIB = "/WEB-INF/lib/"; /* Context attributes - used to pass short-cuts to Jasper */ public static final String MERGED_WEB_XML = "org.apache.tomcat.util.scan.MergedWebXml"; } tomcat7-7.0.52/java/org/apache/tomcat/util/scan/LocalStrings.properties0000644000175100017510000000247512271452644026025 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. jarScan.classloaderFail=Failed to scan [{0}] from classloader hierarchy jarScan.classloaderStart=Scanning for JARs in classloader hierarchy jarScan.classloaderJarScan=Scanning JAR [{0}] from classpath jarScan.classloaderJarNoScan=Not scanning JAR [{0}] from classpath jarScan.jarUrlStart=Scanning JAR at URL [{0}] jarScan.webinflibFail=Failed to scan JAR [{0}] from WEB-INF/lib jarScan.webinflibStart=Scanning WEB-INF/lib for JARs jarScan.webinflibJarScan=Scanning JAR [{0}] from WEB-INF/lib jarScan.webinflibJarNoScan=Not scanning JAR [{0}] from WEB-INF/lib tomcat7-7.0.52/java/org/apache/tomcat/util/scan/JarFactory.java0000644000175100017510000000247511656663416024221 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.scan; import java.io.IOException; import java.net.URL; /** * Provide a mechanism to obtain objects that implement {@link Jar}. */ public class JarFactory { private JarFactory() { // Factory class. Hide public constructor. } public static Jar newInstance(URL url) throws IOException { String jarUrl = url.toString(); if (jarUrl.startsWith("jar:file:")) { return new FileUrlJar(url); } else { return new UrlJar(url); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/scan/Jar.java0000644000175100017510000000565411656663416022673 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.scan; import java.io.IOException; import java.io.InputStream; /** * Provides an abstraction for use by the various classes that need to scan * JARs. The classes provided by the JRE for accessing JARs ({@link java.util.jar.JarFile} and * {@link java.util.jar.JarInputStream}) have significantly different performance * characteristics depending on the form of the URL used to access the JAR. * For file based JAR {@link java.net.URL}s, {@link java.util.jar.JarFile} is faster but for non-file * based {@link java.net.URL}s, {@link java.util.jar.JarFile} creates a copy of the JAR in the * temporary directory so {@link java.util.jar.JarInputStream} is faster. */ public interface Jar { /** * Determines if a specific entry exists within the JAR. * * @param name Entry to look for * @return true if the specified entry exists else * false */ boolean entryExists(String name) throws IOException; /** * Obtain an {@link InputStream} for a given entry in a JAR. The caller is * responsible for closing the stream. * * @param name Entry to obtain an {@link InputStream} for * @return An {@link InputStream} for the specified entry or null if * the entry does not exist */ InputStream getInputStream(String name) throws IOException; /** * Close any resources associated with this JAR. */ void close(); /** * Moves the internal pointer to the next entry in the JAR. */ void nextEntry(); /** * Obtains the name of the current entry. * * @return The entry name */ String getEntryName(); /** * Obtains the input stream for the current entry. * * @return The input stream * @throws IOException If the stream cannot be obtained */ InputStream getEntryInputStream() throws IOException; /** * Resets the internal pointer used to track JAR entries to the beginning of * the JAR. * * @throws IOException If the pointer cannot be reset */ void reset() throws IOException; } tomcat7-7.0.52/java/org/apache/tomcat/util/collections/0000755000175100017510000000000012301126367022657 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/collections/ConcurrentCache.java0000644000175100017510000000342212271446130026570 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.collections; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; public final class ConcurrentCache { private final int size; private final Map eden; private final Map longterm; public ConcurrentCache(int size) { this.size = size; this.eden = new ConcurrentHashMap(size); this.longterm = new WeakHashMap(size); } public V get(K k) { V v = this.eden.get(k); if (v == null) { synchronized (longterm) { v = this.longterm.get(k); } if (v != null) { this.eden.put(k, v); } } return v; } public void put(K k, V v) { if (this.eden.size() >= size) { synchronized (longterm) { this.longterm.putAll(this.eden); } this.eden.clear(); } this.eden.put(k, v); } } tomcat7-7.0.52/java/org/apache/tomcat/util/log/0000755000175100017510000000000012301126367021122 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/log/SystemLogHandler.java0000644000175100017510000001376112271452644025227 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.log; import java.io.IOException; import java.io.PrintStream; import java.util.EmptyStackException; import java.util.Stack; /** * This helper class may be used to do sophisticated redirection of * System.out and System.err on a per Thread basis. * * A stack is implemented per Thread so that nested startCapture * and stopCapture can be used. * * @author Remy Maucherat * @author Glenn L. Nielsen */ public class SystemLogHandler extends PrintStream { // ----------------------------------------------------------- Constructors /** * Construct the handler to capture the output of the given steam. */ public SystemLogHandler(PrintStream wrapped) { super(wrapped); out = wrapped; } // ----------------------------------------------------- Instance Variables /** * Wrapped PrintStream. */ protected PrintStream out = null; /** * Thread <-> CaptureLog associations. */ protected static ThreadLocal> logs = new ThreadLocal>(); /** * Spare CaptureLog ready for reuse. */ protected static Stack reuse = new Stack(); // --------------------------------------------------------- Public Methods /** * Start capturing thread's output. */ public static void startCapture() { CaptureLog log = null; if (!reuse.isEmpty()) { try { log = reuse.pop(); } catch (EmptyStackException e) { log = new CaptureLog(); } } else { log = new CaptureLog(); } Stack stack = logs.get(); if (stack == null) { stack = new Stack(); logs.set(stack); } stack.push(log); } /** * Stop capturing thread's output and return captured data as a String. */ public static String stopCapture() { Stack stack = logs.get(); if (stack == null || stack.isEmpty()) { return null; } CaptureLog log = stack.pop(); if (log == null) { return null; } String capture = log.getCapture(); log.reset(); reuse.push(log); return capture; } // ------------------------------------------------------ Protected Methods /** * Find PrintStream to which the output must be written to. */ protected PrintStream findStream() { Stack stack = logs.get(); if (stack != null && !stack.isEmpty()) { CaptureLog log = stack.peek(); if (log != null) { PrintStream ps = log.getStream(); if (ps != null) { return ps; } } } return out; } // ---------------------------------------------------- PrintStream Methods @Override public void flush() { findStream().flush(); } @Override public void close() { findStream().close(); } @Override public boolean checkError() { return findStream().checkError(); } @Override protected void setError() { //findStream().setError(); } @Override public void write(int b) { findStream().write(b); } @Override public void write(byte[] b) throws IOException { findStream().write(b); } @Override public void write(byte[] buf, int off, int len) { findStream().write(buf, off, len); } @Override public void print(boolean b) { findStream().print(b); } @Override public void print(char c) { findStream().print(c); } @Override public void print(int i) { findStream().print(i); } @Override public void print(long l) { findStream().print(l); } @Override public void print(float f) { findStream().print(f); } @Override public void print(double d) { findStream().print(d); } @Override public void print(char[] s) { findStream().print(s); } @Override public void print(String s) { findStream().print(s); } @Override public void print(Object obj) { findStream().print(obj); } @Override public void println() { findStream().println(); } @Override public void println(boolean x) { findStream().println(x); } @Override public void println(char x) { findStream().println(x); } @Override public void println(int x) { findStream().println(x); } @Override public void println(long x) { findStream().println(x); } @Override public void println(float x) { findStream().println(x); } @Override public void println(double x) { findStream().println(x); } @Override public void println(char[] x) { findStream().println(x); } @Override public void println(String x) { findStream().println(x); } @Override public void println(Object x) { findStream().println(x); } } tomcat7-7.0.52/java/org/apache/tomcat/util/log/UserDataHelper.java0000644000175100017510000001172412123412403024631 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.log; import org.apache.juli.logging.Log; /** * This helper class assists with the logging associated with invalid input * data. A developer may want all instances of invalid input data logged to * assist with debugging whereas in production it is likely to be desirable not * to log anything for invalid data. The following settings may be used: *
      *
    • NOTHING: Log nothing.
    • *
    • DEBUG_ALL: Log all problems at DEBUG log level.
    • *
    • INFO_THEN_DEBUG: Log first problem at INFO log level and any further * issues in the following TBD (configurable) seconds at DEBUG level
    • *
    • INFO_ALL: Log all problems at INFO log level.
    • *
    * By default, INFO_THEN_DEBUG is used with a suppression time of 24 hours. * * NOTE: This class is not completely thread-safe. When using INFO_THEN_DEBUG it * is possible that several INFO messages will be logged before dropping to * DEBUG. */ public class UserDataHelper { private final Log log; private final Config config; // A value of 0 is equivalent to using INFO_ALL // A negative value will trigger infinite suppression // The value is milliseconds private final long suppressionTime; private volatile long lastInfoTime = 0; public UserDataHelper(Log log) { this.log = log; Config tempConfig; String configString = System.getProperty( "org.apache.juli.logging.UserDataHelper.CONFIG"); if (configString == null) { tempConfig = Config.INFO_THEN_DEBUG; } else { try { tempConfig = Config.valueOf(configString); } catch (IllegalArgumentException iae) { // Ignore - use default tempConfig = Config.INFO_THEN_DEBUG; } } // Default suppression time of 1 day. suppressionTime = Integer.getInteger( "org.apache.juli.logging.UserDataHelper.SUPPRESSION_TIME", 60 * 60 * 24).intValue() * 1000L; if (suppressionTime == 0) { tempConfig = Config.INFO_ALL; } config = tempConfig; } /** * Returns log mode for the next log message, or null if the * message should not be logged. * *

    * If INFO_THEN_DEBUG configuration option is enabled, this * method might change internal state of this object. * * @return Log mode, or null */ public Mode getNextMode() { if (Config.NONE == config) { return null; } else if (Config.DEBUG_ALL == config) { return log.isDebugEnabled() ? Mode.DEBUG : null; } else if (Config.INFO_THEN_DEBUG == config) { if (logAtInfo()) { return log.isInfoEnabled() ? Mode.INFO_THEN_DEBUG : null; } else { return log.isDebugEnabled() ? Mode.DEBUG : null; } } else if (Config.INFO_ALL == config) { return log.isInfoEnabled() ? Mode.INFO : null; } // Should never happen return null; } /* * Not completely thread-safe but good enough for this use case. I couldn't * see a simple enough way to make it completely thread-safe that was not * likely to compromise performance. */ private boolean logAtInfo() { if (suppressionTime < 0 && lastInfoTime > 0) { return false; } long now = System.currentTimeMillis(); if (lastInfoTime + suppressionTime > now) { return false; } lastInfoTime = now; return true; } private static enum Config { NONE, DEBUG_ALL, INFO_THEN_DEBUG, INFO_ALL } /** * Log mode for the next log message. */ public static enum Mode { DEBUG(false), INFO_THEN_DEBUG(true), INFO(false); private final boolean fallToDebug; Mode(boolean fallToDebug) { this.fallToDebug = fallToDebug; } /** * @deprecated Unused, removed in Tomcat 8. */ @Deprecated public boolean fallToDebug() { return fallToDebug; } } } tomcat7-7.0.52/java/org/apache/tomcat/util/log/CaptureLog.java0000644000175100017510000000261612271452644024045 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.log; import java.io.ByteArrayOutputStream; import java.io.PrintStream; /** * Per Thread System.err and System.out log capture data. * * @author Glenn L. Nielsen */ class CaptureLog { protected CaptureLog() { baos = new ByteArrayOutputStream(); ps = new PrintStream(baos); } private ByteArrayOutputStream baos; private PrintStream ps; protected PrintStream getStream() { return ps; } protected void reset() { baos.reset(); } protected String getCapture() { return baos.toString(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/0000755000175100017510000000000012301126367021246 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/0000755000175100017510000000000012301126367023213 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java0000644000175100017510000000400012271445223026462 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a long object. * * @author M. Dahm * @see Constant */ public final class ConstantLong extends Constant { private static final long serialVersionUID = -1893131676489003562L; private long bytes; /** * @param bytes Data */ public ConstantLong(long bytes) { super(Constants.CONSTANT_Long); this.bytes = bytes; } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantLong(DataInput file) throws IOException { this(file.readLong()); } /** * @return data, i.e., 8 bytes. */ public final long getBytes() { return bytes; } /** * @return String representation. */ @Override public final String toString() { return super.toString() + "(bytes = " + bytes + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleParameterAnnotations.java0000644000175100017510000000375012271445223033433 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * represents a parameter annotation that is represented in the class file * but is not provided to the JVM. * * @author D. Brosius * @since 5.3 */ public class RuntimeInvisibleParameterAnnotations extends ParameterAnnotations { private static final long serialVersionUID = -6819370369102352536L; /** * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants */ RuntimeInvisibleParameterAnnotations(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { super(Constants.ATTR_RUNTIMEIN_VISIBLE_PARAMETER_ANNOTATIONS, name_index, length, file, constant_pool); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool constant_pool ) { Annotations c = (Annotations) clone(); return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantUtf8.java0000644000175100017510000000677012271445223026431 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.DataInputStream; import java.io.IOException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a Utf8 encoded string. * * @author M. Dahm * @see Constant */ public final class ConstantUtf8 extends Constant { private static final long serialVersionUID = 8119001312020421976L; private final String bytes; private static final int MAX_CACHE_ENTRIES = 20000; private static final int INITIAL_CACHE_CAPACITY = (int)(MAX_CACHE_ENTRIES/0.75); private static HashMap cache; private static synchronized ConstantUtf8 getCachedInstance(String s) { if (s.length() > 200) { return new ConstantUtf8(s); } if (cache == null) { cache = new LinkedHashMap(INITIAL_CACHE_CAPACITY, 0.75f, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_ENTRIES; } }; } ConstantUtf8 result = cache.get(s); if (result != null) { return result; } result = new ConstantUtf8(s); cache.put(s, result); return result; } private static ConstantUtf8 getInstance(String s) { return getCachedInstance(s); } static ConstantUtf8 getInstance(DataInputStream file) throws IOException { return getInstance(file.readUTF()); } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantUtf8(DataInput file) throws IOException { super(Constants.CONSTANT_Utf8); bytes = file.readUTF(); } /** * @param bytes Data */ private ConstantUtf8(String bytes) { super(Constants.CONSTANT_Utf8); if (bytes == null) { throw new IllegalArgumentException("bytes must not be null!"); } this.bytes = bytes; } /** * @return Data converted to string. */ public final String getBytes() { return bytes; } /** * @return String representation */ @Override public final String toString() { return super.toString() + "(\"" + Utility.replace(bytes, "\n", "\\n") + "\")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ParameterAnnotations.java0000644000175100017510000000637212271445223030225 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; /** * base class for parameter annotations * * @author D. Brosius * @since 5.3 */ public abstract class ParameterAnnotations extends Attribute { private static final long serialVersionUID = -8831779739803248091L; private int num_parameters; private ParameterAnnotationEntry[] parameter_annotation_table; // Table of parameter annotations /** * @param parameter_annotation_type the subclass type of the parameter annotation * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants */ ParameterAnnotations(byte parameter_annotation_type, int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(parameter_annotation_type, name_index, length, (ParameterAnnotationEntry[]) null, constant_pool); num_parameters = (file.readUnsignedByte()); parameter_annotation_table = new ParameterAnnotationEntry[num_parameters]; for (int i = 0; i < num_parameters; i++) { parameter_annotation_table[i] = new ParameterAnnotationEntry(file, constant_pool); } } /** * @param parameter_annotation_type the subclass type of the parameter annotation * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param parameter_annotation_table the actual parameter annotations * @param constant_pool Array of constants */ public ParameterAnnotations(byte parameter_annotation_type, int name_index, int length, ParameterAnnotationEntry[] parameter_annotation_table, ConstantPool constant_pool) { super(parameter_annotation_type, name_index, length, constant_pool); setParameterAnnotationTable(parameter_annotation_table); } /** * @param parameter_annotation_table the entries to set in this parameter annotation */ public final void setParameterAnnotationTable( ParameterAnnotationEntry[] parameter_annotation_table ) { this.parameter_annotation_table = parameter_annotation_table; num_parameters = (parameter_annotation_table == null) ? 0 : parameter_annotation_table.length; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTable.java0000644000175100017510000001075212271445223027534 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents colection of local variables in a * method. This attribute is contained in the Code attribute. * * @author M. Dahm * @see Code * @see LocalVariable */ public class LocalVariableTable extends Attribute { private static final long serialVersionUID = -3904314258294133920L; private int local_variable_table_length; // Table of local private LocalVariable[] local_variable_table; // variables /** * @param name_index Index in constant pool to `LocalVariableTable' * @param length Content length in bytes * @param local_variable_table Table of local variables * @param constant_pool Array of constants */ public LocalVariableTable(int name_index, int length, LocalVariable[] local_variable_table, ConstantPool constant_pool) { super(Constants.ATTR_LOCAL_VARIABLE_TABLE, name_index, length, constant_pool); setLocalVariableTable(local_variable_table); } /** * Construct object from file stream. * @param name_index Index in constant pool * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ LocalVariableTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (LocalVariable[]) null, constant_pool); local_variable_table_length = (file.readUnsignedShort()); local_variable_table = new LocalVariable[local_variable_table_length]; for (int i = 0; i < local_variable_table_length; i++) { local_variable_table[i] = new LocalVariable(file, constant_pool); } } /** * * @param index the variable slot * * @return the first LocalVariable that matches the slot or null if not found * * @deprecated since 5.2 because multiple variables can share the * same slot, use getLocalVariable(int index, int pc) instead. */ @java.lang.Deprecated public final LocalVariable getLocalVariable( int index ) { for (int i = 0; i < local_variable_table_length; i++) { if (local_variable_table[i].getIndex() == index) { return local_variable_table[i]; } } return null; } public final void setLocalVariableTable( LocalVariable[] local_variable_table ) { this.local_variable_table = local_variable_table; local_variable_table_length = (local_variable_table == null) ? 0 : local_variable_table.length; } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < local_variable_table_length; i++) { buf.append(local_variable_table[i].toString()); if (i < local_variable_table_length - 1) { buf.append('\n'); } } return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { LocalVariableTable c = (LocalVariableTable) clone(); c.local_variable_table = new LocalVariable[local_variable_table_length]; for (int i = 0; i < local_variable_table_length; i++) { c.local_variable_table[i] = local_variable_table[i].copy(); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java0000644000175100017510000000401012271445223027161 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to an int object. * * @author M. Dahm * @see Constant */ public final class ConstantInteger extends Constant { private static final long serialVersionUID = -6415476571232528966L; private int bytes; /** * @param bytes Data */ public ConstantInteger(int bytes) { super(Constants.CONSTANT_Integer); this.bytes = bytes; } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantInteger(DataInput file) throws IOException { this(file.readInt()); } /** * @return data, i.e., 4 bytes. */ public final int getBytes() { return bytes; } /** * @return String representation. */ @Override public final String toString() { return super.toString() + "(bytes = " + bytes + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantValue.java0000644000175100017510000000754012271445223026653 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from Attribute and represents a constant * value, i.e., a default value for initializing a class field. * This class is instantiated by the Attribute.readAttribute() method. * * @author M. Dahm * @see Attribute */ public final class ConstantValue extends Attribute { private static final long serialVersionUID = -388222612752527969L; private int constantvalue_index; /** * Construct object from file stream. * @param name_index Name index in constant pool * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ ConstantValue(int name_index, int length, DataInput file, ConstantPool constant_pool) throws IOException { this(name_index, length, file.readUnsignedShort(), constant_pool); } /** * @param name_index Name index in constant pool * @param length Content length in bytes * @param constantvalue_index Index in constant pool * @param constant_pool Array of constants */ public ConstantValue(int name_index, int length, int constantvalue_index, ConstantPool constant_pool) { super(Constants.ATTR_CONSTANT_VALUE, name_index, length, constant_pool); this.constantvalue_index = constantvalue_index; } /** * @return String representation of constant value. */ @Override public final String toString() { Constant c = constant_pool.getConstant(constantvalue_index); String buf; int i; // Print constant to string depending on its type switch (c.getTag()) { case Constants.CONSTANT_Long: buf = String.valueOf(((ConstantLong) c).getBytes()); break; case Constants.CONSTANT_Float: buf = String.valueOf(((ConstantFloat) c).getBytes()); break; case Constants.CONSTANT_Double: buf = String.valueOf(((ConstantDouble) c).getBytes()); break; case Constants.CONSTANT_Integer: buf = String.valueOf(((ConstantInteger) c).getBytes()); break; case Constants.CONSTANT_String: i = ((ConstantString) c).getStringIndex(); c = constant_pool.getConstant(i, Constants.CONSTANT_Utf8); buf = "\"" + Utility.convertString(((ConstantUtf8) c).getBytes()) + "\""; break; default: throw new IllegalStateException("Type of ConstValue invalid: " + c); } return buf; } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { ConstantValue c = (ConstantValue) clone(); c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Annotations.java0000644000175100017510000000637112271445223026363 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * base class for annotations * * @author D. Brosius * @since 5.3 */ public abstract class Annotations extends Attribute { private static final long serialVersionUID = 1L; private AnnotationEntry[] annotation_table; /** * @param annotation_type the subclass type of the annotation * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants */ public Annotations(byte annotation_type, int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(annotation_type, name_index, length, (AnnotationEntry[]) null, constant_pool); final int annotation_table_length = (file.readUnsignedShort()); annotation_table = new AnnotationEntry[annotation_table_length]; for (int i = 0; i < annotation_table_length; i++) { annotation_table[i] = AnnotationEntry.read(file, constant_pool); } } /** * @param annotation_type the subclass type of the annotation * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param annotation_table the actual annotations * @param constant_pool Array of constants */ public Annotations(byte annotation_type, int name_index, int length, AnnotationEntry[] annotation_table, ConstantPool constant_pool) { super(annotation_type, name_index, length, constant_pool); setAnnotationTable(annotation_table); } /** * @param annotation_table the entries to set in this annotation */ public final void setAnnotationTable( AnnotationEntry[] annotation_table ) { this.annotation_table = annotation_table; } /** * returns the array of annotation entries in this annotation */ public AnnotationEntry[] getAnnotationEntries() { return annotation_table; } protected void writeAnnotations(DataOutputStream dos) throws IOException { if (annotation_table == null) { return; } dos.writeShort(annotation_table.length); for (int i = 0; i < annotation_table.length; i++) { annotation_table[i].dump(dos); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/AnnotationElementValue.java0000644000175100017510000000365112271445223030505 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataOutputStream; import java.io.IOException; public class AnnotationElementValue extends ElementValue { // For annotation element values, this is the annotation private AnnotationEntry annotationEntry; public AnnotationElementValue(int type, AnnotationEntry annotationEntry, ConstantPool cpool) { super(type, cpool); if (type != ANNOTATION) throw new RuntimeException( "Only element values of type annotation can be built with this ctor - type specified: " + type); this.annotationEntry = annotationEntry; } @Override public void dump(DataOutputStream dos) throws IOException { dos.writeByte(type); // u1 type of value (ANNOTATION == '@') annotationEntry.dump(dos); } @Override public String stringifyValue() { return annotationEntry.toString(); } @Override public String toString() { return stringifyValue(); } public AnnotationEntry getAnnotationEntry() { return annotationEntry; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ClassFormatException.java0000644000175100017510000000266012271445223030160 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; /** * Thrown when the BCEL attempts to read a class file and determines * that the file is malformed or otherwise cannot be interpreted as a * class file. * * @author M. Dahm */ public class ClassFormatException extends RuntimeException { private static final long serialVersionUID = 3243149520175287759L; public ClassFormatException() { super(); } public ClassFormatException(String s) { super(s); } public ClassFormatException(String s, Throwable initCause) { super(s, initCause); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleParameterAnnotations.java0000644000175100017510000000373512271445223033107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * represents a parameter annotation that is represented in the class file * and is provided to the JVM. * * @author D. Brosius * @since 5.3 */ public class RuntimeVisibleParameterAnnotations extends ParameterAnnotations { private static final long serialVersionUID = 7633756460868573992L; /** * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants */ RuntimeVisibleParameterAnnotations(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { super(Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, name_index, length, file, constant_pool); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool constant_pool ) { Annotations c = (Annotations) clone(); return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/JavaClass.java0000644000175100017510000002615012271445223025732 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import org.apache.tomcat.util.bcel.Constants; import org.apache.tomcat.util.bcel.util.BCELComparator; /** * Represents a Java class, i.e., the data structures, constant pool, * fields, methods and commands contained in a Java .class file. * See JVM specification for details. * The intent of this class is to represent a parsed or otherwise existing * class file. Those interested in programatically generating classes * should see the ClassGen class. * @author M. Dahm */ public class JavaClass extends AccessFlags implements Cloneable, Comparable { private static final long serialVersionUID = 7029227708237523236L; private String file_name; private String source_file_name = ""; private String class_name; private String superclass_name; private int major, minor; // Compiler version private ConstantPool constant_pool; // Constant pool private int[] interfaces; // implemented interfaces private String[] interface_names; private Field[] fields; // Fields, i.e., variables of class private Method[] methods; // methods defined in the class private Attribute[] attributes; // attributes defined in the class private AnnotationEntry[] annotations; // annotations defined on the class // Annotations are collected from certain attributes, don't do it more than necessary! private boolean annotationsOutOfDate = true; private static BCELComparator _cmp = new BCELComparator() { @Override public boolean equals( Object o1, Object o2 ) { JavaClass THIS = (JavaClass) o1; JavaClass THAT = (JavaClass) o2; return THIS.getClassName().equals(THAT.getClassName()); } @Override public int hashCode( Object o ) { JavaClass THIS = (JavaClass) o; return THIS.getClassName().hashCode(); } }; /** * Constructor gets all contents as arguments. * * @param class_name_index Index into constant pool referencing a * ConstantClass that represents this class. * @param superclass_name_index Index into constant pool referencing a * ConstantClass that represents this class's superclass. * @param file_name File name * @param major Major compiler version * @param minor Minor compiler version * @param access_flags Access rights defined by bit flags * @param constant_pool Array of constants * @param interfaces Implemented interfaces * @param fields Class fields * @param methods Class methods * @param attributes Class attributes */ public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, int minor, int access_flags, ConstantPool constant_pool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes) { if (interfaces == null) { interfaces = new int[0]; } if (attributes == null) { attributes = new Attribute[0]; } if (fields == null) { fields = new Field[0]; } if (methods == null) { methods = new Method[0]; } this.file_name = file_name; this.major = major; this.minor = minor; this.access_flags = access_flags; this.constant_pool = constant_pool; this.interfaces = interfaces; this.fields = fields; this.methods = methods; this.attributes = attributes; annotationsOutOfDate = true; // Get source file name if available for (int i = 0; i < attributes.length; i++) { if (attributes[i] instanceof SourceFile) { source_file_name = ((SourceFile) attributes[i]).getSourceFileName(); break; } } /* According to the specification the following entries must be of type * `ConstantClass' but we check that anyway via the * `ConstPool.getConstant' method. */ class_name = constant_pool.getConstantString(class_name_index, Constants.CONSTANT_Class); class_name = Utility.compactClassName(class_name, false); if (superclass_name_index > 0) { // May be zero -> class is java.lang.Object superclass_name = constant_pool.getConstantString(superclass_name_index, Constants.CONSTANT_Class); superclass_name = Utility.compactClassName(superclass_name, false); } else { superclass_name = "java.lang.Object"; } interface_names = new String[interfaces.length]; for (int i = 0; i < interfaces.length; i++) { String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class); interface_names[i] = Utility.compactClassName(str, false); } } /** * @return Attributes of the class. */ public Attribute[] getAttributes() { return attributes; } public AnnotationEntry[] getAnnotationEntries() { if (annotationsOutOfDate) { // Find attributes that contain annotation data Attribute[] attrs = getAttributes(); List accumulatedAnnotations = new ArrayList(); for (int i = 0; i < attrs.length; i++) { Attribute attribute = attrs[i]; if (attribute instanceof Annotations) { Annotations runtimeAnnotations = (Annotations)attribute; for(int j = 0; j < runtimeAnnotations.getAnnotationEntries().length; j++) accumulatedAnnotations.add(runtimeAnnotations.getAnnotationEntries()[j]); } } annotations = accumulatedAnnotations.toArray(new AnnotationEntry[accumulatedAnnotations.size()]); annotationsOutOfDate = false; } return annotations; } /** * @return Class name. */ public String getClassName() { return class_name; } /** * @return Names of implemented interfaces. */ public String[] getInterfaceNames() { return interface_names; } /** * returns the super class name of this class. In the case that this class is * java.lang.Object, it will return itself (java.lang.Object). This is probably incorrect * but isn't fixed at this time to not break existing clients. * * @return Superclass name. */ public String getSuperclassName() { return superclass_name; } /** * @return String representing class contents. */ @Override public String toString() { String access = Utility.accessToString(access_flags, true); access = access.equals("") ? "" : (access + " "); StringBuilder buf = new StringBuilder(128); buf.append(access).append(Utility.classOrInterface(access_flags)).append(" ").append( class_name).append(" extends ").append( Utility.compactClassName(superclass_name, false)).append('\n'); int size = interfaces.length; if (size > 0) { buf.append("implements\t\t"); for (int i = 0; i < size; i++) { buf.append(interface_names[i]); if (i < size - 1) { buf.append(", "); } } buf.append('\n'); } buf.append("filename\t\t").append(file_name).append('\n'); buf.append("compiled from\t\t").append(source_file_name).append('\n'); buf.append("compiler version\t").append(major).append(".").append(minor).append('\n'); buf.append("access flags\t\t").append(access_flags).append('\n'); buf.append("constant pool\t\t").append(constant_pool.getLength()).append(" entries\n"); buf.append("ACC_SUPER flag\t\t").append(isSuper()).append("\n"); if (attributes.length > 0) { buf.append("\nAttribute(s):\n"); for (int i = 0; i < attributes.length; i++) { buf.append(indent(attributes[i])); } } AnnotationEntry[] annotations = getAnnotationEntries(); if (annotations!=null && annotations.length>0) { buf.append("\nAnnotation(s):\n"); for (int i=0; i 0) { buf.append("\n").append(fields.length).append(" fields:\n"); for (int i = 0; i < fields.length; i++) { buf.append("\t").append(fields[i]).append('\n'); } } if (methods.length > 0) { buf.append("\n").append(methods.length).append(" methods:\n"); for (int i = 0; i < methods.length; i++) { buf.append("\t").append(methods[i]).append('\n'); } } return buf.toString(); } private static final String indent( Object obj ) { StringTokenizer tok = new StringTokenizer(obj.toString(), "\n"); StringBuilder buf = new StringBuilder(); while (tok.hasMoreTokens()) { buf.append("\t").append(tok.nextToken()).append("\n"); } return buf.toString(); } public final boolean isSuper() { return (access_flags & Constants.ACC_SUPER) != 0; } /** * Return value as defined by given BCELComparator strategy. * By default two JavaClass objects are said to be equal when * their class names are equal. * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals( Object obj ) { return _cmp.equals(this, obj); } /** * Return the natural ordering of two JavaClasses. * This ordering is based on the class name */ @Override public int compareTo(JavaClass obj) { return getClassName().compareTo(obj.getClassName()); } /** * Return value as defined by given BCELComparator strategy. * By default return the hashcode of the class name. * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return _cmp.hashCode(this); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ClassParser.java0000644000175100017510000002471712271445223026314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.tomcat.util.bcel.Constants; /** * Wrapper class that parses a given Java .class file. The method parse returns a * JavaClass object on success. When an I/O error or an * inconsistency occurs an appropiate exception is propagated back to * the caller. * * The structure and the names comply, except for a few conveniences, * exactly with the * JVM specification 1.0. See this paper for * further details about the structure of a bytecode file. * * @author M. Dahm */ public final class ClassParser { private DataInputStream file; private boolean fileOwned; private String file_name; private String zip_file; private int class_name_index, superclass_name_index; private int major, minor; // Compiler version private int access_flags; // Access rights of parsed class private int[] interfaces; // Names of implemented interfaces private ConstantPool constant_pool; // collection of constants private Field[] fields; // class fields, i.e., its variables private Method[] methods; // methods defined in the class private Attribute[] attributes; // attributes defined in the class private boolean is_zip; // Loaded from zip file private static final int BUFSIZE = 8192; /** * Parse class from the given stream. * * @param file Input stream * @param file_name File name */ public ClassParser(InputStream file, String file_name) { this.file_name = file_name; fileOwned = false; String clazz = file.getClass().getName(); // Not a very clean solution ... is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar."); if (file instanceof DataInputStream) { this.file = (DataInputStream) file; } else { this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE)); } } /** * Parse the given Java class file and return an object that represents * the contained data, i.e., constants, methods, fields and commands. * A ClassFormatException is raised, if the file is not a valid * .class file. (This does not include verification of the byte code as it * is performed by the java interpreter). * * @return Class object representing the parsed class file * @throws IOException * @throws ClassFormatException */ public JavaClass parse() throws IOException, ClassFormatException { ZipFile zip = null; try { if (fileOwned) { if (is_zip) { zip = new ZipFile(zip_file); ZipEntry entry = zip.getEntry(file_name); if (entry == null) { throw new IOException("File " + file_name + " not found"); } file = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry), BUFSIZE)); } else { file = new DataInputStream(new BufferedInputStream(new FileInputStream( file_name), BUFSIZE)); } } /****************** Read headers ********************************/ // Check magic tag of class file readID(); // Get compiler version readVersion(); /****************** Read constant pool and related **************/ // Read constant pool entries readConstantPool(); // Get class information readClassInfo(); // Get interface information, i.e., implemented interfaces readInterfaces(); /****************** Read class fields and methods ***************/ // Read class fields, i.e., the variables of the class readFields(); // Read class methods, i.e., the functions in the class readMethods(); // Read class attributes readAttributes(); // Check for unknown variables //Unknown[] u = Unknown.getUnknownAttributes(); //for(int i=0; i < u.length; i++) // System.err.println("WARNING: " + u[i]); // Everything should have been read now // if(file.available() > 0) { // int bytes = file.available(); // byte[] buf = new byte[bytes]; // file.read(buf); // if(!(is_zip && (buf.length == 1))) { // System.err.println("WARNING: Trailing garbage at end of " + file_name); // System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf)); // } // } } finally { // Read everything of interest, so close the file if (fileOwned) { try { if (file != null) { file.close(); } if (zip != null) { zip.close(); } } catch (IOException ioe) { //ignore close exceptions } } } // Return the information we have gathered in a new object return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, access_flags, constant_pool, interfaces, fields, methods, attributes); } /** * Read information about the attributes of the class. * @throws IOException * @throws ClassFormatException */ private final void readAttributes() throws IOException, ClassFormatException { int attributes_count; attributes_count = file.readUnsignedShort(); attributes = new Attribute[attributes_count]; for (int i = 0; i < attributes_count; i++) { attributes[i] = Attribute.readAttribute(file, constant_pool); } } /** * Read information about the class and its super class. * @throws IOException * @throws ClassFormatException */ private final void readClassInfo() throws IOException, ClassFormatException { access_flags = file.readUnsignedShort(); /* Interfaces are implicitely abstract, the flag should be set * according to the JVM specification. */ if ((access_flags & Constants.ACC_INTERFACE) != 0) { access_flags |= Constants.ACC_ABSTRACT; } if (((access_flags & Constants.ACC_ABSTRACT) != 0) && ((access_flags & Constants.ACC_FINAL) != 0)) { throw new ClassFormatException("Class " + file_name + " can't be both final and abstract"); } class_name_index = file.readUnsignedShort(); superclass_name_index = file.readUnsignedShort(); } /** * Read constant pool entries. * @throws IOException * @throws ClassFormatException */ private final void readConstantPool() throws IOException, ClassFormatException { constant_pool = new ConstantPool(file); } /** * Read information about the fields of the class, i.e., its variables. * @throws IOException * @throws ClassFormatException */ private final void readFields() throws IOException, ClassFormatException { int fields_count; fields_count = file.readUnsignedShort(); fields = new Field[fields_count]; for (int i = 0; i < fields_count; i++) { fields[i] = new Field(file, constant_pool); } } /******************** Private utility methods **********************/ /** * Check whether the header of the file is ok. * Of course, this has to be the first action on successive file reads. * @throws IOException * @throws ClassFormatException */ private final void readID() throws IOException, ClassFormatException { int magic = 0xCAFEBABE; if (file.readInt() != magic) { throw new ClassFormatException(file_name + " is not a Java .class file"); } } /** * Read information about the interfaces implemented by this class. * @throws IOException * @throws ClassFormatException */ private final void readInterfaces() throws IOException, ClassFormatException { int interfaces_count; interfaces_count = file.readUnsignedShort(); interfaces = new int[interfaces_count]; for (int i = 0; i < interfaces_count; i++) { interfaces[i] = file.readUnsignedShort(); } } /** * Read information about the methods of the class. * @throws IOException * @throws ClassFormatException */ private final void readMethods() throws IOException, ClassFormatException { int methods_count; methods_count = file.readUnsignedShort(); methods = new Method[methods_count]; for (int i = 0; i < methods_count; i++) { methods[i] = new Method(file, constant_pool); } } /** * Read major and minor version of compiler which created the file. * @throws IOException * @throws ClassFormatException */ private final void readVersion() throws IOException, ClassFormatException { minor = file.readUnsignedShort(); major = file.readUnsignedShort(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ExceptionTable.java0000644000175100017510000001045112271445223026766 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents the table of exceptions that are thrown by a * method. This attribute may be used once per method. The name of * this class is ExceptionTable for historical reasons; The * Java Virtual Machine Specification, Second Edition defines this * attribute using the name Exceptions (which is inconsistent * with the other classes). * * @author M. Dahm * @see Code */ public final class ExceptionTable extends Attribute { private static final long serialVersionUID = -5109672682663772900L; private int number_of_exceptions; // Table of indices into private int[] exception_index_table; // constant pool /** * @param name_index Index in constant pool * @param length Content length in bytes * @param exception_index_table Table of indices in constant pool * @param constant_pool Array of constants */ public ExceptionTable(int name_index, int length, int[] exception_index_table, ConstantPool constant_pool) { super(Constants.ATTR_EXCEPTIONS, name_index, length, constant_pool); setExceptionIndexTable(exception_index_table); } /** * Construct object from file stream. * @param name_index Index in constant pool * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ ExceptionTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (int[]) null, constant_pool); number_of_exceptions = file.readUnsignedShort(); exception_index_table = new int[number_of_exceptions]; for (int i = 0; i < number_of_exceptions; i++) { exception_index_table[i] = file.readUnsignedShort(); } } /** * @param exception_index_table the list of exception indexes * Also redefines number_of_exceptions according to table length. */ public final void setExceptionIndexTable( int[] exception_index_table ) { this.exception_index_table = exception_index_table; number_of_exceptions = (exception_index_table == null) ? 0 : exception_index_table.length; } /** * @return String representation, i.e., a list of thrown exceptions. */ @Override public final String toString() { StringBuilder buf = new StringBuilder(); String str; for (int i = 0; i < number_of_exceptions; i++) { str = constant_pool.getConstantString(exception_index_table[i], Constants.CONSTANT_Class); buf.append(Utility.compactClassName(str, false)); if (i < number_of_exceptions - 1) { buf.append(", "); } } return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { ExceptionTable c = (ExceptionTable) clone(); if (exception_index_table != null) { c.exception_index_table = new int[exception_index_table.length]; System.arraycopy(exception_index_table, 0, c.exception_index_table, 0, exception_index_table.length); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/StackMapTableEntry.java0000644000175100017510000002161312271445223027557 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a stack map entry recording the types of * local variables and the the of stack items at a given byte code offset. * See CLDC specification §5.3.1.2 * * @author M. Dahm * @see StackMap * @see StackMapType */ public final class StackMapTableEntry implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private int frame_type; private int byte_code_offset_delta; private int number_of_locals; private StackMapType[] types_of_locals; private int number_of_stack_items; private StackMapType[] types_of_stack_items; /** * Construct object from file stream. * @param file Input stream * @throws IOException */ StackMapTableEntry(DataInputStream file, ConstantPool constant_pool) throws IOException { this(file.read(), -1, -1, null, -1, null); if (frame_type >= Constants.SAME_FRAME && frame_type <= Constants.SAME_FRAME_MAX) { byte_code_offset_delta = frame_type - Constants.SAME_FRAME; } else if (frame_type >= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME && frame_type <= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { byte_code_offset_delta = frame_type - Constants.SAME_LOCALS_1_STACK_ITEM_FRAME; number_of_stack_items = 1; types_of_stack_items = new StackMapType[1]; types_of_stack_items[0] = new StackMapType(file, constant_pool); } else if (frame_type == Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { byte_code_offset_delta = file.readShort(); number_of_stack_items = 1; types_of_stack_items = new StackMapType[1]; types_of_stack_items[0] = new StackMapType(file, constant_pool); } else if (frame_type >= Constants.CHOP_FRAME && frame_type <= Constants.CHOP_FRAME_MAX) { byte_code_offset_delta = file.readShort(); } else if (frame_type == Constants.SAME_FRAME_EXTENDED) { byte_code_offset_delta = file.readShort(); } else if (frame_type >= Constants.APPEND_FRAME && frame_type <= Constants.APPEND_FRAME_MAX) { byte_code_offset_delta = file.readShort(); number_of_locals = frame_type - 251; types_of_locals = new StackMapType[number_of_locals]; for (int i = 0; i < number_of_locals; i++) { types_of_locals[i] = new StackMapType(file, constant_pool); } } else if (frame_type == Constants.FULL_FRAME) { byte_code_offset_delta = file.readShort(); number_of_locals = file.readShort(); types_of_locals = new StackMapType[number_of_locals]; for (int i = 0; i < number_of_locals; i++) { types_of_locals[i] = new StackMapType(file, constant_pool); } number_of_stack_items = file.readShort(); types_of_stack_items = new StackMapType[number_of_stack_items]; for (int i = 0; i < number_of_stack_items; i++) { types_of_stack_items[i] = new StackMapType(file, constant_pool); } } else { /* Can't happen */ throw new ClassFormatException ("Invalid frame type found while parsing stack map table: " + frame_type); } } public StackMapTableEntry(int tag, int byte_code_offset_delta, int number_of_locals, StackMapType[] types_of_locals, int number_of_stack_items, StackMapType[] types_of_stack_items) { this.frame_type = tag; this.byte_code_offset_delta = byte_code_offset_delta; this.number_of_locals = number_of_locals; this.types_of_locals = types_of_locals; this.number_of_stack_items = number_of_stack_items; this.types_of_stack_items = types_of_stack_items; } /** * Dump stack map entry * * @param file Output file stream * @throws IOException */ public final void dump( DataOutputStream file ) throws IOException { file.write(frame_type); if (frame_type >= Constants.SAME_FRAME && frame_type <= Constants.SAME_FRAME_MAX) { // nothing to be done } else if (frame_type >= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME && frame_type <= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { types_of_stack_items[0].dump(file); } else if (frame_type == Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { file.writeShort(byte_code_offset_delta); types_of_stack_items[0].dump(file); } else if (frame_type >= Constants.CHOP_FRAME && frame_type <= Constants.CHOP_FRAME_MAX) { file.writeShort(byte_code_offset_delta); } else if (frame_type == Constants.SAME_FRAME_EXTENDED) { file.writeShort(byte_code_offset_delta); } else if (frame_type >= Constants.APPEND_FRAME && frame_type <= Constants.APPEND_FRAME_MAX) { file.writeShort(byte_code_offset_delta); for (int i = 0; i < number_of_locals; i++) { types_of_locals[i].dump(file); } } else if (frame_type == Constants.FULL_FRAME) { file.writeShort(byte_code_offset_delta); file.writeShort(number_of_locals); for (int i = 0; i < number_of_locals; i++) { types_of_locals[i].dump(file); } file.writeShort(number_of_stack_items); for (int i = 0; i < number_of_stack_items; i++) { types_of_stack_items[i].dump(file); } } else { /* Can't happen */ throw new ClassFormatException ("Invalid Stack map table tag: " + frame_type); } } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder(64); buf.append("("); if (frame_type >= Constants.SAME_FRAME && frame_type <= Constants.SAME_FRAME_MAX) { buf.append("SAME"); } else if (frame_type >= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME && frame_type <= Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { buf.append("SAME_LOCALS_1_STACK"); } else if (frame_type == Constants.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { buf.append("SAME_LOCALS_1_STACK_EXTENDED"); } else if (frame_type >= Constants.CHOP_FRAME && frame_type <= Constants.CHOP_FRAME_MAX) { buf.append("CHOP "+(251-frame_type)); } else if (frame_type == Constants.SAME_FRAME_EXTENDED) { buf.append("SAME_EXTENDED"); } else if (frame_type >= Constants.APPEND_FRAME && frame_type <= Constants.APPEND_FRAME_MAX) { buf.append("APPEND "+(frame_type-251)); } else if (frame_type == Constants.FULL_FRAME) { buf.append("FULL"); } else { buf.append("UNKNOWN"); } buf.append(", offset delta=").append(byte_code_offset_delta); if (number_of_locals > 0) { buf.append(", locals={"); for (int i = 0; i < number_of_locals; i++) { buf.append(types_of_locals[i]); if (i < number_of_locals - 1) { buf.append(", "); } } buf.append("}"); } if (number_of_stack_items > 0) { buf.append(", stack items={"); for (int i = 0; i < number_of_stack_items; i++) { buf.append(types_of_stack_items[i]); if (i < number_of_stack_items - 1) { buf.append(", "); } } buf.append("}"); } buf.append(")"); return buf.toString(); } /** * @return deep copy of this object */ public StackMapTableEntry copy() { try { return (StackMapTableEntry) clone(); } catch (CloneNotSupportedException e) { } return null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ArrayElementValue.java0000644000175100017510000000474312271445223027454 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataOutputStream; import java.io.IOException; public class ArrayElementValue extends ElementValue { // For array types, this is the array private ElementValue[] evalues; @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{"); for (int i = 0; i < evalues.length; i++) { sb.append(evalues[i].toString()); if ((i + 1) < evalues.length) sb.append(","); } sb.append("}"); return sb.toString(); } public ArrayElementValue(int type, ElementValue[] datums, ConstantPool cpool) { super(type, cpool); if (type != ARRAY) throw new RuntimeException( "Only element values of type array can be built with this ctor - type specified: " + type); this.evalues = datums; } @Override public void dump(DataOutputStream dos) throws IOException { dos.writeByte(type); // u1 type of value (ARRAY == '[') dos.writeShort(evalues.length); for (int i = 0; i < evalues.length; i++) { evalues[i].dump(dos); } } @Override public String stringifyValue() { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < evalues.length; i++) { sb.append(evalues[i].stringifyValue()); if ((i + 1) < evalues.length) sb.append(","); } sb.append("]"); return sb.toString(); } public ElementValue[] getElementValuesArray() { return evalues; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/InnerClasses.java0000644000175100017510000000721412271445223026454 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from Attribute and denotes that this class * is an Inner class of another. * to the source file of this class. * It is instantiated from the Attribute.readAttribute() method. * * @author M. Dahm * @see Attribute */ public final class InnerClasses extends Attribute { private static final long serialVersionUID = 54179484605570305L; private InnerClass[] inner_classes; private int number_of_classes; /** * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param inner_classes array of inner classes attributes * @param constant_pool Array of constants */ public InnerClasses(int name_index, int length, InnerClass[] inner_classes, ConstantPool constant_pool) { super(Constants.ATTR_INNER_CLASSES, name_index, length, constant_pool); setInnerClasses(inner_classes); } /** * Construct object from file stream. * * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ InnerClasses(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (InnerClass[]) null, constant_pool); number_of_classes = file.readUnsignedShort(); inner_classes = new InnerClass[number_of_classes]; for (int i = 0; i < number_of_classes; i++) { inner_classes[i] = new InnerClass(file); } } /** * @param inner_classes the array of inner classes */ public final void setInnerClasses( InnerClass[] inner_classes ) { this.inner_classes = inner_classes; number_of_classes = (inner_classes == null) ? 0 : inner_classes.length; } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder(); for (int i = 0; i < number_of_classes; i++) { buf.append(inner_classes[i].toString(constant_pool)).append("\n"); } return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { InnerClasses c = (InnerClasses) clone(); c.inner_classes = new InnerClass[number_of_classes]; for (int i = 0; i < number_of_classes; i++) { c.inner_classes[i] = inner_classes[i].copy(); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantCP.java0000644000175100017510000000513112271445223026073 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; /** * Abstract super class for Fieldref and Methodref constants. * * @author M. Dahm * @see ConstantFieldref * @see ConstantMethodref * @see ConstantInterfaceMethodref */ public abstract class ConstantCP extends Constant { private static final long serialVersionUID = 7282382456501145526L; /** References to the constants containing the class and the field signature */ protected int class_index, name_and_type_index; /** * Initialize instance from file data. * * @param tag Constant type tag * @param file Input stream * @throws IOException */ ConstantCP(byte tag, DataInput file) throws IOException { this(tag, file.readUnsignedShort(), file.readUnsignedShort()); } /** * @param class_index Reference to the class containing the field * @param name_and_type_index and the field signature */ protected ConstantCP(byte tag, int class_index, int name_and_type_index) { super(tag); this.class_index = class_index; this.name_and_type_index = name_and_type_index; } /** * @return Reference (index) to class this field or method belongs to. */ public final int getClassIndex() { return class_index; } /** * @return Reference (index) to signature of the field. */ public final int getNameAndTypeIndex() { return name_and_type_index; } /** * @return String representation. */ @Override public final String toString() { return super.toString() + "(class_index = " + class_index + ", name_and_type_index = " + name_and_type_index + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/AnnotationEntry.java0000644000175100017510000000656412271445223027226 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.apache.tomcat.util.bcel.Constants; /** * represents one annotation in the annotation table * * @author D. Brosius * @since 5.3 */ public class AnnotationEntry implements Constants, Serializable { private static final long serialVersionUID = 1L; private final int type_index; private final ConstantPool constant_pool; private List element_value_pairs; /** * Factory method to create an AnnotionEntry from a DataInputStream * * @param file * @param constant_pool * @return the entry * @throws IOException */ public static AnnotationEntry read(DataInputStream file, ConstantPool constant_pool) throws IOException { final AnnotationEntry annotationEntry = new AnnotationEntry(file.readUnsignedShort(), constant_pool); final int num_element_value_pairs = (file.readUnsignedShort()); annotationEntry.element_value_pairs = new ArrayList(); for (int i = 0; i < num_element_value_pairs; i++) { annotationEntry.element_value_pairs.add(new ElementValuePair(file.readUnsignedShort(), ElementValue.readElementValue(file, constant_pool), constant_pool)); } return annotationEntry; } public AnnotationEntry(int type_index, ConstantPool constant_pool) { this.type_index = type_index; this.constant_pool = constant_pool; } /** * @return the annotation type name */ public String getAnnotationType() { final ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(type_index, CONSTANT_Utf8); return c.getBytes(); } /** * @return the element value pairs in this annotation entry */ public ElementValuePair[] getElementValuePairs() { // TODO return List return element_value_pairs.toArray(new ElementValuePair[element_value_pairs.size()]); } public void dump(DataOutputStream dos) throws IOException { dos.writeShort(type_index); // u2 index of type name in cpool dos.writeShort(element_value_pairs.size()); // u2 element_value pair // count for (int i = 0; i < element_value_pairs.size(); i++) { final ElementValuePair envp = element_value_pairs.get(i); envp.dump(dos); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ElementValue.java0000644000175100017510000001067012271445223026451 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * @author D. Brosius * @since 5.3 */ public abstract class ElementValue { protected int type; protected ConstantPool cpool; @Override public String toString() { return stringifyValue(); } protected ElementValue(int type, ConstantPool cpool) { this.type = type; this.cpool = cpool; } public abstract String stringifyValue(); public abstract void dump(DataOutputStream dos) throws IOException; public static final int STRING = 's'; public static final int ENUM_CONSTANT = 'e'; public static final int CLASS = 'c'; public static final int ANNOTATION = '@'; public static final int ARRAY = '['; public static final int PRIMITIVE_INT = 'I'; public static final int PRIMITIVE_BYTE = 'B'; public static final int PRIMITIVE_CHAR = 'C'; public static final int PRIMITIVE_DOUBLE = 'D'; public static final int PRIMITIVE_FLOAT = 'F'; public static final int PRIMITIVE_LONG = 'J'; public static final int PRIMITIVE_SHORT = 'S'; public static final int PRIMITIVE_BOOLEAN = 'Z'; public static ElementValue readElementValue(DataInputStream dis, ConstantPool cpool) throws IOException { byte type = dis.readByte(); switch (type) { case 'B': // byte return new SimpleElementValue(PRIMITIVE_BYTE, dis .readUnsignedShort(), cpool); case 'C': // char return new SimpleElementValue(PRIMITIVE_CHAR, dis .readUnsignedShort(), cpool); case 'D': // double return new SimpleElementValue(PRIMITIVE_DOUBLE, dis .readUnsignedShort(), cpool); case 'F': // float return new SimpleElementValue(PRIMITIVE_FLOAT, dis .readUnsignedShort(), cpool); case 'I': // int return new SimpleElementValue(PRIMITIVE_INT, dis .readUnsignedShort(), cpool); case 'J': // long return new SimpleElementValue(PRIMITIVE_LONG, dis .readUnsignedShort(), cpool); case 'S': // short return new SimpleElementValue(PRIMITIVE_SHORT, dis .readUnsignedShort(), cpool); case 'Z': // boolean return new SimpleElementValue(PRIMITIVE_BOOLEAN, dis .readUnsignedShort(), cpool); case 's': // String return new SimpleElementValue(STRING, dis.readUnsignedShort(), cpool); case 'e': // Enum constant return new EnumElementValue(ENUM_CONSTANT, dis.readUnsignedShort(), dis.readUnsignedShort(), cpool); case 'c': // Class return new ClassElementValue(CLASS, dis.readUnsignedShort(), cpool); case '@': // Annotation // TODO isRuntimeVisible return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read( dis, cpool), cpool); case '[': // Array int numArrayVals = dis.readUnsignedShort(); ElementValue[] evalues = new ElementValue[numArrayVals]; for (int j = 0; j < numArrayVals; j++) { evalues[j] = ElementValue.readElementValue(dis, cpool); } return new ArrayElementValue(ARRAY, evalues, cpool); default: throw new RuntimeException( "Unexpected element value kind in annotation: " + type); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Attribute.java0000644000175100017510000002015512271445223026025 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import org.apache.tomcat.util.bcel.Constants; /** * Abstract super class for Attribute objects. Currently the * ConstantValue, SourceFile, Code, * Exceptiontable, LineNumberTable, * LocalVariableTable, InnerClasses and * Synthetic attributes are supported. The Unknown * attribute stands for non-standard-attributes. * * @author M. Dahm * @see ConstantValue * @see SourceFile * @see Code * @see Unknown * @see ExceptionTable * @see LineNumberTable * @see LocalVariableTable * @see InnerClasses * @see Synthetic * @see Deprecated * @see Signature */ public abstract class Attribute implements Cloneable, Serializable { private static final long serialVersionUID = 1514136303496688899L; protected int name_index; // Points to attribute name in constant pool protected int length; // Content length of attribute field protected byte tag; // Tag to distiguish subclasses protected ConstantPool constant_pool; protected Attribute(byte tag, int name_index, int length, ConstantPool constant_pool) { this.tag = tag; this.name_index = name_index; this.length = length; this.constant_pool = constant_pool; } private static final Map readers = new HashMap(); /* * Class method reads one attribute from the input data stream. This method * must not be accessible from the outside. It is called by the Field and * Method constructor methods. * * @see Field * @see Method @param file Input stream @param constant_pool Array of * constants @return Attribute @throws IOException @throws * ClassFormatException */ public static final Attribute readAttribute(DataInputStream file, ConstantPool constant_pool) throws IOException, ClassFormatException { ConstantUtf8 c; String name; int name_index; int length; byte tag = Constants.ATTR_UNKNOWN; // Unknown attribute // Get class name from constant pool via `name_index' indirection name_index = file.readUnsignedShort(); c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8); name = c.getBytes(); // Length of data in bytes length = file.readInt(); // Compare strings to find known attribute // System.out.println(name); for (byte i = 0; i < Constants.KNOWN_ATTRIBUTES; i++) { if (name.equals(Constants.ATTRIBUTE_NAMES[i])) { tag = i; // found! break; } } // Call proper constructor, depending on `tag' switch (tag) { case Constants.ATTR_UNKNOWN: AttributeReader r = readers.get(name); if (r != null) { return r.createAttribute(name_index, length, file, constant_pool); } return new Unknown(name_index, length, file, constant_pool); case Constants.ATTR_CONSTANT_VALUE: return new ConstantValue(name_index, length, file, constant_pool); case Constants.ATTR_SOURCE_FILE: return new SourceFile(name_index, length, file, constant_pool); case Constants.ATTR_CODE: return new Code(name_index, length, file, constant_pool); case Constants.ATTR_EXCEPTIONS: return new ExceptionTable(name_index, length, file, constant_pool); case Constants.ATTR_LINE_NUMBER_TABLE: return new LineNumberTable(name_index, length, file, constant_pool); case Constants.ATTR_LOCAL_VARIABLE_TABLE: return new LocalVariableTable(name_index, length, file, constant_pool); case Constants.ATTR_INNER_CLASSES: return new InnerClasses(name_index, length, file, constant_pool); case Constants.ATTR_SYNTHETIC: return new Synthetic(name_index, length, file, constant_pool); case Constants.ATTR_DEPRECATED: return new Deprecated(name_index, length, file, constant_pool); case Constants.ATTR_PMG: return new PMGClass(name_index, length, file, constant_pool); case Constants.ATTR_SIGNATURE: return new Signature(name_index, length, file, constant_pool); case Constants.ATTR_STACK_MAP: return new StackMap(name_index, length, file, constant_pool); case Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: return new RuntimeVisibleAnnotations(name_index, length, file, constant_pool); case Constants.ATTR_RUNTIMEIN_VISIBLE_ANNOTATIONS: return new RuntimeInvisibleAnnotations(name_index, length, file, constant_pool); case Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: return new RuntimeVisibleParameterAnnotations(name_index, length, file, constant_pool); case Constants.ATTR_RUNTIMEIN_VISIBLE_PARAMETER_ANNOTATIONS: return new RuntimeInvisibleParameterAnnotations(name_index, length, file, constant_pool); case Constants.ATTR_ANNOTATION_DEFAULT: return new AnnotationDefault(name_index, length, file, constant_pool); case Constants.ATTR_LOCAL_VARIABLE_TYPE_TABLE: return new LocalVariableTypeTable(name_index, length, file, constant_pool); case Constants.ATTR_ENCLOSING_METHOD: return new EnclosingMethod(name_index, length, file, constant_pool); case Constants.ATTR_STACK_MAP_TABLE: return new StackMapTable(name_index, length, file, constant_pool); default: // Never reached throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag); } } /** * @return Name of attribute */ public String getName() { ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8); return c.getBytes(); } /** * @return Tag of attribute, i.e., its type. Value may not be altered, thus * there is no setTag() method. */ public final byte getTag() { return tag; } /** * Use copy() if you want to have a deep copy(), i.e., with all references * copied correctly. * * @return shallow copy of this attribute */ @Override public Attribute clone() { Attribute attr = null; try { attr = (Attribute) super.clone(); } catch (CloneNotSupportedException e) { throw new Error("Clone Not Supported"); // never happens } return attr; } /** * @return deep copy of this attribute */ public abstract Attribute copy(ConstantPool _constant_pool); /** * @return attribute name. */ @Override public String toString() { return Constants.ATTRIBUTE_NAMES[tag]; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodType.java0000644000175100017510000000432212016521202027641 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a method type. * * @see Constant */ public final class ConstantMethodType extends Constant { private static final long serialVersionUID = 6750768220616618881L; private int descriptor_index; /** * Initialize from another object. */ public ConstantMethodType(ConstantMethodType c) { this(c.getDescriptorIndex()); } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantMethodType(DataInput file) throws IOException { this(file.readUnsignedShort()); } public ConstantMethodType(int descriptor_index) { super(Constants.CONSTANT_MethodType); this.descriptor_index = descriptor_index; } public int getDescriptorIndex() { return descriptor_index; } public void setDescriptorIndex(int descriptor_index) { this.descriptor_index = descriptor_index; } /** * @return String representation */ @Override public final String toString() { return super.toString() + "(descriptor_index = " + descriptor_index + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/StackMap.java0000644000175100017510000000723612271445223025572 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a stack map attribute used for * preverification of Java classes for the Java 2 Micro Edition * (J2ME). This attribute is used by the KVM and contained * within the Code attribute of a method. See CLDC specification * §5.3.1.2 * * @author M. Dahm * @see Code * @see StackMapEntry * @see StackMapType */ public final class StackMap extends Attribute { private static final long serialVersionUID = 264958819110329590L; private int map_length; private StackMapEntry[] map; // Table of stack map entries /* * @param name_index Index of name * @param length Content length in bytes * @param map Table of stack map entries * @param constant_pool Array of constants */ public StackMap(int name_index, int length, StackMapEntry[] map, ConstantPool constant_pool) { super(Constants.ATTR_STACK_MAP, name_index, length, constant_pool); setStackMap(map); } /** * Construct object from file stream. * @param name_index Index of name * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ StackMap(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (StackMapEntry[]) null, constant_pool); map_length = file.readUnsignedShort(); map = new StackMapEntry[map_length]; for (int i = 0; i < map_length; i++) { map[i] = new StackMapEntry(file, constant_pool); } } /** * @param map Array of stack map entries */ public final void setStackMap( StackMapEntry[] map ) { this.map = map; map_length = (map == null) ? 0 : map.length; } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder("StackMap("); for (int i = 0; i < map_length; i++) { buf.append(map[i].toString()); if (i < map_length - 1) { buf.append(", "); } } buf.append(')'); return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { StackMap c = (StackMap) clone(); c.map = new StackMapEntry[map_length]; for (int i = 0; i < map_length; i++) { c.map[i] = map[i].copy(); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Field.java0000644000175100017510000001025412271445223025104 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; import org.apache.tomcat.util.bcel.util.BCELComparator; /** * This class represents the field info structure, i.e., the representation * for a variable in the class. See JVM specification for details. * * @author M. Dahm */ public final class Field extends FieldOrMethod { private static final long serialVersionUID = 2646214544240375238L; private static BCELComparator _cmp = new BCELComparator() { @Override public boolean equals( Object o1, Object o2 ) { Field THIS = (Field) o1; Field THAT = (Field) o2; return THIS.getName().equals(THAT.getName()) && THIS.getSignature().equals(THAT.getSignature()); } @Override public int hashCode( Object o ) { Field THIS = (Field) o; return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); } }; /** * Construct object from file stream. * @param file Input stream */ Field(DataInputStream file, ConstantPool constant_pool) throws IOException, ClassFormatException { super(file, constant_pool); } /** * @return constant value associated with this field (may be null) */ public final ConstantValue getConstantValue() { for (int i = 0; i < attributes_count; i++) { if (attributes[i].getTag() == Constants.ATTR_CONSTANT_VALUE) { return (ConstantValue) attributes[i]; } } return null; } /** * Return string representation close to declaration format, * `public static final short MAX = 100', e.g.. * * @return String representation of field, including the signature. */ @Override public final String toString() { String name, signature, access; // Short cuts to constant pool // Get names from constant pool access = Utility.accessToString(access_flags); access = access.equals("") ? "" : (access + " "); signature = Utility.signatureToString(getSignature()); name = getName(); StringBuilder buf = new StringBuilder(64); buf.append(access).append(signature).append(" ").append(name); ConstantValue cv = getConstantValue(); if (cv != null) { buf.append(" = ").append(cv); } for (int i = 0; i < attributes_count; i++) { Attribute a = attributes[i]; if (!(a instanceof ConstantValue)) { buf.append(" [").append(a.toString()).append("]"); } } return buf.toString(); } /** * Return value as defined by given BCELComparator strategy. * By default two Field objects are said to be equal when * their names and signatures are equal. * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals( Object obj ) { return _cmp.equals(this, obj); } /** * Return value as defined by given BCELComparator strategy. * By default return the hashcode of the field's name XOR signature. * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return _cmp.hashCode(this); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/PMGClass.java0000644000175100017510000000631112271445223025471 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from Attribute and represents a reference * to a PMG attribute. * * @author M. Dahm * @see Attribute */ public final class PMGClass extends Attribute { private static final long serialVersionUID = -1876065562391587509L; private int pmg_class_index, pmg_index; /** * Construct object from file stream. * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ PMGClass(int name_index, int length, DataInput file, ConstantPool constant_pool) throws IOException { this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), constant_pool); } /** * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param pmg_index index in constant pool for source file name * @param pmg_class_index Index in constant pool to CONSTANT_Utf8 * @param constant_pool Array of constants */ public PMGClass(int name_index, int length, int pmg_index, int pmg_class_index, ConstantPool constant_pool) { super(Constants.ATTR_PMG, name_index, length, constant_pool); this.pmg_index = pmg_index; this.pmg_class_index = pmg_class_index; } /** * @return PMG name. */ public final String getPMGName() { ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(pmg_index, Constants.CONSTANT_Utf8); return c.getBytes(); } /** * @return PMG class name. */ public final String getPMGClassName() { ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(pmg_class_index, Constants.CONSTANT_Utf8); return c.getBytes(); } /** * @return String representation */ @Override public final String toString() { return "PMGClass(" + getPMGName() + ", " + getPMGClassName() + ")"; } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { return (PMGClass) clone(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/EnclosingMethod.java0000644000175100017510000000326012271445223027142 0ustar locutuslocutus/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This attribute exists for local or * anonymous classes and ... there can be only one. */ public class EnclosingMethod extends Attribute { private static final long serialVersionUID = 6755214228300933233L; // Ctors - and code to read an attribute in. public EnclosingMethod(int nameIndex, int len, DataInputStream dis, ConstantPool cpool) throws IOException { super(Constants.ATTR_ENCLOSING_METHOD, nameIndex, len, cpool); // Unused class index dis.readUnsignedShort(); // Unused method index dis.readUnsignedShort(); } @Override public Attribute copy(ConstantPool constant_pool) { throw new RuntimeException("Not implemented yet!"); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/InnerClass.java0000644000175100017510000001105012271445223026115 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a inner class attribute, i.e., the class * indices of the inner and outer classes, the name and the attributes * of the inner class. * * @author M. Dahm * @see InnerClasses */ public final class InnerClass implements Cloneable, Serializable { private static final long serialVersionUID = -4964694103982806087L; private int inner_class_index; private int outer_class_index; private int inner_name_index; private int inner_access_flags; /** * Construct object from file stream. * @param file Input stream * @throws IOException */ InnerClass(DataInput file) throws IOException { this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file .readUnsignedShort()); } /** * @param inner_class_index Class index in constant pool of inner class * @param outer_class_index Class index in constant pool of outer class * @param inner_name_index Name index in constant pool of inner class * @param inner_access_flags Access flags of inner class */ public InnerClass(int inner_class_index, int outer_class_index, int inner_name_index, int inner_access_flags) { this.inner_class_index = inner_class_index; this.outer_class_index = outer_class_index; this.inner_name_index = inner_name_index; this.inner_access_flags = inner_access_flags; } /** * Dump inner class attribute to file stream in binary format. * * @param file Output file stream * @throws IOException */ public final void dump( DataOutputStream file ) throws IOException { file.writeShort(inner_class_index); file.writeShort(outer_class_index); file.writeShort(inner_name_index); file.writeShort(inner_access_flags); } /** * @return String representation. */ @Override public final String toString() { return "InnerClass(" + inner_class_index + ", " + outer_class_index + ", " + inner_name_index + ", " + inner_access_flags + ")"; } /** * @return Resolved string representation */ public final String toString( ConstantPool constant_pool ) { String inner_class_name, outer_class_name, inner_name, access; inner_class_name = constant_pool.getConstantString(inner_class_index, Constants.CONSTANT_Class); inner_class_name = Utility.compactClassName(inner_class_name); if (outer_class_index != 0) { outer_class_name = constant_pool.getConstantString(outer_class_index, Constants.CONSTANT_Class); outer_class_name = Utility.compactClassName(outer_class_name); } else { outer_class_name = ""; } if (inner_name_index != 0) { inner_name = ((ConstantUtf8) constant_pool.getConstant(inner_name_index, Constants.CONSTANT_Utf8)).getBytes(); } else { inner_name = ""; } access = Utility.accessToString(inner_access_flags, true); access = access.equals("") ? "" : (access + " "); return "InnerClass:" + access + inner_class_name + "(\"" + outer_class_name + "\", \"" + inner_name + "\")"; } /** * @return deep copy of this object */ public InnerClass copy() { try { return (InnerClass) clone(); } catch (CloneNotSupportedException e) { } return null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ParameterAnnotationEntry.java0000644000175100017510000000340612271445223031057 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * represents one parameter annotation in the parameter annotation table * * @author D. Brosius * @since 5.3 */ public class ParameterAnnotationEntry implements Constants { private int annotation_table_length; private AnnotationEntry[] annotation_table; /** * Construct object from file stream. * @param file Input stream * @throws IOException */ ParameterAnnotationEntry(DataInputStream file, ConstantPool constant_pool) throws IOException { annotation_table_length = (file.readUnsignedShort()); annotation_table = new AnnotationEntry[annotation_table_length]; for (int i = 0; i < annotation_table_length; i++) { annotation_table[i] = AnnotationEntry.read(file, constant_pool); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantPool.java0000644000175100017510000002332312271445223026505 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import java.io.Serializable; import org.apache.tomcat.util.bcel.Constants; /** * This class represents the constant pool, i.e., a table of constants, of * a parsed classfile. It may contain null references, due to the JVM * specification that skips an entry after an 8-byte constant (double, * long) entry. Those interested in generating constant pools * programatically should see * ConstantPoolGen. * @see Constant * @author M. Dahm */ public class ConstantPool implements Cloneable, Serializable { private static final long serialVersionUID = -6765503791185687014L; private int constant_pool_count; private Constant[] constant_pool; /** * Read constants from given file stream. * * @param file Input stream * @throws IOException * @throws ClassFormatException */ ConstantPool(DataInputStream file) throws IOException, ClassFormatException { byte tag; constant_pool_count = file.readUnsignedShort(); constant_pool = new Constant[constant_pool_count]; /* constant_pool[0] is unused by the compiler and may be used freely * by the implementation. */ for (int i = 1; i < constant_pool_count; i++) { constant_pool[i] = Constant.readConstant(file); /* Quote from the JVM specification: * "All eight byte constants take up two spots in the constant pool. * If this is the n'th byte in the constant pool, then the next item * will be numbered n+2" * * Thus we have to increment the index counter. */ tag = constant_pool[i].getTag(); if ((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long)) { i++; } } } /** * Resolve constant to a string representation. * * @param c Constant to be printed * @return String representation */ public String constantToString( Constant c ) throws ClassFormatException { String str; int i; byte tag = c.getTag(); switch (tag) { case Constants.CONSTANT_Class: i = ((ConstantClass) c).getNameIndex(); c = getConstant(i, Constants.CONSTANT_Utf8); str = Utility.compactClassName(((ConstantUtf8) c).getBytes(), false); break; case Constants.CONSTANT_String: i = ((ConstantString) c).getStringIndex(); c = getConstant(i, Constants.CONSTANT_Utf8); str = "\"" + escape(((ConstantUtf8) c).getBytes()) + "\""; break; case Constants.CONSTANT_Utf8: str = ((ConstantUtf8) c).getBytes(); break; case Constants.CONSTANT_Double: str = String.valueOf(((ConstantDouble) c).getBytes()); break; case Constants.CONSTANT_Float: str = String.valueOf(((ConstantFloat) c).getBytes()); break; case Constants.CONSTANT_Long: str = String.valueOf(((ConstantLong) c).getBytes()); break; case Constants.CONSTANT_Integer: str = String.valueOf(((ConstantInteger) c).getBytes()); break; case Constants.CONSTANT_NameAndType: str = (constantToString(((ConstantNameAndType) c).getNameIndex(), Constants.CONSTANT_Utf8) + " " + constantToString(((ConstantNameAndType) c).getSignatureIndex(), Constants.CONSTANT_Utf8)); break; case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref: case Constants.CONSTANT_Fieldref: str = (constantToString(((ConstantCP) c).getClassIndex(), Constants.CONSTANT_Class) + "." + constantToString(((ConstantCP) c).getNameAndTypeIndex(), Constants.CONSTANT_NameAndType)); break; default: // Never reached throw new RuntimeException("Unknown constant type " + tag); } return str; } private static final String escape( String str ) { int len = str.length(); StringBuilder buf = new StringBuilder(len + 5); char[] ch = str.toCharArray(); for (int i = 0; i < len; i++) { switch (ch[i]) { case '\n': buf.append("\\n"); break; case '\r': buf.append("\\r"); break; case '\t': buf.append("\\t"); break; case '\b': buf.append("\\b"); break; case '"': buf.append("\\\""); break; default: buf.append(ch[i]); } } return buf.toString(); } /** * Retrieve constant at `index' from constant pool and resolve it to * a string representation. * * @param index of constant in constant pool * @param tag expected type * @return String representation */ public String constantToString( int index, byte tag ) throws ClassFormatException { Constant c = getConstant(index, tag); return constantToString(c); } /** * Get constant from constant pool. * * @param index Index in constant pool * @return Constant value * @see Constant */ public Constant getConstant( int index ) { if (index >= constant_pool.length || index < 0) { throw new ClassFormatException("Invalid constant pool reference: " + index + ". Constant pool size is: " + constant_pool.length); } return constant_pool[index]; } /** * Get constant from constant pool and check whether it has the * expected type. * * @param index Index in constant pool * @param tag Tag of expected constant, i.e., its type * @return Constant value * @see Constant * @throws ClassFormatException */ public Constant getConstant( int index, byte tag ) throws ClassFormatException { Constant c; c = getConstant(index); if (c == null) { throw new ClassFormatException("Constant pool at index " + index + " is null."); } if (c.getTag() != tag) { throw new ClassFormatException("Expected class `" + Constants.CONSTANT_NAMES[tag] + "' at index " + index + " and got " + c); } return c; } /** * Get string from constant pool and bypass the indirection of * `ConstantClass' and `ConstantString' objects. I.e. these classes have * an index field that points to another entry of the constant pool of * type `ConstantUtf8' which contains the real data. * * @param index Index in constant pool * @param tag Tag of expected constant, either ConstantClass or ConstantString * @return Contents of string reference * @see ConstantClass * @see ConstantString * @throws ClassFormatException */ public String getConstantString( int index, byte tag ) throws ClassFormatException { Constant c; int i; c = getConstant(index, tag); /* This switch() is not that elegant, since the two classes have the * same contents, they just differ in the name of the index * field variable. * But we want to stick to the JVM naming conventions closely though * we could have solved these more elegantly by using the same * variable name or by subclassing. */ switch (tag) { case Constants.CONSTANT_Class: i = ((ConstantClass) c).getNameIndex(); break; case Constants.CONSTANT_String: i = ((ConstantString) c).getStringIndex(); break; default: throw new RuntimeException("getConstantString called with illegal tag " + tag); } // Finally get the string from the constant pool c = getConstant(i, Constants.CONSTANT_Utf8); return ((ConstantUtf8) c).getBytes(); } /** * @return Length of constant pool. */ public int getLength() { return constant_pool_count; } /** * @return String representation. */ @Override public String toString() { StringBuilder buf = new StringBuilder(); for (int i = 1; i < constant_pool_count; i++) { buf.append(i).append(")").append(constant_pool[i]).append("\n"); } return buf.toString(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/AttributeReader.java0000644000175100017510000000452012271445223027146 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; /** * Unknown (non-standard) attributes may be read via user-defined factory * objects that can be registered with the Attribute.addAttributeReader * method. These factory objects should implement this interface. * @see Attribute * @author M. Dahm */ public interface AttributeReader { /** When this attribute reader is added via the static method Attribute.addAttributeReader, an attribute name is associated with it. As the class file parser parses attributes, it will call various AttributeReaders based on the name of the attributes it is constructing. @param name_index An index into the constant pool, indexing a ConstantUtf8 that represents the name of the attribute. @param length The length of the data contained in the attribute. This is written into the constant pool and should agree with what the factory expects the length to be. @param file This is the data input stream that the factory needs to read its data from. @param constant_pool This is the constant pool associated with the Attribute that we are constructing. @return The user-defined AttributeReader should take this data and use it to construct an attribute. In the case of errors, a null can be returned which will cause the parsing of the class file to fail. */ Attribute createAttribute( int name_index, int length, java.io.DataInputStream file, ConstantPool constant_pool ); } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/package.html0000644000175100017510000000177612271445223025510 0ustar locutuslocutus

    This package contains the classes that describe the structure of a Java class file and a class file parser.

    tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/RuntimeVisibleAnnotations.java0000644000175100017510000000401412271445223031235 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * represents an annotation that is represented in the class file and is * provided to the JVM. * * @author D. Brosius * @since 5.3 */ public class RuntimeVisibleAnnotations extends Annotations { private static final long serialVersionUID = 2912284875689024413L; /** * @param name_index * Index pointing to the name Code * @param length * Content length in bytes * @param file * Input stream * @param constant_pool * Array of constants */ public RuntimeVisibleAnnotations(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { super(Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS, name_index, length, file, constant_pool); } /** * @return deep copy of this attribute */ @Override public Attribute copy(ConstantPool constant_pool) { Annotations c = (Annotations) clone(); return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Synthetic.java0000644000175100017510000000673512271445223026044 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from Attribute and declares this class as * `synthetic', i.e., it needs special handling. The JVM specification * states "A class member that does not appear in the source code must be * marked using a Synthetic attribute." It may appear in the ClassFile * attribute table, a field_info table or a method_info table. This class * is intended to be instantiated from the * Attribute.readAttribute() method. * * @author M. Dahm * @see Attribute */ public final class Synthetic extends Attribute { private static final long serialVersionUID = -5129612853226360165L; private byte[] bytes; /** * @param name_index Index in constant pool to CONSTANT_Utf8, which * should represent the string "Synthetic". * @param length Content length in bytes - should be zero. * @param bytes Attribute contents * @param constant_pool The constant pool this attribute is associated * with. */ public Synthetic(int name_index, int length, byte[] bytes, ConstantPool constant_pool) { super(Constants.ATTR_SYNTHETIC, name_index, length, constant_pool); this.bytes = bytes; } /** * Construct object from file stream. * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ Synthetic(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (byte[]) null, constant_pool); if (length > 0) { bytes = new byte[length]; file.readFully(bytes); System.err.println("Synthetic attribute with length > 0"); } } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder("Synthetic"); if (length > 0) { buf.append(" ").append(Utility.toHexString(bytes)); } return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { Synthetic c = (Synthetic) clone(); if (bytes != null) { c.bytes = new byte[bytes.length]; System.arraycopy(bytes, 0, c.bytes, 0, bytes.length); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ElementValuePair.java0000644000175100017510000000366412271445223027272 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataOutputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * an annotation's element value pair * * @author D. Brosius * @since 5.3 */ public class ElementValuePair { private ElementValue elementValue; private ConstantPool constantPool; private int elementNameIndex; public ElementValuePair(int elementNameIndex, ElementValue elementValue, ConstantPool constantPool) { this.elementValue = elementValue; this.elementNameIndex = elementNameIndex; this.constantPool = constantPool; } public String getNameString() { ConstantUtf8 c = (ConstantUtf8) constantPool.getConstant( elementNameIndex, Constants.CONSTANT_Utf8); return c.getBytes(); } public final ElementValue getValue() { return elementValue; } protected void dump(DataOutputStream dos) throws IOException { dos.writeShort(elementNameIndex); // u2 name of the element elementValue.dump(dos); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/SimpleElementValue.java0000644000175100017510000001034112271445223027616 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataOutputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; public class SimpleElementValue extends ElementValue { private int index; public SimpleElementValue(int type, int index, ConstantPool cpool) { super(type, cpool); this.index = index; } /** * @return Value entry index in the cpool */ public int getIndex() { return index; } @Override public String toString() { return stringifyValue(); } // Whatever kind of value it is, return it as a string @Override public String stringifyValue() { switch (type) { case PRIMITIVE_INT: ConstantInteger c = (ConstantInteger) cpool.getConstant(getIndex(), Constants.CONSTANT_Integer); return Integer.toString(c.getBytes()); case PRIMITIVE_LONG: ConstantLong j = (ConstantLong) cpool.getConstant(getIndex(), Constants.CONSTANT_Long); return Long.toString(j.getBytes()); case PRIMITIVE_DOUBLE: ConstantDouble d = (ConstantDouble) cpool.getConstant(getIndex(), Constants.CONSTANT_Double); return Double.toString(d.getBytes()); case PRIMITIVE_FLOAT: ConstantFloat f = (ConstantFloat) cpool.getConstant(getIndex(), Constants.CONSTANT_Float); return Float.toString(f.getBytes()); case PRIMITIVE_SHORT: ConstantInteger s = (ConstantInteger) cpool.getConstant(getIndex(), Constants.CONSTANT_Integer); return Integer.toString(s.getBytes()); case PRIMITIVE_BYTE: ConstantInteger b = (ConstantInteger) cpool.getConstant(getIndex(), Constants.CONSTANT_Integer); return Integer.toString(b.getBytes()); case PRIMITIVE_CHAR: ConstantInteger ch = (ConstantInteger) cpool.getConstant( getIndex(), Constants.CONSTANT_Integer); return String.valueOf((char)ch.getBytes()); case PRIMITIVE_BOOLEAN: ConstantInteger bo = (ConstantInteger) cpool.getConstant( getIndex(), Constants.CONSTANT_Integer); if (bo.getBytes() == 0) { return "false"; } return "true"; case STRING: ConstantUtf8 cu8 = (ConstantUtf8) cpool.getConstant(getIndex(), Constants.CONSTANT_Utf8); return cu8.getBytes(); default: throw new RuntimeException( "SimpleElementValue class does not know how to stringify type " + type); } } @Override public void dump(DataOutputStream dos) throws IOException { dos.writeByte(type); // u1 kind of value switch (type) { case PRIMITIVE_INT: case PRIMITIVE_BYTE: case PRIMITIVE_CHAR: case PRIMITIVE_FLOAT: case PRIMITIVE_LONG: case PRIMITIVE_BOOLEAN: case PRIMITIVE_SHORT: case PRIMITIVE_DOUBLE: case STRING: dos.writeShort(getIndex()); break; default: throw new RuntimeException( "SimpleElementValue doesnt know how to write out type " + type); } } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Code.java0000644000175100017510000002142712271445223024737 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a chunk of Java byte code contained in a * method. It is instantiated by the * Attribute.readAttribute() method. A Code * attribute contains informations about operand stack, local * variables, byte code and the exceptions handled within this * method. * * This attribute has attributes itself, namely LineNumberTable which * is used for debugging purposes and LocalVariableTable which * contains information about the local variables. * * @author M. Dahm * @see Attribute * @see CodeException * @see LineNumberTable * @see LocalVariableTable */ public final class Code extends Attribute { private static final long serialVersionUID = 8936843273318969602L; private int max_stack; // Maximum size of stack used by this method private int max_locals; // Number of local variables private int code_length; // Length of code in bytes private byte[] code; // Actual byte code private int exception_table_length; private CodeException[] exception_table; // Table of handled exceptions private int attributes_count; // Attributes of code: LineNumber private Attribute[] attributes; // or LocalVariable /** * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants */ Code(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { // Initialize with some default values which will be overwritten later this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, (CodeException[]) null, (Attribute[]) null, constant_pool); code_length = file.readInt(); code = new byte[code_length]; // Read byte code file.readFully(code); /* Read exception table that contains all regions where an exception * handler is active, i.e., a try { ... } catch() block. */ exception_table_length = file.readUnsignedShort(); exception_table = new CodeException[exception_table_length]; for (int i = 0; i < exception_table_length; i++) { exception_table[i] = new CodeException(file); } /* Read all attributes, currently `LineNumberTable' and * `LocalVariableTable' */ attributes_count = file.readUnsignedShort(); attributes = new Attribute[attributes_count]; for (int i = 0; i < attributes_count; i++) { attributes[i] = Attribute.readAttribute(file, constant_pool); } /* Adjust length, because of setAttributes in this(), s.b. length * is incorrect, because it didn't take the internal attributes * into account yet! Very subtle bug, fixed in 3.1.1. */ this.length = length; } /** * @param name_index Index pointing to the name Code * @param length Content length in bytes * @param max_stack Maximum size of stack * @param max_locals Number of local variables * @param code Actual byte code * @param exception_table Table of handled exceptions * @param attributes Attributes of code: LineNumber or LocalVariable * @param constant_pool Array of constants */ public Code(int name_index, int length, int max_stack, int max_locals, byte[] code, CodeException[] exception_table, Attribute[] attributes, ConstantPool constant_pool) { super(Constants.ATTR_CODE, name_index, length, constant_pool); this.max_stack = max_stack; this.max_locals = max_locals; setCode(code); setExceptionTable(exception_table); setAttributes(attributes); // Overwrites length! } /** * @return LocalVariableTable of Code, if it has one */ public LocalVariableTable getLocalVariableTable() { for (int i = 0; i < attributes_count; i++) { if (attributes[i] instanceof LocalVariableTable) { return (LocalVariableTable) attributes[i]; } } return null; } /** * @return the internal length of this code attribute (minus the first 6 bytes) * and excluding all its attributes */ private final int getInternalLength() { return 2 /*max_stack*/+ 2 /*max_locals*/+ 4 /*code length*/ + code_length /*byte-code*/ + 2 /*exception-table length*/ + 8 * exception_table_length /* exception table */ + 2 /* attributes count */; } /** * @return the full size of this code attribute, minus its first 6 bytes, * including the size of all its contained attributes */ private final int calculateLength() { int len = 0; for (int i = 0; i < attributes_count; i++) { len += attributes[i].length + 6 /*attribute header size*/; } return len + getInternalLength(); } /** * @param attributes the attributes to set for this Code */ public final void setAttributes( Attribute[] attributes ) { this.attributes = attributes; attributes_count = (attributes == null) ? 0 : attributes.length; length = calculateLength(); // Adjust length } /** * @param code byte code */ public final void setCode( byte[] code ) { this.code = code; code_length = (code == null) ? 0 : code.length; length = calculateLength(); // Adjust length } /** * @param exception_table exception table */ public final void setExceptionTable( CodeException[] exception_table ) { this.exception_table = exception_table; exception_table_length = (exception_table == null) ? 0 : exception_table.length; length = calculateLength(); // Adjust length } /** * @return String representation of code chunk. */ public final String toString( boolean verbose ) { StringBuilder buf = new StringBuilder(100); buf.append("Code(max_stack = ").append(max_stack).append(", max_locals = ").append( max_locals).append(", code_length = ").append(code_length).append(")\n").append( Utility.codeToString(code, constant_pool, 0, -1, verbose)); if (exception_table_length > 0) { buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n"); for (int i = 0; i < exception_table_length; i++) { buf.append(exception_table[i].toString(constant_pool, verbose)).append("\n"); } } if (attributes_count > 0) { buf.append("\nAttribute(s) = \n"); for (int i = 0; i < attributes_count; i++) { buf.append(attributes[i].toString()).append("\n"); } } return buf.toString(); } /** * @return String representation of code chunk. */ @Override public final String toString() { return toString(true); } /** * @return deep copy of this attribute * * @param _constant_pool the constant pool to duplicate */ @Override public Attribute copy( ConstantPool _constant_pool ) { Code c = (Code) clone(); if (code != null) { c.code = new byte[code.length]; System.arraycopy(code, 0, c.code, 0, code.length); } c.constant_pool = _constant_pool; c.exception_table = new CodeException[exception_table_length]; for (int i = 0; i < exception_table_length; i++) { c.exception_table[i] = exception_table[i].copy(); } c.attributes = new Attribute[attributes_count]; for (int i = 0; i < attributes_count; i++) { c.attributes[i] = attributes[i].copy(_constant_pool); } return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/StackMapEntry.java0000644000175100017510000001074612271445223026614 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; /** * This class represents a stack map entry recording the types of * local variables and the the of stack items at a given byte code offset. * See CLDC specification §5.3.1.2 * * @author M. Dahm * @see StackMap * @see StackMapType */ public final class StackMapEntry implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private int byte_code_offset; private int number_of_locals; private StackMapType[] types_of_locals; private int number_of_stack_items; private StackMapType[] types_of_stack_items; /** * Construct object from file stream. * @param file Input stream * @throws IOException */ StackMapEntry(DataInputStream file, ConstantPool constant_pool) throws IOException { this(file.readShort(), file.readShort(), null, -1, null); types_of_locals = new StackMapType[number_of_locals]; for (int i = 0; i < number_of_locals; i++) { types_of_locals[i] = new StackMapType(file, constant_pool); } number_of_stack_items = file.readShort(); types_of_stack_items = new StackMapType[number_of_stack_items]; for (int i = 0; i < number_of_stack_items; i++) { types_of_stack_items[i] = new StackMapType(file, constant_pool); } } public StackMapEntry(int byte_code_offset, int number_of_locals, StackMapType[] types_of_locals, int number_of_stack_items, StackMapType[] types_of_stack_items) { this.byte_code_offset = byte_code_offset; this.number_of_locals = number_of_locals; this.types_of_locals = types_of_locals; this.number_of_stack_items = number_of_stack_items; this.types_of_stack_items = types_of_stack_items; } /** * Dump stack map entry * * @param file Output file stream * @throws IOException */ public final void dump( DataOutputStream file ) throws IOException { file.writeShort(byte_code_offset); file.writeShort(number_of_locals); for (int i = 0; i < number_of_locals; i++) { types_of_locals[i].dump(file); } file.writeShort(number_of_stack_items); for (int i = 0; i < number_of_stack_items; i++) { types_of_stack_items[i].dump(file); } } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder(64); buf.append("(offset=").append(byte_code_offset); if (number_of_locals > 0) { buf.append(", locals={"); for (int i = 0; i < number_of_locals; i++) { buf.append(types_of_locals[i]); if (i < number_of_locals - 1) { buf.append(", "); } } buf.append("}"); } if (number_of_stack_items > 0) { buf.append(", stack items={"); for (int i = 0; i < number_of_stack_items; i++) { buf.append(types_of_stack_items[i]); if (i < number_of_stack_items - 1) { buf.append(", "); } } buf.append("}"); } buf.append(")"); return buf.toString(); } /** * @return deep copy of this object */ public StackMapEntry copy() { try { return (StackMapEntry) clone(); } catch (CloneNotSupportedException e) { } return null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/LineNumberTable.java0000644000175100017510000001016312271445223027070 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a table of line numbers for debugging * purposes. This attribute is used by the Code attribute. It * contains pairs of PCs and line numbers. * * @author M. Dahm * @see Code * @see LineNumber */ public final class LineNumberTable extends Attribute { private static final long serialVersionUID = 6585122636118666124L; private int line_number_table_length; private LineNumber[] line_number_table; // Table of line/numbers pairs /* * @param name_index Index of name * @param length Content length in bytes * @param line_number_table Table of line/numbers pairs * @param constant_pool Array of constants */ public LineNumberTable(int name_index, int length, LineNumber[] line_number_table, ConstantPool constant_pool) { super(Constants.ATTR_LINE_NUMBER_TABLE, name_index, length, constant_pool); setLineNumberTable(line_number_table); } /** * Construct object from file stream. * @param name_index Index of name * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ LineNumberTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (LineNumber[]) null, constant_pool); line_number_table_length = (file.readUnsignedShort()); line_number_table = new LineNumber[line_number_table_length]; for (int i = 0; i < line_number_table_length; i++) { line_number_table[i] = new LineNumber(file); } } /** * @param line_number_table the line number entries for this table */ public final void setLineNumberTable( LineNumber[] line_number_table ) { this.line_number_table = line_number_table; line_number_table_length = (line_number_table == null) ? 0 : line_number_table.length; } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder(); StringBuilder line = new StringBuilder(); String newLine = System.getProperty("line.separator", "\n"); for (int i = 0; i < line_number_table_length; i++) { line.append(line_number_table[i].toString()); if (i < line_number_table_length - 1) { line.append(", "); } if (line.length() > 72) { line.append(newLine); buf.append(line.toString()); line.setLength(0); } } buf.append(line); return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { LineNumberTable c = (LineNumberTable) clone(); c.line_number_table = new LineNumber[line_number_table_length]; for (int i = 0; i < line_number_table_length; i++) { c.line_number_table[i] = line_number_table[i].copy(); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantString.java0000644000175100017510000000430212271445223027036 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a String object. * * @author M. Dahm * @see Constant */ public final class ConstantString extends Constant { private static final long serialVersionUID = 2809338612858801341L; private int string_index; // Identical to ConstantClass except for this name /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantString(DataInput file) throws IOException { this(file.readUnsignedShort()); } /** * @param string_index Index of Constant_Utf8 in constant pool */ public ConstantString(int string_index) { super(Constants.CONSTANT_String); this.string_index = string_index; } /** * @return Index in constant pool of the string (ConstantUtf8). */ public final int getStringIndex() { return string_index; } /** * @return String representation. */ @Override public final String toString() { return super.toString() + "(string_index = " + string_index + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantFieldref.java0000644000175100017510000000271212271445223027313 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a constant pool reference to a field. * * @author M. Dahm */ public final class ConstantFieldref extends ConstantCP { private static final long serialVersionUID = -8062332095934294437L; /** * Initialize instance from file data. * * @param file input stream * @throws IOException */ ConstantFieldref(DataInputStream file) throws IOException { super(Constants.CONSTANT_Fieldref, file); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantNameAndType.java0000644000175100017510000000512512271445223027741 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to the name and signature * of a field or method. * * @author M. Dahm * @see Constant */ public final class ConstantNameAndType extends Constant { private static final long serialVersionUID = 1010506730811368756L; private int name_index; // Name of field/method private int signature_index; // and its signature. /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantNameAndType(DataInput file) throws IOException { this(file.readUnsignedShort(), file.readUnsignedShort()); } /** * @param name_index Name of field/method * @param signature_index and its signature */ public ConstantNameAndType(int name_index, int signature_index) { super(Constants.CONSTANT_NameAndType); this.name_index = name_index; this.signature_index = signature_index; } /** * @return Name index in constant pool of field/method name. */ public final int getNameIndex() { return name_index; } /** * @return Index in constant pool of field/method signature. */ public final int getSignatureIndex() { return signature_index; } /** * @return String representation */ @Override public final String toString() { return super.toString() + "(name_index = " + name_index + ", signature_index = " + signature_index + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/RuntimeInvisibleAnnotations.java0000644000175100017510000000407012271445223031566 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * represents an annotation that is represented in the class file but is not * provided to the JVM. * * @author D. Brosius * @since 5.3 */ public class RuntimeInvisibleAnnotations extends Annotations { private static final long serialVersionUID = -7962627688723310248L; /** * @param name_index * Index pointing to the name Code * @param length * Content length in bytes * @param file * Input stream * @param constant_pool * Array of constants */ RuntimeInvisibleAnnotations(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { super(Constants.ATTR_RUNTIMEIN_VISIBLE_ANNOTATIONS, name_index, length, file, constant_pool); } /** * @return deep copy of this attribute */ @Override public Attribute copy(ConstantPool constant_pool) { Annotations c = (Annotations) clone(); return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/CodeException.java0000644000175100017510000001021312271445223026605 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import org.apache.tomcat.util.bcel.Constants; /** * This class represents an entry in the exception table of the Code * attribute and is used only there. It contains a range in which a * particular exception handler is active. * * @author M. Dahm * @see Code */ public final class CodeException implements Cloneable, Constants, Serializable { private static final long serialVersionUID = -6351674720658890686L; private int start_pc; // Range in the code the exception handler is private int end_pc; // active. start_pc is inclusive, end_pc exclusive private int handler_pc; /* Starting address of exception handler, i.e., * an offset from start of code. */ private int catch_type; /* If this is zero the handler catches any * exception, otherwise it points to the * exception class which is to be caught. */ /** * Construct object from file stream. * @param file Input stream * @throws IOException */ CodeException(DataInput file) throws IOException { this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file .readUnsignedShort()); } /** * @param start_pc Range in the code the exception handler is active, * start_pc is inclusive while * @param end_pc is exclusive * @param handler_pc Starting address of exception handler, i.e., * an offset from start of code. * @param catch_type If zero the handler catches any * exception, otherwise it points to the exception class which is * to be caught. */ public CodeException(int start_pc, int end_pc, int handler_pc, int catch_type) { this.start_pc = start_pc; this.end_pc = end_pc; this.handler_pc = handler_pc; this.catch_type = catch_type; } /** * Dump code exception to file stream in binary format. * * @param file Output file stream * @throws IOException */ public final void dump( DataOutputStream file ) throws IOException { file.writeShort(start_pc); file.writeShort(end_pc); file.writeShort(handler_pc); file.writeShort(catch_type); } /** * @return String representation. */ @Override public final String toString() { return "CodeException(start_pc = " + start_pc + ", end_pc = " + end_pc + ", handler_pc = " + handler_pc + ", catch_type = " + catch_type + ")"; } /** * @return String representation. */ public final String toString( ConstantPool cp, boolean verbose ) { String str; if (catch_type == 0) { str = "(0)"; } else { str = Utility.compactClassName(cp.getConstantString(catch_type, CONSTANT_Class), false) + (verbose ? "(" + catch_type + ")" : ""); } return start_pc + "\t" + end_pc + "\t" + handler_pc + "\t" + str; } /** * @return deep copy of this object */ public CodeException copy() { try { return (CodeException) clone(); } catch (CloneNotSupportedException e) { } return null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/LocalVariableTypeTable.java0000644000175100017510000000744312271445223030401 0ustar locutuslocutus/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; // The new table is used when generic types are about... //LocalVariableTable_attribute { // u2 attribute_name_index; // u4 attribute_length; // u2 local_variable_table_length; // { u2 start_pc; // u2 length; // u2 name_index; // u2 descriptor_index; // u2 index; // } local_variable_table[local_variable_table_length]; // } //LocalVariableTypeTable_attribute { // u2 attribute_name_index; // u4 attribute_length; // u2 local_variable_type_table_length; // { // u2 start_pc; // u2 length; // u2 name_index; // u2 signature_index; // u2 index; // } local_variable_type_table[local_variable_type_table_length]; // } // J5TODO: Needs some testing ! public class LocalVariableTypeTable extends Attribute { private static final long serialVersionUID = -5466082154076451597L; private int local_variable_type_table_length; // Table of local private LocalVariable[] local_variable_type_table; // variables public LocalVariableTypeTable(int name_index, int length, LocalVariable[] local_variable_table, ConstantPool constant_pool) { super(Constants.ATTR_LOCAL_VARIABLE_TYPE_TABLE, name_index, length, constant_pool); setLocalVariableTable(local_variable_table); } LocalVariableTypeTable(int nameIdx, int len, DataInputStream dis,ConstantPool cpool) throws IOException { this(nameIdx, len, (LocalVariable[])null, cpool); local_variable_type_table_length = (dis.readUnsignedShort()); local_variable_type_table = new LocalVariable[local_variable_type_table_length]; for(int i=0; i < local_variable_type_table_length; i++) local_variable_type_table[i] = new LocalVariable(dis, cpool); } public final void setLocalVariableTable(LocalVariable[] local_variable_table) { this.local_variable_type_table = local_variable_table; local_variable_type_table_length = (local_variable_table == null)? 0 : local_variable_table.length; } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder(); for(int i=0; i < local_variable_type_table_length; i++) { buf.append(local_variable_type_table[i].toString()); if(i < local_variable_type_table_length - 1) buf.append('\n'); } return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy(ConstantPool constant_pool) { LocalVariableTypeTable c = (LocalVariableTypeTable)clone(); c.local_variable_type_table = new LocalVariable[local_variable_type_table_length]; for(int i=0; i < local_variable_type_table_length; i++) c.local_variable_type_table[i] = local_variable_type_table[i].copy(); c.constant_pool = constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/LocalVariable.java0000644000175100017510000001060212271445223026556 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a local variable within a method. It contains its * scope, name, signature and index on the method's frame. * * @author M. Dahm * @see LocalVariableTable */ public final class LocalVariable implements Constants, Cloneable, Serializable { private static final long serialVersionUID = -914189896372081589L; private int start_pc; // Range in which the variable is valid private int length; private int name_index; // Index in constant pool of variable name private int signature_index; // Index of variable signature private int index; /* Variable is `index'th local variable on * this method's frame. */ private ConstantPool constant_pool; /** * Construct object from file stream. * @param file Input stream * @throws IOException */ LocalVariable(DataInput file, ConstantPool constant_pool) throws IOException { this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file .readUnsignedShort(), file.readUnsignedShort(), constant_pool); } /** * @param start_pc Range in which the variable * @param length ... is valid * @param name_index Index in constant pool of variable name * @param signature_index Index of variable's signature * @param index Variable is `index'th local variable on the method's frame * @param constant_pool Array of constants */ public LocalVariable(int start_pc, int length, int name_index, int signature_index, int index, ConstantPool constant_pool) { this.start_pc = start_pc; this.length = length; this.name_index = name_index; this.signature_index = signature_index; this.index = index; this.constant_pool = constant_pool; } /** * Dump local variable to file stream in binary format. * * @param file Output file stream * @throws IOException */ public final void dump( DataOutputStream file ) throws IOException { file.writeShort(start_pc); file.writeShort(length); file.writeShort(name_index); file.writeShort(signature_index); file.writeShort(index); } /** * @return Variable name. */ public final String getName() { ConstantUtf8 c; c = (ConstantUtf8) constant_pool.getConstant(name_index, CONSTANT_Utf8); return c.getBytes(); } /** * @return Signature. */ public final String getSignature() { ConstantUtf8 c; c = (ConstantUtf8) constant_pool.getConstant(signature_index, CONSTANT_Utf8); return c.getBytes(); } /** * @return index of register where variable is stored */ public final int getIndex() { return index; } /** * @return string representation. */ @Override public final String toString() { String name = getName(), signature = Utility.signatureToString(getSignature()); return "LocalVariable(start_pc = " + start_pc + ", length = " + length + ", index = " + index + ":" + signature + " " + name + ")"; } /** * @return deep copy of this object */ public LocalVariable copy() { try { return (LocalVariable) clone(); } catch (CloneNotSupportedException e) { } return null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/FieldOrMethod.java0000644000175100017510000000720212271445223026545 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * Abstract super class for fields and methods. * * @author M. Dahm */ public abstract class FieldOrMethod extends AccessFlags implements Cloneable { private static final long serialVersionUID = -3383525930205542157L; protected int name_index; // Points to field name in constant pool protected int signature_index; // Points to encoded signature protected int attributes_count; // No. of attributes protected Attribute[] attributes; // Collection of attributes protected ConstantPool constant_pool; FieldOrMethod() { } /** * Construct object from file stream. * @param file Input stream * @throws IOException * @throws ClassFormatException */ protected FieldOrMethod(DataInputStream file, ConstantPool constant_pool) throws IOException, ClassFormatException { this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constant_pool); attributes_count = file.readUnsignedShort(); attributes = new Attribute[attributes_count]; for (int i = 0; i < attributes_count; i++) { attributes[i] = Attribute.readAttribute(file, constant_pool); } } /** * @param access_flags Access rights of method * @param name_index Points to field name in constant pool * @param signature_index Points to encoded signature * @param attributes Collection of attributes * @param constant_pool Array of constants */ protected FieldOrMethod(int access_flags, int name_index, int signature_index, Attribute[] attributes, ConstantPool constant_pool) { this.access_flags = access_flags; this.name_index = name_index; this.signature_index = signature_index; this.constant_pool = constant_pool; setAttributes(attributes); } /** * @param attributes Collection of object attributes. */ public final void setAttributes( Attribute[] attributes ) { this.attributes = attributes; attributes_count = (attributes == null) ? 0 : attributes.length; } /** * @return Name of object, i.e., method name or field name */ public final String getName() { ConstantUtf8 c; c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8); return c.getBytes(); } /** * @return String representation of object's type signature (java style) */ public final String getSignature() { ConstantUtf8 c; c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8); return c.getBytes(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Signature.java0000644000175100017510000000546512271445223026032 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from Attribute and represents a reference * to a GJ attribute. * * @author M. Dahm * @see Attribute */ public final class Signature extends Attribute { private static final long serialVersionUID = 7493781777025829964L; private int signature_index; /** * Construct object from file stream. * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ Signature(int name_index, int length, DataInput file, ConstantPool constant_pool) throws IOException { this(name_index, length, file.readUnsignedShort(), constant_pool); } /** * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param signature_index Index in constant pool to CONSTANT_Utf8 * @param constant_pool Array of constants */ public Signature(int name_index, int length, int signature_index, ConstantPool constant_pool) { super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool); this.signature_index = signature_index; } /** * @return GJ signature. */ public final String getSignature() { ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8); return c.getBytes(); } /** * @return String representation */ @Override public final String toString() { String s = getSignature(); return "Signature(" + s + ")"; } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { return (Signature) clone(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Method.java0000644000175100017510000001274512271445223025310 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; import org.apache.tomcat.util.bcel.util.BCELComparator; /** * This class represents the method info structure, i.e., the representation * for a method in the class. See JVM specification for details. * A method has access flags, a name, a signature and a number of attributes. * * @author M. Dahm */ public final class Method extends FieldOrMethod { private static final long serialVersionUID = -7447828891136739513L; private static BCELComparator _cmp = new BCELComparator() { @Override public boolean equals( Object o1, Object o2 ) { Method THIS = (Method) o1; Method THAT = (Method) o2; return THIS.getName().equals(THAT.getName()) && THIS.getSignature().equals(THAT.getSignature()); } @Override public int hashCode( Object o ) { Method THIS = (Method) o; return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); } }; /** * Empty constructor, all attributes have to be defined via `setXXX' * methods. Use at your own risk. */ public Method() { } /** * Construct object from file stream. * @param file Input stream * @throws IOException * @throws ClassFormatException */ Method(DataInputStream file, ConstantPool constant_pool) throws IOException, ClassFormatException { super(file, constant_pool); } /** * @return Code attribute of method, if any */ public final Code getCode() { for (int i = 0; i < attributes_count; i++) { if (attributes[i] instanceof Code) { return (Code) attributes[i]; } } return null; } /** * @return ExceptionTable attribute of method, if any, i.e., list all * exceptions the method may throw not exception handlers! */ public final ExceptionTable getExceptionTable() { for (int i = 0; i < attributes_count; i++) { if (attributes[i] instanceof ExceptionTable) { return (ExceptionTable) attributes[i]; } } return null; } /** @return LocalVariableTable of code attribute if any, i.e. the call is forwarded * to the Code atribute. */ public final LocalVariableTable getLocalVariableTable() { Code code = getCode(); if (code == null) { return null; } return code.getLocalVariableTable(); } /** * Return string representation close to declaration format, * `public static void main(String[] args) throws IOException', e.g. * * @return String representation of the method. */ @Override public final String toString() { ConstantUtf8 c; String name, signature, access; // Short cuts to constant pool StringBuilder buf; access = Utility.accessToString(access_flags); // Get name and signature from constant pool c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8); signature = c.getBytes(); c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8); name = c.getBytes(); signature = Utility.methodSignatureToString(signature, name, access, true, getLocalVariableTable()); buf = new StringBuilder(signature); for (int i = 0; i < attributes_count; i++) { Attribute a = attributes[i]; if (!((a instanceof Code) || (a instanceof ExceptionTable))) { buf.append(" [").append(a.toString()).append("]"); } } ExceptionTable e = getExceptionTable(); if (e != null) { String str = e.toString(); if (!str.equals("")) { buf.append("\n\t\tthrows ").append(str); } } return buf.toString(); } /** * Return value as defined by given BCELComparator strategy. * By default two method objects are said to be equal when * their names and signatures are equal. * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals( Object obj ) { return _cmp.equals(this, obj); } /** * Return value as defined by given BCELComparator strategy. * By default return the hashcode of the method's name XOR signature. * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return _cmp.hashCode(this); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodref.java0000644000175100017510000000271612271445223027514 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a constant pool reference to a method. * * @author M. Dahm */ public final class ConstantMethodref extends ConstantCP { private static final long serialVersionUID = -7857009620954576086L; /** * Initialize instance from file data. * * @param file input stream * @throws IOException */ ConstantMethodref(DataInputStream file) throws IOException { super(Constants.CONSTANT_Methodref, file); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/AnnotationDefault.java0000644000175100017510000000540312271445223027500 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * represents the default value of a annotation for a method info * * @author D. Brosius * @since 5.3 */ public class AnnotationDefault extends Attribute { private static final long serialVersionUID = 6715933396664171543L; ElementValue default_value; /** * @param name_index * Index pointing to the name Code * @param length * Content length in bytes * @param file * Input stream * @param constant_pool * Array of constants */ public AnnotationDefault(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (ElementValue) null, constant_pool); default_value = ElementValue.readElementValue(file, constant_pool); } /** * @param name_index * Index pointing to the name Code * @param length * Content length in bytes * @param defaultValue * the annotation's default value * @param constant_pool * Array of constants */ public AnnotationDefault(int name_index, int length, ElementValue defaultValue, ConstantPool constant_pool) { super(Constants.ATTR_ANNOTATION_DEFAULT, name_index, length, constant_pool); setDefaultValue(defaultValue); } /** * @param defaultValue * the default value of this methodinfo's annotation */ public final void setDefaultValue(ElementValue defaultValue) { default_value = defaultValue; } @Override public Attribute copy(ConstantPool _constant_pool) { throw new RuntimeException("Not implemented yet!"); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantMethodHandle.java0000644000175100017510000000512612016521202030116 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a method handle. * * @see Constant */ public final class ConstantMethodHandle extends Constant { private static final long serialVersionUID = -7875124116920198044L; private int reference_kind; private int reference_index; /** * Initialize from another object. */ public ConstantMethodHandle(ConstantMethodHandle c) { this(c.getReferenceKind(), c.getReferenceIndex()); } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantMethodHandle(DataInput file) throws IOException { this(file.readUnsignedByte(), file.readUnsignedShort()); } public ConstantMethodHandle(int reference_kind, int reference_index) { super(Constants.CONSTANT_MethodHandle); this.reference_kind = reference_kind; this.reference_index = reference_index; } public int getReferenceKind() { return reference_kind; } public void setReferenceKind(int reference_kind) { this.reference_kind = reference_kind; } public int getReferenceIndex() { return reference_index; } public void setReferenceIndex(int reference_index) { this.reference_index = reference_index; } /** * @return String representation */ @Override public final String toString() { return super.toString() + "(reference_kind = " + reference_kind + ", reference_index = " + reference_index + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantInvokeDynamic.java0000644000175100017510000000551212016521202030321 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a invoke dynamic. * * @see Constant */ public final class ConstantInvokeDynamic extends Constant { private static final long serialVersionUID = 4310367359017396174L; private int bootstrap_method_attr_index; private int name_and_type_index; /** * Initialize from another object. */ public ConstantInvokeDynamic(ConstantInvokeDynamic c) { this(c.getBootstrapMethodAttrIndex(), c.getNameAndTypeIndex()); } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantInvokeDynamic(DataInput file) throws IOException { this(file.readUnsignedShort(), file.readUnsignedShort()); } public ConstantInvokeDynamic(int bootstrap_method_attr_index, int name_and_type_index) { super(Constants.CONSTANT_InvokeDynamic); this.bootstrap_method_attr_index = bootstrap_method_attr_index; this.name_and_type_index = name_and_type_index; } public int getBootstrapMethodAttrIndex() { return bootstrap_method_attr_index; } public void setBootstrapMethodAttrIndex(int bootstrap_method_attr_index) { this.bootstrap_method_attr_index = bootstrap_method_attr_index; } public int getNameAndTypeIndex() { return name_and_type_index; } public void setNameAndTypeIndex(int name_and_type_index) { this.name_and_type_index = name_and_type_index; } /** * @return String representation */ @Override public final String toString() { return super.toString() + "(bootstrap_method_attr_index = " + bootstrap_method_attr_index + ", name_and_type_index = " + name_and_type_index + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java0000644000175100017510000000401412271445223026635 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a float object. * * @author M. Dahm * @see Constant */ public final class ConstantFloat extends Constant { private static final long serialVersionUID = 8301269629885378651L; private float bytes; /** * @param bytes Data */ public ConstantFloat(float bytes) { super(Constants.CONSTANT_Float); this.bytes = bytes; } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantFloat(DataInput file) throws IOException { this(file.readFloat()); } /** * @return data, i.e., 4 bytes. */ public final float getBytes() { return bytes; } /** * @return String representation. */ @Override public final String toString() { return super.toString() + "(bytes = " + bytes + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/AccessFlags.java0000644000175100017510000000257512271445223026246 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; /** * Super class for all objects that have modifiers like private, final, ... * I.e. classes, fields, and methods. * * @author M. Dahm */ public abstract class AccessFlags implements java.io.Serializable { private static final long serialVersionUID = 2548932939969293935L; protected int access_flags; public AccessFlags() { } /** * @return Access flags of the object aka. "modifiers". */ public final int getAccessFlags() { return access_flags; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Utility.java0000644000175100017510000007423112271445223025531 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; import org.apache.tomcat.util.bcel.util.ByteSequence; /** * Utility functions that do not really belong to any class in particular. * * @author M. Dahm */ public abstract class Utility { private static int unwrap( ThreadLocal tl ) { return tl.get().intValue(); } private static void wrap( ThreadLocal tl, int value ) { tl.set(Integer.valueOf(value)); } private static ThreadLocal consumed_chars = new ThreadLocal() { @Override protected Integer initialValue() { return Integer.valueOf(0); } };/* How many chars have been consumed * during parsing in signatureToString(). * Read by methodSignatureToString(). * Set by side effect,but only internally. */ private static boolean wide = false; /* The `WIDE' instruction is used in the * byte code to allow 16-bit wide indices * for local variables. This opcode * precedes an `ILOAD', e.g.. The opcode * immediately following takes an extra * byte which is combined with the * following byte to form a * 16-bit value. */ /** * Convert bit field of flags into string such as `static final'. * * @param access_flags Access flags * @return String representation of flags */ public static final String accessToString( int access_flags ) { return accessToString(access_flags, false); } /** * Convert bit field of flags into string such as `static final'. * * Special case: Classes compiled with new compilers and with the * `ACC_SUPER' flag would be said to be "synchronized". This is * because SUN used the same value for the flags `ACC_SUPER' and * `ACC_SYNCHRONIZED'. * * @param access_flags Access flags * @param for_class access flags are for class qualifiers ? * @return String representation of flags */ public static final String accessToString( int access_flags, boolean for_class ) { StringBuilder buf = new StringBuilder(); int p = 0; for (int i = 0; p < Constants.MAX_ACC_FLAG; i++) { // Loop through known flags p = pow2(i); if ((access_flags & p) != 0) { /* Special case: Classes compiled with new compilers and with the * `ACC_SUPER' flag would be said to be "synchronized". This is * because SUN used the same value for the flags `ACC_SUPER' and * `ACC_SYNCHRONIZED'. */ if (for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE))) { continue; } buf.append(Constants.ACCESS_NAMES[i]).append(" "); } } return buf.toString().trim(); } /** * @param access_flags the class flags * * @return "class" or "interface", depending on the ACC_INTERFACE flag */ public static final String classOrInterface( int access_flags ) { return ((access_flags & Constants.ACC_INTERFACE) != 0) ? "interface" : "class"; } /** * Disassemble a byte array of JVM byte codes starting from code line * `index' and return the disassembled string representation. Decode only * `num' opcodes (including their operands), use -1 if you want to * decompile everything. * * @param code byte code array * @param constant_pool Array of constants * @param index offset in `code' array * (number of opcodes, not bytes!) * @param length number of opcodes to decompile, -1 for all * @param verbose be verbose, e.g. print constant pool index * @return String representation of byte codes */ public static final String codeToString( byte[] code, ConstantPool constant_pool, int index, int length, boolean verbose ) { StringBuilder buf = new StringBuilder(code.length * 20); // Should be sufficient ByteSequence stream = new ByteSequence(code); try { for (int i = 0; i < index; i++) { codeToString(stream, constant_pool, verbose); } for (int i = 0; stream.available() > 0; i++) { if ((length < 0) || (i < length)) { String indices = fillup(stream.getIndex() + ":", 6, true, ' '); buf.append(indices).append(codeToString(stream, constant_pool, verbose)) .append('\n'); } } } catch (IOException e) { System.out.println(buf.toString()); e.printStackTrace(); throw new ClassFormatException("Byte code error: " + e, e); } return buf.toString(); } /** * Disassemble a stream of byte codes and return the * string representation. * * @param bytes stream of bytes * @param constant_pool Array of constants * @param verbose be verbose, e.g. print constant pool index * @return String representation of byte code * * @throws IOException if a failure from reading from the bytes argument occurs */ public static final String codeToString( ByteSequence bytes, ConstantPool constant_pool, boolean verbose ) throws IOException { short opcode = (short) bytes.readUnsignedByte(); int default_offset = 0, low, high, npairs; int index, vindex, constant; int[] match, jump_table; int no_pad_bytes = 0, offset; StringBuilder buf = new StringBuilder(Constants.OPCODE_NAMES[opcode]); /* Special case: Skip (0-3) padding bytes, i.e., the * following bytes are 4-byte-aligned */ if ((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) { int remainder = bytes.getIndex() % 4; no_pad_bytes = (remainder == 0) ? 0 : 4 - remainder; for (int i = 0; i < no_pad_bytes; i++) { byte b; if ((b = bytes.readByte()) != 0) { System.err.println("Warning: Padding byte != 0 in " + Constants.OPCODE_NAMES[opcode] + ":" + b); } } // Both cases have a field default_offset in common default_offset = bytes.readInt(); } switch (opcode) { /* Table switch has variable length arguments. */ case Constants.TABLESWITCH: low = bytes.readInt(); high = bytes.readInt(); offset = bytes.getIndex() - 12 - no_pad_bytes - 1; default_offset += offset; buf.append("\tdefault = ").append(default_offset).append(", low = ").append(low) .append(", high = ").append(high).append("("); jump_table = new int[high - low + 1]; for (int i = 0; i < jump_table.length; i++) { jump_table[i] = offset + bytes.readInt(); buf.append(jump_table[i]); if (i < jump_table.length - 1) { buf.append(", "); } } buf.append(")"); break; /* Lookup switch has variable length arguments. */ case Constants.LOOKUPSWITCH: { npairs = bytes.readInt(); offset = bytes.getIndex() - 8 - no_pad_bytes - 1; match = new int[npairs]; jump_table = new int[npairs]; default_offset += offset; buf.append("\tdefault = ").append(default_offset).append(", npairs = ").append( npairs).append(" ("); for (int i = 0; i < npairs; i++) { match[i] = bytes.readInt(); jump_table[i] = offset + bytes.readInt(); buf.append("(").append(match[i]).append(", ").append(jump_table[i]).append(")"); if (i < npairs - 1) { buf.append(", "); } } buf.append(")"); } break; /* Two address bytes + offset from start of byte stream form the * jump target */ case Constants.GOTO: case Constants.IFEQ: case Constants.IFGE: case Constants.IFGT: case Constants.IFLE: case Constants.IFLT: case Constants.JSR: case Constants.IFNE: case Constants.IFNONNULL: case Constants.IFNULL: case Constants.IF_ACMPEQ: case Constants.IF_ACMPNE: case Constants.IF_ICMPEQ: case Constants.IF_ICMPGE: case Constants.IF_ICMPGT: case Constants.IF_ICMPLE: case Constants.IF_ICMPLT: case Constants.IF_ICMPNE: buf.append("\t\t#").append((bytes.getIndex() - 1) + bytes.readShort()); break; /* 32-bit wide jumps */ case Constants.GOTO_W: case Constants.JSR_W: buf.append("\t\t#").append(((bytes.getIndex() - 1) + bytes.readInt())); break; /* Index byte references local variable (register) */ case Constants.ALOAD: case Constants.ASTORE: case Constants.DLOAD: case Constants.DSTORE: case Constants.FLOAD: case Constants.FSTORE: case Constants.ILOAD: case Constants.ISTORE: case Constants.LLOAD: case Constants.LSTORE: case Constants.RET: if (wide) { vindex = bytes.readUnsignedShort(); wide = false; // Clear flag } else { vindex = bytes.readUnsignedByte(); } buf.append("\t\t%").append(vindex); break; /* * Remember wide byte which is used to form a 16-bit address in the * following instruction. Relies on that the method is called again with * the following opcode. */ case Constants.WIDE: wide = true; buf.append("\t(wide)"); break; /* Array of basic type. */ case Constants.NEWARRAY: buf.append("\t\t<").append(Constants.TYPE_NAMES[bytes.readByte()]).append(">"); break; /* Access object/class fields. */ case Constants.GETFIELD: case Constants.GETSTATIC: case Constants.PUTFIELD: case Constants.PUTSTATIC: index = bytes.readUnsignedShort(); buf.append("\t\t").append( constant_pool.constantToString(index, Constants.CONSTANT_Fieldref)).append( (verbose ? " (" + index + ")" : "")); break; /* Operands are references to classes in constant pool */ case Constants.NEW: case Constants.CHECKCAST: buf.append("\t"); //$FALL-THROUGH$ case Constants.INSTANCEOF: index = bytes.readUnsignedShort(); buf.append("\t<").append( constant_pool.constantToString(index, Constants.CONSTANT_Class)) .append(">").append((verbose ? " (" + index + ")" : "")); break; /* Operands are references to methods in constant pool */ case Constants.INVOKESPECIAL: case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL: index = bytes.readUnsignedShort(); buf.append("\t").append( constant_pool.constantToString(index, Constants.CONSTANT_Methodref)) .append((verbose ? " (" + index + ")" : "")); break; case Constants.INVOKEINTERFACE: index = bytes.readUnsignedShort(); int nargs = bytes.readUnsignedByte(); // historical, redundant buf.append("\t").append( constant_pool .constantToString(index, Constants.CONSTANT_InterfaceMethodref)) .append(verbose ? " (" + index + ")\t" : "").append(nargs).append("\t") .append(bytes.readUnsignedByte()); // Last byte is a reserved space break; /* Operands are references to items in constant pool */ case Constants.LDC_W: case Constants.LDC2_W: index = bytes.readUnsignedShort(); buf.append("\t\t").append( constant_pool.constantToString(index, constant_pool.getConstant(index) .getTag())).append((verbose ? " (" + index + ")" : "")); break; case Constants.LDC: index = bytes.readUnsignedByte(); buf.append("\t\t").append( constant_pool.constantToString(index, constant_pool.getConstant(index) .getTag())).append((verbose ? " (" + index + ")" : "")); break; /* Array of references. */ case Constants.ANEWARRAY: index = bytes.readUnsignedShort(); buf.append("\t\t<").append( compactClassName(constant_pool.getConstantString(index, Constants.CONSTANT_Class), false)).append(">").append( (verbose ? " (" + index + ")" : "")); break; /* Multidimensional array of references. */ case Constants.MULTIANEWARRAY: { index = bytes.readUnsignedShort(); int dimensions = bytes.readUnsignedByte(); buf.append("\t<").append( compactClassName(constant_pool.getConstantString(index, Constants.CONSTANT_Class), false)).append(">\t").append(dimensions) .append((verbose ? " (" + index + ")" : "")); } break; /* Increment local variable. */ case Constants.IINC: if (wide) { vindex = bytes.readUnsignedShort(); constant = bytes.readShort(); wide = false; } else { vindex = bytes.readUnsignedByte(); constant = bytes.readByte(); } buf.append("\t\t%").append(vindex).append("\t").append(constant); break; default: if (Constants.NO_OF_OPERANDS[opcode] > 0) { for (int i = 0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) { buf.append("\t\t"); switch (Constants.TYPE_OF_OPERANDS[opcode][i]) { case Constants.T_BYTE: buf.append(bytes.readByte()); break; case Constants.T_SHORT: buf.append(bytes.readShort()); break; case Constants.T_INT: buf.append(bytes.readInt()); break; default: // Never reached System.err.println("Unreachable default case reached!"); System.exit(-1); } } } } return buf.toString(); } /** * Shorten long class names, java/lang/String becomes * String. * * @param str The long class name * @return Compacted class name */ public static final String compactClassName( String str ) { return compactClassName(str, true); } /** * Shorten long class name str, i.e., chop off the prefix, * if the * class name starts with this string and the flag chopit is true. * Slashes / are converted to dots .. * * @param str The long class name * @param prefix The prefix the get rid off * @param chopit Flag that determines whether chopping is executed or not * @return Compacted class name */ public static final String compactClassName( String str, String prefix, boolean chopit ) { int len = prefix.length(); str = str.replace('/', '.'); // Is `/' on all systems, even DOS if (chopit) { // If string starts with `prefix' and contains no further dots if (str.startsWith(prefix) && (str.substring(len).indexOf('.') == -1)) { str = str.substring(len); } } return str; } /** * Shorten long class names, java/lang/String becomes * java.lang.String, * e.g.. If chopit is true the prefix java.lang * is also removed. * * @param str The long class name * @param chopit Flag that determines whether chopping is executed or not * @return Compacted class name */ public static final String compactClassName( String str, boolean chopit ) { return compactClassName(str, "java.lang.", chopit); } /** * A returntype signature represents the return value from a method. * It is a series of bytes in the following grammar: * * ::= | V * * The character V indicates that the method returns no value. Otherwise, the * signature indicates the type of the return value. * An argument signature represents an argument passed to a method: * * ::= * * A method signature represents the arguments that the method expects, and * the value that it returns. * ::= () * ::= * * * This method converts such a string into a Java type declaration like * `void main(String[])' and throws a `ClassFormatException' when the parsed * type is invalid. * * @param signature Method signature * @param name Method name * @param access Method access rights * @param chopit * @param vars * @return Java type declaration * @throws ClassFormatException */ public static final String methodSignatureToString( String signature, String name, String access, boolean chopit, LocalVariableTable vars ) throws ClassFormatException { StringBuilder buf = new StringBuilder("("); String type; int index; int var_index = (access.indexOf("static") >= 0) ? 0 : 1; try { // Read all declarations between for `(' and `)' if (signature.charAt(0) != '(') { throw new ClassFormatException("Invalid method signature: " + signature); } index = 1; // current string position while (signature.charAt(index) != ')') { String param_type = signatureToString(signature.substring(index), chopit); buf.append(param_type); if (vars != null) { LocalVariable l = vars.getLocalVariable(var_index); if (l != null) { buf.append(" ").append(l.getName()); } } else { buf.append(" arg").append(var_index); } if ("double".equals(param_type) || "long".equals(param_type)) { var_index += 2; } else { var_index++; } buf.append(", "); //corrected concurrent private static field acess index += unwrap(consumed_chars); // update position } index++; // update position // Read return type after `)' type = signatureToString(signature.substring(index), chopit); } catch (StringIndexOutOfBoundsException e) { // Should never occur throw new ClassFormatException("Invalid method signature: " + signature, e); } if (buf.length() > 1) { buf.setLength(buf.length() - 2); } buf.append(")"); return access + ((access.length() > 0) ? " " : "") + // May be an empty string type + " " + name + buf.toString(); } // Guess what this does private static final int pow2( int n ) { return 1 << n; } /** * Replace all occurrences of old in str with new. * * @param str String to permute * @param old String to be replaced * @param new_ Replacement string * @return new String object */ public static final String replace( String str, String old, String new_ ) { int index, old_index; try { if (str.indexOf(old) != -1) { // `old' found in str StringBuffer buf = new StringBuffer(); old_index = 0; // String start offset // While we have something to replace while ((index = str.indexOf(old, old_index)) != -1) { buf.append(str.substring(old_index, index)); // append prefix buf.append(new_); // append replacement old_index = index + old.length(); // Skip `old'.length chars } buf.append(str.substring(old_index)); // append rest of string str = buf.toString(); } } catch (StringIndexOutOfBoundsException e) { // Should not occur System.err.println(e); } return str; } /** * Converts signature to string with all class names compacted. * * @param signature to convert * @return Human readable signature */ public static final String signatureToString( String signature ) { return signatureToString(signature, true); } /** * The field signature represents the value of an argument to a function or * the value of a variable. It is a series of bytes generated by the * following grammar: * *
         *  ::= 
         *       ::= ||
         *        ::= B|C|D|F|I|J|S|Z
         *      ::= L;
         *       ::= [
         *
         * The meaning of the base types is as follows:
         * B byte signed byte
         * C char character
         * D double double precision IEEE float
         * F float single precision IEEE float
         * I int integer
         * J long long integer
         * L; ... an object of the given class
         * S short signed short
         * Z boolean true or false
         * [ ... array
         * 
    * * This method converts this string into a Java type declaration such as * `String[]' and throws a `ClassFormatException' when the parsed type is * invalid. * * @param signature Class signature * @param chopit Flag that determines whether chopping is executed or not * @return Java type declaration * @throws ClassFormatException */ public static final String signatureToString( String signature, boolean chopit ) { //corrected concurrent private static field acess wrap(consumed_chars, 1); // This is the default, read just one char like `B' try { switch (signature.charAt(0)) { case 'B': return "byte"; case 'C': return "char"; case 'D': return "double"; case 'F': return "float"; case 'I': return "int"; case 'J': return "long"; case 'L': { // Full class name int index = signature.indexOf(';'); // Look for closing `;' if (index < 0) { throw new ClassFormatException("Invalid signature: " + signature); } //corrected concurrent private static field acess wrap(consumed_chars, index + 1); // "Lblabla;" `L' and `;' are removed return compactClassName(signature.substring(1, index), chopit); } case 'S': return "short"; case 'Z': return "boolean"; case '[': { // Array declaration int n; StringBuilder brackets; String type; int consumed_chars; // Shadows global var brackets = new StringBuilder(); // Accumulate []'s // Count opening brackets and look for optional size argument for (n = 0; signature.charAt(n) == '['; n++) { brackets.append("[]"); } consumed_chars = n; // Remember value // The rest of the string denotes a `' type = signatureToString(signature.substring(n), chopit); //corrected concurrent private static field acess //Utility.consumed_chars += consumed_chars; is replaced by: int _temp = unwrap(Utility.consumed_chars) + consumed_chars; wrap(Utility.consumed_chars, _temp); return type + brackets.toString(); } case 'V': return "void"; default: throw new ClassFormatException("Invalid signature: `" + signature + "'"); } } catch (StringIndexOutOfBoundsException e) { // Should never occur throw new ClassFormatException("Invalid signature: " + signature, e); } } /** * Convert (signed) byte to (unsigned) short value, i.e., all negative * values become positive. */ private static final short byteToShort( byte b ) { return (b < 0) ? (short) (256 + b) : (short) b; } /** Convert bytes into hexadecimal string * * @param bytes an array of bytes to convert to hexadecimal * * @return bytes as hexadecimal string, e.g. 00 FA 12 ... */ public static final String toHexString( byte[] bytes ) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { short b = byteToShort(bytes[i]); String hex = Integer.toString(b, 0x10); if (b < 0x10) { buf.append('0'); } buf.append(hex); if (i < bytes.length - 1) { buf.append(' '); } } return buf.toString(); } /** * Fillup char with up to length characters with char `fill' and justify it left or right. * * @param str string to format * @param length length of desired string * @param left_justify format left or right * @param fill fill character * @return formatted string */ public static final String fillup( String str, int length, boolean left_justify, char fill ) { int len = length - str.length(); char[] buf = new char[(len < 0) ? 0 : len]; for (int j = 0; j < buf.length; j++) { buf[j] = fill; } if (left_justify) { return str + new String(buf); } return new String(buf) + str; } // A-Z, g-z, _, $ private static final int FREE_CHARS = 48; static int[] CHAR_MAP = new int[FREE_CHARS]; static int[] MAP_CHAR = new int[256]; // Reverse map static { int j = 0; for (int i = 'A'; i <= 'Z'; i++) { CHAR_MAP[j] = i; MAP_CHAR[i] = j; j++; } for (int i = 'g'; i <= 'z'; i++) { CHAR_MAP[j] = i; MAP_CHAR[i] = j; j++; } CHAR_MAP[j] = '$'; MAP_CHAR['$'] = j; j++; CHAR_MAP[j] = '_'; MAP_CHAR['_'] = j; } /** * Escape all occurences of newline chars '\n', quotes \", etc. */ public static final String convertString( String label ) { char[] ch = label.toCharArray(); StringBuilder buf = new StringBuilder(); for (int i = 0; i < ch.length; i++) { switch (ch[i]) { case '\n': buf.append("\\n"); break; case '\r': buf.append("\\r"); break; case '\"': buf.append("\\\""); break; case '\'': buf.append("\\'"); break; case '\\': buf.append("\\\\"); break; default: buf.append(ch[i]); break; } } return buf.toString(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java0000644000175100017510000000402112271445223027000 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a Double object. * * @author M. Dahm * @see Constant */ public final class ConstantDouble extends Constant { private static final long serialVersionUID = 3450743772468544760L; private double bytes; /** * @param bytes Data */ public ConstantDouble(double bytes) { super(Constants.CONSTANT_Double); this.bytes = bytes; } /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantDouble(DataInput file) throws IOException { this(file.readDouble()); } /** * @return data, i.e., 8 bytes. */ public final double getBytes() { return bytes; } /** * @return String representation. */ @Override public final String toString() { return super.toString() + "(bytes = " + bytes + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/StackMapTable.java0000644000175100017510000000736112271445223026541 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a stack map attribute used for * preverification of Java classes for the Java 2 Micro Edition * (J2ME). This attribute is used by the KVM and contained * within the Code attribute of a method. See CLDC specification * §5.3.1.2 * * @author M. Dahm * @see Code * @see StackMapEntry * @see StackMapType */ public final class StackMapTable extends Attribute { private static final long serialVersionUID = -2931695092763099621L; private int map_length; private StackMapTableEntry[] map; // Table of stack map entries /* * @param name_index Index of name * @param length Content length in bytes * @param map Table of stack map entries * @param constant_pool Array of constants */ public StackMapTable(int name_index, int length, StackMapTableEntry[] map, ConstantPool constant_pool) { super(Constants.ATTR_STACK_MAP_TABLE, name_index, length, constant_pool); setStackMapTable(map); } /** * Construct object from file stream. * @param name_index Index of name * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ StackMapTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (StackMapTableEntry[]) null, constant_pool); map_length = file.readUnsignedShort(); map = new StackMapTableEntry[map_length]; for (int i = 0; i < map_length; i++) { map[i] = new StackMapTableEntry(file, constant_pool); } } /** * @param map Array of stack map entries */ public final void setStackMapTable( StackMapTableEntry[] map ) { this.map = map; map_length = (map == null) ? 0 : map.length; } /** * @return String representation. */ @Override public final String toString() { StringBuilder buf = new StringBuilder("StackMapTable("); for (int i = 0; i < map_length; i++) { buf.append(map[i].toString()); if (i < map_length - 1) { buf.append(", "); } } buf.append(')'); return buf.toString(); } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { StackMapTable c = (StackMapTable) clone(); c.map = new StackMapTableEntry[map_length]; for (int i = 0; i < map_length; i++) { c.map[i] = map[i].copy(); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Constant.java0000644000175100017510000001253512271445223025656 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import java.io.Serializable; import org.apache.tomcat.util.bcel.Constants; import org.apache.tomcat.util.bcel.util.BCELComparator; /** * Abstract superclass for classes to represent the different constant types * in the constant pool of a class file. The classes keep closely to * the JVM specification. * * @author M. Dahm */ public abstract class Constant implements Cloneable, Serializable { private static final long serialVersionUID = 2827409182154809454L; private static BCELComparator _cmp = new BCELComparator() { @Override public boolean equals( Object o1, Object o2 ) { Constant THIS = (Constant) o1; Constant THAT = (Constant) o2; return THIS.toString().equals(THAT.toString()); } @Override public int hashCode( Object o ) { Constant THIS = (Constant) o; return THIS.toString().hashCode(); } }; /* In fact this tag is redundant since we can distinguish different * `Constant' objects by their type, i.e., via `instanceof'. In some * places we will use the tag for switch()es anyway. * * First, we want match the specification as closely as possible. Second we * need the tag as an index to select the corresponding class name from the * `CONSTANT_NAMES' array. */ protected byte tag; Constant(byte tag) { this.tag = tag; } /** * @return Tag of constant, i.e., its type. No setTag() method to avoid * confusion. */ public final byte getTag() { return tag; } /** * @return String representation. */ @Override public String toString() { return Constants.CONSTANT_NAMES[tag] + "[" + tag + "]"; } @Override public Constant clone() { try { return (Constant) super.clone(); } catch (CloneNotSupportedException e) { throw new Error("Clone Not Supported"); // never happens } } /** * Read one constant from the given file, the type depends on a tag byte. * * @param file Input stream * @return Constant object */ static final Constant readConstant( DataInputStream file ) throws IOException, ClassFormatException { byte b = file.readByte(); // Read tag byte switch (b) { case Constants.CONSTANT_Class: return new ConstantClass(file); case Constants.CONSTANT_Fieldref: return new ConstantFieldref(file); case Constants.CONSTANT_Methodref: return new ConstantMethodref(file); case Constants.CONSTANT_InterfaceMethodref: return new ConstantInterfaceMethodref(file); case Constants.CONSTANT_String: return new ConstantString(file); case Constants.CONSTANT_Integer: return new ConstantInteger(file); case Constants.CONSTANT_Float: return new ConstantFloat(file); case Constants.CONSTANT_Long: return new ConstantLong(file); case Constants.CONSTANT_Double: return new ConstantDouble(file); case Constants.CONSTANT_NameAndType: return new ConstantNameAndType(file); case Constants.CONSTANT_Utf8: return ConstantUtf8.getInstance(file); case Constants.CONSTANT_MethodHandle: return new ConstantMethodHandle(file); case Constants.CONSTANT_MethodType: return new ConstantMethodType(file); case Constants.CONSTANT_InvokeDynamic: return new ConstantInvokeDynamic(file); default: throw new ClassFormatException("Invalid byte tag in constant pool: " + b); } } /** * Return value as defined by given BCELComparator strategy. * By default two Constant objects are said to be equal when * the result of toString() is equal. * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals( Object obj ) { return _cmp.equals(this, obj); } /** * Return value as defined by given BCELComparator strategy. * By default return the hashcode of the result of toString(). * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return _cmp.hashCode(this); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/StackMapType.java0000644000175100017510000000771012271445223026431 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; import org.apache.tomcat.util.bcel.Constants; /** * This class represents the type of a local variable or item on stack * used in the StackMap entries. * * @author M. Dahm * @see StackMapEntry * @see StackMap * @see Constants */ public final class StackMapType implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private byte type; private int index = -1; // Index to CONSTANT_Class or offset private ConstantPool constant_pool; /** * Construct object from file stream. * @param file Input stream * @throws IOException */ StackMapType(DataInput file, ConstantPool constant_pool) throws IOException { this(file.readByte(), -1, constant_pool); if (hasIndex()) { setIndex(file.readShort()); } setConstantPool(constant_pool); } /** * @param type type tag as defined in the Constants interface * @param index index to constant pool, or byte code offset */ public StackMapType(byte type, int index, ConstantPool constant_pool) { setType(type); setIndex(index); setConstantPool(constant_pool); } public void setType( byte t ) { if ((t < Constants.ITEM_Bogus) || (t > Constants.ITEM_NewObject)) { throw new RuntimeException("Illegal type for StackMapType: " + t); } type = t; } public void setIndex( int t ) { index = t; } /** @return index to constant pool if type == ITEM_Object, or offset * in byte code, if type == ITEM_NewObject, and -1 otherwise */ public int getIndex() { return index; } /** * Dump type entries to file. * * @param file Output file stream * @throws IOException */ public final void dump( DataOutputStream file ) throws IOException { file.writeByte(type); if (hasIndex()) { file.writeShort(getIndex()); } } /** @return true, if type is either ITEM_Object or ITEM_NewObject */ public final boolean hasIndex() { return ((type == Constants.ITEM_Object) || (type == Constants.ITEM_NewObject)); } private String printIndex() { if (type == Constants.ITEM_Object) { if (index < 0) { return ", class="; } return ", class=" + constant_pool.constantToString(index, Constants.CONSTANT_Class); } else if (type == Constants.ITEM_NewObject) { return ", offset=" + index; } else { return ""; } } /** * @return String representation */ @Override public final String toString() { return "(type=" + Constants.ITEM_NAMES[type] + printIndex() + ")"; } /** * @param constant_pool Constant pool to be used for this object. */ public final void setConstantPool( ConstantPool constant_pool ) { this.constant_pool = constant_pool; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/SourceFile.java0000644000175100017510000000670312271445223026125 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from Attribute and represents a reference * to the source file of this class. At most one SourceFile attribute * should appear per classfile. The intention of this class is that it is * instantiated from the Attribute.readAttribute() method. * * @author M. Dahm * @see Attribute */ public final class SourceFile extends Attribute { private static final long serialVersionUID = 332346699609443704L; private int sourcefile_index; /** * Construct object from file stream. * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ SourceFile(int name_index, int length, DataInput file, ConstantPool constant_pool) throws IOException { this(name_index, length, file.readUnsignedShort(), constant_pool); } /** * @param name_index Index in constant pool to CONSTANT_Utf8, which * should represent the string "SourceFile". * @param length Content length in bytes, the value should be 2. * @param constant_pool The constant pool that this attribute is * associated with. * @param sourcefile_index Index in constant pool to CONSTANT_Utf8. This * string will be interpreted as the name of the file from which this * class was compiled. It will not be interpreted as indicating the name * of the directory contqining the file or an absolute path; this * information has to be supplied the consumer of this attribute - in * many cases, the JVM. */ public SourceFile(int name_index, int length, int sourcefile_index, ConstantPool constant_pool) { super(Constants.ATTR_SOURCE_FILE, name_index, length, constant_pool); this.sourcefile_index = sourcefile_index; } /** * @return Source file name. */ public final String getSourceFileName() { ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(sourcefile_index, Constants.CONSTANT_Utf8); return c.getBytes(); } /** * @return String representation */ @Override public final String toString() { return "SourceFile(" + getSourceFileName() + ")"; } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { return (SourceFile) clone(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/LineNumber.java0000644000175100017510000000530612271445223026123 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.DataOutputStream; import java.io.IOException; import java.io.Serializable; /** * This class represents a (PC offset, line number) pair, i.e., a line number in * the source that corresponds to a relative address in the byte code. This * is used for debugging purposes. * * @author M. Dahm * @see LineNumberTable */ public final class LineNumber implements Cloneable, Serializable { private static final long serialVersionUID = 3393830630264494355L; private int start_pc; // Program Counter (PC) corresponds to line private int line_number; // number in source file /** * Construct object from file stream. * @param file Input stream * @throws IOException */ LineNumber(DataInput file) throws IOException { this(file.readUnsignedShort(), file.readUnsignedShort()); } /** * @param start_pc Program Counter (PC) corresponds to * @param line_number line number in source file */ public LineNumber(int start_pc, int line_number) { this.start_pc = start_pc; this.line_number = line_number; } /** * Dump line number/pc pair to file stream in binary format. * * @param file Output file stream * @throws IOException */ public final void dump( DataOutputStream file ) throws IOException { file.writeShort(start_pc); file.writeShort(line_number); } /** * @return String representation */ @Override public final String toString() { return "LineNumber(" + start_pc + ", " + line_number + ")"; } /** * @return deep copy of this object */ public LineNumber copy() { try { return (LineNumber) clone(); } catch (CloneNotSupportedException e) { } return null; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Unknown.java0000644000175100017510000001024412271445223025517 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a reference to an unknown (i.e., * application-specific) attribute of a class. It is instantiated from the * Attribute.readAttribute() method. Applications that need to * read in application-specific attributes should create an AttributeReader implementation and * attach it via Attribute.addAttributeReader. * * @see org.apache.tomcat.util.bcel.classfile.Attribute * @see org.apache.tomcat.util.bcel.classfile.AttributeReader * @author M. Dahm */ public final class Unknown extends Attribute { private static final long serialVersionUID = -4152422704743201314L; private byte[] bytes; private String name; private static final Map unknown_attributes = new HashMap(); /** * Create a non-standard attribute. * * @param name_index Index in constant pool * @param length Content length in bytes * @param bytes Attribute contents * @param constant_pool Array of constants */ public Unknown(int name_index, int length, byte[] bytes, ConstantPool constant_pool) { super(Constants.ATTR_UNKNOWN, name_index, length, constant_pool); this.bytes = bytes; name = ((ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8)) .getBytes(); unknown_attributes.put(name, this); } /** * Construct object from file stream. * @param name_index Index in constant pool * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ Unknown(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (byte[]) null, constant_pool); if (length > 0) { bytes = new byte[length]; file.readFully(bytes); } } /** * @return name of attribute. */ @Override public final String getName() { return name; } /** * @return String representation. */ @Override public final String toString() { if (length == 0 || bytes == null) { return "(Unknown attribute " + name + ")"; } String hex; if (length > 10) { byte[] tmp = new byte[10]; System.arraycopy(bytes, 0, tmp, 0, 10); hex = Utility.toHexString(tmp) + "... (truncated)"; } else { hex = Utility.toHexString(bytes); } return "(Unknown attribute " + name + ": " + hex + ")"; } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { Unknown c = (Unknown) clone(); if (bytes != null) { c.bytes = new byte[bytes.length]; System.arraycopy(bytes, 0, c.bytes, 0, bytes.length); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantInterfaceMethodref.java0000644000175100017510000000276412271445223031340 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class represents a constant pool reference to an interface method. * * @author M. Dahm */ public final class ConstantInterfaceMethodref extends ConstantCP { private static final long serialVersionUID = -8587605570227841891L; /** * Initialize instance from file data. * * @param file input stream * @throws IOException */ ConstantInterfaceMethodref(DataInputStream file) throws IOException { super(Constants.CONSTANT_InterfaceMethodref, file); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/Deprecated.java0000644000175100017510000000572112271445223026124 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from Attribute and denotes that this is a * deprecated method. * It is instantiated from the Attribute.readAttribute() method. * * @author M. Dahm * @see Attribute */ public final class Deprecated extends Attribute { private static final long serialVersionUID = 8499975360019639912L; private byte[] bytes; /** * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param bytes Attribute contents * @param constant_pool Array of constants */ public Deprecated(int name_index, int length, byte[] bytes, ConstantPool constant_pool) { super(Constants.ATTR_DEPRECATED, name_index, length, constant_pool); this.bytes = bytes; } /** * Construct object from file stream. * @param name_index Index in constant pool to CONSTANT_Utf8 * @param length Content length in bytes * @param file Input stream * @param constant_pool Array of constants * @throws IOException */ Deprecated(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { this(name_index, length, (byte[]) null, constant_pool); if (length > 0) { bytes = new byte[length]; file.readFully(bytes); System.err.println("Deprecated attribute with length > 0"); } } /** * @return attribute name */ @Override public final String toString() { return Constants.ATTRIBUTE_NAMES[Constants.ATTR_DEPRECATED]; } /** * @return deep copy of this attribute */ @Override public Attribute copy( ConstantPool _constant_pool ) { Deprecated c = (Deprecated) clone(); if (bytes != null) { c.bytes = new byte[bytes.length]; System.arraycopy(bytes, 0, c.bytes, 0, bytes.length); } c.constant_pool = _constant_pool; return c; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ClassElementValue.java0000644000175100017510000000325612271445223027441 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataOutputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; public class ClassElementValue extends ElementValue { // For primitive types and string type, this points to the value entry in // the cpool // For 'class' this points to the class entry in the cpool private int idx; public ClassElementValue(int type, int idx, ConstantPool cpool) { super(type, cpool); this.idx = idx; } @Override public String stringifyValue() { ConstantUtf8 cu8 = (ConstantUtf8) cpool.getConstant(idx, Constants.CONSTANT_Utf8); return cu8.getBytes(); } @Override public void dump(DataOutputStream dos) throws IOException { dos.writeByte(type); // u1 kind of value dos.writeShort(idx); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java0000644000175100017510000000430312271445223026636 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataInput; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; /** * This class is derived from the abstract * Constant class * and represents a reference to a (external) class. * * @author M. Dahm * @see Constant */ public final class ConstantClass extends Constant { private static final long serialVersionUID = -6603658849582876642L; private int name_index; // Identical to ConstantString except for the name /** * Initialize instance from file data. * * @param file Input stream * @throws IOException */ ConstantClass(DataInput file) throws IOException { this(file.readUnsignedShort()); } /** * @param name_index Name index in constant pool. Should refer to a * ConstantUtf8. */ public ConstantClass(int name_index) { super(Constants.CONSTANT_Class); this.name_index = name_index; } /** * @return Name index in constant pool of class name. */ public final int getNameIndex() { return name_index; } /** * @return String representation. */ @Override public final String toString() { return super.toString() + "(name_index = " + name_index + ")"; } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/classfile/EnumElementValue.java0000644000175100017510000000370112271445223027273 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.classfile; import java.io.DataOutputStream; import java.io.IOException; import org.apache.tomcat.util.bcel.Constants; public class EnumElementValue extends ElementValue { // For enum types, these two indices point to the type and value private int typeIdx; private int valueIdx; public EnumElementValue(int type, int typeIdx, int valueIdx, ConstantPool cpool) { super(type, cpool); if (type != ENUM_CONSTANT) throw new RuntimeException( "Only element values of type enum can be built with this ctor - type specified: " + type); this.typeIdx = typeIdx; this.valueIdx = valueIdx; } @Override public void dump(DataOutputStream dos) throws IOException { dos.writeByte(type); // u1 type of value (ENUM_CONSTANT == 'e') dos.writeShort(typeIdx); // u2 dos.writeShort(valueIdx); // u2 } @Override public String stringifyValue() { ConstantUtf8 cu8 = (ConstantUtf8) cpool.getConstant(valueIdx, Constants.CONSTANT_Utf8); return cu8.getBytes(); } } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/package.html0000644000175100017510000000221012271445223023523 0ustar locutuslocutus

    This package contains basic classes for the Byte Code Engineering Library and constants defined by the JVM specification.

    tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/Constants.java0000644000175100017510000007733212271445223024102 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel; /** * Constants for the project, mostly defined in the JVM specification. * * @author M. Dahm */ public interface Constants { /** One of the access flags for fields, methods, or classes. */ public static final short ACC_FINAL = 0x0010; /** One of the access flags for fields, methods, or classes. */ public static final short ACC_INTERFACE = 0x0200; /** One of the access flags for fields, methods, or classes. */ public static final short ACC_ABSTRACT = 0x0400; /** One of the access flags for fields, methods, or classes. */ public static final short ACC_ANNOTATION = 0x2000; /** One of the access flags for fields, methods, or classes. */ public static final short ACC_ENUM = 0x4000; // Applies to classes compiled by new compilers only /** One of the access flags for fields, methods, or classes. */ public static final short ACC_SUPER = 0x0020; /** One of the access flags for fields, methods, or classes. */ public static final short MAX_ACC_FLAG = ACC_ENUM; /** The names of the access flags. */ public static final String[] ACCESS_NAMES = { "public", "private", "protected", "static", "final", "synchronized", "volatile", "transient", "native", "interface", "abstract", "strictfp", "synthetic", "annotation", "enum" }; /** Marks a constant pool entry as type UTF-8. */ public static final byte CONSTANT_Utf8 = 1; /** Marks a constant pool entry as type Integer. */ public static final byte CONSTANT_Integer = 3; /** Marks a constant pool entry as type Float. */ public static final byte CONSTANT_Float = 4; /** Marks a constant pool entry as type Long. */ public static final byte CONSTANT_Long = 5; /** Marks a constant pool entry as type Double. */ public static final byte CONSTANT_Double = 6; /** Marks a constant pool entry as a Class. */ public static final byte CONSTANT_Class = 7; /** Marks a constant pool entry as a Field Reference. */ public static final byte CONSTANT_Fieldref = 9; /** Marks a constant pool entry as type String. */ public static final byte CONSTANT_String = 8; /** Marks a constant pool entry as a Method Reference. */ public static final byte CONSTANT_Methodref = 10; /** Marks a constant pool entry as an Interface Method Reference. */ public static final byte CONSTANT_InterfaceMethodref = 11; /** Marks a constant pool entry as a name and type. */ public static final byte CONSTANT_NameAndType = 12; /** Marks a constant pool entry as a Method Handle. */ public static final byte CONSTANT_MethodHandle = 15; /** Marks a constant pool entry as a Method Type. */ public static final byte CONSTANT_MethodType = 16; /** Marks a constant pool entry as an Invoke Dynamic */ public static final byte CONSTANT_InvokeDynamic = 18; /** The names of the types of entries in a constant pool. */ public static final String[] CONSTANT_NAMES = { "", "CONSTANT_Utf8", "", "CONSTANT_Integer", "CONSTANT_Float", "CONSTANT_Long", "CONSTANT_Double", "CONSTANT_Class", "CONSTANT_String", "CONSTANT_Fieldref", "CONSTANT_Methodref", "CONSTANT_InterfaceMethodref", "CONSTANT_NameAndType", "", "", "CONSTANT_MethodHandle", "CONSTANT_MethodType", "", "CONSTANT_InvokeDynamic" }; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short LDC = 18; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short LDC_W = 19; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short LDC2_W = 20; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short ILOAD = 21; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short LLOAD = 22; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short FLOAD = 23; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short DLOAD = 24; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short ALOAD = 25; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short ISTORE = 54; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short LSTORE = 55; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short FSTORE = 56; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short DSTORE = 57; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short ASTORE = 58; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IINC = 132; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFEQ = 153; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFNE = 154; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFLT = 155; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFGE = 156; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFGT = 157; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFLE = 158; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPEQ = 159; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPNE = 160; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPLT = 161; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPGE = 162; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPGT = 163; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ICMPLE = 164; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ACMPEQ = 165; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IF_ACMPNE = 166; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short GOTO = 167; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short JSR = 168; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short RET = 169; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short TABLESWITCH = 170; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short LOOKUPSWITCH = 171; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short GETSTATIC = 178; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short PUTSTATIC = 179; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short GETFIELD = 180; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short PUTFIELD = 181; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short INVOKEVIRTUAL = 182; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short INVOKESPECIAL = 183; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short INVOKESTATIC = 184; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short INVOKEINTERFACE = 185; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short NEW = 187; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short NEWARRAY = 188; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short ANEWARRAY = 189; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short CHECKCAST = 192; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short INSTANCEOF = 193; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short WIDE = 196; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short MULTIANEWARRAY = 197; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFNULL = 198; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short IFNONNULL = 199; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short GOTO_W = 200; /** Java VM opcode. * @see Opcode definitions in The Java Virtual Machine Specification */ public static final short JSR_W = 201; /** Illegal opcode. */ public static final short UNDEFINED = -1; /** Illegal opcode. */ public static final short UNPREDICTABLE = -2; /** Illegal opcode. */ public static final short RESERVED = -3; /** Mnemonic for an illegal opcode. */ public static final String ILLEGAL_OPCODE = ""; /** Mnemonic for an illegal type. */ public static final String ILLEGAL_TYPE = ""; /** Byte data type. */ public static final byte T_BYTE = 8; /** Short data type. */ public static final byte T_SHORT = 9; /** Int data type. */ public static final byte T_INT = 10; /** Unknown data type. */ public static final byte T_UNKNOWN = 15; /** The primitive type names corresponding to the T_XX constants, * e.g., TYPE_NAMES[T_INT] = "int" */ public static final String[] TYPE_NAMES = { ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, "boolean", "char", "float", "double", "byte", "short", "int", "long", "void", "array", "object", "unknown", "address" }; /** * Number of byte code operands for each opcode, i.e., number of bytes after the tag byte * itself. Indexed by opcode, so NO_OF_OPERANDS[BIPUSH] = the number of operands for a bipush * instruction. */ public static final short[] NO_OF_OPERANDS = { 0/*nop*/, 0/*aconst_null*/, 0/*iconst_m1*/, 0/*iconst_0*/, 0/*iconst_1*/, 0/*iconst_2*/, 0/*iconst_3*/, 0/*iconst_4*/, 0/*iconst_5*/, 0/*lconst_0*/, 0/*lconst_1*/, 0/*fconst_0*/, 0/*fconst_1*/, 0/*fconst_2*/, 0/*dconst_0*/, 0/*dconst_1*/, 1/*bipush*/, 2/*sipush*/, 1/*ldc*/, 2/*ldc_w*/, 2/*ldc2_w*/, 1/*iload*/, 1/*lload*/, 1/*fload*/, 1/*dload*/, 1/*aload*/, 0/*iload_0*/, 0/*iload_1*/, 0/*iload_2*/, 0/*iload_3*/, 0/*lload_0*/, 0/*lload_1*/, 0/*lload_2*/, 0/*lload_3*/, 0/*fload_0*/, 0/*fload_1*/, 0/*fload_2*/, 0/*fload_3*/, 0/*dload_0*/, 0/*dload_1*/, 0/*dload_2*/, 0/*dload_3*/, 0/*aload_0*/, 0/*aload_1*/, 0/*aload_2*/, 0/*aload_3*/, 0/*iaload*/, 0/*laload*/, 0/*faload*/, 0/*daload*/, 0/*aaload*/, 0/*baload*/, 0/*caload*/, 0/*saload*/, 1/*istore*/, 1/*lstore*/, 1/*fstore*/, 1/*dstore*/, 1/*astore*/, 0/*istore_0*/, 0/*istore_1*/, 0/*istore_2*/, 0/*istore_3*/, 0/*lstore_0*/, 0/*lstore_1*/, 0/*lstore_2*/, 0/*lstore_3*/, 0/*fstore_0*/, 0/*fstore_1*/, 0/*fstore_2*/, 0/*fstore_3*/, 0/*dstore_0*/, 0/*dstore_1*/, 0/*dstore_2*/, 0/*dstore_3*/, 0/*astore_0*/, 0/*astore_1*/, 0/*astore_2*/, 0/*astore_3*/, 0/*iastore*/, 0/*lastore*/, 0/*fastore*/, 0/*dastore*/, 0/*aastore*/, 0/*bastore*/, 0/*castore*/, 0/*sastore*/, 0/*pop*/, 0/*pop2*/, 0/*dup*/, 0/*dup_x1*/, 0/*dup_x2*/, 0/*dup2*/, 0/*dup2_x1*/, 0/*dup2_x2*/, 0/*swap*/, 0/*iadd*/, 0/*ladd*/, 0/*fadd*/, 0/*dadd*/, 0/*isub*/, 0/*lsub*/, 0/*fsub*/, 0/*dsub*/, 0/*imul*/, 0/*lmul*/, 0/*fmul*/, 0/*dmul*/, 0/*idiv*/, 0/*ldiv*/, 0/*fdiv*/, 0/*ddiv*/, 0/*irem*/, 0/*lrem*/, 0/*frem*/, 0/*drem*/, 0/*ineg*/, 0/*lneg*/, 0/*fneg*/, 0/*dneg*/, 0/*ishl*/, 0/*lshl*/, 0/*ishr*/, 0/*lshr*/, 0/*iushr*/, 0/*lushr*/, 0/*iand*/, 0/*land*/, 0/*ior*/, 0/*lor*/, 0/*ixor*/, 0/*lxor*/, 2/*iinc*/, 0/*i2l*/, 0/*i2f*/, 0/*i2d*/, 0/*l2i*/, 0/*l2f*/, 0/*l2d*/, 0/*f2i*/, 0/*f2l*/, 0/*f2d*/, 0/*d2i*/, 0/*d2l*/, 0/*d2f*/, 0/*i2b*/, 0/*i2c*/, 0/*i2s*/, 0/*lcmp*/, 0/*fcmpl*/, 0/*fcmpg*/, 0/*dcmpl*/, 0/*dcmpg*/, 2/*ifeq*/, 2/*ifne*/, 2/*iflt*/, 2/*ifge*/, 2/*ifgt*/, 2/*ifle*/, 2/*if_icmpeq*/, 2/*if_icmpne*/, 2/*if_icmplt*/, 2/*if_icmpge*/, 2/*if_icmpgt*/, 2/*if_icmple*/, 2/*if_acmpeq*/, 2/*if_acmpne*/, 2/*goto*/, 2/*jsr*/, 1/*ret*/, UNPREDICTABLE/*tableswitch*/, UNPREDICTABLE/*lookupswitch*/, 0/*ireturn*/, 0/*lreturn*/, 0/*freturn*/, 0/*dreturn*/, 0/*areturn*/, 0/*return*/, 2/*getstatic*/, 2/*putstatic*/, 2/*getfield*/, 2/*putfield*/, 2/*invokevirtual*/, 2/*invokespecial*/, 2/*invokestatic*/, 4/*invokeinterface*/, UNDEFINED, 2/*new*/, 1/*newarray*/, 2/*anewarray*/, 0/*arraylength*/, 0/*athrow*/, 2/*checkcast*/, 2/*instanceof*/, 0/*monitorenter*/, 0/*monitorexit*/, UNPREDICTABLE/*wide*/, 3/*multianewarray*/, 2/*ifnull*/, 2/*ifnonnull*/, 4/*goto_w*/, 4/*jsr_w*/, 0/*breakpoint*/, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, RESERVED/*impdep1*/, RESERVED/*impdep2*/ }; /** * How the byte code operands are to be interpreted for each opcode. * Indexed by opcode. TYPE_OF_OPERANDS[ILOAD] = an array of shorts * describing the data types for the instruction. */ public static final short[][] TYPE_OF_OPERANDS = { {}/*nop*/, {}/*aconst_null*/, {}/*iconst_m1*/, {}/*iconst_0*/, {}/*iconst_1*/, {}/*iconst_2*/, {}/*iconst_3*/, {}/*iconst_4*/, {}/*iconst_5*/, {}/*lconst_0*/, {}/*lconst_1*/, {}/*fconst_0*/, {}/*fconst_1*/, {}/*fconst_2*/, {}/*dconst_0*/, {}/*dconst_1*/, {T_BYTE}/*bipush*/, {T_SHORT}/*sipush*/, {T_BYTE}/*ldc*/, {T_SHORT}/*ldc_w*/, {T_SHORT}/*ldc2_w*/, {T_BYTE}/*iload*/, {T_BYTE}/*lload*/, {T_BYTE}/*fload*/, {T_BYTE}/*dload*/, {T_BYTE}/*aload*/, {}/*iload_0*/, {}/*iload_1*/, {}/*iload_2*/, {}/*iload_3*/, {}/*lload_0*/, {}/*lload_1*/, {}/*lload_2*/, {}/*lload_3*/, {}/*fload_0*/, {}/*fload_1*/, {}/*fload_2*/, {}/*fload_3*/, {}/*dload_0*/, {}/*dload_1*/, {}/*dload_2*/, {}/*dload_3*/, {}/*aload_0*/, {}/*aload_1*/, {}/*aload_2*/, {}/*aload_3*/, {}/*iaload*/, {}/*laload*/, {}/*faload*/, {}/*daload*/, {}/*aaload*/, {}/*baload*/, {}/*caload*/, {}/*saload*/, {T_BYTE}/*istore*/, {T_BYTE}/*lstore*/, {T_BYTE}/*fstore*/, {T_BYTE}/*dstore*/, {T_BYTE}/*astore*/, {}/*istore_0*/, {}/*istore_1*/, {}/*istore_2*/, {}/*istore_3*/, {}/*lstore_0*/, {}/*lstore_1*/, {}/*lstore_2*/, {}/*lstore_3*/, {}/*fstore_0*/, {}/*fstore_1*/, {}/*fstore_2*/, {}/*fstore_3*/, {}/*dstore_0*/, {}/*dstore_1*/, {}/*dstore_2*/, {}/*dstore_3*/, {}/*astore_0*/, {}/*astore_1*/, {}/*astore_2*/, {}/*astore_3*/, {}/*iastore*/, {}/*lastore*/, {}/*fastore*/, {}/*dastore*/, {}/*aastore*/, {}/*bastore*/, {}/*castore*/, {}/*sastore*/, {}/*pop*/, {}/*pop2*/, {}/*dup*/, {}/*dup_x1*/, {}/*dup_x2*/, {}/*dup2*/, {}/*dup2_x1*/, {}/*dup2_x2*/, {}/*swap*/, {}/*iadd*/, {}/*ladd*/, {}/*fadd*/, {}/*dadd*/, {}/*isub*/, {}/*lsub*/, {}/*fsub*/, {}/*dsub*/, {}/*imul*/, {}/*lmul*/, {}/*fmul*/, {}/*dmul*/, {}/*idiv*/, {}/*ldiv*/, {}/*fdiv*/, {}/*ddiv*/, {}/*irem*/, {}/*lrem*/, {}/*frem*/, {}/*drem*/, {}/*ineg*/, {}/*lneg*/, {}/*fneg*/, {}/*dneg*/, {}/*ishl*/, {}/*lshl*/, {}/*ishr*/, {}/*lshr*/, {}/*iushr*/, {}/*lushr*/, {}/*iand*/, {}/*land*/, {}/*ior*/, {}/*lor*/, {}/*ixor*/, {}/*lxor*/, {T_BYTE, T_BYTE}/*iinc*/, {}/*i2l*/, {}/*i2f*/, {}/*i2d*/, {}/*l2i*/, {}/*l2f*/, {}/*l2d*/, {}/*f2i*/, {}/*f2l*/, {}/*f2d*/, {}/*d2i*/, {}/*d2l*/, {}/*d2f*/, {}/*i2b*/, {}/*i2c*/,{}/*i2s*/, {}/*lcmp*/, {}/*fcmpl*/, {}/*fcmpg*/, {}/*dcmpl*/, {}/*dcmpg*/, {T_SHORT}/*ifeq*/, {T_SHORT}/*ifne*/, {T_SHORT}/*iflt*/, {T_SHORT}/*ifge*/, {T_SHORT}/*ifgt*/, {T_SHORT}/*ifle*/, {T_SHORT}/*if_icmpeq*/, {T_SHORT}/*if_icmpne*/, {T_SHORT}/*if_icmplt*/, {T_SHORT}/*if_icmpge*/, {T_SHORT}/*if_icmpgt*/, {T_SHORT}/*if_icmple*/, {T_SHORT}/*if_acmpeq*/, {T_SHORT}/*if_acmpne*/, {T_SHORT}/*goto*/, {T_SHORT}/*jsr*/, {T_BYTE}/*ret*/, {}/*tableswitch*/, {}/*lookupswitch*/, {}/*ireturn*/, {}/*lreturn*/, {}/*freturn*/, {}/*dreturn*/, {}/*areturn*/, {}/*return*/, {T_SHORT}/*getstatic*/, {T_SHORT}/*putstatic*/, {T_SHORT}/*getfield*/, {T_SHORT}/*putfield*/, {T_SHORT}/*invokevirtual*/, {T_SHORT}/*invokespecial*/, {T_SHORT}/*invokestatic*/, {T_SHORT, T_BYTE, T_BYTE}/*invokeinterface*/, {}, {T_SHORT}/*new*/, {T_BYTE}/*newarray*/, {T_SHORT}/*anewarray*/, {}/*arraylength*/, {}/*athrow*/, {T_SHORT}/*checkcast*/, {T_SHORT}/*instanceof*/, {}/*monitorenter*/, {}/*monitorexit*/, {T_BYTE}/*wide*/, {T_SHORT, T_BYTE}/*multianewarray*/, {T_SHORT}/*ifnull*/, {T_SHORT}/*ifnonnull*/, {T_INT}/*goto_w*/, {T_INT}/*jsr_w*/, {}/*breakpoint*/, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}/*impdep1*/, {}/*impdep2*/ }; /** * Names of opcodes. Indexed by opcode. OPCODE_NAMES[ALOAD] = "aload". */ public static final String[] OPCODE_NAMES = { "nop", "aconst_null", "iconst_m1", "iconst_0", "iconst_1", "iconst_2", "iconst_3", "iconst_4", "iconst_5", "lconst_0", "lconst_1", "fconst_0", "fconst_1", "fconst_2", "dconst_0", "dconst_1", "bipush", "sipush", "ldc", "ldc_w", "ldc2_w", "iload", "lload", "fload", "dload", "aload", "iload_0", "iload_1", "iload_2", "iload_3", "lload_0", "lload_1", "lload_2", "lload_3", "fload_0", "fload_1", "fload_2", "fload_3", "dload_0", "dload_1", "dload_2", "dload_3", "aload_0", "aload_1", "aload_2", "aload_3", "iaload", "laload", "faload", "daload", "aaload", "baload", "caload", "saload", "istore", "lstore", "fstore", "dstore", "astore", "istore_0", "istore_1", "istore_2", "istore_3", "lstore_0", "lstore_1", "lstore_2", "lstore_3", "fstore_0", "fstore_1", "fstore_2", "fstore_3", "dstore_0", "dstore_1", "dstore_2", "dstore_3", "astore_0", "astore_1", "astore_2", "astore_3", "iastore", "lastore", "fastore", "dastore", "aastore", "bastore", "castore", "sastore", "pop", "pop2", "dup", "dup_x1", "dup_x2", "dup2", "dup2_x1", "dup2_x2", "swap", "iadd", "ladd", "fadd", "dadd", "isub", "lsub", "fsub", "dsub", "imul", "lmul", "fmul", "dmul", "idiv", "ldiv", "fdiv", "ddiv", "irem", "lrem", "frem", "drem", "ineg", "lneg", "fneg", "dneg", "ishl", "lshl", "ishr", "lshr", "iushr", "lushr", "iand", "land", "ior", "lor", "ixor", "lxor", "iinc", "i2l", "i2f", "i2d", "l2i", "l2f", "l2d", "f2i", "f2l", "f2d", "d2i", "d2l", "d2f", "i2b", "i2c", "i2s", "lcmp", "fcmpl", "fcmpg", "dcmpl", "dcmpg", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", "if_icmple", "if_acmpeq", "if_acmpne", "goto", "jsr", "ret", "tableswitch", "lookupswitch", "ireturn", "lreturn", "freturn", "dreturn", "areturn", "return", "getstatic", "putstatic", "getfield", "putfield", "invokevirtual", "invokespecial", "invokestatic", "invokeinterface", ILLEGAL_OPCODE, "new", "newarray", "anewarray", "arraylength", "athrow", "checkcast", "instanceof", "monitorenter", "monitorexit", "wide", "multianewarray", "ifnull", "ifnonnull", "goto_w", "jsr_w", "breakpoint", ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, ILLEGAL_OPCODE, "impdep1", "impdep2" }; /** Attributes and their corresponding names. */ public static final byte ATTR_UNKNOWN = -1; public static final byte ATTR_SOURCE_FILE = 0; public static final byte ATTR_CONSTANT_VALUE = 1; public static final byte ATTR_CODE = 2; public static final byte ATTR_EXCEPTIONS = 3; public static final byte ATTR_LINE_NUMBER_TABLE = 4; public static final byte ATTR_LOCAL_VARIABLE_TABLE = 5; public static final byte ATTR_INNER_CLASSES = 6; public static final byte ATTR_SYNTHETIC = 7; public static final byte ATTR_DEPRECATED = 8; public static final byte ATTR_PMG = 9; public static final byte ATTR_SIGNATURE = 10; public static final byte ATTR_STACK_MAP = 11; public static final byte ATTR_RUNTIME_VISIBLE_ANNOTATIONS = 12; public static final byte ATTR_RUNTIMEIN_VISIBLE_ANNOTATIONS = 13; public static final byte ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = 14; public static final byte ATTR_RUNTIMEIN_VISIBLE_PARAMETER_ANNOTATIONS = 15; public static final byte ATTR_ANNOTATION_DEFAULT = 16; public static final byte ATTR_LOCAL_VARIABLE_TYPE_TABLE = 17; public static final byte ATTR_ENCLOSING_METHOD = 18; public static final byte ATTR_STACK_MAP_TABLE = 19; public static final short KNOWN_ATTRIBUTES = 20; // TOFO: FIXXXXX public static final String[] ATTRIBUTE_NAMES = { "SourceFile", "ConstantValue", "Code", "Exceptions", "LineNumberTable", "LocalVariableTable", "InnerClasses", "Synthetic", "Deprecated", "PMGClass", "Signature", "StackMap", "RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "AnnotationDefault", "LocalVariableTypeTable", "EnclosingMethod", "StackMapTable" }; /** Constants used in the StackMap attribute. */ public static final byte ITEM_Bogus = 0; public static final byte ITEM_Object = 7; public static final byte ITEM_NewObject = 8; public static final String[] ITEM_NAMES = { "Bogus", "Integer", "Float", "Double", "Long", "Null", "InitObject", "Object", "NewObject" }; /** Constants used to identify StackMapEntry types. * * For those types which can specify a range, the * constant names the lowest value. */ public static final int SAME_FRAME = 0; public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; public static final int CHOP_FRAME = 248; public static final int SAME_FRAME_EXTENDED = 251; public static final int APPEND_FRAME = 252; public static final int FULL_FRAME = 255; /** Constants that define the maximum value of * those constants which store ranges. */ public static final int SAME_FRAME_MAX = 63; public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_MAX = 127; public static final int CHOP_FRAME_MAX = 250; public static final int APPEND_FRAME_MAX = 254; } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/util/0000755000175100017510000000000012301126367022223 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/tomcat/util/bcel/util/package.html0000644000175100017510000000251612271445223024511 0ustar locutuslocutus

    This package contains utility classes for the Byte Code Engineering Library, namely:

    • Collection classes for JavaClass objects
    • A converter for class files to HTML
    • A tool to find instructions patterns via regular expressions
    • A class to find classes as defined in the CLASSPATH
    • A class loader that allows to create classes at run time

    tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/util/BCELComparator.java0000644000175100017510000000261012271445223025623 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.util; /** * Used for BCEL comparison strategy * * @author M. Dahm * @since 5.2 */ public interface BCELComparator { /** * Compare two objects and return what THIS.equals(THAT) should return * * @param THIS * @param THAT * @return true if and only if THIS equals THAT */ boolean equals( Object THIS, Object THAT ); /** * Return hashcode for THIS.hashCode() * * @param THIS * @return hashcode for THIS.hashCode() */ int hashCode( Object THIS ); } tomcat7-7.0.52/java/org/apache/tomcat/util/bcel/util/ByteSequence.java0000644000175100017510000000340212271445223025462 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util.bcel.util; import java.io.ByteArrayInputStream; import java.io.DataInputStream; /** * Utility class that implements a sequence of bytes which can be read * via the `readByte()' method. This is used to implement a wrapper for the * Java byte code stream to gain some more readability. * * @author M. Dahm */ public final class ByteSequence extends DataInputStream { private ByteArrayStream byte_stream; public ByteSequence(byte[] bytes) { super(new ByteArrayStream(bytes)); byte_stream = (ByteArrayStream) in; } public final int getIndex() { return byte_stream.getPosition(); } private static final class ByteArrayStream extends ByteArrayInputStream { ByteArrayStream(byte[] bytes) { super(bytes); } final int getPosition() { return pos; } // is protected in ByteArrayInputStream } } tomcat7-7.0.52/java/org/apache/tomcat/util/IntrospectionUtils.java0000644000175100017510000010601112271452644025072 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.tomcat.util; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; /** * Utils for introspection and reflection */ public final class IntrospectionUtils { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( IntrospectionUtils.class ); /** * Call execute() - any ant-like task should work * @deprecated Not used */ @Deprecated public static void execute(Object proxy, String method) throws Exception { Method executeM = null; Class c = proxy.getClass(); Class params[] = new Class[0]; // params[0]=args.getClass(); executeM = findMethod(c, method, params); if (executeM == null) { throw new RuntimeException("No execute in " + proxy.getClass()); } executeM.invoke(proxy, (Object[]) null);//new Object[] { args }); } /** * Call void setAttribute( String ,Object ) * @deprecated Not used */ @Deprecated public static void setAttribute(Object proxy, String n, Object v) throws Exception { if (proxy instanceof AttributeHolder) { ((AttributeHolder) proxy).setAttribute(n, v); return; } Method executeM = null; Class c = proxy.getClass(); Class params[] = new Class[2]; params[0] = String.class; params[1] = Object.class; executeM = findMethod(c, "setAttribute", params); if (executeM == null) { if (log.isDebugEnabled()) log.debug("No setAttribute in " + proxy.getClass()); return; } if (log.isDebugEnabled()) log.debug("Setting " + n + "=" + v + " in " + proxy); executeM.invoke(proxy, new Object[] { n, v }); return; } /** * Call void getAttribute( String ) * @deprecated Not used */ @Deprecated public static Object getAttribute(Object proxy, String n) throws Exception { Method executeM = null; Class c = proxy.getClass(); Class params[] = new Class[1]; params[0] = String.class; executeM = findMethod(c, "getAttribute", params); if (executeM == null) { if (log.isDebugEnabled()) log.debug("No getAttribute in " + proxy.getClass()); return null; } return executeM.invoke(proxy, new Object[] { n }); } /** * Construct a URLClassLoader. Will compile and work in JDK1.1 too. * @deprecated Not used */ @Deprecated public static ClassLoader getURLClassLoader(URL urls[], ClassLoader parent) { try { Class urlCL = Class.forName("java.net.URLClassLoader"); Class paramT[] = new Class[2]; paramT[0] = urls.getClass(); paramT[1] = ClassLoader.class; Method m = findMethod(urlCL, "newInstance", paramT); if (m == null) return null; ClassLoader cl = (ClassLoader) m.invoke(urlCL, new Object[] { urls, parent }); return cl; } catch (ClassNotFoundException ex) { // jdk1.1 return null; } catch (Exception ex) { ex.printStackTrace(); return null; } } /** * @deprecated No longer required. Will be removed in Tomcat 8.0.x. */ @Deprecated public static String guessInstall(String installSysProp, String homeSysProp, String jarName) { return guessInstall(installSysProp, homeSysProp, jarName, null); } /** * Guess a product install/home by analyzing the class path. It works for * product using the pattern: lib/executable.jar or if executable.jar is * included in classpath by a shell script. ( java -jar also works ) * * Insures both "install" and "home" System properties are set. If either or * both System properties are unset, "install" and "home" will be set to the * same value. This value will be the other System property that is set, or * the guessed value if neither is set. * * @deprecated No longer required. Will be removed in Tomcat 8.0.x. */ @Deprecated public static String guessInstall(String installSysProp, String homeSysProp, String jarName, String classFile) { String install = null; String home = null; if (installSysProp != null) install = System.getProperty(installSysProp); if (homeSysProp != null) home = System.getProperty(homeSysProp); if (install != null) { if (home == null) System.getProperties().put(homeSysProp, install); return install; } // Find the directory where jarName.jar is located String cpath = System.getProperty("java.class.path"); String pathSep = System.getProperty("path.separator"); StringTokenizer st = new StringTokenizer(cpath, pathSep); while (st.hasMoreTokens()) { String path = st.nextToken(); // log( "path " + path ); if (path.endsWith(jarName)) { home = path.substring(0, path.length() - jarName.length()); try { if ("".equals(home)) { home = new File("./").getCanonicalPath(); } else if (home.endsWith(File.separator)) { home = home.substring(0, home.length() - 1); } File f = new File(home); String parentDir = f.getParent(); if (parentDir == null) parentDir = home; // unix style File f1 = new File(parentDir); install = f1.getCanonicalPath(); if (installSysProp != null) System.getProperties().put(installSysProp, install); if (home == null && homeSysProp != null) System.getProperties().put(homeSysProp, install); return install; } catch (Exception ex) { ex.printStackTrace(); } } else { String fname = path + (path.endsWith("/") ? "" : "/") + classFile; if (new File(fname).exists()) { try { File f = new File(path); String parentDir = f.getParent(); if (parentDir == null) parentDir = path; // unix style File f1 = new File(parentDir); install = f1.getCanonicalPath(); if (installSysProp != null) System.getProperties().put(installSysProp, install); if (home == null && homeSysProp != null) System.getProperties().put(homeSysProp, install); return install; } catch (Exception ex) { ex.printStackTrace(); } } } } // if install directory can't be found, use home as the default if (home != null) { System.getProperties().put(installSysProp, home); return home; } return null; } /** * Debug method, display the classpath * @deprecated Not used */ @Deprecated public static void displayClassPath(String msg, URL[] cp) { if (log.isDebugEnabled()) { log.debug(msg); for (int i = 0; i < cp.length; i++) { log.debug(cp[i].getFile()); } } } /** * @deprecated Used only by deprecated method */ @Deprecated public static final String PATH_SEPARATOR = System.getProperty("path.separator"); /** * Adds classpath entries from a vector of URL's to the "tc_path_add" System * property. This System property lists the classpath entries common to web * applications. This System property is currently used by Jasper when its * JSP servlet compiles the Java file for a JSP. * @deprecated Not used */ @Deprecated public static String classPathAdd(URL urls[], String cp) { if (urls == null) return cp; for (int i = 0; i < urls.length; i++) { if (cp != null) cp += PATH_SEPARATOR + urls[i].getFile(); else cp = urls[i].getFile(); } return cp; } /** * Find a method with the right name If found, call the method ( if param is * int or boolean we'll convert value to the right type before) - that means * you can have setDebug(1). */ public static boolean setProperty(Object o, String name, String value) { return setProperty(o,name,value,true); } public static boolean setProperty(Object o, String name, String value, boolean invokeSetProperty) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: setProperty(" + o.getClass() + " " + name + "=" + value + ")"); String setter = "set" + capitalize(name); try { Method methods[] = findMethods(o.getClass()); Method setPropertyMethodVoid = null; Method setPropertyMethodBool = null; // First, the ideal case - a setFoo( String ) method for (int i = 0; i < methods.length; i++) { Class paramT[] = methods[i].getParameterTypes(); if (setter.equals(methods[i].getName()) && paramT.length == 1 && "java.lang.String".equals(paramT[0].getName())) { methods[i].invoke(o, new Object[] { value }); return true; } } // Try a setFoo ( int ) or ( boolean ) for (int i = 0; i < methods.length; i++) { boolean ok = true; if (setter.equals(methods[i].getName()) && methods[i].getParameterTypes().length == 1) { // match - find the type and invoke it Class paramType = methods[i].getParameterTypes()[0]; Object params[] = new Object[1]; // Try a setFoo ( int ) if ("java.lang.Integer".equals(paramType.getName()) || "int".equals(paramType.getName())) { try { params[0] = new Integer(value); } catch (NumberFormatException ex) { ok = false; } // Try a setFoo ( long ) }else if ("java.lang.Long".equals(paramType.getName()) || "long".equals(paramType.getName())) { try { params[0] = new Long(value); } catch (NumberFormatException ex) { ok = false; } // Try a setFoo ( boolean ) } else if ("java.lang.Boolean".equals(paramType.getName()) || "boolean".equals(paramType.getName())) { params[0] = Boolean.valueOf(value); // Try a setFoo ( InetAddress ) } else if ("java.net.InetAddress".equals(paramType .getName())) { try { params[0] = InetAddress.getByName(value); } catch (UnknownHostException exc) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Unable to resolve host name:" + value); ok = false; } // Unknown type } else { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Unknown type " + paramType.getName()); } if (ok) { methods[i].invoke(o, params); return true; } } // save "setProperty" for later if ("setProperty".equals(methods[i].getName())) { if (methods[i].getReturnType()==Boolean.TYPE){ setPropertyMethodBool = methods[i]; }else { setPropertyMethodVoid = methods[i]; } } } // Ok, no setXXX found, try a setProperty("name", "value") if (invokeSetProperty && (setPropertyMethodBool != null || setPropertyMethodVoid != null)) { Object params[] = new Object[2]; params[0] = name; params[1] = value; if (setPropertyMethodBool != null) { try { return ((Boolean) setPropertyMethodBool.invoke(o, params)).booleanValue(); }catch (IllegalArgumentException biae) { //the boolean method had the wrong //parameter types. lets try the other if (setPropertyMethodVoid!=null) { setPropertyMethodVoid.invoke(o, params); return true; }else { throw biae; } } } else { setPropertyMethodVoid.invoke(o, params); return true; } } } catch (IllegalArgumentException ex2) { log.warn("IAE " + o + " " + name + " " + value, ex2); } catch (SecurityException ex1) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: SecurityException for " + o.getClass() + " " + name + "=" + value + ")", ex1); } catch (IllegalAccessException iae) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: IllegalAccessException for " + o.getClass() + " " + name + "=" + value + ")", iae); } catch (InvocationTargetException ie) { ExceptionUtils.handleThrowable(ie.getCause()); if (log.isDebugEnabled()) log.debug("IntrospectionUtils: InvocationTargetException for " + o.getClass() + " " + name + "=" + value + ")", ie); } return false; } public static Object getProperty(Object o, String name) { String getter = "get" + capitalize(name); String isGetter = "is" + capitalize(name); try { Method methods[] = findMethods(o.getClass()); Method getPropertyMethod = null; // First, the ideal case - a getFoo() method for (int i = 0; i < methods.length; i++) { Class paramT[] = methods[i].getParameterTypes(); if (getter.equals(methods[i].getName()) && paramT.length == 0) { return methods[i].invoke(o, (Object[]) null); } if (isGetter.equals(methods[i].getName()) && paramT.length == 0) { return methods[i].invoke(o, (Object[]) null); } if ("getProperty".equals(methods[i].getName())) { getPropertyMethod = methods[i]; } } // Ok, no setXXX found, try a getProperty("name") if (getPropertyMethod != null) { Object params[] = new Object[1]; params[0] = name; return getPropertyMethod.invoke(o, params); } } catch (IllegalArgumentException ex2) { log.warn("IAE " + o + " " + name, ex2); } catch (SecurityException ex1) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: SecurityException for " + o.getClass() + " " + name + ")", ex1); } catch (IllegalAccessException iae) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: IllegalAccessException for " + o.getClass() + " " + name + ")", iae); } catch (InvocationTargetException ie) { ExceptionUtils.handleThrowable(ie.getCause()); if (log.isDebugEnabled()) log.debug("IntrospectionUtils: InvocationTargetException for " + o.getClass() + " " + name + ")"); } return null; } /** * @deprecated Not used */ @Deprecated public static void setProperty(Object o, String name) { String setter = "set" + capitalize(name); try { Method methods[] = findMethods(o.getClass()); // find setFoo() method for (int i = 0; i < methods.length; i++) { Class paramT[] = methods[i].getParameterTypes(); if (setter.equals(methods[i].getName()) && paramT.length == 0) { methods[i].invoke(o, new Object[] {}); return; } } } catch (Exception ex1) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Exception for " + o.getClass() + " " + name, ex1); } } /** * Replace ${NAME} with the property value */ public static String replaceProperties(String value, Hashtable staticProp, PropertySource dynamicProp[]) { if (value.indexOf("$") < 0) { return value; } StringBuilder sb = new StringBuilder(); int prev = 0; // assert value!=nil int pos; while ((pos = value.indexOf("$", prev)) >= 0) { if (pos > 0) { sb.append(value.substring(prev, pos)); } if (pos == (value.length() - 1)) { sb.append('$'); prev = pos + 1; } else if (value.charAt(pos + 1) != '{') { sb.append('$'); prev = pos + 1; // XXX } else { int endName = value.indexOf('}', pos); if (endName < 0) { sb.append(value.substring(pos)); prev = value.length(); continue; } String n = value.substring(pos + 2, endName); String v = null; if (staticProp != null) { v = (String) staticProp.get(n); } if (v == null && dynamicProp != null) { for (int i = 0; i < dynamicProp.length; i++) { v = dynamicProp[i].getProperty(n); if (v != null) { break; } } } if (v == null) v = "${" + n + "}"; sb.append(v); prev = endName + 1; } } if (prev < value.length()) sb.append(value.substring(prev)); return sb.toString(); } /** * Reverse of Introspector.decapitalize */ public static String capitalize(String name) { if (name == null || name.length() == 0) { return name; } char chars[] = name.toCharArray(); chars[0] = Character.toUpperCase(chars[0]); return new String(chars); } /** * @deprecated Not used */ @Deprecated public static String unCapitalize(String name) { if (name == null || name.length() == 0) { return name; } char chars[] = name.toCharArray(); chars[0] = Character.toLowerCase(chars[0]); return new String(chars); } // -------------------- Class path tools -------------------- /** * Add all the jar files in a dir to the classpath, represented as a Vector * of URLs. * @deprecated Is used only by deprecated method */ @Deprecated public static void addToClassPath(Vector cpV, String dir) { try { String cpComp[] = getFilesByExt(dir, ".jar"); if (cpComp != null) { int jarCount = cpComp.length; for (int i = 0; i < jarCount; i++) { URL url = getURL(dir, cpComp[i]); if (url != null) cpV.addElement(url); } } } catch (Exception ex) { ex.printStackTrace(); } } /** * @deprecated Is used only by deprecated method */ @Deprecated public static void addToolsJar(Vector v) { try { // Add tools.jar in any case File f = new File(System.getProperty("java.home") + "/../lib/tools.jar"); if (!f.exists()) { // On some systems java.home gets set to the root of jdk. // That's a bug, but we can work around and be nice. f = new File(System.getProperty("java.home") + "/lib/tools.jar"); if (f.exists()) { if (log.isDebugEnabled()) log.debug("Detected strange java.home value " + System.getProperty("java.home") + ", it should point to jre"); } } URL url = new URL("file", "", f.getAbsolutePath()); v.addElement(url); } catch (MalformedURLException ex) { ex.printStackTrace(); } } /** * Return all files with a given extension in a dir * @deprecated Is used only by deprecated method */ @Deprecated public static String[] getFilesByExt(String ld, String ext) { File dir = new File(ld); String[] names = null; final String lext = ext; if (dir.isDirectory()) { names = dir.list(new FilenameFilter() { @Override public boolean accept(File d, String name) { if (name.endsWith(lext)) { return true; } return false; } }); } return names; } /** * Construct a file url from a file, using a base dir * @deprecated Is used only by deprecated method */ @Deprecated public static URL getURL(String base, String file) { try { File baseF = new File(base); File f = new File(baseF, file); String path = f.getCanonicalPath(); if (f.isDirectory()) { path += "/"; } if (!f.exists()) return null; return new URL("file", "", path); } catch (Exception ex) { ex.printStackTrace(); return null; } } /** * Add elements from the classpath cp to a Vector jars as * file URLs (We use Vector for JDK 1.1 compat). *

    * * @param jars The jar list * @param cp a String classpath of directory or jar file elements * separated by path.separator delimiters. * @throws IOException If an I/O error occurs * @throws MalformedURLException Doh ;) * @deprecated Is used only by deprecated method */ @Deprecated public static void addJarsFromClassPath(Vector jars, String cp) throws IOException, MalformedURLException { String sep = System.getProperty("path.separator"); StringTokenizer st; if (cp != null) { st = new StringTokenizer(cp, sep); while (st.hasMoreTokens()) { File f = new File(st.nextToken()); String path = f.getCanonicalPath(); if (f.isDirectory()) { path += "/"; } URL url = new URL("file", "", path); if (!jars.contains(url)) { jars.addElement(url); } } } } /** * Return a URL[] that can be used to construct a class loader * @deprecated Is used only by deprecated method */ @Deprecated public static URL[] getClassPath(Vector v) { URL[] urls = new URL[v.size()]; for (int i = 0; i < v.size(); i++) { urls[i] = v.elementAt(i); } return urls; } /** * Construct a URL classpath from files in a directory, a cpath property, * and tools.jar. * @deprecated Not used */ @Deprecated public static URL[] getClassPath(String dir, String cpath, String cpathProp, boolean addTools) throws IOException, MalformedURLException { Vector jarsV = new Vector(); if (dir != null) { // Add dir/classes first, if it exists URL url = getURL(dir, "classes"); if (url != null) jarsV.addElement(url); addToClassPath(jarsV, dir); } if (cpath != null) addJarsFromClassPath(jarsV, cpath); if (cpathProp != null) { String cpath1 = System.getProperty(cpathProp); addJarsFromClassPath(jarsV, cpath1); } if (addTools) addToolsJar(jarsV); return getClassPath(jarsV); } // -------------------- other utils -------------------- public static void clear() { objectMethods.clear(); } static Hashtable,Method[]> objectMethods = new Hashtable,Method[]>(); public static Method[] findMethods(Class c) { Method methods[] = objectMethods.get(c); if (methods != null) return methods; methods = c.getMethods(); objectMethods.put(c, methods); return methods; } public static Method findMethod(Class c, String name, Class params[]) { Method methods[] = findMethods(c); if (methods == null) return null; for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(name)) { Class methodParams[] = methods[i].getParameterTypes(); if (methodParams == null) if (params == null || params.length == 0) return methods[i]; if (params == null) if (methodParams == null || methodParams.length == 0) return methods[i]; if (params.length != methodParams.length) continue; boolean found = true; for (int j = 0; j < params.length; j++) { if (params[j] != methodParams[j]) { found = false; break; } } if (found) return methods[i]; } } return null; } /** Test if the object implements a particular * method * @deprecated Not used */ @Deprecated public static boolean hasHook(Object obj, String methodN) { try { Method myMethods[] = findMethods(obj.getClass()); for (int i = 0; i < myMethods.length; i++) { if (methodN.equals(myMethods[i].getName())) { // check if it's overridden Class declaring = myMethods[i].getDeclaringClass(); Class parentOfDeclaring = declaring.getSuperclass(); // this works only if the base class doesn't extend // another class. // if the method is declared in a top level class // like BaseInterceptor parent is Object, otherwise // parent is BaseInterceptor or an intermediate class if (!"java.lang.Object".equals(parentOfDeclaring.getName())) { return true; } } } } catch (Exception ex) { ex.printStackTrace(); } return false; } /** * @deprecated Not used */ @Deprecated public static void callMain(Class c, String args[]) throws Exception { Class p[] = new Class[1]; p[0] = args.getClass(); Method m = c.getMethod("main", p); m.invoke(c, new Object[] { args }); } public static Object callMethod1(Object target, String methodN, Object param1, String typeParam1, ClassLoader cl) throws Exception { if (target == null || param1 == null) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Assert: Illegal params " + target + " " + param1); } if (log.isDebugEnabled()) log.debug("IntrospectionUtils: callMethod1 " + target.getClass().getName() + " " + param1.getClass().getName() + " " + typeParam1); Class params[] = new Class[1]; if (typeParam1 == null) params[0] = param1.getClass(); else params[0] = cl.loadClass(typeParam1); Method m = findMethod(target.getClass(), methodN, params); if (m == null) throw new NoSuchMethodException(target.getClass().getName() + " " + methodN); try { return m.invoke(target, new Object[] { param1 }); } catch (InvocationTargetException ie) { ExceptionUtils.handleThrowable(ie.getCause()); throw ie; } } /** * @deprecated Not used, though compliments callMethod1 and callMethodN here */ @Deprecated public static Object callMethod0(Object target, String methodN) throws Exception { if (target == null) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Assert: Illegal params " + target); return null; } if (log.isDebugEnabled()) log.debug("IntrospectionUtils: callMethod0 " + target.getClass().getName() + "." + methodN); Class params[] = new Class[0]; Method m = findMethod(target.getClass(), methodN, params); if (m == null) throw new NoSuchMethodException(target.getClass().getName() + " " + methodN); try { return m.invoke(target, emptyArray); } catch (InvocationTargetException ie) { ExceptionUtils.handleThrowable(ie.getCause()); throw ie; } } /** * @deprecated Used only by deprecated method */ @Deprecated private static final Object[] emptyArray = new Object[] {}; public static Object callMethodN(Object target, String methodN, Object params[], Class typeParams[]) throws Exception { Method m = null; m = findMethod(target.getClass(), methodN, typeParams); if (m == null) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Can't find method " + methodN + " in " + target + " CLASS " + target.getClass()); return null; } try { Object o = m.invoke(target, params); if (log.isDebugEnabled()) { // debug StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()).append('.') .append(methodN).append("( "); for (int i = 0; i < params.length; i++) { if (i > 0) sb.append(", "); sb.append(params[i]); } sb.append(")"); log.debug("IntrospectionUtils:" + sb.toString()); } return o; } catch (InvocationTargetException ie) { ExceptionUtils.handleThrowable(ie.getCause()); throw ie; } } public static Object convert(String object, Class paramType) { Object result = null; if ("java.lang.String".equals(paramType.getName())) { result = object; } else if ("java.lang.Integer".equals(paramType.getName()) || "int".equals(paramType.getName())) { try { result = new Integer(object); } catch (NumberFormatException ex) { } // Try a setFoo ( boolean ) } else if ("java.lang.Boolean".equals(paramType.getName()) || "boolean".equals(paramType.getName())) { result = Boolean.valueOf(object); // Try a setFoo ( InetAddress ) } else if ("java.net.InetAddress".equals(paramType .getName())) { try { result = InetAddress.getByName(object); } catch (UnknownHostException exc) { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Unable to resolve host name:" + object); } // Unknown type } else { if (log.isDebugEnabled()) log.debug("IntrospectionUtils: Unknown type " + paramType.getName()); } if (result == null) { throw new IllegalArgumentException("Can't convert argument: " + object); } return result; } // -------------------- Get property -------------------- // This provides a layer of abstraction public static interface PropertySource { public String getProperty(String key); } /** * @deprecated Is used only by deprecated method */ @Deprecated public static interface AttributeHolder { public void setAttribute(String key, Object o); } } tomcat7-7.0.52/java/org/apache/naming/0000755000175100017510000000000012301126367017346 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/naming/LocalStrings_es.properties0000644000175100017510000000351512271454623024570 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # language es # package org.apache.naming contextBindings.unknownContext = Contexto {0} desconocido contextBindings.noContextBoundToThread = No hay contexto de nombres asociado a este hilo contextBindings.noContextBoundToCL = No hay contexto de nombres asociado a este cargador de clase selectorContext.noJavaUrl = Este contexto debe de ser accedido a traves de una URL de tipo java\: selectorContext.methodUsingName = Llamada al m\u00E9todo ''{0}'' con un Nombre de ''{1}'' selectorContext.methodUsingString = Llamada al m\u00E9todo ''{0}'' con una Cadena de ''{1}'' namingContext.contextExpected = El nombre no esta asociado a ningun Contexto namingContext.failResolvingReference = Excepci\u00F3n inesperada resolviendo referencia namingContext.nameNotBound = El nombre {0} no este asociado a este contexto namingContext.readOnly = El contexto es de solo lectura namingContext.invalidName = Nombre no valido namingContext.alreadyBound = El nombre {0} este ya asociado en este Contexto namingContext.noAbsoluteName = No se puede generar un nombre absoluto para este espacio de nombres tomcat7-7.0.52/java/org/apache/naming/TransactionRef.java0000644000175100017510000000506612271454623023147 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import javax.naming.Context; import javax.naming.Reference; /** * Represents a reference address to a transaction. * * @author Remy Maucherat */ public class TransactionRef extends Reference { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants /** * Default factory for this reference. */ public static final String DEFAULT_FACTORY = org.apache.naming.factory.Constants.DEFAULT_TRANSACTION_FACTORY; // ----------------------------------------------------------- Constructors /** * Resource Reference. */ public TransactionRef() { this(null, null); } /** * Resource Reference. * * @param factory The factory class * @param factoryLocation The factory location */ public TransactionRef(String factory, String factoryLocation) { super("javax.transaction.UserTransaction", factory, factoryLocation); } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------ Reference Methods /** * Retrieves the class name of the factory of the object to which this * reference refers. */ @Override public String getFactoryClassName() { String factory = super.getFactoryClassName(); if (factory != null) { return factory; } else { factory = System.getProperty(Context.OBJECT_FACTORIES); if (factory != null) { return null; } else { return DEFAULT_FACTORY; } } } // ------------------------------------------------------------- Properties } tomcat7-7.0.52/java/org/apache/naming/EjbRef.java0000644000175100017510000000722712271454623021363 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import javax.naming.Context; import javax.naming.Reference; import javax.naming.StringRefAddr; /** * Represents a reference address to an EJB. * * @author Remy Maucherat */ public class EjbRef extends Reference { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants /** * Default factory for this reference. */ public static final String DEFAULT_FACTORY = org.apache.naming.factory.Constants.DEFAULT_EJB_FACTORY; /** * EJB type address type. */ public static final String TYPE = "type"; /** * Remote interface classname address type. */ public static final String REMOTE = "remote"; /** * Link address type. */ public static final String LINK = "link"; // ----------------------------------------------------------- Constructors /** * EJB Reference. * * @param ejbType EJB type * @param home Home interface classname * @param remote Remote interface classname * @param link EJB link */ public EjbRef(String ejbType, String home, String remote, String link) { this(ejbType, home, remote, link, null, null); } /** * EJB Reference. * * @param ejbType EJB type * @param home Home interface classname * @param remote Remote interface classname * @param link EJB link */ public EjbRef(String ejbType, String home, String remote, String link, String factory, String factoryLocation) { super(home, factory, factoryLocation); StringRefAddr refAddr = null; if (ejbType != null) { refAddr = new StringRefAddr(TYPE, ejbType); add(refAddr); } if (remote != null) { refAddr = new StringRefAddr(REMOTE, remote); add(refAddr); } if (link != null) { refAddr = new StringRefAddr(LINK, link); add(refAddr); } } // ----------------------------------------------------- Instance Variables // -------------------------------------------------------- RefAddr Methods // ------------------------------------------------------ Reference Methods /** * Retrieves the class name of the factory of the object to which this * reference refers. */ @Override public String getFactoryClassName() { String factory = super.getFactoryClassName(); if (factory != null) { return factory; } else { factory = System.getProperty(Context.OBJECT_FACTORIES); if (factory != null) { return null; } else { return DEFAULT_FACTORY; } } } // ------------------------------------------------------------- Properties } tomcat7-7.0.52/java/org/apache/naming/NamingContextEnumeration.java0000644000175100017510000000453612271454623025213 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Iterator; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.NamingException; /** * Naming enumeration implementation. * * @author Remy Maucherat */ public class NamingContextEnumeration implements NamingEnumeration { // ----------------------------------------------------------- Constructors public NamingContextEnumeration(Iterator entries) { iterator = entries; } // -------------------------------------------------------------- Variables /** * Underlying enumeration. */ protected Iterator iterator; // --------------------------------------------------------- Public Methods /** * Retrieves the next element in the enumeration. */ @Override public NameClassPair next() throws NamingException { return nextElement(); } /** * Determines whether there are any more elements in the enumeration. */ @Override public boolean hasMore() throws NamingException { return iterator.hasNext(); } /** * Closes this enumeration. */ @Override public void close() throws NamingException { } @Override public boolean hasMoreElements() { return iterator.hasNext(); } @Override public NameClassPair nextElement() { NamingEntry entry = iterator.next(); return new NameClassPair(entry.name, entry.value.getClass().getName()); } } tomcat7-7.0.52/java/org/apache/naming/resources/0000755000175100017510000000000012301126367021360 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/naming/resources/LocalStrings_es.properties0000644000175100017510000000560112271454623026600 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. fileResources.base = El Documento base {0} no existe o no es un directorio legible fileResources.listingNull = No pude obtener lista de directorio para {0} warResources.notWar = Doc base debe de apuntar a un archivo WAR warResources.invalidWar = Archivo WAR inv\u00E1lido o ilegible\: {0} jarResources.syntax = Documento base {0} debe de empezar con ''jar\:'' y acabar con ''\!/'' resources.addResourcesJarFail = No pude a\u00F1adir jar de recursos [{0}] resources.alreadyStarted = Ya han sido arrancados los Recursos resources.connect = No puedo conectar a documento base {0} resources.input = No puedo crear flujo (stream) de entrada para recurso {0} resources.invalidCache = No pude crear una cach\u00E9 de recursos de tipo [{0}] resources.notStarted = A\u00FAn no han sido arrancados los Recursos resources.null = El Documento base no puede ser nulo resources.notFound = Recurso {0} no hallado resources.path = Trayectoria relativa a contexto {0} debe de comenzar con ''/'' resources.renameFail = No pude cambiar de nombre [{0}] a [{1}] resources.alreadyBound = El Nombre {0} ya ha sido cambiado (bound) en este Contexto resources.bindFailed = Fall\u00F3 el Cambio (Bind)\: {0} resources.unbindFailed = Fall\u00F3 el Descambio (Unbind)\: {0} resources.invalidAliasPath = La ruta de alias ''{0}'' debe de comenzar con ''/'' resources.invalidAliasMapping = El mapeo de alias ''{0}'' no es v\u00E1lido resources.invalidAliasNotAllowed = La localizaci\u00F3n de alias ''{0}'' no est\u00E1 permitida resources.invalidAliasNotExist = La localizaci\u00F3n de alias ''{0}'' no existe resources.invalidAliasFile = La localizaci\u00F3n de alias ''{0}'' apunta a un fichero que no es de tipo WAR resources.invalidName = El nombre [{0}] no es v\u00E1lido standardResources.alreadyStarted = Ya han sido arrancados los Recursos standardResources.directory = El archivo base {0} no es un directorio standardResources.exists = El archivo base {0} no existe standardResources.notStarted = A\u00FAn no han sido arrancados los Recursos standardResources.null = El Documento base no puede ser nulo standardResources.slash = El Documento base {0} no debe de terminar con una barra tomcat7-7.0.52/java/org/apache/naming/resources/FileDirContext.java0000644000175100017510000010535312271454623025122 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Hashtable; import java.util.List; import javax.naming.NameAlreadyBoundException; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.OperationNotSupportedException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.naming.NamingEntry; import org.apache.tomcat.util.http.RequestUtil; /** * Filesystem Directory Context implementation helper class. * * @author Remy Maucherat */ public class FileDirContext extends BaseDirContext { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( FileDirContext.class ); // -------------------------------------------------------------- Constants /** * The descriptive information string for this implementation. */ protected static final int BUFFER_SIZE = 2048; // ----------------------------------------------------------- Constructors /** * Builds a file directory context using the given environment. */ public FileDirContext() { super(); } /** * Builds a file directory context using the given environment. */ public FileDirContext(Hashtable env) { super(env); } // ----------------------------------------------------- Instance Variables /** * The document base directory. */ protected File base = null; /** * Absolute normalized filename of the base. */ protected String absoluteBase = null; /** * Allow linking. */ protected boolean allowLinking = false; // ------------------------------------------------------------- Properties /** * Set the document root. * * @param docBase The new document root * * @exception IllegalArgumentException if the specified value is not * supported by this implementation * @exception IllegalArgumentException if this would create a * malformed URL */ @Override public void setDocBase(String docBase) { // Validate the format of the proposed document root if (docBase == null) throw new IllegalArgumentException (sm.getString("resources.null")); // Calculate a File object referencing this document base directory base = new File(docBase); try { base = base.getCanonicalFile(); } catch (IOException e) { // Ignore } // Validate that the document base is an existing directory if (!base.exists() || !base.isDirectory() || !base.canRead()) throw new IllegalArgumentException (sm.getString("fileResources.base", docBase)); this.absoluteBase = base.getAbsolutePath(); super.setDocBase(docBase); } /** * Set allow linking. */ public void setAllowLinking(boolean allowLinking) { this.allowLinking = allowLinking; } /** * Is linking allowed. */ public boolean getAllowLinking() { return allowLinking; } // --------------------------------------------------------- Public Methods /** * Release any resources allocated for this directory context. */ @Override public void release() { super.release(); } /** * Return the real path for a given virtual path, if possible; otherwise * return null. * * @param path The path to the desired resource */ @Override protected String doGetRealPath(String path) { File file = new File(getDocBase(), path); return file.getAbsolutePath(); } // -------------------------------------------------------- Context Methods /** * Retrieves the named object. * * @param name the name of the object to look up * @return the object bound to name */ @Override protected Object doLookup(String name) { Object result = null; File file = file(name); if (file == null) return null; if (file.isDirectory()) { FileDirContext tempContext = new FileDirContext(env); tempContext.setDocBase(file.getPath()); tempContext.setAllowLinking(getAllowLinking()); result = tempContext; } else { result = new FileResource(file); } return result; } /** * Unbinds the named object. Removes the terminal atomic name in name * from the target context--that named by all but the terminal atomic * part of name. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * @param name the name to bind; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(String name) throws NamingException { File file = file(name); if (file == null) throw new NameNotFoundException( sm.getString("resources.notFound", name)); if (!file.delete()) throw new NamingException (sm.getString("resources.unbindFailed", name)); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. Both names are relative to this context. Any attributes * associated with the old name become associated with the new name. * Intermediate contexts of the old name are not changed. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception NameAlreadyBoundException if newName is already bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(String oldName, String newName) throws NamingException { File file = file(oldName); if (file == null) throw new NameNotFoundException (sm.getString("resources.notFound", oldName)); File newFile = new File(base, newName); if (!file.renameTo(newFile)) { throw new NamingException(sm.getString("resources.renameFail", oldName, newName)); } } /** * Enumerates the names bound in the named context, along with the * objects bound to them. The contents of any subcontexts are not * included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override protected List doListBindings(String name) throws NamingException { File file = file(name); if (file == null) return null; return list(file); } /** * Destroys the named context and removes it from the namespace. Any * attributes associated with the name are also removed. Intermediate * contexts are not destroyed. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * In a federated naming system, a context from one naming system may be * bound to a name in another. One can subsequently look up and perform * operations on the foreign context using a composite name. However, an * attempt destroy the context using this composite name will fail with * NotContextException, because the foreign context is not a "subcontext" * of the context in which it is bound. Instead, use unbind() to remove * the binding of the foreign context. Destroying the foreign context * requires that the destroySubcontext() be performed on a context from * the foreign context's "native" naming system. * * @param name the name of the context to be destroyed; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception javax.naming.NotContextException if the name is bound but does * not name a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(String name) throws NamingException { unbind(name); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. If the object bound to name is not a * link, returns the object itself. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(String name) throws NamingException { // Note : Links are not supported return lookup(name); } /** * Retrieves the full name of this context within its own namespace. *

    * Many naming services have a notion of a "full name" for objects in * their respective namespaces. For example, an LDAP entry has a * distinguished name, and a DNS record has a fully qualified name. This * method allows the client application to retrieve this name. The string * returned by this method is not a JNDI composite name and should not be * passed directly to context methods. In naming systems for which the * notion of full name does not make sense, * OperationNotSupportedException is thrown. * * @return this context's name in its own namespace; never null * @exception OperationNotSupportedException if the naming system does * not have the notion of a full name * @exception NamingException if a naming exception is encountered */ @Override public String getNameInNamespace() throws NamingException { return docBase; } // ----------------------------------------------------- DirContext Methods /** * Retrieves selected attributes associated with a named object. * See the class description regarding attribute models, attribute type * names, and operational attributes. * * @return the requested attributes; never null * @param name the name of the object from which to retrieve attributes * @param attrIds the identifiers of the attributes to retrieve. null * indicates that all attributes should be retrieved; an empty array * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ @Override protected Attributes doGetAttributes(String name, String[] attrIds) throws NamingException { // Building attribute list File file = file(name); if (file == null) return null; return new FileResourceAttributes(file); } /** * Modifies the attributes associated with a named object. The order of * the modifications is not specified. Where possible, the modifications * are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE * @param attrs the attributes to be used for the modification; may not * be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException { throw new OperationNotSupportedException(); } /** * Modifies the attributes associated with a named object using an an * ordered list of modifications. The modifications are performed in the * order specified. Each modification specifies a modification operation * code and an attribute on which to operate. Where possible, the * modifications are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mods an ordered sequence of modifications to be performed; may * not be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException { throw new OperationNotSupportedException(); } /** * Binds a name to an object, along with associated attributes. If attrs * is null, the resulting binding will have the attributes associated * with obj if obj is a DirContext, and no attributes otherwise. If attrs * is non-null, the resulting binding will have attrs as its attributes; * any attributes associated with obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception NameAlreadyBoundException if name is already bound * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void bind(String name, Object obj, Attributes attrs) throws NamingException { // Note: No custom attributes allowed File file = new File(base, name); if (file.exists()) throw new NameAlreadyBoundException (sm.getString("resources.alreadyBound", name)); rebind(name, obj, attrs); } /** * Binds a name to an object, along with associated attributes, * overwriting any existing binding. If attrs is null and obj is a * DirContext, the attributes from obj are used. If attrs is null and obj * is not a DirContext, any existing attributes associated with the object * already bound in the directory remain unchanged. If attrs is non-null, * any existing attributes associated with the object already bound in * the directory are removed and attrs is associated with the named * object. If obj is a DirContext and attrs is non-null, the attributes * of obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj, Attributes attrs) throws NamingException { // Note: No custom attributes allowed // Check obj type File file = new File(base, name); InputStream is = null; if (obj instanceof Resource) { try { is = ((Resource) obj).streamContent(); } catch (IOException e) { // Ignore } } else if (obj instanceof InputStream) { is = (InputStream) obj; } else if (obj instanceof DirContext) { if (file.exists()) { if (!file.delete()) throw new NamingException (sm.getString("resources.bindFailed", name)); } if (!file.mkdir()) throw new NamingException (sm.getString("resources.bindFailed", name)); } if (is == null) throw new NamingException (sm.getString("resources.bindFailed", name)); // Open os try { FileOutputStream os = null; byte buffer[] = new byte[BUFFER_SIZE]; int len = -1; try { os = new FileOutputStream(file); while (true) { len = is.read(buffer); if (len == -1) break; os.write(buffer, 0, len); } } finally { if (os != null) os.close(); is.close(); } } catch (IOException e) { NamingException ne = new NamingException (sm.getString("resources.bindFailed", e)); ne.initCause(e); throw ne; } } /** * Creates and binds a new context, along with associated attributes. * This method creates a new subcontext with the given name, binds it in * the target context (that named by all but terminal atomic component of * the name), and associates the supplied attributes with the newly * created object. All intermediate and target contexts must already * exist. If attrs is null, this method is equivalent to * Context.createSubcontext(). * * @param name the name of the context to create; may not be empty * @param attrs the attributes to associate with the newly created context * @return the newly created context * @exception NameAlreadyBoundException if the name is already bound * @exception javax.naming.directory.InvalidAttributesException if attrs * does not contain all the mandatory attributes required for creation * @exception NamingException if a naming exception is encountered */ @Override public DirContext createSubcontext(String name, Attributes attrs) throws NamingException { File file = new File(base, name); if (file.exists()) throw new NameAlreadyBoundException (sm.getString("resources.alreadyBound", name)); if (!file.mkdir()) throw new NamingException (sm.getString("resources.bindFailed", name)); return (DirContext) lookup(name); } /** * Retrieves the schema associated with the named object. The schema * describes rules regarding the structure of the namespace and the * attributes stored within it. The schema specifies what types of * objects can be added to the directory and where they can be added; * what mandatory and optional attributes an object can have. The range * of support for schemas is directory-specific. * * @param name the name of the object whose schema is to be retrieved * @return the schema associated with the context; never null * @exception OperationNotSupportedException if schema not supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchema(String name) throws NamingException { throw new OperationNotSupportedException(); } /** * Retrieves a context containing the schema objects of the named * object's class definitions. * * @param name the name of the object whose object class definition is to * be retrieved * @return the DirContext containing the named object's class * definitions; never null * @exception OperationNotSupportedException if schema not supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchemaClassDefinition(String name) throws NamingException { throw new OperationNotSupportedException(); } /** * Searches in a single context for objects that contain a specified set * of attributes, and retrieves selected attributes. The search is * performed using the default SearchControls settings. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @param attributesToReturn the attributes to return. null indicates * that all attributes are to be returned; an empty array indicates that * none are to be returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { return null; } /** * Searches in a single context for objects that contain a specified set * of attributes. This method returns all the attributes of such objects. * It is equivalent to supplying null as the atributesToReturn parameter * to the method search(Name, Attributes, String[]). * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, Attributes matchingAttributes) throws NamingException { return null; } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filter the filter expression to use for the search; may not be * null * @param cons the search controls that control the search. If null, * the default search controls are used (equivalent to * (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy * the filter; never null * @exception javax.naming.directory.InvalidSearchFilterException if the * search filter specified is not supported or understood by the underlying * directory * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException { return null; } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filterExpr the filter expression to use for the search. * The expression may contain variables of the form "{i}" where i is a * nonnegative integer. May not be null. * @param filterArgs the array of arguments to substitute for the * variables in filterExpr. The value of filterArgs[i] will replace each * occurrence of "{i}". If null, equivalent to an empty array. * @param cons the search controls that control the search. If null, the * default search controls are used (equivalent to (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy the * filter; never null * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} * expressions where i is outside the bounds of the array filterArgs * @exception javax.naming.directory.InvalidSearchControlsException if cons * contains invalid settings * @exception javax.naming.directory.InvalidSearchFilterException if * filterExpr with filterArgs represents an invalid search filter * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { return null; } // ------------------------------------------------------ Protected Methods /** * Return a context-relative path, beginning with a "/", that represents * the canonical version of the specified path after ".." and "." elements * are resolved out. If the specified path attempts to go outside the * boundaries of the current context (i.e. too many ".." path elements * are present), return null instead. * * @param path Path to be normalized */ protected String normalize(String path) { return RequestUtil.normalize(path, File.separatorChar == '\\'); } /** * Return a File object representing the specified normalized * context-relative path if it exists and is readable. Otherwise, * return null. * * @param name Normalized context-relative path (with leading '/') */ protected File file(String name) { File file = new File(base, name); if (file.exists() && file.canRead()) { if (allowLinking) return file; // Check that this file belongs to our root path String canPath = null; try { canPath = file.getCanonicalPath(); } catch (IOException e) { // Ignore } if (canPath == null) return null; // Check to see if going outside of the web application root if (!canPath.startsWith(absoluteBase)) { return null; } // Case sensitivity check - this is now always done String fileAbsPath = file.getAbsolutePath(); if (fileAbsPath.endsWith(".")) fileAbsPath = fileAbsPath + "/"; String absPath = normalize(fileAbsPath); canPath = normalize(canPath); if ((absoluteBase.length() < absPath.length()) && (absoluteBase.length() < canPath.length())) { absPath = absPath.substring(absoluteBase.length() + 1); if (absPath == null) return null; if (absPath.equals("")) absPath = "/"; canPath = canPath.substring(absoluteBase.length() + 1); if (canPath.equals("")) canPath = "/"; if (!canPath.equals(absPath)) return null; } } else { return null; } return file; } /** * List the resources which are members of a collection. * * @param file Collection * @return Vector containing NamingEntry objects */ protected List list(File file) { List entries = new ArrayList(); if (!file.isDirectory()) return entries; String[] names = file.list(); if (names==null) { /* Some IO error occurred such as bad file permissions. Prevent a NPE with Arrays.sort(names) */ log.warn(sm.getString("fileResources.listingNull", file.getAbsolutePath())); return entries; } Arrays.sort(names); // Sort alphabetically NamingEntry entry = null; for (int i = 0; i < names.length; i++) { File currentFile = new File(file, names[i]); Object object = null; if (currentFile.isDirectory()) { FileDirContext tempContext = new FileDirContext(env); tempContext.setDocBase(currentFile.getPath()); tempContext.setAllowLinking(getAllowLinking()); object = tempContext; } else { object = new FileResource(currentFile); } entry = new NamingEntry(names[i], object, NamingEntry.ENTRY); entries.add(entry); } return entries; } // ----------------------------------------------- FileResource Inner Class /** * This specialized resource implementation avoids opening the InputStream * to the file right away (which would put a lock on the file). */ protected static class FileResource extends Resource { // -------------------------------------------------------- Constructor public FileResource(File file) { this.file = file; } // --------------------------------------------------- Member Variables /** * Associated file object. */ protected File file; // --------------------------------------------------- Resource Methods /** * Content accessor. * * @return InputStream */ @Override public InputStream streamContent() throws IOException { if (binaryContent == null) { FileInputStream fis = new FileInputStream(file); inputStream = fis; return fis; } return super.streamContent(); } } // ------------------------------------- FileResourceAttributes Inner Class /** * This specialized resource attribute implementation does some lazy * reading (to speed up simple checks, like checking the last modified * date). */ protected static class FileResourceAttributes extends ResourceAttributes { private static final long serialVersionUID = 1L; // -------------------------------------------------------- Constructor public FileResourceAttributes(File file) { this.file = file; getCreation(); getLastModified(); } // --------------------------------------------------- Member Variables protected File file; protected boolean accessed = false; protected String canonicalPath = null; // ----------------------------------------- ResourceAttributes Methods /** * Is collection. */ @Override public boolean isCollection() { if (!accessed) { collection = file.isDirectory(); accessed = true; } return super.isCollection(); } /** * Get content length. * * @return content length value */ @Override public long getContentLength() { if (contentLength != -1L) return contentLength; contentLength = file.length(); return contentLength; } /** * Get creation time. * * @return creation time value */ @Override public long getCreation() { if (creation != -1L) return creation; creation = getLastModified(); return creation; } /** * Get creation date. * * @return Creation date value */ @Override public Date getCreationDate() { if (creation == -1L) { creation = getCreation(); } return super.getCreationDate(); } /** * Get last modified time. * * @return lastModified time value */ @Override public long getLastModified() { if (lastModified != -1L) return lastModified; lastModified = file.lastModified(); return lastModified; } /** * Get lastModified date. * * @return LastModified date value */ @Override public Date getLastModifiedDate() { if (lastModified == -1L) { lastModified = getLastModified(); } return super.getLastModifiedDate(); } /** * Get name. * * @return Name value */ @Override public String getName() { if (name == null) name = file.getName(); return name; } /** * Get resource type. * * @return String resource type */ @Override public String getResourceType() { if (!accessed) { collection = file.isDirectory(); accessed = true; } return super.getResourceType(); } /** * Get canonical path. * * @return String the file's canonical path */ @Override public String getCanonicalPath() { if (canonicalPath == null) { try { canonicalPath = file.getCanonicalPath(); } catch (IOException e) { // Ignore } } return canonicalPath; } } } tomcat7-7.0.52/java/org/apache/naming/resources/ResourceAttributes.java0000644000175100017510000007072612271454623026102 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import java.util.Vector; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; /** * Attributes implementation. * * @author Remy Maucherat */ public class ResourceAttributes implements Attributes { // -------------------------------------------------------------- Constants private static final long serialVersionUID = 1L; // Default attribute names /** * Creation date. */ public static final String CREATION_DATE = "creationdate"; /** * Creation date. */ public static final String ALTERNATE_CREATION_DATE = "creation-date"; /** * Last modification date. */ public static final String LAST_MODIFIED = "getlastmodified"; /** * Last modification date. */ public static final String ALTERNATE_LAST_MODIFIED = "last-modified"; /** * Name. */ public static final String NAME = "displayname"; /** * Type. */ public static final String TYPE = "resourcetype"; /** * Type. */ public static final String ALTERNATE_TYPE = "content-type"; /** * MIME type of the content. */ public static final String CONTENT_TYPE = "getcontenttype"; /** * Content length. */ public static final String CONTENT_LENGTH = "getcontentlength"; /** * Content length. */ public static final String ALTERNATE_CONTENT_LENGTH = "content-length"; /** * ETag. */ public static final String ETAG = "getetag"; /** * ETag. */ public static final String ALTERNATE_ETAG = "etag"; /** * Collection type. */ public static final String COLLECTION_TYPE = ""; /** * HTTP date format. */ protected static final SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); /** * Date formats using for Date parsing. */ protected static final SimpleDateFormat formats[] = { new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) }; protected static final TimeZone gmtZone = TimeZone.getTimeZone("GMT"); /** * GMT timezone - all HTTP dates are on GMT */ static { format.setTimeZone(gmtZone); formats[0].setTimeZone(gmtZone); formats[1].setTimeZone(gmtZone); formats[2].setTimeZone(gmtZone); } // ----------------------------------------------------------- Constructors /** * Default constructor. */ public ResourceAttributes() { // NO-OP } /** * Merges with another attribute set. */ public ResourceAttributes(Attributes attributes) { this.attributes = attributes; } // ----------------------------------------------------- Instance Variables /** * Collection flag. */ protected boolean collection = false; /** * Content length. */ protected long contentLength = -1; /** * Creation time. */ protected long creation = -1; /** * Creation date. */ protected Date creationDate = null; /** * Last modified time. */ protected long lastModified = -1; /** * Last modified date. */ protected Date lastModifiedDate = null; /** * Last modified date in HTTP format. */ protected String lastModifiedHttp = null; /** * MIME type. */ protected String mimeType = null; /** * Name. */ protected String name = null; /** * Weak ETag. */ protected String weakETag = null; /** * Strong ETag. */ protected String strongETag = null; /** * External attributes. */ protected Attributes attributes = null; // ------------------------------------------------------------- Properties /** * Is collection. */ public boolean isCollection() { if (attributes != null) { return (COLLECTION_TYPE.equals(getResourceType())); } else { return (collection); } } /** * Set collection flag. * * @param collection New flag value */ public void setCollection(boolean collection) { this.collection = collection; if (attributes != null) { String value = ""; if (collection) value = COLLECTION_TYPE; attributes.put(TYPE, value); } } /** * Get content length. * * @return content length value */ public long getContentLength() { if (contentLength != -1L) return contentLength; if (attributes != null) { Attribute attribute = attributes.get(CONTENT_LENGTH); if (attribute != null) { try { Object value = attribute.get(); if (value instanceof Long) { contentLength = ((Long) value).longValue(); } else { try { contentLength = Long.parseLong(value.toString()); } catch (NumberFormatException e) { // Ignore } } } catch (NamingException e) { // No value for the attribute } } } return contentLength; } /** * Set content length. * * @param contentLength New content length value */ public void setContentLength(long contentLength) { this.contentLength = contentLength; if (attributes != null) attributes.put(CONTENT_LENGTH, Long.valueOf(contentLength)); } /** * Get creation time. * * @return creation time value */ public long getCreation() { if (creation != -1L) return creation; if (creationDate != null) return creationDate.getTime(); if (attributes != null) { Attribute attribute = attributes.get(CREATION_DATE); if (attribute != null) { try { Object value = attribute.get(); if (value instanceof Long) { creation = ((Long) value).longValue(); } else if (value instanceof Date) { creation = ((Date) value).getTime(); creationDate = (Date) value; } else { String creationDateValue = value.toString(); Date result = null; // Parsing the HTTP Date for (int i = 0; (result == null) && (i < formats.length); i++) { try { result = formats[i].parse(creationDateValue); } catch (ParseException e) { // Ignore } } if (result != null) { creation = result.getTime(); creationDate = result; } } } catch (NamingException e) { // No value for the attribute } } } return creation; } /** * Set creation. * * @param creation New creation value * @deprecated - unused */ @Deprecated public void setCreation(long creation) { this.creation = creation; this.creationDate = null; if (attributes != null) attributes.put(CREATION_DATE, new Date(creation)); } /** * Get creation date. * * @return Creation date value */ public Date getCreationDate() { if (creationDate != null) return creationDate; if (creation != -1L) { creationDate = new Date(creation); return creationDate; } if (attributes != null) { Attribute attribute = attributes.get(CREATION_DATE); if (attribute != null) { try { Object value = attribute.get(); if (value instanceof Long) { creation = ((Long) value).longValue(); creationDate = new Date(creation); } else if (value instanceof Date) { creation = ((Date) value).getTime(); creationDate = (Date) value; } else { String creationDateValue = value.toString(); Date result = null; // Parsing the HTTP Date for (int i = 0; (result == null) && (i < formats.length); i++) { try { result = formats[i].parse(creationDateValue); } catch (ParseException e) { // Ignore } } if (result != null) { creation = result.getTime(); creationDate = result; } } } catch (NamingException e) { // No value for the attribute } } } return creationDate; } /** * Creation date mutator. * * @param creationDate New creation date */ public void setCreationDate(Date creationDate) { this.creation = creationDate.getTime(); this.creationDate = creationDate; if (attributes != null) attributes.put(CREATION_DATE, creationDate); } /** * Get last modified time. * * @return lastModified time value */ public long getLastModified() { if (lastModified != -1L) return lastModified; if (lastModifiedDate != null) return lastModifiedDate.getTime(); if (attributes != null) { Attribute attribute = attributes.get(LAST_MODIFIED); if (attribute != null) { try { Object value = attribute.get(); if (value instanceof Long) { lastModified = ((Long) value).longValue(); } else if (value instanceof Date) { lastModified = ((Date) value).getTime(); lastModifiedDate = (Date) value; } else { String lastModifiedDateValue = value.toString(); Date result = null; // Parsing the HTTP Date for (int i = 0; (result == null) && (i < formats.length); i++) { try { result = formats[i].parse(lastModifiedDateValue); } catch (ParseException e) { // Ignore } } if (result != null) { lastModified = result.getTime(); lastModifiedDate = result; } } } catch (NamingException e) { // No value for the attribute } } } return lastModified; } /** * Set last modified. * * @param lastModified New last modified value */ public void setLastModified(long lastModified) { this.lastModified = lastModified; this.lastModifiedDate = null; if (attributes != null) attributes.put(LAST_MODIFIED, new Date(lastModified)); } /** * Get lastModified date. * * @return LastModified date value */ public Date getLastModifiedDate() { if (lastModifiedDate != null) return lastModifiedDate; if (lastModified != -1L) { lastModifiedDate = new Date(lastModified); return lastModifiedDate; } if (attributes != null) { Attribute attribute = attributes.get(LAST_MODIFIED); if (attribute != null) { try { Object value = attribute.get(); if (value instanceof Long) { lastModified = ((Long) value).longValue(); lastModifiedDate = new Date(lastModified); } else if (value instanceof Date) { lastModified = ((Date) value).getTime(); lastModifiedDate = (Date) value; } else { String lastModifiedDateValue = value.toString(); Date result = null; // Parsing the HTTP Date for (int i = 0; (result == null) && (i < formats.length); i++) { try { result = formats[i].parse(lastModifiedDateValue); } catch (ParseException e) { // Ignore } } if (result != null) { lastModified = result.getTime(); lastModifiedDate = result; } } } catch (NamingException e) { // No value for the attribute } } } return lastModifiedDate; } /** * Last modified date mutator. * * @param lastModifiedDate New last modified date * @deprecated - unused */ @Deprecated public void setLastModifiedDate(Date lastModifiedDate) { this.lastModified = lastModifiedDate.getTime(); this.lastModifiedDate = lastModifiedDate; if (attributes != null) attributes.put(LAST_MODIFIED, lastModifiedDate); } /** * @return Returns the lastModifiedHttp. */ public String getLastModifiedHttp() { if (lastModifiedHttp != null) return lastModifiedHttp; Date modifiedDate = getLastModifiedDate(); if (modifiedDate == null) { modifiedDate = getCreationDate(); } if (modifiedDate == null) { modifiedDate = new Date(); } synchronized (format) { lastModifiedHttp = format.format(modifiedDate); } return lastModifiedHttp; } /** * @param lastModifiedHttp The lastModifiedHttp to set. * @deprecated - unused */ @Deprecated public void setLastModifiedHttp(String lastModifiedHttp) { this.lastModifiedHttp = lastModifiedHttp; } /** * @return Returns the mimeType. */ public String getMimeType() { return mimeType; } /** * @param mimeType The mimeType to set. */ public void setMimeType(String mimeType) { this.mimeType = mimeType; } /** * Get name. * * @return Name value */ public String getName() { if (name != null) return name; if (attributes != null) { Attribute attribute = attributes.get(NAME); if (attribute != null) { try { name = attribute.get().toString(); } catch (NamingException e) { // No value for the attribute } } } return name; } /** * Set name. * * @param name New name value */ public void setName(String name) { this.name = name; if (attributes != null) attributes.put(NAME, name); } /** * Get resource type. * * @return String resource type */ public String getResourceType() { String result = null; if (attributes != null) { Attribute attribute = attributes.get(TYPE); if (attribute != null) { try { result = attribute.get().toString(); } catch (NamingException e) { // No value for the attribute } } } if (result == null) { if (collection) result = COLLECTION_TYPE; } return result; } /** * Type mutator. * * @param resourceType New resource type */ public void setResourceType(String resourceType) { collection = resourceType.equals(COLLECTION_TYPE); if (attributes != null) attributes.put(TYPE, resourceType); } /** * Get ETag. * * @return strong ETag if available, else weak ETag. */ public String getETag() { String result = null; if (attributes != null) { Attribute attribute = attributes.get(ETAG); if (attribute != null) { try { result = attribute.get().toString(); } catch (NamingException e) { // No value for the attribute } } } if (result == null) { if (strongETag != null) { // The strong ETag must always be calculated by the resources result = strongETag; } else { // The weakETag is contentLength + lastModified if (weakETag == null) { long contentLength = getContentLength(); long lastModified = getLastModified(); if ((contentLength >= 0) || (lastModified >= 0)) { weakETag = "W/\"" + contentLength + "-" + lastModified + "\""; } } result = weakETag; } } return result; } /** * Set strong ETag. */ public void setETag(String eTag) { this.strongETag = eTag; if (attributes != null) attributes.put(ETAG, eTag); } /** * Return the canonical path of the resource, to possibly be used for * direct file serving. Implementations which support this should override * it to return the file path. * * @return The canonical path of the resource */ public String getCanonicalPath() { return null; } // ----------------------------------------------------- Attributes Methods /** * Get attribute. */ @Override public Attribute get(String attrID) { if (attributes == null) { if (attrID.equals(CREATION_DATE)) { Date creationDate = getCreationDate(); if (creationDate == null) return null; return new BasicAttribute(CREATION_DATE, creationDate); } else if (attrID.equals(ALTERNATE_CREATION_DATE)) { Date creationDate = getCreationDate(); if (creationDate == null) return null; return new BasicAttribute(ALTERNATE_CREATION_DATE, creationDate); } else if (attrID.equals(LAST_MODIFIED)) { Date lastModifiedDate = getLastModifiedDate(); if (lastModifiedDate == null) return null; return new BasicAttribute(LAST_MODIFIED, lastModifiedDate); } else if (attrID.equals(ALTERNATE_LAST_MODIFIED)) { Date lastModifiedDate = getLastModifiedDate(); if (lastModifiedDate == null) return null; return new BasicAttribute(ALTERNATE_LAST_MODIFIED, lastModifiedDate); } else if (attrID.equals(NAME)) { String name = getName(); if (name == null) return null; return new BasicAttribute(NAME, name); } else if (attrID.equals(TYPE)) { String resourceType = getResourceType(); if (resourceType == null) return null; return new BasicAttribute(TYPE, resourceType); } else if (attrID.equals(ALTERNATE_TYPE)) { String resourceType = getResourceType(); if (resourceType == null) return null; return new BasicAttribute(ALTERNATE_TYPE, resourceType); } else if (attrID.equals(CONTENT_LENGTH)) { long contentLength = getContentLength(); if (contentLength < 0) return null; return new BasicAttribute(CONTENT_LENGTH, Long.valueOf(contentLength)); } else if (attrID.equals(ALTERNATE_CONTENT_LENGTH)) { long contentLength = getContentLength(); if (contentLength < 0) return null; return new BasicAttribute(ALTERNATE_CONTENT_LENGTH, Long.valueOf(contentLength)); } else if (attrID.equals(ETAG)) { String etag = getETag(); if (etag == null) return null; return new BasicAttribute(ETAG, etag); } else if (attrID.equals(ALTERNATE_ETAG)) { String etag = getETag(); if (etag == null) return null; return new BasicAttribute(ALTERNATE_ETAG, etag); } } else { return attributes.get(attrID); } return null; } /** * Put attribute. */ @Override public Attribute put(Attribute attribute) { if (attributes == null) { try { return put(attribute.getID(), attribute.get()); } catch (NamingException e) { return null; } } else { return attributes.put(attribute); } } /** * Put attribute. */ @Override public Attribute put(String attrID, Object val) { if (attributes == null) { return null; // No reason to implement this } else { return attributes.put(attrID, val); } } /** * Remove attribute. */ @Override public Attribute remove(String attrID) { if (attributes == null) { return null; // No reason to implement this } else { return attributes.remove(attrID); } } /** * Get all attributes. */ @Override public NamingEnumeration getAll() { if (attributes == null) { Vector attributes = new Vector(); Date creationDate = getCreationDate(); if (creationDate != null) { attributes.addElement(new BasicAttribute (CREATION_DATE, creationDate)); attributes.addElement(new BasicAttribute (ALTERNATE_CREATION_DATE, creationDate)); } Date lastModifiedDate = getLastModifiedDate(); if (lastModifiedDate != null) { attributes.addElement(new BasicAttribute (LAST_MODIFIED, lastModifiedDate)); attributes.addElement(new BasicAttribute (ALTERNATE_LAST_MODIFIED, lastModifiedDate)); } String name = getName(); if (name != null) { attributes.addElement(new BasicAttribute(NAME, name)); } String resourceType = getResourceType(); if (resourceType != null) { attributes.addElement(new BasicAttribute(TYPE, resourceType)); attributes.addElement(new BasicAttribute(ALTERNATE_TYPE, resourceType)); } long contentLength = getContentLength(); if (contentLength >= 0) { Long contentLengthLong = Long.valueOf(contentLength); attributes.addElement(new BasicAttribute(CONTENT_LENGTH, contentLengthLong)); attributes.addElement(new BasicAttribute(ALTERNATE_CONTENT_LENGTH, contentLengthLong)); } String etag = getETag(); if (etag != null) { attributes.addElement(new BasicAttribute(ETAG, etag)); attributes.addElement(new BasicAttribute(ALTERNATE_ETAG, etag)); } return new RecyclableNamingEnumeration(attributes); } else { return attributes.getAll(); } } /** * Get all attribute IDs. */ @Override public NamingEnumeration getIDs() { if (attributes == null) { Vector attributeIDs = new Vector(); Date creationDate = getCreationDate(); if (creationDate != null) { attributeIDs.addElement(CREATION_DATE); attributeIDs.addElement(ALTERNATE_CREATION_DATE); } Date lastModifiedDate = getLastModifiedDate(); if (lastModifiedDate != null) { attributeIDs.addElement(LAST_MODIFIED); attributeIDs.addElement(ALTERNATE_LAST_MODIFIED); } if (getName() != null) { attributeIDs.addElement(NAME); } String resourceType = getResourceType(); if (resourceType != null) { attributeIDs.addElement(TYPE); attributeIDs.addElement(ALTERNATE_TYPE); } long contentLength = getContentLength(); if (contentLength >= 0) { attributeIDs.addElement(CONTENT_LENGTH); attributeIDs.addElement(ALTERNATE_CONTENT_LENGTH); } String etag = getETag(); if (etag != null) { attributeIDs.addElement(ETAG); attributeIDs.addElement(ALTERNATE_ETAG); } return new RecyclableNamingEnumeration(attributeIDs); } else { return attributes.getIDs(); } } /** * Retrieves the number of attributes in the attribute set. */ @Override public int size() { if (attributes == null) { int size = 0; if (getCreationDate() != null) size += 2; if (getLastModifiedDate() != null) size += 2; if (getName() != null) size++; if (getResourceType() != null) size += 2; if (getContentLength() >= 0) size += 2; if (getETag() != null) size += 2; return size; } else { return attributes.size(); } } /** * Clone the attributes object (WARNING: fake cloning). */ @Override public Object clone() { return this; } /** * Case sensitivity. */ @Override public boolean isCaseIgnored() { return false; } } tomcat7-7.0.52/java/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java0000644000175100017510000000524512271454623030706 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * Factory for Stream handlers to a JNDI directory context that also supports * users specifying additional stream handler. * * @author Remy Maucherat */ public class DirContextURLStreamHandlerFactory implements URLStreamHandlerFactory { // Singleton private static DirContextURLStreamHandlerFactory instance = new DirContextURLStreamHandlerFactory(); public static DirContextURLStreamHandlerFactory getInstance() { return instance; } public static void addUserFactory(URLStreamHandlerFactory factory) { instance.userFactories.add(factory); } private List userFactories = new CopyOnWriteArrayList(); private DirContextURLStreamHandlerFactory() { // Hide the default constructor } /** * Creates a new URLStreamHandler instance with the specified protocol. * Will return null if the protocol is not jndi. * * @param protocol the protocol (must be "jndi" here) * @return a URLStreamHandler for the jndi protocol, or null if the * protocol is not JNDI */ @Override public URLStreamHandler createURLStreamHandler(String protocol) { if (protocol.equals("jndi")) { return new DirContextURLStreamHandler(); } else { for (URLStreamHandlerFactory factory : userFactories) { URLStreamHandler handler = factory.createURLStreamHandler(protocol); if (handler != null) { return handler; } } return null; } } } tomcat7-7.0.52/java/org/apache/naming/resources/DirContextURLStreamHandler.java0000644000175100017510000001652012271454623027354 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.Hashtable; import javax.naming.directory.DirContext; /** * Stream handler to a JNDI directory context. * * @author Remy Maucherat */ public class DirContextURLStreamHandler extends URLStreamHandler { // ----------------------------------------------------------- Constructors public DirContextURLStreamHandler() { // NOOP } public DirContextURLStreamHandler(DirContext context) { this.context = context; } // -------------------------------------------------------------- Variables /** * Bindings class loader - directory context. Keyed by CL id. */ private static Hashtable clBindings = new Hashtable(); /** * Bindings thread - directory context. Keyed by thread id. */ private static Hashtable threadBindings = new Hashtable(); // ----------------------------------------------------- Instance Variables /** * Directory context. */ protected DirContext context = null; // ------------------------------------------------------------- Properties // ----------------------------------------------- URLStreamHandler Methods /** * Opens a connection to the object referenced by the URL * argument. */ @Override protected URLConnection openConnection(URL u) throws IOException { DirContext currentContext = this.context; if (currentContext == null) currentContext = get(); return new DirContextURLConnection(currentContext, u); } // ------------------------------------------------------------ URL Methods /** * Override as part of the fix for 36534, to ensure toString is correct. */ @Override protected String toExternalForm(URL u) { // pre-compute length of StringBuilder int len = u.getProtocol().length() + 1; if (u.getPath() != null) { len += u.getPath().length(); } if (u.getQuery() != null) { len += 1 + u.getQuery().length(); } if (u.getRef() != null) len += 1 + u.getRef().length(); StringBuilder result = new StringBuilder(len); result.append(u.getProtocol()); result.append(":"); if (u.getPath() != null) { result.append(u.getPath()); } if (u.getQuery() != null) { result.append('?'); result.append(u.getQuery()); } if (u.getRef() != null) { result.append("#"); result.append(u.getRef()); } return result.toString(); } // --------------------------------------------------------- Public Methods /** * Set the java.protocol.handler.pkgs system property. For use when * embedding Tomcat and the embedding application has already set its own * {@link java.net.URLStreamHandlerFactory}. */ public static void setProtocolHandler() { String value = System.getProperty(Constants.PROTOCOL_HANDLER_VARIABLE); if (value == null) { value = Constants.Package; System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value); } else if (value.indexOf(Constants.Package) == -1) { value += "|" + Constants.Package; System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value); } } /** * Returns true if the thread or the context class loader of the current * thread is bound. */ public static boolean isBound() { return (clBindings.containsKey (Thread.currentThread().getContextClassLoader())) || (threadBindings.containsKey(Thread.currentThread())); } /** * Binds a directory context to a class loader. */ public static void bind(DirContext dirContext) { ClassLoader currentCL = Thread.currentThread().getContextClassLoader(); if (currentCL != null) clBindings.put(currentCL, dirContext); } /** * Unbinds a directory context to a class loader. */ public static void unbind() { ClassLoader currentCL = Thread.currentThread().getContextClassLoader(); if (currentCL != null) clBindings.remove(currentCL); } /** * Binds a directory context to a thread. */ public static void bindThread(DirContext dirContext) { threadBindings.put(Thread.currentThread(), dirContext); } /** * Unbinds a directory context to a thread. */ public static void unbindThread() { threadBindings.remove(Thread.currentThread()); } /** * Get the bound context. */ public static DirContext get() { DirContext result = null; Thread currentThread = Thread.currentThread(); ClassLoader currentCL = currentThread.getContextClassLoader(); // Checking CL binding result = clBindings.get(currentCL); if (result != null) return result; // Checking thread biding result = threadBindings.get(currentThread); // Checking parent CL binding currentCL = currentCL.getParent(); while (currentCL != null) { result = clBindings.get(currentCL); if (result != null) return result; currentCL = currentCL.getParent(); } if (result == null) throw new IllegalStateException("Illegal class loader binding"); return result; } /** * Binds a directory context to a class loader. */ public static void bind(ClassLoader cl, DirContext dirContext) { clBindings.put(cl, dirContext); } /** * Unbinds a directory context to a class loader. */ public static void unbind(ClassLoader cl) { clBindings.remove(cl); } /** * Get the bound context. */ public static DirContext get(ClassLoader cl) { return clBindings.get(cl); } /** * Get the bound context. */ public static DirContext get(Thread thread) { return threadBindings.get(thread); } } tomcat7-7.0.52/java/org/apache/naming/resources/jndi/0000755000175100017510000000000012301126367022304 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/naming/resources/jndi/Handler.java0000644000175100017510000000244312271454623024534 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources.jndi; import org.apache.naming.resources.DirContextURLStreamHandler; /** * Stream handler to a JNDI directory context. For use when * embedding Tomcat and the embedding application has already set its own * {@link java.net.URLStreamHandlerFactory} and the Tomcat jndi handler needs to * be registered via the java.protocol.handler.pkgs system property. */ public class Handler extends DirContextURLStreamHandler { public Handler() { // NOOP } } tomcat7-7.0.52/java/org/apache/naming/resources/RecyclableNamingEnumeration.java0000644000175100017510000000502512271454623027640 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.util.Enumeration; import java.util.Vector; import javax.naming.NamingEnumeration; import javax.naming.NamingException; /** * Naming enumeration implementation. * * @author Remy Maucherat */ public class RecyclableNamingEnumeration implements NamingEnumeration { // ----------------------------------------------------------- Constructors public RecyclableNamingEnumeration(Vector entries) { this.entries = entries; recycle(); } // -------------------------------------------------------------- Variables /** * Entries. */ protected Vector entries; /** * Underlying enumeration. */ protected Enumeration enumeration; // --------------------------------------------------------- Public Methods /** * Retrieves the next element in the enumeration. */ @Override public E next() throws NamingException { return nextElement(); } /** * Determines whether there are any more elements in the enumeration. */ @Override public boolean hasMore() throws NamingException { return enumeration.hasMoreElements(); } /** * Closes this enumeration. */ @Override public void close() throws NamingException { // NO-OP } @Override public boolean hasMoreElements() { return enumeration.hasMoreElements(); } @Override public E nextElement() { return enumeration.nextElement(); } // -------------------------------------------------------- Package Methods /** * Recycle. */ void recycle() { enumeration = entries.elements(); } } tomcat7-7.0.52/java/org/apache/naming/resources/ResourceCache.java0000644000175100017510000002650212271454623024750 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.util.HashMap; import java.util.Random; /** * Implements a special purpose cache. * * @author Remy Maucherat */ public class ResourceCache { // ----------------------------------------------------------- Constructors public ResourceCache() { // NO-OP } // ----------------------------------------------------- Instance Variables /** * Random generator used to determine elements to free. */ protected Random random = new Random(); /** * Cache. * Path -> Cache entry. */ protected CacheEntry[] cache = new CacheEntry[0]; /** * Not found cache. */ protected HashMap notFoundCache = new HashMap(); /** * Max size of resources which will have their content cached. */ protected int cacheMaxSize = 10240; // 10 MB /** * Max amount of removals during a make space. */ protected int maxAllocateIterations = 20; /** * Entry hit ratio at which an entry will never be removed from the cache. * Compared with entry.access / hitsCount */ protected long desiredEntryAccessRatio = 3; /** * Spare amount of not found entries. */ protected int spareNotFoundEntries = 500; /** * Current cache size in KB. */ protected int cacheSize = 0; /** * Number of accesses to the cache. */ protected long accessCount = 0; /** * Number of cache hits. */ protected long hitsCount = 0; // ------------------------------------------------------------- Properties /** * Return the access count. * Note: Update is not synced, so the number may not be completely * accurate. * TODO: Currently unused. Expose via JMX? */ public long getAccessCount() { return accessCount; } /** * Return the maximum size of the cache in KB. * TODO: Currently unused. Expose via JMX? */ public int getCacheMaxSize() { return cacheMaxSize; } /** * Set the maximum size of the cache in KB. */ public void setCacheMaxSize(int cacheMaxSize) { this.cacheMaxSize = cacheMaxSize; } /** * Return the current cache size in KB. * TODO: Currently unused. Expose via JMX? */ public int getCacheSize() { return cacheSize; } /** * Return desired entry access ratio. * @deprecated - unused */ @Deprecated public long getDesiredEntryAccessRatio() { return desiredEntryAccessRatio; } /** * Set the desired entry access ratio. * @deprecated - unused */ @Deprecated public void setDesiredEntryAccessRatio(long desiredEntryAccessRatio) { this.desiredEntryAccessRatio = desiredEntryAccessRatio; } /** * Return the number of cache hits. * Note: Update is not synced, so the number may not be completely * accurate. * TODO: Currently unused. Expose via JMX? */ public long getHitsCount() { return hitsCount; } /** * Return the maximum amount of iterations during a space allocation. * @deprecated - unused */ @Deprecated public int getMaxAllocateIterations() { return maxAllocateIterations; } /** * Set the maximum amount of iterations during a space allocation. * @deprecated - unused */ @Deprecated public void setMaxAllocateIterations(int maxAllocateIterations) { this.maxAllocateIterations = maxAllocateIterations; } /** * Return the amount of spare not found entries. * @deprecated - unused */ @Deprecated public int getSpareNotFoundEntries() { return spareNotFoundEntries; } /** * Set the amount of spare not found entries. * @deprecated - unused */ @Deprecated public void setSpareNotFoundEntries(int spareNotFoundEntries) { this.spareNotFoundEntries = spareNotFoundEntries; } // --------------------------------------------------------- Public Methods public boolean allocate(int space) { int toFree = space - (cacheMaxSize - cacheSize); if (toFree <= 0) { return true; } // Increase the amount to free so that allocate won't have to run right // away again toFree += (cacheMaxSize / 20); int size = notFoundCache.size(); if (size > spareNotFoundEntries) { notFoundCache.clear(); cacheSize -= size; toFree -= size; } if (toFree <= 0) { return true; } int attempts = 0; int entriesFound = 0; long totalSpace = 0; int[] toRemove = new int[maxAllocateIterations]; while (toFree > 0) { if (attempts == maxAllocateIterations) { // Give up, no changes are made to the current cache return false; } if (toFree > 0) { // Randomly select an entry in the array int entryPos = -1; boolean unique = false; while (!unique) { unique = true; entryPos = random.nextInt(cache.length) ; // Guarantee uniqueness for (int i = 0; i < entriesFound; i++) { if (toRemove[i] == entryPos) { unique = false; } } } long entryAccessRatio = ((cache[entryPos].accessCount * 100) / accessCount); if (entryAccessRatio < desiredEntryAccessRatio) { toRemove[entriesFound] = entryPos; totalSpace += cache[entryPos].size; toFree -= cache[entryPos].size; entriesFound++; } } attempts++; } // Now remove the selected entries java.util.Arrays.sort(toRemove, 0, entriesFound); CacheEntry[] newCache = new CacheEntry[cache.length - entriesFound]; int pos = 0; int n = -1; if (entriesFound > 0) { n = toRemove[0]; for (int i = 0; i < cache.length; i++) { if (i == n) { if ((pos + 1) < entriesFound) { n = toRemove[pos + 1]; pos++; } else { pos++; n = -1; } } else { newCache[i - pos] = cache[i]; } } } cache = newCache; cacheSize -= totalSpace; return true; } public CacheEntry lookup(String name) { CacheEntry cacheEntry = null; CacheEntry[] currentCache = cache; accessCount++; int pos = find(currentCache, name); if ((pos != -1) && (name.equals(currentCache[pos].name))) { cacheEntry = currentCache[pos]; } if (cacheEntry == null) { try { cacheEntry = notFoundCache.get(name); } catch (Exception e) { // Ignore: the reliability of this lookup is not critical } } if (cacheEntry != null) { hitsCount++; } return cacheEntry; } public void load(CacheEntry entry) { if (entry.exists) { if (insertCache(entry)) { cacheSize += entry.size; } } else { int sizeIncrement = (notFoundCache.get(entry.name) == null) ? 1 : 0; notFoundCache.put(entry.name, entry); cacheSize += sizeIncrement; } } public boolean unload(String name) { CacheEntry removedEntry = removeCache(name); if (removedEntry != null) { cacheSize -= removedEntry.size; return true; } else if (notFoundCache.remove(name) != null) { cacheSize--; return true; } return false; } /** * Find a map element given its name in a sorted array of map elements. * This will return the index for the closest inferior or equal item in the * given array. */ private static final int find(CacheEntry[] map, String name) { int a = 0; int b = map.length - 1; // Special cases: -1 and 0 if (b == -1) { return -1; } if (name.compareTo(map[0].name) < 0) { return -1; } if (b == 0) { return 0; } int i = 0; while (true) { i = (b + a) >>> 1; int result = name.compareTo(map[i].name); if (result > 0) { a = i; } else if (result == 0) { return i; } else { b = i; } if ((b - a) == 1) { int result2 = name.compareTo(map[b].name); if (result2 < 0) { return a; } else { return b; } } } } /** * Insert into the right place in a sorted MapElement array, and prevent * duplicates. */ private final boolean insertCache(CacheEntry newElement) { CacheEntry[] oldCache = cache; int pos = find(oldCache, newElement.name); if ((pos != -1) && (newElement.name.equals(oldCache[pos].name))) { return false; } CacheEntry[] newCache = new CacheEntry[cache.length + 1]; System.arraycopy(oldCache, 0, newCache, 0, pos + 1); newCache[pos + 1] = newElement; System.arraycopy (oldCache, pos + 1, newCache, pos + 2, oldCache.length - pos - 1); cache = newCache; return true; } /** * Insert into the right place in a sorted MapElement array. */ private final CacheEntry removeCache(String name) { CacheEntry[] oldCache = cache; int pos = find(oldCache, name); if ((pos != -1) && (name.equals(oldCache[pos].name))) { CacheEntry[] newCache = new CacheEntry[cache.length - 1]; System.arraycopy(oldCache, 0, newCache, 0, pos); System.arraycopy(oldCache, pos + 1, newCache, pos, oldCache.length - pos - 1); cache = newCache; return oldCache[pos]; } return null; } } tomcat7-7.0.52/java/org/apache/naming/resources/package.html0000644000175100017510000000212112271454623023642 0ustar locutuslocutus

    This package contains the resources directory context implementation. This includes :

    • A CacheDirContext which handles caching and acts as a proxy for the real resources context
    • A FileDirContext, an implementation of DirContext to access the file system

    tomcat7-7.0.52/java/org/apache/naming/resources/ProxyDirContext.java0000644000175100017510000017267612271454623025400 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.Hashtable; import javax.naming.Binding; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameClassPair; import javax.naming.NameNotFoundException; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.naming.StringManager; /** * Proxy Directory Context implementation. * * @author Remy Maucherat */ public class ProxyDirContext implements DirContext { // -------------------------------------------------------------- Constants public static final String CONTEXT = "context"; public static final String HOST = "host"; /** * Immutable name not found exception. */ protected static final NameNotFoundException NOT_FOUND_EXCEPTION = new ImmutableNameNotFoundException(); // ----------------------------------------------------------- Constructors /** * Builds a proxy directory context using the given environment. */ public ProxyDirContext(Hashtable env, DirContext dirContext) { this.env = env; this.dirContext = dirContext; if (dirContext instanceof BaseDirContext) { // Initialize parameters based on the associated dir context, like // the caching policy. BaseDirContext baseDirContext = (BaseDirContext) dirContext; if (baseDirContext.isCached()) { try { cache = (ResourceCache) Class.forName(cacheClassName).newInstance(); } catch (Exception e) { throw new IllegalArgumentException(sm.getString( "resources.invalidCache", cacheClassName), e); } cache.setCacheMaxSize(baseDirContext.getCacheMaxSize()); cacheTTL = baseDirContext.getCacheTTL(); cacheObjectMaxSize = baseDirContext.getCacheObjectMaxSize(); // cacheObjectMaxSize must be less than cacheMaxSize // Set a sensible limit if (cacheObjectMaxSize > baseDirContext.getCacheMaxSize()/20) { cacheObjectMaxSize = baseDirContext.getCacheMaxSize()/20; } } } hostName = env.get(HOST); contextName = env.get(CONTEXT); int i = contextName.indexOf('#'); if (i == -1) { contextPath = contextName; } else { contextPath = contextName.substring(0, i); } } // ----------------------------------------------------- Instance Variables /** * Proxy DirContext (either this or the real proxy). */ protected ProxyDirContext proxy = this; /** * Environment. */ protected Hashtable env; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Associated DirContext. */ protected DirContext dirContext; /** * Virtual path. */ protected String vPath = null; /** * Host name. */ protected String hostName; /** * Context name. */ protected String contextName; /** * Context path. */ protected String contextPath; /** * Cache class. */ protected String cacheClassName = "org.apache.naming.resources.ResourceCache"; /** * Cache. */ protected ResourceCache cache = null; /** * Cache TTL. */ protected int cacheTTL = 5000; // 5s /** * Max size of resources which will have their content cached. */ protected int cacheObjectMaxSize = 512; // 512 KB /** * Non cacheable resources. */ protected String[] nonCacheable = { "/WEB-INF/lib/", "/WEB-INF/classes/" }; // --------------------------------------------------------- Public Methods /** * Get the cache used for this context. */ public ResourceCache getCache() { return cache; } /** * Return the actual directory context we are wrapping. * @deprecated - unused */ @Deprecated public DirContext getDirContext() { return this.dirContext; } /** * Return the document root for this component. * @deprecated - unused */ @Deprecated public String getDocBase() { if (dirContext instanceof BaseDirContext) return ((BaseDirContext) dirContext).getDocBase(); else return ""; } /** * Return the host name. */ public String getHostName() { return this.hostName; } /** * Return the context name. */ public String getContextName() { return this.contextName; } /** * Return the context path. */ public String getContextPath() { return this.contextPath; } // -------------------------------------------------------- Context Methods /** * Retrieves the named object. If name is empty, returns a new instance * of this context (which represents the same naming context as this * context, but its environment may be modified independently and it may * be accessed concurrently). * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public Object lookup(Name name) throws NamingException { CacheEntry entry = cacheLookup(name.toString()); if (entry != null) { if (!entry.exists) { throw NOT_FOUND_EXCEPTION; } if (entry.resource != null) { // Check content caching. return entry.resource; } else { return entry.context; } } Object object = dirContext.lookup(parseName(name)); if (object instanceof InputStream) return new Resource((InputStream) object); else return object; } /** * Retrieves the named object. * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public Object lookup(String name) throws NamingException { CacheEntry entry = cacheLookup(name); if (entry != null) { if (!entry.exists) { throw NOT_FOUND_EXCEPTION; } if (entry.resource != null) { return entry.resource; } else { return entry.context; } } Object object = dirContext.lookup(parseName(name)); if (object instanceof InputStream) { return new Resource((InputStream) object); } else if (object instanceof DirContext) { return object; } else if (object instanceof Resource) { return object; } else { return new Resource(new ByteArrayInputStream (object.toString().getBytes(Charset.defaultCharset()))); } } /** * Binds a name to an object. All intermediate contexts and the target * context (that named by all but terminal atomic component of the name) * must already exist. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(Name name, Object obj) throws NamingException { dirContext.bind(parseName(name), obj); cacheUnload(name.toString()); } /** * Binds a name to an object. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(String name, Object obj) throws NamingException { dirContext.bind(parseName(name), obj); cacheUnload(name); } /** * Binds a name to an object, overwriting any existing binding. All * intermediate contexts and the target context (that named by all but * terminal atomic component of the name) must already exist. *

    * If the object is a DirContext, any existing attributes associated with * the name are replaced with those of the object. Otherwise, any * existing attributes associated with the name remain unchanged. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(Name name, Object obj) throws NamingException { dirContext.rebind(parseName(name), obj); cacheUnload(name.toString()); } /** * Binds a name to an object, overwriting any existing binding. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj) throws NamingException { dirContext.rebind(parseName(name), obj); cacheUnload(name); } /** * Unbinds the named object. Removes the terminal atomic name in name * from the target context--that named by all but the terminal atomic * part of name. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * @param name the name to bind; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(Name name) throws NamingException { dirContext.unbind(parseName(name)); cacheUnload(name.toString()); } /** * Unbinds the named object. * * @param name the name to bind; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(String name) throws NamingException { dirContext.unbind(parseName(name)); cacheUnload(name); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. Both names are relative to this context. Any attributes * associated with the old name become associated with the new name. * Intermediate contexts of the old name are not changed. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(Name oldName, Name newName) throws NamingException { dirContext.rename(parseName(oldName), parseName(newName)); cacheUnload(oldName.toString()); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(String oldName, String newName) throws NamingException { dirContext.rename(parseName(oldName), parseName(newName)); cacheUnload(oldName); } /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. The contents of any subcontexts are * not included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(Name name) throws NamingException { return dirContext.list(parseName(name)); } /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(String name) throws NamingException { return dirContext.list(parseName(name)); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. The contents of any subcontexts are not * included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration listBindings(Name name) throws NamingException { return dirContext.listBindings(parseName(name)); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration listBindings(String name) throws NamingException { return dirContext.listBindings(parseName(name)); } /** * Destroys the named context and removes it from the namespace. Any * attributes associated with the name are also removed. Intermediate * contexts are not destroyed. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * In a federated naming system, a context from one naming system may be * bound to a name in another. One can subsequently look up and perform * operations on the foreign context using a composite name. However, an * attempt destroy the context using this composite name will fail with * NotContextException, because the foreign context is not a "subcontext" * of the context in which it is bound. Instead, use unbind() to remove * the binding of the foreign context. Destroying the foreign context * requires that the destroySubcontext() be performed on a context from * the foreign context's "native" naming system. * * @param name the name of the context to be destroyed; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception javax.naming.NotContextException if the name is bound but does * not name a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(Name name) throws NamingException { dirContext.destroySubcontext(parseName(name)); cacheUnload(name.toString()); } /** * Destroys the named context and removes it from the namespace. * * @param name the name of the context to be destroyed; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception javax.naming.NotContextException if the name is bound but does * not name a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(String name) throws NamingException { dirContext.destroySubcontext(parseName(name)); cacheUnload(name); } /** * Creates and binds a new context. Creates a new context with the given * name and binds it in the target context (that named by all but * terminal atomic component of the name). All intermediate contexts and * the target context must already exist. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if creation * of the sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(Name name) throws NamingException { Context context = dirContext.createSubcontext(parseName(name)); cacheUnload(name.toString()); return context; } /** * Creates and binds a new context. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if creation * of the sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(String name) throws NamingException { Context context = dirContext.createSubcontext(parseName(name)); cacheUnload(name); return context; } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. If the object bound to name is not a * link, returns the object itself. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(Name name) throws NamingException { return dirContext.lookupLink(parseName(name)); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(String name) throws NamingException { return dirContext.lookupLink(parseName(name)); } /** * Retrieves the parser associated with the named context. In a * federation of namespaces, different naming systems will parse names * differently. This method allows an application to get a parser for * parsing names into their atomic components using the naming convention * of a particular naming system. Within any single naming system, * NameParser objects returned by this method must be equal (using the * equals() test). * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(Name name) throws NamingException { return dirContext.getNameParser(parseName(name)); } /** * Retrieves the parser associated with the named context. * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(String name) throws NamingException { return dirContext.getNameParser(parseName(name)); } /** * Composes the name of this context with a name relative to this context. *

    * Given a name (name) relative to this context, and the name (prefix) * of this context relative to one of its ancestors, this method returns * the composition of the two names using the syntax appropriate for the * naming system(s) involved. That is, if name names an object relative * to this context, the result is the name of the same object, but * relative to the ancestor context. None of the names may be null. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public Name composeName(Name name, Name prefix) throws NamingException { Name prefixClone = (Name) prefix.clone(); return prefixClone.addAll(name); } /** * Composes the name of this context with a name relative to this context. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public String composeName(String name, String prefix) throws NamingException { return prefix + "/" + name; } /** * Adds a new environment property to the environment of this context. If * the property already exists, its value is overwritten. * * @param propName the name of the environment property to add; may not * be null * @param propVal the value of the property to add; may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object addToEnvironment(String propName, Object propVal) throws NamingException { return dirContext.addToEnvironment(propName, propVal); } /** * Removes an environment property from the environment of this context. * * @param propName the name of the environment property to remove; * may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object removeFromEnvironment(String propName) throws NamingException { return dirContext.removeFromEnvironment(propName); } /** * Retrieves the environment in effect for this context. See class * description for more details on environment properties. * The caller should not make any changes to the object returned: their * effect on the context is undefined. The environment of this context * may be changed using addToEnvironment() and removeFromEnvironment(). * * @return the environment of this context; never null * @exception NamingException if a naming exception is encountered */ @Override public Hashtable getEnvironment() throws NamingException { return dirContext.getEnvironment(); } /** * Closes this context. This method releases this context's resources * immediately, instead of waiting for them to be released automatically * by the garbage collector. * This method is idempotent: invoking it on a context that has already * been closed has no effect. Invoking any other method on a closed * context is not allowed, and results in undefined behaviour. * * @exception NamingException if a naming exception is encountered */ @Override public void close() throws NamingException { dirContext.close(); } /** * Retrieves the full name of this context within its own namespace. *

    * Many naming services have a notion of a "full name" for objects in * their respective namespaces. For example, an LDAP entry has a * distinguished name, and a DNS record has a fully qualified name. This * method allows the client application to retrieve this name. The string * returned by this method is not a JNDI composite name and should not be * passed directly to context methods. In naming systems for which the * notion of full name does not make sense, * OperationNotSupportedException is thrown. * * @return this context's name in its own namespace; never null * @exception javax.naming.OperationNotSupportedException if the naming * system does not have the notion of a full name * @exception NamingException if a naming exception is encountered */ @Override public String getNameInNamespace() throws NamingException { return dirContext.getNameInNamespace(); } // ----------------------------------------------------- DirContext Methods /** * Retrieves all of the attributes associated with a named object. * * @return the set of attributes associated with name. * Returns an empty attribute set if name has no attributes; never null. * @param name the name of the object from which to retrieve attributes * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(Name name) throws NamingException { CacheEntry entry = cacheLookup(name.toString()); if (entry != null) { if (!entry.exists) { throw NOT_FOUND_EXCEPTION; } return entry.attributes; } Attributes attributes = dirContext.getAttributes(parseName(name)); if (!(attributes instanceof ResourceAttributes)) { attributes = new ResourceAttributes(attributes); } return attributes; } /** * Retrieves all of the attributes associated with a named object. * * @return the set of attributes associated with name * @param name the name of the object from which to retrieve attributes * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(String name) throws NamingException { CacheEntry entry = cacheLookup(name); if (entry != null) { if (!entry.exists) { throw NOT_FOUND_EXCEPTION; } return entry.attributes; } Attributes attributes = dirContext.getAttributes(parseName(name)); if (!(attributes instanceof ResourceAttributes)) { attributes = new ResourceAttributes(attributes); } return attributes; } /** * Retrieves selected attributes associated with a named object. * See the class description regarding attribute models, attribute type * names, and operational attributes. * * @return the requested attributes; never null * @param name the name of the object from which to retrieve attributes * @param attrIds the identifiers of the attributes to retrieve. null * indicates that all attributes should be retrieved; an empty array * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { Attributes attributes = dirContext.getAttributes(parseName(name), attrIds); if (!(attributes instanceof ResourceAttributes)) { attributes = new ResourceAttributes(attributes); } return attributes; } /** * Retrieves selected attributes associated with a named object. * * @return the requested attributes; never null * @param name the name of the object from which to retrieve attributes * @param attrIds the identifiers of the attributes to retrieve. null * indicates that all attributes should be retrieved; an empty array * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(String name, String[] attrIds) throws NamingException { Attributes attributes = dirContext.getAttributes(parseName(name), attrIds); if (!(attributes instanceof ResourceAttributes)) { attributes = new ResourceAttributes(attributes); } return attributes; } /** * Modifies the attributes associated with a named object. The order of * the modifications is not specified. Where possible, the modifications * are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE * @param attrs the attributes to be used for the modification; may not * be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException { dirContext.modifyAttributes(parseName(name), mod_op, attrs); cacheUnload(name.toString()); } /** * Modifies the attributes associated with a named object. * * @param name the name of the object whose attributes will be updated * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE * @param attrs the attributes to be used for the modification; may not * be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException { dirContext.modifyAttributes(parseName(name), mod_op, attrs); cacheUnload(name); } /** * Modifies the attributes associated with a named object using an an * ordered list of modifications. The modifications are performed in the * order specified. Each modification specifies a modification operation * code and an attribute on which to operate. Where possible, the * modifications are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mods an ordered sequence of modifications to be performed; may * not be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException { dirContext.modifyAttributes(parseName(name), mods); cacheUnload(name.toString()); } /** * Modifies the attributes associated with a named object using an an * ordered list of modifications. * * @param name the name of the object whose attributes will be updated * @param mods an ordered sequence of modifications to be performed; may * not be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException { dirContext.modifyAttributes(parseName(name), mods); cacheUnload(name); } /** * Binds a name to an object, along with associated attributes. If attrs * is null, the resulting binding will have the attributes associated * with obj if obj is a DirContext, and no attributes otherwise. If attrs * is non-null, the resulting binding will have attrs as its attributes; * any attributes associated with obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void bind(Name name, Object obj, Attributes attrs) throws NamingException { dirContext.bind(parseName(name), obj, attrs); cacheUnload(name.toString()); } /** * Binds a name to an object, along with associated attributes. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void bind(String name, Object obj, Attributes attrs) throws NamingException { dirContext.bind(parseName(name), obj, attrs); cacheUnload(name); } /** * Binds a name to an object, along with associated attributes, * overwriting any existing binding. If attrs is null and obj is a * DirContext, the attributes from obj are used. If attrs is null and obj * is not a DirContext, any existing attributes associated with the object * already bound in the directory remain unchanged. If attrs is non-null, * any existing attributes associated with the object already bound in * the directory are removed and attrs is associated with the named * object. If obj is a DirContext and attrs is non-null, the attributes * of obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void rebind(Name name, Object obj, Attributes attrs) throws NamingException { dirContext.rebind(parseName(name), obj, attrs); cacheUnload(name.toString()); } /** * Binds a name to an object, along with associated attributes, * overwriting any existing binding. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj, Attributes attrs) throws NamingException { dirContext.rebind(parseName(name), obj, attrs); cacheUnload(name); } /** * Creates and binds a new context, along with associated attributes. * This method creates a new subcontext with the given name, binds it in * the target context (that named by all but terminal atomic component of * the name), and associates the supplied attributes with the newly * created object. All intermediate and target contexts must already * exist. If attrs is null, this method is equivalent to * Context.createSubcontext(). * * @param name the name of the context to create; may not be empty * @param attrs the attributes to associate with the newly created context * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if attrs * does not contain all the mandatory attributes required for creation * @exception NamingException if a naming exception is encountered */ @Override public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException { DirContext context = dirContext.createSubcontext(parseName(name), attrs); cacheUnload(name.toString()); return context; } /** * Creates and binds a new context, along with associated attributes. * * @param name the name of the context to create; may not be empty * @param attrs the attributes to associate with the newly created context * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if attrs * does not contain all the mandatory attributes required for creation * @exception NamingException if a naming exception is encountered */ @Override public DirContext createSubcontext(String name, Attributes attrs) throws NamingException { DirContext context = dirContext.createSubcontext(parseName(name), attrs); cacheUnload(name); return context; } /** * Retrieves the schema associated with the named object. The schema * describes rules regarding the structure of the namespace and the * attributes stored within it. The schema specifies what types of * objects can be added to the directory and where they can be added; * what mandatory and optional attributes an object can have. The range * of support for schemas is directory-specific. * * @param name the name of the object whose schema is to be retrieved * @return the schema associated with the context; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchema(Name name) throws NamingException { return dirContext.getSchema(parseName(name)); } /** * Retrieves the schema associated with the named object. * * @param name the name of the object whose schema is to be retrieved * @return the schema associated with the context; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchema(String name) throws NamingException { return dirContext.getSchema(parseName(name)); } /** * Retrieves a context containing the schema objects of the named * object's class definitions. * * @param name the name of the object whose object class definition is to * be retrieved * @return the DirContext containing the named object's class * definitions; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchemaClassDefinition(Name name) throws NamingException { return dirContext.getSchemaClassDefinition(parseName(name)); } /** * Retrieves a context containing the schema objects of the named * object's class definitions. * * @param name the name of the object whose object class definition is to * be retrieved * @return the DirContext containing the named object's class * definitions; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchemaClassDefinition(String name) throws NamingException { return dirContext.getSchemaClassDefinition(parseName(name)); } /** * Searches in a single context for objects that contain a specified set * of attributes, and retrieves selected attributes. The search is * performed using the default SearchControls settings. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @param attributesToReturn the attributes to return. null indicates * that all attributes are to be returned; an empty array indicates that * none are to be returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { return dirContext.search(parseName(name), matchingAttributes, attributesToReturn); } /** * Searches in a single context for objects that contain a specified set * of attributes, and retrieves selected attributes. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @param attributesToReturn the attributes to return. null indicates * that all attributes are to be returned; an empty array indicates that * none are to be returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { return dirContext.search(parseName(name), matchingAttributes, attributesToReturn); } /** * Searches in a single context for objects that contain a specified set * of attributes. This method returns all the attributes of such objects. * It is equivalent to supplying null as the atributesToReturn parameter * to the method search(Name, Attributes, String[]). * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(Name name, Attributes matchingAttributes) throws NamingException { return dirContext.search(parseName(name), matchingAttributes); } /** * Searches in a single context for objects that contain a specified set * of attributes. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, Attributes matchingAttributes) throws NamingException { return dirContext.search(parseName(name), matchingAttributes); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filter the filter expression to use for the search; may not be * null * @param cons the search controls that control the search. If null, * the default search controls are used (equivalent to * (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy * the filter; never null * @exception javax.naming.directory.InvalidSearchFilterException if the * search filter specified is not supported or understood by the underlying * directory * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(Name name, String filter, SearchControls cons) throws NamingException { return dirContext.search(parseName(name), filter, cons); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filter the filter expression to use for the search; may not be * null * @param cons the search controls that control the search. If null, * the default search controls are used (equivalent to * (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy * the filter; never null * @exception javax.naming.directory.InvalidSearchFilterException if the * search filter specified is not supported or understood by the underlying * directory * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException { return dirContext.search(parseName(name), filter, cons); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filterExpr the filter expression to use for the search. * The expression may contain variables of the form "{i}" where i is a * nonnegative integer. May not be null. * @param filterArgs the array of arguments to substitute for the * variables in filterExpr. The value of filterArgs[i] will replace each * occurrence of "{i}". If null, equivalent to an empty array. * @param cons the search controls that control the search. If null, the * default search controls are used (equivalent to (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisy the * filter; never null * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} * expressions where i is outside the bounds of the array filterArgs * @exception javax.naming.directory.InvalidSearchControlsException if cons * contains invalid settings * @exception javax.naming.directory.InvalidSearchFilterException if * filterExpr with filterArgs represents an invalid search filter * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { return dirContext.search(parseName(name), filterExpr, filterArgs, cons); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filterExpr the filter expression to use for the search. * The expression may contain variables of the form "{i}" where i is a * nonnegative integer. May not be null. * @param filterArgs the array of arguments to substitute for the * variables in filterExpr. The value of filterArgs[i] will replace each * occurrence of "{i}". If null, equivalent to an empty array. * @param cons the search controls that control the search. If null, the * default search controls are used (equivalent to (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisy the * filter; never null * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} * expressions where i is outside the bounds of the array filterArgs * @exception javax.naming.directory.InvalidSearchControlsException if cons * contains invalid settings * @exception javax.naming.directory.InvalidSearchFilterException if * filterExpr with filterArgs represents an invalid search filter * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { return dirContext.search(parseName(name), filterExpr, filterArgs, cons); } // --------------------------------------------------------- Public Methods /** * Retrieves the named object as a cache entry, without any exception. * * @param name the name of the object to look up * @return the cache entry bound to name */ public CacheEntry lookupCache(String name) { CacheEntry entry = cacheLookup(name); if (entry == null) { entry = new CacheEntry(); entry.name = name; try { Object object = dirContext.lookup(parseName(name)); if (object instanceof InputStream) { entry.resource = new Resource((InputStream) object); } else if (object instanceof DirContext) { entry.context = (DirContext) object; } else if (object instanceof Resource) { entry.resource = (Resource) object; } else { entry.resource = new Resource(new ByteArrayInputStream (object.toString().getBytes(Charset.defaultCharset()))); } Attributes attributes = dirContext.getAttributes(parseName(name)); if (!(attributes instanceof ResourceAttributes)) { attributes = new ResourceAttributes(attributes); } entry.attributes = (ResourceAttributes) attributes; } catch (NamingException e) { entry.exists = false; } } return entry; } // ------------------------------------------------------ Protected Methods /** * Parses a name. * * @return the parsed name * @throws NamingException if the name cannot be parsed */ protected String parseName(String name) throws NamingException { return name; } /** * Parses a name. * * @return the parsed name * @throws NamingException if the name cannot be parsed */ protected Name parseName(Name name) throws NamingException { return name; } /** * Lookup in cache. */ protected CacheEntry cacheLookup(String lookupName) { if (cache == null) return (null); String name; if (lookupName == null) { name = ""; } else { name = lookupName; } for (int i = 0; i < nonCacheable.length; i++) { if (name.startsWith(nonCacheable[i])) { return (null); } } CacheEntry cacheEntry = cache.lookup(name); if (cacheEntry == null) { cacheEntry = new CacheEntry(); cacheEntry.name = name; // Load entry cacheLoad(cacheEntry); } else { if (!validate(cacheEntry)) { if (!revalidate(cacheEntry)) { cacheUnload(cacheEntry.name); return (null); } else { cacheEntry.timestamp = System.currentTimeMillis() + cacheTTL; } } cacheEntry.accessCount++; } return (cacheEntry); } /** * Validate entry. */ protected boolean validate(CacheEntry entry) { if (((!entry.exists) || (entry.context != null) || ((entry.resource != null) && (entry.resource.getContent() != null))) && (System.currentTimeMillis() < entry.timestamp)) { return true; } return false; } /** * Revalidate entry. */ protected boolean revalidate(CacheEntry entry) { // Get the attributes at the given path, and check the last // modification date if (!entry.exists) return false; if (entry.attributes == null) return false; long lastModified = entry.attributes.getLastModified(); long contentLength = entry.attributes.getContentLength(); if (lastModified <= 0) return false; try { Attributes tempAttributes = dirContext.getAttributes(entry.name); ResourceAttributes attributes = null; if (!(tempAttributes instanceof ResourceAttributes)) { attributes = new ResourceAttributes(tempAttributes); } else { attributes = (ResourceAttributes) tempAttributes; } long lastModified2 = attributes.getLastModified(); long contentLength2 = attributes.getContentLength(); return (lastModified == lastModified2) && (contentLength == contentLength2); } catch (NamingException e) { return false; } } /** * Load entry into cache. */ protected void cacheLoad(CacheEntry entry) { String name = entry.name; // Retrieve missing info boolean exists = true; // Retrieving attributes if (entry.attributes == null) { try { Attributes attributes = dirContext.getAttributes(entry.name); if (!(attributes instanceof ResourceAttributes)) { entry.attributes = new ResourceAttributes(attributes); } else { entry.attributes = (ResourceAttributes) attributes; } } catch (NamingException e) { exists = false; } } // Retrieving object if ((exists) && (entry.resource == null) && (entry.context == null)) { try { Object object = dirContext.lookup(name); if (object instanceof InputStream) { entry.resource = new Resource((InputStream) object); } else if (object instanceof DirContext) { entry.context = (DirContext) object; } else if (object instanceof Resource) { entry.resource = (Resource) object; } else { entry.resource = new Resource(new ByteArrayInputStream (object.toString().getBytes(Charset.defaultCharset()))); } } catch (NamingException e) { exists = false; } } // Load object content if ((exists) && (entry.resource != null) && (entry.resource.getContent() == null) && (entry.attributes.getContentLength() >= 0) && (entry.attributes.getContentLength() < (cacheObjectMaxSize * 1024))) { int length = (int) entry.attributes.getContentLength(); // The entry size is 1 + the resource size in KB, if it will be // cached entry.size += (entry.attributes.getContentLength() / 1024); InputStream is = null; try { is = entry.resource.streamContent(); int pos = 0; byte[] b = new byte[length]; while (pos < length) { int n = is.read(b, pos, length - pos); if (n < 0) break; pos = pos + n; } entry.resource.setContent(b); } catch (IOException e) { // Ignore } finally { try { if (is != null) is.close(); } catch (IOException e) { // Ignore } } } // Set existence flag entry.exists = exists; // Set timestamp entry.timestamp = System.currentTimeMillis() + cacheTTL; // Add new entry to cache synchronized (cache) { // Check cache size, and remove elements if too big if ((cache.lookup(name) == null) && cache.allocate(entry.size)) { cache.load(entry); } } } /** * Remove entry from cache. */ protected boolean cacheUnload(String name) { if (cache == null) return false; // To ensure correct operation, particularly of WebDAV, unload // the resource with and without a trailing / String name2; if (name.endsWith("/")) { name2 = name.substring(0, name.length() -1); } else { name2 = name + "/"; } synchronized (cache) { boolean result = cache.unload(name); cache.unload(name2); return result; } } } tomcat7-7.0.52/java/org/apache/naming/resources/VirtualDirContext.java0000644000175100017510000002576412271454623025700 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javax.naming.NamingException; import javax.naming.directory.Attributes; import org.apache.naming.NamingEntry; /** * Extended FileDirContext implementation that allows to expose multiple * directories of the filesystem under a single webapp, a feature mainly used * for development with IDEs. * This should be used in conjunction with * {@link org.apache.catalina.loader.VirtualWebappLoader}. * * Sample context xml configuration: * * * <Context path="/mywebapp" docBase="/Users/theuser/mywebapp/src/main/webapp" > * <Resources className="org.apache.naming.resources.VirtualDirContext" * extraResourcePaths="/pictures=/Users/theuser/mypictures,/movies=/Users/theuser/mymovies" /> * <Loader className="org.apache.catalina.loader.VirtualWebappLoader" * virtualClasspath="/Users/theuser/mywebapp/target/classes" /> * <JarScanner scanAllDirectories="true" /> * </Context> * * * * This is not meant to be used for production. * Its meant to ease development with IDE's without the * need for fully republishing jars in WEB-INF/lib * * * @author Fabrizio Giustina */ public class VirtualDirContext extends FileDirContext { private String extraResourcePaths = ""; private Map> mappedResourcePaths; /** *

    * Allows to map a path of the filesystem to a path in the webapp. Multiple * filesystem paths can be mapped to the same path in the webapp. Filesystem * path and virtual path must be separated by an equal sign. Pairs of paths * must be separated by a comma. *

    * Example: * /=/Users/slaurent/mywebapp/src/main/webapp;/pictures=/Users/slaurent/sharedpictures * *

    * The path to the docBase must not be added here, otherwise resources would * be listed twice. *

    * * @param path */ public void setExtraResourcePaths(String path) { extraResourcePaths = path; } /** * {@inheritDoc} */ @Override public void allocate() { super.allocate(); mappedResourcePaths = new HashMap>(); StringTokenizer tkn = new StringTokenizer(extraResourcePaths, ","); while (tkn.hasMoreTokens()) { String resSpec = tkn.nextToken(); if (resSpec.length() > 0) { int idx = resSpec.indexOf('='); String path; if (idx <= 0) { path = ""; } else { if (resSpec.startsWith("/=")) { resSpec = resSpec.substring(1); idx--; } path = resSpec.substring(0, idx); } String dir = resSpec.substring(idx + 1); List resourcePaths = mappedResourcePaths.get(path); if (resourcePaths == null) { resourcePaths = new ArrayList(); mappedResourcePaths.put(path, resourcePaths); } resourcePaths.add(dir); } } if (mappedResourcePaths.isEmpty()) { mappedResourcePaths = null; } } /** * {@inheritDoc} */ @Override public void release() { mappedResourcePaths = null; super.release(); } @Override public Attributes getAttributes(String name) throws NamingException { NamingException initialException; try { // first try the normal processing, if it fails try with extra // resources Attributes attributes = super.getAttributes(name); return attributes; } catch (NamingException exc) { initialException = exc; } if (mappedResourcePaths != null) { for (Map.Entry> mapping : mappedResourcePaths.entrySet()) { String path = mapping.getKey(); List dirList = mapping.getValue(); String resourcesDir = dirList.get(0); if (name.equals(path)) { File f = new File(resourcesDir); if (f.exists() && f.canRead()) { return new FileResourceAttributes(f); } } path += "/"; if (name.startsWith(path)) { String res = name.substring(path.length()); File f = new File(resourcesDir + "/" + res); if (f.exists() && f.canRead()) { return new FileResourceAttributes(f); } } } } throw initialException; } @Override protected File file(String name) { File file = super.file(name); if (file != null || mappedResourcePaths == null) { return file; } // If not found under docBase, try our other resources // Ensure name string begins with a slash if (name.length() > 0 && name.charAt(0) != '/') { name = "/" + name; } for (Map.Entry> mapping : mappedResourcePaths.entrySet()) { String path = mapping.getKey(); List dirList = mapping.getValue(); if (name.equals(path)) { for (String resourcesDir : dirList) { file = new File(resourcesDir); if (file.exists() && file.canRead()) { return file; } } } if (name.startsWith(path + "/")) { String res = name.substring(path.length()); for (String resourcesDir : dirList) { file = new File(resourcesDir, res); if (file.exists() && file.canRead()) { return file; } } } } return null; } @Override protected List list(File file) { List entries = super.list(file); if (mappedResourcePaths != null && !mappedResourcePaths.isEmpty()) { Set entryNames = new HashSet(entries.size()); for (NamingEntry entry : entries) { entryNames.add(entry.name); } // Add appropriate entries from the extra resource paths String absPath = file.getAbsolutePath(); if (absPath.startsWith(getDocBase() + File.separator)) { String relPath = absPath.substring(getDocBase().length()); String fsRelPath = relPath.replace(File.separatorChar, '/'); for (Map.Entry> mapping : mappedResourcePaths.entrySet()) { String path = mapping.getKey(); List dirList = mapping.getValue(); String res = null; if (fsRelPath.equals(path)) { res = ""; } else if (fsRelPath.startsWith(path + "/")) { res = relPath.substring(path.length()); } if (res != null) { for (String resourcesDir : dirList) { File f = new File(resourcesDir, res); if (f.exists() && f.canRead() && f.isDirectory()) { List virtEntries = super.list(f); for (NamingEntry entry : virtEntries) { // filter duplicate if (!entryNames.contains(entry.name)) { entryNames.add(entry.name); entries.add(entry); } } } } } } } } return entries; } @Override protected Object doLookup(String name) { Object retSuper = super.doLookup(name); if (retSuper != null || mappedResourcePaths == null) { return retSuper; } // Perform lookup using the extra resource paths for (Map.Entry> mapping : mappedResourcePaths.entrySet()) { String path = mapping.getKey(); List dirList = mapping.getValue(); if (name.equals(path)) { for (String resourcesDir : dirList) { File f = new File(resourcesDir); if (f.exists() && f.canRead()) { if (f.isFile()) { return new FileResource(f); } else { // never goes here, if f is a directory the super // implementation already returned a value } } } } path += "/"; if (name.startsWith(path)) { String res = name.substring(path.length()); for (String resourcesDir : dirList) { File f = new File(resourcesDir + "/" + res); if (f.exists() && f.canRead()) { if (f.isFile()) { return new FileResource(f); } else { // never goes here, if f is a directory the super // implementation already returned a value } } } } } return retSuper; } @Override protected String doGetRealPath(String path) { File file = file(path); if (null != file) { return file.getAbsolutePath(); } else { return null; } } } tomcat7-7.0.52/java/org/apache/naming/resources/Resource.java0000644000175100017510000000516112271454623024022 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; /** * Encapsulates the contents of a resource. * * @author Remy Maucherat */ public class Resource { // ----------------------------------------------------------- Constructors public Resource() { // NO-OP } public Resource(InputStream inputStream) { setContent(inputStream); } public Resource(byte[] binaryContent) { setContent(binaryContent); } // ----------------------------------------------------- Instance Variables /** * Binary content. */ protected byte[] binaryContent = null; /** * Input stream. */ protected InputStream inputStream = null; // ------------------------------------------------------------- Properties /** * Content accessor. * * @return InputStream * @throws IOException */ public InputStream streamContent() throws IOException { if (binaryContent != null) { return new ByteArrayInputStream(binaryContent); } return inputStream; } /** * Content accessor. * * @return binary content */ public byte[] getContent() { return binaryContent; } /** * Content mutator. * * @param inputStream New input stream */ public void setContent(InputStream inputStream) { this.inputStream = inputStream; } /** * Content mutator. * * @param binaryContent New bin content */ public void setContent(byte[] binaryContent) { this.binaryContent = binaryContent; } } tomcat7-7.0.52/java/org/apache/naming/resources/ImmutableNameNotFoundException.java0000644000175100017510000000344412271454623030311 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import javax.naming.Name; import javax.naming.NameNotFoundException; /** * Immutable exception to avoid useless object creation by the proxy context. * This should be used only by the proxy context. Actual contexts should return * properly populated exceptions. * * @author Remy Maucherat */ public class ImmutableNameNotFoundException extends NameNotFoundException { private static final long serialVersionUID = 1L; @Override public void appendRemainingComponent(String name) {/*NOOP*/} @Override public void appendRemainingName(Name name) {/*NOOP*/} @Override public void setRemainingName(Name name) {/*NOOP*/} @Override public void setResolvedName(Name name) {/*NOOP*/} @Override public void setRootCause(Throwable e) {/*NOOP*/} @Override public synchronized Throwable fillInStackTrace() { // This class does not provide a stack trace return this; } } tomcat7-7.0.52/java/org/apache/naming/resources/Constants.java0000644000175100017510000000211312271454623024201 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; /** * Static constants for this package. */ public final class Constants { public static final String PROTOCOL_HANDLER_VARIABLE = "java.protocol.handler.pkgs"; public static final String Package = "org.apache.naming.resources"; } tomcat7-7.0.52/java/org/apache/naming/resources/LocalStrings.properties0000644000175100017510000000511312271454623026107 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. fileResources.base=Document base {0} does not exist or is not a readable directory fileResources.listingNull=Could not get dir listing for {0} warResources.notWar=Doc base must point to a WAR file warResources.invalidWar=Invalid or unreadable WAR file : {0} jarResources.syntax=Document base {0} must start with ''jar:'' and end with ''!/'' resources.addResourcesJarFail=Failed to add resources jar [{0}] resources.alreadyStarted=Resources has already been started resources.connect=Cannot connect to document base {0} resources.input=Cannot create input stream for resource {0} resources.invalidCache=Unable to create a resource cache of type [{0}] resources.notStarted=Resources has not yet been started resources.null=Document base cannot be null resources.notFound=Resource {0} not found resources.path=Context relative path {0} must start with ''/'' resources.renameFail=Failed to rename [{0}] to [{1}] resources.alreadyBound=Name {0} is already bound in this Context resources.bindFailed=Bind failed: {0} resources.unbindFailed=Unbind failed: {0} resources.invalidAliasPath=The alias path ''{0}'' must start with ''/'' resources.invalidAliasMapping=The alias mapping ''{0}'' is not valid resources.invalidAliasNotAllowed=The alias location ''{0}'' is not allowed resources.invalidAliasNotExist=The alias location ''{0}'' does not exist resources.invalidAliasFile=The alias location ''{0}'' points to a file that is not a WAR file resources.invalidName=The name [{0}] is not valid standardResources.alreadyStarted=Resources has already been started standardResources.directory=File base {0} is not a directory standardResources.exists=File base {0} does not exist standardResources.notStarted=Resources has not yet been started standardResources.null=Document base cannot be null standardResources.slash=Document base {0} must not end with a slash tomcat7-7.0.52/java/org/apache/naming/resources/LocalStrings_ja.properties0000644000175100017510000000726712271454623026575 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. fileResources.base=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u304c\u5b58\u5728\u3057\u306a\u3044\u3001\u53c8\u306f\u8aad\u3081\u306a\u3044\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u3059 fileResources.listingNull={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30ea\u30b9\u30c8\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 warResources.notWar=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fWAR\u30d5\u30a1\u30a4\u30eb\u3092\u793a\u3055\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 warResources.invalidWar=\u7121\u52b9\u53c8\u306f\u8aad\u3081\u306a\u3044WAR\u30d5\u30a1\u30a4\u30eb\u3067\u3059 : {0} jarResources.syntax=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f''jar:''\u3067\u59cb\u307e\u308a\u3001''!/''\u3067\u7d42\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 resources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 resources.connect=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306b\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093 resources.input=\u30ea\u30bd\u30fc\u30b9 {0} \u306b\u5165\u529b\u30b9\u30c8\u30ea\u30fc\u30e0\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 resources.notStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 resources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 resources.notFound=\u30ea\u30bd\u30fc\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 resources.path=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u76f8\u5bfe\u30d1\u30b9 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 resources.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059 resources.bindFailed=\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0} resources.unbindFailed=\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0} standardResources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 standardResources.directory=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u306f\u3042\u308a\u307e\u305b\u3093 standardResources.exists=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 standardResources.notStarted=\u30ea\u30bd\u30fc\u30b9\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 standardResources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 standardResources.slash=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f\u30b9\u30e9\u30c3\u30b7\u30e5\u3067\u7d42\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 tomcat7-7.0.52/java/org/apache/naming/resources/DirContextURLConnection.java0000644000175100017510000003032112271454623026715 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.security.Permission; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import org.apache.naming.JndiPermission; import org.apache.tomcat.util.buf.UDecoder; import org.apache.tomcat.util.buf.UEncoder; import org.apache.tomcat.util.http.FastHttpDateFormat; /** * Connection to a JNDI directory context. *

    * Note: All the object attribute names are the WebDAV names, not the HTTP * names, so this class overrides some methods from URLConnection to do the * queries using the right names. Content handler is also not used; the * content is directly returned. * * @author Remy Maucherat */ public class DirContextURLConnection extends URLConnection { private static final UDecoder URL_DECODER = new UDecoder(); private static final UEncoder URL_ENCODER = new UEncoder(); static{ URL_ENCODER.addSafeCharacter('/'); } // ----------------------------------------------------------- Constructors public DirContextURLConnection(DirContext context, URL url) { super(url); if (context == null) throw new IllegalArgumentException ("Directory context can't be null"); if (org.apache.naming.Constants.IS_SECURITY_ENABLED) { this.permission = new JndiPermission(url.toString()); } this.context = context; } // ----------------------------------------------------- Instance Variables /** * Directory context. */ protected DirContext context; /** * Associated resource. */ protected Resource resource; /** * Associated DirContext. */ protected DirContext collection; /** * Other unknown object. */ protected Object object; /** * Attributes. */ protected Attributes attributes; /** * Date. */ protected long date; /** * Permission */ protected Permission permission; /** * Cache the path as it there is some processing required - particularly if * the context is a ProxyDirContext. */ private String path = null; // ------------------------------------------------------------- Properties /** * Connect to the DirContext, and retrieve the bound object, as well as * its attributes. If no object is bound with the name specified in the * URL, then an IOException is thrown. * * @throws IOException Object not found */ @Override public void connect() throws IOException { if (!connected) { try { date = System.currentTimeMillis(); path = URL_DECODER.convert(getURL().getFile(), false); if (context instanceof ProxyDirContext) { ProxyDirContext proxyDirContext = (ProxyDirContext) context; String hostName = proxyDirContext.getHostName(); String contextPath = proxyDirContext.getContextPath(); if (hostName != null) { if (!path.startsWith("/" + hostName + "/")) return; path = path.substring(hostName.length()+ 1); } if (contextPath != null) { if (!path.startsWith(contextPath + "/")) { return; } path = path.substring(contextPath.length()); } } object = context.lookup(path); attributes = context.getAttributes(path); if (object instanceof Resource) resource = (Resource) object; if (object instanceof DirContext) collection = (DirContext) object; } catch (NamingException e) { // Object not found } connected = true; } } /** * Return the content length value. */ @Override public int getContentLength() { return getHeaderFieldInt(ResourceAttributes.CONTENT_LENGTH, -1); } /** * Return the content type value. */ @Override public String getContentType() { return getHeaderField(ResourceAttributes.CONTENT_TYPE); } /** * Return the last modified date. */ @Override public long getDate() { return date; } /** * Return the last modified date. */ @Override public long getLastModified() { if (!connected) { // Try to connect (silently) try { connect(); } catch (IOException e) { // Ignore } } if (attributes == null) return 0; Attribute lastModified = attributes.get(ResourceAttributes.LAST_MODIFIED); if (lastModified != null) { try { Date lmDate = (Date) lastModified.get(); return lmDate.getTime(); } catch (Exception e) { // Ignore } } return 0; } protected String getHeaderValueAsString(Object headerValue) { if (headerValue == null) return null; if (headerValue instanceof Date) { // return date strings (ie Last-Modified) in HTTP format, rather // than Java format return FastHttpDateFormat.formatDate( ((Date)headerValue).getTime(), null); } return headerValue.toString(); } /** * Returns an unmodifiable Map of the header fields. */ @Override public Map> getHeaderFields() { if (!connected) { // Try to connect (silently) try { connect(); } catch (IOException e) { //Ignore } } if (attributes == null) return (Collections.emptyMap()); HashMap> headerFields = new HashMap>(attributes.size()); NamingEnumeration attributeEnum = attributes.getIDs(); try { while (attributeEnum.hasMore()) { String attributeID = attributeEnum.next(); Attribute attribute = attributes.get(attributeID); if (attribute == null) continue; ArrayList attributeValueList = new ArrayList(attribute.size()); NamingEnumeration attributeValues = attribute.getAll(); while (attributeValues.hasMore()) { Object attrValue = attributeValues.next(); attributeValueList.add(getHeaderValueAsString(attrValue)); } attributeValueList.trimToSize(); // should be a no-op if attribute.size() didn't lie headerFields.put(attributeID, Collections.unmodifiableList(attributeValueList)); } } catch (NamingException ne) { // Shouldn't happen } return Collections.unmodifiableMap(headerFields); } /** * Returns the name of the specified header field. */ @Override public String getHeaderField(String name) { if (!connected) { // Try to connect (silently) try { connect(); } catch (IOException e) { // Ignore } } if (attributes == null) return (null); NamingEnumeration attributeEnum = attributes.getIDs(); try { while (attributeEnum.hasMore()) { String attributeID = attributeEnum.next(); if (attributeID.equalsIgnoreCase(name)) { Attribute attribute = attributes.get(attributeID); if (attribute == null) return null; Object attrValue = attribute.get(attribute.size()-1); return getHeaderValueAsString(attrValue); } } } catch (NamingException ne) { // Shouldn't happen } return (null); } /** * Get object content. */ @Override public Object getContent() throws IOException { if (!connected) connect(); if (resource != null) return getInputStream(); if (collection != null) return collection; if (object != null) return object; throw new FileNotFoundException( getURL() == null ? "null" : getURL().toString()); } /** * Get object content. */ @Override public Object getContent(@SuppressWarnings("rawtypes") Class[] classes) throws IOException { Object obj = getContent(); for (int i = 0; i < classes.length; i++) { if (classes[i].isInstance(obj)) return obj; } return null; } /** * Get input stream. */ @Override public InputStream getInputStream() throws IOException { if (!connected) connect(); if (resource == null) { throw new FileNotFoundException( getURL() == null ? "null" : getURL().toString()); } // Reopen resource try { resource = (Resource) context.lookup(path); } catch (NamingException e) { // Ignore } return (resource.streamContent()); } /** * Get the Permission for this URL */ @Override public Permission getPermission() { return permission; } // --------------------------------------------------------- Public Methods /** * List children of this collection. The names given are relative to this * URI's path. The full uri of the children is then : path + "/" + name. */ public Enumeration list() throws IOException { if (!connected) { connect(); } if ((resource == null) && (collection == null)) { throw new FileNotFoundException( getURL() == null ? "null" : getURL().toString()); } Vector result = new Vector(); if (collection != null) { try { NamingEnumeration enumeration = collection.list("/"); while (enumeration.hasMoreElements()) { NameClassPair ncp = enumeration.nextElement(); String s = ncp.getName(); result.addElement( URL_ENCODER.encodeURL(s, 0, s.length()).toString()); } } catch (NamingException e) { // Unexpected exception throw new FileNotFoundException( getURL() == null ? "null" : getURL().toString()); } } return result.elements(); } } tomcat7-7.0.52/java/org/apache/naming/resources/CacheEntry.java0000644000175100017510000000367212271454623024265 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import javax.naming.directory.DirContext; /** * Implements a cache entry. * * @author Remy Maucherat */ public class CacheEntry { // ------------------------------------------------- Instance Variables public long timestamp = -1; public String name = null; public ResourceAttributes attributes = null; public Resource resource = null; public DirContext context = null; public boolean exists = true; public long accessCount = 0; public int size = 1; // ----------------------------------------------------- Public Methods public void recycle() { timestamp = -1; name = null; attributes = null; resource = null; context = null; exists = true; accessCount = 0; size = 1; } @Override public String toString() { return ("Cache entry: " + name + "\n" + "Exists: " + exists + "\n" + "Attributes: " + attributes + "\n" + "Resource: " + resource + "\n" + "Context: " + context); } } tomcat7-7.0.52/java/org/apache/naming/resources/BaseDirContext.java0000644000175100017510000016707512271454623025126 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.File; import java.io.IOException; import java.net.JarURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import javax.naming.Binding; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameClassPair; import javax.naming.NameNotFoundException; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.naming.NameParserImpl; import org.apache.naming.NamingContextBindingsEnumeration; import org.apache.naming.NamingContextEnumeration; import org.apache.naming.NamingEntry; import org.apache.naming.StringManager; /** * Directory Context implementation helper class. * * @author Remy Maucherat */ public abstract class BaseDirContext implements DirContext { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( BaseDirContext.class ); // ----------------------------------------------------------- Constructors /** * Builds a base directory context. */ public BaseDirContext() { this.env = new Hashtable(); } /** * Builds a base directory context using the given environment. */ public BaseDirContext(Hashtable env) { this.env = env; } // ----------------------------------------------------- Instance Variables /** * The document base path. */ protected String docBase = null; /** * Environment. */ protected Hashtable env; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Name parser for this context. */ protected final NameParser nameParser = new NameParserImpl(); /** * Cached. */ protected boolean cached = true; /** * Cache TTL. */ protected int cacheTTL = 5000; // 5s /** * Max size of cache for resources. */ protected int cacheMaxSize = 10240; // 10 MB /** * Max size of resources that will be content cached. */ protected int cacheObjectMaxSize = 512; // 512 K /** * Aliases allow content to be included from other locations. */ protected Map aliases = new HashMap(); /** * Alternate / backup DirContexts for static resources. These will be * searched in the order they are added if the requested resource cannot be * found in the primary DirContext. */ protected List altDirContexts = new ArrayList(); // ------------------------------------------------------------- Properties /** * Add a resources JAR. The contents of /META-INF/resources/ will be used if * a requested resource can not be found in the main context. */ public void addResourcesJar(URL url) { try { JarURLConnection conn = (JarURLConnection) url.openConnection(); JarFile jarFile = conn.getJarFile(); ZipEntry entry = jarFile.getEntry("/"); WARDirContext warDirContext = new WARDirContext(jarFile, new WARDirContext.Entry("/", entry)); warDirContext.loadEntries(); altDirContexts.add(warDirContext); } catch (IOException ioe) { log.warn(sm.getString("resources.addResourcesJarFail", url), ioe); } } /** * Add an alternative DirContext (must contain META-INF/resources) directly. */ public void addAltDirContext(DirContext altDirContext) { altDirContexts.add(altDirContext); } /** * Add an alias. */ public void addAlias(String path, BaseDirContext dirContext) { if (!path.startsWith("/")) { throw new IllegalArgumentException( sm.getString("resources.invalidAliasPath", path)); } aliases.put(path, dirContext); } /** * Remove an alias. */ public void removeAlias(String path) { if (!path.startsWith("/")) { throw new IllegalArgumentException( sm.getString("resources.invalidAliasPath", path)); } aliases.remove(path); } /** * Get the current alias configuration in String form. If no aliases are * configured, an empty string will be returned. */ public String getAliases() { StringBuilder result = new StringBuilder(); Iterator> iter = aliases.entrySet().iterator(); boolean first = true; while (iter.hasNext()) { if (first) { first = false; } else { result.append(','); } Entry entry = iter.next(); result.append(entry.getKey()); result.append('='); result.append(entry.getValue().getDocBase()); } return result.toString(); } /** * Set the current alias configuration from a String. The String should be * of the form "/aliasPath1=docBase1,/aliasPath2=docBase2" where aliasPathN * must include a leading '/' and docBaseN must be an absolute path to * either a .war file or a directory. Any call to this method will replace * the current set of aliases. */ public void setAliases(String theAliases) { // Overwrite whatever is currently set aliases.clear(); if (theAliases == null || theAliases.length() == 0) return; String[] kvps = theAliases.split(","); for (String kvp : kvps) { // Skip blanks introduced by regexp split and/or poor input kvp = kvp.trim(); if(0 == kvp.length()) continue; String[] kv = kvp.split("="); if (kv.length != 2) throw new IllegalArgumentException( sm.getString("resources.invalidAliasMapping", kvp)); // Trim whitespace from key and value kv[0] = kv[0].trim(); kv[1] = kv[1].trim(); if(kv[0].length() == 0 || kv[1].length() == 0) throw new IllegalArgumentException( sm.getString("resources.invalidAliasMapping", kvp)); if (kv[0].equals("/")) { throw new IllegalArgumentException( sm.getString("resources.invalidAliasNotAllowed", kv[0])); } File aliasLoc = new File(kv[1]); if (!aliasLoc.exists()) { throw new IllegalArgumentException( sm.getString("resources.invalidAliasNotExist", kv[1])); } BaseDirContext context; if (kv[1].endsWith(".war") && !(aliasLoc.isDirectory())) { context = new WARDirContext(); } else if (aliasLoc.isDirectory()) { context = new FileDirContext(); } else { throw new IllegalArgumentException( sm.getString("resources.invalidAliasFile", kv[1])); } context.setDocBase(kv[1]); addAlias(kv[0], context); } } /** * Return the document root for this component. */ public String getDocBase() { return (this.docBase); } /** * Set the document root for this component. * * @param docBase The new document root * * @exception IllegalArgumentException if the specified value is not * supported by this implementation * @exception IllegalArgumentException if this would create a * malformed URL */ public void setDocBase(String docBase) { // Validate the format of the proposed document root if (docBase == null) throw new IllegalArgumentException (sm.getString("resources.null")); // Change the document root property this.docBase = docBase; } /** * Set cached. */ public void setCached(boolean cached) { this.cached = cached; } /** * Is cached ? */ public boolean isCached() { return cached; } /** * Set cache TTL. */ public void setCacheTTL(int cacheTTL) { this.cacheTTL = cacheTTL; } /** * Get cache TTL. */ public int getCacheTTL() { return cacheTTL; } /** * Return the maximum size of the cache in KB. */ public int getCacheMaxSize() { return cacheMaxSize; } /** * Set the maximum size of the cache in KB. */ public void setCacheMaxSize(int cacheMaxSize) { this.cacheMaxSize = cacheMaxSize; } /** * Return the maximum size of objects to be cached in KB. */ public int getCacheObjectMaxSize() { return cacheObjectMaxSize; } /** * Set the maximum size of objects to be placed the cache in KB. */ public void setCacheObjectMaxSize(int cacheObjectMaxSize) { this.cacheObjectMaxSize = cacheObjectMaxSize; } // --------------------------------------------------------- Public Methods /** * Allocate resources for this directory context. */ public void allocate() { // No action taken by the default implementation } /** * Release any resources allocated for this directory context. */ public void release() { for(BaseDirContext bcontext: this.aliases.values()) { bcontext.release(); } this.aliases.clear(); for(DirContext dcontext: this.altDirContexts) { if(dcontext instanceof BaseDirContext) { ((BaseDirContext)dcontext).release(); } } this.altDirContexts.clear(); } /** * Return the real path for a given virtual path, if possible; otherwise * return null. * * @param name The path to the desired resource */ public String getRealPath(String name) { if (!aliases.isEmpty()) { AliasResult result = findAlias(name); if (result.dirContext != null) { return result.dirContext.doGetRealPath(result.aliasName); } } // Next do a standard getRealPath() String path = doGetRealPath(name); if (path != null) return path; // Check the alternate locations for (DirContext altDirContext : altDirContexts) { if (altDirContext instanceof BaseDirContext){ path = ((BaseDirContext) altDirContext).getRealPath( "/META-INF/resources" + name); if (path != null) return path; } } // Really not found return null; } // -------------------------------------------------------- Context Methods /** * Retrieves the named object. If name is empty, returns a new instance * of this context (which represents the same naming context as this * context, but its environment may be modified independently and it may * be accessed concurrently). * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public final Object lookup(Name name) throws NamingException { return lookup(name.toString()); } /** * Retrieves the named object. * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public final Object lookup(String name) throws NamingException { // First check for aliases if (!aliases.isEmpty()) { AliasResult result = findAlias(name); if (result.dirContext != null) { return result.dirContext.lookup(result.aliasName); } } // Next do a standard lookup Object obj = doLookup(name); if (obj != null) return obj; // Check the alternate locations for (DirContext altDirContext : altDirContexts) { try { obj = altDirContext.lookup("/META-INF/resources" + name); if (obj != null) return obj; } catch ( NamingException ex) { // ignore } } // Really not found throw new NameNotFoundException( sm.getString("resources.notFound", name)); } /** * Binds a name to an object. All intermediate contexts and the target * context (that named by all but terminal atomic component of the name) * must already exist. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(Name name, Object obj) throws NamingException { bind(name.toString(), obj); } /** * Binds a name to an object. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(String name, Object obj) throws NamingException { bind(name, obj, null); } /** * Binds a name to an object, overwriting any existing binding. All * intermediate contexts and the target context (that named by all but * terminal atomic component of the name) must already exist. *

    * If the object is a DirContext, any existing attributes associated with * the name are replaced with those of the object. Otherwise, any * existing attributes associated with the name remain unchanged. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(Name name, Object obj) throws NamingException { rebind(name.toString(), obj); } /** * Binds a name to an object, overwriting any existing binding. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj) throws NamingException { rebind(name, obj, null); } /** * Unbinds the named object. Removes the terminal atomic name in name * from the target context--that named by all but the terminal atomic * part of name. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * @param name the name to bind; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(Name name) throws NamingException { unbind(name.toString()); } /** * Unbinds the named object. * * @param name the name to bind; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NamingException if a naming exception is encountered */ @Override public abstract void unbind(String name) throws NamingException; /** * Binds a new name to the object bound to an old name, and unbinds the * old name. Both names are relative to this context. Any attributes * associated with the old name become associated with the new name. * Intermediate contexts of the old name are not changed. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception javax.naming.NameAlreadyBoundException if newName is already * bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(Name oldName, Name newName) throws NamingException { rename(oldName.toString(), newName.toString()); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception javax.naming.NameAlreadyBoundException if newName is already * bound * @exception NamingException if a naming exception is encountered */ @Override public abstract void rename(String oldName, String newName) throws NamingException; /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. The contents of any subcontexts are * not included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(Name name) throws NamingException { return list(name.toString()); } /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(String name) throws NamingException { if (!aliases.isEmpty()) { AliasResult result = findAlias(name); if (result.dirContext != null) { return result.dirContext.list(result.aliasName); } } // Next do a standard lookup List bindings = doListBindings(name); // Check the alternate locations List altBindings = null; for (DirContext altDirContext : altDirContexts) { if (altDirContext instanceof BaseDirContext) { altBindings = ((BaseDirContext) altDirContext).doListBindings( "/META-INF/resources" + name); } if (altBindings != null) { if (bindings == null) { bindings = altBindings; } else { bindings.addAll(altBindings); } } } if (bindings != null) { return new NamingContextEnumeration(bindings.iterator()); } // Really not found throw new NameNotFoundException( sm.getString("resources.notFound", name)); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. The contents of any subcontexts are not * included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public final NamingEnumeration listBindings(Name name) throws NamingException { return listBindings(name.toString()); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public final NamingEnumeration listBindings(String name) throws NamingException { if (!aliases.isEmpty()) { AliasResult result = findAlias(name); if (result.dirContext != null) { return result.dirContext.listBindings(result.aliasName); } } // Next do a standard lookup List bindings = doListBindings(name); // Check the alternate locations List altBindings = null; for (DirContext altDirContext : altDirContexts) { if (altDirContext instanceof BaseDirContext) { altBindings = ((BaseDirContext) altDirContext).doListBindings( "/META-INF/resources" + name); } if (altBindings != null) { if (bindings == null) { bindings = altBindings; } else { bindings.addAll(altBindings); } } } if (bindings != null) { return new NamingContextBindingsEnumeration(bindings.iterator(), this); } // Really not found throw new NameNotFoundException( sm.getString("resources.notFound", name)); } /** * Destroys the named context and removes it from the namespace. Any * attributes associated with the name are also removed. Intermediate * contexts are not destroyed. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * In a federated naming system, a context from one naming system may be * bound to a name in another. One can subsequently look up and perform * operations on the foreign context using a composite name. However, an * attempt destroy the context using this composite name will fail with * NotContextException, because the foreign context is not a "subcontext" * of the context in which it is bound. Instead, use unbind() to remove * the binding of the foreign context. Destroying the foreign context * requires that the destroySubcontext() be performed on a context from * the foreign context's "native" naming system. * * @param name the name of the context to be destroyed; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception javax.naming.NotContextException if the name is bound but does * not name a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(Name name) throws NamingException { destroySubcontext(name.toString()); } /** * Destroys the named context and removes it from the namespace. * * @param name the name of the context to be destroyed; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception javax.naming.NotContextException if the name is bound but does * not name a context, or does not name a context of the appropriate type */ @Override public abstract void destroySubcontext(String name) throws NamingException; /** * Creates and binds a new context. Creates a new context with the given * name and binds it in the target context (that named by all but * terminal atomic component of the name). All intermediate contexts and * the target context must already exist. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if creation * of the sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(Name name) throws NamingException { return createSubcontext(name.toString()); } /** * Creates and binds a new context. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if creation * of the sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(String name) throws NamingException { return createSubcontext(name, null); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. If the object bound to name is not a * link, returns the object itself. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(Name name) throws NamingException { return lookupLink(name.toString()); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public abstract Object lookupLink(String name) throws NamingException; /** * Retrieves the parser associated with the named context. In a * federation of namespaces, different naming systems will parse names * differently. This method allows an application to get a parser for * parsing names into their atomic components using the naming convention * of a particular naming system. Within any single naming system, * NameParser objects returned by this method must be equal (using the * equals() test). * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(Name name) throws NamingException { return new NameParserImpl(); } /** * Retrieves the parser associated with the named context. * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(String name) throws NamingException { return new NameParserImpl(); } /** * Composes the name of this context with a name relative to this context. *

    * Given a name (name) relative to this context, and the name (prefix) * of this context relative to one of its ancestors, this method returns * the composition of the two names using the syntax appropriate for the * naming system(s) involved. That is, if name names an object relative * to this context, the result is the name of the same object, but * relative to the ancestor context. None of the names may be null. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public Name composeName(Name name, Name prefix) throws NamingException { Name clone = (Name) prefix.clone(); return clone.addAll(name); } /** * Composes the name of this context with a name relative to this context. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public String composeName(String name, String prefix) throws NamingException { return prefix + "/" + name; } /** * Adds a new environment property to the environment of this context. If * the property already exists, its value is overwritten. * * @param propName the name of the environment property to add; may not * be null * @param propVal the value of the property to add; may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object addToEnvironment(String propName, Object propVal) throws NamingException { return env.put(propName, propVal); } /** * Removes an environment property from the environment of this context. * * @param propName the name of the environment property to remove; * may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object removeFromEnvironment(String propName) throws NamingException { return env.remove(propName); } /** * Retrieves the environment in effect for this context. See class * description for more details on environment properties. * The caller should not make any changes to the object returned: their * effect on the context is undefined. The environment of this context * may be changed using addToEnvironment() and removeFromEnvironment(). * * @return the environment of this context; never null * @exception NamingException if a naming exception is encountered */ @Override public Hashtable getEnvironment() throws NamingException { return env; } /** * Closes this context. This method releases this context's resources * immediately, instead of waiting for them to be released automatically * by the garbage collector. * This method is idempotent: invoking it on a context that has already * been closed has no effect. Invoking any other method on a closed * context is not allowed, and results in undefined behaviour. * * @exception NamingException if a naming exception is encountered */ @Override public void close() throws NamingException { env.clear(); } /** * Retrieves the full name of this context within its own namespace. *

    * Many naming services have a notion of a "full name" for objects in * their respective namespaces. For example, an LDAP entry has a * distinguished name, and a DNS record has a fully qualified name. This * method allows the client application to retrieve this name. The string * returned by this method is not a JNDI composite name and should not be * passed directly to context methods. In naming systems for which the * notion of full name does not make sense, * OperationNotSupportedException is thrown. * * @return this context's name in its own namespace; never null * @exception javax.naming.OperationNotSupportedException if the naming * system does not have the notion of a full name * @exception NamingException if a naming exception is encountered */ @Override public abstract String getNameInNamespace() throws NamingException; // ----------------------------------------------------- DirContext Methods /** * Retrieves all of the attributes associated with a named object. * * @return the set of attributes associated with name. * Returns an empty attribute set if name has no attributes; never null. * @param name the name of the object from which to retrieve attributes * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(Name name) throws NamingException { return getAttributes(name.toString()); } /** * Retrieves all of the attributes associated with a named object. * * @return the set of attributes associated with name * @param name the name of the object from which to retrieve attributes * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(String name) throws NamingException { return getAttributes(name, null); } /** * Retrieves selected attributes associated with a named object. * See the class description regarding attribute models, attribute type * names, and operational attributes. * * @return the requested attributes; never null * @param name the name of the object from which to retrieve attributes * @param attrIds the identifiers of the attributes to retrieve. null * indicates that all attributes should be retrieved; an empty array * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { return getAttributes(name.toString(), attrIds); } /** * Retrieves selected attributes associated with a named object. * * @return the requested attributes; never null * @param name the name of the object from which to retrieve attributes * @param attrIds the identifiers of the attributes to retrieve. null * indicates that all attributes should be retrieved; an empty array * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ @Override public final Attributes getAttributes(String name, String[] attrIds) throws NamingException { // First check for aliases if (!aliases.isEmpty()) { AliasResult result = findAlias(name); if (result.dirContext != null) { return result.dirContext.getAttributes( result.aliasName, attrIds); } } // Next do a standard lookup Attributes attrs = doGetAttributes(name, attrIds); if (attrs != null) return attrs; // Check the alternate locations for (DirContext altDirContext : altDirContexts) { if (altDirContext instanceof BaseDirContext) attrs = ((BaseDirContext) altDirContext).doGetAttributes( "/META-INF/resources" + name, attrIds); else { try { attrs = altDirContext.getAttributes(name, attrIds); } catch (NamingException ne) { // Ignore } } if (attrs != null) return attrs; } // Really not found throw new NameNotFoundException( sm.getString("resources.notFound", name)); } /** * Modifies the attributes associated with a named object. The order of * the modifications is not specified. Where possible, the modifications * are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE * @param attrs the attributes to be used for the modification; may not * be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException { modifyAttributes(name.toString(), mod_op, attrs); } /** * Modifies the attributes associated with a named object. * * @param name the name of the object whose attributes will be updated * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE * @param attrs the attributes to be used for the modification; may not * be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public abstract void modifyAttributes (String name, int mod_op, Attributes attrs) throws NamingException; /** * Modifies the attributes associated with a named object using an an * ordered list of modifications. The modifications are performed in the * order specified. Each modification specifies a modification operation * code and an attribute on which to operate. Where possible, the * modifications are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mods an ordered sequence of modifications to be performed; may * not be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException { modifyAttributes(name.toString(), mods); } /** * Modifies the attributes associated with a named object using an an * ordered list of modifications. * * @param name the name of the object whose attributes will be updated * @param mods an ordered sequence of modifications to be performed; may * not be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public abstract void modifyAttributes(String name, ModificationItem[] mods) throws NamingException; /** * Binds a name to an object, along with associated attributes. If attrs * is null, the resulting binding will have the attributes associated * with obj if obj is a DirContext, and no attributes otherwise. If attrs * is non-null, the resulting binding will have attrs as its attributes; * any attributes associated with obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void bind(Name name, Object obj, Attributes attrs) throws NamingException { bind(name.toString(), obj, attrs); } /** * Binds a name to an object, along with associated attributes. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public abstract void bind(String name, Object obj, Attributes attrs) throws NamingException; /** * Binds a name to an object, along with associated attributes, * overwriting any existing binding. If attrs is null and obj is a * DirContext, the attributes from obj are used. If attrs is null and obj * is not a DirContext, any existing attributes associated with the object * already bound in the directory remain unchanged. If attrs is non-null, * any existing attributes associated with the object already bound in * the directory are removed and attrs is associated with the named * object. If obj is a DirContext and attrs is non-null, the attributes * of obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void rebind(Name name, Object obj, Attributes attrs) throws NamingException { rebind(name.toString(), obj, attrs); } /** * Binds a name to an object, along with associated attributes, * overwriting any existing binding. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public abstract void rebind(String name, Object obj, Attributes attrs) throws NamingException; /** * Creates and binds a new context, along with associated attributes. * This method creates a new subcontext with the given name, binds it in * the target context (that named by all but terminal atomic component of * the name), and associates the supplied attributes with the newly * created object. All intermediate and target contexts must already * exist. If attrs is null, this method is equivalent to * Context.createSubcontext(). * * @param name the name of the context to create; may not be empty * @param attrs the attributes to associate with the newly created context * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if attrs * does not contain all the mandatory attributes required for creation * @exception NamingException if a naming exception is encountered */ @Override public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException { return createSubcontext(name.toString(), attrs); } /** * Creates and binds a new context, along with associated attributes. * * @param name the name of the context to create; may not be empty * @param attrs the attributes to associate with the newly created context * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if attrs * does not contain all the mandatory attributes required for creation * @exception NamingException if a naming exception is encountered */ @Override public abstract DirContext createSubcontext(String name, Attributes attrs) throws NamingException; /** * Retrieves the schema associated with the named object. The schema * describes rules regarding the structure of the namespace and the * attributes stored within it. The schema specifies what types of * objects can be added to the directory and where they can be added; * what mandatory and optional attributes an object can have. The range * of support for schemas is directory-specific. * * @param name the name of the object whose schema is to be retrieved * @return the schema associated with the context; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchema(Name name) throws NamingException { return getSchema(name.toString()); } /** * Retrieves the schema associated with the named object. * * @param name the name of the object whose schema is to be retrieved * @return the schema associated with the context; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public abstract DirContext getSchema(String name) throws NamingException; /** * Retrieves a context containing the schema objects of the named * object's class definitions. * * @param name the name of the object whose object class definition is to * be retrieved * @return the DirContext containing the named object's class * definitions; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchemaClassDefinition(Name name) throws NamingException { return getSchemaClassDefinition(name.toString()); } /** * Retrieves a context containing the schema objects of the named * object's class definitions. * * @param name the name of the object whose object class definition is to * be retrieved * @return the DirContext containing the named object's class * definitions; never null * @exception javax.naming.OperationNotSupportedException if schema not * supported * @exception NamingException if a naming exception is encountered */ @Override public abstract DirContext getSchemaClassDefinition(String name) throws NamingException; /** * Searches in a single context for objects that contain a specified set * of attributes, and retrieves selected attributes. The search is * performed using the default SearchControls settings. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @param attributesToReturn the attributes to return. null indicates * that all attributes are to be returned; an empty array indicates that * none are to be returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { return search(name.toString(), matchingAttributes, attributesToReturn); } /** * Searches in a single context for objects that contain a specified set * of attributes, and retrieves selected attributes. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @param attributesToReturn the attributes to return. null indicates * that all attributes are to be returned; an empty array indicates that * none are to be returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public abstract NamingEnumeration search (String name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException; /** * Searches in a single context for objects that contain a specified set * of attributes. This method returns all the attributes of such objects. * It is equivalent to supplying null as the atributesToReturn parameter * to the method search(Name, Attributes, String[]). * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(Name name, Attributes matchingAttributes) throws NamingException { return search(name.toString(), matchingAttributes); } /** * Searches in a single context for objects that contain a specified set * of attributes. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public abstract NamingEnumeration search (String name, Attributes matchingAttributes) throws NamingException; /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filter the filter expression to use for the search; may not be * null * @param cons the search controls that control the search. If null, * the default search controls are used (equivalent to * (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy * the filter; never null * @exception javax.naming.directory.InvalidSearchFilterException if the * search filter specified is not supported or understood by the underlying * directory * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search (Name name, String filter, SearchControls cons) throws NamingException { return search(name.toString(), filter, cons); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filter the filter expression to use for the search; may not be * null * @param cons the search controls that control the search. If null, * the default search controls are used (equivalent to * (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy * the filter; never null * @exception javax.naming.directory.InvalidSearchFilterException if the * search filter specified is not supported or understood by the underlying * directory * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception NamingException if a naming exception is encountered */ @Override public abstract NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException; /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filterExpr the filter expression to use for the search. * The expression may contain variables of the form "{i}" where i is a * nonnegative integer. May not be null. * @param filterArgs the array of arguments to substitute for the * variables in filterExpr. The value of filterArgs[i] will replace each * occurrence of "{i}". If null, equivalent to an empty array. * @param cons the search controls that control the search. If null, the * default search controls are used (equivalent to (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisy the * filter; never null * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} * expressions where i is outside the bounds of the array filterArgs * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception javax.naming.directory.InvalidSearchFilterException if * filterExpr with filterArgs represents an invalid search filter * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { return search(name.toString(), filterExpr, filterArgs, cons); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filterExpr the filter expression to use for the search. * The expression may contain variables of the form "{i}" where i is a * nonnegative integer. May not be null. * @param filterArgs the array of arguments to substitute for the * variables in filterExpr. The value of filterArgs[i] will replace each * occurrence of "{i}". If null, equivalent to an empty array. * @param cons the search controls that control the search. If null, the * default search controls are used (equivalent to (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy the * filter; never null * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} * expressions where i is outside the bounds of the array filterArgs * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception javax.naming.directory.InvalidSearchFilterException if * filterExpr with filterArgs represents an invalid search filter * @exception NamingException if a naming exception is encountered */ @Override public abstract NamingEnumeration search (String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException; // ------------------------------------------------------ Protected Methods protected abstract Attributes doGetAttributes(String name, String[] attrIds) throws NamingException; protected abstract Object doLookup(String name); protected abstract List doListBindings(String name) throws NamingException; protected abstract String doGetRealPath(String name); // -------------------------------------------------------- Private Methods private AliasResult findAlias(String name) { AliasResult result = new AliasResult(); String searchName = name; result.dirContext = aliases.get(searchName); while (result.dirContext == null) { int slash = searchName.lastIndexOf('/'); if (slash < 0) break; searchName = searchName.substring(0, slash); result.dirContext = aliases.get(searchName); } if (result.dirContext != null) result.aliasName = name.substring(searchName.length()); return result; } private static class AliasResult { BaseDirContext dirContext; String aliasName; } } tomcat7-7.0.52/java/org/apache/naming/resources/LocalStrings_fr.properties0000644000175100017510000000435112271454623026601 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. fileResources.base=Le document base {0} n''existe pas ou n''est pas un r\u00e9pertoire lisible warResources.notWar=Doc base doit point\u00e9 vers un fichier WAR warResources.invalidWar=Fichier WAR invalide ou illisible : {0} jarResources.syntax=Le document base {0} doit commencer par ''jar:'' et finir avec ''!/'' resources.alreadyStarted=Les Ressources ont d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9es resources.connect=Impossible de se connecter au document base {0} resources.input=Impossible de cr\u00e9er l''input stream pour la ressource {0} resources.notStarted=Les ressources n''ont pas encore \u00e9t\u00e9 d\u00e9marr\u00e9es resources.null=Le document base ne peut \u00eatre nul resources.notFound=La ressource {0} est introuvable resources.path=Le chemin relatif de context {0} doit commencer par ''/'' resources.alreadyBound=Le nom {0} est d\u00e9j\u00e0 r\u00e9f\u00e9renc\u00e9 par ce contexte resources.bindFailed=Le liage a \u00e9chou\u00e9: {0} resources.unbindFailed=Le d\u00e9liage a \u00e9chou\u00e9: {0} standardResources.alreadyStarted=Les ressources ont d\u00e9ja \u00e9t\u00e9 d\u00e9marr\u00e9es standardResources.directory=Le file base {0} n''est pas un r\u00e9pertoire standardResources.exists=Le file base {0} n''existe pas standardResources.notStarted=Les ressources n''ont pas encore \u00e9t\u00e9 d\u00e9marr\u00e9es standardResources.null=Le document base ne peut \u00eatre nul standardResources.slash=Le document base {0} ne doit pas se terminer par un ''/'' tomcat7-7.0.52/java/org/apache/naming/resources/WARDirContext.java0000644000175100017510000007662312271454623024703 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.resources; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import javax.naming.CompositeName; import javax.naming.InvalidNameException; import javax.naming.Name; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.OperationNotSupportedException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.naming.NamingEntry; /** * WAR Directory Context implementation. * * @author Remy Maucherat */ public class WARDirContext extends BaseDirContext { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( WARDirContext.class ); // ----------------------------------------------------------- Constructors /** * Builds a WAR directory context using the given environment. */ public WARDirContext() { super(); } /** * Builds a WAR directory context using the given environment. */ public WARDirContext(Hashtable env) { super(env); } /** * Constructor used for returning fake sub-contexts or for accessing * META-INF/resources locations in bundled JAR files. */ protected WARDirContext(ZipFile base, Entry entries) { this.base = base; this.entries = entries; } // ----------------------------------------------------- Instance Variables /** * The WAR file. */ protected ZipFile base = null; /** * WAR entries. */ protected Entry entries = null; // ------------------------------------------------------------- Properties /** * Set the document root. * * @param docBase The new document root * * @exception IllegalArgumentException if the specified value is not * supported by this implementation * @exception IllegalArgumentException if this would create a * malformed URL */ @Override public void setDocBase(String docBase) { // Validate the format of the proposed document root if (docBase == null) throw new IllegalArgumentException (sm.getString("resources.null")); if (!(docBase.endsWith(".war"))) throw new IllegalArgumentException (sm.getString("warResources.notWar")); // Calculate a File object referencing this document base directory File base = new File(docBase); // Validate that the document base is an existing directory if (!base.exists() || !base.canRead() || base.isDirectory()) throw new IllegalArgumentException (sm.getString("warResources.invalidWar", docBase)); try { this.base = new ZipFile(base); } catch (Exception e) { throw new IllegalArgumentException (sm.getString("warResources.invalidWar", e.getMessage())); } super.setDocBase(docBase); loadEntries(); } // --------------------------------------------------------- Public Methods /** * Release any resources allocated for this directory context. */ @Override public void release() { entries = null; if (base != null) { try { base.close(); } catch (IOException e) { log.warn ("Exception closing WAR File " + base.getName(), e); } } base = null; super.release(); } /** * Return the real path for a given virtual path, if possible; otherwise * return null. * * @param path The path to the desired resource */ @Override protected String doGetRealPath(String path) { return null; } // -------------------------------------------------------- Context Methods /** * Retrieves the named object. * * @param strName the name of the object to look up * @return the object bound to name */ @Override protected Object doLookup(String strName) { Name name; try { name = getEscapedJndiName(strName); } catch (InvalidNameException e) { log.info(sm.getString("resources.invalidName", strName), e); return null; } if (name.isEmpty()) return this; Entry entry = treeLookup(name); if (entry == null) return null; ZipEntry zipEntry = entry.getEntry(); if (zipEntry.isDirectory()) return new WARDirContext(base, entry); else return new WARResource(entry.getEntry()); } /** * JNDI treats ' and " as reserved characters therefore they need to be * escaped as part of converting file names to JNDI names. Note that while * ' can be used in Windows and Unix file names, " is only valid on Unix. * This method assumes that the string is currently unquoted. * * @return A valid JNDI name * @throws InvalidNameException */ private Name getEscapedJndiName(String name) throws InvalidNameException { return new CompositeName(name.replace("'", "\\'").replace("\"", "")); } /** * {@inheritDoc} * * This method is not supported in this implementation * * @throws OperationNotSupportedException for this implementation */ @Override public void unbind(String name) throws NamingException { throw new OperationNotSupportedException(); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. Both names are relative to this context. Any attributes * associated with the old name become associated with the new name. * Intermediate contexts of the old name are not changed. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception javax.naming.NameAlreadyBoundException if newName is already * bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(String oldName, String newName) throws NamingException { throw new OperationNotSupportedException(); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. The contents of any subcontexts are not * included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param strName the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override protected List doListBindings(String strName) throws NamingException { Name name = getEscapedJndiName(strName); if (name.isEmpty()) return list(entries); Entry entry = treeLookup(name); if (entry == null) return null; return list(entry); } /** * {@inheritDoc} * * This method is not supported in this implementation * * @throws OperationNotSupportedException for this implementation */ @Override public void destroySubcontext(String name) throws NamingException { throw new OperationNotSupportedException(); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. If the object bound to name is not a * link, returns the object itself. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(String name) throws NamingException { // Note : Links are not supported return lookup(name); } /** * Retrieves the full name of this context within its own namespace. *

    * Many naming services have a notion of a "full name" for objects in * their respective namespaces. For example, an LDAP entry has a * distinguished name, and a DNS record has a fully qualified name. This * method allows the client application to retrieve this name. The string * returned by this method is not a JNDI composite name and should not be * passed directly to context methods. In naming systems for which the * notion of full name does not make sense, * OperationNotSupportedException is thrown. * * @return this context's name in its own namespace; never null * @exception OperationNotSupportedException if the naming system does * not have the notion of a full name * @exception NamingException if a naming exception is encountered */ @Override public String getNameInNamespace() throws NamingException { return docBase; } // ----------------------------------------------------- DirContext Methods /** * Retrieves selected attributes associated with a named object. * See the class description regarding attribute models, attribute type * names, and operational attributes. * * @return the requested attributes; never null * @param name the name of the object from which to retrieve attributes * @param attrIds the identifiers of the attributes to retrieve. null * indicates that all attributes should be retrieved; an empty array * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ @Override protected Attributes doGetAttributes(String name, String[] attrIds) throws NamingException { return getAttributes(getEscapedJndiName(name), attrIds); } /** * Retrieves all of the attributes associated with a named object. * * @return the set of attributes associated with name. * Returns an empty attribute set if name has no attributes; never null. * @param name the name of the object from which to retrieve attributes * @exception NamingException if a naming exception is encountered */ @Override public Attributes getAttributes(Name name, String[] attrIds) throws NamingException { Entry entry = null; if (name.isEmpty()) entry = entries; else entry = treeLookup(name); if (entry == null) return null; ZipEntry zipEntry = entry.getEntry(); ResourceAttributes attrs = new ResourceAttributes(); attrs.setCreationDate(new Date(zipEntry.getTime())); attrs.setName(entry.getName()); if (!zipEntry.isDirectory()) attrs.setResourceType(""); else attrs.setCollection(true); attrs.setContentLength(zipEntry.getSize()); attrs.setLastModified(zipEntry.getTime()); return attrs; } /** * Modifies the attributes associated with a named object. The order of * the modifications is not specified. Where possible, the modifications * are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE * @param attrs the attributes to be used for the modification; may not * be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException { throw new OperationNotSupportedException(); } /** * Modifies the attributes associated with a named object using an an * ordered list of modifications. The modifications are performed in the * order specified. Each modification specifies a modification operation * code and an attribute on which to operate. Where possible, the * modifications are performed atomically. * * @param name the name of the object whose attributes will be updated * @param mods an ordered sequence of modifications to be performed; may * not be null * @exception javax.naming.directory.AttributeModificationException if the * modification cannot be completed successfully * @exception NamingException if a naming exception is encountered */ @Override public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException { throw new OperationNotSupportedException(); } /** * Binds a name to an object, along with associated attributes. If attrs * is null, the resulting binding will have the attributes associated * with obj if obj is a DirContext, and no attributes otherwise. If attrs * is non-null, the resulting binding will have attrs as its attributes; * any attributes associated with obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void bind(String name, Object obj, Attributes attrs) throws NamingException { throw new OperationNotSupportedException(); } /** * Binds a name to an object, along with associated attributes, * overwriting any existing binding. If attrs is null and obj is a * DirContext, the attributes from obj are used. If attrs is null and obj * is not a DirContext, any existing attributes associated with the object * already bound in the directory remain unchanged. If attrs is non-null, * any existing attributes associated with the object already bound in * the directory are removed and attrs is associated with the named * object. If obj is a DirContext and attrs is non-null, the attributes * of obj are ignored. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param attrs the attributes to associate with the binding * @exception javax.naming.directory.InvalidAttributesException if some * "mandatory" attributes of the binding are not supplied * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj, Attributes attrs) throws NamingException { throw new OperationNotSupportedException(); } /** * Creates and binds a new context, along with associated attributes. * This method creates a new subcontext with the given name, binds it in * the target context (that named by all but terminal atomic component of * the name), and associates the supplied attributes with the newly * created object. All intermediate and target contexts must already * exist. If attrs is null, this method is equivalent to * Context.createSubcontext(). * * @param name the name of the context to create; may not be empty * @param attrs the attributes to associate with the newly created context * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if attrs * does not contain all the mandatory attributes required for creation * @exception NamingException if a naming exception is encountered */ @Override public DirContext createSubcontext(String name, Attributes attrs) throws NamingException { throw new OperationNotSupportedException(); } /** * Retrieves the schema associated with the named object. The schema * describes rules regarding the structure of the namespace and the * attributes stored within it. The schema specifies what types of * objects can be added to the directory and where they can be added; * what mandatory and optional attributes an object can have. The range * of support for schemas is directory-specific. * * @param name the name of the object whose schema is to be retrieved * @return the schema associated with the context; never null * @exception OperationNotSupportedException if schema not supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchema(String name) throws NamingException { throw new OperationNotSupportedException(); } /** * Retrieves a context containing the schema objects of the named * object's class definitions. * * @param name the name of the object whose object class definition is to * be retrieved * @return the DirContext containing the named object's class * definitions; never null * @exception OperationNotSupportedException if schema not supported * @exception NamingException if a naming exception is encountered */ @Override public DirContext getSchemaClassDefinition(String name) throws NamingException { throw new OperationNotSupportedException(); } /** * Searches in a single context for objects that contain a specified set * of attributes, and retrieves selected attributes. The search is * performed using the default SearchControls settings. * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @param attributesToReturn the attributes to return. null indicates * that all attributes are to be returned; an empty array indicates that * none are to be returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException { throw new OperationNotSupportedException(); } /** * Searches in a single context for objects that contain a specified set * of attributes. This method returns all the attributes of such objects. * It is equivalent to supplying null as the atributesToReturn parameter * to the method search(Name, Attributes, String[]). * * @param name the name of the context to search * @param matchingAttributes the attributes to search for. If empty or * null, all objects in the target context are returned. * @return a non-null enumeration of SearchResult objects. Each * SearchResult contains the attributes identified by attributesToReturn * and the name of the corresponding object, named relative to the * context named by name. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, Attributes matchingAttributes) throws NamingException { throw new OperationNotSupportedException(); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filter the filter expression to use for the search; may not be * null * @param cons the search controls that control the search. If null, * the default search controls are used (equivalent to * (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy * the filter; never null * @exception javax.naming.directory.InvalidSearchFilterException if the * search filter specified is not supported or understood by the underlying * directory * @exception javax.naming.directory.InvalidSearchControlsException if the * search controls contain invalid settings * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, String filter, SearchControls cons) throws NamingException { throw new OperationNotSupportedException(); } /** * Searches in the named context or object for entries that satisfy the * given search filter. Performs the search as specified by the search * controls. * * @param name the name of the context or object to search * @param filterExpr the filter expression to use for the search. * The expression may contain variables of the form "{i}" where i is a * nonnegative integer. May not be null. * @param filterArgs the array of arguments to substitute for the * variables in filterExpr. The value of filterArgs[i] will replace each * occurrence of "{i}". If null, equivalent to an empty array. * @param cons the search controls that control the search. If null, the * default search controls are used (equivalent to (new SearchControls())). * @return an enumeration of SearchResults of the objects that satisfy the * filter; never null * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} * expressions where i is outside the bounds of the array filterArgs * @exception javax.naming.directory.InvalidSearchControlsException if cons * contains invalid settings * @exception javax.naming.directory.InvalidSearchFilterException if * filterExpr with filterArgs represents an invalid search filter * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration search(String name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException { throw new OperationNotSupportedException(); } // ------------------------------------------------------ Protected Methods /** * Normalize the name of an entry read from the Zip. */ protected String normalize(ZipEntry entry) { String result = "/" + entry.getName(); if (entry.isDirectory()) { result = result.substring(0, result.length() - 1); } return result; } /** * Constructs a tree of the entries contained in a WAR file. */ protected void loadEntries() { try { Enumeration entryList = base.entries(); entries = new Entry("/", new ZipEntry("/")); while (entryList.hasMoreElements()) { ZipEntry entry = entryList.nextElement(); String name = normalize(entry); int pos = name.lastIndexOf('/'); // Check that parent entries exist and, if not, create them. // This fixes a bug for war files that don't record separate // zip entries for the directories. int currentPos = -1; int lastPos = 0; while ((currentPos = name.indexOf('/', lastPos)) != -1) { Name parentName = getEscapedJndiName(name.substring(0, lastPos)); Name childName = getEscapedJndiName(name.substring(0, currentPos)); String entryName = name.substring(lastPos, currentPos); // Parent should have been created in last cycle through // this loop Entry parent = treeLookup(parentName); Entry child = treeLookup(childName); if (child == null) { // Create a new entry for missing entry and strip off // the leading '/' character and appended on by the // normalize method and add '/' character to end to // signify that it is a directory entry String zipName = name.substring(1, currentPos) + "/"; child = new Entry(entryName, new ZipEntry(zipName)); if (parent != null) parent.addChild(child); } // Increment lastPos lastPos = currentPos + 1; } String entryName = name.substring(pos + 1, name.length()); Name compositeName = getEscapedJndiName(name.substring(0, pos)); Entry parent = treeLookup(compositeName); Entry child = new Entry(entryName, entry); if (parent != null) parent.addChild(child); } } catch (Exception e) { // Ignore } } /** * Entry tree lookup. */ protected Entry treeLookup(Name name) { if (name.isEmpty() || entries == null) return entries; Entry currentEntry = entries; for (int i = 0; i < name.size(); i++) { if (name.get(i).length() == 0) continue; currentEntry = currentEntry.getChild(name.get(i)); if (currentEntry == null) return null; } return currentEntry; } /** * List children as objects. */ protected ArrayList list(Entry entry) { ArrayList entries = new ArrayList(); Entry[] children = entry.getChildren(); Arrays.sort(children); NamingEntry namingEntry = null; for (int i = 0; i < children.length; i++) { ZipEntry current = children[i].getEntry(); Object object = null; if (current.isDirectory()) { object = new WARDirContext(base, children[i]); } else { object = new WARResource(current); } namingEntry = new NamingEntry (children[i].getName(), object, NamingEntry.ENTRY); entries.add(namingEntry); } return entries; } // ---------------------------------------------------- Entries Inner Class /** * Entries structure. */ protected static class Entry implements Comparable { // -------------------------------------------------------- Constructor public Entry(String name, ZipEntry entry) { this.name = name; this.entry = entry; } // --------------------------------------------------- Member Variables protected String name = null; protected ZipEntry entry = null; protected Entry children[] = new Entry[0]; // ----------------------------------------------------- Public Methods @Override public int compareTo(Object o) { if (!(o instanceof Entry)) return (+1); return name.compareTo(((Entry) o).getName()); } @Override public boolean equals(Object o) { if (!(o instanceof Entry)) return false; return name.equals(((Entry) o).getName()); } @Override public int hashCode() { return name.hashCode(); } public ZipEntry getEntry() { return entry; } public String getName() { return name; } public void addChild(Entry entry) { Entry[] newChildren = new Entry[children.length + 1]; for (int i = 0; i < children.length; i++) newChildren[i] = children[i]; newChildren[children.length] = entry; children = newChildren; } public Entry[] getChildren() { return children; } public Entry getChild(String name) { for (int i = 0; i < children.length; i++) { if (children[i].name.equals(name)) { return children[i]; } } return null; } } // ------------------------------------------------ WARResource Inner Class /** * This specialized resource implementation avoids opening the IputStream * to the WAR right away. */ protected class WARResource extends Resource { // -------------------------------------------------------- Constructor public WARResource(ZipEntry entry) { this.entry = entry; } // --------------------------------------------------- Member Variables protected ZipEntry entry; // ----------------------------------------------------- Public Methods /** * Content accessor. * * @return InputStream */ @Override public InputStream streamContent() throws IOException { try { if (binaryContent == null) { InputStream is = base.getInputStream(entry); inputStream = is; return is; } } catch (ZipException e) { throw new IOException(e.getMessage(), e); } return super.streamContent(); } } } tomcat7-7.0.52/java/org/apache/naming/factory/0000755000175100017510000000000012301126367021015 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/naming/factory/SendMailFactory.java0000644000175100017510000001172512271454623024717 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimePartDataSource; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; /** * Factory class that creates a JNDI named javamail MimePartDataSource * object which can be used for sending email using SMTP. *

    * Can be configured in the Context scope * of your server.xml configuration file. *

    * Example: *

    *

     * <Resource name="mail/send" auth="CONTAINER"
     *           type="javax.mail.internet.MimePartDataSource"/>
     * <ResourceParams name="mail/send">
     *   <parameter><name>factory</name>
     *     <value>org.apache.naming.factory.SendMailFactory</value>
     *   </parameter>
     *   <parameter><name>mail.smtp.host</name>
     *     <value>your.smtp.host</value>
     *   </parameter>
     *   <parameter><name>mail.smtp.user</name>
     *     <value>someuser</value>
     *   </parameter>
     *   <parameter><name>mail.from</name>
     *     <value>someuser@some.host</value>
     *   </parameter>
     *   <parameter><name>mail.smtp.sendpartial</name>
     *     <value>true</value>
     *   </parameter>
     *  <parameter><name>mail.smtp.dsn.notify</name>
     *     <value>FAILURE</value>
     *   </parameter>
     *   <parameter><name>mail.smtp.dsn.ret</name>
     *     <value>FULL</value>
     *   </parameter>
     * </ResourceParams>
     * 
    * * @author Glenn Nielsen Rich Catlett */ public class SendMailFactory implements ObjectFactory { // The class name for the javamail MimeMessageDataSource protected final String DataSourceClassName = "javax.mail.internet.MimePartDataSource"; @Override public Object getObjectInstance(Object refObj, Name name, Context ctx, Hashtable env) throws Exception { final Reference ref = (Reference)refObj; // Creation of the DataSource is wrapped inside a doPrivileged // so that javamail can read its default properties without // throwing Security Exceptions if (ref.getClassName().equals(DataSourceClassName)) { return AccessController.doPrivileged( new PrivilegedAction() { @Override public MimePartDataSource run() { // set up the smtp session that will send the message Properties props = new Properties(); // enumeration of all refaddr Enumeration list = ref.getAll(); // current refaddr to be set RefAddr refaddr; // set transport to smtp props.put("mail.transport.protocol", "smtp"); while (list.hasMoreElements()) { refaddr = list.nextElement(); // set property props.put(refaddr.getType(), refaddr.getContent()); } MimeMessage message = new MimeMessage( Session.getInstance(props)); try { RefAddr fromAddr = ref.get("mail.from"); String from = null; if (fromAddr != null) { from = (String)ref.get("mail.from").getContent(); } if (from != null) { message.setFrom(new InternetAddress(from)); } message.setSubject(""); } catch (Exception e) {/*Ignore*/} MimePartDataSource mds = new MimePartDataSource(message); return mds; } } ); } else { // We can't create an instance of the DataSource return null; } } } tomcat7-7.0.52/java/org/apache/naming/factory/OpenEjbFactory.java0000644000175100017510000000521112271454623024536 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.util.Hashtable; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.naming.EjbRef; /** * Object factory for EJBs. * * @author Jacek Laskowski * @author Remy Maucherat */ public class OpenEjbFactory implements ObjectFactory { // -------------------------------------------------------------- Constants protected static final String DEFAULT_OPENEJB_FACTORY = "org.openejb.client.LocalInitialContextFactory"; // -------------------------------------------------- ObjectFactory Methods /** * Create a new EJB instance using OpenEJB. * * @param obj The reference object describing the DataSource */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { Object beanObj = null; if (obj instanceof EjbRef) { Reference ref = (Reference) obj; String factory = DEFAULT_OPENEJB_FACTORY; RefAddr factoryRefAddr = ref.get("openejb.factory"); if (factoryRefAddr != null) { // Retrieving the OpenEJB factory factory = factoryRefAddr.getContent().toString(); } Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, factory); RefAddr linkRefAddr = ref.get("openejb.link"); if (linkRefAddr != null) { String ejbLink = linkRefAddr.getContent().toString(); beanObj = (new InitialContext(env)).lookup(ejbLink); } } return beanObj; } } tomcat7-7.0.52/java/org/apache/naming/factory/ResourceFactory.java0000644000175100017510000001337212271454623025012 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.naming.ResourceRef; /** * Object factory for Resources. * * @author Remy Maucherat */ public class ResourceFactory implements ObjectFactory { // ----------------------------------------------------------- Constructors // -------------------------------------------------------------- Constants // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods // -------------------------------------------------- ObjectFactory Methods /** * Crete a new DataSource instance. * * @param obj The reference object describing the DataSource */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { if (obj instanceof ResourceRef) { Reference ref = (Reference) obj; ObjectFactory factory = null; RefAddr factoryRefAddr = ref.get(Constants.FACTORY); if (factoryRefAddr != null) { // Using the specified factory String factoryClassName = factoryRefAddr.getContent().toString(); // Loading factory ClassLoader tcl = Thread.currentThread().getContextClassLoader(); Class factoryClass = null; if (tcl != null) { try { factoryClass = tcl.loadClass(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } else { try { factoryClass = Class.forName(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } if (factoryClass != null) { try { factory = (ObjectFactory) factoryClass.newInstance(); } catch (Exception e) { if (e instanceof NamingException) throw (NamingException) e; NamingException ex = new NamingException ("Could not create resource factory instance"); ex.initCause(e); throw ex; } } } else { if (ref.getClassName().equals("javax.sql.DataSource")) { String javaxSqlDataSourceFactoryClassName = System.getProperty("javax.sql.DataSource.Factory", Constants.DBCP_DATASOURCE_FACTORY); try { factory = (ObjectFactory) Class.forName(javaxSqlDataSourceFactoryClassName) .newInstance(); } catch (Exception e) { NamingException ex = new NamingException ("Could not create resource factory instance"); ex.initCause(e); throw ex; } } else if (ref.getClassName().equals("javax.mail.Session")) { String javaxMailSessionFactoryClassName = System.getProperty("javax.mail.Session.Factory", "org.apache.naming.factory.MailSessionFactory"); try { factory = (ObjectFactory) Class.forName(javaxMailSessionFactoryClassName) .newInstance(); } catch(Throwable t) { NamingException ex = new NamingException ("Could not create resource factory instance"); ex.initCause(t); throw ex; } } } if (factory != null) { return factory.getObjectInstance (obj, name, nameCtx, environment); } else { throw new NamingException ("Cannot create resource instance"); } } return null; } } tomcat7-7.0.52/java/org/apache/naming/factory/ResourceEnvFactory.java0000644000175100017510000001035512271454623025461 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.naming.ResourceEnvRef; /** * Object factory for Resources env. * * @author Remy Maucherat */ public class ResourceEnvFactory implements ObjectFactory { // ----------------------------------------------------------- Constructors // -------------------------------------------------------------- Constants // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods // -------------------------------------------------- ObjectFactory Methods /** * Create a new Resource env instance. * * @param obj The reference object describing the DataSource */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { if (obj instanceof ResourceEnvRef) { Reference ref = (Reference) obj; ObjectFactory factory = null; RefAddr factoryRefAddr = ref.get(Constants.FACTORY); if (factoryRefAddr != null) { // Using the specified factory String factoryClassName = factoryRefAddr.getContent().toString(); // Loading factory ClassLoader tcl = Thread.currentThread().getContextClassLoader(); Class factoryClass = null; if (tcl != null) { try { factoryClass = tcl.loadClass(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } else { try { factoryClass = Class.forName(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } if (factoryClass != null) { try { factory = (ObjectFactory) factoryClass.newInstance(); } catch(Throwable t) { if (t instanceof NamingException) throw (NamingException) t; NamingException ex = new NamingException ("Could not create resource factory instance"); ex.initCause(t); throw ex; } } } // Note: No defaults here if (factory != null) { return factory.getObjectInstance (obj, name, nameCtx, environment); } else { throw new NamingException ("Cannot create resource instance"); } } return null; } } tomcat7-7.0.52/java/org/apache/naming/factory/webservices/0000755000175100017510000000000012301126367023336 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/naming/factory/webservices/ServiceRefFactory.java0000644000175100017510000003776212271454623027612 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory.webservices; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import javax.wsdl.Definition; import javax.wsdl.Port; import javax.wsdl.extensions.ExtensibilityElement; import javax.wsdl.extensions.soap.SOAPAddress; import javax.wsdl.factory.WSDLFactory; import javax.wsdl.xml.WSDLReader; import javax.xml.namespace.QName; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceFactory; import javax.xml.rpc.handler.Handler; import javax.xml.rpc.handler.HandlerChain; import javax.xml.rpc.handler.HandlerInfo; import javax.xml.rpc.handler.HandlerRegistry; import org.apache.naming.HandlerRef; import org.apache.naming.ServiceRef; /** * Object factory for Web Services. * * @author Fabien Carrion */ public class ServiceRefFactory implements ObjectFactory { // ----------------------------------------------------------- Constructors // -------------------------------------------------------------- Constants // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods // -------------------------------------------------- ObjectFactory Methods /** * Crete a new serviceref instance. * * @param obj The reference object describing the webservice */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { if (obj instanceof ServiceRef) { Reference ref = (Reference) obj; // ClassLoader ClassLoader tcl = Thread.currentThread().getContextClassLoader(); if (tcl == null) tcl = this.getClass().getClassLoader(); ServiceFactory factory = ServiceFactory.newInstance(); javax.xml.rpc.Service service = null; // Service Interface RefAddr tmp = ref.get(ServiceRef.SERVICE_INTERFACE); String serviceInterface = null; if (tmp != null) serviceInterface = (String) tmp.getContent(); // WSDL tmp = ref.get(ServiceRef.WSDL); String wsdlRefAddr = null; if (tmp != null) wsdlRefAddr = (String) tmp.getContent(); // PortComponent Hashtable portComponentRef = new Hashtable(); // Create QName object QName serviceQname = null; tmp = ref.get(ServiceRef.SERVICE_LOCAL_PART); if (tmp != null) { String serviceLocalPart = (String) tmp.getContent(); tmp = ref.get(ServiceRef.SERVICE_NAMESPACE); if (tmp == null) { serviceQname = new QName(serviceLocalPart); } else { String serviceNamespace = (String) tmp.getContent(); serviceQname = new QName(serviceNamespace, serviceLocalPart); } } Class serviceInterfaceClass = null; // Create service object if (serviceInterface == null) { if (serviceQname == null) { throw new NamingException ("Could not create service-ref instance"); } try { if (wsdlRefAddr == null) { service = factory.createService( serviceQname ); } else { service = factory.createService( new URL(wsdlRefAddr), serviceQname ); } } catch (Exception e) { NamingException ex = new NamingException ("Could not create service"); ex.initCause(e); throw ex; } } else { // Loading service Interface try { serviceInterfaceClass = tcl.loadClass(serviceInterface); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load service Interface"); ex.initCause(e); throw ex; } if (serviceInterfaceClass == null) { throw new NamingException ("Could not load service Interface"); } try { if (wsdlRefAddr == null) { if (!Service.class.isAssignableFrom(serviceInterfaceClass)) { throw new NamingException ("service Interface should extend javax.xml.rpc.Service"); } service = factory.loadService( serviceInterfaceClass ); } else { service = factory.loadService( new URL(wsdlRefAddr), serviceInterfaceClass, new Properties() ); } } catch (Exception e) { NamingException ex = new NamingException ("Could not create service"); ex.initCause(e); throw ex; } } if (service == null) { throw new NamingException ("Cannot create service object"); } serviceQname = service.getServiceName(); serviceInterfaceClass = service.getClass(); if (wsdlRefAddr != null) { try { WSDLFactory wsdlfactory = WSDLFactory.newInstance(); WSDLReader reader = wsdlfactory.newWSDLReader(); reader.setFeature("javax.wsdl.importDocuments", true); Definition def = reader.readWSDL((new URL(wsdlRefAddr)).toExternalForm()); javax.wsdl.Service wsdlservice = def.getService(serviceQname); @SuppressWarnings("unchecked") // Can't change the API Map ports = wsdlservice.getPorts(); Method m = serviceInterfaceClass.getMethod("setEndpointAddress", new Class[] { java.lang.String.class, java.lang.String.class }); for (Iterator i = ports.keySet().iterator(); i.hasNext();) { String portName = i.next(); Port port = wsdlservice.getPort(portName); String endpoint = getSOAPLocation(port); m.invoke(service, new Object[] {port.getName(), endpoint }); portComponentRef.put(endpoint, new QName(port.getName())); } } catch (Exception e) { if (e instanceof InvocationTargetException) { Throwable cause = e.getCause(); if (cause instanceof ThreadDeath) { throw (ThreadDeath) cause; } if (cause instanceof VirtualMachineError) { throw (VirtualMachineError) cause; } } NamingException ex = new NamingException ("Error while reading Wsdl File"); ex.initCause(e); throw ex; } } ServiceProxy proxy = new ServiceProxy(service); // Use port-component-ref for (int i = 0; i < ref.size(); i++) if (ServiceRef.SERVICEENDPOINTINTERFACE.equals(ref.get(i).getType())) { String serviceendpoint = ""; String portlink = ""; serviceendpoint = (String) ref.get(i).getContent(); if (ServiceRef.PORTCOMPONENTLINK.equals(ref.get(i + 1).getType())) { i++; portlink = (String) ref.get(i).getContent(); } portComponentRef.put(serviceendpoint, new QName(portlink)); } proxy.setPortComponentRef(portComponentRef); // Instantiate service with proxy class Class[] interfaces = null; Class[] serviceInterfaces = serviceInterfaceClass.getInterfaces(); interfaces = new Class[serviceInterfaces.length + 1]; for (int i = 0; i < serviceInterfaces.length; i++) { interfaces[i] = serviceInterfaces[i]; } interfaces[interfaces.length - 1] = javax.xml.rpc.Service.class; Object proxyInstance = null; try { proxyInstance = Proxy.newProxyInstance(tcl, interfaces, proxy); } catch (IllegalArgumentException e) { proxyInstance = Proxy.newProxyInstance(tcl, serviceInterfaces, proxy); } // Use handler if (((ServiceRef) ref).getHandlersSize() > 0) { HandlerRegistry handlerRegistry = service.getHandlerRegistry(); ArrayList soaproles = new ArrayList(); while (((ServiceRef) ref).getHandlersSize() > 0) { HandlerRef handlerRef = ((ServiceRef) ref).getHandler(); HandlerInfo handlerInfo = new HandlerInfo(); // Loading handler Class tmp = handlerRef.get(HandlerRef.HANDLER_CLASS); if ((tmp == null) || (tmp.getContent() == null)) break; Class handlerClass = null; try { handlerClass = tcl.loadClass((String) tmp.getContent()); } catch(ClassNotFoundException e) { break; } // Load all datas relative to the handler : SOAPHeaders, config init element, // portNames to be set on ArrayList headers = new ArrayList(); Hashtable config = new Hashtable(); ArrayList portNames = new ArrayList(); for (int i = 0; i < handlerRef.size(); i++) if (HandlerRef.HANDLER_LOCALPART.equals(handlerRef.get(i).getType())) { String localpart = ""; String namespace = ""; localpart = (String) handlerRef.get(i).getContent(); if (HandlerRef.HANDLER_NAMESPACE.equals(handlerRef.get(i + 1).getType())) { i++; namespace = (String) handlerRef.get(i).getContent(); } QName header = new QName(namespace, localpart); headers.add(header); } else if (HandlerRef.HANDLER_PARAMNAME.equals(handlerRef.get(i).getType())) { String paramName = ""; String paramValue = ""; paramName = (String) handlerRef.get(i).getContent(); if (HandlerRef.HANDLER_PARAMVALUE.equals(handlerRef.get(i + 1).getType())) { i++; paramValue = (String) handlerRef.get(i).getContent(); } config.put(paramName, paramValue); } else if (HandlerRef.HANDLER_SOAPROLE.equals(handlerRef.get(i).getType())) { String soaprole = ""; soaprole = (String) handlerRef.get(i).getContent(); soaproles.add(soaprole); } else if (HandlerRef.HANDLER_PORTNAME.equals(handlerRef.get(i).getType())) { String portName = ""; portName = (String) handlerRef.get(i).getContent(); portNames.add(portName); } // Set the handlers informations handlerInfo.setHandlerClass(handlerClass); handlerInfo.setHeaders(headers.toArray(new QName[headers.size()])); handlerInfo.setHandlerConfig(config); if (!portNames.isEmpty()) { Iterator iter = portNames.iterator(); while (iter.hasNext()) initHandlerChain(new QName(iter.next()), handlerRegistry, handlerInfo, soaproles); } else { Enumeration e = portComponentRef.elements(); while(e.hasMoreElements()) initHandlerChain(e.nextElement(), handlerRegistry, handlerInfo, soaproles); } } } return proxyInstance; } return null; } /** * @param port analyzed port * @return Returns the endpoint URL of the given Port */ private String getSOAPLocation(Port port) { String endpoint = null; @SuppressWarnings("unchecked") // Can't change the API List extensions = port.getExtensibilityElements(); for (Iterator i = extensions.iterator(); i.hasNext();) { ExtensibilityElement ext = i.next(); if (ext instanceof SOAPAddress) { SOAPAddress addr = (SOAPAddress) ext; endpoint = addr.getLocationURI(); } } return endpoint; } private void initHandlerChain(QName portName, HandlerRegistry handlerRegistry, HandlerInfo handlerInfo, ArrayList soaprolesToAdd) { HandlerChain handlerChain = (HandlerChain) handlerRegistry.getHandlerChain(portName); @SuppressWarnings("unchecked") // Can't change the API Iterator iter = handlerChain.iterator(); while (iter.hasNext()) { Handler handler = iter.next(); handler.init(handlerInfo); } String[] soaprolesRegistered = handlerChain.getRoles(); String [] soaproles = new String[soaprolesRegistered.length + soaprolesToAdd.size()]; int i; for (i = 0;i < soaprolesRegistered.length; i++) soaproles[i] = soaprolesRegistered[i]; for (int j = 0; j < soaprolesToAdd.size(); j++) soaproles[i+j] = soaprolesToAdd.get(j); handlerChain.setRoles(soaproles); handlerRegistry.setHandlerChain(portName, handlerChain); } } tomcat7-7.0.52/java/org/apache/naming/factory/webservices/ServiceProxy.java0000644000175100017510000001116612271454623026655 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory.webservices; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.rmi.Remote; import java.util.Hashtable; import java.util.Iterator; import javax.xml.namespace.QName; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceException; /** * Object proxy for Web Services. * * @author Fabien Carrion */ public class ServiceProxy implements InvocationHandler { /** * Service object. * used for delegation */ private Service service = null; /** * changing behavior to method : Service.getPort(QName, Class) */ private static Method portQNameClass = null; /** * changing behavior to method : Service.getPort(Class) */ private static Method portClass = null; /** * PortComponentRef list */ private Hashtable portComponentRef = null; /** * Constructs a new ServiceProxy wrapping given Service instance. * @param service the wrapped Service instance * @throws ServiceException should be never thrown */ public ServiceProxy(Service service) throws ServiceException { this.service = service; try { portQNameClass = Service.class.getDeclaredMethod("getPort", new Class[]{QName.class, Class.class}); portClass = Service.class.getDeclaredMethod("getPort", new Class[]{Class.class}); } catch (Exception e) { throw new ServiceException(e); } } /** * @see InvocationHandler#invoke(Object, Method, Object[]) */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (portQNameClass.equals(method)) { return getProxyPortQNameClass(args); } if (portClass.equals(method)) { return getProxyPortClass(args); } try { return method.invoke(service, args); } catch (InvocationTargetException ite) { throw ite.getTargetException(); } } /** * @param args Method call arguments * @return Returns the correct Port * @throws ServiceException if port's QName is an unknown Port (not defined in WSDL). */ @SuppressWarnings("unchecked") private Object getProxyPortQNameClass(Object[] args) throws ServiceException { QName name = (QName) args[0]; String nameString = name.getLocalPart(); Class serviceendpointClass = (Class) args[1]; for (Iterator ports = service.getPorts(); ports.hasNext();) { QName portName = ports.next(); String portnameString = portName.getLocalPart(); if (portnameString.equals(nameString)) { return service.getPort(name, serviceendpointClass); } } // no ports have been found throw new ServiceException("Port-component-ref : " + name + " not found"); } /** * @param portComponentRef List */ public void setPortComponentRef(Hashtable portComponentRef) { this.portComponentRef = portComponentRef; } /** * @param args Method call arguments * @return Returns the correct Port * @throws ServiceException if port's QName is an unknown Port */ private Remote getProxyPortClass(Object[] args) throws ServiceException { Class serviceendpointClass = (Class) args[0]; if (this.portComponentRef == null) return service.getPort(serviceendpointClass); QName portname = this.portComponentRef.get(serviceendpointClass.getName()); if (portname != null) { return service.getPort(portname, serviceendpointClass); } else { return service.getPort(serviceendpointClass); } } } tomcat7-7.0.52/java/org/apache/naming/factory/TransactionFactory.java0000644000175100017510000001035412271454623025505 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.naming.TransactionRef; /** * Object factory for User transactions. * * @author Remy Maucherat */ public class TransactionFactory implements ObjectFactory { // ----------------------------------------------------------- Constructors // -------------------------------------------------------------- Constants // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods // -------------------------------------------------- ObjectFactory Methods /** * Create a new User transaction instance. * * @param obj The reference object describing the DataSource */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { if (obj instanceof TransactionRef) { Reference ref = (Reference) obj; ObjectFactory factory = null; RefAddr factoryRefAddr = ref.get(Constants.FACTORY); if (factoryRefAddr != null) { // Using the specified factory String factoryClassName = factoryRefAddr.getContent().toString(); // Loading factory ClassLoader tcl = Thread.currentThread().getContextClassLoader(); Class factoryClass = null; if (tcl != null) { try { factoryClass = tcl.loadClass(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } else { try { factoryClass = Class.forName(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } if (factoryClass != null) { try { factory = (ObjectFactory) factoryClass.newInstance(); } catch(Throwable t) { if (t instanceof NamingException) throw (NamingException) t; NamingException ex = new NamingException ("Could not create resource factory instance"); ex.initCause(t); throw ex; } } } if (factory != null) { return factory.getObjectInstance (obj, name, nameCtx, environment); } else { throw new NamingException ("Cannot create resource instance"); } } return null; } } tomcat7-7.0.52/java/org/apache/naming/factory/package.html0000644000175100017510000000157012271454623023306 0ustar locutuslocutus

    This package contains object factories used by the naming service.

    tomcat7-7.0.52/java/org/apache/naming/factory/DataSourceLinkFactory.java0000644000175100017510000001322211660135304026056 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.SQLException; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.sql.DataSource; /** *

    Object factory for resource links for shared data sources.

    * * @author Filip Hanik */ public class DataSourceLinkFactory extends ResourceLinkFactory { public static void setGlobalContext(Context newGlobalContext) { ResourceLinkFactory.setGlobalContext(newGlobalContext); } // ------------------------------------------------- ObjectFactory Methods /** * Create a new DataSource instance. * * @param obj The reference object describing the DataSource */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws NamingException { Object result = super.getObjectInstance(obj, name, nameCtx, environment); // Can we process this request? if (result!=null) { Reference ref = (Reference) obj; RefAddr userAttr = ref.get("username"); RefAddr passAttr = ref.get("password"); if (userAttr.getContent()!=null && passAttr.getContent()!=null) { result = wrapDataSource(result,userAttr.getContent().toString(), passAttr.getContent().toString()); } } return result; } protected Object wrapDataSource(Object datasource, String username, String password) throws NamingException { try { Class proxyClass = Proxy.getProxyClass(datasource.getClass().getClassLoader(), datasource.getClass().getInterfaces()); Constructor proxyConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class }); DataSourceHandler handler = new DataSourceHandler((DataSource)datasource, username, password); return proxyConstructor.newInstance(handler); }catch (Exception x) { if (x instanceof InvocationTargetException) { Throwable cause = x.getCause(); if (cause instanceof ThreadDeath) { throw (ThreadDeath) cause; } if (cause instanceof VirtualMachineError) { throw (VirtualMachineError) cause; } if (cause instanceof Exception) { x = (Exception) cause; } } if (x instanceof NamingException) throw (NamingException)x; else { NamingException nx = new NamingException(x.getMessage()); nx.initCause(x); throw nx; } } } /** * Simple wrapper class that will allow a user to configure a ResourceLink for a data source * so that when {@link javax.sql.DataSource#getConnection()} is called, it will invoke * {@link javax.sql.DataSource#getConnection(String, String)} with the preconfigured username and password. */ public static class DataSourceHandler implements InvocationHandler { private final DataSource ds; private final String username; private final String password; private final Method getConnection; public DataSourceHandler(DataSource ds, String username, String password) throws Exception { this.ds = ds; this.username = username; this.password = password; getConnection = ds.getClass().getMethod("getConnection", String.class, String.class); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("getConnection".equals(method.getName()) && (args==null || args.length==0)) { args = new String[] {username,password}; method = getConnection; } else if ("unwrap".equals(method.getName())) { return unwrap((Class)args[0]); } try { return method.invoke(ds,args); }catch (Throwable t) { if (t instanceof InvocationTargetException && t.getCause() != null) { throw t.getCause(); } else { throw t; } } } public Object unwrap(Class iface) throws SQLException { if (iface == DataSource.class) { return ds; } else { throw new SQLException("Not a wrapper of "+iface.getName()); } } } } tomcat7-7.0.52/java/org/apache/naming/factory/MailSessionFactory.java0000644000175100017510000001364712271454623025456 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; /** *

    Factory class that creates a JNDI named JavaMail Session factory, * which can be used for managing inbound and outbound electronic mail * messages via JavaMail APIs. All messaging environment properties * described in the JavaMail Specification may be passed to the Session * factory; however the following properties are the most commonly used:

    *
      *
    • *
    • mail.smtp.host - Hostname for outbound transport * connections. Defaults to localhost if not specified.
    • *
    * *

    This factory can be configured in a * <Context> element in your conf/server.xml * configuration file. An example of factory configuration is:

    *
     * <Resource name="mail/smtp" auth="CONTAINER"
     *           type="javax.mail.Session"/>
     * <ResourceParams name="mail/smtp">
     *   <parameter>
     *     <name>factory</name>
     *     <value>org.apache.naming.factory.MailSessionFactory</value>
     *   </parameter>
     *   <parameter>
     *     <name>mail.smtp.host</name>
     *     <value>mail.mycompany.com</value>
     *   </parameter>
     * </ResourceParams>
     * 
    * * @author Craig R. McClanahan */ public class MailSessionFactory implements ObjectFactory { /** * The Java type for which this factory knows how to create objects. */ protected static final String factoryType = "javax.mail.Session"; /** * Create and return an object instance based on the specified * characteristics. * * @param refObj Reference information containing our parameters, or null * if there are no parameters * @param name The name of this object, relative to context, or null * if there is no name * @param context The context to which name is relative, or null if name * is relative to the default initial context * @param env Environment variables, or null if there are none * * @exception Exception if an error occurs during object creation */ @Override public Object getObjectInstance(Object refObj, Name name, Context context, Hashtable env) throws Exception { // Return null if we cannot create an object of the requested type final Reference ref = (Reference) refObj; if (!ref.getClassName().equals(factoryType)) return (null); // Create a new Session inside a doPrivileged block, so that JavaMail // can read its default properties without throwing Security // exceptions. // // Bugzilla 31288, 33077: add support for authentication. return AccessController.doPrivileged(new PrivilegedAction() { @Override public Session run() { // Create the JavaMail properties we will use Properties props = new Properties(); props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.host", "localhost"); String password = null; Enumeration attrs = ref.getAll(); while (attrs.hasMoreElements()) { RefAddr attr = attrs.nextElement(); if ("factory".equals(attr.getType())) { continue; } if ("password".equals(attr.getType())) { password = (String) attr.getContent(); continue; } props.put(attr.getType(), attr.getContent()); } Authenticator auth = null; if (password != null) { String user = props.getProperty("mail.smtp.user"); if(user == null) { user = props.getProperty("mail.user"); } if(user != null) { final PasswordAuthentication pa = new PasswordAuthentication(user, password); auth = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return pa; } }; } } // Create and return the new Session object Session session = Session.getInstance(props, auth); return (session); } } ); } } tomcat7-7.0.52/java/org/apache/naming/factory/ResourceLinkFactory.java0000644000175100017510000000544012271454623025625 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.naming.ResourceLinkRef; /** *

    Object factory for resource links.

    * * @author Remy Maucherat */ public class ResourceLinkFactory implements ObjectFactory { // ----------------------------------------------------------- Constructors // ------------------------------------------------------- Static Variables /** * Global naming context. */ private static Context globalContext = null; // --------------------------------------------------------- Public Methods /** * Set the global context (note: can only be used once). * * @param newGlobalContext new global context value */ public static void setGlobalContext(Context newGlobalContext) { globalContext = newGlobalContext; } // -------------------------------------------------- ObjectFactory Methods /** * Create a new DataSource instance. * * @param obj The reference object describing the DataSource */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws NamingException { if (!(obj instanceof ResourceLinkRef)) return null; // Can we process this request? Reference ref = (Reference) obj; // Read the global ref addr String globalName = null; RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME); if (refAddr != null) { globalName = refAddr.getContent().toString(); Object result = null; result = globalContext.lookup(globalName); // FIXME: Check type return result; } return (null); } } tomcat7-7.0.52/java/org/apache/naming/factory/Constants.java0000644000175100017510000000366412271454623023652 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; /** * Static constants for this package. */ public final class Constants { public static final String Package = "org.apache.naming.factory"; public static final String DEFAULT_RESOURCE_FACTORY = Package + ".ResourceFactory"; public static final String DEFAULT_RESOURCE_LINK_FACTORY = Package + ".ResourceLinkFactory"; public static final String DEFAULT_TRANSACTION_FACTORY = Package + ".TransactionFactory"; public static final String DEFAULT_RESOURCE_ENV_FACTORY = Package + ".ResourceEnvFactory"; public static final String DEFAULT_EJB_FACTORY = Package + ".EjbFactory"; public static final String DEFAULT_SERVICE_FACTORY = Package + ".webservices.ServiceRefFactory"; public static final String DEFAULT_HANDLER_FACTORY = Package + ".HandlerFactory"; public static final String DBCP_DATASOURCE_FACTORY = "org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"; public static final String OPENEJB_EJB_FACTORY = Package + ".OpenEjbFactory"; public static final String FACTORY = "factory"; } tomcat7-7.0.52/java/org/apache/naming/factory/BeanFactory.java0000644000175100017510000002342112271454623024064 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.naming.ResourceRef; /** * Object factory for any Resource conforming to the JavaBean spec. * *

    This factory can be configured in a <Context> element * in your conf/server.xml * configuration file. An example of factory configuration is:

    *
     * <Resource name="jdbc/myDataSource" auth="SERVLET"
     *   type="oracle.jdbc.pool.OracleConnectionCacheImpl"/>
     * <ResourceParams name="jdbc/myDataSource">
     *   <parameter>
     *     <name>factory</name>
     *     <value>org.apache.naming.factory.BeanFactory</value>
     *   </parameter>
     *   <parameter>
     *     <name>driverType</name>
     *     <value>thin</value>
     *   </parameter>
     *   <parameter>
     *     <name>serverName</name>
     *     <value>hue</value>
     *   </parameter>
     *   <parameter>
     *     <name>networkProtocol</name>
     *     <value>tcp</value>
     *   </parameter> 
     *   <parameter>
     *     <name>databaseName</name>
     *     <value>XXXX</value>
     *   </parameter>
     *   <parameter>
     *     <name>portNumber</name>
     *     <value>NNNN</value>
     *   </parameter>
     *   <parameter>
     *     <name>user</name>
     *     <value>XXXX</value>
     *   </parameter>
     *   <parameter>
     *     <name>password</name>
     *     <value>XXXX</value>
     *   </parameter>
     *   <parameter>
     *     <name>maxLimit</name>
     *     <value>5</value>
     *   </parameter>
     * </ResourceParams>
     * 
    * * @author Aner Perez */ public class BeanFactory implements ObjectFactory { // ----------------------------------------------------------- Constructors // -------------------------------------------------------------- Constants // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods // -------------------------------------------------- ObjectFactory Methods /** * Create a new Bean instance. * * @param obj The reference object describing the Bean */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws NamingException { if (obj instanceof ResourceRef) { try { Reference ref = (Reference) obj; String beanClassName = ref.getClassName(); Class beanClass = null; ClassLoader tcl = Thread.currentThread().getContextClassLoader(); if (tcl != null) { try { beanClass = tcl.loadClass(beanClassName); } catch(ClassNotFoundException e) { } } else { try { beanClass = Class.forName(beanClassName); } catch(ClassNotFoundException e) { e.printStackTrace(); } } if (beanClass == null) { throw new NamingException ("Class not found: " + beanClassName); } BeanInfo bi = Introspector.getBeanInfo(beanClass); PropertyDescriptor[] pda = bi.getPropertyDescriptors(); Object bean = beanClass.newInstance(); Enumeration e = ref.getAll(); while (e.hasMoreElements()) { RefAddr ra = e.nextElement(); String propName = ra.getType(); if (propName.equals(Constants.FACTORY) || propName.equals("scope") || propName.equals("auth") || propName.equals("singleton")) { continue; } String value = (String)ra.getContent(); Object[] valueArray = new Object[1]; int i = 0; for (i = 0; i propType = pda[i].getPropertyType(); if (propType.equals(String.class)) { valueArray[0] = value; } else if (propType.equals(Character.class) || propType.equals(char.class)) { valueArray[0] = Character.valueOf(value.charAt(0)); } else if (propType.equals(Byte.class) || propType.equals(byte.class)) { valueArray[0] = new Byte(value); } else if (propType.equals(Short.class) || propType.equals(short.class)) { valueArray[0] = new Short(value); } else if (propType.equals(Integer.class) || propType.equals(int.class)) { valueArray[0] = new Integer(value); } else if (propType.equals(Long.class) || propType.equals(long.class)) { valueArray[0] = new Long(value); } else if (propType.equals(Float.class) || propType.equals(float.class)) { valueArray[0] = new Float(value); } else if (propType.equals(Double.class) || propType.equals(double.class)) { valueArray[0] = new Double(value); } else if (propType.equals(Boolean.class) || propType.equals(boolean.class)) { valueArray[0] = Boolean.valueOf(value); } else { throw new NamingException ("String conversion for property type '" + propType.getName() + "' not available"); } Method setProp = pda[i].getWriteMethod(); if (setProp != null) { setProp.invoke(bean, valueArray); } else { throw new NamingException ("Write not allowed for property: " + propName); } break; } } if (i == pda.length) { throw new NamingException ("No set method found for property: " + propName); } } return bean; } catch (java.beans.IntrospectionException ie) { NamingException ne = new NamingException(ie.getMessage()); ne.setRootCause(ie); throw ne; } catch (java.lang.IllegalAccessException iae) { NamingException ne = new NamingException(iae.getMessage()); ne.setRootCause(iae); throw ne; } catch (java.lang.InstantiationException ie2) { NamingException ne = new NamingException(ie2.getMessage()); ne.setRootCause(ie2); throw ne; } catch (java.lang.reflect.InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof ThreadDeath) { throw (ThreadDeath) cause; } if (cause instanceof VirtualMachineError) { throw (VirtualMachineError) cause; } NamingException ne = new NamingException(ite.getMessage()); ne.setRootCause(ite); throw ne; } } else { return null; } } } tomcat7-7.0.52/java/org/apache/naming/factory/EjbFactory.java0000644000175100017510000001506512271454623023724 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.factory; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; import org.apache.naming.EjbRef; /** * Object factory for EJBs. * * @author Remy Maucherat */ public class EjbFactory implements ObjectFactory { // ----------------------------------------------------------- Constructors // -------------------------------------------------------------- Constants // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods // -------------------------------------------------- ObjectFactory Methods /** * Create a new EJB instance. * * @param obj The reference object describing the DataSource */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { if (obj instanceof EjbRef) { Reference ref = (Reference) obj; // If ejb-link has been specified, resolving the link using JNDI RefAddr linkRefAddr = ref.get(EjbRef.LINK); if (linkRefAddr != null) { // Retrieving the EJB link String ejbLink = linkRefAddr.getContent().toString(); Object beanObj = (new InitialContext()).lookup(ejbLink); // Load home interface and checking if bean correctly // implements specified home interface /* String homeClassName = ref.getClassName(); try { Class home = Class.forName(homeClassName); if (home.isInstance(beanObj)) { System.out.println("Bean of type " + beanObj.getClass().getName() + " implements home interface " + home.getName()); } else { System.out.println("Bean of type " + beanObj.getClass().getName() + " doesn't implement home interface " + home.getName()); throw new NamingException ("Bean of type " + beanObj.getClass().getName() + " doesn't implement home interface " + home.getName()); } } catch (ClassNotFoundException e) { System.out.println("Couldn't load home interface " + homeClassName); } */ return beanObj; } ObjectFactory factory = null; RefAddr factoryRefAddr = ref.get(Constants.FACTORY); if (factoryRefAddr != null) { // Using the specified factory String factoryClassName = factoryRefAddr.getContent().toString(); // Loading factory ClassLoader tcl = Thread.currentThread().getContextClassLoader(); Class factoryClass = null; if (tcl != null) { try { factoryClass = tcl.loadClass(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } else { try { factoryClass = Class.forName(factoryClassName); } catch(ClassNotFoundException e) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(e); throw ex; } } if (factoryClass != null) { try { factory = (ObjectFactory) factoryClass.newInstance(); } catch(Throwable t) { NamingException ex = new NamingException ("Could not load resource factory class"); ex.initCause(t); throw ex; } } } else { String javaxEjbFactoryClassName = System.getProperty("javax.ejb.Factory", Constants.OPENEJB_EJB_FACTORY); try { factory = (ObjectFactory) Class.forName(javaxEjbFactoryClassName).newInstance(); } catch(Throwable t) { if (t instanceof NamingException) throw (NamingException) t; NamingException ex = new NamingException ("Could not create resource factory instance"); ex.initCause(t); throw ex; } } if (factory != null) { return factory.getObjectInstance (obj, name, nameCtx, environment); } else { throw new NamingException ("Cannot create resource instance"); } } return null; } } tomcat7-7.0.52/java/org/apache/naming/ContextAccessController.java0000644000175100017510000000652212271454623025035 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Hashtable; /** * Handles the access control on the JNDI contexts. * * @author Remy Maucherat */ public class ContextAccessController { // -------------------------------------------------------------- Variables /** * Catalina context names on which writing is not allowed. */ private static Hashtable readOnlyContexts = new Hashtable(); /** * Security tokens repository. */ private static Hashtable securityTokens = new Hashtable(); // --------------------------------------------------------- Public Methods /** * Set a security token for a context. Can be set only once. * * @param name Name of the context * @param token Security token */ public static void setSecurityToken(Object name, Object token) { if ((!securityTokens.containsKey(name)) && (token != null)) { securityTokens.put(name, token); } } /** * Remove a security token for a context. * * @param name Name of the context * @param token Security token */ public static void unsetSecurityToken(Object name, Object token) { if (checkSecurityToken(name, token)) { securityTokens.remove(name); } } /** * Check a submitted security token. The submitted token must be equal to * the token present in the repository. If no token is present for the * context, then returns true. * * @param name Name of the context * @param token Submitted security token */ public static boolean checkSecurityToken (Object name, Object token) { Object refToken = securityTokens.get(name); return (refToken == null || refToken.equals(token)); } /** * Allow writing to a context. * * @param name Name of the context * @param token Security token */ public static void setWritable(Object name, Object token) { if (checkSecurityToken(name, token)) readOnlyContexts.remove(name); } /** * Set whether or not a context is writable. * * @param name Name of the context */ public static void setReadOnly(Object name) { readOnlyContexts.put(name, name); } /** * Returns if a context is writable. * * @param name Name of the context */ public static boolean isWritable(Object name) { return !(readOnlyContexts.containsKey(name)); } } tomcat7-7.0.52/java/org/apache/naming/ResourceRef.java0000644000175100017510000001163412271454623022447 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Enumeration; import javax.naming.Context; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.StringRefAddr; /** * Represents a reference address to a resource. * * @author Remy Maucherat */ public class ResourceRef extends Reference { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants /** * Default factory for this reference. */ public static final String DEFAULT_FACTORY = org.apache.naming.factory.Constants.DEFAULT_RESOURCE_FACTORY; /** * Description address type. */ public static final String DESCRIPTION = "description"; /** * Scope address type. */ public static final String SCOPE = "scope"; /** * Auth address type. */ public static final String AUTH = "auth"; /** * Is this resource a singleton */ public static final String SINGLETON = "singleton"; // ----------------------------------------------------------- Constructors /** * Resource Reference. * * @param resourceClass Resource class * @param scope Resource scope * @param auth Resource authentication */ public ResourceRef(String resourceClass, String description, String scope, String auth, boolean singleton) { this(resourceClass, description, scope, auth, singleton, null, null); } /** * Resource Reference. * * @param resourceClass Resource class * @param scope Resource scope * @param auth Resource authentication */ public ResourceRef(String resourceClass, String description, String scope, String auth, boolean singleton, String factory, String factoryLocation) { super(resourceClass, factory, factoryLocation); StringRefAddr refAddr = null; if (description != null) { refAddr = new StringRefAddr(DESCRIPTION, description); add(refAddr); } if (scope != null) { refAddr = new StringRefAddr(SCOPE, scope); add(refAddr); } if (auth != null) { refAddr = new StringRefAddr(AUTH, auth); add(refAddr); } // singleton is a boolean so slightly different handling refAddr = new StringRefAddr(SINGLETON, Boolean.toString(singleton)); add(refAddr); } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------ Reference Methods /** * Retrieves the class name of the factory of the object to which this * reference refers. */ @Override public String getFactoryClassName() { String factory = super.getFactoryClassName(); if (factory != null) { return factory; } else { factory = System.getProperty(Context.OBJECT_FACTORIES); if (factory != null) { return null; } else { return DEFAULT_FACTORY; } } } // --------------------------------------------------------- Public Methods /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ResourceRef["); sb.append("className="); sb.append(getClassName()); sb.append(",factoryClassLocation="); sb.append(getFactoryClassLocation()); sb.append(",factoryClassName="); sb.append(getFactoryClassName()); Enumeration refAddrs = getAll(); while (refAddrs.hasMoreElements()) { RefAddr refAddr = refAddrs.nextElement(); sb.append(",{type="); sb.append(refAddr.getType()); sb.append(",content="); sb.append(refAddr.getContent()); sb.append("}"); } sb.append("]"); return (sb.toString()); } // ------------------------------------------------------------- Properties } tomcat7-7.0.52/java/org/apache/naming/ContextBindings.java0000644000175100017510000002452612271454623023331 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Hashtable; import javax.naming.Context; import javax.naming.NamingException; /** * Handles the associations : *
      *
    • Catalina context name with the NamingContext
    • *
    • Calling thread with the NamingContext
    • *
    * * @author Remy Maucherat */ public class ContextBindings { // -------------------------------------------------------------- Variables /** * Bindings name - naming context. Keyed by name. */ private static final Hashtable contextNameBindings = new Hashtable(); /** * Bindings thread - naming context. Keyed by thread id. */ private static final Hashtable threadBindings = new Hashtable(); /** * Bindings thread - name. Keyed by thread id. */ private static final Hashtable threadNameBindings = new Hashtable(); /** * Bindings class loader - naming context. Keyed by CL id. */ private static final Hashtable clBindings = new Hashtable(); /** * Bindings class loader - name. Keyed by CL id. */ private static final Hashtable clNameBindings = new Hashtable(); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // --------------------------------------------------------- Public Methods /** * Binds a context name. * * @param name Name of the context * @param context Associated naming context instance */ public static void bindContext(Object name, Context context) { bindContext(name, context, null); } /** * Binds a context name. * * @param name Name of the context * @param context Associated naming context instance * @param token Security token */ public static void bindContext(Object name, Context context, Object token) { if (ContextAccessController.checkSecurityToken(name, token)) contextNameBindings.put(name, context); } /** * Unbind context name. * * @param name Name of the context * * @deprecated - unused */ @Deprecated public static void unbindContext(Object name) { unbindContext(name, null); } /** * Unbind context name. * * @param name Name of the context * @param token Security token */ public static void unbindContext(Object name, Object token) { if (ContextAccessController.checkSecurityToken(name, token)) contextNameBindings.remove(name); } /** * Retrieve a naming context. * * @param name Name of the context */ static Context getContext(Object name) { return contextNameBindings.get(name); } /** * Binds a naming context to a thread. * * @param name Name of the context * * @deprecated - unused */ @Deprecated public static void bindThread(Object name) throws NamingException { bindThread(name, null); } /** * Binds a naming context to a thread. * * @param name Name of the context * @param token Security token */ public static void bindThread(Object name, Object token) throws NamingException { if (ContextAccessController.checkSecurityToken(name, token)) { Context context = contextNameBindings.get(name); if (context == null) throw new NamingException (sm.getString("contextBindings.unknownContext", name)); threadBindings.put(Thread.currentThread(), context); threadNameBindings.put(Thread.currentThread(), name); } } /** * Unbinds a naming context to a thread. * * @param name Name of the context * * @deprecated - unused */ @Deprecated public static void unbindThread(Object name) { unbindThread(name, null); } /** * Unbinds a naming context to a thread. * * @param name Name of the context * @param token Security token */ public static void unbindThread(Object name, Object token) { if (ContextAccessController.checkSecurityToken(name, token)) { threadBindings.remove(Thread.currentThread()); threadNameBindings.remove(Thread.currentThread()); } } /** * Retrieves the naming context bound to a thread. */ public static Context getThread() throws NamingException { Context context = threadBindings.get(Thread.currentThread()); if (context == null) throw new NamingException (sm.getString("contextBindings.noContextBoundToThread")); return context; } /** * Retrieves the naming context name bound to a thread. */ static Object getThreadName() throws NamingException { Object name = threadNameBindings.get(Thread.currentThread()); if (name == null) throw new NamingException (sm.getString("contextBindings.noContextBoundToThread")); return name; } /** * Tests if current thread is bound to a context. */ public static boolean isThreadBound() { return (threadBindings.containsKey(Thread.currentThread())); } /** * Binds a naming context to a class loader. * * @param name Name of the context * * @deprecated - unused */ @Deprecated public static void bindClassLoader(Object name) throws NamingException { bindClassLoader(name, null); } /** * Binds a naming context to a thread. * * @param name Name of the context * @param token Security token * * @deprecated - unused */ @Deprecated public static void bindClassLoader(Object name, Object token) throws NamingException { bindClassLoader (name, token, Thread.currentThread().getContextClassLoader()); } /** * Binds a naming context to a thread. * * @param name Name of the context * @param token Security token */ public static void bindClassLoader(Object name, Object token, ClassLoader classLoader) throws NamingException { if (ContextAccessController.checkSecurityToken(name, token)) { Context context = contextNameBindings.get(name); if (context == null) throw new NamingException (sm.getString("contextBindings.unknownContext", name)); clBindings.put(classLoader, context); clNameBindings.put(classLoader, name); } } /** * Unbinds a naming context to a class loader. * * @param name Name of the context * * @deprecated - unused */ @Deprecated public static void unbindClassLoader(Object name) { unbindClassLoader(name, null); } /** * Unbinds a naming context to a class loader. * * @param name Name of the context * @param token Security token * * @deprecated - unused */ @Deprecated public static void unbindClassLoader(Object name, Object token) { unbindClassLoader(name, token, Thread.currentThread().getContextClassLoader()); } /** * Unbinds a naming context to a class loader. * * @param name Name of the context * @param token Security token */ public static void unbindClassLoader(Object name, Object token, ClassLoader classLoader) { if (ContextAccessController.checkSecurityToken(name, token)) { Object n = clNameBindings.get(classLoader); if ((n==null) || !(n.equals(name))) { return; } clBindings.remove(classLoader); clNameBindings.remove(classLoader); } } /** * Retrieves the naming context bound to a class loader. */ public static Context getClassLoader() throws NamingException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Context context = null; do { context = clBindings.get(cl); if (context != null) { return context; } } while ((cl = cl.getParent()) != null); throw new NamingException (sm.getString("contextBindings.noContextBoundToCL")); } /** * Retrieves the naming context name bound to a class loader. */ static Object getClassLoaderName() throws NamingException { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Object name = null; do { name = clNameBindings.get(cl); if (name != null) { return name; } } while ((cl = cl.getParent()) != null); throw new NamingException (sm.getString("contextBindings.noContextBoundToCL")); } /** * Tests if current class loader is bound to a context. */ public static boolean isClassLoaderBound() { ClassLoader cl = Thread.currentThread().getContextClassLoader(); do { if (clBindings.containsKey(cl)) { return true; } } while ((cl = cl.getParent()) != null); return false; } } tomcat7-7.0.52/java/org/apache/naming/package.html0000644000175100017510000000156312271454623021641 0ustar locutuslocutus

    This package contains a memory based naming service provider.

    tomcat7-7.0.52/java/org/apache/naming/HandlerRef.java0000644000175100017510000001132612271454623022233 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Enumeration; import javax.naming.Context; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.StringRefAddr; /** * Represents a reference handler for a web service. * * @author Fabien Carrion */ public class HandlerRef extends Reference { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants /** * Default factory for this reference. */ public static final String DEFAULT_FACTORY = org.apache.naming.factory.Constants.DEFAULT_HANDLER_FACTORY; /** * HandlerName address type. */ public static final String HANDLER_NAME = "handlername"; /** * Handler Classname address type. */ public static final String HANDLER_CLASS = "handlerclass"; /** * Handler Classname address type. */ public static final String HANDLER_LOCALPART = "handlerlocalpart"; /** * Handler Classname address type. */ public static final String HANDLER_NAMESPACE = "handlernamespace"; /** * Handler Classname address type. */ public static final String HANDLER_PARAMNAME = "handlerparamname"; /** * Handler Classname address type. */ public static final String HANDLER_PARAMVALUE = "handlerparamvalue"; /** * Handler SoapRole address type. */ public static final String HANDLER_SOAPROLE = "handlersoaprole"; /** * Handler PortName address type. */ public static final String HANDLER_PORTNAME = "handlerportname"; // ----------------------------------------------------------- Constructors public HandlerRef(String refname, String handlerClass) { this(refname, handlerClass, null, null); } public HandlerRef(String refname, String handlerClass, String factory, String factoryLocation) { super(refname, factory, factoryLocation); StringRefAddr refAddr = null; if (refname != null) { refAddr = new StringRefAddr(HANDLER_NAME, refname); add(refAddr); } if (handlerClass != null) { refAddr = new StringRefAddr(HANDLER_CLASS, handlerClass); add(refAddr); } } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------ Reference Methods /** * Retrieves the class name of the factory of the object to which this * reference refers. */ @Override public String getFactoryClassName() { String factory = super.getFactoryClassName(); if (factory != null) { return factory; } else { factory = System.getProperty(Context.OBJECT_FACTORIES); if (factory != null) { return null; } else { return DEFAULT_FACTORY; } } } // --------------------------------------------------------- Public Methods /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("HandlerRef["); sb.append("className="); sb.append(getClassName()); sb.append(",factoryClassLocation="); sb.append(getFactoryClassLocation()); sb.append(",factoryClassName="); sb.append(getFactoryClassName()); Enumeration refAddrs = getAll(); while (refAddrs.hasMoreElements()) { RefAddr refAddr = refAddrs.nextElement(); sb.append(",{type="); sb.append(refAddr.getType()); sb.append(",content="); sb.append(refAddr.getContent()); sb.append("}"); } sb.append("]"); return (sb.toString()); } // ------------------------------------------------------------- Properties } tomcat7-7.0.52/java/org/apache/naming/ResourceEnvRef.java0000644000175100017510000000530012271454623023111 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import javax.naming.Context; import javax.naming.Reference; /** * Represents a reference address to a resource environment. * * @author Remy Maucherat */ public class ResourceEnvRef extends Reference { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants /** * Default factory for this reference. */ public static final String DEFAULT_FACTORY = org.apache.naming.factory.Constants.DEFAULT_RESOURCE_ENV_FACTORY; // ----------------------------------------------------------- Constructors /** * Resource env reference. * * @param resourceType Type */ public ResourceEnvRef(String resourceType) { super(resourceType); } /** * Resource env reference. * * @param resourceType Type * @param factory The factory class * @param factoryLocation The factory location */ public ResourceEnvRef(String resourceType, String factory, String factoryLocation) { super(resourceType, factory, factoryLocation); } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------ Reference Methods /** * Retrieves the class name of the factory of the object to which this * reference refers. */ @Override public String getFactoryClassName() { String factory = super.getFactoryClassName(); if (factory != null) { return factory; } else { factory = System.getProperty(Context.OBJECT_FACTORIES); if (factory != null) { return null; } else { return DEFAULT_FACTORY; } } } // ------------------------------------------------------------- Properties } tomcat7-7.0.52/java/org/apache/naming/JndiPermission.java0000644000175100017510000000376012271454623023161 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.security.BasicPermission; /** * Java SecurityManager Permission class for JNDI name based file resources *

    * The JndiPermission extends the BasicPermission. * The permission name is a full or partial jndi resource name. * An * can be used at the end of the name to match all named * resources that start with name. There are no actions.

    *

    * Example that grants permission to read all JNDI file based resources: *

  • permission org.apache.naming.JndiPermission "*";
  • *

    * * @author Glenn Nielsen */ public final class JndiPermission extends BasicPermission { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Creates a new JndiPermission with no actions * * @param name - JNDI resource path name */ public JndiPermission(String name) { super(name); } /** * Creates a new JndiPermission with actions * * @param name - JNDI resource path name * @param actions - JNDI actions (none defined) */ public JndiPermission(String name, String actions) { super(name,actions); } } tomcat7-7.0.52/java/org/apache/naming/SelectorContext.java0000644000175100017510000006517212271454623023356 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Hashtable; import javax.naming.Binding; import javax.naming.Context; import javax.naming.Name; import javax.naming.NameClassPair; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; /** * Catalina JNDI Context implementation. * * @author Remy Maucherat */ public class SelectorContext implements Context { // -------------------------------------------------------------- Constants /** * Namespace URL. */ public static final String prefix = "java:"; /** * Namespace URL length. */ public static final int prefixLength = prefix.length(); /** * Initial context prefix. */ public static final String IC_PREFIX = "IC_"; private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(SelectorContext.class); // ----------------------------------------------------------- Constructors /** * Builds a Catalina selector context using the given environment. */ public SelectorContext(Hashtable env) { this.env = env; } /** * Builds a Catalina selector context using the given environment. */ public SelectorContext(Hashtable env, boolean initialContext) { this(env); this.initialContext = initialContext; } // ----------------------------------------------------- Instance Variables /** * Environment. */ protected Hashtable env; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Request for an initial context. */ protected boolean initialContext = false; // --------------------------------------------------------- Public Methods // -------------------------------------------------------- Context Methods /** * Retrieves the named object. If name is empty, returns a new instance * of this context (which represents the same naming context as this * context, but its environment may be modified independently and it may * be accessed concurrently). * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public Object lookup(Name name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingName", "lookup", name)); } // Strip the URL header // Find the appropriate NamingContext according to the current bindings // Execute the lookup on that context return getBoundContext().lookup(parseName(name)); } /** * Retrieves the named object. * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public Object lookup(String name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingString", "lookup", name)); } // Strip the URL header // Find the appropriate NamingContext according to the current bindings // Execute the lookup on that context return getBoundContext().lookup(parseName(name)); } /** * Binds a name to an object. All intermediate contexts and the target * context (that named by all but terminal atomic component of the name) * must already exist. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if object did not * supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(Name name, Object obj) throws NamingException { getBoundContext().bind(parseName(name), obj); } /** * Binds a name to an object. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if object did not * supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(String name, Object obj) throws NamingException { getBoundContext().bind(parseName(name), obj); } /** * Binds a name to an object, overwriting any existing binding. All * intermediate contexts and the target context (that named by all but * terminal atomic component of the name) must already exist. *

    * If the object is a DirContext, any existing attributes associated with * the name are replaced with those of the object. Otherwise, any * existing attributes associated with the name remain unchanged. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object did not * supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(Name name, Object obj) throws NamingException { getBoundContext().rebind(parseName(name), obj); } /** * Binds a name to an object, overwriting any existing binding. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object did not * supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj) throws NamingException { getBoundContext().rebind(parseName(name), obj); } /** * Unbinds the named object. Removes the terminal atomic name in name * from the target context--that named by all but the terminal atomic * part of name. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * @param name the name to bind; may not be empty * @exception javax.naming NameNotFoundException if an intermediate context * does not exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(Name name) throws NamingException { getBoundContext().unbind(parseName(name)); } /** * Unbinds the named object. * * @param name the name to bind; may not be empty * @exception javax.naming NameNotFoundException if an intermediate context * does not exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(String name) throws NamingException { getBoundContext().unbind(parseName(name)); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. Both names are relative to this context. Any attributes * associated with the old name become associated with the new name. * Intermediate contexts of the old name are not changed. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(Name oldName, Name newName) throws NamingException { getBoundContext().rename(parseName(oldName), parseName(newName)); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(String oldName, String newName) throws NamingException { getBoundContext().rename(parseName(oldName), parseName(newName)); } /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. The contents of any subcontexts are * not included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(Name name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingName", "list", name)); } return getBoundContext().list(parseName(name)); } /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(String name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingString", "list", name)); } return getBoundContext().list(parseName(name)); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. The contents of any subcontexts are not * included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration listBindings(Name name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingName", "listBindings", name)); } return getBoundContext().listBindings(parseName(name)); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration listBindings(String name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingString", "listBindings", name)); } return getBoundContext().listBindings(parseName(name)); } /** * Destroys the named context and removes it from the namespace. Any * attributes associated with the name are also removed. Intermediate * contexts are not destroyed. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * In a federated naming system, a context from one naming system may be * bound to a name in another. One can subsequently look up and perform * operations on the foreign context using a composite name. However, an * attempt destroy the context using this composite name will fail with * NotContextException, because the foreign context is not a "subcontext" * of the context in which it is bound. Instead, use unbind() to remove * the binding of the foreign context. Destroying the foreign context * requires that the destroySubcontext() be performed on a context from * the foreign context's "native" naming system. * * @param name the name of the context to be destroyed; may not be empty * @exception javax.naming NameNotFoundException if an intermediate context * does not exist * @exception javax.naming.NotContextException if the name is bound but does * not name a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(Name name) throws NamingException { getBoundContext().destroySubcontext(parseName(name)); } /** * Destroys the named context and removes it from the namespace. * * @param name the name of the context to be destroyed; may not be empty * @exception javax.naming NameNotFoundException if an intermediate context * does not exist * @exception javax.naming.NotContextException if the name is bound but does * not name a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(String name) throws NamingException { getBoundContext().destroySubcontext(parseName(name)); } /** * Creates and binds a new context. Creates a new context with the given * name and binds it in the target context (that named by all but * terminal atomic component of the name). All intermediate contexts and * the target context must already exist. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if creation of the * sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(Name name) throws NamingException { return getBoundContext().createSubcontext(parseName(name)); } /** * Creates and binds a new context. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception javax.naming.NameAlreadyBoundException if name is already * bound * @exception javax.naming.directory.InvalidAttributesException if creation of the * sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(String name) throws NamingException { return getBoundContext().createSubcontext(parseName(name)); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. If the object bound to name is not a * link, returns the object itself. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(Name name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingName", "lookupLink", name)); } return getBoundContext().lookupLink(parseName(name)); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(String name) throws NamingException { if (log.isDebugEnabled()) { log.debug(sm.getString("selectorContext.methodUsingString", "lookupLink", name)); } return getBoundContext().lookupLink(parseName(name)); } /** * Retrieves the parser associated with the named context. In a * federation of namespaces, different naming systems will parse names * differently. This method allows an application to get a parser for * parsing names into their atomic components using the naming convention * of a particular naming system. Within any single naming system, * NameParser objects returned by this method must be equal (using the * equals() test). * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(Name name) throws NamingException { return getBoundContext().getNameParser(parseName(name)); } /** * Retrieves the parser associated with the named context. * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(String name) throws NamingException { return getBoundContext().getNameParser(parseName(name)); } /** * Composes the name of this context with a name relative to this context. *

    * Given a name (name) relative to this context, and the name (prefix) * of this context relative to one of its ancestors, this method returns * the composition of the two names using the syntax appropriate for the * naming system(s) involved. That is, if name names an object relative * to this context, the result is the name of the same object, but * relative to the ancestor context. None of the names may be null. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public Name composeName(Name name, Name prefix) throws NamingException { Name prefixClone = (Name) prefix.clone(); return prefixClone.addAll(name); } /** * Composes the name of this context with a name relative to this context. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public String composeName(String name, String prefix) throws NamingException { return prefix + "/" + name; } /** * Adds a new environment property to the environment of this context. If * the property already exists, its value is overwritten. * * @param propName the name of the environment property to add; may not * be null * @param propVal the value of the property to add; may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object addToEnvironment(String propName, Object propVal) throws NamingException { return getBoundContext().addToEnvironment(propName, propVal); } /** * Removes an environment property from the environment of this context. * * @param propName the name of the environment property to remove; * may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object removeFromEnvironment(String propName) throws NamingException { return getBoundContext().removeFromEnvironment(propName); } /** * Retrieves the environment in effect for this context. See class * description for more details on environment properties. * The caller should not make any changes to the object returned: their * effect on the context is undefined. The environment of this context * may be changed using addToEnvironment() and removeFromEnvironment(). * * @return the environment of this context; never null * @exception NamingException if a naming exception is encountered */ @Override public Hashtable getEnvironment() throws NamingException { return getBoundContext().getEnvironment(); } /** * Closes this context. This method releases this context's resources * immediately, instead of waiting for them to be released automatically * by the garbage collector. * This method is idempotent: invoking it on a context that has already * been closed has no effect. Invoking any other method on a closed * context is not allowed, and results in undefined behaviour. * * @exception NamingException if a naming exception is encountered */ @Override public void close() throws NamingException { getBoundContext().close(); } /** * Retrieves the full name of this context within its own namespace. *

    * Many naming services have a notion of a "full name" for objects in * their respective namespaces. For example, an LDAP entry has a * distinguished name, and a DNS record has a fully qualified name. This * method allows the client application to retrieve this name. The string * returned by this method is not a JNDI composite name and should not be * passed directly to context methods. In naming systems for which the * notion of full name does not make sense, * OperationNotSupportedException is thrown. * * @return this context's name in its own namespace; never null * @exception javax.naming.OperationNotSupportedException if the naming * system does not have the notion of a full name * @exception NamingException if a naming exception is encountered */ @Override public String getNameInNamespace() throws NamingException { return prefix; } // ------------------------------------------------------ Protected Methods /** * Get the bound context. */ protected Context getBoundContext() throws NamingException { if (initialContext) { String ICName = IC_PREFIX; if (ContextBindings.isThreadBound()) { ICName += ContextBindings.getThreadName(); } else if (ContextBindings.isClassLoaderBound()) { ICName += ContextBindings.getClassLoaderName(); } Context initialContext = ContextBindings.getContext(ICName); if (initialContext == null) { // Allocating a new context and binding it to the appropriate // name initialContext = new NamingContext(env, ICName); ContextBindings.bindContext(ICName, initialContext); } return initialContext; } else { if (ContextBindings.isThreadBound()) { return ContextBindings.getThread(); } else { return ContextBindings.getClassLoader(); } } } /** * Strips the URL header. * * @return the parsed name * @exception NamingException if there is no "java:" header or if no * naming context has been bound to this thread */ protected String parseName(String name) throws NamingException { if ((!initialContext) && (name.startsWith(prefix))) { return (name.substring(prefixLength)); } else { if (initialContext) { return (name); } else { throw new NamingException (sm.getString("selectorContext.noJavaUrl")); } } } /** * Strips the URL header. * * @return the parsed name * @exception NamingException if there is no "java:" header or if no * naming context has been bound to this thread */ protected Name parseName(Name name) throws NamingException { if (!initialContext && !name.isEmpty() && name.get(0).startsWith(prefix)) { if (name.get(0).equals(prefix)) { return name.getSuffix(1); } else { Name result = name.getSuffix(1); result.add(0, name.get(0).substring(prefixLength)); return result; } } else { if (initialContext) { return name; } else { throw new NamingException( sm.getString("selectorContext.noJavaUrl")); } } } } tomcat7-7.0.52/java/org/apache/naming/Constants.java0000644000175100017510000000215612271454623022176 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; /** * Static constants for this package. */ public final class Constants { public static final String Package = "org.apache.naming"; /** * Has security been turned on? */ public static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); } tomcat7-7.0.52/java/org/apache/naming/LocalStrings.properties0000644000175100017510000000324512271454623024101 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. contextBindings.unknownContext=Unknown context name : {0} contextBindings.noContextBoundToThread=No naming context bound to this thread contextBindings.noContextBoundToCL=No naming context bound to this class loader selectorContext.noJavaUrl=This context must be accessed through a java: URL selectorContext.methodUsingName=Call to method ''{0}'' with a Name of ''{1}'' selectorContext.methodUsingString=Call to method ''{0}'' with a String of ''{1}'' namingContext.contextExpected=Name is not bound to a Context namingContext.failResolvingReference=Unexpected exception resolving reference namingContext.nameNotBound=Name [{0}] is not bound in this Context. Unable to find [{1}]. namingContext.readOnly=Context is read only namingContext.invalidName=Name is not valid namingContext.alreadyBound=Name {0} is already bound in this Context namingContext.noAbsoluteName=Can''t generate an absolute name for this namespace tomcat7-7.0.52/java/org/apache/naming/NameParserImpl.java0000644000175100017510000000307612271454623023103 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import javax.naming.CompositeName; import javax.naming.Name; import javax.naming.NameParser; import javax.naming.NamingException; /** * Parses names. * * @author Remy Maucherat */ public class NameParserImpl implements NameParser { // ----------------------------------------------------- Instance Variables // ----------------------------------------------------- NameParser Methods /** * Parses a name into its components. * * @param name The non-null string name to parse * @return A non-null parsed form of the name using the naming convention * of this parser. */ @Override public Name parse(String name) throws NamingException { return new CompositeName(name); } } tomcat7-7.0.52/java/org/apache/naming/NamingEntry.java0000644000175100017510000000403312271454623022451 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; /** * Represents a binding in a NamingContext. * * @author Remy Maucherat */ public class NamingEntry { // -------------------------------------------------------------- Constants public static final int ENTRY = 0; public static final int LINK_REF = 1; public static final int REFERENCE = 2; public static final int CONTEXT = 10; // ----------------------------------------------------------- Constructors public NamingEntry(String name, Object value, int type) { this.name = name; this.value = value; this.type = type; } // ----------------------------------------------------- Instance Variables /** * The type instance variable is used to avoid using RTTI when doing * lookups. */ public int type; public String name; public Object value; // --------------------------------------------------------- Object Methods @Override public boolean equals(Object obj) { if (obj instanceof NamingEntry) { return name.equals(((NamingEntry) obj).name); } else { return false; } } @Override public int hashCode() { return name.hashCode(); } } tomcat7-7.0.52/java/org/apache/naming/ServiceRef.java0000644000175100017510000001344612271454623022263 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Enumeration; import java.util.Vector; import javax.naming.Context; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.StringRefAddr; /** * Represents a reference web service. * * @author Fabien Carrion */ public class ServiceRef extends Reference { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants /** * Default factory for this reference. */ public static final String DEFAULT_FACTORY = org.apache.naming.factory.Constants.DEFAULT_SERVICE_FACTORY; /** * Service Classname address type. */ public static final String SERVICE_INTERFACE = "serviceInterface"; /** * ServiceQname address type. */ public static final String SERVICE_NAMESPACE = "service namespace"; public static final String SERVICE_LOCAL_PART = "service local part"; /** * Wsdl Location address type. */ public static final String WSDL = "wsdl"; /** * Jaxrpcmapping address type. */ public static final String JAXRPCMAPPING = "jaxrpcmapping"; /** * port-component-ref/port-component-link address type. */ public static final String PORTCOMPONENTLINK = "portcomponentlink"; /** * port-component-ref/service-endpoint-interface address type. */ public static final String SERVICEENDPOINTINTERFACE = "serviceendpointinterface"; /** * The vector to save the handler Reference objects, because they can't be saved in the addrs vector. */ private Vector handlers = new Vector(); // ----------------------------------------------------------- Constructors public ServiceRef(String refname, String serviceInterface, String[] serviceQname, String wsdl, String jaxrpcmapping) { this(refname, serviceInterface, serviceQname, wsdl, jaxrpcmapping, null, null); } public ServiceRef(@SuppressWarnings("unused") String refname, String serviceInterface, String[] serviceQname, String wsdl, String jaxrpcmapping, String factory, String factoryLocation) { super(serviceInterface, factory, factoryLocation); StringRefAddr refAddr = null; if (serviceInterface != null) { refAddr = new StringRefAddr(SERVICE_INTERFACE, serviceInterface); add(refAddr); } if (serviceQname[0] != null) { refAddr = new StringRefAddr(SERVICE_NAMESPACE, serviceQname[0]); add(refAddr); } if (serviceQname[1] != null) { refAddr = new StringRefAddr(SERVICE_LOCAL_PART, serviceQname[1]); add(refAddr); } if (wsdl != null) { refAddr = new StringRefAddr(WSDL, wsdl); add(refAddr); } if (jaxrpcmapping != null) { refAddr = new StringRefAddr(JAXRPCMAPPING, jaxrpcmapping); add(refAddr); } } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------ Reference Methods /** * Add and Get Handlers classes. */ public HandlerRef getHandler() { return handlers.remove(0); } public int getHandlersSize() { return handlers.size(); } public void addHandler(HandlerRef handler) { handlers.add(handler); } /** * Retrieves the class name of the factory of the object to which this * reference refers. */ @Override public String getFactoryClassName() { String factory = super.getFactoryClassName(); if (factory != null) { return factory; } else { factory = System.getProperty(Context.OBJECT_FACTORIES); if (factory != null) { return null; } else { return DEFAULT_FACTORY; } } } // --------------------------------------------------------- Public Methods /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ServiceRef["); sb.append("className="); sb.append(getClassName()); sb.append(",factoryClassLocation="); sb.append(getFactoryClassLocation()); sb.append(",factoryClassName="); sb.append(getFactoryClassName()); Enumeration refAddrs = getAll(); while (refAddrs.hasMoreElements()) { RefAddr refAddr = refAddrs.nextElement(); sb.append(",{type="); sb.append(refAddr.getType()); sb.append(",content="); sb.append(refAddr.getContent()); sb.append("}"); } sb.append("]"); return (sb.toString()); } // ------------------------------------------------------------- Properties } tomcat7-7.0.52/java/org/apache/naming/ResourceLinkRef.java0000644000175100017510000000607512271454623023270 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import javax.naming.Context; import javax.naming.Reference; import javax.naming.StringRefAddr; /** * Represents a reference address to a resource. * * @author Remy Maucherat */ public class ResourceLinkRef extends Reference { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants /** * Default factory for this reference. */ public static final String DEFAULT_FACTORY = org.apache.naming.factory.Constants.DEFAULT_RESOURCE_LINK_FACTORY; /** * Description address type. */ public static final String GLOBALNAME = "globalName"; // ----------------------------------------------------------- Constructors /** * ResourceLink Reference. * * @param resourceClass Resource class * @param globalName Global name */ public ResourceLinkRef(String resourceClass, String globalName) { this(resourceClass, globalName, null, null); } /** * ResourceLink Reference. * * @param resourceClass Resource class * @param globalName Global name */ public ResourceLinkRef(String resourceClass, String globalName, String factory, String factoryLocation) { super(resourceClass, factory, factoryLocation); StringRefAddr refAddr = null; if (globalName != null) { refAddr = new StringRefAddr(GLOBALNAME, globalName); add(refAddr); } } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------ Reference Methods /** * Retrieves the class name of the factory of the object to which this * reference refers. */ @Override public String getFactoryClassName() { String factory = super.getFactoryClassName(); if (factory != null) { return factory; } else { factory = System.getProperty(Context.OBJECT_FACTORIES); if (factory != null) { return null; } else { return DEFAULT_FACTORY; } } } // ------------------------------------------------------------- Properties } tomcat7-7.0.52/java/org/apache/naming/LocalStrings_ja.properties0000644000175100017510000000473112271454623024554 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. contextBindings.unknownContext=\u672a\u77e5\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u540d\u3067\u3059: {0} contextBindings.noContextBoundToThread=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 contextBindings.noContextBoundToCL=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 selectorContext.noJavaUrl=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u306fjava: URL\u3092\u7528\u3044\u3066\u30a2\u30af\u30bb\u30b9\u3055\u308c\u306d\u3070\u3044\u3051\u307e\u305b\u3093 namingContext.contextExpected=\u540d\u524d\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 namingContext.failResolvingReference=\u53c2\u7167\u306e\u89e3\u6c7a\u4e2d\u306b\u4e88\u6e2c\u3057\u306a\u3044\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f namingContext.nameNotBound=\u540d\u524d {0} \u306f\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 namingContext.readOnly=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u30ea\u30fc\u30c9\u30aa\u30f3\u30ea\u30fc\u3067\u3059 namingContext.invalidName=\u540d\u524d\u306f\u7121\u52b9\u3067\u3059 namingContext.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059 namingContext.noAbsoluteName=\u3053\u306e\u540d\u524d\u7a7a\u9593\u306b\u7d76\u5bfe\u540d\u3092\u751f\u6210\u3067\u304d\u307e\u305b\u3093 tomcat7-7.0.52/java/org/apache/naming/NamingContext.java0000644000175100017510000010422412271454623022777 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import javax.naming.Binding; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.LinkRef; import javax.naming.Name; import javax.naming.NameAlreadyBoundException; import javax.naming.NameClassPair; import javax.naming.NameNotFoundException; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.NotContextException; import javax.naming.OperationNotSupportedException; import javax.naming.Reference; import javax.naming.Referenceable; import javax.naming.spi.NamingManager; /** * Catalina JNDI Context implementation. * * @author Remy Maucherat */ public class NamingContext implements Context { // -------------------------------------------------------------- Constants /** * Name parser for this context. */ protected static final NameParser nameParser = new NameParserImpl(); private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(NamingContext.class); // ----------------------------------------------------------- Constructors /** * Builds a naming context using the given environment. */ public NamingContext(Hashtable env, String name) throws NamingException { this.bindings = new HashMap(); this.env = new Hashtable(); // FIXME ? Could be put in the environment ? this.name = name; // Populating the environment hashtable if (env != null ) { Enumeration envEntries = env.keys(); while (envEntries.hasMoreElements()) { String entryName = envEntries.nextElement(); addToEnvironment(entryName, env.get(entryName)); } } } /** * Builds a naming context using the given environment. */ public NamingContext(Hashtable env, String name, HashMap bindings) throws NamingException { this(env, name); this.bindings = bindings; } // ----------------------------------------------------- Instance Variables /** * Environment. */ protected Hashtable env; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Bindings in this Context. */ protected HashMap bindings; /** * Name of the associated Catalina Context. */ protected String name; /** * Determines if an attempt to write to a read-only context results in an * exception or if the request is ignored. */ private boolean exceptionOnFailedWrite = true; public boolean getExceptionOnFailedWrite() { return exceptionOnFailedWrite; } public void setExceptionOnFailedWrite(boolean exceptionOnFailedWrite) { this.exceptionOnFailedWrite = exceptionOnFailedWrite; } // -------------------------------------------------------- Context Methods /** * Retrieves the named object. If name is empty, returns a new instance * of this context (which represents the same naming context as this * context, but its environment may be modified independently and it may * be accessed concurrently). * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public Object lookup(Name name) throws NamingException { return lookup(name, true); } /** * Retrieves the named object. * * @param name the name of the object to look up * @return the object bound to name * @exception NamingException if a naming exception is encountered */ @Override public Object lookup(String name) throws NamingException { return lookup(new CompositeName(name), true); } /** * Binds a name to an object. All intermediate contexts and the target * context (that named by all but terminal atomic component of the name) * must already exist. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception NameAlreadyBoundException if name is already bound * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(Name name, Object obj) throws NamingException { bind(name, obj, false); } /** * Binds a name to an object. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception NameAlreadyBoundException if name is already bound * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void bind(String name, Object obj) throws NamingException { bind(new CompositeName(name), obj); } /** * Binds a name to an object, overwriting any existing binding. All * intermediate contexts and the target context (that named by all but * terminal atomic component of the name) must already exist. *

    * If the object is a DirContext, any existing attributes associated with * the name are replaced with those of the object. Otherwise, any * existing attributes associated with the name remain unchanged. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(Name name, Object obj) throws NamingException { bind(name, obj, true); } /** * Binds a name to an object, overwriting any existing binding. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public void rebind(String name, Object obj) throws NamingException { rebind(new CompositeName(name), obj); } /** * Unbinds the named object. Removes the terminal atomic name in name * from the target context--that named by all but the terminal atomic * part of name. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * @param name the name to bind; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(Name name) throws NamingException { if (!checkWritable()) { return; } while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1); if (name.isEmpty()) throw new NamingException (sm.getString("namingContext.invalidName")); NamingEntry entry = bindings.get(name.get(0)); if (entry == null) { throw new NameNotFoundException (sm.getString("namingContext.nameNotBound", name, name.get(0))); } if (name.size() > 1) { if (entry.type == NamingEntry.CONTEXT) { ((Context) entry.value).unbind(name.getSuffix(1)); } else { throw new NamingException (sm.getString("namingContext.contextExpected")); } } else { bindings.remove(name.get(0)); } } /** * Unbinds the named object. * * @param name the name to bind; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NamingException if a naming exception is encountered */ @Override public void unbind(String name) throws NamingException { unbind(new CompositeName(name)); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. Both names are relative to this context. Any attributes * associated with the old name become associated with the new name. * Intermediate contexts of the old name are not changed. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception NameAlreadyBoundException if newName is already bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(Name oldName, Name newName) throws NamingException { Object value = lookup(oldName); bind(newName, value); unbind(oldName); } /** * Binds a new name to the object bound to an old name, and unbinds the * old name. * * @param oldName the name of the existing binding; may not be empty * @param newName the name of the new binding; may not be empty * @exception NameAlreadyBoundException if newName is already bound * @exception NamingException if a naming exception is encountered */ @Override public void rename(String oldName, String newName) throws NamingException { rename(new CompositeName(oldName), new CompositeName(newName)); } /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. The contents of any subcontexts are * not included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(Name name) throws NamingException { // Removing empty parts while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1); if (name.isEmpty()) { return new NamingContextEnumeration(bindings.values().iterator()); } NamingEntry entry = bindings.get(name.get(0)); if (entry == null) { throw new NameNotFoundException (sm.getString("namingContext.nameNotBound", name, name.get(0))); } if (entry.type != NamingEntry.CONTEXT) { throw new NamingException (sm.getString("namingContext.contextExpected")); } return ((Context) entry.value).list(name.getSuffix(1)); } /** * Enumerates the names bound in the named context, along with the class * names of objects bound to them. * * @param name the name of the context to list * @return an enumeration of the names and class names of the bindings in * this context. Each element of the enumeration is of type NameClassPair. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration list(String name) throws NamingException { return list(new CompositeName(name)); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. The contents of any subcontexts are not * included. *

    * If a binding is added to or removed from this context, its effect on * an enumeration previously returned is undefined. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration listBindings(Name name) throws NamingException { // Removing empty parts while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1); if (name.isEmpty()) { return new NamingContextBindingsEnumeration(bindings.values().iterator(), this); } NamingEntry entry = bindings.get(name.get(0)); if (entry == null) { throw new NameNotFoundException (sm.getString("namingContext.nameNotBound", name, name.get(0))); } if (entry.type != NamingEntry.CONTEXT) { throw new NamingException (sm.getString("namingContext.contextExpected")); } return ((Context) entry.value).listBindings(name.getSuffix(1)); } /** * Enumerates the names bound in the named context, along with the * objects bound to them. * * @param name the name of the context to list * @return an enumeration of the bindings in this context. * Each element of the enumeration is of type Binding. * @exception NamingException if a naming exception is encountered */ @Override public NamingEnumeration listBindings(String name) throws NamingException { return listBindings(new CompositeName(name)); } /** * Destroys the named context and removes it from the namespace. Any * attributes associated with the name are also removed. Intermediate * contexts are not destroyed. *

    * This method is idempotent. It succeeds even if the terminal atomic * name is not bound in the target context, but throws * NameNotFoundException if any of the intermediate contexts do not exist. * * In a federated naming system, a context from one naming system may be * bound to a name in another. One can subsequently look up and perform * operations on the foreign context using a composite name. However, an * attempt destroy the context using this composite name will fail with * NotContextException, because the foreign context is not a "subcontext" * of the context in which it is bound. Instead, use unbind() to remove * the binding of the foreign context. Destroying the foreign context * requires that the destroySubcontext() be performed on a context from * the foreign context's "native" naming system. * * @param name the name of the context to be destroyed; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NotContextException if the name is bound but does not name * a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(Name name) throws NamingException { if (!checkWritable()) { return; } while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1); if (name.isEmpty()) throw new NamingException (sm.getString("namingContext.invalidName")); NamingEntry entry = bindings.get(name.get(0)); if (entry == null) { throw new NameNotFoundException (sm.getString("namingContext.nameNotBound", name, name.get(0))); } if (name.size() > 1) { if (entry.type == NamingEntry.CONTEXT) { ((Context) entry.value).destroySubcontext(name.getSuffix(1)); } else { throw new NamingException (sm.getString("namingContext.contextExpected")); } } else { if (entry.type == NamingEntry.CONTEXT) { ((Context) entry.value).close(); bindings.remove(name.get(0)); } else { throw new NotContextException (sm.getString("namingContext.contextExpected")); } } } /** * Destroys the named context and removes it from the namespace. * * @param name the name of the context to be destroyed; may not be empty * @exception NameNotFoundException if an intermediate context does not * exist * @exception NotContextException if the name is bound but does not name * a context, or does not name a context of the appropriate type */ @Override public void destroySubcontext(String name) throws NamingException { destroySubcontext(new CompositeName(name)); } /** * Creates and binds a new context. Creates a new context with the given * name and binds it in the target context (that named by all but * terminal atomic component of the name). All intermediate contexts and * the target context must already exist. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception NameAlreadyBoundException if name is already bound * @exception javax.naming.directory.InvalidAttributesException if creation * of the sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(Name name) throws NamingException { if (!checkWritable()) { return null; } NamingContext newContext = new NamingContext(env, this.name); bind(name, newContext); newContext.setExceptionOnFailedWrite(getExceptionOnFailedWrite()); return newContext; } /** * Creates and binds a new context. * * @param name the name of the context to create; may not be empty * @return the newly created context * @exception NameAlreadyBoundException if name is already bound * @exception javax.naming.directory.InvalidAttributesException if creation * of the sub-context requires specification of mandatory attributes * @exception NamingException if a naming exception is encountered */ @Override public Context createSubcontext(String name) throws NamingException { return createSubcontext(new CompositeName(name)); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. If the object bound to name is not a * link, returns the object itself. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(Name name) throws NamingException { return lookup(name, false); } /** * Retrieves the named object, following links except for the terminal * atomic component of the name. * * @param name the name of the object to look up * @return the object bound to name, not following the terminal link * (if any). * @exception NamingException if a naming exception is encountered */ @Override public Object lookupLink(String name) throws NamingException { return lookup(new CompositeName(name), false); } /** * Retrieves the parser associated with the named context. In a * federation of namespaces, different naming systems will parse names * differently. This method allows an application to get a parser for * parsing names into their atomic components using the naming convention * of a particular naming system. Within any single naming system, * NameParser objects returned by this method must be equal (using the * equals() test). * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(Name name) throws NamingException { while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1); if (name.isEmpty()) return nameParser; if (name.size() > 1) { Object obj = bindings.get(name.get(0)); if (obj instanceof Context) { return ((Context) obj).getNameParser(name.getSuffix(1)); } else { throw new NotContextException (sm.getString("namingContext.contextExpected")); } } return nameParser; } /** * Retrieves the parser associated with the named context. * * @param name the name of the context from which to get the parser * @return a name parser that can parse compound names into their atomic * components * @exception NamingException if a naming exception is encountered */ @Override public NameParser getNameParser(String name) throws NamingException { return getNameParser(new CompositeName(name)); } /** * Composes the name of this context with a name relative to this context. *

    * Given a name (name) relative to this context, and the name (prefix) * of this context relative to one of its ancestors, this method returns * the composition of the two names using the syntax appropriate for the * naming system(s) involved. That is, if name names an object relative * to this context, the result is the name of the same object, but * relative to the ancestor context. None of the names may be null. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public Name composeName(Name name, Name prefix) throws NamingException { prefix = (Name) prefix.clone(); return prefix.addAll(name); } /** * Composes the name of this context with a name relative to this context. * * @param name a name relative to this context * @param prefix the name of this context relative to one of its ancestors * @return the composition of prefix and name * @exception NamingException if a naming exception is encountered */ @Override public String composeName(String name, String prefix) throws NamingException { return prefix + "/" + name; } /** * Adds a new environment property to the environment of this context. If * the property already exists, its value is overwritten. * * @param propName the name of the environment property to add; may not * be null * @param propVal the value of the property to add; may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object addToEnvironment(String propName, Object propVal) throws NamingException { return env.put(propName, propVal); } /** * Removes an environment property from the environment of this context. * * @param propName the name of the environment property to remove; * may not be null * @exception NamingException if a naming exception is encountered */ @Override public Object removeFromEnvironment(String propName) throws NamingException { return env.remove(propName); } /** * Retrieves the environment in effect for this context. See class * description for more details on environment properties. * The caller should not make any changes to the object returned: their * effect on the context is undefined. The environment of this context * may be changed using addToEnvironment() and removeFromEnvironment(). * * @return the environment of this context; never null * @exception NamingException if a naming exception is encountered */ @Override public Hashtable getEnvironment() throws NamingException { return env; } /** * Closes this context. This method releases this context's resources * immediately, instead of waiting for them to be released automatically * by the garbage collector. * This method is idempotent: invoking it on a context that has already * been closed has no effect. Invoking any other method on a closed * context is not allowed, and results in undefined behaviour. * * @exception NamingException if a naming exception is encountered */ @Override public void close() throws NamingException { if (!checkWritable()) { return; } env.clear(); } /** * Retrieves the full name of this context within its own namespace. *

    * Many naming services have a notion of a "full name" for objects in * their respective namespaces. For example, an LDAP entry has a * distinguished name, and a DNS record has a fully qualified name. This * method allows the client application to retrieve this name. The string * returned by this method is not a JNDI composite name and should not be * passed directly to context methods. In naming systems for which the * notion of full name does not make sense, * OperationNotSupportedException is thrown. * * @return this context's name in its own namespace; never null * @exception OperationNotSupportedException if the naming system does * not have the notion of a full name * @exception NamingException if a naming exception is encountered */ @Override public String getNameInNamespace() throws NamingException { throw new OperationNotSupportedException (sm.getString("namingContext.noAbsoluteName")); //FIXME ? } // ------------------------------------------------------ Protected Methods /** * Retrieves the named object. * * @param name the name of the object to look up * @param resolveLinks If true, the links will be resolved * @return the object bound to name * @exception NamingException if a naming exception is encountered */ protected Object lookup(Name name, boolean resolveLinks) throws NamingException { // Removing empty parts while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1); if (name.isEmpty()) { // If name is empty, a newly allocated naming context is returned return new NamingContext(env, this.name, bindings); } NamingEntry entry = bindings.get(name.get(0)); if (entry == null) { throw new NameNotFoundException (sm.getString("namingContext.nameNotBound", name, name.get(0))); } if (name.size() > 1) { // If the size of the name is greater that 1, then we go through a // number of subcontexts. if (entry.type != NamingEntry.CONTEXT) { throw new NamingException (sm.getString("namingContext.contextExpected")); } return ((Context) entry.value).lookup(name.getSuffix(1)); } else { if ((resolveLinks) && (entry.type == NamingEntry.LINK_REF)) { String link = ((LinkRef) entry.value).getLinkName(); if (link.startsWith(".")) { // Link relative to this context return lookup(link.substring(1)); } else { return (new InitialContext(env)).lookup(link); } } else if (entry.type == NamingEntry.REFERENCE) { try { Object obj = NamingManager.getObjectInstance (entry.value, name, this, env); if(entry.value instanceof ResourceRef) { boolean singleton = Boolean.parseBoolean( (String) ((ResourceRef) entry.value).get( "singleton").getContent()); if (singleton) { entry.type = NamingEntry.ENTRY; entry.value = obj; } } return obj; } catch (NamingException e) { throw e; } catch (Exception e) { log.warn(sm.getString ("namingContext.failResolvingReference"), e); throw new NamingException(e.getMessage()); } } else { return entry.value; } } } /** * Binds a name to an object. All intermediate contexts and the target * context (that named by all but terminal atomic component of the name) * must already exist. * * @param name the name to bind; may not be empty * @param obj the object to bind; possibly null * @param rebind if true, then perform a rebind (ie, overwrite) * @exception NameAlreadyBoundException if name is already bound * @exception javax.naming.directory.InvalidAttributesException if object * did not supply all mandatory attributes * @exception NamingException if a naming exception is encountered */ protected void bind(Name name, Object obj, boolean rebind) throws NamingException { if (!checkWritable()) { return; } while ((!name.isEmpty()) && (name.get(0).length() == 0)) name = name.getSuffix(1); if (name.isEmpty()) throw new NamingException (sm.getString("namingContext.invalidName")); NamingEntry entry = bindings.get(name.get(0)); if (name.size() > 1) { if (entry == null) { throw new NameNotFoundException(sm.getString( "namingContext.nameNotBound", name, name.get(0))); } if (entry.type == NamingEntry.CONTEXT) { if (rebind) { ((Context) entry.value).rebind(name.getSuffix(1), obj); } else { ((Context) entry.value).bind(name.getSuffix(1), obj); } } else { throw new NamingException (sm.getString("namingContext.contextExpected")); } } else { if ((!rebind) && (entry != null)) { throw new NameAlreadyBoundException (sm.getString("namingContext.alreadyBound", name.get(0))); } else { // Getting the type of the object and wrapping it within a new // NamingEntry Object toBind = NamingManager.getStateToBind(obj, name, this, env); if (toBind instanceof Context) { entry = new NamingEntry(name.get(0), toBind, NamingEntry.CONTEXT); } else if (toBind instanceof LinkRef) { entry = new NamingEntry(name.get(0), toBind, NamingEntry.LINK_REF); } else if (toBind instanceof Reference) { entry = new NamingEntry(name.get(0), toBind, NamingEntry.REFERENCE); } else if (toBind instanceof Referenceable) { toBind = ((Referenceable) toBind).getReference(); entry = new NamingEntry(name.get(0), toBind, NamingEntry.REFERENCE); } else { entry = new NamingEntry(name.get(0), toBind, NamingEntry.ENTRY); } bindings.put(name.get(0), entry); } } } /** * Returns true if writing is allowed on this context. */ protected boolean isWritable() { return ContextAccessController.isWritable(name); } /** * Throws a naming exception is Context is not writable. */ protected boolean checkWritable() throws NamingException { if (isWritable()) { return true; } else { if (exceptionOnFailedWrite) { throw new javax.naming.OperationNotSupportedException( sm.getString("namingContext.readOnly")); } } return false; } } tomcat7-7.0.52/java/org/apache/naming/NamingContextBindingsEnumeration.java0000644000175100017510000000657612271454623026677 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.util.Iterator; import javax.naming.Binding; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; /** * Naming enumeration implementation. * * @author Remy Maucherat */ public class NamingContextBindingsEnumeration implements NamingEnumeration { // ----------------------------------------------------------- Constructors public NamingContextBindingsEnumeration(Iterator entries, Context ctx) { iterator = entries; this.ctx = ctx; } // -------------------------------------------------------------- Variables /** * Underlying enumeration. */ protected Iterator iterator; /** * The context for which this enumeration is being generated. */ private Context ctx; // --------------------------------------------------------- Public Methods /** * Retrieves the next element in the enumeration. */ @Override public Binding next() throws NamingException { return nextElementInternal(); } /** * Determines whether there are any more elements in the enumeration. */ @Override public boolean hasMore() throws NamingException { return iterator.hasNext(); } /** * Closes this enumeration. */ @Override public void close() throws NamingException { } @Override public boolean hasMoreElements() { return iterator.hasNext(); } @Override public Binding nextElement() { try { return nextElementInternal(); } catch (NamingException e) { throw new RuntimeException(e.getMessage(), e); } } private Binding nextElementInternal() throws NamingException { NamingEntry entry = iterator.next(); Object value; // If the entry is a reference, resolve it if (entry.type == NamingEntry.REFERENCE || entry.type == NamingEntry.LINK_REF) { try { value = ctx.lookup(new CompositeName(entry.name)); } catch (NamingException e) { throw e; } catch (Exception e) { NamingException ne = new NamingException(e.getMessage()); ne.initCause(e); throw ne; } } else { value = entry.value; } return new Binding(entry.name, value.getClass().getName(), value, true); } } tomcat7-7.0.52/java/org/apache/naming/java/0000755000175100017510000000000012301126367020267 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/naming/java/package.html0000644000175100017510000000157512271454623022565 0ustar locutuslocutus

    This package contains the URL context factory for the "java" namespace.

    tomcat7-7.0.52/java/org/apache/naming/java/javaURLContextFactory.java0000644000175100017510000000746712271454623025356 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming.java; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; import javax.naming.spi.ObjectFactory; import org.apache.naming.ContextBindings; import org.apache.naming.NamingContext; import org.apache.naming.SelectorContext; /** * Context factory for the "java:" namespace. *

    * Important note : This factory MUST be associated with the "java" URL * prefix, which can be done by either : *

      *
    • Adding a * java.naming.factory.url.pkgs=org.apache.naming property * to the JNDI properties file
    • *
    • Setting an environment variable named Context.URL_PKG_PREFIXES with * its value including the org.apache.naming package name. * More detail about this can be found in the JNDI documentation : * {@link javax.naming.spi.NamingManager#getURLContext(java.lang.String, java.util.Hashtable)}.
    • *
    * * @author Remy Maucherat */ public class javaURLContextFactory implements ObjectFactory, InitialContextFactory { // ----------------------------------------------------------- Constructors // -------------------------------------------------------------- Constants public static final String MAIN = "initialContext"; // ----------------------------------------------------- Instance Variables /** * Initial context. */ protected static volatile Context initialContext = null; // --------------------------------------------------------- Public Methods // -------------------------------------------------- ObjectFactory Methods /** * Crete a new Context's instance. */ @SuppressWarnings("unchecked") @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws NamingException { if ((ContextBindings.isThreadBound()) || (ContextBindings.isClassLoaderBound())) { return new SelectorContext((Hashtable)environment); } return null; } /** * Get a new (writable) initial context. */ @SuppressWarnings("unchecked") @Override public Context getInitialContext(Hashtable environment) throws NamingException { if (ContextBindings.isThreadBound() || (ContextBindings.isClassLoaderBound())) { // Redirect the request to the bound initial context return new SelectorContext( (Hashtable)environment, true); } // If the thread is not bound, return a shared writable context if (initialContext == null) { synchronized(javaURLContextFactory.class) { if (initialContext == null) { initialContext = new NamingContext( (Hashtable)environment, MAIN); } } } return initialContext; } } tomcat7-7.0.52/java/org/apache/naming/LocalStrings_fr.properties0000644000175100017510000000323312271454623024565 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. contextBindings.unknownContext=Nom de Contexte inconnu : {0} contextBindings.noContextBoundToThread=Aucun Contexte de nommage li\u00e9 \u00e0 ce thread contextBindings.noContextBoundToCL=Aucun Contexte de nommage li\u00e9 \u00e0 ce chargeur de classes selectorContext.noJavaUrl=Ce Contexte doit \u00eatre acc\u00e9d\u00e9 par une java: URL namingContext.contextExpected=Le Nom n''est pas li\u00e9 \u00e0 un Contexte namingContext.failResolvingReference=Une erreur s est produite durant la r\u00e9solution de la r\u00e9f\u00e9rence namingContext.nameNotBound=Le Nom {0} n''est pas li\u00e9 \u00e0 ce Contexte namingContext.readOnly=Le Contexte est en lecture seule namingContext.invalidName=Le Nom est invalide namingContext.alreadyBound=Le Nom {0} est d\u00e9j\u00e0 li\u00e9 \u00e0 ce Contexte namingContext.noAbsoluteName=Impossible de g\u00e9n\u00e9rer un nom absolu pour cet espace de nommage (namespace) tomcat7-7.0.52/java/org/apache/naming/StringManager.java0000644000175100017510000001401312271454623022756 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.naming; import java.text.MessageFormat; import java.util.Hashtable; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; /** * An internationalization / localization helper class which reduces * the bother of handling ResourceBundles and takes care of the * common cases of message formating which otherwise require the * creation of Object arrays and such. * *

    The StringManager operates on a package basis. One StringManager * per package can be created and accessed via the getManager method * call. * *

    The StringManager will look for a ResourceBundle named by * the package name given plus the suffix of "LocalStrings". In * practice, this means that the localized information will be contained * in a LocalStrings.properties file located in the package * directory of the classpath. * *

    Please see the documentation for java.util.ResourceBundle for * more information. * * @author James Duncan Davidson [duncan@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Mel Martinez [mmartinez@g1440.com] * @see java.util.ResourceBundle */ public class StringManager { /** * The ResourceBundle for this StringManager. */ private ResourceBundle bundle; private Locale locale; /** * Creates a new StringManager for a given package. This is a * private method and all access to it is arbitrated by the * static getManager method call so that only one StringManager * per package will be created. * * @param packageName Name of package to create StringManager for. */ private StringManager(String packageName) { String bundleName = packageName + ".LocalStrings"; try { bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); } catch( MissingResourceException ex ) { // Try from the current loader (that's the case for trusted apps) // Should only be required if using a TC5 style classloader structure // where common != shared != server ClassLoader cl = Thread.currentThread().getContextClassLoader(); if( cl != null ) { try { bundle = ResourceBundle.getBundle( bundleName, Locale.getDefault(), cl); } catch(MissingResourceException ex2) { // Ignore } } } // Get the actual locale, which may be different from the requested one if (bundle != null) { locale = bundle.getLocale(); } } /** Get a string from the underlying resource bundle or return null if the String is not found. @param key to desired resource String @return resource String matching key from underlying bundle or null if not found. @throws IllegalArgumentException if key is null. */ public String getString(String key) { if(key == null){ String msg = "key may not have a null value"; throw new IllegalArgumentException(msg); } String str = null; try { str = bundle.getString(key); } catch(MissingResourceException mre) { //bad: shouldn't mask an exception the following way: // str = "[cannot find message associated with key '" + key + "' due to " + mre + "]"; // because it hides the fact that the String was missing // from the calling code. //good: could just throw the exception (or wrap it in another) // but that would probably cause much havoc on existing // code. //better: consistent with container pattern to // simply return null. Calling code can then do // a null check. str = null; } return str; } /** * Get a string from the underlying resource bundle and format * it with the given set of arguments. * * @param key * @param args */ public String getString(final String key, final Object... args) { String value = getString(key); if (value == null) { value = key; } MessageFormat mf = new MessageFormat(value); mf.setLocale(locale); return mf.format(args, new StringBuffer(), null).toString(); } // -------------------------------------------------------------- // STATIC SUPPORT METHODS // -------------------------------------------------------------- private static Hashtable managers = new Hashtable(); /** * Get the StringManager for a particular package. If a manager for * a package already exists, it will be reused, else a new * StringManager will be created and returned. * * @param packageName The package name */ public static final synchronized StringManager getManager(String packageName) { StringManager mgr = managers.get(packageName); if (mgr == null) { mgr = new StringManager(packageName); managers.put(packageName, mgr); } return mgr; } } tomcat7-7.0.52/java/org/apache/coyote/0000755000175100017510000000000012301126366017376 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/coyote/LocalStrings_es.properties0000644000175100017510000000152512012773207024613 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. abstractConnectionHandler.error = Error leyendo requerimiento, ignorado tomcat7-7.0.52/java/org/apache/coyote/InputBuffer.java0000644000175100017510000000276412271461367022514 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.io.IOException; import org.apache.tomcat.util.buf.ByteChunk; /** * Input buffer. * * This class is used only in the protocol implementation. All reading from * Tomcat ( or adapter ) should be done using Request.doRead(). * * * @author Remy Maucherat */ public interface InputBuffer { /** Return from the input stream. IMPORTANT: the current model assumes that the protocol will 'own' the buffer and return a pointer to it in ByteChunk ( i.e. the param will have chunk.getBytes()==null before call, and the result after the call ). */ public int doRead(ByteChunk chunk, Request request) throws IOException; } tomcat7-7.0.52/java/org/apache/coyote/Request.java0000644000175100017510000003315212271461367021706 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.io.IOException; import java.util.HashMap; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.buf.UDecoder; import org.apache.tomcat.util.http.ContentType; import org.apache.tomcat.util.http.Cookies; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.Parameters; /** * This is a low-level, efficient representation of a server request. Most * fields are GC-free, expensive operations are delayed until the user code * needs the information. * * Processing is delegated to modules, using a hook mechanism. * * This class is not intended for user code - it is used internally by tomcat * for processing the request in the most efficient way. Users ( servlets ) can * access the information using a facade, which provides the high-level view * of the request. * * For lazy evaluation, the request uses the getInfo() hook. The following ids * are defined: *

      *
    • req.encoding - returns the request encoding *
    • req.attribute - returns a module-specific attribute ( like SSL keys, etc ). *
    * * Tomcat defines a number of attributes: *
      *
    • "org.apache.tomcat.request" - allows access to the low-level * request object in trusted applications *
    * * @author James Duncan Davidson [duncan@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author Harish Prabandham * @author Alex Cruikshank [alex@epitonic.com] * @author Hans Bergsten [hans@gefionsoftware.com] * @author Costin Manolache * @author Remy Maucherat */ public final class Request { // ----------------------------------------------------------- Constructors public Request() { parameters.setQuery(queryMB); parameters.setURLDecoder(urlDecoder); } // ----------------------------------------------------- Instance Variables private int serverPort = -1; private MessageBytes serverNameMB = MessageBytes.newInstance(); private int remotePort; private int localPort; private MessageBytes schemeMB = MessageBytes.newInstance(); private MessageBytes methodMB = MessageBytes.newInstance(); private MessageBytes unparsedURIMB = MessageBytes.newInstance(); private MessageBytes uriMB = MessageBytes.newInstance(); private MessageBytes decodedUriMB = MessageBytes.newInstance(); private MessageBytes queryMB = MessageBytes.newInstance(); private MessageBytes protoMB = MessageBytes.newInstance(); // remote address/host private MessageBytes remoteAddrMB = MessageBytes.newInstance(); private MessageBytes localNameMB = MessageBytes.newInstance(); private MessageBytes remoteHostMB = MessageBytes.newInstance(); private MessageBytes localAddrMB = MessageBytes.newInstance(); private MimeHeaders headers = new MimeHeaders(); private MessageBytes instanceId = MessageBytes.newInstance(); /** * Notes. */ private Object notes[] = new Object[Constants.MAX_NOTES]; /** * Associated input buffer. */ private InputBuffer inputBuffer = null; /** * URL decoder. */ private UDecoder urlDecoder = new UDecoder(); /** * HTTP specific fields. (remove them ?) */ private long contentLength = -1; private MessageBytes contentTypeMB = null; private String charEncoding = null; private Cookies cookies = new Cookies(headers); private Parameters parameters = new Parameters(); private MessageBytes remoteUser=MessageBytes.newInstance(); private MessageBytes authType=MessageBytes.newInstance(); private HashMap attributes=new HashMap(); private Response response; private ActionHook hook; private int bytesRead=0; // Time of the request - useful to avoid repeated calls to System.currentTime private long startTime = -1; private int available = 0; private RequestInfo reqProcessorMX=new RequestInfo(this); // ------------------------------------------------------------- Properties /** * Get the instance id (or JVM route). Currently Ajp is sending it with each * request. In future this should be fixed, and sent only once ( or * 'negotiated' at config time so both tomcat and apache share the same name. * * @return the instance id */ public MessageBytes instanceId() { return instanceId; } public MimeHeaders getMimeHeaders() { return headers; } public UDecoder getURLDecoder() { return urlDecoder; } // -------------------- Request data -------------------- public MessageBytes scheme() { return schemeMB; } public MessageBytes method() { return methodMB; } public MessageBytes unparsedURI() { return unparsedURIMB; } public MessageBytes requestURI() { return uriMB; } public MessageBytes decodedURI() { return decodedUriMB; } public MessageBytes queryString() { return queryMB; } public MessageBytes protocol() { return protoMB; } /** * Return the buffer holding the server name, if * any. Use isNull() to check if there is no value * set. * This is the "virtual host", derived from the * Host: header. */ public MessageBytes serverName() { return serverNameMB; } public int getServerPort() { return serverPort; } public void setServerPort(int serverPort ) { this.serverPort=serverPort; } public MessageBytes remoteAddr() { return remoteAddrMB; } public MessageBytes remoteHost() { return remoteHostMB; } public MessageBytes localName() { return localNameMB; } public MessageBytes localAddr() { return localAddrMB; } public int getRemotePort(){ return remotePort; } public void setRemotePort(int port){ this.remotePort = port; } public int getLocalPort(){ return localPort; } public void setLocalPort(int port){ this.localPort = port; } // -------------------- encoding/type -------------------- /** * Get the character encoding used for this request. */ public String getCharacterEncoding() { if (charEncoding != null) return charEncoding; charEncoding = ContentType.getCharsetFromContentType(getContentType()); return charEncoding; } public void setCharacterEncoding(String enc) { this.charEncoding = enc; } public void setContentLength(long len) { this.contentLength = len; } public int getContentLength() { long length = getContentLengthLong(); if (length < Integer.MAX_VALUE) { return (int) length; } return -1; } public long getContentLengthLong() { if( contentLength > -1 ) return contentLength; MessageBytes clB = headers.getUniqueValue("content-length"); contentLength = (clB == null || clB.isNull()) ? -1 : clB.getLong(); return contentLength; } public String getContentType() { contentType(); if ((contentTypeMB == null) || contentTypeMB.isNull()) return null; return contentTypeMB.toString(); } public void setContentType(String type) { contentTypeMB.setString(type); } public MessageBytes contentType() { if (contentTypeMB == null) contentTypeMB = headers.getValue("content-type"); return contentTypeMB; } public void setContentType(MessageBytes mb) { contentTypeMB=mb; } public String getHeader(String name) { return headers.getHeader(name); } // -------------------- Associated response -------------------- public Response getResponse() { return response; } public void setResponse( Response response ) { this.response=response; response.setRequest( this ); } public void action(ActionCode actionCode, Object param) { if( hook==null && response!=null ) hook=response.getHook(); if (hook != null) { if( param==null ) hook.action(actionCode, this); else hook.action(actionCode, param); } } // -------------------- Cookies -------------------- public Cookies getCookies() { return cookies; } // -------------------- Parameters -------------------- public Parameters getParameters() { return parameters; } // -------------------- Other attributes -------------------- // We can use notes for most - need to discuss what is of general interest public void setAttribute( String name, Object o ) { attributes.put( name, o ); } public HashMap getAttributes() { return attributes; } public Object getAttribute(String name ) { return attributes.get(name); } public MessageBytes getRemoteUser() { return remoteUser; } public MessageBytes getAuthType() { return authType; } public int getAvailable() { return available; } public void setAvailable(int available) { this.available = available; } // -------------------- Input Buffer -------------------- public InputBuffer getInputBuffer() { return inputBuffer; } public void setInputBuffer(InputBuffer inputBuffer) { this.inputBuffer = inputBuffer; } /** * Read data from the input buffer and put it into a byte chunk. * * The buffer is owned by the protocol implementation - it will be reused on the next read. * The Adapter must either process the data in place or copy it to a separate buffer if it needs * to hold it. In most cases this is done during byte->char conversions or via InputStream. Unlike * InputStream, this interface allows the app to process data in place, without copy. * */ public int doRead(ByteChunk chunk) throws IOException { int n = inputBuffer.doRead(chunk, this); if (n > 0) { bytesRead+=n; } return n; } // -------------------- debug -------------------- @Override public String toString() { return "R( " + requestURI().toString() + ")"; } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime = startTime; } // -------------------- Per-Request "notes" -------------------- /** * Used to store private data. Thread data could be used instead - but * if you have the req, getting/setting a note is just a array access, may * be faster than ThreadLocal for very frequent operations. * * Example use: * Jk: * HandlerRequest.HOSTBUFFER = 10 CharChunk, buffer for Host decoding * WorkerEnv: SSL_CERT_NOTE=16 - MessageBytes containing the cert * * Catalina CoyoteAdapter: * ADAPTER_NOTES = 1 - stores the HttpServletRequest object ( req/res) * * To avoid conflicts, note in the range 0 - 8 are reserved for the * servlet container ( catalina connector, etc ), and values in 9 - 16 * for connector use. * * 17-31 range is not allocated or used. */ public final void setNote(int pos, Object value) { notes[pos] = value; } public final Object getNote(int pos) { return notes[pos]; } // -------------------- Recycling -------------------- public void recycle() { bytesRead=0; contentLength = -1; contentTypeMB = null; charEncoding = null; headers.recycle(); serverNameMB.recycle(); serverPort=-1; localNameMB.recycle(); localPort = -1; remotePort = -1; available = 0; cookies.recycle(); parameters.recycle(); unparsedURIMB.recycle(); uriMB.recycle(); decodedUriMB.recycle(); queryMB.recycle(); methodMB.recycle(); protoMB.recycle(); schemeMB.recycle(); instanceId.recycle(); remoteUser.recycle(); authType.recycle(); attributes.clear(); startTime = -1; } // -------------------- Info -------------------- public void updateCounters() { reqProcessorMX.updateCounters(); } public RequestInfo getRequestProcessor() { return reqProcessorMX; } public int getBytesRead() { return bytesRead; } public boolean isProcessing() { return reqProcessorMX.getStage()==org.apache.coyote.Constants.STAGE_SERVICE; } } tomcat7-7.0.52/java/org/apache/coyote/OutputBuffer.java0000644000175100017510000000326612271461367022713 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.io.IOException; import org.apache.tomcat.util.buf.ByteChunk; /** * Output buffer. * * This class is used internally by the protocol implementation. All writes from * higher level code should happen via Resonse.doWrite(). * * @author Remy Maucherat */ public interface OutputBuffer { /** * Write the response. The caller ( tomcat ) owns the chunks. * * @param chunk data to write * @param response used to allow buffers that can be shared by multiple * responses. * @throws IOException */ public int doWrite(ByteChunk chunk, Response response) throws IOException; /** * Bytes written to the underlying socket. This includes the effects of * chunking, compression, etc. * * @return Bytes written for the current request */ public long getBytesWritten(); } tomcat7-7.0.52/java/org/apache/coyote/Response.java0000644000175100017510000003260212271461367022053 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.io.IOException; import java.io.StringReader; import java.util.Locale; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.parser.HttpParser; import org.apache.tomcat.util.http.parser.MediaType; /** * Response object. * * @author James Duncan Davidson [duncan@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Harish Prabandham * @author Hans Bergsten * @author Remy Maucherat */ public final class Response { // ----------------------------------------------------- Class Variables /** * Default locale as mandated by the spec. */ private static Locale DEFAULT_LOCALE = Locale.getDefault(); // ----------------------------------------------------- Instance Variables /** * Status code. */ protected int status = 200; /** * Status message. */ protected String message = null; /** * Response headers. */ protected MimeHeaders headers = new MimeHeaders(); /** * Associated output buffer. */ protected OutputBuffer outputBuffer; /** * Notes. */ protected Object notes[] = new Object[Constants.MAX_NOTES]; /** * Committed flag. */ protected boolean commited = false; /** * Action hook. */ public ActionHook hook; /** * HTTP specific fields. */ protected String contentType = null; protected String contentLanguage = null; protected String characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; protected long contentLength = -1; private Locale locale = DEFAULT_LOCALE; // General informations private long contentWritten = 0; private long commitTime = -1; /** * Holds request error exception. */ protected Exception errorException = null; /** * Has the charset been explicitly set. */ protected boolean charsetSet = false; protected Request req; // ------------------------------------------------------------- Properties public Request getRequest() { return req; } public void setRequest( Request req ) { this.req=req; } public OutputBuffer getOutputBuffer() { return outputBuffer; } public void setOutputBuffer(OutputBuffer outputBuffer) { this.outputBuffer = outputBuffer; } public MimeHeaders getMimeHeaders() { return headers; } public ActionHook getHook() { return hook; } public void setHook(ActionHook hook) { this.hook = hook; } // -------------------- Per-Response "notes" -------------------- public final void setNote(int pos, Object value) { notes[pos] = value; } public final Object getNote(int pos) { return notes[pos]; } // -------------------- Actions -------------------- public void action(ActionCode actionCode, Object param) { if (hook != null) { if( param==null ) hook.action(actionCode, this); else hook.action(actionCode, param); } } // -------------------- State -------------------- public int getStatus() { return status; } /** * Set the response status */ public void setStatus( int status ) { this.status = status; } /** * Get the status message. */ public String getMessage() { return message; } /** * Set the status message. */ public void setMessage(String message) { this.message = message; } public boolean isCommitted() { return commited; } public void setCommitted(boolean v) { if (v && !this.commited) { this.commitTime = System.currentTimeMillis(); } this.commited = v; } /** * Return the time the response was committed (based on System.currentTimeMillis). * * @return the time the response was committed */ public long getCommitTime() { return commitTime; } // -----------------Error State -------------------- /** * Set the error Exception that occurred during * request processing. */ public void setErrorException(Exception ex) { errorException = ex; } /** * Get the Exception that occurred during request * processing. */ public Exception getErrorException() { return errorException; } public boolean isExceptionPresent() { return ( errorException != null ); } // -------------------- Methods -------------------- public void reset() throws IllegalStateException { // Reset the headers only if this is the main request, // not for included contentType = null; locale = DEFAULT_LOCALE; contentLanguage = null; characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; contentLength = -1; charsetSet = false; status = 200; message = null; headers.clear(); // Force the PrintWriter to flush its data to the output // stream before resetting the output stream // // Reset the stream if (commited) { //String msg = sm.getString("servletOutputStreamImpl.reset.ise"); throw new IllegalStateException(); } action(ActionCode.RESET, this); } public void finish() { action(ActionCode.CLOSE, this); } public void acknowledge() { action(ActionCode.ACK, this); } // -------------------- Headers -------------------- /** * Warning: This method always returns false for Content-Type * and Content-Length. */ public boolean containsHeader(String name) { return headers.getHeader(name) != null; } public void setHeader(String name, String value) { char cc=name.charAt(0); if( cc=='C' || cc=='c' ) { if( checkSpecialHeader(name, value) ) return; } headers.setValue(name).setString( value); } public void addHeader(String name, String value) { char cc=name.charAt(0); if( cc=='C' || cc=='c' ) { if( checkSpecialHeader(name, value) ) return; } headers.addValue(name).setString( value ); } /** * Set internal fields for special header names. * Called from set/addHeader. * Return true if the header is special, no need to set the header. */ private boolean checkSpecialHeader( String name, String value) { // XXX Eliminate redundant fields !!! // ( both header and in special fields ) if( name.equalsIgnoreCase( "Content-Type" ) ) { setContentType( value ); return true; } if( name.equalsIgnoreCase( "Content-Length" ) ) { try { long cL=Long.parseLong( value ); setContentLength( cL ); return true; } catch( NumberFormatException ex ) { // Do nothing - the spec doesn't have any "throws" // and the user might know what he's doing return false; } } if( name.equalsIgnoreCase( "Content-Language" ) ) { // XXX XXX Need to construct Locale or something else } return false; } /** Signal that we're done with the headers, and body will follow. * Any implementation needs to notify ContextManager, to allow * interceptors to fix headers. */ public void sendHeaders() { action(ActionCode.COMMIT, this); setCommitted(true); } // -------------------- I18N -------------------- public Locale getLocale() { return locale; } /** * Called explicitly by user to set the Content-Language and * the default encoding */ public void setLocale(Locale locale) { if (locale == null) { return; // throw an exception? } // Save the locale for use by getLocale() this.locale = locale; // Set the contentLanguage for header output contentLanguage = locale.getLanguage(); if ((contentLanguage != null) && (contentLanguage.length() > 0)) { String country = locale.getCountry(); StringBuilder value = new StringBuilder(contentLanguage); if ((country != null) && (country.length() > 0)) { value.append('-'); value.append(country); } contentLanguage = value.toString(); } } /** * Return the content language. */ public String getContentLanguage() { return contentLanguage; } /* * Overrides the name of the character encoding used in the body * of the response. This method must be called prior to writing output * using getWriter(). * * @param charset String containing the name of the character encoding. */ public void setCharacterEncoding(String charset) { if (isCommitted()) return; if (charset == null) return; characterEncoding = charset; charsetSet=true; } public String getCharacterEncoding() { return characterEncoding; } /** * Sets the content type. * * This method must preserve any response charset that may already have * been set via a call to response.setContentType(), response.setLocale(), * or response.setCharacterEncoding(). * * @param type the content type */ public void setContentType(String type) { if (type == null) { this.contentType = null; return; } MediaType m = null; try { m = HttpParser.parseMediaType(new StringReader(type)); } catch (IOException e) { // Ignore - null test below handles this } if (m == null) { // Invalid - Assume no charset and just pass through whatever // the user provided. this.contentType = type; return; } this.contentType = m.toStringNoCharset(); String charsetValue = m.getCharset(); if (charsetValue != null) { charsetValue = charsetValue.trim(); if (charsetValue.length() > 0) { charsetSet = true; this.characterEncoding = charsetValue; } } } public void setContentTypeNoCharset(String type) { this.contentType = type; } public String getContentType() { String ret = contentType; if (ret != null && characterEncoding != null && charsetSet) { ret = ret + ";charset=" + characterEncoding; } return ret; } public void setContentLength(int contentLength) { this.contentLength = contentLength; } public void setContentLength(long contentLength) { this.contentLength = contentLength; } public int getContentLength() { long length = getContentLengthLong(); if (length < Integer.MAX_VALUE) { return (int) length; } return -1; } public long getContentLengthLong() { return contentLength; } /** * Write a chunk of bytes. */ public void doWrite(ByteChunk chunk/*byte buffer[], int pos, int count*/) throws IOException { outputBuffer.doWrite(chunk, this); contentWritten+=chunk.getLength(); } // -------------------- public void recycle() { contentType = null; contentLanguage = null; locale = DEFAULT_LOCALE; characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; charsetSet = false; contentLength = -1; status = 200; message = null; commited = false; commitTime = -1; errorException = null; headers.clear(); // update counters contentWritten=0; } /** * Bytes written by application - i.e. before compression, chunking, etc. */ public long getContentWritten() { return contentWritten; } /** * Bytes written to socket - i.e. after compression, chunking, etc. */ public long getBytesWritten(boolean flush) { if (flush) { action(ActionCode.CLIENT_FLUSH, this); } return outputBuffer.getBytesWritten(); } } tomcat7-7.0.52/java/org/apache/coyote/AsyncContextCallback.java0000644000175100017510000000234511500741203024275 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; /** * Provides a mechanism for the Coyote connectors to signal to a * {@link javax.servlet.AsyncContext} implementation that an action, such as * firing event listeners needs to be taken. It is implemented in this manner * so that the org.apache.coyote package does not have a dependency on the * org.apache.coyote package. */ public interface AsyncContextCallback { public void fireOnComplete(); } tomcat7-7.0.52/java/org/apache/coyote/AbstractProcessor.java0000644000175100017510000001105412276702205023710 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.io.IOException; import java.util.concurrent.Executor; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Provides functionality and attributes common to all supported protocols * (currently HTTP and AJP). */ public abstract class AbstractProcessor implements ActionHook, Processor { protected Adapter adapter; protected AsyncStateMachine asyncStateMachine; protected AbstractEndpoint endpoint; protected Request request; protected Response response; protected SocketWrapper socketWrapper = null; /** * Intended for use by the Upgrade sub-classes that have no need to * initialise the request, response, etc. */ protected AbstractProcessor() { // NOOP } public AbstractProcessor(AbstractEndpoint endpoint) { this.endpoint = endpoint; asyncStateMachine = new AsyncStateMachine(this); request = new Request(); response = new Response(); response.setHook(this); request.setResponse(response); } /** * The endpoint receiving connections that are handled by this processor. */ protected AbstractEndpoint getEndpoint() { return endpoint; } /** * The request associated with this processor. */ @Override public Request getRequest() { return request; } /** * Set the associated adapter. * * @param adapter the new adapter */ public void setAdapter(Adapter adapter) { this.adapter = adapter; } /** * Get the associated adapter. * * @return the associated adapter */ public Adapter getAdapter() { return adapter; } /** * Set the socket wrapper being used. */ protected final void setSocketWrapper(SocketWrapper socketWrapper) { this.socketWrapper = socketWrapper; } /** * Get the socket wrapper being used. */ protected final SocketWrapper getSocketWrapper() { return socketWrapper; } /** * Obtain the Executor used by the underlying endpoint. */ @Override public Executor getExecutor() { return endpoint.getExecutor(); } @Override public boolean isAsync() { return (asyncStateMachine != null && asyncStateMachine.isAsync()); } @Override public SocketState asyncPostProcess() { return asyncStateMachine.asyncPostProcess(); } @Override public abstract boolean isComet(); @Override public abstract boolean isUpgrade(); /** * Process HTTP requests. All requests are treated as HTTP requests to start * with although they may change type during processing. */ @Override public abstract SocketState process(SocketWrapper socket) throws IOException; /** * Process in-progress Comet requests. These will start as HTTP requests. */ @Override public abstract SocketState event(SocketStatus status) throws IOException; /** * Process in-progress Servlet 3.0 Async requests. These will start as HTTP * requests. */ @Override public abstract SocketState asyncDispatch(SocketStatus status); /** * Processes data received on a connection that has been through an HTTP * upgrade. */ @Override public abstract SocketState upgradeDispatch() throws IOException; /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated @Override public abstract org.apache.coyote.http11.upgrade.UpgradeInbound getUpgradeInbound(); } tomcat7-7.0.52/java/org/apache/coyote/RequestGroupInfo.java0000644000175100017510000001256412271461367023543 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.util.ArrayList; /** This can be moved to top level ( eventually with a better name ). * It is currently used only as a JMX artifact, to aggregate the data * collected from each RequestProcessor thread. */ public class RequestGroupInfo { ArrayList processors=new ArrayList(); private long deadMaxTime = 0; private long deadProcessingTime = 0; private int deadRequestCount = 0; private int deadErrorCount = 0; private long deadBytesReceived = 0; private long deadBytesSent = 0; public synchronized void addRequestProcessor( RequestInfo rp ) { processors.add( rp ); } public synchronized void removeRequestProcessor( RequestInfo rp ) { if( rp != null ) { if( deadMaxTime < rp.getMaxTime() ) deadMaxTime = rp.getMaxTime(); deadProcessingTime += rp.getProcessingTime(); deadRequestCount += rp.getRequestCount(); deadErrorCount += rp.getErrorCount(); deadBytesReceived += rp.getBytesReceived(); deadBytesSent += rp.getBytesSent(); processors.remove( rp ); } } public synchronized long getMaxTime() { long maxTime=deadMaxTime; for( int i=0; i { Executor getExecutor(); SocketState process(SocketWrapper socketWrapper) throws IOException; SocketState event(SocketStatus status) throws IOException; SocketState asyncDispatch(SocketStatus status); SocketState asyncPostProcess(); /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated org.apache.coyote.http11.upgrade.UpgradeInbound getUpgradeInbound(); /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated SocketState upgradeDispatch() throws IOException; HttpUpgradeHandler getHttpUpgradeHandler(); SocketState upgradeDispatch(SocketStatus status) throws IOException; boolean isComet(); boolean isAsync(); boolean isUpgrade(); Request getRequest(); void recycle(boolean socketClosing); void setSslSupport(SSLSupport sslSupport); } tomcat7-7.0.52/java/org/apache/coyote/ActionHook.java0000644000175100017510000000305612271461367022314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; /** * Action hook. Actions represent the callback mechanism used by * coyote servlet containers to request operations on the coyote connectors. * Some standard actions are defined in ActionCode, however custom * actions are permitted. * * The param object can be used to pass and return informations related with the * action. * * * This interface is typically implemented by ProtocolHandlers, and the param * is usually a Request or Response object. * * @author Remy Maucherat */ public interface ActionHook { /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ public void action(ActionCode actionCode, Object param); } tomcat7-7.0.52/java/org/apache/coyote/ProtocolHandler.java0000644000175100017510000000431512271461367023354 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.util.concurrent.Executor; /** * Abstract the protocol implementation, including threading, etc. * Processor is single threaded and specific to stream-based protocols, * will not fit Jk protocols like JNI. * * This is the main interface to be implemented by a coyote connector. * Adapter is the main interface to be implemented by a coyote servlet * container. * * @author Remy Maucherat * @author Costin Manolache * @see Adapter */ public interface ProtocolHandler { /** * The adapter, used to call the connector. */ public void setAdapter(Adapter adapter); public Adapter getAdapter(); /** * The executor, provide access to the underlying thread pool. */ public Executor getExecutor(); /** * Initialise the protocol. */ public void init() throws Exception; /** * Start the protocol. */ public void start() throws Exception; /** * Pause the protocol (optional). */ public void pause() throws Exception; /** * Resume the protocol (optional). */ public void resume() throws Exception; /** * Stop the protocol. */ public void stop() throws Exception; /** * Destroy the protocol (optional). */ public void destroy() throws Exception; /** * Requires APR/native library */ public boolean isAprRequired(); } tomcat7-7.0.52/java/org/apache/coyote/AbstractProtocol.java0000644000175100017510000007412712243424003023533 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.io.IOException; import java.net.InetAddress; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.coyote.http11.upgrade.servlet31.WebConnection; import org.apache.juli.logging.Log; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.AbstractEndpoint.Handler; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; import org.apache.tomcat.util.res.StringManager; public abstract class AbstractProtocol implements ProtocolHandler, MBeanRegistration { /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Counter used to generate unique JMX names for connectors using automatic * port binding. */ private static final AtomicInteger nameCounter = new AtomicInteger(0); /** * Name of MBean for the Global Request Processor. */ protected ObjectName rgOname = null; /** * Name of MBean for the ThreadPool. */ protected ObjectName tpOname = null; /** * Unique ID for this connector. Only used if the connector is configured * to use a random port as the port will change if stop(), start() is * called. */ private int nameIndex = 0; /** * Endpoint that provides low-level network I/O - must be matched to the * ProtocolHandler implementation (ProtocolHandler using BIO, requires BIO * Endpoint etc.). */ protected AbstractEndpoint endpoint = null; // ----------------------------------------------- Generic property handling /** * Generic property setter used by the digester. Other code should not need * to use this. The digester will only use this method if it can't find a * more specific setter. That means the property belongs to the Endpoint, * the ServerSocketFactory or some other lower level component. This method * ensures that it is visible to both. */ public boolean setProperty(String name, String value) { return endpoint.setProperty(name, value); } /** * Generic property getter used by the digester. Other code should not need * to use this. */ public String getProperty(String name) { return endpoint.getProperty(name); } // ------------------------------- Properties managed by the ProtocolHandler /** * The adapter provides the link between the ProtocolHandler and the * connector. */ protected Adapter adapter; @Override public void setAdapter(Adapter adapter) { this.adapter = adapter; } @Override public Adapter getAdapter() { return adapter; } /** * The maximum number of idle processors that will be retained in the cache * and re-used with a subsequent request. The default is 200. A value of -1 * means unlimited. In the unlimited case, the theoretical maximum number of * cached Processor objects is {@link #getMaxConnections()} although it will * usually be closer to {@link #getMaxThreads()}. */ protected int processorCache = 200; public int getProcessorCache() { return this.processorCache; } public void setProcessorCache(int processorCache) { this.processorCache = processorCache; } /** * When client certificate information is presented in a form other than * instances of {@link java.security.cert.X509Certificate} it needs to be * converted before it can be used and this property controls which JSSE * provider is used to perform the conversion. For example it is used with * the AJP connectors, the HTTP APR connector and with the * {@link org.apache.catalina.valves.SSLValve}. If not specified, the * default provider will be used. */ protected String clientCertProvider = null; public String getClientCertProvider() { return clientCertProvider; } public void setClientCertProvider(String s) { this.clientCertProvider = s; } @Override public boolean isAprRequired() { return false; } // ---------------------- Properties that are passed through to the EndPoint @Override public Executor getExecutor() { return endpoint.getExecutor(); } public void setExecutor(Executor executor) { endpoint.setExecutor(executor); } public int getMaxThreads() { return endpoint.getMaxThreads(); } public void setMaxThreads(int maxThreads) { endpoint.setMaxThreads(maxThreads); } public int getMaxConnections() { return endpoint.getMaxConnections(); } public void setMaxConnections(int maxConnections) { endpoint.setMaxConnections(maxConnections); } public int getMinSpareThreads() { return endpoint.getMinSpareThreads(); } public void setMinSpareThreads(int minSpareThreads) { endpoint.setMinSpareThreads(minSpareThreads); } public int getThreadPriority() { return endpoint.getThreadPriority(); } public void setThreadPriority(int threadPriority) { endpoint.setThreadPriority(threadPriority); } public int getBacklog() { return endpoint.getBacklog(); } public void setBacklog(int backlog) { endpoint.setBacklog(backlog); } public boolean getTcpNoDelay() { return endpoint.getTcpNoDelay(); } public void setTcpNoDelay(boolean tcpNoDelay) { endpoint.setTcpNoDelay(tcpNoDelay); } public int getSoLinger() { return endpoint.getSoLinger(); } public void setSoLinger(int soLinger) { endpoint.setSoLinger(soLinger); } public int getKeepAliveTimeout() { return endpoint.getKeepAliveTimeout(); } public void setKeepAliveTimeout(int keepAliveTimeout) { endpoint.setKeepAliveTimeout(keepAliveTimeout); } public InetAddress getAddress() { return endpoint.getAddress(); } public void setAddress(InetAddress ia) { endpoint.setAddress(ia); } public int getPort() { return endpoint.getPort(); } public void setPort(int port) { endpoint.setPort(port); } public int getLocalPort() { return endpoint.getLocalPort(); } /* * When Tomcat expects data from the client, this is the time Tomcat will * wait for that data to arrive before closing the connection. */ public int getConnectionTimeout() { // Note that the endpoint uses the alternative name return endpoint.getSoTimeout(); } public void setConnectionTimeout(int timeout) { // Note that the endpoint uses the alternative name endpoint.setSoTimeout(timeout); } /* * Alternative name for connectionTimeout property */ public int getSoTimeout() { return getConnectionTimeout(); } public void setSoTimeout(int timeout) { setConnectionTimeout(timeout); } public int getMaxHeaderCount() { return endpoint.getMaxHeaderCount(); } public void setMaxHeaderCount(int maxHeaderCount) { endpoint.setMaxHeaderCount(maxHeaderCount); } public long getConnectionCount() { return endpoint.getConnectionCount(); } // ---------------------------------------------------------- Public methods public synchronized int getNameIndex() { if (nameIndex == 0) { nameIndex = nameCounter.incrementAndGet(); } return nameIndex; } /** * The name will be prefix-address-port if address is non-null and * prefix-port if the address is null. The name will be appropriately quoted * so it can be used directly in an ObjectName. */ public String getName() { StringBuilder name = new StringBuilder(getNamePrefix()); name.append('-'); if (getAddress() != null) { name.append(getAddress().getHostAddress()); name.append('-'); } int port = getPort(); if (port == 0) { // Auto binding is in use. Check if port is known name.append("auto-"); name.append(getNameIndex()); port = getLocalPort(); if (port != -1) { name.append('-'); name.append(port); } } else { name.append(port); } return ObjectName.quote(name.toString()); } // -------------------------------------------------------- Abstract methods /** * Concrete implementations need to provide access to their logger to be * used by the abstract classes. */ protected abstract Log getLog(); /** * Obtain the prefix to be used when construction a name for this protocol * handler. The name will be prefix-address-port. */ protected abstract String getNamePrefix(); /** * Obtain the name of the protocol, (Http, Ajp, etc.). Used with JMX. */ protected abstract String getProtocolName(); /** * Obtain the handler associated with the underlying Endpoint */ protected abstract Handler getHandler(); // ----------------------------------------------------- JMX related methods protected String domain; protected ObjectName oname; protected MBeanServer mserver; public ObjectName getObjectName() { return oname; } public String getDomain() { return domain; } @Override public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { oname = name; mserver = server; domain = name.getDomain(); return name; } @Override public void postRegister(Boolean registrationDone) { // NOOP } @Override public void preDeregister() throws Exception { // NOOP } @Override public void postDeregister() { // NOOP } private ObjectName createObjectName() throws MalformedObjectNameException { // Use the same domain as the connector domain = adapter.getDomain(); if (domain == null) { return null; } StringBuilder name = new StringBuilder(getDomain()); name.append(":type=ProtocolHandler,port="); int port = getPort(); if (port > 0) { name.append(getPort()); } else { name.append("auto-"); name.append(getNameIndex()); } InetAddress address = getAddress(); if (address != null) { name.append(",address="); name.append(ObjectName.quote(address.getHostAddress())); } return new ObjectName(name.toString()); } // ------------------------------------------------------- Lifecycle methods /* * NOTE: There is no maintenance of state or checking for valid transitions * within this class. It is expected that the connector will maintain state * and prevent invalid state transitions. */ @Override public void init() throws Exception { if (getLog().isInfoEnabled()) getLog().info(sm.getString("abstractProtocolHandler.init", getName())); if (oname == null) { // Component not pre-registered so register it oname = createObjectName(); if (oname != null) { Registry.getRegistry(null, null).registerComponent(this, oname, null); } } if (this.domain != null) { try { tpOname = new ObjectName(domain + ":" + "type=ThreadPool,name=" + getName()); Registry.getRegistry(null, null).registerComponent(endpoint, tpOname, null); } catch (Exception e) { getLog().error(sm.getString( "abstractProtocolHandler.mbeanRegistrationFailed", tpOname, getName()), e); } rgOname=new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName()); Registry.getRegistry(null, null).registerComponent( getHandler().getGlobal(), rgOname, null ); } String endpointName = getName(); endpoint.setName(endpointName.substring(1, endpointName.length()-1)); try { endpoint.init(); } catch (Exception ex) { getLog().error(sm.getString("abstractProtocolHandler.initError", getName()), ex); throw ex; } } @Override public void start() throws Exception { if (getLog().isInfoEnabled()) getLog().info(sm.getString("abstractProtocolHandler.start", getName())); try { endpoint.start(); } catch (Exception ex) { getLog().error(sm.getString("abstractProtocolHandler.startError", getName()), ex); throw ex; } } @Override public void pause() throws Exception { if(getLog().isInfoEnabled()) getLog().info(sm.getString("abstractProtocolHandler.pause", getName())); try { endpoint.pause(); } catch (Exception ex) { getLog().error(sm.getString("abstractProtocolHandler.pauseError", getName()), ex); throw ex; } } @Override public void resume() throws Exception { if(getLog().isInfoEnabled()) getLog().info(sm.getString("abstractProtocolHandler.resume", getName())); try { endpoint.resume(); } catch (Exception ex) { getLog().error(sm.getString("abstractProtocolHandler.resumeError", getName()), ex); throw ex; } } @Override public void stop() throws Exception { if(getLog().isInfoEnabled()) getLog().info(sm.getString("abstractProtocolHandler.stop", getName())); try { endpoint.stop(); } catch (Exception ex) { getLog().error(sm.getString("abstractProtocolHandler.stopError", getName()), ex); throw ex; } } @Override public void destroy() { if(getLog().isInfoEnabled()) { getLog().info(sm.getString("abstractProtocolHandler.destroy", getName())); } try { endpoint.destroy(); } catch (Exception e) { getLog().error(sm.getString("abstractProtocolHandler.destroyError", getName()), e); } if (oname != null) { Registry.getRegistry(null, null).unregisterComponent(oname); } if (tpOname != null) Registry.getRegistry(null, null).unregisterComponent(tpOname); if (rgOname != null) Registry.getRegistry(null, null).unregisterComponent(rgOname); } // ------------------------------------------- Connection handler base class protected abstract static class AbstractConnectionHandler> implements AbstractEndpoint.Handler { protected abstract Log getLog(); protected RequestGroupInfo global = new RequestGroupInfo(); protected AtomicLong registerCount = new AtomicLong(0); protected ConcurrentHashMap> connections = new ConcurrentHashMap>(); protected RecycledProcessors recycledProcessors = new RecycledProcessors(this); protected abstract AbstractProtocol getProtocol(); @Override public Object getGlobal() { return global; } @Override public void recycle() { recycledProcessors.clear(); } @SuppressWarnings("deprecation") // Old HTTP upgrade method has been deprecated public SocketState process(SocketWrapper wrapper, SocketStatus status) { if (wrapper == null) { // Nothing to do. Socket has been closed. return SocketState.CLOSED; } S socket = wrapper.getSocket(); if (socket == null) { // Nothing to do. Socket has been closed. return SocketState.CLOSED; } Processor processor = connections.get(socket); if (status == SocketStatus.DISCONNECT && processor == null) { // Nothing to do. Endpoint requested a close and there is no // longer a processor associated with this socket. return SocketState.CLOSED; } wrapper.setAsync(false); try { if (processor == null) { processor = recycledProcessors.poll(); } if (processor == null) { processor = createProcessor(); } initSsl(wrapper, processor); SocketState state = SocketState.CLOSED; do { if (status == SocketStatus.DISCONNECT && !processor.isComet()) { // Do nothing here, just wait for it to get recycled // Don't do this for Comet we need to generate an end // event (see BZ 54022) } else if (processor.isAsync() || state == SocketState.ASYNC_END) { state = processor.asyncDispatch(status); } else if (processor.isComet()) { state = processor.event(status); } else if (processor.getUpgradeInbound() != null) { state = processor.upgradeDispatch(); } else if (processor.isUpgrade()) { state = processor.upgradeDispatch(status); } else { state = processor.process(wrapper); } if (state != SocketState.CLOSED && processor.isAsync()) { state = processor.asyncPostProcess(); } if (state == SocketState.UPGRADING) { // Get the HTTP upgrade handler HttpUpgradeHandler httpUpgradeHandler = processor.getHttpUpgradeHandler(); // Release the Http11 processor to be re-used release(wrapper, processor, false, false); // Create the upgrade processor processor = createUpgradeProcessor( wrapper, httpUpgradeHandler); // Mark the connection as upgraded wrapper.setUpgraded(true); // Associate with the processor with the connection connections.put(socket, processor); // Initialise the upgrade handler (which may trigger // some IO using the new protocol which is why the lines // above are necessary) // This cast should be safe. If it fails the error // handling for the surrounding try/catch will deal with // it. httpUpgradeHandler.init((WebConnection) processor); } else if (state == SocketState.UPGRADING_TOMCAT) { // Get the UpgradeInbound handler org.apache.coyote.http11.upgrade.UpgradeInbound inbound = processor.getUpgradeInbound(); // Release the Http11 processor to be re-used release(wrapper, processor, false, false); // Create the light-weight upgrade processor processor = createUpgradeProcessor(wrapper, inbound); inbound.onUpgradeComplete(); } if (getLog().isDebugEnabled()) { getLog().debug("Socket: [" + wrapper + "], Status in: [" + status + "], State out: [" + state + "]"); } } while (state == SocketState.ASYNC_END || state == SocketState.UPGRADING || state == SocketState.UPGRADING_TOMCAT); if (state == SocketState.LONG) { // In the middle of processing a request/response. Keep the // socket associated with the processor. Exact requirements // depend on type of long poll connections.put(socket, processor); longPoll(wrapper, processor); } else if (state == SocketState.OPEN) { // In keep-alive but between requests. OK to recycle // processor. Continue to poll for the next request. connections.remove(socket); release(wrapper, processor, false, true); } else if (state == SocketState.SENDFILE) { // Sendfile in progress. If it fails, the socket will be // closed. If it works, the socket will be re-added to the // poller connections.remove(socket); release(wrapper, processor, false, false); } else if (state == SocketState.UPGRADED) { // Need to keep the connection associated with the processor connections.put(socket, processor); // Don't add sockets back to the poller if this was a // non-blocking write otherwise the poller may trigger // multiple read events which may lead to thread starvation // in the connector. The write() method will add this socket // to the poller if necessary. if (status != SocketStatus.OPEN_WRITE) { longPoll(wrapper, processor); } } else { // Connection closed. OK to recycle the processor. Upgrade // processors are not recycled. connections.remove(socket); if (processor.isUpgrade()) { processor.getHttpUpgradeHandler().destroy(); } else if (processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor) { // NO-OP } else { release(wrapper, processor, true, false); } } return state; } catch(java.net.SocketException e) { // SocketExceptions are normal getLog().debug(sm.getString( "abstractConnectionHandler.socketexception.debug"), e); } catch (java.io.IOException e) { // IOExceptions are normal getLog().debug(sm.getString( "abstractConnectionHandler.ioexception.debug"), e); } // Future developers: if you discover any other // rare-but-nonfatal exceptions, catch them here, and log as // above. catch (Throwable e) { ExceptionUtils.handleThrowable(e); // any other exception or error is odd. Here we log it // with "ERROR" level, so it will show up even on // less-than-verbose logs. getLog().error( sm.getString("abstractConnectionHandler.error"), e); } // Make sure socket/processor is removed from the list of current // connections connections.remove(socket); // Don't try to add upgrade processors back into the pool if (!(processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor) && !processor.isUpgrade()) { release(wrapper, processor, true, false); } return SocketState.CLOSED; } protected abstract P createProcessor(); protected abstract void initSsl(SocketWrapper socket, Processor processor); protected abstract void longPoll(SocketWrapper socket, Processor processor); protected abstract void release(SocketWrapper socket, Processor processor, boolean socketClosing, boolean addToPoller); /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated protected abstract Processor createUpgradeProcessor( SocketWrapper socket, org.apache.coyote.http11.upgrade.UpgradeInbound inbound) throws IOException; protected abstract Processor createUpgradeProcessor( SocketWrapper socket, HttpUpgradeHandler httpUpgradeProcessor) throws IOException; protected void register(AbstractProcessor processor) { if (getProtocol().getDomain() != null) { synchronized (this) { try { long count = registerCount.incrementAndGet(); RequestInfo rp = processor.getRequest().getRequestProcessor(); rp.setGlobalProcessor(global); ObjectName rpName = new ObjectName( getProtocol().getDomain() + ":type=RequestProcessor,worker=" + getProtocol().getName() + ",name=" + getProtocol().getProtocolName() + "Request" + count); if (getLog().isDebugEnabled()) { getLog().debug("Register " + rpName); } Registry.getRegistry(null, null).registerComponent(rp, rpName, null); rp.setRpName(rpName); } catch (Exception e) { getLog().warn("Error registering request"); } } } } protected void unregister(Processor processor) { if (getProtocol().getDomain() != null) { synchronized (this) { try { Request r = processor.getRequest(); if (r == null) { // Probably an UpgradeProcessor return; } RequestInfo rp = r.getRequestProcessor(); rp.setGlobalProcessor(null); ObjectName rpName = rp.getRpName(); if (getLog().isDebugEnabled()) { getLog().debug("Unregister " + rpName); } Registry.getRegistry(null, null).unregisterComponent( rpName); rp.setRpName(null); } catch (Exception e) { getLog().warn("Error unregistering request", e); } } } } } protected static class RecycledProcessors

    , S> extends ConcurrentLinkedQueue> { private static final long serialVersionUID = 1L; private transient AbstractConnectionHandler handler; protected AtomicInteger size = new AtomicInteger(0); public RecycledProcessors(AbstractConnectionHandler handler) { this.handler = handler; } @Override public boolean offer(Processor processor) { int cacheSize = handler.getProtocol().getProcessorCache(); boolean offer = cacheSize == -1 ? true : size.get() < cacheSize; //avoid over growing our cache or add after we have stopped boolean result = false; if (offer) { result = super.offer(processor); if (result) { size.incrementAndGet(); } } if (!result) handler.unregister(processor); return result; } @Override public Processor poll() { Processor result = super.poll(); if (result != null) { size.decrementAndGet(); } return result; } @Override public void clear() { Processor next = poll(); while (next != null) { handler.unregister(next); next = poll(); } super.clear(); size.set(0); } } } tomcat7-7.0.52/java/org/apache/coyote/ajp/0000755000175100017510000000000012301126366020150 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/coyote/ajp/LocalStrings_es.properties0000644000175100017510000000366412271461367025403 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. ajpprotocol.endpoint.starterror = Error arrancando punto final ajpprotocol.init = Inicializando Coyote AJP/1.3 en {0} ajpprotocol.proto.error = Error leyendo requerimiento, ignorado ajpprotocol.start = Arrancando Coyote AJP/1.3 en {0} ajpprotocol.failedwrite = Fallo en escritura de Conector ajpprotocol.request.register = Error registrando procesador de requerimiento en JMX ajpprocessor.failedread = Fallo en lectura de Conector ajpprocessor.failedflush = No pude vaciar mensaje AJP ajpprocessor.failedsend = No pude enviar mensaje AJP ajpprocessor.header.error = Fallo en an\u00E1lisis de mensaje de cabecera ajpprocessor.request.prepare = Error preparando requerimiento ajpprocessor.request.process = Error procesando requerimiento ajpprocessor.certs.fail = Fallo en conversi\u00F3n de Certificado ajpprocessor.socket.info = Excepci\u00F3n obteniendo informaci\u00F3n de conector ajpmessage.null = No puedo a\u00F1adir valor nulo ajpmessage.overflow = Error de desbordamiento en b\u00FAfer al a\u00F1adir {0} bytes en posici\u00F3n {1} ajpmessage.read = Los {0} bytes requeridos exceden los datos disponibles de mensaje ajpmessage.invalid = Mensaje inv\u00E1lido recibido con firma {0} tomcat7-7.0.52/java/org/apache/coyote/ajp/AjpProcessor.java0000644000175100017510000003022312276702205023430 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Socket; import org.apache.coyote.ActionCode; import org.apache.coyote.RequestInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.JIoEndpoint; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Processes AJP requests. * * @author Remy Maucherat * @author Henri Gomez * @author Dan Milstein * @author Keith Wannamaker * @author Kevin Seguin * @author Costin Manolache * @author Bill Barker */ public class AjpProcessor extends AbstractAjpProcessor { /** * Logger. */ private static final Log log = LogFactory.getLog(AjpProcessor.class); @Override protected Log getLog() { return log; } // ----------------------------------------------------------- Constructors public AjpProcessor(int packetSize, JIoEndpoint endpoint) { super(packetSize, endpoint); response.setOutputBuffer(new SocketOutputBuffer()); } // ----------------------------------------------------- Instance Variables /** * Input stream. */ protected InputStream input; /** * Output stream. */ protected OutputStream output; // --------------------------------------------------------- Public Methods /** * Process pipelined HTTP requests using the specified input and output * streams. * * @throws IOException error during an I/O operation */ @Override public SocketState process(SocketWrapper socket) throws IOException { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); // Setting up the socket this.socketWrapper = socket; input = socket.getSocket().getInputStream(); output = socket.getSocket().getOutputStream(); int soTimeout = -1; if (keepAliveTimeout > 0) { soTimeout = socket.getSocket().getSoTimeout(); } boolean cping = false; // Error flag error = false; while (!error && !endpoint.isPaused()) { // Parsing the request header try { // Set keep alive timeout if enabled if (keepAliveTimeout > 0) { socket.getSocket().setSoTimeout(keepAliveTimeout); } // Get first message of the request if (!readMessage(requestHeaderMessage)) { // This means a connection timeout break; } // Set back timeout if keep alive timeout is enabled if (keepAliveTimeout > 0) { socket.getSocket().setSoTimeout(soTimeout); } // Check message type, process right away and break if // not regular request processing int type = requestHeaderMessage.getByte(); if (type == Constants.JK_AJP13_CPING_REQUEST) { if (endpoint.isPaused()) { recycle(true); break; } cping = true; try { output.write(pongMessageArray); } catch (IOException e) { error = true; } continue; } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { // Unexpected packet type. Unread body packets should have // been swallowed in finish(). if (log.isDebugEnabled()) { log.debug("Unexpected message: " + type); } error = true; break; } request.setStartTime(System.currentTimeMillis()); } catch (IOException e) { error = true; break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.header.error"), t); // 400 - Bad Request response.setStatus(400); adapter.log(request, response, 0); error = true; } if (!error) { // Setting up filters, and parse some request headers rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); try { prepareRequest(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.request.prepare"), t); // 400 - Internal Server Error response.setStatus(400); adapter.log(request, response, 0); error = true; } } if (!error && !cping && endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); adapter.log(request, response, 0); error = true; } cping = false; // Process the request in the adapter if (!error) { try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("ajpprocessor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); error = true; } } if (isAsync() && !error) { break; } // Finish the response if not done yet if (!finished) { try { finish(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); error = true; } } // If there was an error, make sure the request is counted as // and error, and update the statistics counter if (error) { response.setStatus(500); } request.updateCounters(); rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); recycle(false); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (isAsync() && !error && !endpoint.isPaused()) { return SocketState.LONG; } else { input = null; output = null; return SocketState.CLOSED; } } @Override public void recycle(boolean socketClosing) { super.recycle(socketClosing); if (socketClosing) { input = null; output = null; } } // ----------------------------------------------------- ActionHook Methods /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override protected void actionInternal(ActionCode actionCode, Object param) { if (actionCode == ActionCode.ASYNC_COMPLETE) { if (asyncStateMachine.asyncComplete()) { ((JIoEndpoint)endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) { if (param == null) return; long timeout = ((Long)param).longValue(); // if we are not piggy backing on a worker thread, set the timeout socketWrapper.setTimeout(timeout); } else if (actionCode == ActionCode.ASYNC_DISPATCH) { if (asyncStateMachine.asyncDispatch()) { ((JIoEndpoint)endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } } @Override protected void resetTimeouts() { // NO-OP. The AJP BIO connector only uses the timeout value on the // SocketWrapper for async timeouts. } @Override protected void output(byte[] src, int offset, int length) throws IOException { output.write(src, offset, length); } /** * Read at least the specified amount of bytes, and place them * in the input buffer. */ protected boolean read(byte[] buf, int pos, int n) throws IOException { int read = 0; int res = 0; while (read < n) { res = input.read(buf, read + pos, n - read); if (res > 0) { read += res; } else { throw new IOException(sm.getString("ajpprocessor.failedread")); } } return true; } /** Receive a chunk of data. Called to implement the * 'special' packet in ajp13 and to receive the data * after we send a GET_BODY packet */ @Override public boolean receive() throws IOException { first = false; bodyMessage.reset(); if (!readMessage(bodyMessage)) { // Invalid message return false; } // No data received. if (bodyMessage.getLen() == 0) { // just the header // Don't mark 'end of stream' for the first chunk. return false; } int blen = bodyMessage.peekInt(); if (blen == 0) { return false; } bodyMessage.getBodyBytes(bodyBytes); empty = false; return true; } /** * Read an AJP message. * * @return true if the message has been read, false if the short read * didn't return anything * @throws IOException any other failure, including incomplete reads */ protected boolean readMessage(AjpMessage message) throws IOException { byte[] buf = message.getBuffer(); int headerLength = message.getHeaderLength(); read(buf, 0, headerLength); int messageLength = message.processHeader(true); if (messageLength < 0) { // Invalid AJP header signature // TODO: Throw some exception and close the connection to frontend. return false; } else if (messageLength == 0) { // Zero length message. return true; } else { if (messageLength > buf.length) { // Message too long for the buffer // Need to trigger a 400 response throw new IllegalArgumentException(sm.getString( "ajpprocessor.header.tooLong", Integer.valueOf(messageLength), Integer.valueOf(buf.length))); } read(buf, headerLength, messageLength); return true; } } } tomcat7-7.0.52/java/org/apache/coyote/ajp/AjpNioProtocol.java0000644000175100017510000001402712271461367023732 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import java.nio.channels.SocketChannel; import java.util.Iterator; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioEndpoint.Handler; import org.apache.tomcat.util.net.SSLImplementation; import org.apache.tomcat.util.net.SocketWrapper; /** * Abstract the protocol implementation, including threading, etc. * Processor is single threaded and specific to stream-based protocols, * will not fit Jk protocols like JNI. */ public class AjpNioProtocol extends AbstractAjpProtocol { private static final Log log = LogFactory.getLog(AjpNioProtocol.class); @Override protected Log getLog() { return log; } @Override protected AbstractEndpoint.Handler getHandler() { return cHandler; } // ------------------------------------------------------------ Constructor public AjpNioProtocol() { endpoint = new NioEndpoint(); cHandler = new AjpConnectionHandler(this); ((NioEndpoint) endpoint).setHandler(cHandler); setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); // AJP does not use Send File ((NioEndpoint) endpoint).setUseSendfile(false); } // ----------------------------------------------------- Instance Variables /** * Connection handler for AJP. */ private AjpConnectionHandler cHandler; // ----------------------------------------------------- JMX related methods @Override protected String getNamePrefix() { return ("ajp-nio"); } // -------------------------------------- AjpConnectionHandler Inner Class protected static class AjpConnectionHandler extends AbstractAjpConnectionHandler implements Handler { protected AjpNioProtocol proto; public AjpConnectionHandler(AjpNioProtocol proto) { this.proto = proto; } @Override protected AbstractProtocol getProtocol() { return proto; } @Override protected Log getLog() { return log; } @Override public SSLImplementation getSslImplementation() { // AJP does not support SSL return null; } /** * Expected to be used by the Poller to release resources on socket * close, errors etc. */ @Override public void release(SocketChannel socket) { if (log.isDebugEnabled()) log.debug("Iterating through our connections to release a socket channel:"+socket); boolean released = false; Iterator>> it = connections.entrySet().iterator(); while (it.hasNext()) { java.util.Map.Entry> entry = it.next(); if (entry.getKey().getIOChannel()==socket) { it.remove(); Processor result = entry.getValue(); result.recycle(true); unregister(result); released = true; break; } } if (log.isDebugEnabled()) log.debug("Done iterating through our connections to release a socket channel:"+socket +" released:"+released); } /** * Expected to be used by the Poller to release resources on socket * close, errors etc. */ @Override public void release(SocketWrapper socket) { Processor processor = connections.remove(socket.getSocket()); if (processor != null) { processor.recycle(true); recycledProcessors.offer(processor); } } /** * Expected to be used by the handler once the processor is no longer * required. */ @Override public void release(SocketWrapper socket, Processor processor, boolean isSocketClosing, boolean addToPoller) { processor.recycle(isSocketClosing); recycledProcessors.offer(processor); if (addToPoller) { socket.getSocket().getPoller().add(socket.getSocket()); } } @Override protected AjpNioProcessor createProcessor() { AjpNioProcessor processor = new AjpNioProcessor(proto.packetSize, (NioEndpoint)proto.endpoint); processor.setAdapter(proto.adapter); processor.setTomcatAuthentication(proto.tomcatAuthentication); processor.setRequiredSecret(proto.requiredSecret); processor.setClientCertProvider(proto.getClientCertProvider()); register(processor); return processor; } } } tomcat7-7.0.52/java/org/apache/coyote/ajp/AjpMessage.java0000644000175100017510000003173712271461367023056 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.res.StringManager; /** * A single packet for communication between the web server and the * container. Designed to be reused many times with no creation of * garbage. Understands the format of data types for these packets. * Can be used (somewhat confusingly) for both incoming and outgoing * packets. * * @author Henri Gomez * @author Dan Milstein * @author Keith Wannamaker * @author Kevin Seguin * @author Costin Manolache */ public class AjpMessage { private static final Log log = LogFactory.getLog(AjpMessage.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------------------------------------ Constructor public AjpMessage(int packetSize) { buf = new byte[packetSize]; } // ----------------------------------------------------- Instance Variables /** * Fixed size buffer. */ protected byte buf[] = null; /** * The current read or write position in the buffer. */ protected int pos; /** * This actually means different things depending on whether the * packet is read or write. For read, it's the length of the * payload (excluding the header). For write, it's the length of * the packet as a whole (counting the header). Oh, well. */ protected int len; // --------------------------------------------------------- Public Methods /** * Prepare this packet for accumulating a message from the container to * the web server. Set the write position to just after the header * (but leave the length unwritten, because it is as yet unknown). */ public void reset() { len = 4; pos = 4; } /** * For a packet to be sent to the web server, finish the process of * accumulating data and write the length of the data payload into * the header. */ public void end() { len = pos; int dLen = len - 4; buf[0] = (byte) 0x41; buf[1] = (byte) 0x42; buf[2] = (byte) ((dLen>>>8) & 0xFF); buf[3] = (byte) (dLen & 0xFF); } /** * Return the underlying byte buffer. */ public byte[] getBuffer() { return buf; } /** * Return the current message length. For read, it's the length of the * payload (excluding the header). For write, it's the length of * the packet as a whole (counting the header). */ public int getLen() { return len; } /** * Add a short integer (2 bytes) to the message. */ public void appendInt(int val) { buf[pos++] = (byte) ((val >>> 8) & 0xFF); buf[pos++] = (byte) (val & 0xFF); } /** * Append a byte (1 byte) to the message. */ public void appendByte(int val) { buf[pos++] = (byte) val; } /** * Write a MessageBytes out at the current write position. * A null MessageBytes is encoded as a string with length 0. */ public void appendBytes(MessageBytes mb) { if (mb == null) { log.error(sm.getString("ajpmessage.null"), new NullPointerException()); appendInt(0); appendByte(0); return; } if (mb.getType() == MessageBytes.T_BYTES) { ByteChunk bc = mb.getByteChunk(); appendByteChunk(bc); } else if (mb.getType() == MessageBytes.T_CHARS) { CharChunk cc = mb.getCharChunk(); appendCharChunk(cc); } else { appendString(mb.toString()); } } /** * Write a ByteChunk out at the current write position. * A null ByteChunk is encoded as a string with length 0. */ public void appendByteChunk(ByteChunk bc) { if (bc == null) { log.error(sm.getString("ajpmessage.null"), new NullPointerException()); appendInt(0); appendByte(0); return; } appendBytes(bc.getBytes(), bc.getStart(), bc.getLength()); } /** * Write a CharChunk out at the current write position. * A null CharChunk is encoded as a string with length 0. */ public void appendCharChunk(CharChunk cc) { if (cc == null) { log.error(sm.getString("ajpmessage.null"), new NullPointerException()); appendInt(0); appendByte(0); return; } int start = cc.getStart(); int end = cc.getEnd(); appendInt(end - start); char[] cbuf = cc.getBuffer(); for (int i = start; i < end; i++) { char c = cbuf[i]; // Note: This is clearly incorrect for many strings, // but is the only consistent approach within the current // servlet framework. It must suffice until servlet output // streams properly encode their output. if (((c <= 31) && (c != 9)) || c == 127 || c > 255) { c = ' '; } appendByte(c); } appendByte(0); } /** * Write a String out at the current write position. Strings are * encoded with the length in two bytes first, then the string, and * then a terminating \0 (which is not included in the * encoded length). The terminator is for the convenience of the C * code, where it saves a round of copying. A null string is * encoded as a string with length 0. */ public void appendString(String str) { if (str == null) { log.error(sm.getString("ajpmessage.null"), new NullPointerException()); appendInt(0); appendByte(0); return; } int len = str.length(); appendInt(len); for (int i = 0; i < len; i++) { char c = str.charAt (i); // Note: This is clearly incorrect for many strings, // but is the only consistent approach within the current // servlet framework. It must suffice until servlet output // streams properly encode their output. if (((c <= 31) && (c != 9)) || c == 127 || c > 255) { c = ' '; } appendByte(c); } appendByte(0); } /** * Copy a chunk of bytes into the packet, starting at the current * write position. The chunk of bytes is encoded with the length * in two bytes first, then the data itself, and finally a * terminating \0 (which is not included in the encoded * length). * * @param b The array from which to copy bytes. * @param off The offset into the array at which to start copying * @param numBytes The number of bytes to copy. */ public void appendBytes(byte[] b, int off, int numBytes) { if (pos + numBytes + 3 > buf.length) { log.error(sm.getString("ajpmessage.overflow", "" + numBytes, "" + pos), new ArrayIndexOutOfBoundsException()); if (log.isDebugEnabled()) { dump("Overflow/coBytes"); } return; } appendInt(numBytes); System.arraycopy(b, off, buf, pos, numBytes); pos += numBytes; appendByte(0); } /** * Read an integer from packet, and advance the read position past * it. Integers are encoded as two unsigned bytes with the * high-order byte first, and, as far as I can tell, in * little-endian order within each byte. */ public int getInt() { int b1 = buf[pos++] & 0xFF; int b2 = buf[pos++] & 0xFF; validatePos(pos); return (b1<<8) + b2; } public int peekInt() { validatePos(pos + 2); int b1 = buf[pos] & 0xFF; int b2 = buf[pos+1] & 0xFF; return (b1<<8) + b2; } public byte getByte() { byte res = buf[pos++]; validatePos(pos); return res; } public void getBytes(MessageBytes mb) { doGetBytes(mb, true); } public void getBodyBytes(MessageBytes mb) { doGetBytes(mb, false); } private void doGetBytes(MessageBytes mb, boolean terminated) { int length = getInt(); if ((length == 0xFFFF) || (length == -1)) { mb.recycle(); return; } if (terminated) { validatePos(pos + length + 1); } else { validatePos(pos + length); } mb.setBytes(buf, pos, length); mb.getCharChunk().recycle(); // not valid anymore pos += length; if (terminated) { pos++; // Skip the terminating \0 } } /** * Read a 32 bits integer from packet, and advance the read position past * it. Integers are encoded as four unsigned bytes with the * high-order byte first, and, as far as I can tell, in * little-endian order within each byte. */ public int getLongInt() { int b1 = buf[pos++] & 0xFF; // No swap, Java order b1 <<= 8; b1 |= (buf[pos++] & 0xFF); b1 <<= 8; b1 |= (buf[pos++] & 0xFF); b1 <<=8; b1 |= (buf[pos++] & 0xFF); validatePos(pos); return b1; } public int getHeaderLength() { return Constants.H_SIZE; } public int getPacketSize() { return buf.length; } @Deprecated public int processHeader() { return processHeader(true); } public int processHeader(boolean toContainer) { pos = 0; int mark = getInt(); len = getInt(); // Verify message signature if ((toContainer && mark != 0x1234) || (!toContainer && mark != 0x4142)) { log.error(sm.getString("ajpmessage.invalid", "" + mark)); if (log.isDebugEnabled()) { dump("In: "); } return -1; } if (log.isDebugEnabled()) { log.debug("Received " + len + " " + buf[0]); } return len; } /** * Dump the contents of the message, prefixed with the given String. */ public void dump(String msg) { if (log.isDebugEnabled()) { log.debug(msg + ": " + HexUtils.toHexString(buf) + " " + pos +"/" + (len + 4)); } int max = pos; if (len + 4 > pos) max = len+4; if (max > 1000) max = 1000; if (log.isDebugEnabled()) { for (int j = 0; j < max; j += 16) { log.debug(hexLine(buf, j, len)); } } } private void validatePos(int posToTest) { if (posToTest > len + 4) { // Trying to read data beyond the end of the AJP message throw new ArrayIndexOutOfBoundsException(sm.getString( "ajpMessage.invalidPos", Integer.valueOf(posToTest))); } } // ------------------------------------------------------ Protected Methods protected static String hexLine(byte buf[], int start, int len) { StringBuilder sb = new StringBuilder(); for (int i = start; i < start + 16 ; i++) { if (i < len + 4) { sb.append(hex(buf[i]) + " "); } else { sb.append(" "); } } sb.append(" | "); for (int i = start; i < start + 16 && i < len + 4; i++) { if (!Character.isISOControl((char) buf[i])) { sb.append(Character.valueOf((char) buf[i])); } else { sb.append("."); } } return sb.toString(); } protected static String hex(int x) { String h = Integer.toHexString(x); if (h.length() == 1) { h = "0" + h; } return h.substring(h.length() - 2); } } tomcat7-7.0.52/java/org/apache/coyote/ajp/AbstractAjpProtocol.java0000644000175100017510000000710512205357621024741 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.tomcat.util.net.SocketWrapper; import org.apache.tomcat.util.res.StringManager; public abstract class AbstractAjpProtocol extends AbstractProtocol { /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); @Override protected String getProtocolName() { return "Ajp"; } // ------------------------------------------------- AJP specific properties // ------------------------------------------ managed in the ProtocolHandler /** * Should authentication be done in the native webserver layer, * or in the Servlet container ? */ protected boolean tomcatAuthentication = true; public boolean getTomcatAuthentication() { return tomcatAuthentication; } public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; } /** * Required secret. */ protected String requiredSecret = null; public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; } /** * AJP packet size. */ protected int packetSize = Constants.MAX_PACKET_SIZE; public int getPacketSize() { return packetSize; } public void setPacketSize(int packetSize) { if(packetSize < Constants.MAX_PACKET_SIZE) { this.packetSize = Constants.MAX_PACKET_SIZE; } else { this.packetSize = packetSize; } } protected abstract static class AbstractAjpConnectionHandler> extends AbstractConnectionHandler { @Override protected void initSsl(SocketWrapper socket, Processor processor) { // NOOP for AJP } @Override protected void longPoll(SocketWrapper socket, Processor processor) { // Same requirements for all AJP connectors socket.setAsync(true); } /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated @Override protected P createUpgradeProcessor(SocketWrapper socket, org.apache.coyote.http11.upgrade.UpgradeInbound inbound) { // TODO should fail - throw IOE return null; } @Override protected P createUpgradeProcessor(SocketWrapper socket, HttpUpgradeHandler httpUpgradeHandler) { // TODO should fail - throw IOE return null; } } } tomcat7-7.0.52/java/org/apache/coyote/ajp/AjpAprProtocol.java0000644000175100017510000001170712271461367023731 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.AprEndpoint.Handler; import org.apache.tomcat.util.net.SocketWrapper; /** * Abstract the protocol implementation, including threading, etc. * Processor is single threaded and specific to stream-based protocols, * will not fit Jk protocols like JNI. * * @author Remy Maucherat * @author Costin Manolache */ public class AjpAprProtocol extends AbstractAjpProtocol { private static final Log log = LogFactory.getLog(AjpAprProtocol.class); @Override protected Log getLog() { return log; } @Override protected AbstractEndpoint.Handler getHandler() { return cHandler; } @Override public boolean isAprRequired() { // Override since this protocol implementation requires the APR/native // library return true; } // ------------------------------------------------------------ Constructor public AjpAprProtocol() { endpoint = new AprEndpoint(); cHandler = new AjpConnectionHandler(this); ((AprEndpoint) endpoint).setHandler(cHandler); setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); // AJP does not use Send File ((AprEndpoint) endpoint).setUseSendfile(false); } // ----------------------------------------------------- Instance Variables /** * Connection handler for AJP. */ private AjpConnectionHandler cHandler; // --------------------------------------------------------- Public Methods public int getPollTime() { return ((AprEndpoint)endpoint).getPollTime(); } public void setPollTime(int pollTime) { ((AprEndpoint)endpoint).setPollTime(pollTime); } // pollerSize is now a synonym for maxConnections public void setPollerSize(int pollerSize) { endpoint.setMaxConnections(pollerSize); } public int getPollerSize() { return endpoint.getMaxConnections(); } // ----------------------------------------------------- JMX related methods @Override protected String getNamePrefix() { return ("ajp-apr"); } // -------------------------------------- AjpConnectionHandler Inner Class protected static class AjpConnectionHandler extends AbstractAjpConnectionHandler implements Handler { protected AjpAprProtocol proto; public AjpConnectionHandler(AjpAprProtocol proto) { this.proto = proto; } @Override protected AbstractProtocol getProtocol() { return proto; } @Override protected Log getLog() { return log; } /** * Expected to be used by the handler once the processor is no longer * required. */ @Override public void release(SocketWrapper socket, Processor processor, boolean isSocketClosing, boolean addToPoller) { processor.recycle(isSocketClosing); recycledProcessors.offer(processor); if (addToPoller) { ((AprEndpoint)proto.endpoint).getPoller().add( socket.getSocket().longValue(), proto.endpoint.getKeepAliveTimeout(), true, false); } } @Override protected AjpAprProcessor createProcessor() { AjpAprProcessor processor = new AjpAprProcessor(proto.packetSize, (AprEndpoint)proto.endpoint); processor.setAdapter(proto.adapter); processor.setTomcatAuthentication(proto.tomcatAuthentication); processor.setRequiredSecret(proto.requiredSecret); processor.setClientCertProvider(proto.getClientCertProvider()); register(processor); return processor; } } } tomcat7-7.0.52/java/org/apache/coyote/ajp/AbstractAjpProcessor.java0000644000175100017510000011672512276703610025131 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.net.InetAddress; import java.security.NoSuchProviderException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.http.HttpServletResponse; import org.apache.coyote.AbstractProcessor; import org.apache.coyote.ActionCode; import org.apache.coyote.AsyncContextCallback; import org.apache.coyote.InputBuffer; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Request; import org.apache.coyote.RequestInfo; import org.apache.coyote.Response; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.HttpMessages; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.res.StringManager; /** * Base class for AJP Processor implementations. */ public abstract class AbstractAjpProcessor extends AbstractProcessor { protected abstract Log getLog(); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * End message array. */ protected static final byte[] endMessageArray; protected static final byte[] endAndCloseMessageArray; /** * Flush message array. */ protected static final byte[] flushMessageArray; /** * Pong message array. */ protected static final byte[] pongMessageArray; static { // Allocate the end message array AjpMessage endMessage = new AjpMessage(16); endMessage.reset(); endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE); endMessage.appendByte(1); endMessage.end(); endMessageArray = new byte[endMessage.getLen()]; System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0, endMessage.getLen()); // Allocate the end and close message array AjpMessage endAndCloseMessage = new AjpMessage(16); endAndCloseMessage.reset(); endAndCloseMessage.appendByte(Constants.JK_AJP13_END_RESPONSE); endAndCloseMessage.appendByte(0); endAndCloseMessage.end(); endAndCloseMessageArray = new byte[endAndCloseMessage.getLen()]; System.arraycopy(endAndCloseMessage.getBuffer(), 0, endAndCloseMessageArray, 0, endAndCloseMessage.getLen()); // Allocate the flush message array AjpMessage flushMessage = new AjpMessage(16); flushMessage.reset(); flushMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK); flushMessage.appendInt(0); flushMessage.appendByte(0); flushMessage.end(); flushMessageArray = new byte[flushMessage.getLen()]; System.arraycopy(flushMessage.getBuffer(), 0, flushMessageArray, 0, flushMessage.getLen()); // Allocate the pong message array AjpMessage pongMessage = new AjpMessage(16); pongMessage.reset(); pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY); pongMessage.end(); pongMessageArray = new byte[pongMessage.getLen()]; System.arraycopy(pongMessage.getBuffer(), 0, pongMessageArray, 0, pongMessage.getLen()); } // ----------------------------------------------------- Instance Variables /** * GetBody message array. Not static like the other message arrays since the * message varies with packetSize and that can vary per connector. */ protected final byte[] getBodyMessageArray; /** * AJP packet size. */ protected int packetSize; /** * Header message. Note that this header is merely the one used during the * processing of the first message of a "request", so it might not be a * request header. It will stay unchanged during the processing of the whole * request. */ protected AjpMessage requestHeaderMessage = null; /** * Message used for response composition. */ protected AjpMessage responseMessage = null; /** * Body message. */ protected AjpMessage bodyMessage = null; /** * Body message. */ protected MessageBytes bodyBytes = MessageBytes.newInstance(); /** * Error flag. */ protected boolean error = false; /** * Host name (used to avoid useless B2C conversion on the host name). */ protected char[] hostNameC = new char[0]; /** * Temp message bytes used for processing. */ protected MessageBytes tmpMB = MessageBytes.newInstance(); /** * Byte chunk for certs. */ protected MessageBytes certificates = MessageBytes.newInstance(); /** * End of stream flag. */ protected boolean endOfStream = false; /** * Body empty flag. */ protected boolean empty = true; /** * First read. */ protected boolean first = true; /** * Replay read. */ protected boolean replay = false; /** * Should any response body be swallowed and not sent to the client. */ private boolean swallowResponse = false; /** * Finished response. */ protected boolean finished = false; /** * Bytes written to client for the current request. */ protected long bytesWritten = 0; // ------------------------------------------------------------ Constructor public AbstractAjpProcessor(int packetSize, AbstractEndpoint endpoint) { super(endpoint); this.packetSize = packetSize; request.setInputBuffer(new SocketInputBuffer()); requestHeaderMessage = new AjpMessage(packetSize); responseMessage = new AjpMessage(packetSize); bodyMessage = new AjpMessage(packetSize); // Set the getBody message buffer AjpMessage getBodyMessage = new AjpMessage(16); getBodyMessage.reset(); getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK); // Adjust read size if packetSize != default (Constants.MAX_PACKET_SIZE) getBodyMessage.appendInt(Constants.MAX_READ_SIZE + packetSize - Constants.MAX_PACKET_SIZE); getBodyMessage.end(); getBodyMessageArray = new byte[getBodyMessage.getLen()]; System.arraycopy(getBodyMessage.getBuffer(), 0, getBodyMessageArray, 0, getBodyMessage.getLen()); } // ------------------------------------------------------------- Properties /** * The number of milliseconds Tomcat will wait for a subsequent request * before closing the connection. The default is the same as for * Apache HTTP Server (15 000 milliseconds). */ protected int keepAliveTimeout = -1; public int getKeepAliveTimeout() { return keepAliveTimeout; } public void setKeepAliveTimeout(int timeout) { keepAliveTimeout = timeout; } /** * Use Tomcat authentication ? */ protected boolean tomcatAuthentication = true; public boolean getTomcatAuthentication() { return tomcatAuthentication; } public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; } /** * Required secret. */ protected String requiredSecret = null; public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; } /** * When client certificate information is presented in a form other than * instances of {@link java.security.cert.X509Certificate} it needs to be * converted before it can be used and this property controls which JSSE * provider is used to perform the conversion. For example it is used with * the AJP connectors, the HTTP APR connector and with the * {@link org.apache.catalina.valves.SSLValve}. If not specified, the * default provider will be used. */ protected String clientCertProvider = null; public String getClientCertProvider() { return clientCertProvider; } public void setClientCertProvider(String s) { this.clientCertProvider = s; } // --------------------------------------------------------- Public Methods /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override public final void action(ActionCode actionCode, Object param) { if (actionCode == ActionCode.COMMIT) { if (response.isCommitted()) return; // Validate and write response headers try { prepareResponse(); } catch (IOException e) { // Set error flag error = true; } try { flush(false); } catch (IOException e) { // Set error flag error = true; } } else if (actionCode == ActionCode.CLIENT_FLUSH) { if (!response.isCommitted()) { // Validate and write response headers try { prepareResponse(); } catch (IOException e) { // Set error flag error = true; return; } } try { flush(true); } catch (IOException e) { // Set error flag error = true; } } else if (actionCode == ActionCode.IS_ERROR) { ((AtomicBoolean) param).set(error); } else if (actionCode == ActionCode.DISABLE_SWALLOW_INPUT) { // TODO: Do not swallow request input but // make sure we are closing the connection error = true; } else if (actionCode == ActionCode.CLOSE) { // Close // End the processing of the current request, and stop any further // transactions with the client try { finish(); } catch (IOException e) { // Set error flag error = true; } } else if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) { if (!certificates.isNull()) { ByteChunk certData = certificates.getByteChunk(); X509Certificate jsseCerts[] = null; ByteArrayInputStream bais = new ByteArrayInputStream(certData.getBytes(), certData.getStart(), certData.getLength()); // Fill the elements. try { CertificateFactory cf; if (clientCertProvider == null) { cf = CertificateFactory.getInstance("X.509"); } else { cf = CertificateFactory.getInstance("X.509", clientCertProvider); } while(bais.available() > 0) { X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); if(jsseCerts == null) { jsseCerts = new X509Certificate[1]; jsseCerts[0] = cert; } else { X509Certificate [] temp = new X509Certificate[jsseCerts.length+1]; System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length); temp[jsseCerts.length] = cert; jsseCerts = temp; } } } catch (java.security.cert.CertificateException e) { getLog().error(sm.getString("ajpprocessor.certs.fail"), e); return; } catch (NoSuchProviderException e) { getLog().error(sm.getString("ajpprocessor.certs.fail"), e); return; } request.setAttribute(SSLSupport.CERTIFICATE_KEY, jsseCerts); } } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) { // Get remote host name using a DNS resolution if (request.remoteHost().isNull()) { try { request.remoteHost().setString(InetAddress.getByName (request.remoteAddr().toString()).getHostName()); } catch (IOException iex) { // Ignore } } } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) { // Copy from local name for now, which should simply be an address request.localAddr().setString(request.localName().toString()); } else if (actionCode == ActionCode.REQ_SET_BODY_REPLAY) { // Set the given bytes as the content ByteChunk bc = (ByteChunk) param; int length = bc.getLength(); bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length); request.setContentLength(length); first = false; empty = false; replay = true; endOfStream = false; } else if (actionCode == ActionCode.ASYNC_START) { asyncStateMachine.asyncStart((AsyncContextCallback) param); // Async time out is based on SocketWrapper access time getSocketWrapper().access(); } else if (actionCode == ActionCode.ASYNC_DISPATCHED) { asyncStateMachine.asyncDispatched(); } else if (actionCode == ActionCode.ASYNC_TIMEOUT) { AtomicBoolean result = (AtomicBoolean) param; result.set(asyncStateMachine.asyncTimeout()); } else if (actionCode == ActionCode.ASYNC_RUN) { asyncStateMachine.asyncRun((Runnable) param); } else if (actionCode == ActionCode.ASYNC_ERROR) { asyncStateMachine.asyncError(); } else if (actionCode == ActionCode.ASYNC_IS_STARTED) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncStarted()); } else if (actionCode == ActionCode.ASYNC_IS_DISPATCHING) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncDispatching()); } else if (actionCode == ActionCode.ASYNC_IS_ASYNC) { ((AtomicBoolean) param).set(asyncStateMachine.isAsync()); } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut()); } else if (actionCode == ActionCode.ASYNC_IS_ERROR) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncError()); } else if (actionCode == ActionCode.UPGRADE_TOMCAT) { // HTTP connections only. Unsupported for AJP. // NOOP } else { actionInternal(actionCode, param); } } @Override public SocketState asyncDispatch(SocketStatus status) { RequestInfo rp = request.getRequestProcessor(); try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); error = !adapter.asyncDispatch(request, response, status); resetTimeouts(); } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().error(sm.getString("http11processor.request.process"), t); error = true; } finally { if (error) { // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); } } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (isAsync()) { if (error) { request.updateCounters(); return SocketState.CLOSED; } else { return SocketState.LONG; } } else { request.updateCounters(); if (error) { return SocketState.CLOSED; } else { return SocketState.OPEN; } } } @Override public void setSslSupport(SSLSupport sslSupport) { // Should never reach this code but in case we do... throw new IllegalStateException( sm.getString("ajpprocessor.ssl.notsupported")); } @Override public SocketState event(SocketStatus status) throws IOException { // Should never reach this code but in case we do... throw new IOException( sm.getString("ajpprocessor.comet.notsupported")); } @Override public SocketState upgradeDispatch() throws IOException { // Should never reach this code but in case we do... throw new IOException( sm.getString("ajpprocessor.httpupgrade.notsupported")); } /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated @Override public org.apache.coyote.http11.upgrade.UpgradeInbound getUpgradeInbound() { // Can't throw exception as this is used to test if connection has been // upgraded using Tomcat's proprietary HTTP upgrade mechanism. return null; } @Override public SocketState upgradeDispatch(SocketStatus status) throws IOException { // Should never reach this code but in case we do... throw new IOException( sm.getString("ajpprocessor.httpupgrade.notsupported")); } @Override public HttpUpgradeHandler getHttpUpgradeHandler() { // Should never reach this code but in case we do... throw new IllegalStateException( sm.getString("ajpprocessor.httpupgrade.notsupported")); } /** * Recycle the processor, ready for the next request which may be on the * same connection or a different connection. * * @param socketClosing Indicates if the socket is about to be closed * allowing the processor to perform any additional * clean-up that may be required */ @Override public void recycle(boolean socketClosing) { asyncStateMachine.recycle(); // Recycle Request object first = true; endOfStream = false; empty = true; replay = false; finished = false; request.recycle(); response.recycle(); certificates.recycle(); swallowResponse = false; bytesWritten = 0; } // ------------------------------------------------------ Protected Methods // Methods called by action() protected abstract void actionInternal(ActionCode actionCode, Object param); // Methods called by asyncDispatch /** * Provides a mechanism for those connector implementations (currently only * NIO) that need to reset timeouts from Async timeouts to standard HTTP * timeouts once async processing completes. */ protected abstract void resetTimeouts(); // Methods called by prepareResponse() protected abstract void output(byte[] src, int offset, int length) throws IOException; // Methods used by SocketInputBuffer protected abstract boolean receive() throws IOException; @Override public final boolean isComet() { // AJP does not support Comet return false; } @Override public final boolean isUpgrade() { // AJP does not support HTTP upgrade return false; } /** * Get more request body data from the web server and store it in the * internal buffer. * * @return true if there is more data, false if not. */ protected boolean refillReadBuffer() throws IOException { // If the server returns an empty packet, assume that that end of // the stream has been reached (yuck -- fix protocol??). // FORM support if (replay) { endOfStream = true; // we've read everything there is } if (endOfStream) { return false; } // Request more data immediately output(getBodyMessageArray, 0, getBodyMessageArray.length); boolean moreData = receive(); if( !moreData ) { endOfStream = true; } return moreData; } /** * After reading the request headers, we have to setup the request filters. */ protected void prepareRequest() { // Translate the HTTP method code to a String. byte methodCode = requestHeaderMessage.getByte(); if (methodCode != Constants.SC_M_JK_STORED) { String methodName = Constants.getMethodForCode(methodCode - 1); request.method().setString(methodName); } requestHeaderMessage.getBytes(request.protocol()); requestHeaderMessage.getBytes(request.requestURI()); requestHeaderMessage.getBytes(request.remoteAddr()); requestHeaderMessage.getBytes(request.remoteHost()); requestHeaderMessage.getBytes(request.localName()); request.setLocalPort(requestHeaderMessage.getInt()); boolean isSSL = requestHeaderMessage.getByte() != 0; if (isSSL) { request.scheme().setString("https"); } // Decode headers MimeHeaders headers = request.getMimeHeaders(); // Set this every time in case limit has been changed via JMX headers.setLimit(endpoint.getMaxHeaderCount()); boolean contentLengthSet = false; int hCount = requestHeaderMessage.getInt(); for(int i = 0 ; i < hCount ; i++) { String hName = null; // Header names are encoded as either an integer code starting // with 0xA0, or as a normal string (in which case the first // two bytes are the length). int isc = requestHeaderMessage.peekInt(); int hId = isc & 0xFF; MessageBytes vMB = null; isc &= 0xFF00; if(0xA000 == isc) { requestHeaderMessage.getInt(); // To advance the read position hName = Constants.getHeaderForCode(hId - 1); vMB = headers.addValue(hName); } else { // reset hId -- if the header currently being read // happens to be 7 or 8 bytes long, the code below // will think it's the content-type header or the // content-length header - SC_REQ_CONTENT_TYPE=7, // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected // behaviour. see bug 5861 for more information. hId = -1; requestHeaderMessage.getBytes(tmpMB); ByteChunk bc = tmpMB.getByteChunk(); vMB = headers.addValue(bc.getBuffer(), bc.getStart(), bc.getLength()); } requestHeaderMessage.getBytes(vMB); if (hId == Constants.SC_REQ_CONTENT_LENGTH || (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { long cl = vMB.getLong(); if (contentLengthSet) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); error = true; } else { contentLengthSet = true; // Set the content-length header for the request request.setContentLength(cl); } } else if (hId == Constants.SC_REQ_CONTENT_TYPE || (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { // just read the content-type header, so set it ByteChunk bchunk = vMB.getByteChunk(); request.contentType().setBytes(bchunk.getBytes(), bchunk.getOffset(), bchunk.getLength()); } } // Decode extra attributes boolean secret = false; byte attributeCode; while ((attributeCode = requestHeaderMessage.getByte()) != Constants.SC_A_ARE_DONE) { switch (attributeCode) { case Constants.SC_A_REQ_ATTRIBUTE : requestHeaderMessage.getBytes(tmpMB); String n = tmpMB.toString(); requestHeaderMessage.getBytes(tmpMB); String v = tmpMB.toString(); /* * AJP13 misses to forward the remotePort. * Allow the AJP connector to add this info via * a private request attribute. * We will accept the forwarded data as the remote port, * and remove it from the public list of request attributes. */ if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) { try { request.setRemotePort(Integer.parseInt(v)); } catch (NumberFormatException nfe) { // Ignore invalid value } } else { request.setAttribute(n, v ); } break; case Constants.SC_A_CONTEXT : requestHeaderMessage.getBytes(tmpMB); // nothing break; case Constants.SC_A_SERVLET_PATH : requestHeaderMessage.getBytes(tmpMB); // nothing break; case Constants.SC_A_REMOTE_USER : if (tomcatAuthentication) { // ignore server requestHeaderMessage.getBytes(tmpMB); } else { requestHeaderMessage.getBytes(request.getRemoteUser()); } break; case Constants.SC_A_AUTH_TYPE : if (tomcatAuthentication) { // ignore server requestHeaderMessage.getBytes(tmpMB); } else { requestHeaderMessage.getBytes(request.getAuthType()); } break; case Constants.SC_A_QUERY_STRING : requestHeaderMessage.getBytes(request.queryString()); break; case Constants.SC_A_JVM_ROUTE : requestHeaderMessage.getBytes(request.instanceId()); break; case Constants.SC_A_SSL_CERT : request.scheme().setString("https"); // SSL certificate extraction is lazy, moved to JkCoyoteHandler requestHeaderMessage.getBytes(certificates); break; case Constants.SC_A_SSL_CIPHER : request.scheme().setString("https"); requestHeaderMessage.getBytes(tmpMB); request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, tmpMB.toString()); break; case Constants.SC_A_SSL_SESSION : request.scheme().setString("https"); requestHeaderMessage.getBytes(tmpMB); request.setAttribute(SSLSupport.SESSION_ID_KEY, tmpMB.toString()); break; case Constants.SC_A_SSL_KEY_SIZE : request.setAttribute(SSLSupport.KEY_SIZE_KEY, Integer.valueOf(requestHeaderMessage.getInt())); break; case Constants.SC_A_STORED_METHOD: requestHeaderMessage.getBytes(request.method()); break; case Constants.SC_A_SECRET: requestHeaderMessage.getBytes(tmpMB); if (requiredSecret != null) { secret = true; if (!tmpMB.equals(requiredSecret)) { response.setStatus(403); error = true; } } break; default: // Ignore unknown attribute for backward compatibility break; } } // Check if secret was submitted if required if ((requiredSecret != null) && !secret) { response.setStatus(403); error = true; } // Check for a full URI (including protocol://host:port/) ByteChunk uriBC = request.requestURI().getByteChunk(); if (uriBC.startsWithIgnoreCase("http", 0)) { int pos = uriBC.indexOf("://", 0, 3, 4); int uriBCStart = uriBC.getStart(); int slashPos = -1; if (pos != -1) { byte[] uriB = uriBC.getBytes(); slashPos = uriBC.indexOf('/', pos + 3); if (slashPos == -1) { slashPos = uriBC.getLength(); // Set URI as "/" request.requestURI().setBytes (uriB, uriBCStart + pos + 1, 1); } else { request.requestURI().setBytes (uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos); } MessageBytes hostMB = headers.setValue("host"); hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos - pos - 3); } } MessageBytes valueMB = request.getMimeHeaders().getValue("host"); parseHost(valueMB); if (error) { adapter.log(request, response, 0); } } /** * Parse host. */ protected void parseHost(MessageBytes valueMB) { if (valueMB == null || valueMB.isNull()) { // HTTP/1.0 request.setServerPort(request.getLocalPort()); try { request.serverName().duplicate(request.localName()); } catch (IOException e) { response.setStatus(400); error = true; } return; } ByteChunk valueBC = valueMB.getByteChunk(); byte[] valueB = valueBC.getBytes(); int valueL = valueBC.getLength(); int valueS = valueBC.getStart(); int colonPos = -1; if (hostNameC.length < valueL) { hostNameC = new char[valueL]; } boolean ipv6 = (valueB[valueS] == '['); boolean bracketClosed = false; for (int i = 0; i < valueL; i++) { char b = (char) valueB[i + valueS]; hostNameC[i] = b; if (b == ']') { bracketClosed = true; } else if (b == ':') { if (!ipv6 || bracketClosed) { colonPos = i; break; } } } if (colonPos < 0) { if (request.scheme().equalsIgnoreCase("https")) { // 443 - Default HTTPS port request.setServerPort(443); } else { // 80 - Default HTTTP port request.setServerPort(80); } request.serverName().setChars(hostNameC, 0, valueL); } else { request.serverName().setChars(hostNameC, 0, colonPos); int port = 0; int mult = 1; for (int i = valueL - 1; i > colonPos; i--) { int charValue = HexUtils.getDec(valueB[i + valueS]); if (charValue == -1) { // Invalid character error = true; // 400 - Bad request response.setStatus(400); break; } port = port + (charValue * mult); mult = 10 * mult; } request.setServerPort(port); } } /** * When committing the response, we have to validate the set of headers, as * well as setup the response filters. */ protected void prepareResponse() throws IOException { response.setCommitted(true); responseMessage.reset(); responseMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS); // Responses with certain status codes are not permitted to include a // response body. int statusCode = response.getStatus(); if (statusCode < 200 || statusCode == 204 || statusCode == 205 || statusCode == 304) { // No entity body swallowResponse = true; } // Responses to HEAD requests are not permitted to incude a response // body. MessageBytes methodMB = request.method(); if (methodMB.equals("HEAD")) { // No entity body swallowResponse = true; } // HTTP header contents responseMessage.appendInt(statusCode); String message = null; if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER && HttpMessages.isSafeInHttpHeader(response.getMessage())) { message = response.getMessage(); } if (message == null){ message = HttpMessages.getInstance( response.getLocale()).getMessage(response.getStatus()); } if (message == null) { // mod_jk + httpd 2.x fails with a null status message - bug 45026 message = Integer.toString(response.getStatus()); } tmpMB.setString(message); responseMessage.appendBytes(tmpMB); // Special headers MimeHeaders headers = response.getMimeHeaders(); String contentType = response.getContentType(); if (contentType != null) { headers.setValue("Content-Type").setString(contentType); } String contentLanguage = response.getContentLanguage(); if (contentLanguage != null) { headers.setValue("Content-Language").setString(contentLanguage); } long contentLength = response.getContentLengthLong(); if (contentLength >= 0) { headers.setValue("Content-Length").setLong(contentLength); } // Other headers int numHeaders = headers.size(); responseMessage.appendInt(numHeaders); for (int i = 0; i < numHeaders; i++) { MessageBytes hN = headers.getName(i); int hC = Constants.getResponseAjpIndex(hN.toString()); if (hC > 0) { responseMessage.appendInt(hC); } else { responseMessage.appendBytes(hN); } MessageBytes hV=headers.getValue(i); responseMessage.appendBytes(hV); } // Write to buffer responseMessage.end(); output(responseMessage.getBuffer(), 0, responseMessage.getLen()); } /** * Callback to write data from the buffer. */ protected void flush(boolean explicit) throws IOException { if (explicit && !finished) { // Send the flush message output(flushMessageArray, 0, flushMessageArray.length); } } /** * Finish AJP response. */ protected void finish() throws IOException { if (!response.isCommitted()) { // Validate and write response headers try { prepareResponse(); } catch (IOException e) { // Set error flag error = true; } } if (finished) return; finished = true; // Swallow the unread body packet if present if (first && request.getContentLengthLong() > 0) { receive(); } // Add the end message if (error) { output(endAndCloseMessageArray, 0, endAndCloseMessageArray.length); } else { output(endMessageArray, 0, endMessageArray.length); } } // ------------------------------------- InputStreamInputBuffer Inner Class /** * This class is an input buffer which will read its data from an input * stream. */ protected class SocketInputBuffer implements InputBuffer { /** * Read bytes into the specified chunk. */ @Override public int doRead(ByteChunk chunk, Request req) throws IOException { if (endOfStream) { return -1; } if (first && req.getContentLengthLong() > 0) { // Handle special first-body-chunk if (!receive()) { return 0; } } else if (empty) { if (!refillReadBuffer()) { return -1; } } ByteChunk bc = bodyBytes.getByteChunk(); chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength()); empty = true; return chunk.getLength(); } } // ----------------------------------- OutputStreamOutputBuffer Inner Class /** * This class is an output buffer which will write data to an output * stream. */ protected class SocketOutputBuffer implements OutputBuffer { /** * Write chunk. */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { if (!response.isCommitted()) { // Validate and write response headers try { prepareResponse(); } catch (IOException e) { // Set error flag error = true; } } if (!swallowResponse) { int len = chunk.getLength(); // 4 - hardcoded, byte[] marshaling overhead // Adjust allowed size if packetSize != default (Constants.MAX_PACKET_SIZE) int chunkSize = Constants.MAX_SEND_SIZE + packetSize - Constants.MAX_PACKET_SIZE; int off = 0; while (len > 0) { int thisTime = len; if (thisTime > chunkSize) { thisTime = chunkSize; } len -= thisTime; responseMessage.reset(); responseMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK); responseMessage.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime); responseMessage.end(); output(responseMessage.getBuffer(), 0, responseMessage.getLen()); off += thisTime; } bytesWritten += chunk.getLength(); } return chunk.getLength(); } @Override public long getBytesWritten() { return bytesWritten; } } } tomcat7-7.0.52/java/org/apache/coyote/ajp/AjpAprProcessor.java0000644000175100017510000003531612276702205024103 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import org.apache.coyote.ActionCode; import org.apache.coyote.RequestInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Processes AJP requests. * * @author Remy Maucherat * @author Henri Gomez * @author Dan Milstein * @author Keith Wannamaker * @author Kevin Seguin * @author Costin Manolache * @author Bill Barker */ public class AjpAprProcessor extends AbstractAjpProcessor { /** * Logger. */ private static final Log log = LogFactory.getLog(AjpAprProcessor.class); @Override protected Log getLog() { return log; } // ----------------------------------------------------------- Constructors public AjpAprProcessor(int packetSize, AprEndpoint endpoint) { super(packetSize, endpoint); response.setOutputBuffer(new SocketOutputBuffer()); // Allocate input and output buffers inputBuffer = ByteBuffer.allocateDirect(packetSize * 2); inputBuffer.limit(0); outputBuffer = ByteBuffer.allocateDirect(packetSize * 2); } // ----------------------------------------------------- Instance Variables /** * Direct buffer used for input. */ protected ByteBuffer inputBuffer = null; /** * Direct buffer used for output. */ protected ByteBuffer outputBuffer = null; // --------------------------------------------------------- Public Methods /** * Process pipelined HTTP requests using the specified input and output * streams. * * @throws IOException error during an I/O operation */ @Override public SocketState process(SocketWrapper socket) throws IOException { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); // Setting up the socket this.socketWrapper = socket; long socketRef = socket.getSocket().longValue(); Socket.setrbb(socketRef, inputBuffer); Socket.setsbb(socketRef, outputBuffer); boolean cping = false; // Error flag error = false; boolean keptAlive = false; while (!error && !endpoint.isPaused()) { // Parsing the request header try { // Get first message of the request if (!readMessage(requestHeaderMessage, true, keptAlive)) { // This means that no data is available right now // (long keepalive), so that the processor should be recycled // and the method should return true break; } // Check message type, process right away and break if // not regular request processing int type = requestHeaderMessage.getByte(); if (type == Constants.JK_AJP13_CPING_REQUEST) { if (endpoint.isPaused()) { recycle(true); break; } cping = true; if (Socket.send(socketRef, pongMessageArray, 0, pongMessageArray.length) < 0) { error = true; } continue; } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { // Unexpected packet type. Unread body packets should have // been swallowed in finish(). if (log.isDebugEnabled()) { log.debug("Unexpected message: " + type); } error = true; break; } keptAlive = true; request.setStartTime(System.currentTimeMillis()); } catch (IOException e) { error = true; break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.header.error"), t); // 400 - Bad Request response.setStatus(400); adapter.log(request, response, 0); error = true; } if (!error) { // Setting up filters, and parse some request headers rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); try { prepareRequest(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.request.prepare"), t); // 400 - Internal Server Error response.setStatus(400); adapter.log(request, response, 0); error = true; } } if (!error && !cping && endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); adapter.log(request, response, 0); error = true; } cping = false; // Process the request in the adapter if (!error) { try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("ajpprocessor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); error = true; } } if (isAsync() && !error) { break; } // Finish the response if not done yet if (!finished) { try { finish(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); error = true; } } // If there was an error, make sure the request is counted as // and error, and update the statistics counter if (error) { response.setStatus(500); } request.updateCounters(); rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); recycle(false); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (!error && !endpoint.isPaused()) { if (isAsync()) { return SocketState.LONG; } else { return SocketState.OPEN; } } else { return SocketState.CLOSED; } } // ----------------------------------------------------- ActionHook Methods /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override protected void actionInternal(ActionCode actionCode, Object param) { if (actionCode == ActionCode.ASYNC_COMPLETE) { if (asyncStateMachine.asyncComplete()) { ((AprEndpoint)endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) { if (param == null) return; long timeout = ((Long)param).longValue(); socketWrapper.setTimeout(timeout); } else if (actionCode == ActionCode.ASYNC_DISPATCH) { if (asyncStateMachine.asyncDispatch()) { ((AprEndpoint)endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } } @Override protected void resetTimeouts() { // NO-OP. The AJP APR/native connector only uses the timeout value on // time SocketWrapper for async timeouts. } @Override protected void output(byte[] src, int offset, int length) throws IOException { outputBuffer.put(src, offset, length); long socketRef = socketWrapper.getSocket().longValue(); if (outputBuffer.position() > 0) { if ((socketRef != 0) && Socket.sendbb(socketRef, 0, outputBuffer.position()) < 0) { // There are no re-tries so clear the buffer to prevent a // possible overflow if the buffer is used again. BZ53119. outputBuffer.clear(); throw new IOException(sm.getString("ajpprocessor.failedsend")); } outputBuffer.clear(); } } /** * Read at least the specified amount of bytes, and place them * in the input buffer. */ protected boolean read(int n) throws IOException { if (inputBuffer.capacity() - inputBuffer.limit() <= n - inputBuffer.remaining()) { inputBuffer.compact(); inputBuffer.limit(inputBuffer.position()); inputBuffer.position(0); } int nRead; while (inputBuffer.remaining() < n) { nRead = Socket.recvbb (socketWrapper.getSocket().longValue(), inputBuffer.limit(), inputBuffer.capacity() - inputBuffer.limit()); if (nRead > 0) { inputBuffer.limit(inputBuffer.limit() + nRead); } else { throw new IOException(sm.getString("ajpprocessor.failedread")); } } return true; } /** * Read at least the specified amount of bytes, and place them * in the input buffer. */ protected boolean readt(int n, boolean useAvailableData) throws IOException { if (useAvailableData && inputBuffer.remaining() == 0) { return false; } if (inputBuffer.capacity() - inputBuffer.limit() <= n - inputBuffer.remaining()) { inputBuffer.compact(); inputBuffer.limit(inputBuffer.position()); inputBuffer.position(0); } int nRead; while (inputBuffer.remaining() < n) { nRead = Socket.recvbb (socketWrapper.getSocket().longValue(), inputBuffer.limit(), inputBuffer.capacity() - inputBuffer.limit()); if (nRead > 0) { inputBuffer.limit(inputBuffer.limit() + nRead); } else { if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { return false; } else { throw new IOException(sm.getString("ajpprocessor.failedread")); } } } return true; } /** Receive a chunk of data. Called to implement the * 'special' packet in ajp13 and to receive the data * after we send a GET_BODY packet */ @Override public boolean receive() throws IOException { first = false; bodyMessage.reset(); if (!readMessage(bodyMessage, false, false)) { // Invalid message return false; } // No data received. if (bodyMessage.getLen() == 0) { // just the header // Don't mark 'end of stream' for the first chunk. return false; } int blen = bodyMessage.peekInt(); if (blen == 0) { return false; } bodyMessage.getBodyBytes(bodyBytes); empty = false; return true; } /** * Read an AJP message. * * @param first is true if the message is the first in the request, which * will cause a short duration blocking read * @return true if the message has been read, false if the short read * didn't return anything * @throws IOException any other failure, including incomplete reads */ protected boolean readMessage(AjpMessage message, boolean first, boolean useAvailableData) throws IOException { int headerLength = message.getHeaderLength(); if (first) { if (!readt(headerLength, useAvailableData)) { return false; } } else { read(headerLength); } inputBuffer.get(message.getBuffer(), 0, headerLength); int messageLength = message.processHeader(true); if (messageLength < 0) { // Invalid AJP header signature // TODO: Throw some exception and close the connection to frontend. return false; } else if (messageLength == 0) { // Zero length message. return true; } else { if (messageLength > message.getBuffer().length) { // Message too long for the buffer // Need to trigger a 400 response throw new IllegalArgumentException(sm.getString( "ajpprocessor.header.tooLong", Integer.valueOf(messageLength), Integer.valueOf(message.getBuffer().length))); } read(messageLength); inputBuffer.get(message.getBuffer(), headerLength, messageLength); return true; } } /** * Recycle the processor. */ @Override public void recycle(boolean socketClosing) { super.recycle(socketClosing); inputBuffer.clear(); inputBuffer.limit(0); outputBuffer.clear(); } } tomcat7-7.0.52/java/org/apache/coyote/ajp/AjpNioProcessor.java0000644000175100017510000003547012276702205024107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import java.io.EOFException; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.nio.channels.Selector; import org.apache.coyote.ActionCode; import org.apache.coyote.RequestInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; import org.apache.tomcat.util.net.NioSelectorPool; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Processes AJP requests using NIO. */ public class AjpNioProcessor extends AbstractAjpProcessor { /** * Logger. */ private static final Log log = LogFactory.getLog(AjpNioProcessor.class); @Override protected Log getLog() { return log; } // ----------------------------------------------------------- Constructors public AjpNioProcessor(int packetSize, NioEndpoint endpoint) { super(packetSize, endpoint); response.setOutputBuffer(new SocketOutputBuffer()); pool = endpoint.getSelectorPool(); } // ----------------------------------------------------- Instance Variables /** * Selector pool for the associated endpoint. */ protected NioSelectorPool pool; // --------------------------------------------------------- Public Methods /** * Process pipelined HTTP requests using the specified input and output * streams. * * @throws IOException error during an I/O operation */ @Override public SocketState process(SocketWrapper socket) throws IOException { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); // Setting up the socket this.socketWrapper = socket; long soTimeout = endpoint.getSoTimeout(); boolean cping = false; // Error flag error = false; while (!error && !endpoint.isPaused()) { // Parsing the request header try { // Get first message of the request int bytesRead = readMessage(requestHeaderMessage, false); if (bytesRead == 0) { break; } // Set back timeout if keep alive timeout is enabled if (keepAliveTimeout > 0) { socket.setTimeout(soTimeout); } // Check message type, process right away and break if // not regular request processing int type = requestHeaderMessage.getByte(); if (type == Constants.JK_AJP13_CPING_REQUEST) { if (endpoint.isPaused()) { recycle(true); break; } cping = true; try { output(pongMessageArray, 0, pongMessageArray.length); } catch (IOException e) { error = true; } recycle(false); continue; } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { // Unexpected packet type. Unread body packets should have // been swallowed in finish(). if (log.isDebugEnabled()) { log.debug("Unexpected message: " + type); } error = true; recycle(true); break; } request.setStartTime(System.currentTimeMillis()); } catch (IOException e) { error = true; break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.header.error"), t); // 400 - Bad Request response.setStatus(400); adapter.log(request, response, 0); error = true; } if (!error) { // Setting up filters, and parse some request headers rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); try { prepareRequest(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.request.prepare"), t); // 400 - Internal Server Error response.setStatus(400); adapter.log(request, response, 0); error = true; } } if (!error && !cping && endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); adapter.log(request, response, 0); error = true; } cping = false; // Process the request in the adapter if (!error) { try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("ajpprocessor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); error = true; } } if (isAsync() && !error) { break; } // Finish the response if not done yet if (!finished) { try { finish(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); error = true; } } // If there was an error, make sure the request is counted as // and error, and update the statistics counter if (error) { response.setStatus(500); } request.updateCounters(); rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); // Set keep alive timeout if enabled if (keepAliveTimeout > 0) { socket.setTimeout(keepAliveTimeout); } recycle(false); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (!error && !endpoint.isPaused()) { if (isAsync()) { return SocketState.LONG; } else { return SocketState.OPEN; } } else { return SocketState.CLOSED; } } // ----------------------------------------------------- ActionHook Methods /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override protected void actionInternal(ActionCode actionCode, Object param) { if (actionCode == ActionCode.ASYNC_COMPLETE) { if (asyncStateMachine.asyncComplete()) { ((NioEndpoint)endpoint).processSocket(this.socketWrapper.getSocket(), SocketStatus.OPEN_READ, false); } } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) { if (param == null) return; long timeout = ((Long)param).longValue(); final KeyAttachment ka = (KeyAttachment)socketWrapper.getSocket().getAttachment(false); ka.setTimeout(timeout); } else if (actionCode == ActionCode.ASYNC_DISPATCH) { if (asyncStateMachine.asyncDispatch()) { ((NioEndpoint)endpoint).processSocket(this.socketWrapper.getSocket(), SocketStatus.OPEN_READ, true); } } } @Override protected void resetTimeouts() { // The NIO connector uses the timeout configured on the wrapper in the // poller. Therefore, it needs to be reset once asycn processing has // finished. final KeyAttachment attach = (KeyAttachment)socketWrapper.getSocket().getAttachment(false); if (!error && attach != null && asyncStateMachine.isAsyncDispatching()) { long soTimeout = endpoint.getSoTimeout(); //reset the timeout if (keepAliveTimeout > 0) { attach.setTimeout(keepAliveTimeout); } else { attach.setTimeout(soTimeout); } } } @Override protected void output(byte[] src, int offset, int length) throws IOException { ByteBuffer writeBuffer = socketWrapper.getSocket().getBufHandler().getWriteBuffer(); writeBuffer.put(src, offset, length); writeBuffer.flip(); KeyAttachment att = (KeyAttachment) socketWrapper.getSocket().getAttachment(false); if ( att == null ) throw new IOException("Key must be cancelled"); long writeTimeout = att.getWriteTimeout(); Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { //ignore } try { pool.write(writeBuffer, socketWrapper.getSocket(), selector, writeTimeout, true); }finally { if ( selector != null ) pool.put(selector); } writeBuffer.clear(); } /** * Read the specified amount of bytes, and place them in the input buffer. */ protected int read(byte[] buf, int pos, int n, boolean blockFirstRead) throws IOException { int read = 0; int res = 0; boolean block = blockFirstRead; while (read < n) { res = readSocket(buf, read + pos, n, block); if (res > 0) { read += res; } else if (res == 0 && !block) { break; } else { throw new IOException(sm.getString("ajpprocessor.failedread")); } block = true; } return read; } private int readSocket(byte[] buf, int pos, int n, boolean block) throws IOException { int nRead = 0; ByteBuffer readBuffer = socketWrapper.getSocket().getBufHandler().getReadBuffer(); readBuffer.clear(); readBuffer.limit(n); if ( block ) { Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { // Ignore } try { NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) socketWrapper.getSocket().getAttachment(false); if ( att == null ) throw new IOException("Key must be cancelled."); nRead = pool.read(readBuffer, socketWrapper.getSocket(), selector, att.getTimeout()); } catch ( EOFException eof ) { nRead = -1; } finally { if ( selector != null ) pool.put(selector); } } else { nRead = socketWrapper.getSocket().read(readBuffer); } if (nRead > 0) { readBuffer.flip(); readBuffer.limit(nRead); readBuffer.get(buf, pos, nRead); return nRead; } else if (nRead == -1) { //return false; throw new EOFException(sm.getString("iib.eof.error")); } else { return 0; } } /** Receive a chunk of data. Called to implement the * 'special' packet in ajp13 and to receive the data * after we send a GET_BODY packet */ @Override public boolean receive() throws IOException { first = false; bodyMessage.reset(); readMessage(bodyMessage, true); // No data received. if (bodyMessage.getLen() == 0) { // just the header // Don't mark 'end of stream' for the first chunk. return false; } int blen = bodyMessage.peekInt(); if (blen == 0) { return false; } bodyMessage.getBodyBytes(bodyBytes); empty = false; return true; } /** * Read an AJP message. * * @return The number of bytes read * @throws IOException any other failure, including incomplete reads */ protected int readMessage(AjpMessage message, boolean blockFirstRead) throws IOException { byte[] buf = message.getBuffer(); int headerLength = message.getHeaderLength(); int bytesRead = read(buf, 0, headerLength, blockFirstRead); if (bytesRead == 0) { return 0; } int messageLength = message.processHeader(true); if (messageLength < 0) { // Invalid AJP header signature throw new IOException(sm.getString("ajpmessage.invalidLength", Integer.valueOf(messageLength))); } else if (messageLength == 0) { // Zero length message. return bytesRead; } else { if (messageLength > buf.length) { // Message too long for the buffer // Need to trigger a 400 response throw new IllegalArgumentException(sm.getString( "ajpprocessor.header.tooLong", Integer.valueOf(messageLength), Integer.valueOf(buf.length))); } bytesRead += read(buf, headerLength, messageLength, true); return bytesRead; } } } tomcat7-7.0.52/java/org/apache/coyote/ajp/Constants.java0000644000175100017510000003550412271461367023007 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import java.util.Hashtable; import org.apache.tomcat.util.buf.ByteChunk; /** * Constants. * * @author Remy Maucherat */ public final class Constants { // -------------------------------------------------------------- Constants /** * Package name. */ public static final String Package = "org.apache.coyote.ajp"; public static final int DEFAULT_CONNECTION_LINGER = -1; public static final int DEFAULT_CONNECTION_TIMEOUT = -1; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000; public static final boolean DEFAULT_TCP_NO_DELAY = true; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final boolean DEFAULT_USE_SENDFILE = false; // Prefix codes for message types from server to container public static final byte JK_AJP13_FORWARD_REQUEST = 2; public static final byte JK_AJP13_SHUTDOWN = 7; // XXX Unused public static final byte JK_AJP13_PING_REQUEST = 8; // XXX Unused public static final byte JK_AJP13_CPING_REQUEST = 10; // Prefix codes for message types from container to server public static final byte JK_AJP13_SEND_BODY_CHUNK = 3; public static final byte JK_AJP13_SEND_HEADERS = 4; public static final byte JK_AJP13_END_RESPONSE = 5; public static final byte JK_AJP13_GET_BODY_CHUNK = 6; public static final byte JK_AJP13_CPONG_REPLY = 9; // Integer codes for common response header strings public static final int SC_RESP_CONTENT_TYPE = 0xA001; public static final int SC_RESP_CONTENT_LANGUAGE = 0xA002; public static final int SC_RESP_CONTENT_LENGTH = 0xA003; public static final int SC_RESP_DATE = 0xA004; public static final int SC_RESP_LAST_MODIFIED = 0xA005; public static final int SC_RESP_LOCATION = 0xA006; public static final int SC_RESP_SET_COOKIE = 0xA007; public static final int SC_RESP_SET_COOKIE2 = 0xA008; public static final int SC_RESP_SERVLET_ENGINE = 0xA009; public static final int SC_RESP_STATUS = 0xA00A; public static final int SC_RESP_WWW_AUTHENTICATE = 0xA00B; public static final int SC_RESP_AJP13_MAX = 11; // Integer codes for common (optional) request attribute names public static final byte SC_A_CONTEXT = 1; // XXX Unused public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused public static final byte SC_A_REMOTE_USER = 3; public static final byte SC_A_AUTH_TYPE = 4; public static final byte SC_A_QUERY_STRING = 5; public static final byte SC_A_JVM_ROUTE = 6; public static final byte SC_A_SSL_CERT = 7; public static final byte SC_A_SSL_CIPHER = 8; public static final byte SC_A_SSL_SESSION = 9; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte SC_A_SSL_KEYSIZE = 11; public static final byte SC_A_SSL_KEY_SIZE = 11; public static final byte SC_A_SECRET = 12; public static final byte SC_A_STORED_METHOD = 13; // Used for attributes which are not in the list above public static final byte SC_A_REQ_ATTRIBUTE = 10; /** * AJP private request attributes */ public static final String SC_A_REQ_REMOTE_PORT = "AJP_REMOTE_PORT"; // Terminates list of attributes public static final byte SC_A_ARE_DONE = (byte)0xFF; // Ajp13 specific - needs refactoring for the new model /** * Default maximum total byte size for a AJP packet */ public static final int MAX_PACKET_SIZE = 8192; /** * Size of basic packet header */ public static final int H_SIZE = 4; /** * Size of the header metadata */ public static final int READ_HEAD_LEN = 6; public static final int SEND_HEAD_LEN = 8; /** * Default maximum size of data that can be sent in one packet */ public static final int MAX_READ_SIZE = MAX_PACKET_SIZE - READ_HEAD_LEN; public static final int MAX_SEND_SIZE = MAX_PACKET_SIZE - SEND_HEAD_LEN; // Translates integer codes to names of HTTP methods private static final String [] methodTransArray = { "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", "ACL", "REPORT", "VERSION-CONTROL", "CHECKIN", "CHECKOUT", "UNCHECKOUT", "SEARCH", "MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BASELINE-CONTROL", "MKACTIVITY" }; /** * Converts an AJP coded HTTP method to the method name. * @param code the coded value * @return the string value of the method */ public static final String getMethodForCode(final int code) { return methodTransArray[code]; } public static final int SC_M_JK_STORED = (byte) 0xFF; // id's for common request headers public static final int SC_REQ_ACCEPT = 1; public static final int SC_REQ_ACCEPT_CHARSET = 2; public static final int SC_REQ_ACCEPT_ENCODING = 3; public static final int SC_REQ_ACCEPT_LANGUAGE = 4; public static final int SC_REQ_AUTHORIZATION = 5; public static final int SC_REQ_CONNECTION = 6; public static final int SC_REQ_CONTENT_TYPE = 7; public static final int SC_REQ_CONTENT_LENGTH = 8; public static final int SC_REQ_COOKIE = 9; public static final int SC_REQ_COOKIE2 = 10; public static final int SC_REQ_HOST = 11; public static final int SC_REQ_PRAGMA = 12; public static final int SC_REQ_REFERER = 13; public static final int SC_REQ_USER_AGENT = 14; // Translates integer codes to request header names private static final String [] headerTransArray = { "accept", "accept-charset", "accept-encoding", "accept-language", "authorization", "connection", "content-type", "content-length", "cookie", "cookie2", "host", "pragma", "referer", "user-agent" }; /** * Converts an AJP coded HTTP request header to the header name. * @param code the coded value * @return the string value of the header name */ public static final String getHeaderForCode(final int code) { return headerTransArray[code]; } // Translates integer codes to response header names private static final String [] responseTransArray = { "Content-Type", "Content-Language", "Content-Length", "Date", "Last-Modified", "Location", "Set-Cookie", "Set-Cookie2", "Servlet-Engine", "Status", "WWW-Authenticate" }; /** * Converts an AJP coded response header name to the HTTP response header name. * @param code the coded value * @return the string value of the header */ public static final String getResponseHeaderForCode(final int code) { return responseTransArray[code]; } private static final Hashtable responseTransHash = new Hashtable(20); static { try { int i; for (i = 0; i < SC_RESP_AJP13_MAX; i++) { responseTransHash.put(getResponseHeaderForCode(i), Integer.valueOf(0xA001 + i)); } } catch (Exception e) { // Do nothing } } public static final int getResponseAjpIndex(String header) { Integer i = responseTransHash.get(header); if (i == null) return 0; else return i.intValue(); } /** * CRLF. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String CRLF = "\r\n"; /** * Server string. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] SERVER_BYTES = ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF); /** * CR. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte CR = (byte) '\r'; /** * LF. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte LF = (byte) '\n'; /** * SP. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte SP = (byte) ' '; /** * HT. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte HT = (byte) '\t'; /** * COLON. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte COLON = (byte) ':'; /** * 'A'. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte A = (byte) 'A'; /** * 'a'. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte a = (byte) 'a'; /** * 'Z'. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte Z = (byte) 'Z'; /** * '?'. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte QUESTION = (byte) '?'; /** * Lower case offset. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte LC_OFFSET = A - a; /** * Default HTTP header buffer size. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024; /* Various constant "strings" */ /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF); /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": "); /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String CONNECTION = "Connection"; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String CLOSE = "close"; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] CLOSE_BYTES = ByteChunk.convertToBytes(CLOSE); /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String KEEPALIVE = "keep-alive"; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] KEEPALIVE_BYTES = ByteChunk.convertToBytes(KEEPALIVE); /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String CHUNKED = "chunked"; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] ACK_BYTES = ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF); /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String TRANSFERENCODING = "Transfer-Encoding"; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] _200_BYTES = ByteChunk.convertToBytes("200"); /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] _400_BYTES = ByteChunk.convertToBytes("400"); /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] _404_BYTES = ByteChunk.convertToBytes("404"); /** * Identity filters (input and output). * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final int IDENTITY_FILTER = 0; /** * Chunked filters (input and output). * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final int CHUNKED_FILTER = 1; /** * Void filters (input and output). * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final int VOID_FILTER = 2; /** * GZIP filter (output). * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final int GZIP_FILTER = 3; /** * Buffered filter (input) * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final int BUFFERED_FILTER = 3; /** * HTTP/1.0. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String HTTP_10 = "HTTP/1.0"; /** * HTTP/1.1. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String HTTP_11 = "HTTP/1.1"; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final byte[] HTTP_11_BYTES = ByteChunk.convertToBytes(HTTP_11); /** * GET. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String GET = "GET"; /** * HEAD. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String HEAD = "HEAD"; /** * POST. * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final String POST = "POST"; } tomcat7-7.0.52/java/org/apache/coyote/ajp/LocalStrings.properties0000644000175100017510000000432712271461367024711 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. ajpprotocol.endpoint.starterror=Error starting endpoint ajpprotocol.init=Initializing Coyote AJP/1.3 on {0} ajpprotocol.start=Starting Coyote AJP/1.3 on {0} ajpprotocol.failedwrite=Socket write failed ajpprotocol.request.register=Error registering request processor in JMX ajpprocessor.failedread=Socket read failed ajpprocessor.failedflush=Failed to flush AJP message ajpprocessor.failedsend=Failed to send AJP message ajpprocessor.header.error=Header message parsing failed ajpprocessor.header.tooLong=Header message of length [{0}] received but the packetSize is only [{1}] ajpprocessor.request.prepare=Error preparing request ajpprocessor.request.process=Error processing request ajpprocessor.certs.fail=Certificate conversion failed ajpprocessor.socket.info=Exception getting socket information ajpprocessor.comet.notsupported=The Comet protocol is not supported by this connector ajpprocessor.ssl.notsupported=The SSL protocol is not supported by this connector ajpprocessor.httpupgrade.notsupported=HTTP upgrades are not supported by this connector ajpmessage.null=Cannot append null value ajpmessage.overflow=Overflow error for buffer adding {0} bytes at position {1} ajpmessage.read=Requested {0} bytes exceeds message available data ajpmessage.invalid=Invalid message received with signature {0} ajpmessage.invalidLength=Invalid message received with length {0} ajpMessage.invalidPos=Requested read of bytes at position [{0}] which is beyond the end of the AJP message tomcat7-7.0.52/java/org/apache/coyote/ajp/AjpProtocol.java0000644000175100017510000001065612271461367023270 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.ajp; import java.net.Socket; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.JIoEndpoint; import org.apache.tomcat.util.net.JIoEndpoint.Handler; import org.apache.tomcat.util.net.SSLImplementation; import org.apache.tomcat.util.net.SocketWrapper; /** * Abstract the protocol implementation, including threading, etc. * Processor is single threaded and specific to stream-based protocols, * will not fit Jk protocols like JNI. * * @author Remy Maucherat * @author Costin Manolache */ public class AjpProtocol extends AbstractAjpProtocol { private static final Log log = LogFactory.getLog(AjpProtocol.class); @Override protected Log getLog() { return log; } @Override protected AbstractEndpoint.Handler getHandler() { return cHandler; } // ------------------------------------------------------------ Constructor public AjpProtocol() { endpoint = new JIoEndpoint(); cHandler = new AjpConnectionHandler(this); ((JIoEndpoint) endpoint).setHandler(cHandler); setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); } // ----------------------------------------------------- Instance Variables /** * Connection handler for AJP. */ private AjpConnectionHandler cHandler; // ----------------------------------------------------- JMX related methods @Override protected String getNamePrefix() { return ("ajp-bio"); } // -------------------------------------- AjpConnectionHandler Inner Class protected static class AjpConnectionHandler extends AbstractAjpConnectionHandler implements Handler { protected AjpProtocol proto; public AjpConnectionHandler(AjpProtocol proto) { this.proto = proto; } @Override protected AbstractProtocol getProtocol() { return proto; } @Override protected Log getLog() { return log; } @Override public SSLImplementation getSslImplementation() { // AJP does not support SSL return null; } /** * Expected to be used by the handler once the processor is no longer * required. * * @param socket Ignored for BIO * @param processor * @param isSocketClosing * @param addToPoller Ignored for BIO */ @Override public void release(SocketWrapper socket, Processor processor, boolean isSocketClosing, boolean addToPoller) { processor.recycle(isSocketClosing); recycledProcessors.offer(processor); } @Override protected AjpProcessor createProcessor() { AjpProcessor processor = new AjpProcessor(proto.packetSize, (JIoEndpoint)proto.endpoint); processor.setAdapter(proto.adapter); processor.setTomcatAuthentication(proto.tomcatAuthentication); processor.setRequiredSecret(proto.requiredSecret); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); processor.setClientCertProvider(proto.getClientCertProvider()); register(processor); return processor; } } } tomcat7-7.0.52/java/org/apache/coyote/RequestInfo.java0000644000175100017510000001570112271461367022522 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import javax.management.ObjectName; /** * Structure holding the Request and Response objects. It also holds statistical * informations about request processing and provide management informations * about the requests being processed. * * Each thread uses a Request/Response pair that is recycled on each request. * This object provides a place to collect global low-level statistics - without * having to deal with synchronization ( since each thread will have it's own * RequestProcessorMX ). * * TODO: Request notifications will be registered here. * * @author Costin Manolache */ public class RequestInfo { RequestGroupInfo global=null; // ----------------------------------------------------------- Constructors public RequestInfo( Request req) { this.req=req; } public RequestGroupInfo getGlobalProcessor() { return global; } public void setGlobalProcessor(RequestGroupInfo global) { if( global != null) { this.global=global; global.addRequestProcessor( this ); } else { if (this.global != null) { this.global.removeRequestProcessor( this ); this.global = null; } } } // ----------------------------------------------------- Instance Variables Request req; int stage = Constants.STAGE_NEW; String workerThreadName; ObjectName rpName; // -------------------- Information about the current request ----------- // This is useful for long-running requests only public String getMethod() { return req.method().toString(); } public String getCurrentUri() { return req.requestURI().toString(); } public String getCurrentQueryString() { return req.queryString().toString(); } public String getProtocol() { return req.protocol().toString(); } public String getVirtualHost() { return req.serverName().toString(); } public int getServerPort() { return req.getServerPort(); } public String getRemoteAddr() { req.action(ActionCode.REQ_HOST_ADDR_ATTRIBUTE, null); return req.remoteAddr().toString(); } /** * Obtain the remote address for this connection as reported by an * intermediate proxy (if any). */ public String getRemoteAddrForwarded() { String remoteAddrProxy = (String) req.getAttribute(Constants.REMOTE_ADDR_ATTRIBUTE); if (remoteAddrProxy == null) { return getRemoteAddr(); } return remoteAddrProxy; } public int getContentLength() { return req.getContentLength(); } public long getRequestBytesReceived() { return req.getBytesRead(); } public long getRequestBytesSent() { return req.getResponse().getContentWritten(); } public long getRequestProcessingTime() { if ( getStage() == org.apache.coyote.Constants.STAGE_ENDED ) return 0; else return (System.currentTimeMillis() - req.getStartTime()); } // -------------------- Statistical data -------------------- // Collected at the end of each request. private long bytesSent; private long bytesReceived; // Total time = divide by requestCount to get average. private long processingTime; // The longest response time for a request private long maxTime; // URI of the request that took maxTime private String maxRequestUri; private int requestCount; // number of response codes >= 400 private int errorCount; //the time of the last request private long lastRequestProcessingTime = 0; /** Called by the processor before recycling the request. It'll collect * statistic information. */ void updateCounters() { bytesReceived+=req.getBytesRead(); bytesSent+=req.getResponse().getContentWritten(); requestCount++; if( req.getResponse().getStatus() >=400 ) errorCount++; long t0=req.getStartTime(); long t1=System.currentTimeMillis(); long time=t1-t0; this.lastRequestProcessingTime = time; processingTime+=time; if( maxTime < time ) { maxTime=time; maxRequestUri=req.requestURI().toString(); } } public int getStage() { return stage; } public void setStage(int stage) { this.stage = stage; } public long getBytesSent() { return bytesSent; } public void setBytesSent(long bytesSent) { this.bytesSent = bytesSent; } public long getBytesReceived() { return bytesReceived; } public void setBytesReceived(long bytesReceived) { this.bytesReceived = bytesReceived; } public long getProcessingTime() { return processingTime; } public void setProcessingTime(long processingTime) { this.processingTime = processingTime; } public long getMaxTime() { return maxTime; } public void setMaxTime(long maxTime) { this.maxTime = maxTime; } public String getMaxRequestUri() { return maxRequestUri; } public void setMaxRequestUri(String maxRequestUri) { this.maxRequestUri = maxRequestUri; } public int getRequestCount() { return requestCount; } public void setRequestCount(int requestCount) { this.requestCount = requestCount; } public int getErrorCount() { return errorCount; } public void setErrorCount(int errorCount) { this.errorCount = errorCount; } public String getWorkerThreadName() { return workerThreadName; } public ObjectName getRpName() { return rpName; } public long getLastRequestProcessingTime() { return lastRequestProcessingTime; } public void setWorkerThreadName(String workerThreadName) { this.workerThreadName = workerThreadName; } public void setRpName(ObjectName rpName) { this.rpName = rpName; } public void setLastRequestProcessingTime(long lastRequestProcessingTime) { this.lastRequestProcessingTime = lastRequestProcessingTime; } } tomcat7-7.0.52/java/org/apache/coyote/http11/0000755000175100017510000000000012301126366020517 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/coyote/http11/LocalStrings_es.properties0000644000175100017510000000470212271461367025744 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. http11protocol.endpoint.starterror = Error arrancando punto final (endpoint) http11protocol.proto.error = Error leyendo requerimiento, ignorado http11protocol.proto.ioexception.debug = IOException leyendo requerimiento http11protocol.proto.ioexception.info = IOException leyendo requerimiento, ignorada http11protocol.proto.socketexception.debug = SocketException leyendo requerimiento http11protocol.proto.socketexception.info = SocketException leyendo requerimiento, ignorada http11protocol.start = Arrancando Coyote HTTP/1.1 en puerto {0} http11processor.regexp.error = Error al analizar expresi\u00F3n regular {0} http11processor.filter.unknown = Filtro desconocido {0} http11processor.filter.error = Error inicializando filtro {0} http11processor.header.parse = Error analizando cabecera de requerimiento HTTP http11processor.neverused = Este m\u00E9todo no deber\u00EDa de usarse nunca http11processor.request.prepare = Error preparando requerimiento http11processor.request.process = Error procesando requerimiento http11processor.request.finish = Error acabando requerimiento http11processor.response.finish = Error acabando respuesta http11processor.socket.info = Excepci\u00F3n obteniendo informaci\u00F3n de conector http11processor.socket.ssl = Excepci\u00F3n obteniendo atributos SSL http11processor.socket.sslreneg = Excepci\u00F3n renegociando la conexi\u00F3n SSL http11processor.socket.timeout = Error poniendo tiempo agotado para conector iib.eof.error = Inesperado Fin De Archivo (EOF) le\u00EDdo en el enchufe (socket) iib.requestheadertoolarge.error = La cabecera del requerimiento es demasido grande iib.invalidmethod = Car\u00E1cter inv\u00E1lido (CR o LF) hallado en el nombre del m\u00E9todo tomcat7-7.0.52/java/org/apache/coyote/http11/InternalAprInputBuffer.java0000644000175100017510000004336212271461367025774 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.EOFException; import java.io.IOException; import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; /** * Implementation of InputBuffer which provides HTTP request header parsing as * well as transfer decoding. * * @author Remy Maucherat */ public class InternalAprInputBuffer extends AbstractInputBuffer { private static final Log log = LogFactory.getLog(InternalAprInputBuffer.class); // ----------------------------------------------------------- Constructors /** * Alternate constructor. */ public InternalAprInputBuffer(Request request, int headerBufferSize) { this.request = request; headers = request.getMimeHeaders(); buf = new byte[headerBufferSize]; if (headerBufferSize < (8 * 1024)) { bbuf = ByteBuffer.allocateDirect(6 * 1500); } else { bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); } inputStreamInputBuffer = new SocketInputBuffer(); filterLibrary = new InputFilter[0]; activeFilters = new InputFilter[0]; lastActiveFilter = -1; parsingHeader = true; swallowInput = true; } // ----------------------------------------------------- Instance Variables /** * Direct byte buffer used to perform actual reading. */ private ByteBuffer bbuf; /** * Underlying socket. */ private long socket; // --------------------------------------------------------- Public Methods /** * Recycle the input buffer. This should be called when closing the * connection. */ @Override public void recycle() { socket = 0; super.recycle(); } /** * Read the request line. This function is meant to be used during the * HTTP request header parsing. Do NOT attempt to read the request body * using it. * * @throws IOException If an exception occurs during the underlying socket * read operations, or if the given buffer is not big enough to accommodate * the whole line. * @return true if data is properly fed; false if no data is available * immediately and thread should be freed */ @Override public boolean parseRequestLine(boolean useAvailableData) throws IOException { int start = 0; // // Skipping blank lines // byte chr = 0; do { // Read new bytes if needed if (pos >= lastValid) { if (useAvailableData) { return false; } if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } chr = buf[pos++]; } while ((chr == Constants.CR) || (chr == Constants.LF)); pos--; // Mark the current buffer position start = pos; if (pos >= lastValid) { if (useAvailableData) { return false; } if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } // // Reading the method name // Method name is always US-ASCII // boolean space = false; while (!space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } // Spec says no CR or LF in method name if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) { throw new IllegalArgumentException( sm.getString("iib.invalidmethod")); } // Spec says single SP but it also says be tolerant of HT if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; request.method().setBytes(buf, start, pos - start); } pos++; } // Spec says single SP but also says be tolerant of multiple and/or HT while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { pos++; } else { space = false; } } // Mark the current buffer position start = pos; int end = 0; int questionPos = -1; // // Reading the URI // boolean eol = false; while (!space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } // Spec says single SP but it also says be tolerant of HT if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; end = pos; } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) { // HTTP/0.9 style request eol = true; space = true; end = pos; } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { questionPos = pos; } pos++; } request.unparsedURI().setBytes(buf, start, end - start); if (questionPos >= 0) { request.queryString().setBytes(buf, questionPos + 1, end - questionPos - 1); request.requestURI().setBytes(buf, start, questionPos - start); } else { request.requestURI().setBytes(buf, start, end - start); } // Spec says single SP but also says be tolerant of multiple and/or HT while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { pos++; } else { space = false; } } // Mark the current buffer position start = pos; end = 0; // // Reading the protocol // Protocol is always US-ASCII // while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.CR) { end = pos; } else if (buf[pos] == Constants.LF) { if (end == 0) end = pos; eol = true; } pos++; } if ((end - start) > 0) { request.protocol().setBytes(buf, start, end - start); } else { request.protocol().setString(""); } return true; } /** * Parse the HTTP headers. */ @Override public boolean parseHeaders() throws IOException { if (!parsingHeader) { throw new IllegalStateException( sm.getString("iib.parseheaders.ise.error")); } while (parseHeader()) { // Loop until there are no more headers } parsingHeader = false; end = pos; return true; } /** * Parse an HTTP header. * * @return false after reading a blank line (which indicates that the * HTTP header parsing is done */ @SuppressWarnings("null") // headerValue cannot be null private boolean parseHeader() throws IOException { // // Check for blank line // byte chr = 0; while (true) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } chr = buf[pos]; if (chr == Constants.CR) { // Skip } else if (chr == Constants.LF) { pos++; return false; } else { break; } pos++; } // Mark the current buffer position int start = pos; // // Reading the header name // Header name is always US-ASCII // boolean colon = false; MessageBytes headerValue = null; while (!colon) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.COLON) { colon = true; headerValue = headers.addValue(buf, start, pos - start); } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { // If a non-token header is detected, skip the line and // ignore the header skipLine(start); return true; } chr = buf[pos]; if ((chr >= Constants.A) && (chr <= Constants.Z)) { buf[pos] = (byte) (chr - Constants.LC_OFFSET); } pos++; } // Mark the current buffer position start = pos; int realPos = pos; // // Reading the header value (which can be spanned over multiple lines) // boolean eol = false; boolean validLine = true; while (validLine) { boolean space = true; // Skipping spaces while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { pos++; } else { space = false; } } int lastSignificantChar = realPos; // Reading bytes until the end of the line while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.CR) { // Skip } else if (buf[pos] == Constants.LF) { eol = true; } else if (buf[pos] == Constants.SP) { buf[realPos] = buf[pos]; realPos++; } else { buf[realPos] = buf[pos]; realPos++; lastSignificantChar = realPos; } pos++; } realPos = lastSignificantChar; // Checking the first character of the new line. If the character // is a LWS, then it's a multiline header // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } chr = buf[pos]; if ((chr != Constants.SP) && (chr != Constants.HT)) { validLine = false; } else { eol = false; // Copying one extra space in the buffer (since there must // be at least one space inserted between the lines) buf[realPos] = chr; realPos++; } } // Set the header value headerValue.setBytes(buf, start, realPos - start); return true; } private void skipLine(int start) throws IOException { boolean eol = false; int lastRealByte = start; if (pos - 1 > start) { lastRealByte = pos - 1; } while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.CR) { // Skip } else if (buf[pos] == Constants.LF) { eol = true; } else { lastRealByte = pos; } pos++; } if (log.isDebugEnabled()) { log.debug(sm.getString("iib.invalidheader", new String(buf, start, lastRealByte - start + 1, Charset.forName("ISO-8859-1")))); } } // ---------------------------------------------------- InputBuffer Methods /** * Read some bytes. */ @Override public int doRead(ByteChunk chunk, Request req) throws IOException { if (lastActiveFilter == -1) return inputStreamInputBuffer.doRead(chunk, req); else return activeFilters[lastActiveFilter].doRead(chunk,req); } // ------------------------------------------------------ Protected Methods @Override protected void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException { socket = socketWrapper.getSocket().longValue(); Socket.setrbb(this.socket, bbuf); } @Override protected boolean fill(boolean block) throws IOException { // Ignore the block parameter and just call fill return fill(); } /** * Fill the internal buffer using data from the underlying input stream. * * @return false if at end of stream */ protected boolean fill() throws IOException { int nRead = 0; if (parsingHeader) { if (lastValid == buf.length) { throw new IllegalArgumentException (sm.getString("iib.requestheadertoolarge.error")); } bbuf.clear(); nRead = Socket.recvbb(socket, 0, buf.length - lastValid); if (nRead > 0) { bbuf.limit(nRead); bbuf.get(buf, pos, nRead); lastValid = pos + nRead; } else { if ((-nRead) == Status.EAGAIN) { return false; } else { throw new IOException(sm.getString("iib.failedread")); } } } else { if (buf.length - end < 4500) { // In this case, the request header was really large, so we allocate a // brand new one; the old one will get GCed when subsequent requests // clear all references buf = new byte[buf.length]; end = 0; } pos = end; lastValid = pos; bbuf.clear(); nRead = Socket.recvbb(socket, 0, buf.length - lastValid); if (nRead > 0) { bbuf.limit(nRead); bbuf.get(buf, pos, nRead); lastValid = pos + nRead; } else { if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { throw new SocketTimeoutException(sm.getString("iib.failedread")); } else if (nRead == 0) { // APR_STATUS_IS_EOF, since native 1.1.22 return false; } else { throw new IOException(sm.getString("iib.failedread")); } } } return (nRead > 0); } // ------------------------------------- InputStreamInputBuffer Inner Class /** * This class is an input buffer which will read its data from an input * stream. */ protected class SocketInputBuffer implements InputBuffer { /** * Read bytes into the specified chunk. */ @Override public int doRead(ByteChunk chunk, Request req ) throws IOException { if (pos >= lastValid) { if (!fill()) return -1; } int length = lastValid - pos; chunk.setBytes(buf, pos, length); pos = lastValid; return (length); } } } tomcat7-7.0.52/java/org/apache/coyote/http11/HeadersTooLargeException.java0000644000175100017510000000262512017761001026251 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; /** * Exception used to mark the specific error condition of the HTTP headers * exceeding the maximum permitted size. */ public class HeadersTooLargeException extends IllegalStateException { private static final long serialVersionUID = 1L; public HeadersTooLargeException() { super(); } public HeadersTooLargeException(String message, Throwable cause) { super(message, cause); } public HeadersTooLargeException(String s) { super(s); } public HeadersTooLargeException(Throwable cause) { super(cause); } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/0000755000175100017510000000000012301126366022167 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/coyote/http11/filters/BufferedInputFilter.java0000644000175100017510000000775212271461367026766 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import java.nio.charset.Charset; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.coyote.http11.InputFilter; import org.apache.tomcat.util.buf.ByteChunk; /** * Input filter responsible for reading and buffering the request body, so that * it does not interfere with client SSL handshake messages. */ public class BufferedInputFilter implements InputFilter { // -------------------------------------------------------------- Constants private static final String ENCODING_NAME = "buffered"; private static final ByteChunk ENCODING = new ByteChunk(); // ----------------------------------------------------- Instance Variables private ByteChunk buffered = null; private ByteChunk tempRead = new ByteChunk(1024); private InputBuffer buffer; private boolean hasRead = false; // ----------------------------------------------------- Static Initializer static { ENCODING.setBytes(ENCODING_NAME.getBytes(Charset.defaultCharset()), 0, ENCODING_NAME.length()); } // --------------------------------------------------------- Public Methods /** * Set the buffering limit. This should be reset every time the buffer is * used. */ public void setLimit(int limit) { if (buffered == null) { buffered = new ByteChunk(4048); buffered.setLimit(limit); } } // ---------------------------------------------------- InputBuffer Methods /** * Reads the request body and buffers it. */ @Override public void setRequest(Request request) { // save off the Request body try { while (buffer.doRead(tempRead, request) >= 0) { buffered.append(tempRead); tempRead.recycle(); } } catch(IOException ioe) { // No need for i18n - this isn't going to get logged anywhere throw new IllegalStateException( "Request body too large for buffer"); } } /** * Fills the given ByteChunk with the buffered request body. */ @Override public int doRead(ByteChunk chunk, Request request) throws IOException { if (hasRead || buffered.getLength() <= 0) { return -1; } chunk.setBytes(buffered.getBytes(), buffered.getStart(), buffered.getLength()); hasRead = true; return chunk.getLength(); } @Override public void setBuffer(InputBuffer buffer) { this.buffer = buffer; } @Override public void recycle() { if (buffered != null) { if (buffered.getBuffer().length > 65536) { buffered = null; } else { buffered.recycle(); } } tempRead.recycle(); hasRead = false; buffer = null; } @Override public ByteChunk getEncodingName() { return ENCODING; } @Override public long end() throws IOException { return 0; } @Override public int available() { return buffered.getLength(); } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java0000644000175100017510000001071212271461367027014 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.coyote.http11.OutputFilter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.HexUtils; /** * Chunked output filter. * * @author Remy Maucherat */ public class ChunkedOutputFilter implements OutputFilter { // -------------------------------------------------------------- Constants /** * End chunk. */ protected static final ByteChunk END_CHUNK = new ByteChunk(); // ----------------------------------------------------- Static Initializer static { byte[] END_CHUNK_BYTES = {(byte) '0', (byte) '\r', (byte) '\n', (byte) '\r', (byte) '\n'}; END_CHUNK.setBytes(END_CHUNK_BYTES, 0, END_CHUNK_BYTES.length); } // ------------------------------------------------------------ Constructor /** * Default constructor. */ public ChunkedOutputFilter() { chunkLength = new byte[10]; chunkLength[8] = (byte) '\r'; chunkLength[9] = (byte) '\n'; } // ----------------------------------------------------- Instance Variables /** * Next buffer in the pipeline. */ protected OutputBuffer buffer; /** * Buffer used for chunk length conversion. */ protected byte[] chunkLength = new byte[10]; /** * Chunk header. */ protected ByteChunk chunkHeader = new ByteChunk(); // ------------------------------------------------------------- Properties // --------------------------------------------------- OutputBuffer Methods /** * Write some bytes. * * @return number of bytes written by the filter */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { int result = chunk.getLength(); if (result <= 0) { return 0; } // Calculate chunk header int pos = 7; int current = result; while (current > 0) { int digit = current % 16; current = current / 16; chunkLength[pos--] = HexUtils.getHex(digit); } chunkHeader.setBytes(chunkLength, pos + 1, 9 - pos); buffer.doWrite(chunkHeader, res); buffer.doWrite(chunk, res); chunkHeader.setBytes(chunkLength, 8, 2); buffer.doWrite(chunkHeader, res); return result; } @Override public long getBytesWritten() { return buffer.getBytesWritten(); } // --------------------------------------------------- OutputFilter Methods /** * Some filters need additional parameters from the response. All the * necessary reading can occur in that method, as this method is called * after the response header processing is complete. */ @Override public void setResponse(Response response) { // NOOP: No need for parameters from response in this filter } /** * Set the next buffer in the filter pipeline. */ @Override public void setBuffer(OutputBuffer buffer) { this.buffer = buffer; } /** * End the current request. It is acceptable to write extra bytes using * buffer.doWrite during the execution of this method. */ @Override public long end() throws IOException { // Write end chunk buffer.doWrite(END_CHUNK, null); return 0; } /** * Make the filter ready to process the next request. */ @Override public void recycle() { // NOOP: Nothing to recycle } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java0000644000175100017510000001004112271461367027217 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.coyote.http11.OutputFilter; import org.apache.tomcat.util.buf.ByteChunk; /** * Identity output filter. * * @author Remy Maucherat */ public class IdentityOutputFilter implements OutputFilter { // ----------------------------------------------------- Instance Variables /** * Content length. */ protected long contentLength = -1; /** * Remaining bytes. */ protected long remaining = 0; /** * Next buffer in the pipeline. */ protected OutputBuffer buffer; // --------------------------------------------------- OutputBuffer Methods /** * Write some bytes. * * @return number of bytes written by the filter */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { int result = -1; if (contentLength >= 0) { if (remaining > 0) { result = chunk.getLength(); if (result > remaining) { // The chunk is longer than the number of bytes remaining // in the body; changing the chunk length to the number // of bytes remaining chunk.setBytes(chunk.getBytes(), chunk.getStart(), (int) remaining); result = (int) remaining; remaining = 0; } else { remaining = remaining - result; } buffer.doWrite(chunk, res); } else { // No more bytes left to be written : return -1 and clear the // buffer chunk.recycle(); result = -1; } } else { // If no content length was set, just write the bytes buffer.doWrite(chunk, res); result = chunk.getLength(); } return result; } @Override public long getBytesWritten() { return buffer.getBytesWritten(); } // --------------------------------------------------- OutputFilter Methods /** * Some filters need additional parameters from the response. All the * necessary reading can occur in that method, as this method is called * after the response header processing is complete. */ @Override public void setResponse(Response response) { contentLength = response.getContentLengthLong(); remaining = contentLength; } /** * Set the next buffer in the filter pipeline. */ @Override public void setBuffer(OutputBuffer buffer) { this.buffer = buffer; } /** * End the current request. It is acceptable to write extra bytes using * buffer.doWrite during the execution of this method. */ @Override public long end() throws IOException { if (remaining > 0) return remaining; return 0; } /** * Make the filter ready to process the next request. */ @Override public void recycle() { contentLength = -1; remaining = 0; } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/GzipOutputFilter.java0000644000175100017510000001233012271461367026342 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.coyote.http11.OutputFilter; import org.apache.tomcat.util.buf.ByteChunk; /** * Gzip output filter. * * @author Remy Maucherat */ public class GzipOutputFilter implements OutputFilter { /** * Logger. */ protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(GzipOutputFilter.class); // ----------------------------------------------------- Instance Variables /** * Next buffer in the pipeline. */ protected OutputBuffer buffer; /** * Compression output stream. */ protected GZIPOutputStream compressionStream = null; /** * Fake internal output stream. */ protected OutputStream fakeOutputStream = new FakeOutputStream(); // --------------------------------------------------- OutputBuffer Methods /** * Write some bytes. * * @return number of bytes written by the filter */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { if (compressionStream == null) { compressionStream = new FlushableGZIPOutputStream(fakeOutputStream); } compressionStream.write(chunk.getBytes(), chunk.getStart(), chunk.getLength()); return chunk.getLength(); } @Override public long getBytesWritten() { return buffer.getBytesWritten(); } // --------------------------------------------------- OutputFilter Methods /** * Added to allow flushing to happen for the gzip'ed outputstream */ public void flush() { if (compressionStream != null) { try { if (log.isDebugEnabled()) { log.debug("Flushing the compression stream!"); } compressionStream.flush(); } catch (IOException e) { if (log.isDebugEnabled()) { log.debug("Ignored exception while flushing gzip filter", e); } } } } /** * Some filters need additional parameters from the response. All the * necessary reading can occur in that method, as this method is called * after the response header processing is complete. */ @Override public void setResponse(Response response) { // NOOP: No need for parameters from response in this filter } /** * Set the next buffer in the filter pipeline. */ @Override public void setBuffer(OutputBuffer buffer) { this.buffer = buffer; } /** * End the current request. It is acceptable to write extra bytes using * buffer.doWrite during the execution of this method. */ @Override public long end() throws IOException { if (compressionStream == null) { compressionStream = new FlushableGZIPOutputStream(fakeOutputStream); } compressionStream.finish(); compressionStream.close(); return ((OutputFilter) buffer).end(); } /** * Make the filter ready to process the next request. */ @Override public void recycle() { // Set compression stream to null compressionStream = null; } // ------------------------------------------- FakeOutputStream Inner Class protected class FakeOutputStream extends OutputStream { protected ByteChunk outputChunk = new ByteChunk(); protected byte[] singleByteBuffer = new byte[1]; @Override public void write(int b) throws IOException { // Shouldn't get used for good performance, but is needed for // compatibility with Sun JDK 1.4.0 singleByteBuffer[0] = (byte) (b & 0xff); outputChunk.setBytes(singleByteBuffer, 0, 1); buffer.doWrite(outputChunk, null); } @Override public void write(byte[] b, int off, int len) throws IOException { outputChunk.setBytes(b, off, len); buffer.doWrite(outputChunk, null); } @Override public void flush() throws IOException {/*NOOP*/} @Override public void close() throws IOException {/*NOOP*/} } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java0000644000175100017510000000620112271461367027643 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import org.apache.coyote.InputBuffer; import org.apache.coyote.http11.InputFilter; import org.apache.tomcat.util.buf.ByteChunk; /** * Input filter responsible for replaying the request body when restoring the * saved request after FORM authentication. */ public class SavedRequestInputFilter implements InputFilter { /** * The original request body. */ protected ByteChunk input = null; /** * Create a new SavedRequestInputFilter. * * @param input The saved request body to be replayed. */ public SavedRequestInputFilter(ByteChunk input) { this.input = input; } /** * Read bytes. */ @Override public int doRead(ByteChunk chunk, org.apache.coyote.Request request) throws IOException { int writeLength = 0; if (chunk.getLimit() > 0 && chunk.getLimit() < input.getLength()) { writeLength = chunk.getLimit(); } else { writeLength = input.getLength(); } if(input.getOffset()>= input.getEnd()) return -1; input.substract(chunk.getBuffer(), 0, writeLength); chunk.setOffset(0); chunk.setEnd(writeLength); return writeLength; } /** * Set the content length on the request. */ @Override public void setRequest(org.apache.coyote.Request request) { request.setContentLength(input.getLength()); } /** * Make the filter ready to process the next request. */ @Override public void recycle() { input = null; } /** * Return the name of the associated encoding; here, the value is null. */ @Override public ByteChunk getEncodingName() { return null; } /** * Set the next buffer in the filter pipeline (has no effect). */ @Override public void setBuffer(InputBuffer buffer) { // NOOP since this filter will be providing the request body } /** * Amount of bytes still available in a buffer. */ @Override public int available() { return input.getLength(); } /** * End the current request (has no effect). */ @Override public long end() throws IOException { return 0; } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/VoidOutputFilter.java0000644000175100017510000000562612271461367026344 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.coyote.http11.OutputFilter; import org.apache.tomcat.util.buf.ByteChunk; /** * Void output filter, which silently swallows bytes written. Used with a 204 * status (no content) or a HEAD request. * * @author Remy Maucherat */ public class VoidOutputFilter implements OutputFilter { // --------------------------------------------------- OutputBuffer Methods /** * Write some bytes. * * @return number of bytes written by the filter */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { return chunk.getLength(); } @Override public long getBytesWritten() { return 0; } // --------------------------------------------------- OutputFilter Methods /** * Some filters need additional parameters from the response. All the * necessary reading can occur in that method, as this method is called * after the response header processing is complete. */ @Override public void setResponse(Response response) { // NOOP: No need for parameters from response in this filter } /** * Set the next buffer in the filter pipeline. */ @Override public void setBuffer(OutputBuffer buffer) { // NO-OP } /** * Make the filter ready to process the next request. */ @Override public void recycle() { // NOOP: Nothing to recycle } /** * End the current request. It is acceptable to write extra bytes using * buffer.doWrite during the execution of this method. * * @return Should return 0 unless the filter does some content length * delimitation, in which case the number is the amount of extra bytes or * missing bytes, which would indicate an error. * Note: It is recommended that extra bytes be swallowed by the filter. */ @Override public long end() throws IOException { return 0; } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/IdentityInputFilter.java0000644000175100017510000001270012271461367027022 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import java.nio.charset.Charset; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.coyote.http11.InputFilter; import org.apache.tomcat.util.buf.ByteChunk; /** * Identity input filter. * * @author Remy Maucherat */ public class IdentityInputFilter implements InputFilter { // -------------------------------------------------------------- Constants protected static final String ENCODING_NAME = "identity"; protected static final ByteChunk ENCODING = new ByteChunk(); // ----------------------------------------------------- Static Initializer static { ENCODING.setBytes(ENCODING_NAME.getBytes(Charset.defaultCharset()), 0, ENCODING_NAME.length()); } // ----------------------------------------------------- Instance Variables /** * Content length. */ protected long contentLength = -1; /** * Remaining bytes. */ protected long remaining = 0; /** * Next buffer in the pipeline. */ protected InputBuffer buffer; /** * Chunk used to read leftover bytes. */ protected ByteChunk endChunk = new ByteChunk(); // ------------------------------------------------------------- Properties /** * Get content length. * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public long getContentLength() { return contentLength; } /** * Get remaining bytes. * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public long getRemaining() { return remaining; } // ---------------------------------------------------- InputBuffer Methods /** * Read bytes. * * @return If the filter does request length control, this value is * significant; it should be the number of bytes consumed from the buffer, * up until the end of the current request body, or the buffer length, * whichever is greater. If the filter does not do request body length * control, the returned value should be -1. */ @Override public int doRead(ByteChunk chunk, Request req) throws IOException { int result = -1; if (contentLength >= 0) { if (remaining > 0) { int nRead = buffer.doRead(chunk, req); if (nRead > remaining) { // The chunk is longer than the number of bytes remaining // in the body; changing the chunk length to the number // of bytes remaining chunk.setBytes(chunk.getBytes(), chunk.getStart(), (int) remaining); result = (int) remaining; } else { result = nRead; } remaining = remaining - nRead; } else { // No more bytes left to be read : return -1 and clear the // buffer chunk.recycle(); result = -1; } } return result; } // ---------------------------------------------------- InputFilter Methods /** * Read the content length from the request. */ @Override public void setRequest(Request request) { contentLength = request.getContentLengthLong(); remaining = contentLength; } /** * End the current request. */ @Override public long end() throws IOException { // Consume extra bytes. while (remaining > 0) { int nread = buffer.doRead(endChunk, null); if (nread > 0 ) { remaining = remaining - nread; } else { // errors are handled higher up. remaining = 0; } } // If too many bytes were read, return the amount. return -remaining; } /** * Amount of bytes still available in a buffer. */ @Override public int available() { return 0; } /** * Set the next buffer in the filter pipeline. */ @Override public void setBuffer(InputBuffer buffer) { this.buffer = buffer; } /** * Make the filter ready to process the next request. */ @Override public void recycle() { contentLength = -1; remaining = 0; endChunk.recycle(); } /** * Return the name of the associated encoding; Here, the value is * "identity". */ @Override public ByteChunk getEncodingName() { return ENCODING; } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/VoidInputFilter.java0000644000175100017510000000674112271461367026142 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import java.nio.charset.Charset; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.coyote.http11.InputFilter; import org.apache.tomcat.util.buf.ByteChunk; /** * Void input filter, which returns -1 when attempting a read. Used with a GET, * HEAD, or a similar request. * * @author Remy Maucherat */ public class VoidInputFilter implements InputFilter { // -------------------------------------------------------------- Constants protected static final String ENCODING_NAME = "void"; protected static final ByteChunk ENCODING = new ByteChunk(); // ----------------------------------------------------- Static Initializer static { ENCODING.setBytes(ENCODING_NAME.getBytes(Charset.defaultCharset()), 0, ENCODING_NAME.length()); } // ----------------------------------------------------- Instance Variables // --------------------------------------------------- OutputBuffer Methods /** * Write some bytes. * * @return number of bytes written by the filter */ @Override public int doRead(ByteChunk chunk, Request req) throws IOException { return -1; } // --------------------------------------------------- OutputFilter Methods /** * Set the associated request. */ @Override public void setRequest(Request request) { // NOOP: Request isn't used so ignore it } /** * Set the next buffer in the filter pipeline. */ @Override public void setBuffer(InputBuffer buffer) { // NOOP: No body to read } /** * Make the filter ready to process the next request. */ @Override public void recycle() { // NOOP: Nothing to recycle } /** * Return the name of the associated encoding; Here, the value is * "void". */ @Override public ByteChunk getEncodingName() { return ENCODING; } /** * End the current request. It is acceptable to write extra bytes using * buffer.doWrite during the execution of this method. * * @return Should return 0 unless the filter does some content length * delimitation, in which case the number is the amount of extra bytes or * missing bytes, which would indicate an error. * Note: It is recommended that extra bytes be swallowed by the filter. */ @Override public long end() throws IOException { return 0; } /** * Amount of bytes still available in a buffer. */ @Override public int available() { return 0; } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java0000644000175100017510000001177412017264173030043 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.IOException; import java.io.OutputStream; import java.util.zip.Deflater; import java.util.zip.GZIPOutputStream; /** * Extension of {@link GZIPOutputStream} to workaround for a couple of long * standing JDK bugs * (Bug * 4255743 and * Bug * 4813885) so the GZIP'd output can be flushed. */ public class FlushableGZIPOutputStream extends GZIPOutputStream { public FlushableGZIPOutputStream(OutputStream os) throws IOException { super(os); } /** * It is used to reserve one byte of real data so that it can be used when * flushing the stream. */ private byte[] lastByte = new byte[1]; private boolean hasLastByte = false; /** * Flag that compression has to be re-enabled before the next write * operation. */ private boolean flagReenableCompression = false; @Override public void write(byte[] bytes) throws IOException { write(bytes, 0, bytes.length); } @Override public synchronized void write(byte[] bytes, int offset, int length) throws IOException { if (length > 0) { flushLastByte(); if (length > 1) { reenableCompression(); super.write(bytes, offset, length - 1); } rememberLastByte(bytes[offset + length - 1]); } } @Override public synchronized void write(int i) throws IOException { flushLastByte(); rememberLastByte((byte) i); } @Override public synchronized void finish() throws IOException { try { flushLastByte(); } catch (IOException ignore) { // If our write failed, then trailer write in finish() will fail // with IOException as well, but it will leave Deflater in more // consistent state. } super.finish(); } @Override public synchronized void close() throws IOException { try { flushLastByte(); } catch (IOException ignored) { // Ignore. As OutputStream#close() says, the contract of close() // is to close the stream. It does not matter much if the // stream is not writable any more. } super.close(); } private void reenableCompression() { if (flagReenableCompression && !def.finished()) { flagReenableCompression = false; def.setLevel(Deflater.DEFAULT_COMPRESSION); } } private void rememberLastByte(byte b) { lastByte[0] = b; hasLastByte = true; } private void flushLastByte() throws IOException { if (hasLastByte) { reenableCompression(); // Clear the flag first, because write() may fail hasLastByte = false; super.write(lastByte, 0, 1); } } @Override public synchronized void flush() throws IOException { if (hasLastByte) { // - do not allow the gzip header to be flushed on its own // - do not do anything if there is no data to send // trick the deflater to flush /** * Now this is tricky: We force the Deflater to flush its data by * switching compression level. As yet, a perplexingly simple workaround * for * http://developer.java.sun.com/developer/bugParade/bugs/4255743.html */ if (!def.finished()) { def.setLevel(Deflater.NO_COMPRESSION); flushLastByte(); flagReenableCompression = true; } } out.flush(); } /* * Keep on calling deflate until it runs dry. The default implementation * only does it once and can therefore hold onto data when they need to be * flushed out. */ @Override protected void deflate() throws IOException { int len; do { len = def.deflate(buf, 0, buf.length); if (len > 0) { out.write(buf, 0, len); } } while (len != 0); } } tomcat7-7.0.52/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java0000644000175100017510000004015112271461367026613 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.filters; import java.io.EOFException; import java.io.IOException; import java.nio.charset.Charset; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.coyote.http11.Constants; import org.apache.coyote.http11.InputFilter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.MimeHeaders; /** * Chunked input filter. Parses chunked data according to * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
    * * @author Remy Maucherat * @author Filip Hanik */ public class ChunkedInputFilter implements InputFilter { // -------------------------------------------------------------- Constants protected static final String ENCODING_NAME = "chunked"; protected static final ByteChunk ENCODING = new ByteChunk(); // ----------------------------------------------------- Static Initializer static { ENCODING.setBytes(ENCODING_NAME.getBytes(Charset.defaultCharset()), 0, ENCODING_NAME.length()); } // ----------------------------------------------------- Instance Variables /** * Next buffer in the pipeline. */ protected InputBuffer buffer; /** * Number of bytes remaining in the current chunk. */ protected int remaining = 0; /** * Position in the buffer. */ protected int pos = 0; /** * Last valid byte in the buffer. */ protected int lastValid = 0; /** * Read bytes buffer. */ protected byte[] buf = null; /** * Byte chunk used to read bytes. */ protected ByteChunk readChunk = new ByteChunk(); /** * Flag set to true when the end chunk has been read. */ protected boolean endChunk = false; /** * Byte chunk used to store trailing headers. */ protected ByteChunk trailingHeaders = new ByteChunk(); /** * Flag set to true if the next call to doRead() must parse a CRLF pair * before doing anything else. */ protected boolean needCRLFParse = false; /** * Request being parsed. */ private Request request; /** * Limit for extension size. */ private final long maxExtensionSize; /** * Limit for trailer size. */ private final int maxTrailerSize; /** * Size of extensions processed for this request. */ private long extensionSize; // ----------------------------------------------------------- Constructors public ChunkedInputFilter(int maxTrailerSize, int maxExtensionSize) { this.trailingHeaders.setLimit(maxTrailerSize); this.maxExtensionSize = maxExtensionSize; this.maxTrailerSize = maxTrailerSize; } // ---------------------------------------------------- InputBuffer Methods /** * Read bytes. * * @return If the filter does request length control, this value is * significant; it should be the number of bytes consumed from the buffer, * up until the end of the current request body, or the buffer length, * whichever is greater. If the filter does not do request body length * control, the returned value should be -1. */ @Override public int doRead(ByteChunk chunk, Request req) throws IOException { if (endChunk) return -1; if(needCRLFParse) { needCRLFParse = false; parseCRLF(false); } if (remaining <= 0) { if (!parseChunkHeader()) { throw new IOException("Invalid chunk header"); } if (endChunk) { parseEndChunk(); return -1; } } int result = 0; if (pos >= lastValid) { if (readBytes() < 0) { throw new IOException( "Unexpected end of stream whilst reading request body"); } } if (remaining > (lastValid - pos)) { result = lastValid - pos; remaining = remaining - result; chunk.setBytes(buf, pos, result); pos = lastValid; } else { result = remaining; chunk.setBytes(buf, pos, remaining); pos = pos + remaining; remaining = 0; //we need a CRLF if ((pos+1) >= lastValid) { //if we call parseCRLF we overrun the buffer here //so we defer it to the next call BZ 11117 needCRLFParse = true; } else { parseCRLF(false); //parse the CRLF immediately } } return result; } // ---------------------------------------------------- InputFilter Methods /** * Read the content length from the request. */ @Override public void setRequest(Request request) { this.request = request; } /** * End the current request. */ @Override public long end() throws IOException { // Consume extra bytes : parse the stream until the end chunk is found while (doRead(readChunk, null) >= 0) { // NOOP: Just consume the input } // Return the number of extra bytes which were consumed return (lastValid - pos); } /** * Amount of bytes still available in a buffer. */ @Override public int available() { return (lastValid - pos); } /** * Set the next buffer in the filter pipeline. */ @Override public void setBuffer(InputBuffer buffer) { this.buffer = buffer; } /** * Make the filter ready to process the next request. */ @Override public void recycle() { remaining = 0; pos = 0; lastValid = 0; endChunk = false; needCRLFParse = false; trailingHeaders.recycle(); trailingHeaders.setLimit(maxTrailerSize); extensionSize = 0; } /** * Return the name of the associated encoding; Here, the value is * "identity". */ @Override public ByteChunk getEncodingName() { return ENCODING; } // ------------------------------------------------------ Protected Methods /** * Read bytes from the previous buffer. */ protected int readBytes() throws IOException { int nRead = buffer.doRead(readChunk, null); pos = readChunk.getStart(); lastValid = pos + nRead; buf = readChunk.getBytes(); return nRead; } /** * Parse the header of a chunk. * A chunk header can look like one of the following:
    * A10CRLF
    * F23;chunk-extension to be ignoredCRLF * *

    * The letters before CRLF or ';' (whatever comes first) must be valid hex * digits. We should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid * header according to the spec. */ protected boolean parseChunkHeader() throws IOException { int result = 0; boolean eol = false; boolean readDigit = false; boolean extension = false; while (!eol) { if (pos >= lastValid) { if (readBytes() <= 0) return false; } if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) { parseCRLF(false); eol = true; } else if (buf[pos] == Constants.SEMI_COLON && !extension) { // First semi-colon marks the start of the extension. Further // semi-colons may appear to separate multiple chunk-extensions. // These need to be processed as part of parsing the extensions. extension = true; extensionSize++; } else if (!extension) { //don't read data after the trailer int charValue = HexUtils.getDec(buf[pos]); if (charValue != -1) { readDigit = true; result *= 16; result += charValue; } else { //we shouldn't allow invalid, non hex characters //in the chunked header return false; } } else { // Extension 'parsing' // Note that the chunk-extension is neither parsed nor // validated. Currently it is simply ignored. extensionSize++; if (maxExtensionSize > -1 && extensionSize > maxExtensionSize) { throw new IOException("maxExtensionSize exceeded"); } } // Parsing the CRLF increments pos if (!eol) { pos++; } } if (!readDigit) return false; if (result == 0) endChunk = true; remaining = result; if (remaining < 0) return false; return true; } /** * Parse CRLF at end of chunk. * @deprecated Use {@link #parseCRLF(boolean)} */ @Deprecated protected boolean parseCRLF() throws IOException { parseCRLF(false); return true; } /** * Parse CRLF at end of chunk. * * @param tolerant Should tolerant parsing (LF and CRLF) be used? This * is recommended (RFC2616, section 19.3) for message * headers. */ protected void parseCRLF(boolean tolerant) throws IOException { boolean eol = false; boolean crfound = false; while (!eol) { if (pos >= lastValid) { if (readBytes() <= 0) throw new IOException("Invalid CRLF"); } if (buf[pos] == Constants.CR) { if (crfound) throw new IOException("Invalid CRLF, two CR characters encountered."); crfound = true; } else if (buf[pos] == Constants.LF) { if (!tolerant && !crfound) { throw new IOException("Invalid CRLF, no CR character encountered."); } eol = true; } else { throw new IOException("Invalid CRLF"); } pos++; } } /** * Parse end chunk data. */ protected void parseEndChunk() throws IOException { // Handle optional trailer headers while (parseHeader()) { // Loop until we run out of headers } } private boolean parseHeader() throws IOException { MimeHeaders headers = request.getMimeHeaders(); byte chr = 0; // Read new bytes if needed if (pos >= lastValid) { if (readBytes() <0) throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request"); } chr = buf[pos]; // CRLF terminates the request if (chr == Constants.CR || chr == Constants.LF) { parseCRLF(false); return false; } // Mark the current buffer position int start = trailingHeaders.getEnd(); // // Reading the header name // Header name is always US-ASCII // boolean colon = false; while (!colon) { // Read new bytes if needed if (pos >= lastValid) { if (readBytes() <0) throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request"); } chr = buf[pos]; if ((chr >= Constants.A) && (chr <= Constants.Z)) { chr = (byte) (chr - Constants.LC_OFFSET); } if (chr == Constants.COLON) { colon = true; } else { trailingHeaders.append(chr); } pos++; } MessageBytes headerValue = headers.addValue(trailingHeaders.getBytes(), start, trailingHeaders.getEnd() - start); // Mark the current buffer position start = trailingHeaders.getEnd(); // // Reading the header value (which can be spanned over multiple lines) // boolean eol = false; boolean validLine = true; int lastSignificantChar = 0; while (validLine) { boolean space = true; // Skipping spaces while (space) { // Read new bytes if needed if (pos >= lastValid) { if (readBytes() <0) throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request"); } chr = buf[pos]; if ((chr == Constants.SP) || (chr == Constants.HT)) { pos++; // If we swallow whitespace, make sure it counts towards the // limit placed on trailing header size int newlimit = trailingHeaders.getLimit() -1; if (trailingHeaders.getEnd() > newlimit) { throw new IOException("Exceeded maxTrailerSize"); } trailingHeaders.setLimit(newlimit); } else { space = false; } } // Reading bytes until the end of the line while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (readBytes() <0) throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request"); } chr = buf[pos]; if (chr == Constants.CR || chr == Constants.LF) { parseCRLF(true); eol = true; } else if (chr == Constants.SP) { trailingHeaders.append(chr); } else { trailingHeaders.append(chr); lastSignificantChar = trailingHeaders.getEnd(); } if (!eol) { pos++; } } // Checking the first character of the new line. If the character // is a LWS, then it's a multiline header // Read new bytes if needed if (pos >= lastValid) { if (readBytes() <0) throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request"); } chr = buf[pos]; if ((chr != Constants.SP) && (chr != Constants.HT)) { validLine = false; } else { eol = false; // Copying one extra space in the buffer (since there must // be at least one space inserted between the lines) trailingHeaders.append(chr); } } // Set the header value headerValue.setBytes(trailingHeaders.getBytes(), start, lastSignificantChar - start); return true; } } tomcat7-7.0.52/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java0000644000175100017510000001140111635362167026505 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import org.apache.tomcat.util.net.SSLImplementation; public abstract class AbstractHttp11JsseProtocol extends AbstractHttp11Protocol { protected SSLImplementation sslImplementation = null; public String getAlgorithm() { return endpoint.getAlgorithm();} public void setAlgorithm(String s ) { endpoint.setAlgorithm(s);} public String getClientAuth() { return endpoint.getClientAuth();} public void setClientAuth(String s ) { endpoint.setClientAuth(s);} public String getKeystoreFile() { return endpoint.getKeystoreFile();} public void setKeystoreFile(String s ) { endpoint.setKeystoreFile(s);} public String getKeystorePass() { return endpoint.getKeystorePass();} public void setKeystorePass(String s ) { endpoint.setKeystorePass(s);} public String getKeystoreType() { return endpoint.getKeystoreType();} public void setKeystoreType(String s ) { endpoint.setKeystoreType(s);} public String getKeystoreProvider() { return endpoint.getKeystoreProvider(); } public void setKeystoreProvider(String s ) { endpoint.setKeystoreProvider(s); } public String getSslProtocol() { return endpoint.getSslProtocol();} public void setSslProtocol(String s) { endpoint.setSslProtocol(s);} public String getCiphers() { return endpoint.getCiphers();} public void setCiphers(String s) { endpoint.setCiphers(s);} public String getKeyAlias() { return endpoint.getKeyAlias();} public void setKeyAlias(String s ) { endpoint.setKeyAlias(s);} public String getKeyPass() { return endpoint.getKeyPass();} public void setKeyPass(String s ) { endpoint.setKeyPass(s);} public void setTruststoreFile(String f){ endpoint.setTruststoreFile(f);} public String getTruststoreFile(){ return endpoint.getTruststoreFile();} public void setTruststorePass(String p){ endpoint.setTruststorePass(p);} public String getTruststorePass(){return endpoint.getTruststorePass();} public void setTruststoreType(String t){ endpoint.setTruststoreType(t);} public String getTruststoreType(){ return endpoint.getTruststoreType();} public void setTruststoreProvider(String t){ endpoint.setTruststoreProvider(t); } public String getTruststoreProvider(){ return endpoint.getTruststoreProvider(); } public void setTruststoreAlgorithm(String a){ endpoint.setTruststoreAlgorithm(a); } public String getTruststoreAlgorithm(){ return endpoint.getTruststoreAlgorithm(); } public void setTrustMaxCertLength(String s){ endpoint.setTrustMaxCertLength(s); } public String getTrustMaxCertLength(){ return endpoint.getTrustMaxCertLength(); } public void setCrlFile(String s){endpoint.setCrlFile(s);} public String getCrlFile(){ return endpoint.getCrlFile();} public void setSessionCacheSize(String s){endpoint.setSessionCacheSize(s);} public String getSessionCacheSize(){ return endpoint.getSessionCacheSize();} public void setSessionTimeout(String s){endpoint.setSessionTimeout(s);} public String getSessionTimeout(){ return endpoint.getSessionTimeout();} public void setAllowUnsafeLegacyRenegotiation(String s) { endpoint.setAllowUnsafeLegacyRenegotiation(s); } public String getAllowUnsafeLegacyRenegotiation() { return endpoint.getAllowUnsafeLegacyRenegotiation(); } private String sslImplementationName = null; public String getSslImplementationName() { return sslImplementationName; } public void setSslImplementationName(String s) { this.sslImplementationName = s; } // ------------------------------------------------------- Lifecycle methods @Override public void init() throws Exception { // SSL implementation needs to be in place before end point is // initialized sslImplementation = SSLImplementation.getInstance(sslImplementationName); super.init(); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/0000755000175100017510000000000012301126366022146 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/NioServletInputStream.java0000644000175100017510000001061212203412523027271 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Selector; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioSelectorPool; import org.apache.tomcat.util.net.SocketWrapper; public class NioServletInputStream extends AbstractServletInputStream { private final NioChannel channel; private final NioSelectorPool pool; public NioServletInputStream(SocketWrapper wrapper, NioSelectorPool pool) { this.channel = wrapper.getSocket(); this.pool = pool; } @Override protected boolean doIsReady() throws IOException { ByteBuffer readBuffer = channel.getBufHandler().getReadBuffer(); if (readBuffer.remaining() > 0) { return true; } readBuffer.clear(); fillReadBuffer(false); boolean isReady = readBuffer.position() > 0; readBuffer.flip(); return isReady; } @Override protected int doRead(boolean block, byte[] b, int off, int len) throws IOException { ByteBuffer readBuffer = channel.getBufHandler().getReadBuffer(); int remaining = readBuffer.remaining(); // Is there enough data in the read buffer to satisfy this request? if (remaining >= len) { readBuffer.get(b, off, len); return len; } // Copy what data there is in the read buffer to the byte array int leftToWrite = len; int newOffset = off; if (remaining > 0) { readBuffer.get(b, off, remaining); leftToWrite -= remaining; newOffset += remaining; } // Fill the read buffer as best we can readBuffer.clear(); int nRead = fillReadBuffer(block); // Full as much of the remaining byte array as possible with the data // that was just read if (nRead > 0) { readBuffer.flip(); if (nRead > leftToWrite) { readBuffer.get(b, newOffset, leftToWrite); leftToWrite = 0; } else { readBuffer.get(b, newOffset, nRead); leftToWrite -= nRead; } } else if (nRead == 0) { readBuffer.flip(); } else if (nRead == -1) { // TODO i18n throw new EOFException(); } return len - leftToWrite; } @Override protected void doClose() throws IOException { channel.close(); } private int fillReadBuffer(boolean block) throws IOException { int nRead; if (block) { Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { // Ignore } try { NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) channel.getAttachment(false); if (att == null) { throw new IOException("Key must be cancelled."); } nRead = pool.read(channel.getBufHandler().getReadBuffer(), channel, selector, att.getTimeout()); } catch (EOFException eof) { nRead = -1; } finally { if (selector != null) { pool.put(selector); } } } else { nRead = channel.read(channel.getBufHandler().getReadBuffer()); } return nRead; } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/BioServletOutputStream.java0000644000175100017510000000311612203412523027457 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import org.apache.tomcat.util.net.SocketWrapper; public class BioServletOutputStream extends AbstractServletOutputStream { private final OutputStream os; public BioServletOutputStream(SocketWrapper wrapper) throws IOException { os = wrapper.getSocket().getOutputStream(); } @Override protected int doWrite(boolean block, byte[] b, int off, int len) throws IOException { os.write(b, off, len); return len; } @Override protected void doFlush() throws IOException { os.flush(); } @Override protected void doClose() throws IOException { os.close(); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/BioProcessor.java0000644000175100017510000000321612203412523025416 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.net.Socket; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.SocketWrapper; public class BioProcessor extends AbstractProcessor { private static final Log log = LogFactory.getLog(BioProcessor.class); @Override protected Log getLog() {return log;} private static final int INFINITE_TIMEOUT = 0; public BioProcessor(SocketWrapper wrapper, HttpUpgradeHandler httpUpgradeProcessor) throws IOException { super(httpUpgradeProcessor, new BioServletInputStream(wrapper), new BioServletOutputStream(wrapper)); wrapper.getSocket().setSoTimeout(INFINITE_TIMEOUT); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/UpgradeInbound.java0000644000175100017510000000306612204665710025727 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; /** * Receives notification that there is data to be read on the upgraded * connection and processes it. * * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public interface UpgradeInbound { void setUpgradeProcessor(UpgradeProcessor processor); void onUpgradeComplete(); SocketState onData() throws IOException; void setUpgradeOutbound(UpgradeOutbound upgradeOutbound); /** * Allow the upgraded protocol to define the read timeout to be used with * the upgraded connection. * * @return The read timeout in milliseconds or -1 for infinite */ int getReadTimeout(); } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java0000644000175100017510000001132512204665710026305 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.util.concurrent.Executor; import org.apache.coyote.Processor; import org.apache.coyote.Request; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; import org.apache.tomcat.util.res.StringManager; /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public abstract class UpgradeProcessor implements Processor { protected static final StringManager sm = StringManager.getManager(Constants.Package); private final UpgradeInbound upgradeInbound; protected UpgradeProcessor (UpgradeInbound upgradeInbound) { this.upgradeInbound = upgradeInbound; upgradeInbound.setUpgradeProcessor(this); upgradeInbound.setUpgradeOutbound(new UpgradeOutbound(this)); } // Output methods public abstract void flush() throws IOException; public abstract void write(int b) throws IOException; public abstract void write(byte[] b, int off, int len) throws IOException; // Input methods /** * This is always a blocking read of a single byte. * * @return The next byte or -1 if the end of the input is reached. * * @throws IOException If a problem occurs trying to read from the input */ public abstract int read() throws IOException; /** * Read up to len bytes from the input in either blocking or non-blocking * mode (where non-blocking is supported). If the input does not support * non-blocking reads, a blcoking read will be performed. * * @param block * @param bytes * @param off * @param len * @return The number of bytes read or -1 if the end of the input is * reached. Non-blocking reads may return zero if no data is * available. Blocking reads never return zero. * * @throws IOException If a problem occurs trying to read from the input */ public abstract int read(boolean block, byte[] bytes, int off, int len) throws IOException; @Override public final UpgradeInbound getUpgradeInbound() { return upgradeInbound; } @Override public final SocketState upgradeDispatch() throws IOException { return upgradeInbound.onData(); } @Override public final void recycle(boolean socketClosing) { // Currently a NO-OP as upgrade processors are not recycled. } // Servlet 3.1 based HTTP upgrade mechanism. NO-OPs for the proprietary // Tomcat upgrade mechanism. @Override public HttpUpgradeHandler getHttpUpgradeHandler() { return null; } @Override public SocketState upgradeDispatch(SocketStatus status) throws IOException { return null; } @Override public boolean isUpgrade() { return false; } // NO-OP methods for upgrade @Override public final Executor getExecutor() { return null; } @Override public final SocketState process(SocketWrapper socketWrapper) throws IOException { return null; } @Override public final SocketState event(SocketStatus status) throws IOException { return null; } @Override public final SocketState asyncDispatch(SocketStatus status) { return null; } @Override public final SocketState asyncPostProcess() { return null; } @Override public final boolean isComet() { return false; } @Override public final boolean isAsync() { return false; } @Override public final Request getRequest() { return null; } @Override public final void setSslSupport(SSLSupport sslSupport) { // NOOP } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/UpgradeOutbound.java0000644000175100017510000000303412204665710026123 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.io.OutputStream; /** * Allows data to be written to the upgraded connection. * * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public class UpgradeOutbound extends OutputStream { @Override public void flush() throws IOException { processor.flush(); } private final UpgradeProcessor processor; public UpgradeOutbound(UpgradeProcessor processor) { this.processor = processor; } @Override public void write(int b) throws IOException { processor.write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { processor.write(b, off, len); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java0000644000175100017510000001320712204665710026462 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.util.concurrent.Executor; import org.apache.coyote.Processor; import org.apache.coyote.Request; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.coyote.http11.upgrade.servlet31.WebConnection; import org.apache.juli.logging.Log; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; import org.apache.tomcat.util.res.StringManager; public abstract class AbstractProcessor implements Processor, WebConnection { protected static final StringManager sm = StringManager.getManager(Constants.Package); protected abstract Log getLog(); private final HttpUpgradeHandler httpUpgradeHandler; private final AbstractServletInputStream upgradeServletInputStream; private final AbstractServletOutputStream upgradeServletOutputStream; protected AbstractProcessor (HttpUpgradeHandler httpUpgradeHandler, AbstractServletInputStream upgradeServletInputStream, AbstractServletOutputStream upgradeServletOutputStream) { this.httpUpgradeHandler = httpUpgradeHandler; this.upgradeServletInputStream = upgradeServletInputStream; this.upgradeServletOutputStream = upgradeServletOutputStream; } // --------------------------------------------------- AutoCloseable methods @Override public void close() throws Exception { upgradeServletInputStream.close(); upgradeServletOutputStream.close(); } // --------------------------------------------------- WebConnection methods @Override public AbstractServletInputStream getInputStream() throws IOException { return upgradeServletInputStream; } @Override public AbstractServletOutputStream getOutputStream() throws IOException { return upgradeServletOutputStream; } // ------------------------------------------- Implemented Processor methods @Override public final boolean isUpgrade() { return true; } @Override public HttpUpgradeHandler getHttpUpgradeHandler() { return httpUpgradeHandler; } @Override public final SocketState upgradeDispatch(SocketStatus status) throws IOException { if (status == SocketStatus.OPEN_READ) { upgradeServletInputStream.onDataAvailable(); } else if (status == SocketStatus.OPEN_WRITE) { upgradeServletOutputStream.onWritePossible(); } else if (status == SocketStatus.STOP) { try { upgradeServletInputStream.close(); } catch (IOException ioe) { getLog().debug(sm.getString( "abstractProcessor.isCloseFail", ioe)); } try { upgradeServletOutputStream.close(); } catch (IOException ioe) { getLog().debug(sm.getString( "abstractProcessor.osCloseFail", ioe)); } return SocketState.CLOSED; } else { // Unexpected state return SocketState.CLOSED; } if (upgradeServletInputStream.isCloseRequired() || upgradeServletOutputStream.isCloseRequired()) { return SocketState.CLOSED; } return SocketState.UPGRADED; } @Override public final void recycle(boolean socketClosing) { // Currently a NO-OP as upgrade processors are not recycled. } // ------------------ Processor methods for Inbound/Outbound based mechanism @Override @Deprecated public UpgradeInbound getUpgradeInbound() { return null; } @Override public SocketState upgradeDispatch() throws IOException { return null; } // ---------------------------- Processor methods that are NO-OP for upgrade @Override public final Executor getExecutor() { return null; } @Override public final SocketState process(SocketWrapper socketWrapper) throws IOException { return null; } @Override public final SocketState event(SocketStatus status) throws IOException { return null; } @Override public final SocketState asyncDispatch(SocketStatus status) { return null; } @Override public final SocketState asyncPostProcess() { return null; } @Override public final boolean isComet() { return false; } @Override public final boolean isAsync() { return false; } @Override public final Request getRequest() { return null; } @Override public final void setSslSupport(SSLSupport sslSupport) { // NOOP } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/UpgradeAprProcessor.java0000644000175100017510000000624112204665710026751 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.net.SocketWrapper; /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public class UpgradeAprProcessor extends UpgradeProcessor { private final long socket; public UpgradeAprProcessor(SocketWrapper wrapper, UpgradeInbound upgradeInbound) { super(upgradeInbound); Socket.timeoutSet(wrapper.getSocket().longValue(), upgradeInbound.getReadTimeout()); this.socket = wrapper.getSocket().longValue(); } /* * Output methods */ @Override public void flush() throws IOException { // NOOP } @Override public void write(int b) throws IOException { int result = Socket.send(socket, new byte[] {(byte) b}, 0, 1); if (result != 1) { throw new IOException(sm.getString("apr.write.error", Integer.valueOf(-result))); } } @Override public void write(byte[]b, int off, int len) throws IOException { int result = Socket.send(socket, b, off, len); if (result != len) { throw new IOException(sm.getString("apr.write.error", Integer.valueOf(-result))); } } /* * Input methods */ @Override public int read() throws IOException { byte[] bytes = new byte[1]; int result = Socket.recv(socket, bytes, 0, 1); if (result == -1) { return -1; } else { return bytes[0] & 0xFF; } } @Override public int read(boolean block, byte[] bytes, int off, int len) throws IOException { if (!block) { Socket.optSet(socket, Socket.APR_SO_NONBLOCK, -1); } try { int result = Socket.recv(socket, bytes, off, len); if (result > 0) { return result; } else if (-result == Status.EAGAIN) { return 0; } else { throw new IOException(sm.getString("apr.read.error", Integer.valueOf(-result))); } } finally { if (!block) { Socket.optSet(socket, Socket.APR_SO_NONBLOCK, 0); } } } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/AprServletOutputStream.java0000644000175100017510000001367012232541115027500 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.apache.tomcat.jni.OS; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.SocketWrapper; public class AprServletOutputStream extends AbstractServletOutputStream { private static final int SSL_OUTPUT_BUFFER_SIZE = 8192; private final AprEndpoint endpoint; private final SocketWrapper wrapper; private final long socket; private volatile boolean closed = false; private final ByteBuffer sslOutputBuffer; public AprServletOutputStream(SocketWrapper wrapper, AprEndpoint endpoint) { this.endpoint = endpoint; this.wrapper = wrapper; this.socket = wrapper.getSocket().longValue(); if (endpoint.isSSLEnabled()) { sslOutputBuffer = ByteBuffer.allocateDirect(SSL_OUTPUT_BUFFER_SIZE); sslOutputBuffer.position(SSL_OUTPUT_BUFFER_SIZE); } else { sslOutputBuffer = null; } } @Override protected int doWrite(boolean block, byte[] b, int off, int len) throws IOException { if (closed) { throw new IOException(sm.getString("apr.closed", Long.valueOf(socket))); } Lock readLock = wrapper.getBlockingStatusReadLock(); WriteLock writeLock = wrapper.getBlockingStatusWriteLock(); try { readLock.lock(); if (wrapper.getBlockingStatus() == block) { return doWriteInternal(b, off, len); } } finally { readLock.unlock(); } try { writeLock.lock(); // Set the current settings for this socket wrapper.setBlockingStatus(block); if (block) { Socket.timeoutSet(socket, endpoint.getSoTimeout() * 1000); } else { Socket.timeoutSet(socket, 0); } // Downgrade the lock try { readLock.lock(); writeLock.unlock(); return doWriteInternal(b, off, len); } finally { readLock.unlock(); } } finally { // Should have been released above but may not have been on some // exception paths if (writeLock.isHeldByCurrentThread()) { writeLock.unlock(); } } } private int doWriteInternal(byte[] b, int off, int len) throws IOException { int start = off; int left = len; int written; do { if (endpoint.isSSLEnabled()) { if (sslOutputBuffer.remaining() == 0) { // Buffer was fully written last time around sslOutputBuffer.clear(); if (left < SSL_OUTPUT_BUFFER_SIZE) { sslOutputBuffer.put(b, start, left); } else { sslOutputBuffer.put(b, start, SSL_OUTPUT_BUFFER_SIZE); } sslOutputBuffer.flip(); } else { // Buffer still has data from previous attempt to write // APR + SSL requires that exactly the same parameters are // passed when re-attempting the write } written = Socket.sendb(socket, sslOutputBuffer, sslOutputBuffer.position(), sslOutputBuffer.limit()); if (written > 0) { sslOutputBuffer.position( sslOutputBuffer.position() + written); } } else { written = Socket.send(socket, b, start, left); } if (Status.APR_STATUS_IS_EAGAIN(-written)) { written = 0; } else if (-written == Status.APR_EOF) { throw new EOFException(sm.getString("apr.clientAbort")); } else if ((OS.IS_WIN32 || OS.IS_WIN64) && (-written == Status.APR_OS_START_SYSERR + 10053)) { // 10053 on Windows is connection aborted throw new EOFException(sm.getString("apr.clientAbort")); } else if (written < 0) { throw new IOException(sm.getString("apr.write.error", Integer.valueOf(-written), Long.valueOf(socket), wrapper)); } start += written; left -= written; } while (written > 0 && left > 0); if (left > 0) { endpoint.getPoller().add(socket, -1, false, true); } return len - left; } @Override protected void doFlush() throws IOException { // TODO Auto-generated method stub } @Override protected void doClose() throws IOException { closed = true; // AbstractProcessor needs to trigger the close as multiple closes for // APR/native sockets will cause problems. } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/AprServletInputStream.java0000644000175100017510000001131712232541543027300 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.EOFException; import java.io.IOException; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.OS; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.net.SocketWrapper; public class AprServletInputStream extends AbstractServletInputStream { private static final Log log = LogFactory.getLog(AprServletInputStream.class); private final SocketWrapper wrapper; private final long socket; private volatile boolean eagain = false; private volatile boolean closed = false; public AprServletInputStream(SocketWrapper wrapper) { this.wrapper = wrapper; this.socket = wrapper.getSocket().longValue(); } @Override protected int doRead(boolean block, byte[] b, int off, int len) throws IOException { if (closed) { throw new IOException(sm.getString("apr.closed", Long.valueOf(socket))); } Lock readLock = wrapper.getBlockingStatusReadLock(); WriteLock writeLock = wrapper.getBlockingStatusWriteLock(); boolean readDone = false; int result = 0; try { readLock.lock(); if (wrapper.getBlockingStatus() == block) { result = Socket.recv(socket, b, off, len); readDone = true; } } finally { readLock.unlock(); } if (!readDone) { try { writeLock.lock(); wrapper.setBlockingStatus(block); // Set the current settings for this socket Socket.optSet(socket, Socket.APR_SO_NONBLOCK, (block ? 0 : 1)); // Downgrade the lock try { readLock.lock(); writeLock.unlock(); result = Socket.recv(socket, b, off, len); } finally { readLock.unlock(); } } finally { // Should have been released above but may not have been on some // exception paths if (writeLock.isHeldByCurrentThread()) { writeLock.unlock(); } } } if (result > 0) { eagain = false; return result; } else if (-result == Status.EAGAIN) { eagain = true; return 0; } else if (-result == Status.APR_EGENERAL && wrapper.isSecure()) { // Not entirely sure why this is necessary. Testing to date has not // identified any issues with this but log it so it can be tracked // if it is suspected of causing issues in the future. if (log.isDebugEnabled()) { log.debug(sm.getString("apr.read.sslGeneralError", Long.valueOf(socket), wrapper)); } eagain = true; return 0; } else if (-result == Status.APR_EOF) { throw new EOFException(sm.getString("apr.clientAbort")); } else if ((OS.IS_WIN32 || OS.IS_WIN64) && (-result == Status.APR_OS_START_SYSERR + 10053)) { // 10053 on Windows is connection aborted throw new EOFException(sm.getString("apr.clientAbort")); } else { throw new IOException(sm.getString("apr.read.error", Integer.valueOf(-result), Long.valueOf(socket), wrapper)); } } @Override protected boolean doIsReady() { return !eagain; } @Override protected void doClose() throws IOException { closed = true; // AbstractProcessor needs to trigger the close as multiple closes for // APR/native sockets will cause problems. } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/NioServletOutputStream.java0000644000175100017510000001044612267550170027512 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioSelectorPool; import org.apache.tomcat.util.net.SocketWrapper; public class NioServletOutputStream extends AbstractServletOutputStream { private final NioChannel channel; private final NioSelectorPool pool; private final int maxWrite; public NioServletOutputStream( SocketWrapper wrapper, NioSelectorPool pool) { channel = wrapper.getSocket(); this.pool = pool; maxWrite = channel.getBufHandler().getWriteBuffer().capacity(); } @Override protected int doWrite(boolean block, byte[] b, int off, int len) throws IOException { int leftToWrite = len; int count = 0; int offset = off; while (leftToWrite > 0) { int writeThisLoop; int writtenThisLoop; if (leftToWrite > maxWrite) { writeThisLoop = maxWrite; } else { writeThisLoop = leftToWrite; } writtenThisLoop = doWriteInternal(block, b, offset, writeThisLoop); count += writtenThisLoop; offset += writtenThisLoop; leftToWrite -= writtenThisLoop; if (writtenThisLoop < writeThisLoop) { break; } } return count; } private int doWriteInternal (boolean block, byte[] b, int off, int len) throws IOException { channel.getBufHandler().getWriteBuffer().clear(); channel.getBufHandler().getWriteBuffer().put(b, off, len); channel.getBufHandler().getWriteBuffer().flip(); int written = 0; NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) channel.getAttachment(false); if (att == null) { throw new IOException("Key must be cancelled"); } long writeTimeout = att.getWriteTimeout(); Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { //ignore } try { written = pool.write(channel.getBufHandler().getWriteBuffer(), channel, selector, writeTimeout, block); } finally { if (selector != null) { pool.put(selector); } } if (written < len) { channel.getPoller().add(channel, SelectionKey.OP_WRITE); } return written; } @Override protected void doFlush() throws IOException { NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) channel.getAttachment(false); if (att == null) { throw new IOException("Key must be cancelled"); } long writeTimeout = att.getWriteTimeout(); Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { //ignore } try { do { if (channel.flush(true, selector, writeTimeout)) { break; } } while (true); } finally { if (selector != null) { pool.put(selector); } } } @Override protected void doClose() throws IOException { channel.close(true); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/AprProcessor.java0000644000175100017510000000333112203412523025425 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.SocketWrapper; public class AprProcessor extends AbstractProcessor { private static final Log log = LogFactory.getLog(AprProcessor.class); @Override protected Log getLog() {return log;} private static final int INFINITE_TIMEOUT = -1; public AprProcessor(SocketWrapper wrapper, HttpUpgradeHandler httpUpgradeProcessor, AprEndpoint endpoint) { super(httpUpgradeProcessor, new AprServletInputStream(wrapper), new AprServletOutputStream(wrapper, endpoint)); Socket.timeoutSet(wrapper.getSocket().longValue(), INFINITE_TIMEOUT); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/Constants.java0000644000175100017510000000170212271461367024776 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; public class Constants { public static final String Package = "org.apache.coyote.http11.upgrade"; } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/LocalStrings.properties0000644000175100017510000000474212232541543026700 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. abstractProcessor.isCloseFail=Failed to close input stream associated with upgraded connection abstractProcessor.osCloseFail=Failed to close output stream associated with upgraded connection upgrade.sis.isFinished.ise=It is illegal to call isFinished() when the ServletInputStream is not in non-blocking mode (i.e. setReadListener() must be called first) upgrade.sis.isReady.ise=It is illegal to call isReady() when the ServletInputStream is not in non-blocking mode (i.e. setReadListener() must be called first) upgrade.sis.readListener.null=It is illegal to pass null to setReadListener() upgrade.sis.read.ise=It is illegal to call any of the read() methods in non-blocking mode without first checking that there is data available by calling isReady() upgrade.sos.canWrite.ise=It is illegal to call canWrite() when the ServletOutputStream is not in non-blocking mode (i.e. setWriteListener() must be called first) upgrade.sos.writeListener.null=It is illegal to pass null to setWriteListener() upgrade.sis.write.ise=It is illegal to call any of the write() methods in non-blocking mode without first checking that there is space available by calling isReady() apr.clientAbort=The client aborted the connection. apr.read.error=Unexpected error [{0}] reading data from the APR/native socket [{1}] with wrapper [{2}]. apr.read.sslGeneralError=An APR general error was returned by the SSL read operation on APR/native socket [{0}] with wrapper [{1}]. It will be treated as EAGAIN and the socket returned to the poller. apr.write.error=Unexpected error [{0}] writing data to the APR/native socket [{1}] with wrapper [{2}]. apr.closed=The socket [{0}] associated with this connection has been closed. nio.eof.error=Unexpected EOF read on the socket tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java0000644000175100017510000001505112233433413030516 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import javax.servlet.ServletOutputStream; import org.apache.coyote.http11.upgrade.servlet31.WriteListener; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Implements the new Servlet 3.1 methods for {@link ServletOutputStream}. */ public abstract class AbstractServletOutputStream extends ServletOutputStream { protected static final StringManager sm = StringManager.getManager(Constants.Package); private final Object fireListenerLock = new Object(); private final Object writeLock = new Object(); private volatile boolean closeRequired = false; // Start in blocking-mode private volatile WriteListener listener = null; private volatile boolean fireListener = false; private volatile ClassLoader applicationLoader = null; private volatile byte[] buffer; /** * New Servlet 3.1 method. */ public final boolean isReady() { if (listener == null) { throw new IllegalStateException( sm.getString("upgrade.sos.canWrite.is")); } // Make sure isReady() and onWritePossible() have a consistent view of // buffer and fireListener when determining if the listener should fire synchronized (fireListenerLock) { boolean result = (buffer == null); fireListener = !result; return result; } } /** * New Servlet 3.1 method. */ public final void setWriteListener(WriteListener listener) { if (listener == null) { throw new IllegalArgumentException( sm.getString("upgrade.sos.writeListener.null")); } this.listener = listener; this.applicationLoader = Thread.currentThread().getContextClassLoader(); } protected final boolean isCloseRequired() { return closeRequired; } @Override public void write(int b) throws IOException { synchronized (writeLock) { preWriteChecks(); writeInternal(new byte[] { (byte) b }, 0, 1); } } @Override public void write(byte[] b, int off, int len) throws IOException { synchronized (writeLock) { preWriteChecks(); writeInternal(b, off, len); } } @Override public void close() throws IOException { closeRequired = true; doClose(); } private void preWriteChecks() { if (buffer != null) { throw new IllegalStateException( sm.getString("upgrade.sis.write.ise")); } } /** * Must hold writeLock to call this method. */ private void writeInternal(byte[] b, int off, int len) throws IOException { if (listener == null) { // Simple case - blocking IO doWrite(true, b, off, len); } else { // Non-blocking IO // If the non-blocking read does not complete, doWrite() will add // the socket back into the poller. The poller may trigger a new // write event before this method has finished updating buffer. The // writeLock sync makes sure that buffer is updated before the next // write executes. int written = doWrite(false, b, off, len); if (written < len) { // TODO: - Reuse the buffer // - Only reallocate if it gets too big (>8k?) buffer = new byte[len - written]; System.arraycopy(b, off + written, buffer, 0, len - written); } else { buffer = null; } } } protected final void onWritePossible() throws IOException { synchronized (writeLock) { try { writeInternal(buffer, 0, buffer.length); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); Thread thread = Thread.currentThread(); ClassLoader originalClassLoader = thread.getContextClassLoader(); try { thread.setContextClassLoader(applicationLoader); listener.onError(t); } finally { thread.setContextClassLoader(originalClassLoader); } if (t instanceof IOException) { throw (IOException) t; } else { throw new IOException(t); } } // Make sure isReady() and onWritePossible() have a consistent view of // buffer and fireListener when determining if the listener should fire boolean fire = false; synchronized (fireListenerLock) { if (buffer == null && fireListener) { fireListener = false; fire = true; } } if (fire) { Thread thread = Thread.currentThread(); ClassLoader originalClassLoader = thread.getContextClassLoader(); try { thread.setContextClassLoader(applicationLoader); listener.onWritePossible(); } finally { thread.setContextClassLoader(originalClassLoader); } } } } /** * Abstract method to be overridden by concrete implementations. The base * class will ensure that there are no concurrent calls to this method for * the same socket. */ protected abstract int doWrite(boolean block, byte[] b, int off, int len) throws IOException; protected abstract void doFlush() throws IOException; protected abstract void doClose() throws IOException; } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/BioServletInputStream.java0000644000175100017510000000316712203412523027264 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import org.apache.tomcat.util.net.SocketWrapper; public class BioServletInputStream extends AbstractServletInputStream { private final InputStream inputStream; public BioServletInputStream(SocketWrapper wrapper) throws IOException { inputStream = wrapper.getSocket().getInputStream(); } @Override protected int doRead(boolean block, byte[] b, int off, int len) throws IOException { return inputStream.read(b, off, len); } @Override protected boolean doIsReady() { // Always returns true for BIO return true; } @Override protected void doClose() throws IOException { inputStream.close(); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/NioProcessor.java0000644000175100017510000000332412203412523025432 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioSelectorPool; import org.apache.tomcat.util.net.SocketWrapper; public class NioProcessor extends AbstractProcessor { private static final Log log = LogFactory.getLog(NioProcessor.class); @Override protected Log getLog() {return log;} private static final int INFINITE_TIMEOUT = -1; public NioProcessor(SocketWrapper wrapper, HttpUpgradeHandler httpUpgradeProcessor, NioSelectorPool pool) { super(httpUpgradeProcessor, new NioServletInputStream(wrapper, pool), new NioServletOutputStream(wrapper, pool)); wrapper.setTimeout(INFINITE_TIMEOUT); } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/UpgradeNioProcessor.java0000644000175100017510000001651212204665710026756 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Selector; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioSelectorPool; import org.apache.tomcat.util.net.SocketWrapper; /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public class UpgradeNioProcessor extends UpgradeProcessor { private final NioChannel nioChannel; private final NioSelectorPool pool; private final int maxRead; private final int maxWrite; public UpgradeNioProcessor(SocketWrapper wrapper, UpgradeInbound upgradeInbound, NioSelectorPool pool) { super(upgradeInbound); wrapper.setTimeout(upgradeInbound.getReadTimeout()); this.nioChannel = wrapper.getSocket(); this.pool = pool; this.maxRead = nioChannel.getBufHandler().getReadBuffer().capacity(); this.maxWrite = nioChannel.getBufHandler().getWriteBuffer().capacity(); } /* * Output methods */ @Override public void flush() throws IOException { NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) nioChannel.getAttachment(false); if (att == null) { throw new IOException("Key must be cancelled"); } long writeTimeout = att.getTimeout(); Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { //ignore } try { do { if (nioChannel.flush(true, selector, writeTimeout)) { break; } } while (true); } finally { if (selector != null) { pool.put(selector); } } } @Override public void write(int b) throws IOException { writeToSocket(new byte[] {(byte) b}, 0, 1); } @Override public void write(byte[]b, int off, int len) throws IOException { int written = 0; while (len - written > maxWrite) { written += writeToSocket(b, off + written, maxWrite); } writeToSocket(b, off + written, len - written); } /* * Input methods */ @Override public int read() throws IOException { byte[] bytes = new byte[1]; int result = readSocket(true, bytes, 0, 1); if (result == -1) { return -1; } else { return bytes[0] & 0xFF; } } @Override public int read(boolean block, byte[] bytes, int off, int len) throws IOException { if (len > maxRead) { return readSocket(block, bytes, off, maxRead); } else { return readSocket(block, bytes, off, len); } } /* * Adapted from the NioInputBuffer. */ private int readSocket(boolean block, byte[] bytes, int offset, int len) throws IOException { ByteBuffer readBuffer = nioChannel.getBufHandler().getReadBuffer(); int remaining = readBuffer.remaining(); // Is there enough data in the read buffer to satisfy this request? if (remaining >= len) { readBuffer.get(bytes, offset, len); return len; } // Copy what data there is in the read buffer to the byte array int leftToWrite = len; int newOffset = offset; if (remaining > 0) { readBuffer.get(bytes, offset, remaining); leftToWrite -= remaining; newOffset += remaining; } // Fill the read buffer as best we can readBuffer.clear(); int nRead = fillReadBuffer(block); // Full as much of the remaining byte array as possible with the data // that was just read if (nRead > 0) { readBuffer.flip(); readBuffer.limit(nRead); if (nRead > leftToWrite) { readBuffer.get(bytes, newOffset, leftToWrite); leftToWrite = 0; } else { readBuffer.get(bytes, newOffset, nRead); leftToWrite -= nRead; } } else if (nRead == 0) { readBuffer.flip(); readBuffer.limit(nRead); } else if (nRead == -1) { throw new EOFException(sm.getString("nio.eof.error")); } return len - leftToWrite; } private int fillReadBuffer(boolean block) throws IOException { int nRead; if (block) { Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { // Ignore } try { NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) nioChannel.getAttachment(false); if (att == null) { throw new IOException("Key must be cancelled."); } nRead = pool.read(nioChannel.getBufHandler().getReadBuffer(), nioChannel, selector, att.getTimeout()); } catch (EOFException eof) { nRead = -1; } finally { if (selector != null) { pool.put(selector); } } } else { nRead = nioChannel.read(nioChannel.getBufHandler().getReadBuffer()); } return nRead; } /* * Adapted from the NioOutputBuffer */ private synchronized int writeToSocket(byte[] bytes, int off, int len) throws IOException { nioChannel.getBufHandler().getWriteBuffer().clear(); nioChannel.getBufHandler().getWriteBuffer().put(bytes, off, len); nioChannel.getBufHandler().getWriteBuffer().flip(); int written = 0; NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) nioChannel.getAttachment(false); if (att == null) { throw new IOException("Key must be cancelled"); } long writeTimeout = att.getTimeout(); Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { //ignore } try { written = pool.write(nioChannel.getBufHandler().getWriteBuffer(), nioChannel, selector, writeTimeout, true); } finally { if (selector != null) { pool.put(selector); } } return written; } } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/servlet31/0000755000175100017510000000000012301126366023776 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/servlet31/HttpUpgradeHandler.java0000644000175100017510000000266612204476003030376 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade.servlet31; /** * Interface between the HTTP upgrade process and the new protocol. */ public interface HttpUpgradeHandler { /** * This method is called once the request/response pair where the upgrade * is initiated has completed processing and is the point where control of * the connection passes from the container to the * {@link HttpUpgradeHandler}. * * @param connection The connection that has been upgraded */ void init(WebConnection connection); /** * This method is called after the upgraded connection has been closed. */ void destroy(); } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/servlet31/WriteListener.java0000644000175100017510000000323112203412523027432 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade.servlet31; import java.io.IOException; /** * Receives notification of write events when using non-blocking IO. */ public interface WriteListener extends java.util.EventListener{ /** * Invoked when it it possible to write data without blocking. The container * will invoke this method the first time for a request as soon as data can * be written. Subsequent invocations will only occur if a call to {@link * org.apache.coyote.http11.upgrade.AbstractServletOutputStream#isReady()} * has returned false and it has since become possible to write data. * * @throws IOException */ public void onWritePossible() throws IOException; /** * Invoked if an error occurs while writing the response. * * @param throwable */ public void onError(java.lang.Throwable throwable); }tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/servlet31/ReadListener.java0000644000175100017510000000354512203412523027223 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade.servlet31; import java.io.IOException; /** * Receives notification of read events when using non-blocking IO. */ public interface ReadListener extends java.util.EventListener{ /** * Invoked when data is available to read. The container will invoke this * method the first time for a request as soon as there is data to read. * Subsequent invocations will only occur if a call to {@link * org.apache.coyote.http11.upgrade.AbstractServletInputStream#isReady()} * has returned false and data has subsequently become available to read. * * @throws IOException */ public abstract void onDataAvailable() throws IOException; /** * Invoked when the request body has been fully read. * * @throws IOException */ public abstract void onAllDataRead() throws IOException; /** * Invoked if an error occurs while reading the request body. * * @param throwable The exception that occurred */ public abstract void onError(java.lang.Throwable throwable); } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/servlet31/WebConnection.java0000644000175100017510000000333212203412523027371 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade.servlet31; import java.io.IOException; import org.apache.coyote.http11.upgrade.AbstractServletInputStream; import org.apache.coyote.http11.upgrade.AbstractServletOutputStream; /** * The interface used by a {@link HttpUpgradeHandler} to interact with an upgraded * HTTP connection. */ public interface WebConnection { /** * Provides access to the {@link AbstractServletInputStream} for reading * data from the client. */ AbstractServletInputStream getInputStream() throws IOException; /** * Provides access to the {@link AbstractServletOutputStream} for writing * data to the client. */ AbstractServletOutputStream getOutputStream() throws IOException; /** * The Servlet 3.1 interface extends AutoCloseable but that is not available * in Java 6 so this is the single method from that interface. */ void close() throws Exception; }tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/AbstractServletInputStream.java0000644000175100017510000001425512233433413030322 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import javax.servlet.ServletInputStream; import org.apache.coyote.http11.upgrade.servlet31.ReadListener; import org.apache.tomcat.util.res.StringManager; /** * Implements the new Servlet 3.1 methods for {@link ServletInputStream}. */ public abstract class AbstractServletInputStream extends ServletInputStream { protected static final StringManager sm = StringManager.getManager(Constants.Package); private volatile boolean closeRequired = false; // Start in blocking-mode private volatile Boolean ready = Boolean.TRUE; private volatile ReadListener listener = null; private volatile ClassLoader applicationLoader = null; /** * New Servlet 3.1 method. */ public final boolean isFinished() { if (listener == null) { throw new IllegalStateException( sm.getString("upgrade.sis.isFinished.ise")); } // The only way to finish an HTTP Upgrade connection is to close the // socket. return false; } /** * New Servlet 3.1 method. */ public final boolean isReady() { if (listener == null) { throw new IllegalStateException( sm.getString("upgrade.sis.isReady.ise")); } // If we already know the current state, return it. if (ready != null) { return ready.booleanValue(); } try { ready = Boolean.valueOf(doIsReady()); } catch (IOException e) { Thread thread = Thread.currentThread(); ClassLoader originalClassLoader = thread.getContextClassLoader(); try { thread.setContextClassLoader(applicationLoader); listener.onError(e); } finally { thread.setContextClassLoader(originalClassLoader); } ready = Boolean.FALSE; } return ready.booleanValue(); } /** * New Servlet 3.1 method. */ public final void setReadListener(ReadListener listener) { if (listener == null) { throw new IllegalArgumentException( sm.getString("upgrade.sis.readListener.null")); } this.listener = listener; this.applicationLoader = Thread.currentThread().getContextClassLoader(); // Switching to non-blocking. Don't know if data is available. ready = null; } @Override public final int read() throws IOException { preReadChecks(); return readInternal(); } @Override public final int readLine(byte[] b, int off, int len) throws IOException { preReadChecks(); if (len <= 0) { return 0; } int count = 0, c; while ((c = readInternal()) != -1) { b[off++] = (byte) c; count++; if (c == '\n' || count == len) { break; } } return count > 0 ? count : -1; } @Override public final int read(byte[] b, int off, int len) throws IOException { preReadChecks(); try { return doRead(listener == null, b, off, len); } catch (IOException ioe) { closeRequired = true; throw ioe; } } @Override public void close() throws IOException { closeRequired = true; doClose(); } private void preReadChecks() { if (listener != null && (ready == null || !ready.booleanValue())) { throw new IllegalStateException( sm.getString("upgrade.sis.read.ise")); } // No longer know if data is available ready = null; } private int readInternal() throws IOException { // Single byte reads for non-blocking need special handling so all // single byte reads run through this method. byte[] b = new byte[1]; int result; try { result = doRead(listener == null, b, 0, 1); } catch (IOException ioe) { closeRequired = true; throw ioe; } if (result == 0) { return -1; } else if (result == -1) { // Will never happen with a network socket. An IOException will be // thrown when the client closes the connection. // Echo back the -1 to be safe. return -1; } else { return b[0] & 0xFF; } } protected final void onDataAvailable() throws IOException { ready = Boolean.TRUE; Thread thread = Thread.currentThread(); ClassLoader originalClassLoader = thread.getContextClassLoader(); try { thread.setContextClassLoader(applicationLoader); listener.onDataAvailable(); } finally { thread.setContextClassLoader(originalClassLoader); } } protected final boolean isCloseRequired() { return closeRequired; } protected abstract boolean doIsReady() throws IOException; /** * Abstract method to be overridden by concrete implementations. The base * class will ensure that there are no concurrent calls to this method for * the same socket. */ protected abstract int doRead(boolean block, byte[] b, int off, int len) throws IOException; protected abstract void doClose() throws IOException; } tomcat7-7.0.52/java/org/apache/coyote/http11/upgrade/UpgradeBioProcessor.java0000644000175100017510000000473012204665710026741 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11.upgrade; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import org.apache.tomcat.util.net.SocketWrapper; /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public class UpgradeBioProcessor extends UpgradeProcessor { private final InputStream inputStream; private final OutputStream outputStream; public UpgradeBioProcessor(SocketWrapper wrapper, UpgradeInbound upgradeInbound) throws IOException { super(upgradeInbound); int timeout = upgradeInbound.getReadTimeout(); if (timeout < 0) { timeout = 0; } wrapper.getSocket().setSoTimeout(timeout); this.inputStream = wrapper.getSocket().getInputStream(); this.outputStream = wrapper.getSocket().getOutputStream(); } /* * Output methods */ @Override public void flush() throws IOException { outputStream.flush(); } @Override public void write(int b) throws IOException { outputStream.write(b); } @Override public void write(byte[]b, int off, int len) throws IOException { outputStream.write(b, off, len); } /* * Input methods */ @Override public int read() throws IOException { return inputStream.read(); } @Override public int read(boolean block, byte[] bytes, int off, int len) throws IOException { // The BIO endpoint always uses blocking IO so the block parameter is // ignored and a blocking read is performed. return inputStream.read(bytes, off, len); } } tomcat7-7.0.52/java/org/apache/coyote/http11/Http11NioProtocol.java0000644000175100017510000002507212271461367024652 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.nio.channels.SocketChannel; import java.util.Iterator; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.coyote.http11.upgrade.NioProcessor; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioEndpoint.Handler; import org.apache.tomcat.util.net.SSLImplementation; import org.apache.tomcat.util.net.SecureNioChannel; import org.apache.tomcat.util.net.SocketWrapper; /** * Abstract the protocol implementation, including threading, etc. * Processor is single threaded and specific to stream-based protocols, * will not fit Jk protocols like JNI. * * @author Remy Maucherat * @author Costin Manolache * @author Filip Hanik */ public class Http11NioProtocol extends AbstractHttp11JsseProtocol { private static final Log log = LogFactory.getLog(Http11NioProtocol.class); @Override protected Log getLog() { return log; } @Override protected AbstractEndpoint.Handler getHandler() { return cHandler; } public Http11NioProtocol() { endpoint=new NioEndpoint(); cHandler = new Http11ConnectionHandler(this); ((NioEndpoint) endpoint).setHandler(cHandler); setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); } public NioEndpoint getEndpoint() { return ((NioEndpoint)endpoint); } // -------------------- Properties-------------------- private Http11ConnectionHandler cHandler; // -------------------- Pool setup -------------------- public void setPollerThreadCount(int count) { ((NioEndpoint)endpoint).setPollerThreadCount(count); } public int getPollerThreadCount() { return ((NioEndpoint)endpoint).getPollerThreadCount(); } public void setSelectorTimeout(long timeout) { ((NioEndpoint)endpoint).setSelectorTimeout(timeout); } public long getSelectorTimeout() { return ((NioEndpoint)endpoint).getSelectorTimeout(); } public void setAcceptorThreadPriority(int threadPriority) { ((NioEndpoint)endpoint).setAcceptorThreadPriority(threadPriority); } public void setPollerThreadPriority(int threadPriority) { ((NioEndpoint)endpoint).setPollerThreadPriority(threadPriority); } public int getAcceptorThreadPriority() { return ((NioEndpoint)endpoint).getAcceptorThreadPriority(); } public int getPollerThreadPriority() { return ((NioEndpoint)endpoint).getThreadPriority(); } public boolean getUseSendfile() { return ((NioEndpoint)endpoint).getUseSendfile(); } public void setUseSendfile(boolean useSendfile) { ((NioEndpoint)endpoint).setUseSendfile(useSendfile); } // -------------------- Tcp setup -------------------- public void setOomParachute(int oomParachute) { ((NioEndpoint)endpoint).setOomParachute(oomParachute); } // ----------------------------------------------------- JMX related methods @Override protected String getNamePrefix() { return ("http-nio"); } // -------------------- Connection handler -------------------- protected static class Http11ConnectionHandler extends AbstractConnectionHandler implements Handler { protected Http11NioProtocol proto; Http11ConnectionHandler(Http11NioProtocol proto) { this.proto = proto; } @Override protected AbstractProtocol getProtocol() { return proto; } @Override protected Log getLog() { return log; } @Override public SSLImplementation getSslImplementation() { return proto.sslImplementation; } /** * Expected to be used by the Poller to release resources on socket * close, errors etc. */ @Override public void release(SocketChannel socket) { if (log.isDebugEnabled()) log.debug("Iterating through our connections to release a socket channel:"+socket); boolean released = false; Iterator>> it = connections.entrySet().iterator(); while (it.hasNext()) { java.util.Map.Entry> entry = it.next(); if (entry.getKey().getIOChannel()==socket) { it.remove(); Processor result = entry.getValue(); result.recycle(true); unregister(result); released = true; break; } } if (log.isDebugEnabled()) log.debug("Done iterating through our connections to release a socket channel:"+socket +" released:"+released); } /** * Expected to be used by the Poller to release resources on socket * close, errors etc. */ @Override public void release(SocketWrapper socket) { Processor processor = connections.remove(socket.getSocket()); if (processor != null) { processor.recycle(true); recycledProcessors.offer(processor); } } /** * Expected to be used by the handler once the processor is no longer * required. * * @param socket * @param processor * @param isSocketClosing Not used in HTTP * @param addToPoller */ @Override public void release(SocketWrapper socket, Processor processor, boolean isSocketClosing, boolean addToPoller) { processor.recycle(isSocketClosing); recycledProcessors.offer(processor); if (addToPoller) { socket.getSocket().getPoller().add(socket.getSocket()); } } @Override protected void initSsl(SocketWrapper socket, Processor processor) { if (proto.isSSLEnabled() && (proto.sslImplementation != null) && (socket.getSocket() instanceof SecureNioChannel)) { SecureNioChannel ch = (SecureNioChannel)socket.getSocket(); processor.setSslSupport( proto.sslImplementation.getSSLSupport( ch.getSslEngine().getSession())); } else { processor.setSslSupport(null); } } @Override protected void longPoll(SocketWrapper socket, Processor processor) { if (processor.isAsync()) { socket.setAsync(true); } else { // Either: // - this is comet request // - this is an upgraded connection // - the request line/headers have not been completely // read socket.getSocket().getPoller().add(socket.getSocket()); } } @Override public Http11NioProcessor createProcessor() { Http11NioProcessor processor = new Http11NioProcessor( proto.getMaxHttpHeaderSize(), (NioEndpoint)proto.endpoint, proto.getMaxTrailerSize(), proto.getMaxExtensionSize()); processor.setAdapter(proto.adapter); processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); processor.setConnectionUploadTimeout( proto.getConnectionUploadTimeout()); processor.setDisableUploadTimeout(proto.getDisableUploadTimeout()); processor.setCompressionMinSize(proto.getCompressionMinSize()); processor.setCompression(proto.getCompression()); processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents()); processor.setCompressableMimeTypes(proto.getCompressableMimeTypes()); processor.setRestrictedUserAgents(proto.getRestrictedUserAgents()); processor.setSocketBuffer(proto.getSocketBuffer()); processor.setMaxSavePostSize(proto.getMaxSavePostSize()); processor.setServer(proto.getServer()); register(processor); return processor; } /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated @Override protected Processor createUpgradeProcessor( SocketWrapper socket, org.apache.coyote.http11.upgrade.UpgradeInbound inbound) throws IOException { return new org.apache.coyote.http11.upgrade.UpgradeNioProcessor( socket, inbound, ((Http11NioProtocol) getProtocol()).getEndpoint().getSelectorPool()); } @Override protected Processor createUpgradeProcessor( SocketWrapper socket, HttpUpgradeHandler httpUpgradeProcessor) throws IOException { return new NioProcessor(socket, httpUpgradeProcessor, ((Http11NioProtocol) getProtocol()).getEndpoint().getSelectorPool()); } } } tomcat7-7.0.52/java/org/apache/coyote/http11/InternalAprOutputBuffer.java0000644000175100017510000001441512271461367026172 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.nio.ByteBuffer; import org.apache.coyote.ActionCode; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.http.HttpMessages; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; /** * Output buffer. * * @author Remy Maucherat */ public class InternalAprOutputBuffer extends AbstractOutputBuffer { // ----------------------------------------------------------- Constructors /** * Default constructor. */ public InternalAprOutputBuffer(Response response, int headerBufferSize) { this.response = response; buf = new byte[headerBufferSize]; if (headerBufferSize < (8 * 1024)) { bbuf = ByteBuffer.allocateDirect(6 * 1500); } else { bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); } outputStreamOutputBuffer = new SocketOutputBuffer(); filterLibrary = new OutputFilter[0]; activeFilters = new OutputFilter[0]; lastActiveFilter = -1; committed = false; finished = false; // Cause loading of HttpMessages HttpMessages.getInstance(response.getLocale()).getMessage(200); } // ----------------------------------------------------- Instance Variables /** * Underlying socket. */ private long socket; /** * Direct byte buffer used for writing. */ private ByteBuffer bbuf = null; // --------------------------------------------------------- Public Methods @Override public void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException { socket = socketWrapper.getSocket().longValue(); Socket.setsbb(this.socket, bbuf); } /** * Flush the response. * * @throws IOException an underlying I/O error occurred */ @Override public void flush() throws IOException { super.flush(); // Flush the current buffer flushBuffer(); } /** * Recycle the output buffer. This should be called when closing the * connection. */ @Override public void recycle() { super.recycle(); bbuf.clear(); } /** * End request. * * @throws IOException an underlying I/O error occurred */ @Override public void endRequest() throws IOException { if (!committed) { // Send the connector a request for commit. The connector should // then validate the headers, send them (using sendHeader) and // set the filters accordingly. response.action(ActionCode.COMMIT, null); } if (finished) return; if (lastActiveFilter != -1) activeFilters[lastActiveFilter].end(); flushBuffer(); finished = true; } // ------------------------------------------------ HTTP/1.1 Output Methods /** * Send an acknowledgment. */ @Override public void sendAck() throws IOException { if (!committed) { if (Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0) throw new IOException(sm.getString("iib.failedwrite")); } } // ------------------------------------------------------ Protected Methods /** * Commit the response. * * @throws IOException an underlying I/O error occurred */ @Override protected void commit() throws IOException { // The response is now committed committed = true; response.setCommitted(true); if (pos > 0) { // Sending the response header buffer bbuf.put(buf, 0, pos); } } /** * Callback to write data from the buffer. */ private void flushBuffer() throws IOException { if (bbuf.position() > 0) { if (Socket.sendbb(socket, 0, bbuf.position()) < 0) { throw new IOException(); } bbuf.clear(); } } // ----------------------------------- OutputStreamOutputBuffer Inner Class /** * This class is an output buffer which will write data to an output * stream. */ protected class SocketOutputBuffer implements OutputBuffer { /** * Write chunk. */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { int len = chunk.getLength(); int start = chunk.getStart(); byte[] b = chunk.getBuffer(); while (len > 0) { int thisTime = len; if (bbuf.position() == bbuf.capacity()) { flushBuffer(); } if (thisTime > bbuf.capacity() - bbuf.position()) { thisTime = bbuf.capacity() - bbuf.position(); } bbuf.put(b, start, thisTime); len = len - thisTime; start = start + thisTime; } byteCount += chunk.getLength(); return chunk.getLength(); } @Override public long getBytesWritten() { return byteCount; } } } tomcat7-7.0.52/java/org/apache/coyote/http11/Http11Protocol.java0000644000175100017510000001665612271461367024214 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.net.Socket; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.coyote.http11.upgrade.BioProcessor; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.JIoEndpoint; import org.apache.tomcat.util.net.JIoEndpoint.Handler; import org.apache.tomcat.util.net.SSLImplementation; import org.apache.tomcat.util.net.SocketWrapper; /** * Abstract the protocol implementation, including threading, etc. * Processor is single threaded and specific to stream-based protocols, * will not fit Jk protocols like JNI. * * @author Remy Maucherat * @author Costin Manolache */ public class Http11Protocol extends AbstractHttp11JsseProtocol { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(Http11Protocol.class); @Override protected Log getLog() { return log; } @Override protected AbstractEndpoint.Handler getHandler() { return cHandler; } // ------------------------------------------------------------ Constructor public Http11Protocol() { endpoint = new JIoEndpoint(); cHandler = new Http11ConnectionHandler(this); ((JIoEndpoint) endpoint).setHandler(cHandler); setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); } // ----------------------------------------------------------------- Fields protected Http11ConnectionHandler cHandler; // ------------------------------------------------ HTTP specific properties // ------------------------------------------ managed in the ProtocolHandler private int disableKeepAlivePercentage = 75; public int getDisableKeepAlivePercentage() { return disableKeepAlivePercentage; } public void setDisableKeepAlivePercentage(int disableKeepAlivePercentage) { if (disableKeepAlivePercentage < 0) { this.disableKeepAlivePercentage = 0; } else if (disableKeepAlivePercentage > 100) { this.disableKeepAlivePercentage = 100; } else { this.disableKeepAlivePercentage = disableKeepAlivePercentage; } } // ----------------------------------------------------- JMX related methods @Override protected String getNamePrefix() { return ("http-bio"); } // ----------------------------------- Http11ConnectionHandler Inner Class protected static class Http11ConnectionHandler extends AbstractConnectionHandler implements Handler { protected Http11Protocol proto; Http11ConnectionHandler(Http11Protocol proto) { this.proto = proto; } @Override protected AbstractProtocol getProtocol() { return proto; } @Override protected Log getLog() { return log; } @Override public SSLImplementation getSslImplementation() { return proto.sslImplementation; } /** * Expected to be used by the handler once the processor is no longer * required. * * @param socket Not used in BIO * @param processor * @param isSocketClosing Not used in HTTP * @param addToPoller Not used in BIO */ @Override public void release(SocketWrapper socket, Processor processor, boolean isSocketClosing, boolean addToPoller) { processor.recycle(isSocketClosing); recycledProcessors.offer(processor); } @Override protected void initSsl(SocketWrapper socket, Processor processor) { if (proto.isSSLEnabled() && (proto.sslImplementation != null)) { processor.setSslSupport( proto.sslImplementation.getSSLSupport( socket.getSocket())); } else { processor.setSslSupport(null); } } @Override protected void longPoll(SocketWrapper socket, Processor processor) { // NO-OP } @Override protected Http11Processor createProcessor() { Http11Processor processor = new Http11Processor( proto.getMaxHttpHeaderSize(), (JIoEndpoint)proto.endpoint, proto.getMaxTrailerSize(),proto.getMaxExtensionSize()); processor.setAdapter(proto.adapter); processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); processor.setConnectionUploadTimeout( proto.getConnectionUploadTimeout()); processor.setDisableUploadTimeout(proto.getDisableUploadTimeout()); processor.setCompressionMinSize(proto.getCompressionMinSize()); processor.setCompression(proto.getCompression()); processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents()); processor.setCompressableMimeTypes(proto.getCompressableMimeTypes()); processor.setRestrictedUserAgents(proto.getRestrictedUserAgents()); processor.setSocketBuffer(proto.getSocketBuffer()); processor.setMaxSavePostSize(proto.getMaxSavePostSize()); processor.setServer(proto.getServer()); processor.setDisableKeepAlivePercentage( proto.getDisableKeepAlivePercentage()); register(processor); return processor; } /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated @Override protected Processor createUpgradeProcessor( SocketWrapper socket, org.apache.coyote.http11.upgrade.UpgradeInbound inbound) throws IOException { return new org.apache.coyote.http11.upgrade.UpgradeBioProcessor( socket, inbound); } @Override protected Processor createUpgradeProcessor( SocketWrapper socket, HttpUpgradeHandler httpUpgradeProcessor) throws IOException { return new BioProcessor(socket, httpUpgradeProcessor); } } } tomcat7-7.0.52/java/org/apache/coyote/http11/InternalNioOutputBuffer.java0000644000175100017510000001776512271461367026210 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.http.HttpMessages; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioSelectorPool; import org.apache.tomcat.util.net.SocketWrapper; /** * Output buffer. * * @author Remy Maucherat * @author Filip Hanik */ public class InternalNioOutputBuffer extends AbstractOutputBuffer { // ----------------------------------------------------------- Constructors /** * Default constructor. */ public InternalNioOutputBuffer(Response response, int headerBufferSize) { this.response = response; buf = new byte[headerBufferSize]; outputStreamOutputBuffer = new SocketOutputBuffer(); filterLibrary = new OutputFilter[0]; activeFilters = new OutputFilter[0]; lastActiveFilter = -1; committed = false; finished = false; // Cause loading of HttpMessages HttpMessages.getInstance(response.getLocale()).getMessage(200); } /** * Underlying socket. */ private NioChannel socket; /** * Selector pool, for blocking reads and blocking writes */ private NioSelectorPool pool; // --------------------------------------------------------- Public Methods /** * Flush the response. * * @throws IOException an underlying I/O error occurred * */ @Override public void flush() throws IOException { super.flush(); // Flush the current buffer flushBuffer(); } /** * Recycle the output buffer. This should be called when closing the * connection. */ @Override public void recycle() { super.recycle(); if (socket != null) { socket.getBufHandler().getWriteBuffer().clear(); socket = null; } } /** * End request. * * @throws IOException an underlying I/O error occurred */ @Override public void endRequest() throws IOException { super.endRequest(); flushBuffer(); } // ------------------------------------------------ HTTP/1.1 Output Methods /** * Send an acknowledgment. */ @Override public void sendAck() throws IOException { if (!committed) { //Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0 socket.getBufHandler() .getWriteBuffer().put(Constants.ACK_BYTES,0,Constants.ACK_BYTES.length); writeToSocket(socket.getBufHandler() .getWriteBuffer(),true,true); } } /** * * @param bytebuffer ByteBuffer * @param flip boolean * @return int * @throws IOException * TODO Fix non blocking write properly */ private synchronized int writeToSocket(ByteBuffer bytebuffer, boolean block, boolean flip) throws IOException { if ( flip ) bytebuffer.flip(); int written = 0; NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment)socket.getAttachment(false); if ( att == null ) throw new IOException("Key must be cancelled"); long writeTimeout = att.getWriteTimeout(); Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { //ignore } try { written = pool.write(bytebuffer, socket, selector, writeTimeout, block); //make sure we are flushed do { if (socket.flush(true,selector,writeTimeout)) break; }while ( true ); }finally { if ( selector != null ) pool.put(selector); } if ( block ) bytebuffer.clear(); //only clear return written; } // ------------------------------------------------------ Protected Methods @Override public void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException { socket = socketWrapper.getSocket(); pool = ((NioEndpoint)endpoint).getSelectorPool(); } /** * Commit the response. * * @throws IOException an underlying I/O error occurred */ @Override protected void commit() throws IOException { // The response is now committed committed = true; response.setCommitted(true); if (pos > 0) { // Sending the response header buffer addToBB(buf, 0, pos); } } private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException { while (length > 0) { int thisTime = length; if (socket.getBufHandler().getWriteBuffer().position() == socket.getBufHandler().getWriteBuffer().capacity() || socket.getBufHandler().getWriteBuffer().remaining()==0) { flushBuffer(); } if (thisTime > socket.getBufHandler().getWriteBuffer().remaining()) { thisTime = socket.getBufHandler().getWriteBuffer().remaining(); } socket.getBufHandler().getWriteBuffer().put(buf, offset, thisTime); length = length - thisTime; offset = offset + thisTime; } NioEndpoint.KeyAttachment ka = (NioEndpoint.KeyAttachment)socket.getAttachment(false); if ( ka!= null ) ka.access();//prevent timeouts for just doing client writes } /** * Callback to write data from the buffer. */ private void flushBuffer() throws IOException { //prevent timeout for async, SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector()); if (key != null) { NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); attach.access(); } //write to the socket, if there is anything to write if (socket.getBufHandler().getWriteBuffer().position() > 0) { socket.getBufHandler().getWriteBuffer().flip(); writeToSocket(socket.getBufHandler().getWriteBuffer(),true, false); } } // ----------------------------------- OutputStreamOutputBuffer Inner Class /** * This class is an output buffer which will write data to an output * stream. */ protected class SocketOutputBuffer implements OutputBuffer { /** * Write chunk. */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { int len = chunk.getLength(); int start = chunk.getStart(); byte[] b = chunk.getBuffer(); addToBB(b, start, len); byteCount += chunk.getLength(); return chunk.getLength(); } @Override public long getBytesWritten() { return byteCount; } } } tomcat7-7.0.52/java/org/apache/coyote/http11/AbstractInputBuffer.java0000644000175100017510000002164011751567060025312 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; import org.apache.tomcat.util.res.StringManager; public abstract class AbstractInputBuffer implements InputBuffer{ protected static final boolean[] HTTP_TOKEN_CHAR = new boolean[128]; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); static { for (int i = 0; i < 128; i++) { if (i < 32) { HTTP_TOKEN_CHAR[i] = false; } else if (i == 127) { HTTP_TOKEN_CHAR[i] = false; } else if (i == '(') { HTTP_TOKEN_CHAR[i] = false; } else if (i == ')') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '<') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '>') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '@') { HTTP_TOKEN_CHAR[i] = false; } else if (i == ',') { HTTP_TOKEN_CHAR[i] = false; } else if (i == ';') { HTTP_TOKEN_CHAR[i] = false; } else if (i == ':') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '\\') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '\"') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '/') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '[') { HTTP_TOKEN_CHAR[i] = false; } else if (i == ']') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '?') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '=') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '{') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '}') { HTTP_TOKEN_CHAR[i] = false; } else if (i == ' ') { HTTP_TOKEN_CHAR[i] = false; } else if (i == '\t') { HTTP_TOKEN_CHAR[i] = false; } else { HTTP_TOKEN_CHAR[i] = true; } } } /** * Associated Coyote request. */ protected Request request; /** * Headers of the associated request. */ protected MimeHeaders headers; /** * State. */ protected boolean parsingHeader; /** * Swallow input ? (in the case of an expectation) */ protected boolean swallowInput; /** * Pointer to the current read buffer. */ protected byte[] buf; /** * Last valid byte. */ protected int lastValid; /** * Position in the buffer. */ protected int pos; /** * Pos of the end of the header in the buffer, which is also the * start of the body. */ protected int end; /** * Underlying input buffer. */ protected InputBuffer inputStreamInputBuffer; /** * Filter library. * Note: Filter[0] is always the "chunked" filter. */ protected InputFilter[] filterLibrary; /** * Active filters (in order). */ protected InputFilter[] activeFilters; /** * Index of the last active filter. */ protected int lastActiveFilter; // ------------------------------------------------------------- Properties /** * Add an input filter to the filter library. */ public void addFilter(InputFilter filter) { // FIXME: Check for null ? InputFilter[] newFilterLibrary = new InputFilter[filterLibrary.length + 1]; for (int i = 0; i < filterLibrary.length; i++) { newFilterLibrary[i] = filterLibrary[i]; } newFilterLibrary[filterLibrary.length] = filter; filterLibrary = newFilterLibrary; activeFilters = new InputFilter[filterLibrary.length]; } /** * Get filters. */ public InputFilter[] getFilters() { return filterLibrary; } /** * Add an input filter to the filter library. */ public void addActiveFilter(InputFilter filter) { if (lastActiveFilter == -1) { filter.setBuffer(inputStreamInputBuffer); } else { for (int i = 0; i <= lastActiveFilter; i++) { if (activeFilters[i] == filter) return; } filter.setBuffer(activeFilters[lastActiveFilter]); } activeFilters[++lastActiveFilter] = filter; filter.setRequest(request); } /** * Set the swallow input flag. */ public void setSwallowInput(boolean swallowInput) { this.swallowInput = swallowInput; } public abstract boolean parseRequestLine(boolean useAvailableDataOnly) throws IOException; public abstract boolean parseHeaders() throws IOException; protected abstract boolean fill(boolean block) throws IOException; protected abstract void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException; // --------------------------------------------------------- Public Methods /** * Recycle the input buffer. This should be called when closing the * connection. */ public void recycle() { // Recycle Request object request.recycle(); // Recycle filters for (int i = 0; i <= lastActiveFilter; i++) { activeFilters[i].recycle(); } lastValid = 0; pos = 0; lastActiveFilter = -1; parsingHeader = true; swallowInput = true; } /** * End processing of current HTTP request. * Note: All bytes of the current request should have been already * consumed. This method only resets all the pointers so that we are ready * to parse the next HTTP request. */ public void nextRequest() { // Recycle Request object request.recycle(); // Copy leftover bytes to the beginning of the buffer if (lastValid - pos > 0) { int npos = 0; int opos = pos; while (lastValid - opos > opos - npos) { System.arraycopy(buf, opos, buf, npos, opos - npos); npos += pos; opos += pos; } System.arraycopy(buf, opos, buf, npos, lastValid - opos); } // Recycle filters for (int i = 0; i <= lastActiveFilter; i++) { activeFilters[i].recycle(); } // Reset pointers lastValid = lastValid - pos; pos = 0; lastActiveFilter = -1; parsingHeader = true; swallowInput = true; } /** * End request (consumes leftover bytes). * * @throws IOException an underlying I/O error occurred */ public void endRequest() throws IOException { if (swallowInput && (lastActiveFilter != -1)) { int extraBytes = (int) activeFilters[lastActiveFilter].end(); pos = pos - extraBytes; } } /** * Available bytes in the buffers (note that due to encoding, this may not * correspond). */ public int available() { int result = (lastValid - pos); if ((result == 0) && (lastActiveFilter >= 0)) { for (int i = 0; (result == 0) && (i <= lastActiveFilter); i++) { result = activeFilters[i].available(); } } return result; } // ---------------------------------------------------- InputBuffer Methods /** * Read some bytes. */ @Override public int doRead(ByteChunk chunk, Request req) throws IOException { if (lastActiveFilter == -1) return inputStreamInputBuffer.doRead(chunk, req); else return activeFilters[lastActiveFilter].doRead(chunk,req); } } tomcat7-7.0.52/java/org/apache/coyote/http11/Http11NioProcessor.java0000644000175100017510000005035612276702205025025 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.io.InterruptedIOException; import java.net.InetAddress; import java.nio.channels.SelectionKey; import javax.net.ssl.SSLEngine; import org.apache.coyote.ActionCode; import org.apache.coyote.RequestInfo; import org.apache.coyote.http11.filters.BufferedInputFilter; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SecureNioChannel; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Processes HTTP requests. * * @author Remy Maucherat * @author Filip Hanik */ public class Http11NioProcessor extends AbstractHttp11Processor { private static final Log log = LogFactory.getLog(Http11NioProcessor.class); @Override protected Log getLog() { return log; } /** * SSL information. */ protected SSLSupport sslSupport; // ----------------------------------------------------------- Constructors public Http11NioProcessor(int maxHttpHeaderSize, NioEndpoint endpoint, int maxTrailerSize, int maxExtensionSize) { super(endpoint); inputBuffer = new InternalNioInputBuffer(request, maxHttpHeaderSize); request.setInputBuffer(inputBuffer); outputBuffer = new InternalNioOutputBuffer(response, maxHttpHeaderSize); response.setOutputBuffer(outputBuffer); initializeFilters(maxTrailerSize, maxExtensionSize); } // ----------------------------------------------------- Instance Variables /** * Input. */ protected InternalNioInputBuffer inputBuffer = null; /** * Output. */ protected InternalNioOutputBuffer outputBuffer = null; /** * Sendfile data. */ protected NioEndpoint.SendfileData sendfileData = null; // --------------------------------------------------------- Public Methods /** * Process pipelined HTTP requests using the specified input and output * streams. * * @throws IOException error during an I/O operation */ @Override public SocketState event(SocketStatus status) throws IOException { long soTimeout = endpoint.getSoTimeout(); RequestInfo rp = request.getRequestProcessor(); final NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment)socketWrapper.getSocket().getAttachment(false); try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); error = !adapter.event(request, response, status); if ( !error ) { if (attach != null) { attach.setComet(comet); if (comet) { Integer comettimeout = (Integer) request.getAttribute( org.apache.coyote.Constants.COMET_TIMEOUT_ATTR); if (comettimeout != null) { attach.setTimeout(comettimeout.longValue()); } } else { //reset the timeout if (keepAlive) { attach.setTimeout(keepAliveTimeout); } else { attach.setTimeout(soTimeout); } } } } } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("http11processor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); error = true; } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (error || status==SocketStatus.STOP) { return SocketState.CLOSED; } else if (!comet) { if (keepAlive) { inputBuffer.nextRequest(); outputBuffer.nextRequest(); return SocketState.OPEN; } else { return SocketState.CLOSED; } } else { return SocketState.LONG; } } @Override protected void resetTimeouts() { final NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment)socketWrapper.getSocket().getAttachment(false); if (!error && attach != null && asyncStateMachine.isAsyncDispatching()) { long soTimeout = endpoint.getSoTimeout(); //reset the timeout if (keepAlive) { attach.setTimeout(keepAliveTimeout); } else { attach.setTimeout(soTimeout); } } } @Override protected boolean disableKeepAlive() { return false; } @Override protected void setRequestLineReadTimeout() throws IOException { // socket.setTimeout() // - timeout used by poller // socket.getSocket().getIOChannel().socket().setSoTimeout() // - timeout used for blocking reads // When entering the processing loop there will always be data to read // so no point changing timeouts at this point // For the second and subsequent executions of the processing loop, a // non-blocking read is used so again no need to set the timeouts // Because NIO supports non-blocking reading of the request line and // headers the timeouts need to be set when returning the socket to // the poller rather than here. // NO-OP } @Override protected boolean handleIncompleteRequestLineRead() { // Haven't finished reading the request so keep the socket // open openSocket = true; // Check to see if we have read any of the request line yet if (inputBuffer.getParsingRequestLinePhase() < 2) { if (socketWrapper.getLastAccess() > -1 || keptAlive) { // Haven't read the request line and have previously processed a // request. Must be keep-alive. Make sure poller uses keepAlive. socketWrapper.setTimeout(endpoint.getKeepAliveTimeout()); } } else { // Started to read request line. Need to keep processor // associated with socket readComplete = false; // Make sure poller uses soTimeout from here onwards socketWrapper.setTimeout(endpoint.getSoTimeout()); } if (endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); adapter.log(request, response, 0); error = true; } else { return true; } return false; } @Override protected void setSocketTimeout(int timeout) throws IOException { socketWrapper.getSocket().getIOChannel().socket().setSoTimeout(timeout); } @Override protected void setCometTimeouts(SocketWrapper socketWrapper) { // Comet support SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor( socketWrapper.getSocket().getPoller().getSelector()); if (key != null) { NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); if (attach != null) { attach.setComet(comet); if (comet) { Integer comettimeout = (Integer) request.getAttribute( org.apache.coyote.Constants.COMET_TIMEOUT_ATTR); if (comettimeout != null) { attach.setTimeout(comettimeout.longValue()); } } } } } @Override protected boolean breakKeepAliveLoop( SocketWrapper socketWrapper) { openSocket = keepAlive; // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !error) { ((KeyAttachment) socketWrapper).setSendfileData(sendfileData); sendfileData.keepAlive = keepAlive; SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor( socketWrapper.getSocket().getPoller().getSelector()); //do the first write on this thread, might as well if (socketWrapper.getSocket().getPoller().processSendfile(key, (KeyAttachment) socketWrapper, true)) { sendfileInProgress = true; } else { // Write failed if (log.isDebugEnabled()) { log.debug(sm.getString("http11processor.sendfile.error")); } error = true; } return true; } return false; } @Override public void recycleInternal() { socketWrapper = null; sendfileData = null; } // ----------------------------------------------------- ActionHook Methods /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override public void actionInternal(ActionCode actionCode, Object param) { if (actionCode == ActionCode.REQ_HOST_ADDR_ATTRIBUTE) { // Get remote host address if ((remoteAddr == null) && (socketWrapper != null)) { InetAddress inetAddr = socketWrapper.getSocket().getIOChannel().socket().getInetAddress(); if (inetAddr != null) { remoteAddr = inetAddr.getHostAddress(); } } request.remoteAddr().setString(remoteAddr); } else if (actionCode == ActionCode.REQ_LOCAL_NAME_ATTRIBUTE) { // Get local host name if ((localName == null) && (socketWrapper != null)) { InetAddress inetAddr = socketWrapper.getSocket().getIOChannel().socket().getLocalAddress(); if (inetAddr != null) { localName = inetAddr.getHostName(); } } request.localName().setString(localName); } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) { // Get remote host name if ((remoteHost == null) && (socketWrapper != null)) { InetAddress inetAddr = socketWrapper.getSocket().getIOChannel().socket().getInetAddress(); if (inetAddr != null) { remoteHost = inetAddr.getHostName(); } if(remoteHost == null) { if(remoteAddr != null) { remoteHost = remoteAddr; } else { // all we can do is punt request.remoteHost().recycle(); } } } request.remoteHost().setString(remoteHost); } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) { if (localAddr == null) { localAddr = socketWrapper.getSocket().getIOChannel().socket().getLocalAddress().getHostAddress(); } request.localAddr().setString(localAddr); } else if (actionCode == ActionCode.REQ_REMOTEPORT_ATTRIBUTE) { if ((remotePort == -1 ) && (socketWrapper !=null)) { remotePort = socketWrapper.getSocket().getIOChannel().socket().getPort(); } request.setRemotePort(remotePort); } else if (actionCode == ActionCode.REQ_LOCALPORT_ATTRIBUTE) { if ((localPort == -1 ) && (socketWrapper !=null)) { localPort = socketWrapper.getSocket().getIOChannel().socket().getLocalPort(); } request.setLocalPort(localPort); } else if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) { try { if (sslSupport != null) { Object sslO = sslSupport.getCipherSuite(); if (sslO != null) { request.setAttribute (SSLSupport.CIPHER_SUITE_KEY, sslO); } sslO = sslSupport.getPeerCertificateChain(false); if (sslO != null) { request.setAttribute (SSLSupport.CERTIFICATE_KEY, sslO); } sslO = sslSupport.getKeySize(); if (sslO != null) { request.setAttribute (SSLSupport.KEY_SIZE_KEY, sslO); } sslO = sslSupport.getSessionId(); if (sslO != null) { request.setAttribute (SSLSupport.SESSION_ID_KEY, sslO); } request.setAttribute(SSLSupport.SESSION_MGR, sslSupport); } } catch (Exception e) { log.warn(sm.getString("http11processor.socket.ssl"), e); } } else if (actionCode == ActionCode.REQ_SSL_CERTIFICATE) { if( sslSupport != null) { /* * Consume and buffer the request body, so that it does not * interfere with the client's handshake messages */ InputFilter[] inputFilters = inputBuffer.getFilters(); ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) .setLimit(maxSavePostSize); inputBuffer.addActiveFilter (inputFilters[Constants.BUFFERED_FILTER]); SecureNioChannel sslChannel = (SecureNioChannel) socketWrapper.getSocket(); SSLEngine engine = sslChannel.getSslEngine(); if (!engine.getNeedClientAuth()) { // Need to re-negotiate SSL connection engine.setNeedClientAuth(true); try { sslChannel.rehandshake(endpoint.getSoTimeout()); sslSupport = ((NioEndpoint)endpoint).getHandler() .getSslImplementation().getSSLSupport( engine.getSession()); } catch (IOException ioe) { log.warn(sm.getString("http11processor.socket.sslreneg",ioe)); } } try { // use force=false since re-negotiation is handled above // (and it is a NO-OP for NIO anyway) Object sslO = sslSupport.getPeerCertificateChain(false); if( sslO != null) { request.setAttribute (SSLSupport.CERTIFICATE_KEY, sslO); } } catch (Exception e) { log.warn(sm.getString("http11processor.socket.ssl"), e); } } } else if (actionCode == ActionCode.AVAILABLE) { request.setAvailable(inputBuffer.available()); } else if (actionCode == ActionCode.COMET_BEGIN) { comet = true; } else if (actionCode == ActionCode.COMET_END) { comet = false; } else if (actionCode == ActionCode.COMET_CLOSE) { if (socketWrapper==null || socketWrapper.getSocket().getAttachment(false)==null) { return; } NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment)socketWrapper.getSocket().getAttachment(false); attach.setCometOps(NioEndpoint.OP_CALLBACK); RequestInfo rp = request.getRequestProcessor(); if (rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE) { // Close event for this processor triggered by request // processing in another processor, a non-Tomcat thread (i.e. // an application controlled thread) or similar. socketWrapper.getSocket().getPoller().add(socketWrapper.getSocket()); } } else if (actionCode == ActionCode.COMET_SETTIMEOUT) { if (param==null) { return; } if (socketWrapper==null || socketWrapper.getSocket().getAttachment(false)==null) { return; } NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment)socketWrapper.getSocket().getAttachment(false); long timeout = ((Long)param).longValue(); //if we are not piggy backing on a worker thread, set the timeout RequestInfo rp = request.getRequestProcessor(); if ( rp.getStage() != org.apache.coyote.Constants.STAGE_SERVICE ) { attach.setTimeout(timeout); } } else if (actionCode == ActionCode.ASYNC_COMPLETE) { if (asyncStateMachine.asyncComplete()) { ((NioEndpoint)endpoint).processSocket(socketWrapper.getSocket(), SocketStatus.OPEN_READ, true); } } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) { if (param==null) { return; } if (socketWrapper==null || socketWrapper.getSocket().getAttachment(false)==null) { return; } NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment)socketWrapper.getSocket().getAttachment(false); long timeout = ((Long)param).longValue(); //if we are not piggy backing on a worker thread, set the timeout attach.setTimeout(timeout); } else if (actionCode == ActionCode.ASYNC_DISPATCH) { if (asyncStateMachine.asyncDispatch()) { ((NioEndpoint)endpoint).processSocket(socketWrapper.getSocket(), SocketStatus.OPEN_READ, true); } } } // ------------------------------------------------------ Protected Methods @Override protected void prepareRequestInternal() { sendfileData = null; } @Override protected boolean prepareSendfile(OutputFilter[] outputFilters) { String fileName = (String) request.getAttribute( org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR); if (fileName != null) { // No entity body sent here outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]); contentDelimitation = true; sendfileData = new NioEndpoint.SendfileData(); sendfileData.fileName = fileName; sendfileData.pos = ((Long) request.getAttribute( org.apache.coyote.Constants.SENDFILE_FILE_START_ATTR)).longValue(); sendfileData.length = ((Long) request.getAttribute( org.apache.coyote.Constants.SENDFILE_FILE_END_ATTR)).longValue() - sendfileData.pos; return true; } return false; } @Override protected AbstractInputBuffer getInputBuffer() { return inputBuffer; } @Override protected AbstractOutputBuffer getOutputBuffer() { return outputBuffer; } /** * Set the SSL information for this HTTP connection. */ @Override public void setSslSupport(SSLSupport sslSupport) { this.sslSupport = sslSupport; } } tomcat7-7.0.52/java/org/apache/coyote/http11/AbstractHttp11Protocol.java0000644000175100017510000001425412214076006025655 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import org.apache.coyote.AbstractProtocol; import org.apache.tomcat.util.res.StringManager; public abstract class AbstractHttp11Protocol extends AbstractProtocol { /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); @Override protected String getProtocolName() { return "Http"; } // ------------------------------------------------ HTTP specific properties // ------------------------------------------ managed in the ProtocolHandler private int socketBuffer = 9000; public int getSocketBuffer() { return socketBuffer; } public void setSocketBuffer(int socketBuffer) { this.socketBuffer = socketBuffer; } /** * Maximum size of the post which will be saved when processing certain * requests, such as a POST. */ private int maxSavePostSize = 4 * 1024; public int getMaxSavePostSize() { return maxSavePostSize; } public void setMaxSavePostSize(int valueI) { maxSavePostSize = valueI; } /** * Maximum size of the HTTP message header. */ private int maxHttpHeaderSize = 8 * 1024; public int getMaxHttpHeaderSize() { return maxHttpHeaderSize; } public void setMaxHttpHeaderSize(int valueI) { maxHttpHeaderSize = valueI; } /** * Specifies a different (usually longer) connection timeout during data * upload. */ private int connectionUploadTimeout = 300000; public int getConnectionUploadTimeout() { return connectionUploadTimeout; } public void setConnectionUploadTimeout(int i) { connectionUploadTimeout = i; } /** * If true, the connectionUploadTimeout will be ignored and the regular * socket timeout will be used for the full duration of the connection. */ private boolean disableUploadTimeout = true; public boolean getDisableUploadTimeout() { return disableUploadTimeout; } public void setDisableUploadTimeout(boolean isDisabled) { disableUploadTimeout = isDisabled; } /** * Integrated compression support. */ private String compression = "off"; public String getCompression() { return compression; } public void setCompression(String valueS) { compression = valueS; } private String noCompressionUserAgents = null; public String getNoCompressionUserAgents() { return noCompressionUserAgents; } public void setNoCompressionUserAgents(String valueS) { noCompressionUserAgents = valueS; } private String compressableMimeTypes = "text/html,text/xml,text/plain"; public String getCompressableMimeType() { return compressableMimeTypes; } public void setCompressableMimeType(String valueS) { compressableMimeTypes = valueS; } public String getCompressableMimeTypes() { return getCompressableMimeType(); } public void setCompressableMimeTypes(String valueS) { setCompressableMimeType(valueS); } private int compressionMinSize = 2048; public int getCompressionMinSize() { return compressionMinSize; } public void setCompressionMinSize(int valueI) { compressionMinSize = valueI; } /** * Regular expression that defines the User agents which should be * restricted to HTTP/1.0 support. */ private String restrictedUserAgents = null; public String getRestrictedUserAgents() { return restrictedUserAgents; } public void setRestrictedUserAgents(String valueS) { restrictedUserAgents = valueS; } /** * Server header. */ private String server; public String getServer() { return server; } public void setServer( String server ) { this.server = server; } /** * Maximum size of trailing headers in bytes */ private int maxTrailerSize = 8192; public int getMaxTrailerSize() { return maxTrailerSize; } public void setMaxTrailerSize(int maxTrailerSize) { this.maxTrailerSize = maxTrailerSize; } /** * Maximum size of extension information in chunked encoding */ private int maxExtensionSize = 8192; public int getMaxExtensionSize() { return maxExtensionSize; } public void setMaxExtensionSize(int maxExtensionSize) { this.maxExtensionSize = maxExtensionSize; } /** * This field indicates if the protocol is treated as if it is secure. This * normally means https is being used but can be used to fake https e.g * behind a reverse proxy. */ private boolean secure; public boolean getSecure() { return secure; } public void setSecure(boolean b) { secure = b; } // ------------------------------------------------ HTTP specific properties // ------------------------------------------ passed through to the EndPoint public boolean isSSLEnabled() { return endpoint.isSSLEnabled();} public void setSSLEnabled(boolean SSLEnabled) { endpoint.setSSLEnabled(SSLEnabled); } /** * Maximum number of requests which can be performed over a keepalive * connection. The default is the same as for Apache HTTP Server. */ public int getMaxKeepAliveRequests() { return endpoint.getMaxKeepAliveRequests(); } public void setMaxKeepAliveRequests(int mkar) { endpoint.setMaxKeepAliveRequests(mkar); } } tomcat7-7.0.52/java/org/apache/coyote/http11/OutputFilter.java0000644000175100017510000000437712271461367024054 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.tomcat.util.buf.ByteChunk; /** * Output filter. * * @author Remy Maucherat */ public interface OutputFilter extends OutputBuffer { /** * Write some bytes. * * @return number of bytes written by the filter */ @Override public int doWrite(ByteChunk chunk, Response unused) throws IOException; /** * Some filters need additional parameters from the response. All the * necessary reading can occur in that method, as this method is called * after the response header processing is complete. */ public void setResponse(Response response); /** * Make the filter ready to process the next request. */ public void recycle(); /** * Set the next buffer in the filter pipeline. */ public void setBuffer(OutputBuffer buffer); /** * End the current request. It is acceptable to write extra bytes using * buffer.doWrite during the execution of this method. * * @return Should return 0 unless the filter does some content length * delimitation, in which case the number is the amount of extra bytes or * missing bytes, which would indicate an error. * Note: It is recommended that extra bytes be swallowed by the filter. */ public long end() throws IOException; } tomcat7-7.0.52/java/org/apache/coyote/http11/AbstractOutputBuffer.java0000644000175100017510000003526512203242036025505 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import org.apache.coyote.ActionCode; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.coyote.http11.filters.GzipOutputFilter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.HttpMessages; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; import org.apache.tomcat.util.res.StringManager; public abstract class AbstractOutputBuffer implements OutputBuffer{ // ----------------------------------------------------- Instance Variables /** * Associated Coyote response. */ protected Response response; /** * Committed flag. */ protected boolean committed; /** * Finished flag. */ protected boolean finished; /** * The buffer used for header composition. */ protected byte[] buf; /** * Position in the buffer. */ protected int pos; /** * Filter library. * Note: Filter[0] is always the "chunked" filter. */ protected OutputFilter[] filterLibrary; /** * Active filter (which is actually the top of the pipeline). */ protected OutputFilter[] activeFilters; /** * Index of the last active filter. */ protected int lastActiveFilter; /** * Underlying output buffer. */ protected OutputBuffer outputStreamOutputBuffer; /** * Bytes written to client for the current request */ protected long byteCount = 0; // -------------------------------------------------------------- Variables /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Logger. */ private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(AbstractOutputBuffer.class); // ------------------------------------------------------------- Properties /** * Add an output filter to the filter library. */ public void addFilter(OutputFilter filter) { OutputFilter[] newFilterLibrary = new OutputFilter[filterLibrary.length + 1]; for (int i = 0; i < filterLibrary.length; i++) { newFilterLibrary[i] = filterLibrary[i]; } newFilterLibrary[filterLibrary.length] = filter; filterLibrary = newFilterLibrary; activeFilters = new OutputFilter[filterLibrary.length]; } /** * Get filters. */ public OutputFilter[] getFilters() { return filterLibrary; } /** * Add an output filter to the filter library. */ public void addActiveFilter(OutputFilter filter) { if (lastActiveFilter == -1) { filter.setBuffer(outputStreamOutputBuffer); } else { for (int i = 0; i <= lastActiveFilter; i++) { if (activeFilters[i] == filter) return; } filter.setBuffer(activeFilters[lastActiveFilter]); } activeFilters[++lastActiveFilter] = filter; filter.setResponse(response); } // --------------------------------------------------- OutputBuffer Methods /** * Write the contents of a byte chunk. * * @param chunk byte chunk * @return number of bytes written * @throws IOException an underlying I/O error occurred */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { if (!committed) { // Send the connector a request for commit. The connector should // then validate the headers, send them (using sendHeaders) and // set the filters accordingly. response.action(ActionCode.COMMIT, null); } if (lastActiveFilter == -1) return outputStreamOutputBuffer.doWrite(chunk, res); else return activeFilters[lastActiveFilter].doWrite(chunk, res); } @Override public long getBytesWritten() { if (lastActiveFilter == -1) { return outputStreamOutputBuffer.getBytesWritten(); } else { return activeFilters[lastActiveFilter].getBytesWritten(); } } // --------------------------------------------------------- Public Methods /** * Flush the response. * * @throws IOException an underlying I/O error occurred */ public void flush() throws IOException { if (!committed) { // Send the connector a request for commit. The connector should // then validate the headers, send them (using sendHeader) and // set the filters accordingly. response.action(ActionCode.COMMIT, null); } // go through the filters and if there is gzip filter // invoke it to flush for (int i = 0; i <= lastActiveFilter; i++) { if (activeFilters[i] instanceof GzipOutputFilter) { if (log.isDebugEnabled()) { log.debug("Flushing the gzip filter at position " + i + " of the filter chain..."); } ((GzipOutputFilter) activeFilters[i]).flush(); break; } } } /** * Reset current response. * * @throws IllegalStateException if the response has already been committed */ public void reset() { if (committed) throw new IllegalStateException(/*FIXME:Put an error message*/); // Recycle Request object response.recycle(); // These will need to be reset if the reset was triggered by the error // handling if the headers were too large pos = 0; byteCount = 0; } /** * Recycle the output buffer. This should be called when closing the * connection. */ public void recycle() { // Sub-classes may wish to do more than this. nextRequest(); } /** * End processing of current HTTP request. * Note: All bytes of the current request should have been already * consumed. This method only resets all the pointers so that we are ready * to parse the next HTTP request. */ public void nextRequest() { // Recycle filters for (int i = 0; i <= lastActiveFilter; i++) { activeFilters[i].recycle(); } // Recycle response object response.recycle(); // Reset pointers pos = 0; lastActiveFilter = -1; committed = false; finished = false; byteCount = 0; } /** * End request. * * @throws IOException an underlying I/O error occurred */ public void endRequest() throws IOException { if (!committed) { // Send the connector a request for commit. The connector should // then validate the headers, send them (using sendHeader) and // set the filters accordingly. response.action(ActionCode.COMMIT, null); } if (finished) return; if (lastActiveFilter != -1) activeFilters[lastActiveFilter].end(); finished = true; } public abstract void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException; public abstract void sendAck() throws IOException; protected abstract void commit() throws IOException; /** * Send the response status line. */ public void sendStatus() { // Write protocol name write(Constants.HTTP_11_BYTES); buf[pos++] = Constants.SP; // Write status code int status = response.getStatus(); switch (status) { case 200: write(Constants._200_BYTES); break; case 400: write(Constants._400_BYTES); break; case 404: write(Constants._404_BYTES); break; default: write(status); } buf[pos++] = Constants.SP; // Write message String message = null; if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER && HttpMessages.isSafeInHttpHeader(response.getMessage())) { message = response.getMessage(); } if (message == null) { write(HttpMessages.getInstance( response.getLocale()).getMessage(status)); } else { write(message); } // End the response status line if (org.apache.coyote.Constants.IS_SECURITY_ENABLED){ AccessController.doPrivileged( new PrivilegedAction(){ @Override public Void run(){ buf[pos++] = Constants.CR; buf[pos++] = Constants.LF; return null; } } ); } else { buf[pos++] = Constants.CR; buf[pos++] = Constants.LF; } } /** * Send a header. * * @param name Header name * @param value Header value */ public void sendHeader(MessageBytes name, MessageBytes value) { write(name); buf[pos++] = Constants.COLON; buf[pos++] = Constants.SP; write(value); buf[pos++] = Constants.CR; buf[pos++] = Constants.LF; } /** * End the header block. */ public void endHeaders() { buf[pos++] = Constants.CR; buf[pos++] = Constants.LF; } /** * This method will write the contents of the specified message bytes * buffer to the output stream, without filtering. This method is meant to * be used to write the response header. * * @param mb data to be written */ protected void write(MessageBytes mb) { if (mb.getType() == MessageBytes.T_BYTES) { ByteChunk bc = mb.getByteChunk(); write(bc); } else if (mb.getType() == MessageBytes.T_CHARS) { CharChunk cc = mb.getCharChunk(); write(cc); } else { write(mb.toString()); } } /** * This method will write the contents of the specified message bytes * buffer to the output stream, without filtering. This method is meant to * be used to write the response header. * * @param bc data to be written */ protected void write(ByteChunk bc) { // Writing the byte chunk to the output buffer int length = bc.getLength(); checkLengthBeforeWrite(length); System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos, length); pos = pos + length; } /** * This method will write the contents of the specified char * buffer to the output stream, without filtering. This method is meant to * be used to write the response header. * * @param cc data to be written */ protected void write(CharChunk cc) { int start = cc.getStart(); int end = cc.getEnd(); checkLengthBeforeWrite(end-start); char[] cbuf = cc.getBuffer(); for (int i = start; i < end; i++) { char c = cbuf[i]; // Note: This is clearly incorrect for many strings, // but is the only consistent approach within the current // servlet framework. It must suffice until servlet output // streams properly encode their output. if (((c <= 31) && (c != 9)) || c == 127 || c > 255) { c = ' '; } buf[pos++] = (byte) c; } } /** * This method will write the contents of the specified byte * buffer to the output stream, without filtering. This method is meant to * be used to write the response header. * * @param b data to be written */ public void write(byte[] b) { checkLengthBeforeWrite(b.length); // Writing the byte chunk to the output buffer System.arraycopy(b, 0, buf, pos, b.length); pos = pos + b.length; } /** * This method will write the contents of the specified String to the * output stream, without filtering. This method is meant to be used to * write the response header. * * @param s data to be written */ protected void write(String s) { if (s == null) return; // From the Tomcat 3.3 HTTP/1.0 connector int len = s.length(); checkLengthBeforeWrite(len); for (int i = 0; i < len; i++) { char c = s.charAt (i); // Note: This is clearly incorrect for many strings, // but is the only consistent approach within the current // servlet framework. It must suffice until servlet output // streams properly encode their output. if (((c <= 31) && (c != 9)) || c == 127 || c > 255) { c = ' '; } buf[pos++] = (byte) c; } } /** * This method will print the specified integer to the output stream, * without filtering. This method is meant to be used to write the * response header. * * @param i data to be written */ protected void write(int i) { write(String.valueOf(i)); } /** * Checks to see if there is enough space in the buffer to write the * requested number of bytes. */ private void checkLengthBeforeWrite(int length) { if (pos + length > buf.length) { throw new HeadersTooLargeException( sm.getString("iob.responseheadertoolarge.error")); } } } tomcat7-7.0.52/java/org/apache/coyote/http11/Constants.java0000644000175100017510000001100212271461367023341 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import org.apache.tomcat.util.buf.ByteChunk; /** * Constants. * * @author Remy Maucherat */ public final class Constants { // -------------------------------------------------------------- Constants /** * Package name. */ public static final String Package = "org.apache.coyote.http11"; public static final int DEFAULT_CONNECTION_LINGER = -1; public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; public static final boolean DEFAULT_TCP_NO_DELAY = true; /** * CRLF. */ public static final String CRLF = "\r\n"; /** * Server string. */ public static final byte[] SERVER_BYTES = ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF); /** * CR. */ public static final byte CR = (byte) '\r'; /** * LF. */ public static final byte LF = (byte) '\n'; /** * SP. */ public static final byte SP = (byte) ' '; /** * HT. */ public static final byte HT = (byte) '\t'; /** * COLON. */ public static final byte COLON = (byte) ':'; /** * SEMI_COLON. */ public static final byte SEMI_COLON = (byte) ';'; /** * 'A'. */ public static final byte A = (byte) 'A'; /** * 'a'. */ public static final byte a = (byte) 'a'; /** * 'Z'. */ public static final byte Z = (byte) 'Z'; /** * '?'. */ public static final byte QUESTION = (byte) '?'; /** * Lower case offset. */ public static final byte LC_OFFSET = A - a; /* Various constant "strings" */ public static final String CONNECTION = "Connection"; public static final String CLOSE = "close"; public static final byte[] CLOSE_BYTES = ByteChunk.convertToBytes(CLOSE); public static final String KEEPALIVE = "keep-alive"; public static final byte[] KEEPALIVE_BYTES = ByteChunk.convertToBytes(KEEPALIVE); public static final String CHUNKED = "chunked"; public static final byte[] ACK_BYTES = ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF); public static final String TRANSFERENCODING = "Transfer-Encoding"; public static final byte[] _200_BYTES = ByteChunk.convertToBytes("200"); public static final byte[] _400_BYTES = ByteChunk.convertToBytes("400"); public static final byte[] _404_BYTES = ByteChunk.convertToBytes("404"); /** * Identity filters (input and output). */ public static final int IDENTITY_FILTER = 0; /** * Chunked filters (input and output). */ public static final int CHUNKED_FILTER = 1; /** * Void filters (input and output). */ public static final int VOID_FILTER = 2; /** * GZIP filter (output). */ public static final int GZIP_FILTER = 3; /** * Buffered filter (input) */ public static final int BUFFERED_FILTER = 3; /** * HTTP/1.0. */ public static final String HTTP_10 = "HTTP/1.0"; /** * HTTP/1.1. */ public static final String HTTP_11 = "HTTP/1.1"; public static final byte[] HTTP_11_BYTES = ByteChunk.convertToBytes(HTTP_11); /** * GET. */ public static final String GET = "GET"; /** * HEAD. */ public static final String HEAD = "HEAD"; /** * POST. */ public static final String POST = "POST"; /** * Has security been turned on? * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); } tomcat7-7.0.52/java/org/apache/coyote/http11/LocalStrings.properties0000644000175100017510000000562412271461367025261 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. http11protocol.endpoint.starterror=Error starting endpoint http11protocol.proto.error=Error reading request, ignored http11protocol.proto.ioexception.debug=IOException reading request http11protocol.proto.ioexception.info=IOException reading request, ignored http11protocol.proto.socketexception.debug=SocketException reading request http11protocol.proto.socketexception.info=SocketException reading request, ignored http11protocol.start=Starting Coyote HTTP/1.1 on {0} http11processor.regexp.error=Error parsing regular expression {0} http11processor.fallToDebug=\n Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level. http11processor.filter.unknown=Unknown filter {0} http11processor.filter.error=Error intializing filter {0} http11processor.header.parse=Error parsing HTTP request header http11processor.neverused=This method should never be used http11processor.request.prepare=Error preparing request http11processor.request.process=Error processing request http11processor.request.finish=Error finishing request http11processor.response.finish=Error finishing response http11processor.socket.info=Exception getting socket information http11processor.socket.ssl=Exception getting SSL attributes http11processor.socket.sslreneg=Exception re-negotiating SSL connection http11processor.socket.timeout=Error setting socket timeout http11processor.comet.notsupported=The Comet protocol is not supported by this connector http11processor.sendfile.error=Error sending data using sendfile. May be caused by invalid request attributes for start/end points iib.eof.error=Unexpected EOF read on the socket iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 2616 and has been ignored. iib.invalidmethod=Invalid character (CR or LF) found in method name iib.parseheaders.ise.error=Unexpected state: headers already parsed. Buffer not recycled? iib.requestheadertoolarge.error=Request header is too large iob.responseheadertoolarge.error=An attempt was made to write more data to the response headers than there was room available in the buffer. Increase maxHttpHeaderSize on the connector or write less data into the response headers. tomcat7-7.0.52/java/org/apache/coyote/http11/InternalOutputBuffer.java0000644000175100017510000001425412271461367025530 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; /** * Output buffer. * * @author Remy Maucherat */ public class InternalOutputBuffer extends AbstractOutputBuffer implements ByteChunk.ByteOutputChannel { // ----------------------------------------------------------- Constructors /** * Default constructor. */ public InternalOutputBuffer(Response response, int headerBufferSize) { this.response = response; buf = new byte[headerBufferSize]; outputStreamOutputBuffer = new OutputStreamOutputBuffer(); filterLibrary = new OutputFilter[0]; activeFilters = new OutputFilter[0]; lastActiveFilter = -1; socketBuffer = new ByteChunk(); socketBuffer.setByteOutputChannel(this); committed = false; finished = false; } /** * Underlying output stream. Note: protected to assist with unit testing */ protected OutputStream outputStream; /** * Socket buffer. */ private ByteChunk socketBuffer; /** * Socket buffer (extra buffering to reduce number of packets sent). */ private boolean useSocketBuffer = false; /** * Set the socket buffer size. */ public void setSocketBuffer(int socketBufferSize) { if (socketBufferSize > 500) { useSocketBuffer = true; socketBuffer.allocate(socketBufferSize, socketBufferSize); } else { useSocketBuffer = false; } } // --------------------------------------------------------- Public Methods @Override public void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException { outputStream = socketWrapper.getSocket().getOutputStream(); } /** * Flush the response. * * @throws IOException an underlying I/O error occurred */ @Override public void flush() throws IOException { super.flush(); // Flush the current buffer if (useSocketBuffer) { socketBuffer.flushBuffer(); } } /** * Recycle the output buffer. This should be called when closing the * connection. */ @Override public void recycle() { super.recycle(); outputStream = null; } /** * End processing of current HTTP request. * Note: All bytes of the current request should have been already * consumed. This method only resets all the pointers so that we are ready * to parse the next HTTP request. */ @Override public void nextRequest() { super.nextRequest(); socketBuffer.recycle(); } /** * End request. * * @throws IOException an underlying I/O error occurred */ @Override public void endRequest() throws IOException { super.endRequest(); if (useSocketBuffer) { socketBuffer.flushBuffer(); } } // ------------------------------------------------ HTTP/1.1 Output Methods /** * Send an acknowledgment. */ @Override public void sendAck() throws IOException { if (!committed) outputStream.write(Constants.ACK_BYTES); } // ------------------------------------------------------ Protected Methods /** * Commit the response. * * @throws IOException an underlying I/O error occurred */ @Override protected void commit() throws IOException { // The response is now committed committed = true; response.setCommitted(true); if (pos > 0) { // Sending the response header buffer if (useSocketBuffer) { socketBuffer.append(buf, 0, pos); } else { outputStream.write(buf, 0, pos); } } } /** * Callback to write data from the buffer. */ @Override public void realWriteBytes(byte cbuf[], int off, int len) throws IOException { if (len > 0) { outputStream.write(cbuf, off, len); } } // ----------------------------------- OutputStreamOutputBuffer Inner Class /** * This class is an output buffer which will write data to an output * stream. */ protected class OutputStreamOutputBuffer implements OutputBuffer { /** * Write chunk. */ @Override public int doWrite(ByteChunk chunk, Response res) throws IOException { int length = chunk.getLength(); if (useSocketBuffer) { socketBuffer.append(chunk.getBuffer(), chunk.getStart(), length); } else { outputStream.write(chunk.getBuffer(), chunk.getStart(), length); } byteCount += chunk.getLength(); return chunk.getLength(); } @Override public long getBytesWritten() { return byteCount; } } } tomcat7-7.0.52/java/org/apache/coyote/http11/LocalStrings_ja.properties0000644000175100017510000000406512271461367025731 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. http11protocol.endpoint.starterror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 http11protocol.proto.error=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f http11protocol.proto.ioexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059 http11protocol.proto.ioexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f http11protocol.proto.socketexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059 http11protocol.proto.socketexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f http11protocol.start=Coyote HTTP/1.1\u3092 {0} \u3067\u8d77\u52d5\u3057\u307e\u3059 iib.eof.error=\u30bd\u30b1\u30c3\u30c8\u304b\u3089\u4e88\u671f\u3057\u306a\u3044EOF\u3092\u8aad\u307f\u8fbc\u307f\u307e\u3057\u305f iib.requestheadertoolarge.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30d8\u30c3\u30c0\u304c\u9577\u3059\u304e\u307e\u3059 tomcat7-7.0.52/java/org/apache/coyote/http11/AbstractHttp11Processor.java0000644000175100017510000016364412276703610026051 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import java.io.InterruptedIOException; import java.util.Locale; import java.util.StringTokenizer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; import org.apache.coyote.AbstractProcessor; import org.apache.coyote.ActionCode; import org.apache.coyote.AsyncContextCallback; import org.apache.coyote.RequestInfo; import org.apache.coyote.http11.filters.BufferedInputFilter; import org.apache.coyote.http11.filters.ChunkedInputFilter; import org.apache.coyote.http11.filters.ChunkedOutputFilter; import org.apache.coyote.http11.filters.GzipOutputFilter; import org.apache.coyote.http11.filters.IdentityInputFilter; import org.apache.coyote.http11.filters.IdentityOutputFilter; import org.apache.coyote.http11.filters.SavedRequestInputFilter; import org.apache.coyote.http11.filters.VoidInputFilter; import org.apache.coyote.http11.filters.VoidOutputFilter; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.Ascii; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.FastHttpDateFormat; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.log.UserDataHelper; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; import org.apache.tomcat.util.res.StringManager; public abstract class AbstractHttp11Processor extends AbstractProcessor { protected abstract Log getLog(); private final UserDataHelper userDataHelper; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /* * Tracks how many internal filters are in the filter library so they * are skipped when looking for pluggable filters. */ private int pluggableFilterIndex = Integer.MAX_VALUE; /** * Error flag. */ protected boolean error = false; /** * Keep-alive. */ protected boolean keepAlive = true; /** * Flag used to indicate that the socket should be kept open (e.g. for keep * alive or send file. */ protected boolean openSocket = false; /** * Flag used to indicate that the socket should treat the next request * processed like a keep-alive connection - i.e. one where there may not be * any data to process. The initial value of this flag on entering the * process method is different for connectors that use polling (NIO / APR - * data is always expected) compared to those that use blocking (BIO - data * is only expected if the connection isn't in the keep-alive state). */ protected boolean keptAlive; /** * Flag that indicates that send file processing is in progress and that the * socket should not be returned to the poller (where a poller is used). */ protected boolean sendfileInProgress = false; /** * Flag that indicates if the request headers have been completely read. */ protected boolean readComplete = true; /** * HTTP/1.1 flag. */ protected boolean http11 = true; /** * HTTP/0.9 flag. */ protected boolean http09 = false; /** * Content delimiter for the request (if false, the connection will * be closed at the end of the request). */ protected boolean contentDelimitation = true; /** * Is there an expectation ? */ protected boolean expectation = false; /** * Comet used. */ protected boolean comet = false; /** * Regular expression that defines the restricted user agents. */ protected Pattern restrictedUserAgents = null; /** * Maximum number of Keep-Alive requests to honor. */ protected int maxKeepAliveRequests = -1; /** * The number of seconds Tomcat will wait for a subsequent request * before closing the connection. */ protected int keepAliveTimeout = -1; /** * Remote Address associated with the current connection. */ protected String remoteAddr = null; /** * Remote Host associated with the current connection. */ protected String remoteHost = null; /** * Local Host associated with the current connection. */ protected String localName = null; /** * Local port to which the socket is connected */ protected int localPort = -1; /** * Remote port to which the socket is connected */ protected int remotePort = -1; /** * The local Host address. */ protected String localAddr = null; /** * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server. */ protected int connectionUploadTimeout = 300000; /** * Flag to disable setting a different time-out on uploads. */ protected boolean disableUploadTimeout = false; /** * Allowed compression level. */ protected int compressionLevel = 0; /** * Minimum content size to make compression. */ protected int compressionMinSize = 2048; /** * Socket buffering. */ protected int socketBuffer = -1; /** * Max saved post size. */ protected int maxSavePostSize = 4 * 1024; /** * Regular expression that defines the user agents to not use gzip with */ protected Pattern noCompressionUserAgents = null; /** * List of MIMES which could be gzipped */ protected String[] compressableMimeTypes = { "text/html", "text/xml", "text/plain" }; /** * Host name (used to avoid useless B2C conversion on the host name). */ protected char[] hostNameC = new char[0]; /** * Allow a customized the server header for the tin-foil hat folks. */ protected String server = null; /** * Listener to which data available events are passed once the associated * connection has completed the proprietary Tomcat HTTP upgrade process. * * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated protected org.apache.coyote.http11.upgrade.UpgradeInbound upgradeInbound = null; /** * Instance of the new protocol to use after the HTTP connection has been * upgraded using the Servlet 3.1 based upgrade process. */ protected HttpUpgradeHandler httpUpgradeHandler = null; public AbstractHttp11Processor(AbstractEndpoint endpoint) { super(endpoint); userDataHelper = new UserDataHelper(getLog()); } /** * Set compression level. */ public void setCompression(String compression) { if (compression.equals("on")) { this.compressionLevel = 1; } else if (compression.equals("force")) { this.compressionLevel = 2; } else if (compression.equals("off")) { this.compressionLevel = 0; } else { try { // Try to parse compression as an int, which would give the // minimum compression size compressionMinSize = Integer.parseInt(compression); this.compressionLevel = 1; } catch (Exception e) { this.compressionLevel = 0; } } } /** * Set Minimum size to trigger compression. */ public void setCompressionMinSize(int compressionMinSize) { this.compressionMinSize = compressionMinSize; } /** * Set no compression user agent pattern. Regular expression as supported * by {@link Pattern}. * * ie: "gorilla|desesplorer|tigrus" */ public void setNoCompressionUserAgents(String noCompressionUserAgents) { if (noCompressionUserAgents == null || noCompressionUserAgents.length() == 0) { this.noCompressionUserAgents = null; } else { this.noCompressionUserAgents = Pattern.compile(noCompressionUserAgents); } } /** * Add a mime-type which will be compressible * The mime-type String will be exactly matched * in the response mime-type header . * * @param mimeType mime-type string */ public void addCompressableMimeType(String mimeType) { compressableMimeTypes = addStringArray(compressableMimeTypes, mimeType); } /** * Set compressible mime-type list (this method is best when used with * a large number of connectors, where it would be better to have all of * them referenced a single array). */ public void setCompressableMimeTypes(String[] compressableMimeTypes) { this.compressableMimeTypes = compressableMimeTypes; } /** * Set compressable mime-type list * List contains users agents separated by ',' : * * ie: "text/html,text/xml,text/plain" */ public void setCompressableMimeTypes(String compressableMimeTypes) { if (compressableMimeTypes != null) { this.compressableMimeTypes = null; StringTokenizer st = new StringTokenizer(compressableMimeTypes, ","); while (st.hasMoreTokens()) { addCompressableMimeType(st.nextToken().trim()); } } } /** * Return compression level. */ public String getCompression() { switch (compressionLevel) { case 0: return "off"; case 1: return "on"; case 2: return "force"; } return "off"; } /** * General use method * * @param sArray the StringArray * @param value string */ private String[] addStringArray(String sArray[], String value) { String[] result = null; if (sArray == null) { result = new String[1]; result[0] = value; } else { result = new String[sArray.length + 1]; for (int i = 0; i < sArray.length; i++) { result[i] = sArray[i]; } result[sArray.length] = value; } return result; } /** * Checks if any entry in the string array starts with the specified value * * @param sArray the StringArray * @param value string */ private boolean startsWithStringArray(String sArray[], String value) { if (value == null) { return false; } for (int i = 0; i < sArray.length; i++) { if (value.startsWith(sArray[i])) { return true; } } return false; } /** * Set restricted user agent list (which will downgrade the connector * to HTTP/1.0 mode). Regular expression as supported by {@link Pattern}. * * ie: "gorilla|desesplorer|tigrus" */ public void setRestrictedUserAgents(String restrictedUserAgents) { if (restrictedUserAgents == null || restrictedUserAgents.length() == 0) { this.restrictedUserAgents = null; } else { this.restrictedUserAgents = Pattern.compile(restrictedUserAgents); } } /** * Set the maximum number of Keep-Alive requests to honor. * This is to safeguard from DoS attacks. Setting to a negative * value disables the check. */ public void setMaxKeepAliveRequests(int mkar) { maxKeepAliveRequests = mkar; } /** * Return the number of Keep-Alive requests that we will honor. */ public int getMaxKeepAliveRequests() { return maxKeepAliveRequests; } /** * Set the Keep-Alive timeout. */ public void setKeepAliveTimeout(int timeout) { keepAliveTimeout = timeout; } /** * Return the number Keep-Alive timeout. */ public int getKeepAliveTimeout() { return keepAliveTimeout; } /** * Set the maximum size of a POST which will be buffered in SSL mode. */ public void setMaxSavePostSize(int msps) { maxSavePostSize = msps; } /** * Return the maximum size of a POST which will be buffered in SSL mode. */ public int getMaxSavePostSize() { return maxSavePostSize; } /** * Set the flag to control upload time-outs. */ public void setDisableUploadTimeout(boolean isDisabled) { disableUploadTimeout = isDisabled; } /** * Get the flag that controls upload time-outs. */ public boolean getDisableUploadTimeout() { return disableUploadTimeout; } /** * Set the socket buffer flag. */ public void setSocketBuffer(int socketBuffer) { this.socketBuffer = socketBuffer; } /** * Get the socket buffer flag. */ public int getSocketBuffer() { return socketBuffer; } /** * Set the upload timeout. */ public void setConnectionUploadTimeout(int timeout) { connectionUploadTimeout = timeout ; } /** * Get the upload timeout. */ public int getConnectionUploadTimeout() { return connectionUploadTimeout; } /** * Set the server header name. */ public void setServer( String server ) { if (server==null || server.equals("")) { this.server = null; } else { this.server = server; } } /** * Get the server header name. */ public String getServer() { return server; } /** * Check if the resource could be compressed, if the client supports it. */ private boolean isCompressable() { // Check if content is not already gzipped MessageBytes contentEncodingMB = response.getMimeHeaders().getValue("Content-Encoding"); if ((contentEncodingMB != null) && (contentEncodingMB.indexOf("gzip") != -1)) { return false; } // If force mode, always compress (test purposes only) if (compressionLevel == 2) { return true; } // Check if sufficient length to trigger the compression long contentLength = response.getContentLengthLong(); if ((contentLength == -1) || (contentLength > compressionMinSize)) { // Check for compatible MIME-TYPE if (compressableMimeTypes != null) { return (startsWithStringArray(compressableMimeTypes, response.getContentType())); } } return false; } /** * Check if compression should be used for this resource. Already checked * that the resource could be compressed if the client supports it. */ private boolean useCompression() { // Check if browser support gzip encoding MessageBytes acceptEncodingMB = request.getMimeHeaders().getValue("accept-encoding"); if ((acceptEncodingMB == null) || (acceptEncodingMB.indexOf("gzip") == -1)) { return false; } // If force mode, always compress (test purposes only) if (compressionLevel == 2) { return true; } // Check for incompatible Browser if (noCompressionUserAgents != null) { MessageBytes userAgentValueMB = request.getMimeHeaders().getValue("user-agent"); if(userAgentValueMB != null) { String userAgentValue = userAgentValueMB.toString(); if (noCompressionUserAgents != null && noCompressionUserAgents.matcher(userAgentValue).matches()) { return false; } } } return true; } /** * Specialized utility method: find a sequence of lower case bytes inside * a ByteChunk. */ protected int findBytes(ByteChunk bc, byte[] b) { byte first = b[0]; byte[] buff = bc.getBuffer(); int start = bc.getStart(); int end = bc.getEnd(); // Look for first char int srcEnd = b.length; for (int i = start; i <= (end - srcEnd); i++) { if (Ascii.toLower(buff[i]) != first) { continue; } // found first char, now look for a match int myPos = i+1; for (int srcPos = 1; srcPos < srcEnd;) { if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) { break; } if (srcPos == srcEnd) { return i - start; // found it } } } return -1; } /** * Determine if we must drop the connection because of the HTTP status * code. Use the same list of codes as Apache/httpd. */ protected boolean statusDropsConnection(int status) { return status == 400 /* SC_BAD_REQUEST */ || status == 408 /* SC_REQUEST_TIMEOUT */ || status == 411 /* SC_LENGTH_REQUIRED */ || status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || status == 414 /* SC_REQUEST_URI_TOO_LONG */ || status == 500 /* SC_INTERNAL_SERVER_ERROR */ || status == 503 /* SC_SERVICE_UNAVAILABLE */ || status == 501 /* SC_NOT_IMPLEMENTED */; } /** * Exposes input buffer to super class to allow better code re-use. * @return The input buffer used by the processor. */ protected abstract AbstractInputBuffer getInputBuffer(); /** * Exposes output buffer to super class to allow better code re-use. * @return The output buffer used by the processor. */ protected abstract AbstractOutputBuffer getOutputBuffer(); /** * Initialize standard input and output filters. */ protected void initializeFilters(int maxTrailerSize, int maxExtensionSize) { // Create and add the identity filters. getInputBuffer().addFilter(new IdentityInputFilter()); getOutputBuffer().addFilter(new IdentityOutputFilter()); // Create and add the chunked filters. getInputBuffer().addFilter( new ChunkedInputFilter(maxTrailerSize, maxExtensionSize)); getOutputBuffer().addFilter(new ChunkedOutputFilter()); // Create and add the void filters. getInputBuffer().addFilter(new VoidInputFilter()); getOutputBuffer().addFilter(new VoidOutputFilter()); // Create and add buffered input filter getInputBuffer().addFilter(new BufferedInputFilter()); // Create and add the chunked filters. //getInputBuffer().addFilter(new GzipInputFilter()); getOutputBuffer().addFilter(new GzipOutputFilter()); pluggableFilterIndex = getInputBuffer().getFilters().length; } /** * Add an input filter to the current request. * * @return false if the encoding was not found (which would mean it is * unsupported) */ protected boolean addInputFilter(InputFilter[] inputFilters, String encodingName) { if (encodingName.equals("identity")) { // Skip } else if (encodingName.equals("chunked")) { getInputBuffer().addActiveFilter (inputFilters[Constants.CHUNKED_FILTER]); contentDelimitation = true; } else { for (int i = pluggableFilterIndex; i < inputFilters.length; i++) { if (inputFilters[i].getEncodingName() .toString().equals(encodingName)) { getInputBuffer().addActiveFilter(inputFilters[i]); return true; } } return false; } return true; } /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override @SuppressWarnings("deprecation") // Inbound/Outbound based upgrade mechanism public final void action(ActionCode actionCode, Object param) { if (actionCode == ActionCode.CLOSE) { // End the processing of the current request try { getOutputBuffer().endRequest(); } catch (IOException e) { // Set error flag error = true; } } else if (actionCode == ActionCode.COMMIT) { // Commit current response if (response.isCommitted()) { return; } // Validate and write response headers try { prepareResponse(); getOutputBuffer().commit(); } catch (IOException e) { // Set error flag error = true; } } else if (actionCode == ActionCode.ACK) { // Acknowledge request // Send a 100 status back if it makes sense (response not committed // yet, and client specified an expectation for 100-continue) if ((response.isCommitted()) || !expectation) { return; } getInputBuffer().setSwallowInput(true); try { getOutputBuffer().sendAck(); } catch (IOException e) { // Set error flag error = true; } } else if (actionCode == ActionCode.CLIENT_FLUSH) { try { getOutputBuffer().flush(); } catch (IOException e) { // Set error flag error = true; response.setErrorException(e); } } else if (actionCode == ActionCode.IS_ERROR) { ((AtomicBoolean) param).set(error); } else if (actionCode == ActionCode.DISABLE_SWALLOW_INPUT) { // Do not swallow request input but // make sure we are closing the connection error = true; getInputBuffer().setSwallowInput(false); } else if (actionCode == ActionCode.RESET) { // Reset response // Note: This must be called before the response is committed getOutputBuffer().reset(); } else if (actionCode == ActionCode.CUSTOM) { // Do nothing // TODO Remove this action } else if (actionCode == ActionCode.REQ_SET_BODY_REPLAY) { ByteChunk body = (ByteChunk) param; InputFilter savedBody = new SavedRequestInputFilter(body); savedBody.setRequest(request); @SuppressWarnings("unchecked") AbstractInputBuffer internalBuffer = (AbstractInputBuffer) request.getInputBuffer(); internalBuffer.addActiveFilter(savedBody); } else if (actionCode == ActionCode.ASYNC_START) { asyncStateMachine.asyncStart((AsyncContextCallback) param); // Async time out is based on SocketWrapper access time getSocketWrapper().access(); } else if (actionCode == ActionCode.ASYNC_DISPATCHED) { asyncStateMachine.asyncDispatched(); } else if (actionCode == ActionCode.ASYNC_TIMEOUT) { AtomicBoolean result = (AtomicBoolean) param; result.set(asyncStateMachine.asyncTimeout()); } else if (actionCode == ActionCode.ASYNC_RUN) { asyncStateMachine.asyncRun((Runnable) param); } else if (actionCode == ActionCode.ASYNC_ERROR) { asyncStateMachine.asyncError(); } else if (actionCode == ActionCode.ASYNC_IS_STARTED) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncStarted()); } else if (actionCode == ActionCode.ASYNC_IS_DISPATCHING) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncDispatching()); } else if (actionCode == ActionCode.ASYNC_IS_ASYNC) { ((AtomicBoolean) param).set(asyncStateMachine.isAsync()); } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut()); } else if (actionCode == ActionCode.ASYNC_IS_ERROR) { ((AtomicBoolean) param).set(asyncStateMachine.isAsyncError()); } else if (actionCode == ActionCode.UPGRADE_TOMCAT) { upgradeInbound = (org.apache.coyote.http11.upgrade.UpgradeInbound) param; // Stop further HTTP output getOutputBuffer().finished = true; } else if (actionCode == ActionCode.UPGRADE) { httpUpgradeHandler = (HttpUpgradeHandler) param; // Stop further HTTP output getOutputBuffer().finished = true; } else { actionInternal(actionCode, param); } } abstract void actionInternal(ActionCode actionCode, Object param); /** * Processors (currently only HTTP BIO) may elect to disable HTTP keep-alive * in some circumstances. This method allows the processor implementation to * determine if keep-alive should be disabled or not. */ protected abstract boolean disableKeepAlive(); /** * Configures the timeout to be used for reading the request line. */ protected abstract void setRequestLineReadTimeout() throws IOException; /** * Defines how a connector handles an incomplete request line read. * * @return true if the processor should break out of the * processing loop, otherwise false. */ protected abstract boolean handleIncompleteRequestLineRead(); /** * Set the socket timeout. */ protected abstract void setSocketTimeout(int timeout) throws IOException; /** * Process pipelined HTTP requests using the specified input and output * streams. * * @param socketWrapper Socket from which the HTTP requests will be read * and the HTTP responses will be written. * * @throws IOException error during an I/O operation */ @Override public SocketState process(SocketWrapper socketWrapper) throws IOException { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); // Setting up the I/O setSocketWrapper(socketWrapper); getInputBuffer().init(socketWrapper, endpoint); getOutputBuffer().init(socketWrapper, endpoint); // Flags error = false; keepAlive = true; comet = false; openSocket = false; sendfileInProgress = false; readComplete = true; if (endpoint.getUsePolling()) { keptAlive = false; } else { keptAlive = socketWrapper.isKeptAlive(); } if (disableKeepAlive()) { socketWrapper.setKeepAliveLeft(0); } while (!error && keepAlive && !comet && !isAsync() && upgradeInbound == null && httpUpgradeHandler == null && !endpoint.isPaused()) { // Parsing the request header try { setRequestLineReadTimeout(); if (!getInputBuffer().parseRequestLine(keptAlive)) { if (handleIncompleteRequestLineRead()) { break; } } if (endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); error = true; } else { // Make sure that connectors that are non-blocking during // header processing (NIO) only set the start time the first // time a request is processed. if (request.getStartTime() < 0) { request.setStartTime(System.currentTimeMillis()); } keptAlive = true; // Set this every time in case limit has been changed via JMX request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount()); // Currently only NIO will ever return false here if (!getInputBuffer().parseHeaders()) { // We've read part of the request, don't recycle it // instead associate it with the socket openSocket = true; readComplete = false; break; } if (!disableUploadTimeout) { setSocketTimeout(connectionUploadTimeout); } } } catch (IOException e) { if (getLog().isDebugEnabled()) { getLog().debug( sm.getString("http11processor.header.parse"), e); } error = true; break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); UserDataHelper.Mode logMode = userDataHelper.getNextMode(); if (logMode != null) { String message = sm.getString( "http11processor.header.parse"); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString( "http11processor.fallToDebug"); //$FALL-THROUGH$ case INFO: getLog().info(message); break; case DEBUG: getLog().debug(message); } } // 400 - Bad Request response.setStatus(400); adapter.log(request, response, 0); error = true; } if (!error) { // Setting up filters, and parse some request headers rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); try { prepareRequest(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (getLog().isDebugEnabled()) { getLog().debug(sm.getString( "http11processor.request.prepare"), t); } // 400 - Internal Server Error response.setStatus(400); adapter.log(request, response, 0); error = true; } } if (maxKeepAliveRequests == 1) { keepAlive = false; } else if (maxKeepAliveRequests > 0 && socketWrapper.decrementKeepAlive() <= 0) { keepAlive = false; } // Process the request in the adapter if (!error) { try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); // Handle when the response was committed before a serious // error occurred. Throwing a ServletException should both // set the status to 500 and set the errorException. // If we fail here, then the response is likely already // committed, so we can't try and set headers. if(keepAlive && !error) { // Avoid checking twice. error = response.getErrorException() != null || (!isAsync() && statusDropsConnection(response.getStatus())); } setCometTimeouts(socketWrapper); } catch (InterruptedIOException e) { error = true; } catch (HeadersTooLargeException e) { error = true; // The response should not have been committed but check it // anyway to be safe if (!response.isCommitted()) { response.reset(); response.setStatus(500); response.setHeader("Connection", "close"); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().error(sm.getString( "http11processor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); error = true; } } // Finish the handling of the request rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT); if (!isAsync() && !comet) { if (error) { // If we know we are closing the connection, don't drain // input. This way uploading a 100GB file doesn't tie up the // thread if the servlet has rejected it. getInputBuffer().setSwallowInput(false); } if (response.getStatus() < 200 || response.getStatus() > 299) { if (expectation) { // Client sent Expect: 100-continue but received a // non-2xx response. Disable keep-alive (if enabled) to // ensure the connection is closed. Some clients may // still send the body, some may send the next request. // No way to differentiate, so close the connection to // force the client to send the next request. getInputBuffer().setSwallowInput(false); keepAlive = false; } } endRequest(); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT); // If there was an error, make sure the request is counted as // and error, and update the statistics counter if (error) { response.setStatus(500); } request.updateCounters(); if (!isAsync() && !comet || error) { getInputBuffer().nextRequest(); getOutputBuffer().nextRequest(); } if (!disableUploadTimeout) { if(endpoint.getSoTimeout() > 0) { setSocketTimeout(endpoint.getSoTimeout()); } else { setSocketTimeout(0); } } rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); if (breakKeepAliveLoop(socketWrapper)) { break; } } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (error || endpoint.isPaused()) { return SocketState.CLOSED; } else if (isAsync() || comet) { return SocketState.LONG; } else if (isUpgrade()) { return SocketState.UPGRADING; } else if (getUpgradeInbound() != null) { return SocketState.UPGRADING_TOMCAT; } else { if (sendfileInProgress) { return SocketState.SENDFILE; } else { if (openSocket) { if (readComplete) { return SocketState.OPEN; } else { return SocketState.LONG; } } else { return SocketState.CLOSED; } } } } /** * After reading the request headers, we have to setup the request filters. */ protected void prepareRequest() { http11 = true; http09 = false; contentDelimitation = false; expectation = false; prepareRequestInternal(); if (endpoint.isSSLEnabled()) { request.scheme().setString("https"); } MessageBytes protocolMB = request.protocol(); if (protocolMB.equals(Constants.HTTP_11)) { http11 = true; protocolMB.setString(Constants.HTTP_11); } else if (protocolMB.equals(Constants.HTTP_10)) { http11 = false; keepAlive = false; protocolMB.setString(Constants.HTTP_10); } else if (protocolMB.equals("")) { // HTTP/0.9 http09 = true; http11 = false; keepAlive = false; } else { // Unsupported protocol http11 = false; error = true; // Send 505; Unsupported HTTP version if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("http11processor.request.prepare")+ " Unsupported HTTP version \""+protocolMB+"\""); } response.setStatus(505); } MessageBytes methodMB = request.method(); if (methodMB.equals(Constants.GET)) { methodMB.setString(Constants.GET); } else if (methodMB.equals(Constants.POST)) { methodMB.setString(Constants.POST); } MimeHeaders headers = request.getMimeHeaders(); // Check connection header MessageBytes connectionValueMB = headers.getValue(Constants.CONNECTION); if (connectionValueMB != null) { ByteChunk connectionValueBC = connectionValueMB.getByteChunk(); if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) { keepAlive = false; } else if (findBytes(connectionValueBC, Constants.KEEPALIVE_BYTES) != -1) { keepAlive = true; } } MessageBytes expectMB = null; if (http11) { expectMB = headers.getValue("expect"); } if ((expectMB != null) && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) { getInputBuffer().setSwallowInput(false); expectation = true; } // Check user-agent header if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { MessageBytes userAgentValueMB = headers.getValue("user-agent"); // Check in the restricted list, and adjust the http11 // and keepAlive flags accordingly if(userAgentValueMB != null) { String userAgentValue = userAgentValueMB.toString(); if (restrictedUserAgents != null && restrictedUserAgents.matcher(userAgentValue).matches()) { http11 = false; keepAlive = false; } } } // Check for a full URI (including protocol://host:port/) ByteChunk uriBC = request.requestURI().getByteChunk(); if (uriBC.startsWithIgnoreCase("http", 0)) { int pos = uriBC.indexOf("://", 0, 3, 4); int uriBCStart = uriBC.getStart(); int slashPos = -1; if (pos != -1) { byte[] uriB = uriBC.getBytes(); slashPos = uriBC.indexOf('/', pos + 3); if (slashPos == -1) { slashPos = uriBC.getLength(); // Set URI as "/" request.requestURI().setBytes (uriB, uriBCStart + pos + 1, 1); } else { request.requestURI().setBytes (uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos); } MessageBytes hostMB = headers.setValue("host"); hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos - pos - 3); } } // Input filter setup InputFilter[] inputFilters = getInputBuffer().getFilters(); // Parse transfer-encoding header MessageBytes transferEncodingValueMB = null; if (http11) { transferEncodingValueMB = headers.getValue("transfer-encoding"); } if (transferEncodingValueMB != null) { String transferEncodingValue = transferEncodingValueMB.toString(); // Parse the comma separated list. "identity" codings are ignored int startPos = 0; int commaPos = transferEncodingValue.indexOf(','); String encodingName = null; while (commaPos != -1) { encodingName = transferEncodingValue.substring (startPos, commaPos).toLowerCase(Locale.ENGLISH).trim(); if (!addInputFilter(inputFilters, encodingName)) { // Unsupported transfer encoding error = true; // 501 - Unimplemented response.setStatus(501); } startPos = commaPos + 1; commaPos = transferEncodingValue.indexOf(',', startPos); } encodingName = transferEncodingValue.substring(startPos) .toLowerCase(Locale.ENGLISH).trim(); if (!addInputFilter(inputFilters, encodingName)) { // Unsupported transfer encoding error = true; // 501 - Unimplemented if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("http11processor.request.prepare")+ " Unsupported transfer encoding \""+encodingName+"\""); } response.setStatus(501); } } // Parse content-length header long contentLength = request.getContentLengthLong(); if (contentLength >= 0) { if (contentDelimitation) { // contentDelimitation being true at this point indicates that // chunked encoding is being used but chunked encoding should // not be used with a content length. RFC 2616, section 4.4, // bullet 3 states Content-Length must be ignored in this case - // so remove it. headers.removeHeader("content-length"); request.setContentLength(-1); } else { getInputBuffer().addActiveFilter (inputFilters[Constants.IDENTITY_FILTER]); contentDelimitation = true; } } MessageBytes valueMB = headers.getValue("host"); // Check host header if (http11 && (valueMB == null)) { error = true; // 400 - Bad request if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("http11processor.request.prepare")+ " host header missing"); } response.setStatus(400); } parseHost(valueMB); if (!contentDelimitation) { // If there's no content length // (broken HTTP/1.0 or HTTP/1.1), assume // the client is not broken and didn't send a body getInputBuffer().addActiveFilter (inputFilters[Constants.VOID_FILTER]); contentDelimitation = true; } // Advertise sendfile support through a request attribute if (endpoint.getUseSendfile()) { request.setAttribute( org.apache.coyote.Constants.SENDFILE_SUPPORTED_ATTR, Boolean.TRUE); } // Advertise comet support through a request attribute if (endpoint.getUseComet()) { request.setAttribute( org.apache.coyote.Constants.COMET_SUPPORTED_ATTR, Boolean.TRUE); } // Advertise comet timeout support if (endpoint.getUseCometTimeout()) { request.setAttribute( org.apache.coyote.Constants.COMET_TIMEOUT_SUPPORTED_ATTR, Boolean.TRUE); } if (error) { adapter.log(request, response, 0); } } /** * Connector implementation specific request preparation. Ideally, this will * go away in the future. */ protected abstract void prepareRequestInternal(); /** * When committing the response, we have to validate the set of headers, as * well as setup the response filters. */ private void prepareResponse() { boolean entityBody = true; contentDelimitation = false; OutputFilter[] outputFilters = getOutputBuffer().getFilters(); if (http09 == true) { // HTTP/0.9 getOutputBuffer().addActiveFilter (outputFilters[Constants.IDENTITY_FILTER]); return; } int statusCode = response.getStatus(); if (statusCode < 200 || statusCode == 204 || statusCode == 205 || statusCode == 304) { // No entity body getOutputBuffer().addActiveFilter (outputFilters[Constants.VOID_FILTER]); entityBody = false; contentDelimitation = true; } MessageBytes methodMB = request.method(); if (methodMB.equals("HEAD")) { // No entity body getOutputBuffer().addActiveFilter (outputFilters[Constants.VOID_FILTER]); contentDelimitation = true; } // Sendfile support boolean sendingWithSendfile = false; if (getEndpoint().getUseSendfile()) { sendingWithSendfile = prepareSendfile(outputFilters); } // Check for compression boolean isCompressable = false; boolean useCompression = false; if (entityBody && (compressionLevel > 0) && !sendingWithSendfile) { isCompressable = isCompressable(); if (isCompressable) { useCompression = useCompression(); } // Change content-length to -1 to force chunking if (useCompression) { response.setContentLength(-1); } } MimeHeaders headers = response.getMimeHeaders(); if (!entityBody) { response.setContentLength(-1); } // A SC_NO_CONTENT response may include entity headers if (entityBody || statusCode == 204) { String contentType = response.getContentType(); if (contentType != null) { headers.setValue("Content-Type").setString(contentType); } String contentLanguage = response.getContentLanguage(); if (contentLanguage != null) { headers.setValue("Content-Language") .setString(contentLanguage); } } long contentLength = response.getContentLengthLong(); boolean connectionClosePresent = false; if (contentLength != -1) { headers.setValue("Content-Length").setLong(contentLength); getOutputBuffer().addActiveFilter (outputFilters[Constants.IDENTITY_FILTER]); contentDelimitation = true; } else { // If the response code supports an entity body and we're on // HTTP 1.1 then we chunk unless we have a Connection: close header connectionClosePresent = isConnectionClose(headers); if (entityBody && http11 && !connectionClosePresent) { getOutputBuffer().addActiveFilter (outputFilters[Constants.CHUNKED_FILTER]); contentDelimitation = true; headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); } else { getOutputBuffer().addActiveFilter (outputFilters[Constants.IDENTITY_FILTER]); } } if (useCompression) { getOutputBuffer().addActiveFilter(outputFilters[Constants.GZIP_FILTER]); headers.setValue("Content-Encoding").setString("gzip"); } // If it might be compressed, set the Vary header if (isCompressable) { // Make Proxies happy via Vary (from mod_deflate) MessageBytes vary = headers.getValue("Vary"); if (vary == null) { // Add a new Vary header headers.setValue("Vary").setString("Accept-Encoding"); } else if (vary.equals("*")) { // No action required } else { // Merge into current header headers.setValue("Vary").setString( vary.getString() + ",Accept-Encoding"); } } // Add date header unless application has already set one (e.g. in a // Caching Filter) if (headers.getValue("Date") == null) { headers.setValue("Date").setString( FastHttpDateFormat.getCurrentDate()); } // FIXME: Add transfer encoding header if ((entityBody) && (!contentDelimitation)) { // Mark as close the connection after the request, and add the // connection: close header keepAlive = false; } // If we know that the request is bad this early, add the // Connection: close header. keepAlive = keepAlive && !statusDropsConnection(statusCode); if (!keepAlive) { // Avoid adding the close header twice if (!connectionClosePresent) { headers.addValue(Constants.CONNECTION).setString( Constants.CLOSE); } } else if (!http11 && !error) { headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE); } // Build the response header getOutputBuffer().sendStatus(); // Add server header if (server != null) { // Always overrides anything the app might set headers.setValue("Server").setString(server); } else if (headers.getValue("Server") == null) { // If app didn't set the header, use the default getOutputBuffer().write(Constants.SERVER_BYTES); } int size = headers.size(); for (int i = 0; i < size; i++) { getOutputBuffer().sendHeader(headers.getName(i), headers.getValue(i)); } getOutputBuffer().endHeaders(); } private boolean isConnectionClose(MimeHeaders headers) { MessageBytes connection = headers.getValue(Constants.CONNECTION); if (connection == null) { return false; } return connection.equals(Constants.CLOSE); } abstract boolean prepareSendfile(OutputFilter[] outputFilters); /** * Parse host. */ protected void parseHost(MessageBytes valueMB) { if (valueMB == null || valueMB.isNull()) { // HTTP/1.0 // If no host header, use the port info from the endpoint // The host will be obtained lazily from the socket if required // using ActionCode#REQ_LOCAL_NAME_ATTRIBUTE request.setServerPort(endpoint.getPort()); return; } ByteChunk valueBC = valueMB.getByteChunk(); byte[] valueB = valueBC.getBytes(); int valueL = valueBC.getLength(); int valueS = valueBC.getStart(); int colonPos = -1; if (hostNameC.length < valueL) { hostNameC = new char[valueL]; } boolean ipv6 = (valueB[valueS] == '['); boolean bracketClosed = false; for (int i = 0; i < valueL; i++) { char b = (char) valueB[i + valueS]; hostNameC[i] = b; if (b == ']') { bracketClosed = true; } else if (b == ':') { if (!ipv6 || bracketClosed) { colonPos = i; break; } } } if (colonPos < 0) { if (!endpoint.isSSLEnabled()) { // 80 - Default HTTP port request.setServerPort(80); } else { // 443 - Default HTTPS port request.setServerPort(443); } request.serverName().setChars(hostNameC, 0, valueL); } else { request.serverName().setChars(hostNameC, 0, colonPos); int port = 0; int mult = 1; for (int i = valueL - 1; i > colonPos; i--) { int charValue = HexUtils.getDec(valueB[i + valueS]); if (charValue == -1 || charValue > 9) { // Invalid character error = true; // 400 - Bad request response.setStatus(400); break; } port = port + (charValue * mult); mult = 10 * mult; } request.setServerPort(port); } } @Override public SocketState asyncDispatch(SocketStatus status) { RequestInfo rp = request.getRequestProcessor(); try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); error = !adapter.asyncDispatch(request, response, status); resetTimeouts(); } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().error(sm.getString("http11processor.request.process"), t); error = true; } finally { if (error) { // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); } } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (error) { return SocketState.CLOSED; } else if (isAsync()) { return SocketState.LONG; } else { if (!keepAlive) { return SocketState.CLOSED; } else { getInputBuffer().nextRequest(); getOutputBuffer().nextRequest(); return SocketState.OPEN; } } } @Override public boolean isComet() { return comet; } @Override public SocketState upgradeDispatch() throws IOException { // Should never reach this code but in case we do... // TODO throw new IOException( sm.getString("TODO")); } /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated @Override public org.apache.coyote.http11.upgrade.UpgradeInbound getUpgradeInbound() { return upgradeInbound; } @Override public boolean isUpgrade() { return httpUpgradeHandler != null; } @Override public SocketState upgradeDispatch(SocketStatus status) throws IOException { // Should never reach this code but in case we do... throw new IOException( sm.getString("ajpprocessor.httpupgrade.notsupported")); } @Override public HttpUpgradeHandler getHttpUpgradeHandler() { return httpUpgradeHandler; } /** * Provides a mechanism for those connector implementations (currently only * NIO) that need to reset timeouts from Async timeouts to standard HTTP * timeouts once async processing completes. */ protected abstract void resetTimeouts(); /** * Provides a mechanism for those connectors (currently only NIO) that need * that need to set comet timeouts. */ protected abstract void setCometTimeouts(SocketWrapper socketWrapper); public void endRequest() { // Finish the handling of the request try { getInputBuffer().endRequest(); } catch (IOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().error(sm.getString("http11processor.request.finish"), t); // 500 - Internal Server Error // Can't add a 500 to the access log since that has already been // written in the Adapter.service method. response.setStatus(500); error = true; } try { getOutputBuffer().endRequest(); } catch (IOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().error(sm.getString("http11processor.response.finish"), t); error = true; } } /** * Checks to see if the keep-alive loop should be broken, performing any * processing (e.g. sendfile handling) that may have an impact on whether * or not the keep-alive loop should be broken. * @return true if the keep-alive loop should be broken */ protected abstract boolean breakKeepAliveLoop( SocketWrapper socketWrapper); @Override public final void recycle(boolean isSocketClosing) { if (getInputBuffer() != null) { getInputBuffer().recycle(); } if (getOutputBuffer() != null) { getOutputBuffer().recycle(); } if (asyncStateMachine != null) { asyncStateMachine.recycle(); } upgradeInbound = null; httpUpgradeHandler = null; remoteAddr = null; remoteHost = null; localAddr = null; localName = null; remotePort = -1; localPort = -1; comet = false; recycleInternal(); } protected abstract void recycleInternal(); } tomcat7-7.0.52/java/org/apache/coyote/http11/Http11Processor.java0000644000175100017510000003247012276710425024357 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.EOFException; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import org.apache.coyote.ActionCode; import org.apache.coyote.http11.filters.BufferedInputFilter; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.JIoEndpoint; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Processes HTTP requests. * * @author Remy Maucherat * @author fhanik */ public class Http11Processor extends AbstractHttp11Processor { private static final Log log = LogFactory.getLog(Http11Processor.class); @Override protected Log getLog() { return log; } // ------------------------------------------------------------ Constructor public Http11Processor(int headerBufferSize, JIoEndpoint endpoint, int maxTrailerSize, int maxExtensionSize) { super(endpoint); inputBuffer = new InternalInputBuffer(request, headerBufferSize); request.setInputBuffer(inputBuffer); outputBuffer = new InternalOutputBuffer(response, headerBufferSize); response.setOutputBuffer(outputBuffer); initializeFilters(maxTrailerSize, maxExtensionSize); } // ----------------------------------------------------- Instance Variables /** * Input. */ protected InternalInputBuffer inputBuffer = null; /** * Output. */ protected InternalOutputBuffer outputBuffer = null; /** * SSL information. */ protected SSLSupport sslSupport; /** * The percentage of threads that have to be in use before keep-alive is * disabled to aid scalability. */ private int disableKeepAlivePercentage = 75; // --------------------------------------------------------- Public Methods /** * Set the SSL information for this HTTP connection. */ @Override public void setSslSupport(SSLSupport sslSupport) { this.sslSupport = sslSupport; } public int getDisableKeepAlivePercentage() { return disableKeepAlivePercentage; } public void setDisableKeepAlivePercentage(int disableKeepAlivePercentage) { this.disableKeepAlivePercentage = disableKeepAlivePercentage; } @Override protected boolean disableKeepAlive() { int threadRatio = -1; // These may return zero or negative values // Only calculate a thread ratio when both are >0 to ensure we get a // sensible result int maxThreads, threadsBusy; if ((maxThreads = endpoint.getMaxThreads()) > 0 && (threadsBusy = endpoint.getCurrentThreadsBusy()) > 0) { threadRatio = (threadsBusy * 100) / maxThreads; } // Disable keep-alive if we are running low on threads if (threadRatio > getDisableKeepAlivePercentage()) { return true; } return false; } @Override protected void setRequestLineReadTimeout() throws IOException { /* * When there is no data in the buffer and this is not the first * request on this connection and timeouts are being used the * first read for this request may need a different timeout to * take account of time spent waiting for a processing thread. * * This is a little hacky but better than exposing the socket * and the timeout info to the InputBuffer */ if (inputBuffer.lastValid == 0 && socketWrapper.getLastAccess() > -1) { int firstReadTimeout; if (keepAliveTimeout == -1) { firstReadTimeout = 0; } else { long queueTime = System.currentTimeMillis() - socketWrapper.getLastAccess(); if (queueTime >= keepAliveTimeout) { // Queued for longer than timeout but there might be // data so use shortest possible timeout firstReadTimeout = 1; } else { // Cast is safe since queueTime must be less than // keepAliveTimeout which is an int firstReadTimeout = keepAliveTimeout - (int) queueTime; } } socketWrapper.getSocket().setSoTimeout(firstReadTimeout); if (!inputBuffer.fill()) { throw new EOFException(sm.getString("iib.eof.error")); } // Once the first byte has been read, the standard timeout should be // used so restore it here. if (endpoint.getSoTimeout()> 0) { setSocketTimeout(endpoint.getSoTimeout()); } else { setSocketTimeout(0); } } } @Override protected boolean handleIncompleteRequestLineRead() { // Not used with BIO since it uses blocking reads return false; } @Override protected void setSocketTimeout(int timeout) throws IOException { socketWrapper.getSocket().setSoTimeout(timeout); } @Override protected void setCometTimeouts(SocketWrapper socketWrapper) { // NO-OP for BIO } @Override protected boolean breakKeepAliveLoop(SocketWrapper socketWrapper) { openSocket = keepAlive; // If we don't have a pipe-lined request allow this thread to be // used by another connection if (inputBuffer.lastValid == 0) { return true; } return false; } @Override protected void resetTimeouts() { // NOOP for BIO } @Override protected void recycleInternal() { // Recycle this.socketWrapper = null; // Recycle ssl info sslSupport = null; } @Override public SocketState event(SocketStatus status) throws IOException { // Should never reach this code but in case we do... throw new IOException( sm.getString("http11processor.comet.notsupported")); } // ----------------------------------------------------- ActionHook Methods /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override public void actionInternal(ActionCode actionCode, Object param) { if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) { try { if (sslSupport != null) { Object sslO = sslSupport.getCipherSuite(); if (sslO != null) request.setAttribute (SSLSupport.CIPHER_SUITE_KEY, sslO); sslO = sslSupport.getPeerCertificateChain(false); if (sslO != null) request.setAttribute (SSLSupport.CERTIFICATE_KEY, sslO); sslO = sslSupport.getKeySize(); if (sslO != null) request.setAttribute (SSLSupport.KEY_SIZE_KEY, sslO); sslO = sslSupport.getSessionId(); if (sslO != null) request.setAttribute (SSLSupport.SESSION_ID_KEY, sslO); request.setAttribute(SSLSupport.SESSION_MGR, sslSupport); } } catch (Exception e) { log.warn(sm.getString("http11processor.socket.ssl"), e); } } else if (actionCode == ActionCode.REQ_HOST_ADDR_ATTRIBUTE) { if ((remoteAddr == null) && (socketWrapper != null)) { InetAddress inetAddr = socketWrapper.getSocket().getInetAddress(); if (inetAddr != null) { remoteAddr = inetAddr.getHostAddress(); } } request.remoteAddr().setString(remoteAddr); } else if (actionCode == ActionCode.REQ_LOCAL_NAME_ATTRIBUTE) { if ((localName == null) && (socketWrapper != null)) { InetAddress inetAddr = socketWrapper.getSocket().getLocalAddress(); if (inetAddr != null) { localName = inetAddr.getHostName(); } } request.localName().setString(localName); } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) { if ((remoteHost == null) && (socketWrapper != null)) { InetAddress inetAddr = socketWrapper.getSocket().getInetAddress(); if (inetAddr != null) { remoteHost = inetAddr.getHostName(); } if(remoteHost == null) { if(remoteAddr != null) { remoteHost = remoteAddr; } else { // all we can do is punt request.remoteHost().recycle(); } } } request.remoteHost().setString(remoteHost); } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) { if (localAddr == null) localAddr = socketWrapper.getSocket().getLocalAddress().getHostAddress(); request.localAddr().setString(localAddr); } else if (actionCode == ActionCode.REQ_REMOTEPORT_ATTRIBUTE) { if ((remotePort == -1 ) && (socketWrapper !=null)) { remotePort = socketWrapper.getSocket().getPort(); } request.setRemotePort(remotePort); } else if (actionCode == ActionCode.REQ_LOCALPORT_ATTRIBUTE) { if ((localPort == -1 ) && (socketWrapper !=null)) { localPort = socketWrapper.getSocket().getLocalPort(); } request.setLocalPort(localPort); } else if (actionCode == ActionCode.REQ_SSL_CERTIFICATE) { if( sslSupport != null) { /* * Consume and buffer the request body, so that it does not * interfere with the client's handshake messages */ InputFilter[] inputFilters = inputBuffer.getFilters(); ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) .setLimit(maxSavePostSize); inputBuffer.addActiveFilter (inputFilters[Constants.BUFFERED_FILTER]); try { Object sslO = sslSupport.getPeerCertificateChain(true); if( sslO != null) { request.setAttribute (SSLSupport.CERTIFICATE_KEY, sslO); } } catch (Exception e) { log.warn(sm.getString("http11processor.socket.ssl"), e); } } } else if (actionCode == ActionCode.ASYNC_COMPLETE) { if (asyncStateMachine.asyncComplete()) { ((JIoEndpoint) endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) { if (param == null) return; long timeout = ((Long)param).longValue(); // if we are not piggy backing on a worker thread, set the timeout socketWrapper.setTimeout(timeout); } else if (actionCode == ActionCode.ASYNC_DISPATCH) { if (asyncStateMachine.asyncDispatch()) { ((JIoEndpoint) endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } } // ------------------------------------------------------ Protected Methods @Override protected void prepareRequestInternal() { // NOOP for BIO } @Override protected boolean prepareSendfile(OutputFilter[] outputFilters) { // Should never, ever call this code Exception e = new Exception(); log.error(sm.getString("http11processor.neverused"), e); return false; } @Override protected AbstractInputBuffer getInputBuffer() { return inputBuffer; } @Override protected AbstractOutputBuffer getOutputBuffer() { return outputBuffer; } /** * Set the socket buffer flag. */ @Override public void setSocketBuffer(int socketBuffer) { super.setSocketBuffer(socketBuffer); outputBuffer.setSocketBuffer(socketBuffer); } } tomcat7-7.0.52/java/org/apache/coyote/http11/InternalInputBuffer.java0000644000175100017510000003637112271461367025333 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.nio.charset.Charset; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.SocketWrapper; /** * Implementation of InputBuffer which provides HTTP request header parsing as * well as transfer decoding. * * @author Remy Maucherat */ public class InternalInputBuffer extends AbstractInputBuffer { private static final Log log = LogFactory.getLog(InternalInputBuffer.class); /** * Underlying input stream. */ private InputStream inputStream; /** * Default constructor. */ public InternalInputBuffer(Request request, int headerBufferSize) { this.request = request; headers = request.getMimeHeaders(); buf = new byte[headerBufferSize]; inputStreamInputBuffer = new InputStreamInputBuffer(); filterLibrary = new InputFilter[0]; activeFilters = new InputFilter[0]; lastActiveFilter = -1; parsingHeader = true; swallowInput = true; } /** * Read the request line. This function is meant to be used during the * HTTP request header parsing. Do NOT attempt to read the request body * using it. * * @throws IOException If an exception occurs during the underlying socket * read operations, or if the given buffer is not big enough to accommodate * the whole line. */ @Override public boolean parseRequestLine(boolean useAvailableDataOnly) throws IOException { int start = 0; // // Skipping blank lines // byte chr = 0; do { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } chr = buf[pos++]; } while ((chr == Constants.CR) || (chr == Constants.LF)); pos--; // Mark the current buffer position start = pos; // // Reading the method name // Method name is always US-ASCII // boolean space = false; while (!space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } // Spec says no CR or LF in method name if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) { throw new IllegalArgumentException( sm.getString("iib.invalidmethod")); } // Spec says single SP but it also says be tolerant of HT if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; request.method().setBytes(buf, start, pos - start); } pos++; } // Spec says single SP but also says be tolerant of multiple and/or HT while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { pos++; } else { space = false; } } // Mark the current buffer position start = pos; int end = 0; int questionPos = -1; // // Reading the URI // boolean eol = false; while (!space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } // Spec says single SP but it also says be tolerant of HT if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; end = pos; } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) { // HTTP/0.9 style request eol = true; space = true; end = pos; } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { questionPos = pos; } pos++; } request.unparsedURI().setBytes(buf, start, end - start); if (questionPos >= 0) { request.queryString().setBytes(buf, questionPos + 1, end - questionPos - 1); request.requestURI().setBytes(buf, start, questionPos - start); } else { request.requestURI().setBytes(buf, start, end - start); } // Spec says single SP but also says be tolerant of multiple and/or HT while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { pos++; } else { space = false; } } // Mark the current buffer position start = pos; end = 0; // // Reading the protocol // Protocol is always US-ASCII // while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.CR) { end = pos; } else if (buf[pos] == Constants.LF) { if (end == 0) end = pos; eol = true; } pos++; } if ((end - start) > 0) { request.protocol().setBytes(buf, start, end - start); } else { request.protocol().setString(""); } return true; } /** * Parse the HTTP headers. */ @Override public boolean parseHeaders() throws IOException { if (!parsingHeader) { throw new IllegalStateException( sm.getString("iib.parseheaders.ise.error")); } while (parseHeader()) { // Loop until we run out of headers } parsingHeader = false; end = pos; return true; } /** * Parse an HTTP header. * * @return false after reading a blank line (which indicates that the * HTTP header parsing is done */ @SuppressWarnings("null") // headerValue cannot be null private boolean parseHeader() throws IOException { // // Check for blank line // byte chr = 0; while (true) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } chr = buf[pos]; if (chr == Constants.CR) { // Skip } else if (chr == Constants.LF) { pos++; return false; } else { break; } pos++; } // Mark the current buffer position int start = pos; // // Reading the header name // Header name is always US-ASCII // boolean colon = false; MessageBytes headerValue = null; while (!colon) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.COLON) { colon = true; headerValue = headers.addValue(buf, start, pos - start); } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { // If a non-token header is detected, skip the line and // ignore the header skipLine(start); return true; } chr = buf[pos]; if ((chr >= Constants.A) && (chr <= Constants.Z)) { buf[pos] = (byte) (chr - Constants.LC_OFFSET); } pos++; } // Mark the current buffer position start = pos; int realPos = pos; // // Reading the header value (which can be spanned over multiple lines) // boolean eol = false; boolean validLine = true; while (validLine) { boolean space = true; // Skipping spaces while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { pos++; } else { space = false; } } int lastSignificantChar = realPos; // Reading bytes until the end of the line while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.CR) { // Skip } else if (buf[pos] == Constants.LF) { eol = true; } else if (buf[pos] == Constants.SP) { buf[realPos] = buf[pos]; realPos++; } else { buf[realPos] = buf[pos]; realPos++; lastSignificantChar = realPos; } pos++; } realPos = lastSignificantChar; // Checking the first character of the new line. If the character // is a LWS, then it's a multiline header // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } chr = buf[pos]; if ((chr != Constants.SP) && (chr != Constants.HT)) { validLine = false; } else { eol = false; // Copying one extra space in the buffer (since there must // be at least one space inserted between the lines) buf[realPos] = chr; realPos++; } } // Set the header value headerValue.setBytes(buf, start, realPos - start); return true; } @Override public void recycle() { super.recycle(); inputStream = null; } // ------------------------------------------------------ Protected Methods @Override protected void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException { inputStream = socketWrapper.getSocket().getInputStream(); } private void skipLine(int start) throws IOException { boolean eol = false; int lastRealByte = start; if (pos - 1 > start) { lastRealByte = pos - 1; } while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill()) throw new EOFException(sm.getString("iib.eof.error")); } if (buf[pos] == Constants.CR) { // Skip } else if (buf[pos] == Constants.LF) { eol = true; } else { lastRealByte = pos; } pos++; } if (log.isDebugEnabled()) { log.debug(sm.getString("iib.invalidheader", new String(buf, start, lastRealByte - start + 1, Charset.forName("ISO-8859-1")))); } } /** * Fill the internal buffer using data from the underlying input stream. * * @return false if at end of stream */ protected boolean fill() throws IOException { return fill(true); } @Override protected boolean fill(boolean block) throws IOException { int nRead = 0; if (parsingHeader) { if (lastValid == buf.length) { throw new IllegalArgumentException (sm.getString("iib.requestheadertoolarge.error")); } nRead = inputStream.read(buf, pos, buf.length - lastValid); if (nRead > 0) { lastValid = pos + nRead; } } else { if (buf.length - end < 4500) { // In this case, the request header was really large, so we allocate a // brand new one; the old one will get GCed when subsequent requests // clear all references buf = new byte[buf.length]; end = 0; } pos = end; lastValid = pos; nRead = inputStream.read(buf, pos, buf.length - lastValid); if (nRead > 0) { lastValid = pos + nRead; } } return (nRead > 0); } // ------------------------------------- InputStreamInputBuffer Inner Class /** * This class is an input buffer which will read its data from an input * stream. */ protected class InputStreamInputBuffer implements InputBuffer { /** * Read bytes into the specified chunk. */ @Override public int doRead(ByteChunk chunk, Request req ) throws IOException { if (pos >= lastValid) { if (!fill()) return -1; } int length = lastValid - pos; chunk.setBytes(buf, pos, length); pos = lastValid; return (length); } } } tomcat7-7.0.52/java/org/apache/coyote/http11/LocalStrings_fr.properties0000644000175100017510000000316412271461367025745 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. http11protocol.endpoint.starterror=Erreur au d\u00e9marrage du point de contact http11protocol.proto.error=Erreur \u00e0 la lecture de la requ\u00eate, ignor\u00e9 http11protocol.proto.ioexception.debug=Exception d'entr\u00e9e/sortie (IOException) \u00e0 la lecture de la requ\u00eate http11protocol.proto.ioexception.info=Exception d'entr\u00e9e/sortie \u00e0 la lecture de la requ\u00eate, ignor\u00e9 http11protocol.proto.socketexception.debug=Exception "Socket" (SocketException) \u00e0 la lecture de la requ\u00eate http11protocol.proto.socketexception.info=Exception "Socket" (SocketException) \u00e0 la lecture de la requ\u00eate, ignor\u00e9 http11protocol.start=D\u00e9marrage de Coyote HTTP/1.1 sur {0} iib.eof.error=Fin de flux (EOF) inattendue \u00e0 la lecture sur la socket iib.requestheadertoolarge.error=L'ent\u00eate de requ\u00eate est trop important tomcat7-7.0.52/java/org/apache/coyote/http11/Http11AprProtocol.java0000644000175100017510000003272612271461367024653 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.coyote.http11.upgrade.AprProcessor; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.AprEndpoint.Handler; import org.apache.tomcat.util.net.AprEndpoint.Poller; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Abstract the protocol implementation, including threading, etc. * Processor is single threaded and specific to stream-based protocols, * will not fit Jk protocols like JNI. * * @author Remy Maucherat * @author Costin Manolache */ public class Http11AprProtocol extends AbstractHttp11Protocol { private static final Log log = LogFactory.getLog(Http11AprProtocol.class); @Override protected Log getLog() { return log; } @Override protected AbstractEndpoint.Handler getHandler() { return cHandler; } @Override public boolean isAprRequired() { // Override since this protocol implementation requires the APR/native // library return true; } public Http11AprProtocol() { endpoint = new AprEndpoint(); cHandler = new Http11ConnectionHandler(this); ((AprEndpoint) endpoint).setHandler(cHandler); setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); } private final Http11ConnectionHandler cHandler; public boolean getUseSendfile() { return ((AprEndpoint)endpoint).getUseSendfile(); } public void setUseSendfile(boolean useSendfile) { ((AprEndpoint)endpoint).setUseSendfile(useSendfile); } public int getPollTime() { return ((AprEndpoint)endpoint).getPollTime(); } public void setPollTime(int pollTime) { ((AprEndpoint)endpoint).setPollTime(pollTime); } public void setPollerSize(int pollerSize) { endpoint.setMaxConnections(pollerSize); } public int getPollerSize() { return endpoint.getMaxConnections(); } public int getSendfileSize() { return ((AprEndpoint)endpoint).getSendfileSize(); } public void setSendfileSize(int sendfileSize) { ((AprEndpoint)endpoint).setSendfileSize(sendfileSize); } public void setSendfileThreadCount(int sendfileThreadCount) { ((AprEndpoint)endpoint).setSendfileThreadCount(sendfileThreadCount); } public int getSendfileThreadCount() { return ((AprEndpoint)endpoint).getSendfileThreadCount(); } public boolean getDeferAccept() { return ((AprEndpoint)endpoint).getDeferAccept(); } public void setDeferAccept(boolean deferAccept) { ((AprEndpoint)endpoint).setDeferAccept(deferAccept); } // -------------------- SSL related properties -------------------- /** * SSL protocol. */ public String getSSLProtocol() { return ((AprEndpoint)endpoint).getSSLProtocol(); } public void setSSLProtocol(String SSLProtocol) { ((AprEndpoint)endpoint).setSSLProtocol(SSLProtocol); } /** * SSL password (if a cert is encrypted, and no password has been provided, a callback * will ask for a password). */ public String getSSLPassword() { return ((AprEndpoint)endpoint).getSSLPassword(); } public void setSSLPassword(String SSLPassword) { ((AprEndpoint)endpoint).setSSLPassword(SSLPassword); } /** * SSL cipher suite. */ public String getSSLCipherSuite() { return ((AprEndpoint)endpoint).getSSLCipherSuite(); } public void setSSLCipherSuite(String SSLCipherSuite) { ((AprEndpoint)endpoint).setSSLCipherSuite(SSLCipherSuite); } /** * SSL honor cipher order. * * Set to true to enforce the server's cipher order * instead of the default which is to allow the client to choose a * preferred cipher. */ public boolean getSSLHonorCipherOrder() { return ((AprEndpoint)endpoint).getSSLHonorCipherOrder(); } public void setSSLHonorCipherOrder(boolean SSLHonorCipherOrder) { ((AprEndpoint)endpoint).setSSLHonorCipherOrder(SSLHonorCipherOrder); } /** * SSL certificate file. */ public String getSSLCertificateFile() { return ((AprEndpoint)endpoint).getSSLCertificateFile(); } public void setSSLCertificateFile(String SSLCertificateFile) { ((AprEndpoint)endpoint).setSSLCertificateFile(SSLCertificateFile); } /** * SSL certificate key file. */ public String getSSLCertificateKeyFile() { return ((AprEndpoint)endpoint).getSSLCertificateKeyFile(); } public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ((AprEndpoint)endpoint).setSSLCertificateKeyFile(SSLCertificateKeyFile); } /** * SSL certificate chain file. */ public String getSSLCertificateChainFile() { return ((AprEndpoint)endpoint).getSSLCertificateChainFile(); } public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ((AprEndpoint)endpoint).setSSLCertificateChainFile(SSLCertificateChainFile); } /** * SSL CA certificate path. */ public String getSSLCACertificatePath() { return ((AprEndpoint)endpoint).getSSLCACertificatePath(); } public void setSSLCACertificatePath(String SSLCACertificatePath) { ((AprEndpoint)endpoint).setSSLCACertificatePath(SSLCACertificatePath); } /** * SSL CA certificate file. */ public String getSSLCACertificateFile() { return ((AprEndpoint)endpoint).getSSLCACertificateFile(); } public void setSSLCACertificateFile(String SSLCACertificateFile) { ((AprEndpoint)endpoint).setSSLCACertificateFile(SSLCACertificateFile); } /** * SSL CA revocation path. */ public String getSSLCARevocationPath() { return ((AprEndpoint)endpoint).getSSLCARevocationPath(); } public void setSSLCARevocationPath(String SSLCARevocationPath) { ((AprEndpoint)endpoint).setSSLCARevocationPath(SSLCARevocationPath); } /** * SSL CA revocation file. */ public String getSSLCARevocationFile() { return ((AprEndpoint)endpoint).getSSLCARevocationFile(); } public void setSSLCARevocationFile(String SSLCARevocationFile) { ((AprEndpoint)endpoint).setSSLCARevocationFile(SSLCARevocationFile); } /** * SSL verify client. */ public String getSSLVerifyClient() { return ((AprEndpoint)endpoint).getSSLVerifyClient(); } public void setSSLVerifyClient(String SSLVerifyClient) { ((AprEndpoint)endpoint).setSSLVerifyClient(SSLVerifyClient); } /** * SSL verify depth. */ public int getSSLVerifyDepth() { return ((AprEndpoint)endpoint).getSSLVerifyDepth(); } public void setSSLVerifyDepth(int SSLVerifyDepth) { ((AprEndpoint)endpoint).setSSLVerifyDepth(SSLVerifyDepth); } /** * Disable SSL compression. */ public boolean getSSLDisableCompression() { return ((AprEndpoint)endpoint).getSSLDisableCompression(); } public void setSSLDisableCompression(boolean disable) { ((AprEndpoint)endpoint).setSSLDisableCompression(disable); } // ----------------------------------------------------- JMX related methods @Override protected String getNamePrefix() { return ("http-apr"); } // -------------------- Connection handler -------------------- protected static class Http11ConnectionHandler extends AbstractConnectionHandler implements Handler { protected Http11AprProtocol proto; Http11ConnectionHandler(Http11AprProtocol proto) { this.proto = proto; } @Override protected AbstractProtocol getProtocol() { return proto; } @Override protected Log getLog() { return log; } @Override public void recycle() { recycledProcessors.clear(); } /** * Expected to be used by the handler once the processor is no longer * required. * * @param socket * @param processor * @param isSocketClosing Not used in HTTP * @param addToPoller */ @Override public void release(SocketWrapper socket, Processor processor, boolean isSocketClosing, boolean addToPoller) { processor.recycle(isSocketClosing); recycledProcessors.offer(processor); if (addToPoller && proto.endpoint.isRunning()) { ((AprEndpoint)proto.endpoint).getPoller().add( socket.getSocket().longValue(), proto.endpoint.getKeepAliveTimeout(), true, false); } } @Override protected void initSsl(SocketWrapper socket, Processor processor) { // NOOP for APR } @SuppressWarnings("deprecation") // Inbound/Outbound based upgrade @Override protected void longPoll(SocketWrapper socket, Processor processor) { if (processor.isAsync()) { // Async socket.setAsync(true); } else if (processor.isComet()) { // Comet if (proto.endpoint.isRunning()) { socket.setComet(true); ((AprEndpoint) proto.endpoint).getPoller().add( socket.getSocket().longValue(), proto.endpoint.getSoTimeout(), true, false); } else { // Process a STOP directly ((AprEndpoint) proto.endpoint).processSocket( socket.getSocket().longValue(), SocketStatus.STOP); } } else if (processor.isUpgrade()) { // Upgraded Poller p = ((AprEndpoint) proto.endpoint).getPoller(); if (p == null) { // Connector has been stopped release(socket, processor, true, false); } else { p.add(socket.getSocket().longValue(), -1, true, false); } } else { // Tomcat 7 proprietary upgrade ((AprEndpoint) proto.endpoint).getPoller().add( socket.getSocket().longValue(), processor.getUpgradeInbound().getReadTimeout(), true, false); } } @Override protected Http11AprProcessor createProcessor() { Http11AprProcessor processor = new Http11AprProcessor( proto.getMaxHttpHeaderSize(), (AprEndpoint)proto.endpoint, proto.getMaxTrailerSize(), proto.getMaxExtensionSize()); processor.setAdapter(proto.adapter); processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests()); processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); processor.setConnectionUploadTimeout( proto.getConnectionUploadTimeout()); processor.setDisableUploadTimeout(proto.getDisableUploadTimeout()); processor.setCompressionMinSize(proto.getCompressionMinSize()); processor.setCompression(proto.getCompression()); processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents()); processor.setCompressableMimeTypes(proto.getCompressableMimeTypes()); processor.setRestrictedUserAgents(proto.getRestrictedUserAgents()); processor.setSocketBuffer(proto.getSocketBuffer()); processor.setMaxSavePostSize(proto.getMaxSavePostSize()); processor.setServer(proto.getServer()); processor.setClientCertProvider(proto.getClientCertProvider()); register(processor); return processor; } /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated @Override protected Processor createUpgradeProcessor( SocketWrapper socket, org.apache.coyote.http11.upgrade.UpgradeInbound inbound) throws IOException { return new org.apache.coyote.http11.upgrade.UpgradeAprProcessor( socket, inbound); } @Override protected Processor createUpgradeProcessor( SocketWrapper socket, HttpUpgradeHandler httpUpgradeProcessor) throws IOException { return new AprProcessor(socket, httpUpgradeProcessor, (AprEndpoint) proto.endpoint); } } } tomcat7-7.0.52/java/org/apache/coyote/http11/InternalNioInputBuffer.java0000644000175100017510000007130612271461367025776 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.EOFException; import java.io.IOException; import java.nio.channels.Selector; import java.nio.charset.Charset; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioSelectorPool; import org.apache.tomcat.util.net.SocketWrapper; /** * Implementation of InputBuffer which provides HTTP request header parsing as * well as transfer decoding. * * @author Remy Maucherat * @author Filip Hanik */ public class InternalNioInputBuffer extends AbstractInputBuffer { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(InternalNioInputBuffer.class); private static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); // -------------------------------------------------------------- Constants enum HeaderParseStatus { DONE, HAVE_MORE_HEADERS, NEED_MORE_DATA } enum HeaderParsePosition { /** * Start of a new header. A CRLF here means that there are no more * headers. Any other character starts a header name. */ HEADER_START, /** * Reading a header name. All characters of header are HTTP_TOKEN_CHAR. * Header name is followed by ':'. No whitespace is allowed.
    * Any non-HTTP_TOKEN_CHAR (this includes any whitespace) encountered * before ':' will result in the whole line being ignored. */ HEADER_NAME, /** * Skipping whitespace before text of header value starts, either on the * first line of header value (just after ':') or on subsequent lines * when it is known that subsequent line starts with SP or HT. */ HEADER_VALUE_START, /** * Reading the header value. We are inside the value. Either on the * first line or on any subsequent line. We come into this state from * HEADER_VALUE_START after the first non-SP/non-HT byte is encountered * on the line. */ HEADER_VALUE, /** * Before reading a new line of a header. Once the next byte is peeked, * the state changes without advancing our position. The state becomes * either HEADER_VALUE_START (if that first byte is SP or HT), or * HEADER_START (otherwise). */ HEADER_MULTI_LINE, /** * Reading all bytes until the next CRLF. The line is being ignored. */ HEADER_SKIPLINE } // ----------------------------------------------------------- Constructors /** * Alternate constructor. */ public InternalNioInputBuffer(Request request, int headerBufferSize) { this.request = request; headers = request.getMimeHeaders(); this.headerBufferSize = headerBufferSize; inputStreamInputBuffer = new SocketInputBuffer(); filterLibrary = new InputFilter[0]; activeFilters = new InputFilter[0]; lastActiveFilter = -1; parsingHeader = true; parsingRequestLine = true; parsingRequestLinePhase = 0; parsingRequestLineEol = false; parsingRequestLineStart = 0; parsingRequestLineQPos = -1; headerParsePos = HeaderParsePosition.HEADER_START; headerData.recycle(); swallowInput = true; } /** * Parsing state - used for non blocking parsing so that * when more data arrives, we can pick up where we left off. */ private boolean parsingRequestLine; private int parsingRequestLinePhase = 0; private boolean parsingRequestLineEol = false; private int parsingRequestLineStart = 0; private int parsingRequestLineQPos = -1; private HeaderParsePosition headerParsePos; /** * Underlying socket. */ private NioChannel socket; /** * Selector pool, for blocking reads and blocking writes */ private NioSelectorPool pool; /** * Maximum allowed size of the HTTP request line plus headers plus any * leading blank lines. */ private final int headerBufferSize; /** * Known size of the NioChannel read buffer. */ private int socketReadBufferSize; // --------------------------------------------------------- Public Methods /** * Recycle the input buffer. This should be called when closing the * connection. */ @Override public void recycle() { super.recycle(); socket = null; headerParsePos = HeaderParsePosition.HEADER_START; parsingRequestLine = true; parsingRequestLinePhase = 0; parsingRequestLineEol = false; parsingRequestLineStart = 0; parsingRequestLineQPos = -1; headerData.recycle(); } /** * End processing of current HTTP request. * Note: All bytes of the current request should have been already * consumed. This method only resets all the pointers so that we are ready * to parse the next HTTP request. */ @Override public void nextRequest() { super.nextRequest(); headerParsePos = HeaderParsePosition.HEADER_START; parsingRequestLine = true; parsingRequestLinePhase = 0; parsingRequestLineEol = false; parsingRequestLineStart = 0; parsingRequestLineQPos = -1; headerData.recycle(); } /** * Read the request line. This function is meant to be used during the * HTTP request header parsing. Do NOT attempt to read the request body * using it. * * @throws IOException If an exception occurs during the underlying socket * read operations, or if the given buffer is not big enough to accommodate * the whole line. * @return true if data is properly fed; false if no data is available * immediately and thread should be freed */ @Override public boolean parseRequestLine(boolean useAvailableDataOnly) throws IOException { //check state if ( !parsingRequestLine ) return true; // // Skipping blank lines // if ( parsingRequestLinePhase == 0 ) { byte chr = 0; do { // Read new bytes if needed if (pos >= lastValid) { if (useAvailableDataOnly) { return false; } // Do a simple read with a short timeout if (!fill(true, false)) { return false; } } chr = buf[pos++]; } while ((chr == Constants.CR) || (chr == Constants.LF)); pos--; parsingRequestLineStart = pos; parsingRequestLinePhase = 2; if (log.isDebugEnabled()) { log.debug("Received [" + new String(buf, pos, lastValid - pos, DEFAULT_CHARSET) + "]"); } } if ( parsingRequestLinePhase == 2 ) { // // Reading the method name // Method name is always US-ASCII // boolean space = false; while (!space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true, false)) //request line parsing return false; } // Spec says no CR or LF in method name if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) { throw new IllegalArgumentException( sm.getString("iib.invalidmethod")); } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; request.method().setBytes(buf, parsingRequestLineStart, pos - parsingRequestLineStart); } pos++; } parsingRequestLinePhase = 3; } if ( parsingRequestLinePhase == 3 ) { // Spec says single SP but also be tolerant of multiple and/or HT boolean space = true; while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true, false)) //request line parsing return false; } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { pos++; } else { space = false; } } parsingRequestLineStart = pos; parsingRequestLinePhase = 4; } if (parsingRequestLinePhase == 4) { // Mark the current buffer position int end = 0; // // Reading the URI // boolean space = false; while (!space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true,false)) //request line parsing return false; } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { space = true; end = pos; } else if ((buf[pos] == Constants.CR) || (buf[pos] == Constants.LF)) { // HTTP/0.9 style request parsingRequestLineEol = true; space = true; end = pos; } else if ((buf[pos] == Constants.QUESTION) && (parsingRequestLineQPos == -1)) { parsingRequestLineQPos = pos; } pos++; } request.unparsedURI().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart); if (parsingRequestLineQPos >= 0) { request.queryString().setBytes(buf, parsingRequestLineQPos + 1, end - parsingRequestLineQPos - 1); request.requestURI().setBytes(buf, parsingRequestLineStart, parsingRequestLineQPos - parsingRequestLineStart); } else { request.requestURI().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart); } parsingRequestLinePhase = 5; } if ( parsingRequestLinePhase == 5 ) { // Spec says single SP but also be tolerant of multiple and/or HT boolean space = true; while (space) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true, false)) //request line parsing return false; } if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { pos++; } else { space = false; } } parsingRequestLineStart = pos; parsingRequestLinePhase = 6; // Mark the current buffer position end = 0; } if (parsingRequestLinePhase == 6) { // // Reading the protocol // Protocol is always US-ASCII // while (!parsingRequestLineEol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true, false)) //request line parsing return false; } if (buf[pos] == Constants.CR) { end = pos; } else if (buf[pos] == Constants.LF) { if (end == 0) end = pos; parsingRequestLineEol = true; } pos++; } if ( (end - parsingRequestLineStart) > 0) { request.protocol().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart); } else { request.protocol().setString(""); } parsingRequestLine = false; parsingRequestLinePhase = 0; parsingRequestLineEol = false; parsingRequestLineStart = 0; return true; } throw new IllegalStateException("Invalid request line parse phase:"+parsingRequestLinePhase); } private void expand(int newsize) { if ( newsize > buf.length ) { if (parsingHeader) { throw new IllegalArgumentException( sm.getString("iib.requestheadertoolarge.error")); } // Should not happen log.warn("Expanding buffer size. Old size: " + buf.length + ", new size: " + newsize, new Exception()); byte[] tmp = new byte[newsize]; System.arraycopy(buf,0,tmp,0,buf.length); buf = tmp; } } /** * Perform blocking read with a timeout if desired * @param timeout boolean - if we want to use the timeout data * @param block - true if the system should perform a blocking read, false otherwise * @return boolean - true if data was read, false is no data read, EOFException if EOF is reached * @throws IOException if a socket exception occurs * @throws EOFException if end of stream is reached */ private int readSocket(boolean timeout, boolean block) throws IOException { int nRead = 0; socket.getBufHandler().getReadBuffer().clear(); if ( block ) { Selector selector = null; try { selector = pool.get(); } catch ( IOException x ) { // Ignore } try { NioEndpoint.KeyAttachment att = (NioEndpoint.KeyAttachment) socket.getAttachment(false); if (att == null) { throw new IOException("Key must be cancelled."); } nRead = pool.read(socket.getBufHandler().getReadBuffer(), socket, selector, socket.getIOChannel().socket().getSoTimeout()); } catch ( EOFException eof ) { nRead = -1; } finally { if ( selector != null ) pool.put(selector); } } else { nRead = socket.read(socket.getBufHandler().getReadBuffer()); } if (nRead > 0) { socket.getBufHandler().getReadBuffer().flip(); socket.getBufHandler().getReadBuffer().limit(nRead); expand(nRead + pos); socket.getBufHandler().getReadBuffer().get(buf, pos, nRead); lastValid = pos + nRead; return nRead; } else if (nRead == -1) { //return false; throw new EOFException(sm.getString("iib.eof.error")); } else { return 0; } } /** * Parse the HTTP headers. */ @Override public boolean parseHeaders() throws IOException { if (!parsingHeader) { throw new IllegalStateException( sm.getString("iib.parseheaders.ise.error")); } HeaderParseStatus status = HeaderParseStatus.HAVE_MORE_HEADERS; do { status = parseHeader(); // Checking that // (1) Headers plus request line size does not exceed its limit // (2) There are enough bytes to avoid expanding the buffer when // reading body // Technically, (2) is technical limitation, (1) is logical // limitation to enforce the meaning of headerBufferSize // From the way how buf is allocated and how blank lines are being // read, it should be enough to check (1) only. if (pos > headerBufferSize || buf.length - pos < socketReadBufferSize) { throw new IllegalArgumentException( sm.getString("iib.requestheadertoolarge.error")); } } while ( status == HeaderParseStatus.HAVE_MORE_HEADERS ); if (status == HeaderParseStatus.DONE) { parsingHeader = false; end = pos; return true; } else { return false; } } /** * Parse an HTTP header. * * @return false after reading a blank line (which indicates that the * HTTP header parsing is done */ private HeaderParseStatus parseHeader() throws IOException { // // Check for blank line // byte chr = 0; while (headerParsePos == HeaderParsePosition.HEADER_START) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true,false)) {//parse header headerParsePos = HeaderParsePosition.HEADER_START; return HeaderParseStatus.NEED_MORE_DATA; } } chr = buf[pos]; if (chr == Constants.CR) { // Skip } else if (chr == Constants.LF) { pos++; return HeaderParseStatus.DONE; } else { break; } pos++; } if ( headerParsePos == HeaderParsePosition.HEADER_START ) { // Mark the current buffer position headerData.start = pos; headerParsePos = HeaderParsePosition.HEADER_NAME; } // // Reading the header name // Header name is always US-ASCII // while (headerParsePos == HeaderParsePosition.HEADER_NAME) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true,false)) { //parse header return HeaderParseStatus.NEED_MORE_DATA; } } chr = buf[pos]; if (chr == Constants.COLON) { headerParsePos = HeaderParsePosition.HEADER_VALUE_START; headerData.headerValue = headers.addValue(buf, headerData.start, pos - headerData.start); pos++; // Mark the current buffer position headerData.start = pos; headerData.realPos = pos; headerData.lastSignificantChar = pos; break; } else if (!HTTP_TOKEN_CHAR[chr]) { // If a non-token header is detected, skip the line and // ignore the header headerData.lastSignificantChar = pos; return skipLine(); } // chr is next byte of header name. Convert to lowercase. if ((chr >= Constants.A) && (chr <= Constants.Z)) { buf[pos] = (byte) (chr - Constants.LC_OFFSET); } pos++; } // Skip the line and ignore the header if (headerParsePos == HeaderParsePosition.HEADER_SKIPLINE) { return skipLine(); } // // Reading the header value (which can be spanned over multiple lines) // while (headerParsePos == HeaderParsePosition.HEADER_VALUE_START || headerParsePos == HeaderParsePosition.HEADER_VALUE || headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE) { if ( headerParsePos == HeaderParsePosition.HEADER_VALUE_START ) { // Skipping spaces while (true) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true,false)) {//parse header //HEADER_VALUE_START return HeaderParseStatus.NEED_MORE_DATA; } } chr = buf[pos]; if (chr == Constants.SP || chr == Constants.HT) { pos++; } else { headerParsePos = HeaderParsePosition.HEADER_VALUE; break; } } } if ( headerParsePos == HeaderParsePosition.HEADER_VALUE ) { // Reading bytes until the end of the line boolean eol = false; while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true,false)) {//parse header //HEADER_VALUE return HeaderParseStatus.NEED_MORE_DATA; } } chr = buf[pos]; if (chr == Constants.CR) { // Skip } else if (chr == Constants.LF) { eol = true; } else if (chr == Constants.SP || chr == Constants.HT) { buf[headerData.realPos] = chr; headerData.realPos++; } else { buf[headerData.realPos] = chr; headerData.realPos++; headerData.lastSignificantChar = headerData.realPos; } pos++; } // Ignore whitespaces at the end of the line headerData.realPos = headerData.lastSignificantChar; // Checking the first character of the new line. If the character // is a LWS, then it's a multiline header headerParsePos = HeaderParsePosition.HEADER_MULTI_LINE; } // Read new bytes if needed if (pos >= lastValid) { if (!fill(true,false)) {//parse header //HEADER_MULTI_LINE return HeaderParseStatus.NEED_MORE_DATA; } } chr = buf[pos]; if ( headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE ) { if ( (chr != Constants.SP) && (chr != Constants.HT)) { headerParsePos = HeaderParsePosition.HEADER_START; break; } else { // Copying one extra space in the buffer (since there must // be at least one space inserted between the lines) buf[headerData.realPos] = chr; headerData.realPos++; headerParsePos = HeaderParsePosition.HEADER_VALUE_START; } } } // Set the header value headerData.headerValue.setBytes(buf, headerData.start, headerData.lastSignificantChar - headerData.start); headerData.recycle(); return HeaderParseStatus.HAVE_MORE_HEADERS; } public int getParsingRequestLinePhase() { return parsingRequestLinePhase; } private HeaderParseStatus skipLine() throws IOException { headerParsePos = HeaderParsePosition.HEADER_SKIPLINE; boolean eol = false; // Reading bytes until the end of the line while (!eol) { // Read new bytes if needed if (pos >= lastValid) { if (!fill(true,false)) { return HeaderParseStatus.NEED_MORE_DATA; } } if (buf[pos] == Constants.CR) { // Skip } else if (buf[pos] == Constants.LF) { eol = true; } else { headerData.lastSignificantChar = pos; } pos++; } if (log.isDebugEnabled()) { log.debug(sm.getString("iib.invalidheader", new String(buf, headerData.start, headerData.lastSignificantChar - headerData.start + 1, DEFAULT_CHARSET))); } headerParsePos = HeaderParsePosition.HEADER_START; return HeaderParseStatus.HAVE_MORE_HEADERS; } private HeaderParseData headerData = new HeaderParseData(); public static class HeaderParseData { /** * When parsing header name: first character of the header.
    * When skipping broken header line: first character of the header.
    * When parsing header value: first character after ':'. */ int start = 0; /** * When parsing header name: not used (stays as 0).
    * When skipping broken header line: not used (stays as 0).
    * When parsing header value: starts as the first character after ':'. * Then is increased as far as more bytes of the header are harvested. * Bytes from buf[pos] are copied to buf[realPos]. Thus the string from * [start] to [realPos-1] is the prepared value of the header, with * whitespaces removed as needed.
    */ int realPos = 0; /** * When parsing header name: not used (stays as 0).
    * When skipping broken header line: last non-CR/non-LF character.
    * When parsing header value: position after the last not-LWS character.
    */ int lastSignificantChar = 0; /** * MB that will store the value of the header. It is null while parsing * header name and is created after the name has been parsed. */ MessageBytes headerValue = null; public void recycle() { start = 0; realPos = 0; lastSignificantChar = 0; headerValue = null; } } // ------------------------------------------------------ Protected Methods @Override protected void init(SocketWrapper socketWrapper, AbstractEndpoint endpoint) throws IOException { socket = socketWrapper.getSocket(); socketReadBufferSize = socket.getBufHandler().getReadBuffer().capacity(); int bufLength = headerBufferSize + socketReadBufferSize; if (buf == null || buf.length < bufLength) { buf = new byte[bufLength]; } pool = ((NioEndpoint)endpoint).getSelectorPool(); } /** * Fill the internal buffer using data from the underlying input stream. * * @return false if at end of stream */ @Override protected boolean fill(boolean block) throws IOException, EOFException { return fill(true,block); } protected boolean fill(boolean timeout, boolean block) throws IOException, EOFException { boolean read = false; if (parsingHeader) { if (lastValid > headerBufferSize) { throw new IllegalArgumentException (sm.getString("iib.requestheadertoolarge.error")); } // Do a simple read with a short timeout read = readSocket(timeout,block)>0; } else { lastValid = pos = end; // Do a simple read with a short timeout read = readSocket(timeout, block)>0; } return read; } // ------------------------------------- InputStreamInputBuffer Inner Class /** * This class is an input buffer which will read its data from an input * stream. */ protected class SocketInputBuffer implements InputBuffer { /** * Read bytes into the specified chunk. */ @Override public int doRead(ByteChunk chunk, Request req ) throws IOException { if (pos >= lastValid) { if (!fill(true,true)) //read body, must be blocking, as the thread is inside the app return -1; } int length = lastValid - pos; chunk.setBytes(buf, pos, length); pos = lastValid; return (length); } } } tomcat7-7.0.52/java/org/apache/coyote/http11/InputFilter.java0000644000175100017510000000455212271461367023646 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.IOException; import org.apache.coyote.InputBuffer; import org.apache.coyote.Request; import org.apache.tomcat.util.buf.ByteChunk; /** * Input filter interface. * * @author Remy Maucherat */ public interface InputFilter extends InputBuffer { /** * Read bytes. * * @return Number of bytes read. */ @Override public int doRead(ByteChunk chunk, Request unused) throws IOException; /** * Some filters need additional parameters from the request. All the * necessary reading can occur in that method, as this method is called * after the request header processing is complete. */ public void setRequest(Request request); /** * Make the filter ready to process the next request. */ public void recycle(); /** * Get the name of the encoding handled by this filter. */ public ByteChunk getEncodingName(); /** * Set the next buffer in the filter pipeline. */ public void setBuffer(InputBuffer buffer); /** * End the current request. * * @return 0 is the expected return value. A positive value indicates that * too many bytes were read. This method is allowed to use buffer.doRead * to consume extra bytes. The result of this method can't be negative (if * an error happens, an IOException should be thrown instead). */ public long end() throws IOException; /** * Amount of bytes still available in a buffer. */ public int available(); } tomcat7-7.0.52/java/org/apache/coyote/http11/Http11AprProcessor.java0000644000175100017510000004665512276710425025034 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote.http11; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import org.apache.coyote.ActionCode; import org.apache.coyote.RequestInfo; import org.apache.coyote.http11.filters.BufferedInputFilter; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.Address; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLSocket; import org.apache.tomcat.jni.Sockaddr; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; /** * Processes HTTP requests. * * @author Remy Maucherat */ public class Http11AprProcessor extends AbstractHttp11Processor { private static final Log log = LogFactory.getLog(Http11AprProcessor.class); @Override protected Log getLog() { return log; } // ----------------------------------------------------------- Constructors public Http11AprProcessor(int headerBufferSize, AprEndpoint endpoint, int maxTrailerSize, int maxExtensionSize) { super(endpoint); inputBuffer = new InternalAprInputBuffer(request, headerBufferSize); request.setInputBuffer(inputBuffer); outputBuffer = new InternalAprOutputBuffer(response, headerBufferSize); response.setOutputBuffer(outputBuffer); initializeFilters(maxTrailerSize, maxExtensionSize); } // ----------------------------------------------------- Instance Variables /** * Input. */ protected InternalAprInputBuffer inputBuffer = null; /** * Output. */ protected InternalAprOutputBuffer outputBuffer = null; /** * Sendfile data. */ protected AprEndpoint.SendfileData sendfileData = null; /** * When client certificate information is presented in a form other than * instances of {@link java.security.cert.X509Certificate} it needs to be * converted before it can be used and this property controls which JSSE * provider is used to perform the conversion. For example it is used with * the AJP connectors, the HTTP APR connector and with the * {@link org.apache.catalina.valves.SSLValve}. If not specified, the * default provider will be used. */ protected String clientCertProvider = null; public String getClientCertProvider() { return clientCertProvider; } public void setClientCertProvider(String s) { this.clientCertProvider = s; } // --------------------------------------------------------- Public Methods /** * Process pipelined HTTP requests using the specified input and output * streams. * * @throws IOException error during an I/O operation */ @Override public SocketState event(SocketStatus status) throws IOException { RequestInfo rp = request.getRequestProcessor(); try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); error = !adapter.event(request, response, status); } catch (InterruptedIOException e) { error = true; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("http11processor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); adapter.log(request, response, 0); error = true; } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (error || status==SocketStatus.STOP) { return SocketState.CLOSED; } else if (!comet) { inputBuffer.nextRequest(); outputBuffer.nextRequest(); return SocketState.OPEN; } else { return SocketState.LONG; } } @Override protected boolean disableKeepAlive() { return false; } @Override protected void setRequestLineReadTimeout() throws IOException { // Timeouts while in the poller are handled entirely by the poller // Only need to be concerned with socket timeouts // APR uses simulated blocking so if some request line data is present // then it must all be presented (with the normal socket timeout). // When entering the processing loop for the first time there will // always be some data to read so the keep-alive timeout is not required // For the second and subsequent executions of the processing loop, if // there is no request line data present then no further data will be // read from the socket. If there is request line data present then it // must all be presented (with the normal socket timeout) // When the socket is created it is given the correct timeout. // sendfile may change the timeout but will restore it // This processor may change the timeout for uploads but will restore it // NO-OP } @Override protected boolean handleIncompleteRequestLineRead() { // This means that no data is available right now // (long keepalive), so that the processor should be recycled // and the method should return true openSocket = true; if (endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); adapter.log(request, response, 0); error = true; } else { return true; } return false; } @Override protected void setSocketTimeout(int timeout) { Socket.timeoutSet(socketWrapper.getSocket().longValue(), timeout * 1000); } @Override protected void setCometTimeouts(SocketWrapper socketWrapper) { // NO-OP for APR/native } @Override protected boolean breakKeepAliveLoop(SocketWrapper socketWrapper) { openSocket = keepAlive; // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !error) { sendfileData.socket = socketWrapper.getSocket().longValue(); sendfileData.keepAlive = keepAlive; if (!((AprEndpoint)endpoint).getSendfile().add(sendfileData)) { // Didn't send all of the data to sendfile. if (sendfileData.socket == 0) { // The socket is no longer set. Something went wrong. // Close the connection. Too late to set status code. if (log.isDebugEnabled()) { log.debug(sm.getString( "http11processor.sendfile.error")); } error = true; } else { // The sendfile Poller will add the socket to the main // Poller once sendfile processing is complete sendfileInProgress = true; } return true; } } return false; } @Override protected void resetTimeouts() { // NOOP for APR } @Override public void recycleInternal() { socketWrapper = null; sendfileData = null; } @Override public void setSslSupport(SSLSupport sslSupport) { // NOOP for APR } // ----------------------------------------------------- ActionHook Methods /** * Send an action to the connector. * * @param actionCode Type of the action * @param param Action parameter */ @Override public void actionInternal(ActionCode actionCode, Object param) { long socketRef = socketWrapper.getSocket().longValue(); if (actionCode == ActionCode.REQ_HOST_ADDR_ATTRIBUTE) { // Get remote host address if (remoteAddr == null && (socketRef != 0)) { try { long sa = Address.get(Socket.APR_REMOTE, socketRef); remoteAddr = Address.getip(sa); } catch (Exception e) { log.warn(sm.getString("http11processor.socket.info"), e); } } request.remoteAddr().setString(remoteAddr); } else if (actionCode == ActionCode.REQ_LOCAL_NAME_ATTRIBUTE) { // Get local host name if (localName == null && (socketRef != 0)) { try { long sa = Address.get(Socket.APR_LOCAL, socketRef); localName = Address.getnameinfo(sa, 0); } catch (Exception e) { log.warn(sm.getString("http11processor.socket.info"), e); } } request.localName().setString(localName); } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) { // Get remote host name if (remoteHost == null && (socketRef != 0)) { try { long sa = Address.get(Socket.APR_REMOTE, socketRef); remoteHost = Address.getnameinfo(sa, 0); if (remoteHost == null) { remoteHost = Address.getip(sa); } } catch (Exception e) { log.warn(sm.getString("http11processor.socket.info"), e); } } request.remoteHost().setString(remoteHost); } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) { // Get local host address if (localAddr == null && (socketRef != 0)) { try { long sa = Address.get(Socket.APR_LOCAL, socketRef); localAddr = Address.getip(sa); } catch (Exception e) { log.warn(sm.getString("http11processor.socket.info"), e); } } request.localAddr().setString(localAddr); } else if (actionCode == ActionCode.REQ_REMOTEPORT_ATTRIBUTE) { // Get remote port if (remotePort == -1 && (socketRef != 0)) { try { long sa = Address.get(Socket.APR_REMOTE, socketRef); Sockaddr addr = Address.getInfo(sa); remotePort = addr.port; } catch (Exception e) { log.warn(sm.getString("http11processor.socket.info"), e); } } request.setRemotePort(remotePort); } else if (actionCode == ActionCode.REQ_LOCALPORT_ATTRIBUTE) { // Get local port if (localPort == -1 && (socketRef != 0)) { try { long sa = Address.get(Socket.APR_LOCAL, socketRef); Sockaddr addr = Address.getInfo(sa); localPort = addr.port; } catch (Exception e) { log.warn(sm.getString("http11processor.socket.info"), e); } } request.setLocalPort(localPort); } else if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) { if (endpoint.isSSLEnabled() && (socketRef != 0)) { try { // Cipher suite Object sslO = SSLSocket.getInfoS(socketRef, SSL.SSL_INFO_CIPHER); if (sslO != null) { request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, sslO); } // Get client certificate and the certificate chain if present // certLength == -1 indicates an error int certLength = SSLSocket.getInfoI(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN); byte[] clientCert = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT); X509Certificate[] certs = null; if (clientCert != null && certLength > -1) { certs = new X509Certificate[certLength + 1]; CertificateFactory cf; if (clientCertProvider == null) { cf = CertificateFactory.getInstance("X.509"); } else { cf = CertificateFactory.getInstance("X.509", clientCertProvider); } certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert)); for (int i = 0; i < certLength; i++) { byte[] data = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); certs[i+1] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data)); } } if (certs != null) { request.setAttribute(SSLSupport.CERTIFICATE_KEY, certs); } // User key size sslO = Integer.valueOf(SSLSocket.getInfoI(socketRef, SSL.SSL_INFO_CIPHER_USEKEYSIZE)); request.setAttribute(SSLSupport.KEY_SIZE_KEY, sslO); // SSL session ID sslO = SSLSocket.getInfoS(socketRef, SSL.SSL_INFO_SESSION_ID); if (sslO != null) { request.setAttribute(SSLSupport.SESSION_ID_KEY, sslO); } //TODO provide a hook to enable the SSL session to be // invalidated. Set AprEndpoint.SESSION_MGR req attr } catch (Exception e) { log.warn(sm.getString("http11processor.socket.ssl"), e); } } } else if (actionCode == ActionCode.REQ_SSL_CERTIFICATE) { if (endpoint.isSSLEnabled() && (socketRef != 0)) { // Consume and buffer the request body, so that it does not // interfere with the client's handshake messages InputFilter[] inputFilters = inputBuffer.getFilters(); ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]).setLimit(maxSavePostSize); inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]); try { // Configure connection to require a certificate SSLSocket.setVerify(socketRef, SSL.SSL_CVERIFY_REQUIRE, ((AprEndpoint)endpoint).getSSLVerifyDepth()); // Renegotiate certificates if (SSLSocket.renegotiate(socketRef) == 0) { // Don't look for certs unless we know renegotiation worked. // Get client certificate and the certificate chain if present // certLength == -1 indicates an error int certLength = SSLSocket.getInfoI(socketRef,SSL.SSL_INFO_CLIENT_CERT_CHAIN); byte[] clientCert = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT); X509Certificate[] certs = null; if (clientCert != null && certLength > -1) { certs = new X509Certificate[certLength + 1]; CertificateFactory cf = CertificateFactory.getInstance("X.509"); certs[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(clientCert)); for (int i = 0; i < certLength; i++) { byte[] data = SSLSocket.getInfoB(socketRef, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); certs[i+1] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data)); } } if (certs != null) { request.setAttribute(SSLSupport.CERTIFICATE_KEY, certs); } } } catch (Exception e) { log.warn(sm.getString("http11processor.socket.ssl"), e); } } } else if (actionCode == ActionCode.AVAILABLE) { request.setAvailable(inputBuffer.available()); } else if (actionCode == ActionCode.COMET_BEGIN) { comet = true; } else if (actionCode == ActionCode.COMET_END) { comet = false; } else if (actionCode == ActionCode.COMET_CLOSE) { ((AprEndpoint)endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } else if (actionCode == ActionCode.COMET_SETTIMEOUT) { //no op } else if (actionCode == ActionCode.ASYNC_COMPLETE) { if (asyncStateMachine.asyncComplete()) { ((AprEndpoint)endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } else if (actionCode == ActionCode.ASYNC_SETTIMEOUT) { if (param==null) { return; } long timeout = ((Long)param).longValue(); socketWrapper.setTimeout(timeout); } else if (actionCode == ActionCode.ASYNC_DISPATCH) { if (asyncStateMachine.asyncDispatch()) { ((AprEndpoint)endpoint).processSocketAsync(this.socketWrapper, SocketStatus.OPEN_READ); } } } // ------------------------------------------------------ Protected Methods @Override protected void prepareRequestInternal() { sendfileData = null; } @Override protected boolean prepareSendfile(OutputFilter[] outputFilters) { String fileName = (String) request.getAttribute( org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR); if (fileName != null) { // No entity body sent here outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]); contentDelimitation = true; sendfileData = new AprEndpoint.SendfileData(); sendfileData.fileName = fileName; sendfileData.start = ((Long) request.getAttribute( org.apache.coyote.Constants.SENDFILE_FILE_START_ATTR)).longValue(); sendfileData.end = ((Long) request.getAttribute( org.apache.coyote.Constants.SENDFILE_FILE_END_ATTR)).longValue(); return true; } return false; } @Override protected AbstractInputBuffer getInputBuffer() { return inputBuffer; } @Override protected AbstractOutputBuffer getOutputBuffer() { return outputBuffer; } } tomcat7-7.0.52/java/org/apache/coyote/AsyncStateMachine.java0000644000175100017510000003461712176431635023627 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import java.security.AccessController; import java.security.PrivilegedAction; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.res.StringManager; /** * Manages the state transitions for async requests. * *

     * The internal states that are used are:
     * DISPATCHED    - Standard request. Not in Async mode.
     * STARTING      - ServletRequest.startAsync() has been called but the
     *                 request in which that call was made has not finished
     *                 processing.
     * STARTED       - ServletRequest.startAsync() has been called and the
     *                 request in which that call was made has finished
     *                 processing.
     * MUST_COMPLETE - complete() has been called before the request in which
     *                 ServletRequest.startAsync() has finished. As soon as that
     *                 request finishes, the complete() will be processed.
     * COMPLETING    - The call to complete() was made once the request was in
     *                 the STARTED state. May or may not be triggered by a
     *                 container thread - depends if start(Runnable) was used
     * TIMING_OUT    - The async request has timed out and is waiting for a call
     *                 to complete(). If that isn't made, the error state will
     *                 entered.
     * MUST_DISPATCH - dispatch() has been called before the request in which
     *                 ServletRequest.startAsync() has finished. As soon as that
     *                 request finishes, the dispatch() will be processed.
     * DISPATCHING   - The dispatch is being processed.
     * ERROR         - Something went wrong.
     *
     * |----------------->--------------|
     * |                               \|/
     * |   |----------<---------------ERROR
     * |   |      complete()         /|\ | \                                                          
     * |   |                          |  |  \---------------|                                         
     * |   |                          |  |                  |dispatch()                               
     * |   |                          |  |postProcess()    \|/                                        
     * |   |                   error()|  |                  |                                         
     * |   |                          |  |  |--|timeout()   |                                         
     * |   |           postProcess()  | \|/ | \|/           |         auto                            
     * |   |         |--------------->DISPATCHED<---------- | --------------COMPLETING<-----|         
     * |   |         |               /|\  |                 |                 | /|\         |         
     * |   |         |    |--->-------|   |                 |                 |--|          |         
     * |   |         ^    |               |startAsync()     |               timeout()       |         
     * |   |         |    |               |                 |                               |         
     * |  \|/        |    |  complete()  \|/  postProcess() |                               |         
     * | MUST_COMPLETE-<- | ----<------STARTING-->--------- | ------------|                 ^         
     * |         /|\      |               |                 |             |      complete() |         
     * |          |       |               |                 |             |     /-----------|         
     * |          |       ^               |dispatch()       |             |    /                      
     * |          |       |               |                 |             |   /                       
     * |          |       |              \|/                /            \|/ /                        
     * |          |       |         MUST_DISPATCH          /           STARTED
     * |          |       |           |                   /            /|  
     * |          |       |           |postProcess()     /            / |   
     * ^          ^       |           |                 /  dispatch()/  |    
     * |          |       |           |                /            /   |    
     * |          |       |           |   |---------- / -----------/    |auto
     * |          |       |           |   |          /                  |   
     * |          |       |           |   |   |-----/                   |   
     * |          |       | auto     \|/ \|/ \|/                       \|/  
     * |          |       |---<------DISPATCHING<-----------------TIMING_OUT
     * |          |                               dispatch()        |   |
     * |          |                                                 |   |
     * |          |-------<----------------------------------<------|   |
     * |                              complete()                        |  
     * |                                                                |  
     * |<--------<-------------------<-------------------------------<--|  
     *                                 error()                             
     * 
    */ public class AsyncStateMachine { /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); private static enum AsyncState { DISPATCHED(false, false, false), STARTING(true, true, false), STARTED(true, true, false), MUST_COMPLETE(true, false, false), COMPLETING(true, false, false), TIMING_OUT(true, false, false), MUST_DISPATCH(true, true, true), DISPATCHING(true, false, true), ERROR(true,false,false); private boolean isAsync; private boolean isStarted; private boolean isDispatching; private AsyncState(boolean isAsync, boolean isStarted, boolean isDispatching) { this.isAsync = isAsync; this.isStarted = isStarted; this.isDispatching = isDispatching; } public boolean isAsync() { return this.isAsync; } public boolean isStarted() { return this.isStarted; } public boolean isDispatching() { return this.isDispatching; } } private volatile AsyncState state = AsyncState.DISPATCHED; // Need this to fire listener on complete private AsyncContextCallback asyncCtxt = null; private Processor processor; public AsyncStateMachine(Processor processor) { this.processor = processor; } public boolean isAsync() { return state.isAsync(); } public boolean isAsyncDispatching() { return state.isDispatching(); } public boolean isAsyncStarted() { return state.isStarted(); } public boolean isAsyncTimingOut() { return state == AsyncState.TIMING_OUT; } public boolean isAsyncError() { return state == AsyncState.ERROR; } public synchronized void asyncStart(AsyncContextCallback asyncCtxt) { if (state == AsyncState.DISPATCHED) { state = AsyncState.STARTING; this.asyncCtxt = asyncCtxt; } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncStart()", state)); } } /* * Async has been processed. Whether or not to enter a long poll depends on * current state. For example, as per SRV.2.3.3.3 can now process calls to * complete() or dispatch(). */ public synchronized SocketState asyncPostProcess() { if (state == AsyncState.STARTING) { state = AsyncState.STARTED; return SocketState.LONG; } else if (state == AsyncState.MUST_COMPLETE) { asyncCtxt.fireOnComplete(); state = AsyncState.DISPATCHED; return SocketState.ASYNC_END; } else if (state == AsyncState.COMPLETING) { asyncCtxt.fireOnComplete(); state = AsyncState.DISPATCHED; return SocketState.ASYNC_END; } else if (state == AsyncState.MUST_DISPATCH) { state = AsyncState.DISPATCHING; return SocketState.ASYNC_END; } else if (state == AsyncState.DISPATCHING) { state = AsyncState.DISPATCHED; return SocketState.ASYNC_END; } else if (state == AsyncState.STARTED) { // This can occur if an async listener does a dispatch to an async // servlet during onTimeout return SocketState.LONG; } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncPostProcess()", state)); } } public synchronized boolean asyncComplete() { boolean doComplete = false; if (state == AsyncState.STARTING) { state = AsyncState.MUST_COMPLETE; } else if (state == AsyncState.STARTED) { state = AsyncState.COMPLETING; doComplete = true; } else if (state == AsyncState.TIMING_OUT || state == AsyncState.ERROR) { state = AsyncState.MUST_COMPLETE; } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncComplete()", state)); } return doComplete; } public synchronized boolean asyncTimeout() { if (state == AsyncState.STARTED) { state = AsyncState.TIMING_OUT; return true; } else if (state == AsyncState.COMPLETING || state == AsyncState.DISPATCHED) { // NOOP - App called complete between the the timeout firing and // execution reaching this point return false; } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncTimeout()", state)); } } public synchronized boolean asyncDispatch() { boolean doDispatch = false; if (state == AsyncState.STARTING) { state = AsyncState.MUST_DISPATCH; } else if (state == AsyncState.STARTED || state == AsyncState.TIMING_OUT || state == AsyncState.ERROR) { state = AsyncState.DISPATCHING; doDispatch = true; } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncDispatch()", state)); } return doDispatch; } public synchronized void asyncDispatched() { if (state == AsyncState.DISPATCHING) { state = AsyncState.DISPATCHED; } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncDispatched()", state)); } } public synchronized boolean asyncError() { boolean doDispatch = false; if (state == AsyncState.DISPATCHED || state == AsyncState.TIMING_OUT) { state = AsyncState.ERROR; } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncError()", state)); } return doDispatch; } public synchronized void asyncRun(Runnable runnable) { if (state == AsyncState.STARTING || state == AsyncState.STARTED) { // Execute the runnable using a container thread from the // Connector's thread pool. Use a wrapper to prevent a memory leak ClassLoader oldCL; if (Constants.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedGetTccl(); oldCL = AccessController.doPrivileged(pa); } else { oldCL = Thread.currentThread().getContextClassLoader(); } try { if (Constants.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( this.getClass().getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader()); } processor.getExecutor().execute(runnable); } finally { if (Constants.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( oldCL); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(oldCL); } } } else { throw new IllegalStateException( sm.getString("asyncStateMachine.invalidAsyncState", "asyncRun()", state)); } } public synchronized void recycle() { asyncCtxt = null; state = AsyncState.DISPATCHED; } private static class PrivilegedSetTccl implements PrivilegedAction { private ClassLoader cl; PrivilegedSetTccl(ClassLoader cl) { this.cl = cl; } @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); return null; } } private static class PrivilegedGetTccl implements PrivilegedAction { @Override public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } } } tomcat7-7.0.52/java/org/apache/coyote/Constants.java0000644000175100017510000001171712271461367022235 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; /** * Constants. * * @author Remy Maucherat */ public final class Constants { // -------------------------------------------------------------- Constants public static final String Package = "org.apache.coyote"; public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; public static final int MAX_NOTES = 32; // Request states public static final int STAGE_NEW = 0; public static final int STAGE_PARSE = 1; public static final int STAGE_PREPARE = 2; public static final int STAGE_SERVICE = 3; public static final int STAGE_ENDINPUT = 4; public static final int STAGE_ENDOUTPUT = 5; public static final int STAGE_KEEPALIVE = 6; public static final int STAGE_ENDED = 7; /** * Has security been turned on? */ public static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); /** * If true, custom HTTP status messages will be used in headers. */ public static final boolean USE_CUSTOM_STATUS_MSG_IN_HEADER = Boolean.valueOf(System.getProperty( "org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER", "false")).booleanValue(); /** * The request attribute that is set to the value of {@code Boolean.TRUE} * if connector processing this request supports Comet API. */ public static final String COMET_SUPPORTED_ATTR = "org.apache.tomcat.comet.support"; /** * The request attribute that is set to the value of {@code Boolean.TRUE} * if connector processing this request supports setting * per-connection request timeout through Comet API. * * @see org.apache.catalina.comet.CometEvent#setTimeout(int) */ public static final String COMET_TIMEOUT_SUPPORTED_ATTR = "org.apache.tomcat.comet.timeout.support"; /** * The request attribute that can be set to a value of type * {@code java.lang.Integer} to specify per-connection request * timeout for Comet API. The value is in milliseconds. * * @see org.apache.catalina.comet.CometEvent#setTimeout(int) */ public static final String COMET_TIMEOUT_ATTR = "org.apache.tomcat.comet.timeout"; /** * The request attribute that is set to the value of {@code Boolean.TRUE} * if connector processing this request supports use of sendfile. */ public static final String SENDFILE_SUPPORTED_ATTR = "org.apache.tomcat.sendfile.support"; /** * The request attribute that can be used by a servlet to pass * to the connector the name of the file that is to be served * by sendfile. The value should be {@code java.lang.String} * that is {@code File.getCanonicalPath()} of the file to be served. */ public static final String SENDFILE_FILENAME_ATTR = "org.apache.tomcat.sendfile.filename"; /** * The request attribute that can be used by a servlet to pass * to the connector the start offset of the part of a file * that is to be served by sendfile. The value should be * {@code java.lang.Long}. To serve complete file * the value should be {@code Long.valueOf(0)}. */ public static final String SENDFILE_FILE_START_ATTR = "org.apache.tomcat.sendfile.start"; /** * The request attribute that can be used by a servlet to pass * to the connector the end offset (not including) of the part * of a file that is to be served by sendfile. The value should be * {@code java.lang.Long}. To serve complete file * the value should be equal to the length of the file. */ public static final String SENDFILE_FILE_END_ATTR = "org.apache.tomcat.sendfile.end"; /** * The request attribute set by the RemoteIpFilter, RemoteIpValve (and may * be set by other similar components) that identifies for the connector the * remote IP address claimed to be associated with this request when a * request is received via one or more proxies. It is typically provided via * the X-Forwarded-For HTTP header. */ public static final String REMOTE_ADDR_ATTRIBUTE = "org.apache.tomcat.remoteAddr"; } tomcat7-7.0.52/java/org/apache/coyote/Adapter.java0000644000175100017510000000446712271461367021645 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; import org.apache.tomcat.util.net.SocketStatus; /** * Adapter. This represents the entry point in a coyote-based servlet container. * * * @author Remy Maucherat * @see ProtocolHandler */ public interface Adapter { /** * Call the service method, and notify all listeners * * @exception Exception if an error happens during handling of * the request. Common errors are: *
    • IOException if an input/output error occurs and we are * processing an included servlet (otherwise it is swallowed and * handled by the top level error handler mechanism) *
    • ServletException if a servlet throws an exception and * we are processing an included servlet (otherwise it is swallowed * and handled by the top level error handler mechanism) *
    * Tomcat should be able to handle and log any other exception ( including * runtime exceptions ) */ public void service(Request req, Response res) throws Exception; public boolean event(Request req, Response res, SocketStatus status) throws Exception; public boolean asyncDispatch(Request req,Response res, SocketStatus status) throws Exception; public void log(Request req, Response res, long time); /** * Provide the name of the domain to use to register MBeans for conponents * associated with the connector. * * @return The MBean domain name */ public String getDomain(); } tomcat7-7.0.52/java/org/apache/coyote/LocalStrings.properties0000644000175100017510000000443712012773207024131 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. abstractConnectionHandler.error=Error reading request, ignored abstractConnectionHandler.ioexception.debug=IOExceptions are normal, ignored abstractConnectionHandler.socketexception.debug=SocketExceptions are normal, ignored abstractProtocolHandler.getAttribute=Get attribute [{0}] with value [{1}] abstractProtocolHandler.setAttribute=Set attribute [{0}] with value [{1}] abstractProtocolHandler.init=Initializing ProtocolHandler [{0}] abstractProtocolHandler.initError=Failed to initialize end point associated with ProtocolHandler [{0}] abstractProtocolHandler.mbeanRegistrationFailed=Failed to register MBean [{0}] for ProtocolHandler [{1}] abstractProtocolHandler.start=Starting ProtocolHandler [{0}] abstractProtocolHandler.startError=Failed to start end point associated with ProtocolHandler [{0}] abstractProtocolHandler.pause=Pausing ProtocolHandler [{0}] abstractProtocolHandler.pauseError=Failed to pause end point associated with ProtocolHandler [{0}] abstractProtocolHandler.resume=Resuming ProtocolHandler [{0}] abstractProtocolHandler.resumeError=Failed to resume end point associated with ProtocolHandler [{0}] abstractProtocolHandler.stop=Stopping ProtocolHandler [{0}] abstractProtocolHandler.stopError=Failed to stop end point associated with ProtocolHandler [{0}] abstractProtocolHandler.destroy=Destroying ProtocolHandler [{0}] abstractProtocolHandler.destroyError=Failed to destroy end point associated with ProtocolHandler [{0}] asyncStateMachine.invalidAsyncState=Calling [{0}] is not valid for a request with Async state [{1}] tomcat7-7.0.52/java/org/apache/coyote/ActionCode.java0000644000175100017510000001162412271461367022266 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.coyote; /** * ActionCodes represent callbacks from the servlet container to the coyote * connector. Actions are implemented by ProtocolHandler, using the ActionHook * interface. * * @see ProtocolHandler * @see ActionHook * @author Remy Maucherat */ public enum ActionCode { ACK, CLOSE, COMMIT, /** * A flush() operation originated by the client ( i.e. a flush() on the * servlet output stream or writer, called by a servlet ). Argument is the * Response. */ CLIENT_FLUSH, CUSTOM, RESET, /** * Hook called after request, but before recycling. Can be used for logging, * to update counters, custom cleanup - the request is still visible */ POST_REQUEST, /** * Has the processor been placed into the error state? Note that the * response may not have an appropriate error code set. */ IS_ERROR, /** * Hook called if swallowing request input should be disabled. * Example: Cancel a large file upload. * */ DISABLE_SWALLOW_INPUT, /** * Callback for lazy evaluation - extract the remote host address. */ REQ_HOST_ATTRIBUTE, /** * Callback for lazy evaluation - extract the remote host infos (address, * name, port) and local address. */ REQ_HOST_ADDR_ATTRIBUTE, /** * Callback for lazy evaluation - extract the SSL-related attributes. */ REQ_SSL_ATTRIBUTE, /** * Callback for lazy evaluation - extract the SSL-certificate (including * forcing a re-handshake if necessary) */ REQ_SSL_CERTIFICATE, /** * Callback for lazy evaluation - socket remote port. */ REQ_REMOTEPORT_ATTRIBUTE, /** * Callback for lazy evaluation - socket local port. */ REQ_LOCALPORT_ATTRIBUTE, /** * Callback for lazy evaluation - local address. */ REQ_LOCAL_ADDR_ATTRIBUTE, /** * Callback for lazy evaluation - local address. */ REQ_LOCAL_NAME_ATTRIBUTE, /** * Callback for setting FORM auth body replay */ REQ_SET_BODY_REPLAY, /** * Callback for begin Comet processing */ COMET_BEGIN, /** * Callback for end Comet processing */ COMET_END, /** * Callback for getting the amount of available bytes */ AVAILABLE, /** * Callback for an asynchronous close of the Comet event */ COMET_CLOSE, /** * Callback for setting the timeout asynchronously */ COMET_SETTIMEOUT, /** * Callback for an async request */ ASYNC_START, /** * Callback for an async call to * {@link javax.servlet.AsyncContext#dispatch()} */ ASYNC_DISPATCH, /** * Callback to indicate the the actual dispatch has started and that the * async state needs change. */ ASYNC_DISPATCHED, /** * Callback for an async call to * {@link javax.servlet.AsyncContext#start(Runnable)} */ ASYNC_RUN, /** * Callback for an async call to * {@link javax.servlet.AsyncContext#complete()} */ ASYNC_COMPLETE, /** * Callback to trigger the processing of an async timeout */ ASYNC_TIMEOUT, /** * Callback to trigger the error processing */ ASYNC_ERROR, /** * Callback for an async call to * {@link javax.servlet.AsyncContext#setTimeout(long)} */ ASYNC_SETTIMEOUT, /** * Callback to determine if async processing is in progress */ ASYNC_IS_ASYNC, /** * Callback to determine if async dispatch is in progress */ ASYNC_IS_STARTED, /** * Callback to determine if async dispatch is in progress */ ASYNC_IS_DISPATCHING, /** * Callback to determine if async is timing out */ ASYNC_IS_TIMINGOUT, /** * Callback to determine if async is in error */ ASYNC_IS_ERROR, /** * Callback to trigger Tomcat's proprietary HTTP upgrade process. */ UPGRADE_TOMCAT, /** * Callback to trigger the Servlet 3.1 based HTTP upgrade process. */ UPGRADE } tomcat7-7.0.52/java/org/apache/el/0000755000175100017510000000000012301126371016470 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/el/ValueExpressionLiteral.java0000644000175100017510000000703012271461077024017 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import javax.el.ELContext; import javax.el.PropertyNotWritableException; import javax.el.ValueExpression; import org.apache.el.lang.ELSupport; import org.apache.el.util.MessageFactory; import org.apache.el.util.ReflectionUtil; public final class ValueExpressionLiteral extends ValueExpression implements Externalizable { private static final long serialVersionUID = 1L; private Object value; private Class expectedType; public ValueExpressionLiteral() { super(); } public ValueExpressionLiteral(Object value, Class expectedType) { this.value = value; this.expectedType = expectedType; } @Override public Object getValue(ELContext context) { if (this.expectedType != null) { return ELSupport.coerceToType(this.value, this.expectedType); } return this.value; } @Override public void setValue(ELContext context, Object value) { throw new PropertyNotWritableException(MessageFactory.get( "error.value.literal.write", this.value)); } @Override public boolean isReadOnly(ELContext context) { return true; } @Override public Class getType(ELContext context) { return (this.value != null) ? this.value.getClass() : null; } @Override public Class getExpectedType() { return this.expectedType; } @Override public String getExpressionString() { return (this.value != null) ? this.value.toString() : null; } @Override public boolean equals(Object obj) { return (obj instanceof ValueExpressionLiteral && this .equals((ValueExpressionLiteral) obj)); } public boolean equals(ValueExpressionLiteral ve) { return (ve != null && (this.value != null && ve.value != null && (this.value == ve.value || this.value .equals(ve.value)))); } @Override public int hashCode() { return (this.value != null) ? this.value.hashCode() : 0; } @Override public boolean isLiteralText() { return true; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(this.value); out.writeUTF((this.expectedType != null) ? this.expectedType.getName() : ""); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.value = in.readObject(); String type = in.readUTF(); if (!"".equals(type)) { this.expectedType = ReflectionUtil.forName(type); } } } tomcat7-7.0.52/java/org/apache/el/MethodExpressionImpl.java0000644000175100017510000002774512271461077023507 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import javax.el.ELContext; import javax.el.ELException; import javax.el.FunctionMapper; import javax.el.MethodExpression; import javax.el.MethodInfo; import javax.el.MethodNotFoundException; import javax.el.PropertyNotFoundException; import javax.el.VariableMapper; import org.apache.el.lang.EvaluationContext; import org.apache.el.lang.ExpressionBuilder; import org.apache.el.parser.Node; import org.apache.el.util.ReflectionUtil; /** * An Expression that refers to a method on an object. * *

    * The {@link javax.el.ExpressionFactory#createMethodExpression} method * can be used to parse an expression string and return a concrete instance * of MethodExpression that encapsulates the parsed expression. * The {@link FunctionMapper} is used at parse time, not evaluation time, * so one is not needed to evaluate an expression using this class. * However, the {@link ELContext} is needed at evaluation time.

    * *

    The {@link #getMethodInfo} and {@link #invoke} methods will evaluate the * expression each time they are called. The {@link javax.el.ELResolver} in the * ELContext is used to resolve the top-level variables and to * determine the behavior of the . and [] * operators. For any of the two methods, the * {@link javax.el.ELResolver#getValue} method is used to resolve all properties * up to but excluding the last one. This provides the base object * on which the method appears. If the base object is null, a * NullPointerException must be thrown. At the last resolution, * the final property is then coerced to a String, * which provides the name of the method to be found. A method matching the * name and expected parameters provided at parse time is found and it is * either queried or invoked (depending on the method called on this * MethodExpression).

    * *

    See the notes about comparison, serialization and immutability in * the {@link javax.el.Expression} javadocs. * * @see javax.el.ELResolver * @see javax.el.Expression * @see javax.el.ExpressionFactory * @see javax.el.MethodExpression * * @author Jacob Hookom [jacob@hookom.net] */ public final class MethodExpressionImpl extends MethodExpression implements Externalizable { private Class expectedType; private String expr; private FunctionMapper fnMapper; private VariableMapper varMapper; private transient Node node; private Class[] paramTypes; /** * */ public MethodExpressionImpl() { super(); } /** * @param expr * @param node * @param fnMapper * @param expectedType * @param paramTypes */ public MethodExpressionImpl(String expr, Node node, FunctionMapper fnMapper, VariableMapper varMapper, Class expectedType, Class[] paramTypes) { super(); this.expr = expr; this.node = node; this.fnMapper = fnMapper; this.varMapper = varMapper; this.expectedType = expectedType; this.paramTypes = paramTypes; } /** * Determines whether the specified object is equal to this * Expression. * *

    * The result is true if and only if the argument is not * null, is an Expression object that is the * of the same type (ValueExpression or * MethodExpression), and has an identical parsed * representation. *

    * *

    * Note that two expressions can be equal if their expression Strings are * different. For example, ${fn1:foo()} and * ${fn2:foo()} are equal if their corresponding * FunctionMappers mapped fn1:foo and * fn2:foo to the same method. *

    * * @param obj * the Object to test for equality. * @return true if obj equals this * Expression; false otherwise. * @see java.util.Hashtable * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { return (obj instanceof MethodExpressionImpl && obj.hashCode() == this .hashCode()); } /** * Returns the original String used to create this Expression, * unmodified. * *

    * This is used for debugging purposes but also for the purposes of * comparison (e.g. to ensure the expression in a configuration file has not * changed). *

    * *

    * This method does not provide sufficient information to re-create an * expression. Two different expressions can have exactly the same * expression string but different function mappings. Serialization should * be used to save and restore the state of an Expression. *

    * * @return The original expression String. * * @see javax.el.Expression#getExpressionString() */ @Override public String getExpressionString() { return this.expr; } /** * Evaluates the expression relative to the provided context, and returns * information about the actual referenced method. * * @param context * The context of this evaluation * @return an instance of MethodInfo containing information * about the method the expression evaluated to. * @throws NullPointerException * if context is null or the base object is * null on the last resolution. * @throws PropertyNotFoundException * if one of the property resolutions failed because a specified * variable or property does not exist or is not readable. * @throws MethodNotFoundException * if no suitable method can be found. * @throws ELException * if an exception was thrown while performing property or * variable resolution. The thrown exception must be included as * the cause property of this exception, if available. * @see javax.el.MethodExpression#getMethodInfo(javax.el.ELContext) */ @Override public MethodInfo getMethodInfo(ELContext context) throws PropertyNotFoundException, MethodNotFoundException, ELException { Node n = this.getNode(); EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, this.varMapper); return n.getMethodInfo(ctx, this.paramTypes); } private Node getNode() throws ELException { if (this.node == null) { this.node = ExpressionBuilder.createNode(this.expr); } return this.node; } /** * Returns the hash code for this Expression. * *

    * See the note in the {@link #equals} method on how two expressions can be * equal if their expression Strings are different. Recall that if two * objects are equal according to the equals(Object) method, * then calling the hashCode method on each of the two * objects must produce the same integer result. Implementations must take * special note and implement hashCode correctly. *

    * * @return The hash code for this Expression. * @see #equals * @see java.util.Hashtable * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return this.expr.hashCode(); } /** * Evaluates the expression relative to the provided context, invokes the * method that was found using the supplied parameters, and returns the * result of the method invocation. * * @param context * The context of this evaluation. * @param params * The parameters to pass to the method, or null * if no parameters. * @return the result of the method invocation (null if the * method has a void return type). * @throws NullPointerException * if context is null or the base object is * null on the last resolution. * @throws PropertyNotFoundException * if one of the property resolutions failed because a specified * variable or property does not exist or is not readable. * @throws MethodNotFoundException * if no suitable method can be found. * @throws ELException * if an exception was thrown while performing property or * variable resolution. The thrown exception must be included as * the cause property of this exception, if available. If the * exception thrown is an InvocationTargetException, * extract its cause and pass it to the * ELException constructor. * @see javax.el.MethodExpression#invoke(javax.el.ELContext, * java.lang.Object[]) */ @Override public Object invoke(ELContext context, Object[] params) throws PropertyNotFoundException, MethodNotFoundException, ELException { EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, this.varMapper); return this.getNode().invoke(ctx, this.paramTypes, params); } /* * (non-Javadoc) * * @see java.io.Externalizable#readExternal(java.io.ObjectInput) */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.expr = in.readUTF(); String type = in.readUTF(); if (!"".equals(type)) { this.expectedType = ReflectionUtil.forName(type); } this.paramTypes = ReflectionUtil.toTypeArray(((String[]) in .readObject())); this.fnMapper = (FunctionMapper) in.readObject(); this.varMapper = (VariableMapper) in.readObject(); } /* * (non-Javadoc) * * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) */ @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(this.expr); out.writeUTF((this.expectedType != null) ? this.expectedType.getName() : ""); out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes)); out.writeObject(this.fnMapper); out.writeObject(this.varMapper); } @Override public boolean isLiteralText() { return false; } /** * @since EL 2.2 * Note: The spelling mistake is deliberate. * isParmetersProvided() - Specification definition * isParametersProvided() - Corrected spelling */ @Override public boolean isParmetersProvided() { return this.getNode().isParametersProvided(); } } tomcat7-7.0.52/java/org/apache/el/lang/0000755000175100017510000000000012301126371017411 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/el/lang/ELSupport.java0000644000175100017510000004311212271461077022165 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; import java.math.BigDecimal; import java.math.BigInteger; import javax.el.ELException; import org.apache.el.util.MessageFactory; /** * A helper class that implements the EL Specification * * @author Jacob Hookom [jacob@hookom.net] */ public class ELSupport { private static final Long ZERO = Long.valueOf(0L); /** * Compare two objects, after coercing to the same type if appropriate. * * If the objects are identical, or they are equal according to * {@link #equals(Object, Object)} then return 0. * * If either object is a BigDecimal, then coerce both to BigDecimal first. * Similarly for Double(Float), BigInteger, and Long(Integer, Char, Short, Byte). * * Otherwise, check that the first object is an instance of Comparable, and compare * against the second object. If that is null, return 1, otherwise * return the result of comparing against the second object. * * Similarly, if the second object is Comparable, if the first is null, return -1, * else return the result of comparing against the first object. * * A null object is considered as: *
      *
    • ZERO when compared with Numbers
    • *
    • the empty string for String compares
    • *
    • Otherwise null is considered to be lower than anything else.
    • *
    * * @param obj0 first object * @param obj1 second object * @return -1, 0, or 1 if this object is less than, equal to, or greater than val. * @throws ELException if neither object is Comparable * @throws ClassCastException if the objects are not mutually comparable */ public static final int compare(final Object obj0, final Object obj1) throws ELException { if (obj0 == obj1 || equals(obj0, obj1)) { return 0; } if (isBigDecimalOp(obj0, obj1)) { BigDecimal bd0 = (BigDecimal) coerceToNumber(obj0, BigDecimal.class); BigDecimal bd1 = (BigDecimal) coerceToNumber(obj1, BigDecimal.class); return bd0.compareTo(bd1); } if (isDoubleOp(obj0, obj1)) { Double d0 = (Double) coerceToNumber(obj0, Double.class); Double d1 = (Double) coerceToNumber(obj1, Double.class); return d0.compareTo(d1); } if (isBigIntegerOp(obj0, obj1)) { BigInteger bi0 = (BigInteger) coerceToNumber(obj0, BigInteger.class); BigInteger bi1 = (BigInteger) coerceToNumber(obj1, BigInteger.class); return bi0.compareTo(bi1); } if (isLongOp(obj0, obj1)) { Long l0 = (Long) coerceToNumber(obj0, Long.class); Long l1 = (Long) coerceToNumber(obj1, Long.class); return l0.compareTo(l1); } if (obj0 instanceof String || obj1 instanceof String) { return coerceToString(obj0).compareTo(coerceToString(obj1)); } if (obj0 instanceof Comparable) { @SuppressWarnings("unchecked") // checked above final Comparable comparable = (Comparable) obj0; return (obj1 != null) ? comparable.compareTo(obj1) : 1; } if (obj1 instanceof Comparable) { @SuppressWarnings("unchecked") // checked above final Comparable comparable = (Comparable) obj1; return (obj0 != null) ? -comparable.compareTo(obj0) : -1; } throw new ELException(MessageFactory.get("error.compare", obj0, obj1)); } /** * Compare two objects for equality, after coercing to the same type if appropriate. * * If the objects are identical (including both null) return true. * If either object is null, return false. * If either object is Boolean, coerce both to Boolean and check equality. * Similarly for Enum, String, BigDecimal, Double(Float), Long(Integer, Short, Byte, Character) * Otherwise default to using Object.equals(). * * @param obj0 the first object * @param obj1 the second object * @return true if the objects are equal * @throws ELException */ public static final boolean equals(final Object obj0, final Object obj1) throws ELException { if (obj0 == obj1) { return true; } else if (obj0 == null || obj1 == null) { return false; } else if (isBigDecimalOp(obj0, obj1)) { BigDecimal bd0 = (BigDecimal) coerceToNumber(obj0, BigDecimal.class); BigDecimal bd1 = (BigDecimal) coerceToNumber(obj1, BigDecimal.class); return bd0.equals(bd1); } else if (isDoubleOp(obj0, obj1)) { Double d0 = (Double) coerceToNumber(obj0, Double.class); Double d1 = (Double) coerceToNumber(obj1, Double.class); return d0.equals(d1); } else if (isBigIntegerOp(obj0, obj1)) { BigInteger bi0 = (BigInteger) coerceToNumber(obj0, BigInteger.class); BigInteger bi1 = (BigInteger) coerceToNumber(obj1, BigInteger.class); return bi0.equals(bi1); } else if (isLongOp(obj0, obj1)) { Long l0 = (Long) coerceToNumber(obj0, Long.class); Long l1 = (Long) coerceToNumber(obj1, Long.class); return l0.equals(l1); } else if (obj0 instanceof Boolean || obj1 instanceof Boolean) { return coerceToBoolean(obj0).equals(coerceToBoolean(obj1)); } else if (obj0.getClass().isEnum()) { return obj0.equals(coerceToEnum(obj1, obj0.getClass())); } else if (obj1.getClass().isEnum()) { return obj1.equals(coerceToEnum(obj0, obj1.getClass())); } else if (obj0 instanceof String || obj1 instanceof String) { int lexCompare = coerceToString(obj0).compareTo(coerceToString(obj1)); return (lexCompare == 0) ? true : false; } else { return obj0.equals(obj1); } } // Going to have to have some casts /raw types somewhere so doing it here // keeps them all in one place. There might be a neater / better solution // but I couldn't find it @SuppressWarnings("unchecked") public static final Enum coerceToEnum(final Object obj, @SuppressWarnings("rawtypes") Class type) { if (obj == null || "".equals(obj)) { return null; } if (type.isAssignableFrom(obj.getClass())) { return (Enum) obj; } if (!(obj instanceof String)) { throw new ELException(MessageFactory.get("error.convert", obj, obj.getClass(), type)); } Enum result; try { result = Enum.valueOf(type, (String) obj); } catch (IllegalArgumentException iae) { throw new ELException(MessageFactory.get("error.convert", obj, obj.getClass(), type)); } return result; } /** * Convert an object to Boolean. * Null and empty string are false. * @param obj the object to convert * @return the Boolean value of the object * @throws ELException if object is not Boolean or String */ public static final Boolean coerceToBoolean(final Object obj) throws ELException { if (obj == null || "".equals(obj)) { return Boolean.FALSE; } if (obj instanceof Boolean) { return (Boolean) obj; } if (obj instanceof String) { return Boolean.valueOf((String) obj); } throw new ELException(MessageFactory.get("error.convert", obj, obj.getClass(), Boolean.class)); } public static final Character coerceToCharacter(final Object obj) throws ELException { if (obj == null || "".equals(obj)) { return Character.valueOf((char) 0); } if (obj instanceof String) { return Character.valueOf(((String) obj).charAt(0)); } if (ELArithmetic.isNumber(obj)) { return Character.valueOf((char) ((Number) obj).shortValue()); } Class objType = obj.getClass(); if (obj instanceof Character) { return (Character) obj; } throw new ELException(MessageFactory.get("error.convert", obj, objType, Character.class)); } protected static final Number coerceToNumber(final Number number, final Class type) throws ELException { if (Long.TYPE == type || Long.class.equals(type)) { return Long.valueOf(number.longValue()); } if (Double.TYPE == type || Double.class.equals(type)) { return new Double(number.doubleValue()); } if (Integer.TYPE == type || Integer.class.equals(type)) { return Integer.valueOf(number.intValue()); } if (BigInteger.class.equals(type)) { if (number instanceof BigDecimal) { return ((BigDecimal) number).toBigInteger(); } if (number instanceof BigInteger) { return number; } return BigInteger.valueOf(number.longValue()); } if (BigDecimal.class.equals(type)) { if (number instanceof BigDecimal) { return number; } if (number instanceof BigInteger) { return new BigDecimal((BigInteger) number); } return new BigDecimal(number.doubleValue()); } if (Byte.TYPE == type || Byte.class.equals(type)) { return Byte.valueOf(number.byteValue()); } if (Short.TYPE == type || Short.class.equals(type)) { return Short.valueOf(number.shortValue()); } if (Float.TYPE == type || Float.class.equals(type)) { return new Float(number.floatValue()); } if (Number.class.equals(type)) { return number; } throw new ELException(MessageFactory.get("error.convert", number, number.getClass(), type)); } public static final Number coerceToNumber(final Object obj, final Class type) throws ELException { if (obj == null || "".equals(obj)) { return coerceToNumber(ZERO, type); } if (obj instanceof String) { return coerceToNumber((String) obj, type); } if (ELArithmetic.isNumber(obj)) { return coerceToNumber((Number) obj, type); } if (obj instanceof Character) { return coerceToNumber(Short.valueOf((short) ((Character) obj) .charValue()), type); } throw new ELException(MessageFactory.get("error.convert", obj, obj.getClass(), type)); } protected static final Number coerceToNumber(final String val, final Class type) throws ELException { if (Long.TYPE == type || Long.class.equals(type)) { try { return Long.valueOf(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } if (Integer.TYPE == type || Integer.class.equals(type)) { try { return Integer.valueOf(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } if (Double.TYPE == type || Double.class.equals(type)) { try { return Double.valueOf(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } if (BigInteger.class.equals(type)) { try { return new BigInteger(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } if (BigDecimal.class.equals(type)) { try { return new BigDecimal(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } if (Byte.TYPE == type || Byte.class.equals(type)) { try { return Byte.valueOf(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } if (Short.TYPE == type || Short.class.equals(type)) { try { return Short.valueOf(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } if (Float.TYPE == type || Float.class.equals(type)) { try { return Float.valueOf(val); } catch (NumberFormatException nfe) { throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } } throw new ELException(MessageFactory.get("error.convert", val, String.class, type)); } /** * Coerce an object to a string * @param obj * @return the String value of the object */ public static final String coerceToString(final Object obj) { if (obj == null) { return ""; } else if (obj instanceof String) { return (String) obj; } else if (obj instanceof Enum) { return ((Enum) obj).name(); } else { return obj.toString(); } } public static final Object coerceToType(final Object obj, final Class type) throws ELException { if (type == null || Object.class.equals(type) || (obj != null && type.isAssignableFrom(obj.getClass()))) { return obj; } if (String.class.equals(type)) { return coerceToString(obj); } if (ELArithmetic.isNumberType(type)) { return coerceToNumber(obj, type); } if (Character.class.equals(type) || Character.TYPE == type) { return coerceToCharacter(obj); } if (Boolean.class.equals(type) || Boolean.TYPE == type) { return coerceToBoolean(obj); } if (type.isEnum()) { return coerceToEnum(obj, type); } // new to spec if (obj == null) return null; if (obj instanceof String) { if ("".equals(obj)) return null; PropertyEditor editor = PropertyEditorManager.findEditor(type); if (editor != null) { editor.setAsText((String) obj); return editor.getValue(); } } throw new ELException(MessageFactory.get("error.convert", obj, obj.getClass(), type)); } public static final boolean isBigDecimalOp(final Object obj0, final Object obj1) { return (obj0 instanceof BigDecimal || obj1 instanceof BigDecimal); } public static final boolean isBigIntegerOp(final Object obj0, final Object obj1) { return (obj0 instanceof BigInteger || obj1 instanceof BigInteger); } public static final boolean isDoubleOp(final Object obj0, final Object obj1) { return (obj0 instanceof Double || obj1 instanceof Double || obj0 instanceof Float || obj1 instanceof Float); } public static final boolean isLongOp(final Object obj0, final Object obj1) { return (obj0 instanceof Long || obj1 instanceof Long || obj0 instanceof Integer || obj1 instanceof Integer || obj0 instanceof Character || obj1 instanceof Character || obj0 instanceof Short || obj1 instanceof Short || obj0 instanceof Byte || obj1 instanceof Byte); } public static final boolean isStringFloat(final String str) { int len = str.length(); if (len > 1) { for (int i = 0; i < len; i++) { switch (str.charAt(i)) { case 'E': return true; case 'e': return true; case '.': return true; } } } return false; } /** * */ public ELSupport() { super(); } } tomcat7-7.0.52/java/org/apache/el/lang/VariableMapperFactory.java0000644000175100017510000000355512271461077024521 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import javax.el.ValueExpression; import javax.el.VariableMapper; public class VariableMapperFactory extends VariableMapper { private final VariableMapper target; private VariableMapper momento; public VariableMapperFactory(VariableMapper target) { if (target == null) { throw new NullPointerException("Target VariableMapper cannot be null"); } this.target = target; } public VariableMapper create() { return this.momento; } @Override public ValueExpression resolveVariable(String variable) { ValueExpression expr = this.target.resolveVariable(variable); if (expr != null) { if (this.momento == null) { this.momento = new VariableMapperImpl(); } this.momento.setVariable(variable, expr); } return expr; } @Override public ValueExpression setVariable(String variable, ValueExpression expression) { throw new UnsupportedOperationException("Cannot Set Variables on Factory"); } } tomcat7-7.0.52/java/org/apache/el/lang/FunctionMapperImpl.java0000644000175100017510000001332312271461077024045 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import javax.el.FunctionMapper; import org.apache.el.util.ReflectionUtil; /** * @author Jacob Hookom [jacob@hookom.net] */ public class FunctionMapperImpl extends FunctionMapper implements Externalizable { private static final long serialVersionUID = 1L; protected Map functions = null; /* * (non-Javadoc) * * @see javax.el.FunctionMapper#resolveFunction(java.lang.String, * java.lang.String) */ @Override public Method resolveFunction(String prefix, String localName) { if (this.functions != null) { Function f = this.functions.get(prefix + ":" + localName); return f.getMethod(); } return null; } public void addFunction(String prefix, String localName, Method m) { if (this.functions == null) { this.functions = new HashMap(); } Function f = new Function(prefix, localName, m); synchronized (this) { this.functions.put(prefix+":"+localName, f); } } /* * (non-Javadoc) * * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) */ @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(this.functions); } /* * (non-Javadoc) * * @see java.io.Externalizable#readExternal(java.io.ObjectInput) */ @SuppressWarnings("unchecked") @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.functions = (Map) in.readObject(); } public static class Function implements Externalizable { protected transient Method m; protected String owner; protected String name; protected String[] types; protected String prefix; protected String localName; /** * */ public Function(String prefix, String localName, Method m) { if (localName == null) { throw new NullPointerException("LocalName cannot be null"); } if (m == null) { throw new NullPointerException("Method cannot be null"); } this.prefix = prefix; this.localName = localName; this.m = m; } public Function() { // for serialization } /* * (non-Javadoc) * * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) */ @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF((this.prefix != null) ? this.prefix : ""); out.writeUTF(this.localName); // make sure m isn't null getMethod(); out.writeUTF((this.owner != null) ? this.owner : this.m.getDeclaringClass().getName()); out.writeUTF((this.name != null) ? this.name : this.m.getName()); out.writeObject((this.types != null) ? this.types : ReflectionUtil.toTypeNameArray(this.m.getParameterTypes())); } /* * (non-Javadoc) * * @see java.io.Externalizable#readExternal(java.io.ObjectInput) */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.prefix = in.readUTF(); if ("".equals(this.prefix)) this.prefix = null; this.localName = in.readUTF(); this.owner = in.readUTF(); this.name = in.readUTF(); this.types = (String[]) in.readObject(); } public Method getMethod() { if (this.m == null) { try { Class t = ReflectionUtil.forName(this.owner); Class[] p = ReflectionUtil.toTypeArray(this.types); this.m = t.getMethod(this.name, p); } catch (Exception e) { e.printStackTrace(); } } return this.m; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj instanceof Function) { return this.hashCode() == obj.hashCode(); } return false; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (this.prefix + this.localName).hashCode(); } } } tomcat7-7.0.52/java/org/apache/el/lang/EvaluationContext.java0000644000175100017510000000523212271461077023745 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import java.util.Locale; import javax.el.ELContext; import javax.el.ELResolver; import javax.el.FunctionMapper; import javax.el.VariableMapper; public final class EvaluationContext extends ELContext { private final ELContext elContext; private final FunctionMapper fnMapper; private final VariableMapper varMapper; public EvaluationContext(ELContext elContext, FunctionMapper fnMapper, VariableMapper varMapper) { this.elContext = elContext; this.fnMapper = fnMapper; this.varMapper = varMapper; } public ELContext getELContext() { return this.elContext; } @Override public FunctionMapper getFunctionMapper() { return this.fnMapper; } @Override public VariableMapper getVariableMapper() { return this.varMapper; } @Override // Can't use Class because API needs to match specification in superclass public Object getContext(@SuppressWarnings("rawtypes") Class key) { return this.elContext.getContext(key); } @Override public ELResolver getELResolver() { return this.elContext.getELResolver(); } @Override public boolean isPropertyResolved() { return this.elContext.isPropertyResolved(); } @Override // Can't use Class because API needs to match specification in superclass public void putContext(@SuppressWarnings("rawtypes") Class key, Object contextObject) { this.elContext.putContext(key, contextObject); } @Override public void setPropertyResolved(boolean resolved) { this.elContext.setPropertyResolved(resolved); } @Override public Locale getLocale() { return this.elContext.getLocale(); } @Override public void setLocale(Locale locale) { this.elContext.setLocale(locale); } } tomcat7-7.0.52/java/org/apache/el/lang/VariableMapperImpl.java0000644000175100017510000000370212271461077024005 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.HashMap; import java.util.Map; import javax.el.ValueExpression; import javax.el.VariableMapper; public class VariableMapperImpl extends VariableMapper implements Externalizable { private static final long serialVersionUID = 1L; private Map vars = new HashMap(); public VariableMapperImpl() { super(); } @Override public ValueExpression resolveVariable(String variable) { return this.vars.get(variable); } @Override public ValueExpression setVariable(String variable, ValueExpression expression) { return this.vars.put(variable, expression); } @SuppressWarnings("unchecked") @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.vars = (Map) in.readObject(); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(this.vars); } } tomcat7-7.0.52/java/org/apache/el/lang/ELArithmetic.java0000644000175100017510000003221412271461077022603 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import java.math.BigDecimal; import java.math.BigInteger; import org.apache.el.util.MessageFactory; /** * A helper class of Arithmetic defined by the EL Specification * @author Jacob Hookom [jacob@hookom.net] */ public abstract class ELArithmetic { public static final class BigDecimalDelegate extends ELArithmetic { @Override protected Number add(Number num0, Number num1) { return ((BigDecimal) num0).add((BigDecimal) num1); } @Override protected Number coerce(Number num) { if (num instanceof BigDecimal) return num; if (num instanceof BigInteger) return new BigDecimal((BigInteger) num); return new BigDecimal(num.doubleValue()); } @Override protected Number coerce(String str) { return new BigDecimal(str); } @Override protected Number divide(Number num0, Number num1) { return ((BigDecimal) num0).divide((BigDecimal) num1, BigDecimal.ROUND_HALF_UP); } @Override protected Number subtract(Number num0, Number num1) { return ((BigDecimal) num0).subtract((BigDecimal) num1); } @Override protected Number mod(Number num0, Number num1) { return new Double(num0.doubleValue() % num1.doubleValue()); } @Override protected Number multiply(Number num0, Number num1) { return ((BigDecimal) num0).multiply((BigDecimal) num1); } @Override public boolean matches(Object obj0, Object obj1) { return (obj0 instanceof BigDecimal || obj1 instanceof BigDecimal); } } public static final class BigIntegerDelegate extends ELArithmetic { @Override protected Number add(Number num0, Number num1) { return ((BigInteger) num0).add((BigInteger) num1); } @Override protected Number coerce(Number num) { if (num instanceof BigInteger) return num; return new BigInteger(num.toString()); } @Override protected Number coerce(String str) { return new BigInteger(str); } @Override protected Number divide(Number num0, Number num1) { return (new BigDecimal((BigInteger) num0)).divide(new BigDecimal((BigInteger) num1), BigDecimal.ROUND_HALF_UP); } @Override protected Number multiply(Number num0, Number num1) { return ((BigInteger) num0).multiply((BigInteger) num1); } @Override protected Number mod(Number num0, Number num1) { return ((BigInteger) num0).mod((BigInteger) num1); } @Override protected Number subtract(Number num0, Number num1) { return ((BigInteger) num0).subtract((BigInteger) num1); } @Override public boolean matches(Object obj0, Object obj1) { return (obj0 instanceof BigInteger || obj1 instanceof BigInteger); } } public static final class DoubleDelegate extends ELArithmetic { @Override protected Number add(Number num0, Number num1) { // could only be one of these if (num0 instanceof BigDecimal) { return ((BigDecimal) num0).add(new BigDecimal(num1.doubleValue())); } else if (num1 instanceof BigDecimal) { return ((new BigDecimal(num0.doubleValue()).add((BigDecimal) num1))); } return new Double(num0.doubleValue() + num1.doubleValue()); } @Override protected Number coerce(Number num) { if (num instanceof Double) return num; if (num instanceof BigInteger) return new BigDecimal((BigInteger) num); return new Double(num.doubleValue()); } @Override protected Number coerce(String str) { return new Double(str); } @Override protected Number divide(Number num0, Number num1) { return new Double(num0.doubleValue() / num1.doubleValue()); } @Override protected Number mod(Number num0, Number num1) { return new Double(num0.doubleValue() % num1.doubleValue()); } @Override protected Number subtract(Number num0, Number num1) { // could only be one of these if (num0 instanceof BigDecimal) { return ((BigDecimal) num0).subtract(new BigDecimal(num1.doubleValue())); } else if (num1 instanceof BigDecimal) { return ((new BigDecimal(num0.doubleValue()).subtract((BigDecimal) num1))); } return new Double(num0.doubleValue() - num1.doubleValue()); } @Override protected Number multiply(Number num0, Number num1) { // could only be one of these if (num0 instanceof BigDecimal) { return ((BigDecimal) num0).multiply(new BigDecimal(num1.doubleValue())); } else if (num1 instanceof BigDecimal) { return ((new BigDecimal(num0.doubleValue()).multiply((BigDecimal) num1))); } return new Double(num0.doubleValue() * num1.doubleValue()); } @Override public boolean matches(Object obj0, Object obj1) { return (obj0 instanceof Double || obj1 instanceof Double || obj0 instanceof Float || obj1 instanceof Float || (obj0 instanceof String && ELSupport .isStringFloat((String) obj0)) || (obj1 instanceof String && ELSupport .isStringFloat((String) obj1))); } } public static final class LongDelegate extends ELArithmetic { @Override protected Number add(Number num0, Number num1) { return Long.valueOf(num0.longValue() + num1.longValue()); } @Override protected Number coerce(Number num) { if (num instanceof Long) return num; return Long.valueOf(num.longValue()); } @Override protected Number coerce(String str) { return Long.valueOf(str); } @Override protected Number divide(Number num0, Number num1) { return Long.valueOf(num0.longValue() / num1.longValue()); } @Override protected Number mod(Number num0, Number num1) { return Long.valueOf(num0.longValue() % num1.longValue()); } @Override protected Number subtract(Number num0, Number num1) { return Long.valueOf(num0.longValue() - num1.longValue()); } @Override protected Number multiply(Number num0, Number num1) { return Long.valueOf(num0.longValue() * num1.longValue()); } @Override public boolean matches(Object obj0, Object obj1) { return (obj0 instanceof Long || obj1 instanceof Long); } } public static final BigDecimalDelegate BIGDECIMAL = new BigDecimalDelegate(); public static final BigIntegerDelegate BIGINTEGER = new BigIntegerDelegate(); public static final DoubleDelegate DOUBLE = new DoubleDelegate(); public static final LongDelegate LONG = new LongDelegate(); private static final Long ZERO = Long.valueOf(0); public static final Number add(final Object obj0, final Object obj1) { if (obj0 == null && obj1 == null) { return Long.valueOf(0); } final ELArithmetic delegate; if (BIGDECIMAL.matches(obj0, obj1)) delegate = BIGDECIMAL; else if (DOUBLE.matches(obj0, obj1)) { if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGDECIMAL; else delegate = DOUBLE; } else if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGINTEGER; else delegate = LONG; Number num0 = delegate.coerce(obj0); Number num1 = delegate.coerce(obj1); return delegate.add(num0, num1); } public static final Number mod(final Object obj0, final Object obj1) { if (obj0 == null && obj1 == null) { return Long.valueOf(0); } final ELArithmetic delegate; if (BIGDECIMAL.matches(obj0, obj1)) delegate = DOUBLE; else if (DOUBLE.matches(obj0, obj1)) delegate = DOUBLE; else if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGINTEGER; else delegate = LONG; Number num0 = delegate.coerce(obj0); Number num1 = delegate.coerce(obj1); return delegate.mod(num0, num1); } public static final Number subtract(final Object obj0, final Object obj1) { if (obj0 == null && obj1 == null) { return Long.valueOf(0); } final ELArithmetic delegate; if (BIGDECIMAL.matches(obj0, obj1)) delegate = BIGDECIMAL; else if (DOUBLE.matches(obj0, obj1)) { if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGDECIMAL; else delegate = DOUBLE; } else if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGINTEGER; else delegate = LONG; Number num0 = delegate.coerce(obj0); Number num1 = delegate.coerce(obj1); return delegate.subtract(num0, num1); } public static final Number divide(final Object obj0, final Object obj1) { if (obj0 == null && obj1 == null) { return ZERO; } final ELArithmetic delegate; if (BIGDECIMAL.matches(obj0, obj1)) delegate = BIGDECIMAL; else if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGDECIMAL; else delegate = DOUBLE; Number num0 = delegate.coerce(obj0); Number num1 = delegate.coerce(obj1); return delegate.divide(num0, num1); } public static final Number multiply(final Object obj0, final Object obj1) { if (obj0 == null && obj1 == null) { return Long.valueOf(0); } final ELArithmetic delegate; if (BIGDECIMAL.matches(obj0, obj1)) delegate = BIGDECIMAL; else if (DOUBLE.matches(obj0, obj1)) { if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGDECIMAL; else delegate = DOUBLE; } else if (BIGINTEGER.matches(obj0, obj1)) delegate = BIGINTEGER; else delegate = LONG; Number num0 = delegate.coerce(obj0); Number num1 = delegate.coerce(obj1); return delegate.multiply(num0, num1); } public static final boolean isNumber(final Object obj) { return (obj != null && isNumberType(obj.getClass())); } public static final boolean isNumberType(final Class type) { return type == Long.TYPE || type == Double.TYPE || type == Byte.TYPE || type == Short.TYPE || type == Integer.TYPE || type == Float.TYPE || Number.class.isAssignableFrom(type); } /** * */ protected ELArithmetic() { super(); } protected abstract Number add(final Number num0, final Number num1); protected abstract Number multiply(final Number num0, final Number num1); protected abstract Number subtract(final Number num0, final Number num1); protected abstract Number mod(final Number num0, final Number num1); protected abstract Number coerce(final Number num); protected final Number coerce(final Object obj) { if (isNumber(obj)) { return coerce((Number) obj); } if (obj == null || "".equals(obj)) { return coerce(ZERO); } if (obj instanceof String) { return coerce((String) obj); } if (obj instanceof Character) { return coerce(Short.valueOf((short) ((Character) obj).charValue())); } throw new IllegalArgumentException(MessageFactory.get("error.convert", obj, obj.getClass(), "Number")); } protected abstract Number coerce(final String str); protected abstract Number divide(final Number num0, final Number num1); protected abstract boolean matches(final Object obj0, final Object obj1); } tomcat7-7.0.52/java/org/apache/el/lang/ExpressionBuilder.java0000644000175100017510000002054312271461077023741 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import java.io.StringReader; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import javax.el.ELContext; import javax.el.ELException; import javax.el.FunctionMapper; import javax.el.MethodExpression; import javax.el.ValueExpression; import javax.el.VariableMapper; import org.apache.el.MethodExpressionImpl; import org.apache.el.MethodExpressionLiteral; import org.apache.el.ValueExpressionImpl; import org.apache.el.parser.AstDeferredExpression; import org.apache.el.parser.AstDynamicExpression; import org.apache.el.parser.AstFunction; import org.apache.el.parser.AstIdentifier; import org.apache.el.parser.AstLiteralExpression; import org.apache.el.parser.AstValue; import org.apache.el.parser.ELParser; import org.apache.el.parser.Node; import org.apache.el.parser.NodeVisitor; import org.apache.el.util.ConcurrentCache; import org.apache.el.util.MessageFactory; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class ExpressionBuilder implements NodeVisitor { private static final int CACHE_SIZE; private static final String CACHE_SIZE_PROP = "org.apache.el.ExpressionBuilder.CACHE_SIZE"; static { if (System.getSecurityManager() == null) { CACHE_SIZE = Integer.parseInt( System.getProperty(CACHE_SIZE_PROP, "5000")); } else { CACHE_SIZE = AccessController.doPrivileged( new PrivilegedAction() { @Override public Integer run() { return Integer.valueOf( System.getProperty(CACHE_SIZE_PROP, "5000")); } }).intValue(); } } private static final ConcurrentCache cache = new ConcurrentCache(CACHE_SIZE); private FunctionMapper fnMapper; private VariableMapper varMapper; private String expression; /** * */ public ExpressionBuilder(String expression, ELContext ctx) throws ELException { this.expression = expression; FunctionMapper ctxFn = ctx.getFunctionMapper(); VariableMapper ctxVar = ctx.getVariableMapper(); if (ctxFn != null) { this.fnMapper = new FunctionMapperFactory(ctxFn); } if (ctxVar != null) { this.varMapper = new VariableMapperFactory(ctxVar); } } public static final Node createNode(String expr) throws ELException { Node n = createNodeInternal(expr); return n; } private static final Node createNodeInternal(String expr) throws ELException { if (expr == null) { throw new ELException(MessageFactory.get("error.null")); } Node n = cache.get(expr); if (n == null) { try { n = (new ELParser(new StringReader(expr))) .CompositeExpression(); // validate composite expression int numChildren = n.jjtGetNumChildren(); if (numChildren == 1) { n = n.jjtGetChild(0); } else { Class type = null; Node child = null; for (int i = 0; i < numChildren; i++) { child = n.jjtGetChild(i); if (child instanceof AstLiteralExpression) continue; if (type == null) type = child.getClass(); else { if (!type.equals(child.getClass())) { throw new ELException(MessageFactory.get( "error.mixed", expr)); } } } } if (n instanceof AstDeferredExpression || n instanceof AstDynamicExpression) { n = n.jjtGetChild(0); } cache.put(expr, n); } catch (Exception e) { throw new ELException( MessageFactory.get("error.parseFail", expr), e); } } return n; } private void prepare(Node node) throws ELException { try { node.accept(this); } catch (Exception e) { if (e instanceof ELException) { throw (ELException) e; } else { throw (new ELException(e)); } } if (this.fnMapper instanceof FunctionMapperFactory) { this.fnMapper = ((FunctionMapperFactory) this.fnMapper).create(); } if (this.varMapper instanceof VariableMapperFactory) { this.varMapper = ((VariableMapperFactory) this.varMapper).create(); } } private Node build() throws ELException { Node n = createNodeInternal(this.expression); this.prepare(n); if (n instanceof AstDeferredExpression || n instanceof AstDynamicExpression) { n = n.jjtGetChild(0); } return n; } /* * (non-Javadoc) * * @see com.sun.el.parser.NodeVisitor#visit(com.sun.el.parser.Node) */ @Override public void visit(Node node) throws ELException { if (node instanceof AstFunction) { AstFunction funcNode = (AstFunction) node; if (this.fnMapper == null) { throw new ELException(MessageFactory.get("error.fnMapper.null")); } Method m = fnMapper.resolveFunction(funcNode.getPrefix(), funcNode .getLocalName()); if (m == null) { throw new ELException(MessageFactory.get( "error.fnMapper.method", funcNode.getOutputName())); } int pcnt = m.getParameterTypes().length; if (node.jjtGetNumChildren() != pcnt) { throw new ELException(MessageFactory.get( "error.fnMapper.paramcount", funcNode.getOutputName(), "" + pcnt, "" + node.jjtGetNumChildren())); } } else if (node instanceof AstIdentifier && this.varMapper != null) { String variable = ((AstIdentifier) node).getImage(); // simply capture it this.varMapper.resolveVariable(variable); } } public ValueExpression createValueExpression(Class expectedType) throws ELException { Node n = this.build(); return new ValueExpressionImpl(this.expression, n, this.fnMapper, this.varMapper, expectedType); } public MethodExpression createMethodExpression(Class expectedReturnType, Class[] expectedParamTypes) throws ELException { Node n = this.build(); if (!n.isParametersProvided() && expectedParamTypes == null) { throw new NullPointerException(MessageFactory .get("error.method.nullParms")); } if (n instanceof AstValue || n instanceof AstIdentifier) { return new MethodExpressionImpl(expression, n, this.fnMapper, this.varMapper, expectedReturnType, expectedParamTypes); } else if (n instanceof AstLiteralExpression) { return new MethodExpressionLiteral(expression, expectedReturnType, expectedParamTypes); } else { throw new ELException("Not a Valid Method Expression: " + expression); } } } tomcat7-7.0.52/java/org/apache/el/lang/FunctionMapperFactory.java0000644000175100017510000000353212271461077024554 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.lang; import java.lang.reflect.Method; import javax.el.FunctionMapper; /** * @author Jacob Hookom [jacob@hookom.net] */ public class FunctionMapperFactory extends FunctionMapper { protected FunctionMapperImpl memento = null; protected FunctionMapper target; public FunctionMapperFactory(FunctionMapper mapper) { if (mapper == null) { throw new NullPointerException("FunctionMapper target cannot be null"); } this.target = mapper; } /* (non-Javadoc) * @see javax.el.FunctionMapper#resolveFunction(java.lang.String, java.lang.String) */ @Override public Method resolveFunction(String prefix, String localName) { if (this.memento == null) { this.memento = new FunctionMapperImpl(); } Method m = this.target.resolveFunction(prefix, localName); if (m != null) { this.memento.addFunction(prefix, localName, m); } return m; } public FunctionMapper create() { return this.memento; } } tomcat7-7.0.52/java/org/apache/el/ExpressionFactoryImpl.java0000644000175100017510000000510612271461077023661 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el; import javax.el.ELContext; import javax.el.ExpressionFactory; import javax.el.MethodExpression; import javax.el.ValueExpression; import org.apache.el.lang.ELSupport; import org.apache.el.lang.ExpressionBuilder; import org.apache.el.util.MessageFactory; /** * @see javax.el.ExpressionFactory * * @author Jacob Hookom [jacob@hookom.net] */ public class ExpressionFactoryImpl extends ExpressionFactory { /** * */ public ExpressionFactoryImpl() { super(); } @Override public Object coerceToType(Object obj, Class type) { return ELSupport.coerceToType(obj, type); } @Override public MethodExpression createMethodExpression(ELContext context, String expression, Class expectedReturnType, Class[] expectedParamTypes) { ExpressionBuilder builder = new ExpressionBuilder(expression, context); return builder.createMethodExpression(expectedReturnType, expectedParamTypes); } @Override public ValueExpression createValueExpression(ELContext context, String expression, Class expectedType) { if (expectedType == null) { throw new NullPointerException(MessageFactory .get("error.value.expectedType")); } ExpressionBuilder builder = new ExpressionBuilder(expression, context); return builder.createValueExpression(expectedType); } @Override public ValueExpression createValueExpression(Object instance, Class expectedType) { if (expectedType == null) { throw new NullPointerException(MessageFactory .get("error.value.expectedType")); } return new ValueExpressionLiteral(instance, expectedType); } } tomcat7-7.0.52/java/org/apache/el/ValueExpressionImpl.java0000644000175100017510000002147712271461077023337 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import javax.el.ELContext; import javax.el.ELException; import javax.el.FunctionMapper; import javax.el.PropertyNotFoundException; import javax.el.PropertyNotWritableException; import javax.el.ValueExpression; import javax.el.ValueReference; import javax.el.VariableMapper; import org.apache.el.lang.ELSupport; import org.apache.el.lang.EvaluationContext; import org.apache.el.lang.ExpressionBuilder; import org.apache.el.parser.AstLiteralExpression; import org.apache.el.parser.Node; import org.apache.el.util.ReflectionUtil; /** * An Expression that can get or set a value. * *

    * In previous incarnations of this API, expressions could only be read. * ValueExpression objects can now be used both to retrieve a * value and to set a value. Expressions that can have a value set on them are * referred to as l-value expressions. Those that cannot are referred to as * r-value expressions. Not all r-value expressions can be used as l-value * expressions (e.g. "${1+1}" or * "${firstName} ${lastName}"). See the EL Specification for * details. Expressions that cannot be used as l-values must always return * true from isReadOnly(). *

    * *

    * The {@link javax.el.ExpressionFactory#createValueExpression} method * can be used to parse an expression string and return a concrete instance * of ValueExpression that encapsulates the parsed expression. * The {@link FunctionMapper} is used at parse time, not evaluation time, * so one is not needed to evaluate an expression using this class. * However, the {@link ELContext} is needed at evaluation time.

    * *

    The {@link #getValue}, {@link #setValue}, {@link #isReadOnly} and * {@link #getType} methods will evaluate the expression each time they are * called. The {@link javax.el.ELResolver} in the ELContext is used * to resolve the top-level variables and to determine the behavior of the * . and [] operators. For any of the four methods, * the {@link javax.el.ELResolver#getValue} method is used to resolve all * properties up to but excluding the last one. This provides the * base object. At the last resolution, the * ValueExpression will call the corresponding * {@link javax.el.ELResolver#getValue}, {@link javax.el.ELResolver#setValue}, * {@link javax.el.ELResolver#isReadOnly} or {@link javax.el.ELResolver#getType} * method, depending on which was called on the ValueExpression. *

    * *

    See the notes about comparison, serialization and immutability in * the {@link javax.el.Expression} javadocs. * * @see javax.el.ELResolver * @see javax.el.Expression * @see javax.el.ExpressionFactory * @see javax.el.ValueExpression * * @author Jacob Hookom [jacob@hookom.net] */ public final class ValueExpressionImpl extends ValueExpression implements Externalizable { private Class expectedType; private String expr; private FunctionMapper fnMapper; private VariableMapper varMapper; private transient Node node; public ValueExpressionImpl() { super(); } /** * */ public ValueExpressionImpl(String expr, Node node, FunctionMapper fnMapper, VariableMapper varMapper, Class expectedType) { this.expr = expr; this.node = node; this.fnMapper = fnMapper; this.varMapper = varMapper; this.expectedType = expectedType; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { return (obj instanceof ValueExpressionImpl && obj.hashCode() == this .hashCode()); } /* * (non-Javadoc) * * @see javax.el.ValueExpression#getExpectedType() */ @Override public Class getExpectedType() { return this.expectedType; } /** * Returns the type the result of the expression will be coerced to after * evaluation. * * @return the expectedType passed to the * ExpressionFactory.createValueExpression method * that created this ValueExpression. * * @see javax.el.Expression#getExpressionString() */ @Override public String getExpressionString() { return this.expr; } private Node getNode() throws ELException { if (this.node == null) { this.node = ExpressionBuilder.createNode(this.expr); } return this.node; } /* * (non-Javadoc) * * @see javax.el.ValueExpression#getType(javax.el.ELContext) */ @Override public Class getType(ELContext context) throws PropertyNotFoundException, ELException { EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, this.varMapper); return this.getNode().getType(ctx); } /* * (non-Javadoc) * * @see javax.el.ValueExpression#getValue(javax.el.ELContext) */ @Override public Object getValue(ELContext context) throws PropertyNotFoundException, ELException { EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, this.varMapper); Object value = this.getNode().getValue(ctx); if (this.expectedType != null) { return ELSupport.coerceToType(value, this.expectedType); } return value; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return this.getNode().hashCode(); } /* * (non-Javadoc) * * @see javax.el.ValueExpression#isLiteralText() */ @Override public boolean isLiteralText() { try { return this.getNode() instanceof AstLiteralExpression; } catch (ELException ele) { return false; } } /* * (non-Javadoc) * * @see javax.el.ValueExpression#isReadOnly(javax.el.ELContext) */ @Override public boolean isReadOnly(ELContext context) throws PropertyNotFoundException, ELException { EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, this.varMapper); return this.getNode().isReadOnly(ctx); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.expr = in.readUTF(); String type = in.readUTF(); if (!"".equals(type)) { this.expectedType = ReflectionUtil.forName(type); } this.fnMapper = (FunctionMapper) in.readObject(); this.varMapper = (VariableMapper) in.readObject(); } /* * (non-Javadoc) * * @see javax.el.ValueExpression#setValue(javax.el.ELContext, * java.lang.Object) */ @Override public void setValue(ELContext context, Object value) throws PropertyNotFoundException, PropertyNotWritableException, ELException { EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, this.varMapper); this.getNode().setValue(ctx, value); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(this.expr); out.writeUTF((this.expectedType != null) ? this.expectedType.getName() : ""); out.writeObject(this.fnMapper); out.writeObject(this.varMapper); } @Override public String toString() { return "ValueExpression["+this.expr+"]"; } /** * @since EL 2.2 */ @Override public ValueReference getValueReference(ELContext context) { EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, this.varMapper); return this.getNode().getValueReference(ctx); } } tomcat7-7.0.52/java/org/apache/el/parser/0000755000175100017510000000000012301126371017764 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/el/parser/AstString.java0000644000175100017510000000434312271461077022564 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstString.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstString extends SimpleNode { public AstString(int id) { super(id); } private volatile String string; public String getString() { if (this.string == null) { this.string = this.image.substring(1, this.image.length() - 1); } return this.string; } @Override public Class getType(EvaluationContext ctx) throws ELException { return String.class; } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.getString(); } @Override public void setImage(String image) { if (image.indexOf('\\') == -1) { this.image = image; return; } int size = image.length(); StringBuilder buf = new StringBuilder(size); for (int i = 0; i < size; i++) { char c = image.charAt(i); if (c == '\\' && i + 1 < size) { char c1 = image.charAt(i + 1); if (c1 == '\\' || c1 == '"' || c1 == '\'') { c = c1; i++; } } buf.append(c); } this.image = buf.toString(); } } tomcat7-7.0.52/java/org/apache/el/parser/AstValue.java0000644000175100017510000003157512271461077022401 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstValue.java */ package org.apache.el.parser; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import javax.el.ELException; import javax.el.ELResolver; import javax.el.MethodInfo; import javax.el.PropertyNotFoundException; import javax.el.ValueReference; import org.apache.el.lang.ELSupport; import org.apache.el.lang.EvaluationContext; import org.apache.el.util.MessageFactory; import org.apache.el.util.ReflectionUtil; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstValue extends SimpleNode { private static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); protected static final boolean COERCE_TO_ZERO; static { if (IS_SECURITY_ENABLED) { COERCE_TO_ZERO = AccessController.doPrivileged( new PrivilegedAction(){ @Override public Boolean run() { return Boolean.valueOf(System.getProperty( "org.apache.el.parser.COERCE_TO_ZERO", "true")); } } ).booleanValue(); } else { COERCE_TO_ZERO = Boolean.valueOf(System.getProperty( "org.apache.el.parser.COERCE_TO_ZERO", "true")).booleanValue(); } } protected static class Target { protected Object base; protected Object property; } public AstValue(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { Target t = getTarget(ctx); ctx.setPropertyResolved(false); Class result = ctx.getELResolver().getType(ctx, t.base, t.property); if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled", t.base, t.property)); } return result; } private final Target getTarget(EvaluationContext ctx) throws ELException { // evaluate expr-a to value-a Object base = this.children[0].getValue(ctx); // if our base is null (we know there are more properties to evaluate) if (base == null) { throw new PropertyNotFoundException(MessageFactory.get( "error.unreachable.base", this.children[0].getImage())); } // set up our start/end Object property = null; int propCount = this.jjtGetNumChildren(); int i = 1; // Evaluate any properties or methods before our target ELResolver resolver = ctx.getELResolver(); while (i < propCount) { if (i + 2 < propCount && this.children[i + 1] instanceof AstMethodParameters) { // Method call not at end of expression base = resolver.invoke(ctx, base, this.children[i].getValue(ctx), null, ((AstMethodParameters) this.children[i + 1]).getParameters(ctx)); i += 2; } else if (i + 2 == propCount && this.children[i + 1] instanceof AstMethodParameters) { // Method call at end of expression ctx.setPropertyResolved(false); property = this.children[i].getValue(ctx); i += 2; if (property == null) { throw new PropertyNotFoundException(MessageFactory.get( "error.unreachable.property", property)); } } else if (i + 1 < propCount) { // Object with property not at end of expression property = this.children[i].getValue(ctx); ctx.setPropertyResolved(false); base = resolver.getValue(ctx, base, property); i++; } else { // Object with property at end of expression ctx.setPropertyResolved(false); property = this.children[i].getValue(ctx); i++; if (property == null) { throw new PropertyNotFoundException(MessageFactory.get( "error.unreachable.property", property)); } } if (base == null) { throw new PropertyNotFoundException(MessageFactory.get( "error.unreachable.property", property)); } } Target t = new Target(); t.base = base; t.property = property; return t; } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object base = this.children[0].getValue(ctx); int propCount = this.jjtGetNumChildren(); int i = 1; Object suffix = null; ELResolver resolver = ctx.getELResolver(); while (base != null && i < propCount) { suffix = this.children[i].getValue(ctx); if (i + 1 < propCount && (this.children[i+1] instanceof AstMethodParameters)) { AstMethodParameters mps = (AstMethodParameters) this.children[i+1]; // This is a method base = resolver.invoke(ctx, base, suffix, null, mps.getParameters(ctx)); i+=2; } else { // This is a property if (suffix == null) { return null; } ctx.setPropertyResolved(false); base = resolver.getValue(ctx, base, suffix); i++; } } if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled", base, suffix)); } return base; } @Override public boolean isReadOnly(EvaluationContext ctx) throws ELException { Target t = getTarget(ctx); ctx.setPropertyResolved(false); boolean result = ctx.getELResolver().isReadOnly(ctx, t.base, t.property); if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled", t.base, t.property)); } return result; } @Override public void setValue(EvaluationContext ctx, Object value) throws ELException { Target t = getTarget(ctx); ctx.setPropertyResolved(false); ELResolver resolver = ctx.getELResolver(); // coerce to the expected type Class targetClass = resolver.getType(ctx, t.base, t.property); if (COERCE_TO_ZERO == true || !isAssignable(value, targetClass)) { resolver.setValue(ctx, t.base, t.property, ELSupport.coerceToType(value, targetClass)); } else { resolver.setValue(ctx, t.base, t.property, value); } if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled", t.base, t.property)); } } private boolean isAssignable(Object value, Class targetClass) { if (targetClass == null) { return false; } else if (value != null && targetClass.isPrimitive()) { return false; } else if (value != null && !targetClass.isInstance(value)) { return false; } return true; } @Override // Interface el.parser.Node uses raw types (and is auto-generated) public MethodInfo getMethodInfo(EvaluationContext ctx, @SuppressWarnings("rawtypes") Class[] paramTypes) throws ELException { Target t = getTarget(ctx); Method m = ReflectionUtil.getMethod( t.base, t.property, paramTypes, null); return new MethodInfo(m.getName(), m.getReturnType(), m .getParameterTypes()); } @Override // Interface el.parser.Node uses a raw type (and is auto-generated) public Object invoke(EvaluationContext ctx, @SuppressWarnings("rawtypes") Class[] paramTypes, Object[] paramValues) throws ELException { Target t = getTarget(ctx); Method m = null; Object[] values = null; Class[] types = null; if (isParametersProvided()) { values = ((AstMethodParameters) this.jjtGetChild( this.jjtGetNumChildren() - 1)).getParameters(ctx); types = getTypesFromValues(values); } else { values = paramValues; types = paramTypes; } m = ReflectionUtil.getMethod(t.base, t.property, types, values); // Handle varArgs and any co-ercion required values = convertArgs(values, m); Object result = null; try { result = m.invoke(t.base, values); } catch (IllegalAccessException iae) { throw new ELException(iae); } catch (IllegalArgumentException iae) { throw new ELException(iae); } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof ThreadDeath) { throw (ThreadDeath) cause; } if (cause instanceof VirtualMachineError) { throw (VirtualMachineError) cause; } throw new ELException(cause); } return result; } private Object[] convertArgs(Object[] src, Method m) { Class[] types = m.getParameterTypes(); if (types.length == 0) { return new Object[0]; } int paramCount = types.length; Object[] dest = new Object[paramCount]; for (int i = 0; i < paramCount - 1; i++) { dest[i] = ELSupport.coerceToType(src[i], types[i]); } if (m.isVarArgs()) { Object[] varArgs = (Object[]) Array.newInstance( m.getParameterTypes()[paramCount - 1].getComponentType(), src.length - (paramCount - 1)); for (int i = 0; i < src.length - (paramCount - 1); i ++) { varArgs[i] = ELSupport.coerceToType(src[paramCount - 1 + i], types[paramCount - 1].getComponentType()); } dest[paramCount - 1] = varArgs; } else { dest[paramCount - 1] = ELSupport.coerceToType( src[paramCount - 1], types[paramCount - 1]); } return dest; } private Class[] getTypesFromValues(Object[] values) { if (values == null) { return null; } Class result[] = new Class[values.length]; for (int i = 0; i < values.length; i++) { if (values[i] == null) { result[i] = null; } else { result[i] = values[i].getClass(); } } return result; } /** * @since EL 2.2 */ @Override public ValueReference getValueReference(EvaluationContext ctx) { // Check this is a reference to a base and a property if (this.children.length > 2 && this.jjtGetChild(2) instanceof AstMethodParameters) { // This is a method call return null; } Target t = getTarget(ctx); return new ValueReference(t.base, t.property); } /** * @since EL 2.2 */ @Override public boolean isParametersProvided() { // Assumption is that method parameters, if present, will be the last // child int len = children.length; if (len > 2) { if (this.jjtGetChild(len - 1) instanceof AstMethodParameters) { return true; } } return false; } } tomcat7-7.0.52/java/org/apache/el/parser/AstGreaterThan.java0000644000175100017510000000305412271461077023520 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstGreaterThan.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstGreaterThan extends BooleanNode { public AstGreaterThan(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); if (obj0 == null) { return Boolean.FALSE; } Object obj1 = this.children[1].getValue(ctx); if (obj1 == null) { return Boolean.FALSE; } return (compare(obj0, obj1) > 0) ? Boolean.TRUE : Boolean.FALSE; } } tomcat7-7.0.52/java/org/apache/el/parser/AstDeferredExpression.java0000644000175100017510000000340012271461077025107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstDeferredExpression.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstDeferredExpression extends SimpleNode { public AstDeferredExpression(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return this.children[0].getType(ctx); } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.children[0].getValue(ctx); } @Override public boolean isReadOnly(EvaluationContext ctx) throws ELException { return this.children[0].isReadOnly(ctx); } @Override public void setValue(EvaluationContext ctx, Object value) throws ELException { this.children[0].setValue(ctx, value); } } tomcat7-7.0.52/java/org/apache/el/parser/AstCompositeExpression.java0000644000175100017510000000347012271461077025340 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstCompositeExpression.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.ELSupport; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstCompositeExpression extends SimpleNode { public AstCompositeExpression(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return String.class; } @Override public Object getValue(EvaluationContext ctx) throws ELException { StringBuilder sb = new StringBuilder(16); Object obj = null; if (this.children != null) { for (int i = 0; i < this.children.length; i++) { obj = this.children[i].getValue(ctx); if (obj != null) { sb.append(ELSupport.coerceToString(obj)); } } } return sb.toString(); } } tomcat7-7.0.52/java/org/apache/el/parser/ELParserConstants.java0000644000175100017510000000763212271461077024224 0ustar locutuslocutus/* Generated By:JJTree&JavaCC: Do not edit this line. ELParserConstants.java */ package org.apache.el.parser; /** * Token literal values and constants. * Generated by org.javacc.parser.OtherFilesGen#start() */ public interface ELParserConstants { /** End of File. */ int EOF = 0; /** RegularExpression Id. */ int LITERAL_EXPRESSION = 1; /** RegularExpression Id. */ int START_DYNAMIC_EXPRESSION = 2; /** RegularExpression Id. */ int START_DEFERRED_EXPRESSION = 3; /** RegularExpression Id. */ int INTEGER_LITERAL = 8; /** RegularExpression Id. */ int FLOATING_POINT_LITERAL = 9; /** RegularExpression Id. */ int EXPONENT = 10; /** RegularExpression Id. */ int STRING_LITERAL = 11; /** RegularExpression Id. */ int TRUE = 12; /** RegularExpression Id. */ int FALSE = 13; /** RegularExpression Id. */ int NULL = 14; /** RegularExpression Id. */ int END_EXPRESSION = 15; /** RegularExpression Id. */ int DOT = 16; /** RegularExpression Id. */ int LPAREN = 17; /** RegularExpression Id. */ int RPAREN = 18; /** RegularExpression Id. */ int LBRACK = 19; /** RegularExpression Id. */ int RBRACK = 20; /** RegularExpression Id. */ int COLON = 21; /** RegularExpression Id. */ int COMMA = 22; /** RegularExpression Id. */ int GT0 = 23; /** RegularExpression Id. */ int GT1 = 24; /** RegularExpression Id. */ int LT0 = 25; /** RegularExpression Id. */ int LT1 = 26; /** RegularExpression Id. */ int GE0 = 27; /** RegularExpression Id. */ int GE1 = 28; /** RegularExpression Id. */ int LE0 = 29; /** RegularExpression Id. */ int LE1 = 30; /** RegularExpression Id. */ int EQ0 = 31; /** RegularExpression Id. */ int EQ1 = 32; /** RegularExpression Id. */ int NE0 = 33; /** RegularExpression Id. */ int NE1 = 34; /** RegularExpression Id. */ int NOT0 = 35; /** RegularExpression Id. */ int NOT1 = 36; /** RegularExpression Id. */ int AND0 = 37; /** RegularExpression Id. */ int AND1 = 38; /** RegularExpression Id. */ int OR0 = 39; /** RegularExpression Id. */ int OR1 = 40; /** RegularExpression Id. */ int EMPTY = 41; /** RegularExpression Id. */ int INSTANCEOF = 42; /** RegularExpression Id. */ int MULT = 43; /** RegularExpression Id. */ int PLUS = 44; /** RegularExpression Id. */ int MINUS = 45; /** RegularExpression Id. */ int QUESTIONMARK = 46; /** RegularExpression Id. */ int DIV0 = 47; /** RegularExpression Id. */ int DIV1 = 48; /** RegularExpression Id. */ int MOD0 = 49; /** RegularExpression Id. */ int MOD1 = 50; /** RegularExpression Id. */ int IDENTIFIER = 51; /** RegularExpression Id. */ int FUNCTIONSUFFIX = 52; /** RegularExpression Id. */ int IMPL_OBJ_START = 53; /** RegularExpression Id. */ int LETTER = 54; /** RegularExpression Id. */ int DIGIT = 55; /** RegularExpression Id. */ int ILLEGAL_CHARACTER = 56; /** Lexical state. */ int DEFAULT = 0; /** Lexical state. */ int IN_EXPRESSION = 1; /** Literal token values. */ String[] tokenImage = { "", "", "\"${\"", "\"#{\"", "\" \"", "\"\\t\"", "\"\\n\"", "\"\\r\"", "", "", "", "", "\"true\"", "\"false\"", "\"null\"", "\"}\"", "\".\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\":\"", "\",\"", "\">\"", "\"gt\"", "\"<\"", "\"lt\"", "\">=\"", "\"ge\"", "\"<=\"", "\"le\"", "\"==\"", "\"eq\"", "\"!=\"", "\"ne\"", "\"!\"", "\"not\"", "\"&&\"", "\"and\"", "\"||\"", "\"or\"", "\"empty\"", "\"instanceof\"", "\"*\"", "\"+\"", "\"-\"", "\"?\"", "\"/\"", "\"div\"", "\"%\"", "\"mod\"", "", "", "\"#\"", "", "", "", }; } tomcat7-7.0.52/java/org/apache/el/parser/BooleanNode.java0000644000175100017510000000232212271461077023026 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public class BooleanNode extends SimpleNode { /** * @param i */ public BooleanNode(int i) { super(i); } @Override public Class getType(EvaluationContext ctx) throws ELException { return Boolean.class; } } tomcat7-7.0.52/java/org/apache/el/parser/TokenMgrError.java0000644000175100017510000001061412271461077023404 0ustar locutuslocutus/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */ /* JavaCCOptions: */ package org.apache.el.parser; /** Token Manager Error. */ @SuppressWarnings("all") // Ignore warnings in generated code public class TokenMgrError extends Error { /** * The version identifier for this Serializable class. * Increment only if the serialized form of the * class changes. */ private static final long serialVersionUID = 1L; /* * Ordinals for various reasons why an Error of this type can be thrown. */ /** * Lexical error occurred. */ static final int LEXICAL_ERROR = 0; /** * An attempt was made to create a second instance of a static token manager. */ static final int STATIC_LEXER_ERROR = 1; /** * Tried to change to an invalid lexical state. */ static final int INVALID_LEXICAL_STATE = 2; /** * Detected (and bailed out of) an infinite loop in the token manager. */ static final int LOOP_DETECTED = 3; /** * Indicates the reason why the exception is thrown. It will have * one of the above 4 values. */ int errorCode; /** * Replaces unprintable characters by their escaped (or unicode escaped) * equivalents in the given string */ protected static final String addEscapes(String str) { StringBuffer retval = new StringBuffer(); char ch; for (int i = 0; i < str.length(); i++) { switch (str.charAt(i)) { case 0 : continue; case '\b': retval.append("\\b"); continue; case '\t': retval.append("\\t"); continue; case '\n': retval.append("\\n"); continue; case '\f': retval.append("\\f"); continue; case '\r': retval.append("\\r"); continue; case '\"': retval.append("\\\""); continue; case '\'': retval.append("\\\'"); continue; case '\\': retval.append("\\\\"); continue; default: if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { String s = "0000" + Integer.toString(ch, 16); retval.append("\\u" + s.substring(s.length() - 4, s.length())); } else { retval.append(ch); } continue; } } return retval.toString(); } /** * Returns a detailed message for the Error when it is thrown by the * token manager to indicate a lexical error. * Parameters : * EOFSeen : indicates if EOF caused the lexical error * curLexState : lexical state in which this error occurred * errorLine : line number when the error occurred * errorColumn : column number when the error occurred * errorAfter : prefix that was seen before this error occurred * curchar : the offending character * Note: You can customize the lexical error message by modifying this method. */ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { return("Lexical error at line " + errorLine + ", column " + errorColumn + ". Encountered: " + (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + "after : \"" + addEscapes(errorAfter) + "\""); } /** * You can also modify the body of this method to customize your error messages. * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not * of end-users concern, so you can return something like : * * "Internal Error : Please file a bug report .... " * * from this method for such cases in the release version of your parser. */ public String getMessage() { return super.getMessage(); } /* * Constructors of various flavors follow. */ /** No arg constructor. */ public TokenMgrError() { } /** Constructor with message and reason. */ public TokenMgrError(String message, int reason) { super(message); errorCode = reason; } /** Full Constructor. */ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); } } /* JavaCC - OriginalChecksum=de3ff0bacfb0fe749cc8eaf56ae82fea (do not edit this line) */ tomcat7-7.0.52/java/org/apache/el/parser/AstOr.java0000644000175100017510000000271512271461077021677 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstOr.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstOr extends BooleanNode { public AstOr(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj = this.children[0].getValue(ctx); Boolean b = coerceToBoolean(obj); if (b.booleanValue()) { return b; } obj = this.children[1].getValue(ctx); b = coerceToBoolean(obj); return b; } } tomcat7-7.0.52/java/org/apache/el/parser/AstGreaterThanEqual.java0000644000175100017510000000311312271461077024504 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstGreaterThanEqual.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstGreaterThanEqual extends BooleanNode { public AstGreaterThanEqual(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); if (obj0 == obj1) { return Boolean.TRUE; } if (obj0 == null || obj1 == null) { return Boolean.FALSE; } return (compare(obj0, obj1) >= 0) ? Boolean.TRUE : Boolean.FALSE; } } tomcat7-7.0.52/java/org/apache/el/parser/ArithmeticNode.java0000644000175100017510000000233212271461077023541 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public class ArithmeticNode extends SimpleNode { /** * @param i */ public ArithmeticNode(int i) { super(i); } @Override public Class getType(EvaluationContext ctx) throws ELException { return Number.class; } } tomcat7-7.0.52/java/org/apache/el/parser/AstMult.java0000644000175100017510000000263312271461077022237 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstMult.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.ELArithmetic; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstMult extends ArithmeticNode { public AstMult(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); return ELArithmetic.multiply(obj0, obj1); } } tomcat7-7.0.52/java/org/apache/el/parser/AstLessThanEqual.java0000644000175100017510000000310212271461077024017 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstLessThanEqual.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstLessThanEqual extends BooleanNode { public AstLessThanEqual(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); if (obj0 == obj1) { return Boolean.TRUE; } if (obj0 == null || obj1 == null) { return Boolean.FALSE; } return (compare(obj0, obj1) <= 0) ? Boolean.TRUE : Boolean.FALSE; } } tomcat7-7.0.52/java/org/apache/el/parser/ELParser.java0000644000175100017510000017347512271461077022340 0ustar locutuslocutus/* Generated By:JJTree&JavaCC: Do not edit this line. ELParser.java */ package org.apache.el.parser; import java.io.StringReader; import javax.el.ELException; @SuppressWarnings("all") // Ignore warnings in generated code public class ELParser/*@bgen(jjtree)*/implements ELParserTreeConstants, ELParserConstants {/*@bgen(jjtree)*/ protected JJTELParserState jjtree = new JJTELParserState();public static Node parse(String ref) throws ELException { try { return (new ELParser(new StringReader(ref))).CompositeExpression(); } catch (ParseException pe) { throw new ELException(pe.getMessage()); } } /* * CompositeExpression * Allow most flexible parsing, restrict by examining * type of returned node */ final public AstCompositeExpression CompositeExpression() throws ParseException { /*@bgen(jjtree) CompositeExpression */ AstCompositeExpression jjtn000 = new AstCompositeExpression(JJTCOMPOSITEEXPRESSION); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000); try { label_1: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case LITERAL_EXPRESSION: case START_DYNAMIC_EXPRESSION: case START_DEFERRED_EXPRESSION: ; break; default: jj_la1[0] = jj_gen; break label_1; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case START_DEFERRED_EXPRESSION: DeferredExpression(); break; case START_DYNAMIC_EXPRESSION: DynamicExpression(); break; case LITERAL_EXPRESSION: LiteralExpression(); break; default: jj_la1[1] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } jj_consume_token(0); jjtree.closeNodeScope(jjtn000, true); jjtc000 = false; {if (true) return jjtn000;} } catch (Throwable jjte000) { if (jjtc000) { jjtree.clearNodeScope(jjtn000); jjtc000 = false; } else { jjtree.popNode(); } if (jjte000 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte000;} } if (jjte000 instanceof ParseException) { {if (true) throw (ParseException)jjte000;} } {if (true) throw (Error)jjte000;} } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } throw new Error("Missing return statement in function"); } /* * LiteralExpression * Non-EL Expression blocks */ final public void LiteralExpression() throws ParseException { /*@bgen(jjtree) LiteralExpression */ AstLiteralExpression jjtn000 = new AstLiteralExpression(JJTLITERALEXPRESSION); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000);Token t = null; try { t = jj_consume_token(LITERAL_EXPRESSION); jjtree.closeNodeScope(jjtn000, true); jjtc000 = false; jjtn000.setImage(t.image); } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * DeferredExpression * #{..} Expressions */ final public void DeferredExpression() throws ParseException { /*@bgen(jjtree) DeferredExpression */ AstDeferredExpression jjtn000 = new AstDeferredExpression(JJTDEFERREDEXPRESSION); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000); try { jj_consume_token(START_DEFERRED_EXPRESSION); Expression(); jj_consume_token(END_EXPRESSION); } catch (Throwable jjte000) { if (jjtc000) { jjtree.clearNodeScope(jjtn000); jjtc000 = false; } else { jjtree.popNode(); } if (jjte000 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte000;} } if (jjte000 instanceof ParseException) { {if (true) throw (ParseException)jjte000;} } {if (true) throw (Error)jjte000;} } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * DynamicExpression * ${..} Expressions */ final public void DynamicExpression() throws ParseException { /*@bgen(jjtree) DynamicExpression */ AstDynamicExpression jjtn000 = new AstDynamicExpression(JJTDYNAMICEXPRESSION); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000); try { jj_consume_token(START_DYNAMIC_EXPRESSION); Expression(); jj_consume_token(END_EXPRESSION); } catch (Throwable jjte000) { if (jjtc000) { jjtree.clearNodeScope(jjtn000); jjtc000 = false; } else { jjtree.popNode(); } if (jjte000 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte000;} } if (jjte000 instanceof ParseException) { {if (true) throw (ParseException)jjte000;} } {if (true) throw (Error)jjte000;} } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * Expression * EL Expression Language Root, goes to Choice */ final public void Expression() throws ParseException { Choice(); } /* * Choice * For Choice markup a ? b : c, then Or */ final public void Choice() throws ParseException { Or(); label_2: while (true) { if (jj_2_1(3)) { ; } else { break label_2; } jj_consume_token(QUESTIONMARK); Choice(); jj_consume_token(COLON); AstChoice jjtn001 = new AstChoice(JJTCHOICE); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { Choice(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, 3); } } } } /* * Or * For 'or' '||', then And */ final public void Or() throws ParseException { And(); label_3: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case OR0: case OR1: ; break; default: jj_la1[2] = jj_gen; break label_3; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case OR0: jj_consume_token(OR0); break; case OR1: jj_consume_token(OR1); break; default: jj_la1[3] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstOr jjtn001 = new AstOr(JJTOR); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { And(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, 2); } } } } /* * And * For 'and' '&&', then Equality */ final public void And() throws ParseException { Equality(); label_4: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case AND0: case AND1: ; break; default: jj_la1[4] = jj_gen; break label_4; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case AND0: jj_consume_token(AND0); break; case AND1: jj_consume_token(AND1); break; default: jj_la1[5] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstAnd jjtn001 = new AstAnd(JJTAND); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { Equality(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, 2); } } } } /* * Equality * For '==' 'eq' '!=' 'ne', then Compare */ final public void Equality() throws ParseException { Compare(); label_5: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EQ0: case EQ1: case NE0: case NE1: ; break; default: jj_la1[6] = jj_gen; break label_5; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EQ0: case EQ1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EQ0: jj_consume_token(EQ0); break; case EQ1: jj_consume_token(EQ1); break; default: jj_la1[7] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstEqual jjtn001 = new AstEqual(JJTEQUAL); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { Compare(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, 2); } } break; case NE0: case NE1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case NE0: jj_consume_token(NE0); break; case NE1: jj_consume_token(NE1); break; default: jj_la1[8] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstNotEqual jjtn002 = new AstNotEqual(JJTNOTEQUAL); boolean jjtc002 = true; jjtree.openNodeScope(jjtn002); try { Compare(); } catch (Throwable jjte002) { if (jjtc002) { jjtree.clearNodeScope(jjtn002); jjtc002 = false; } else { jjtree.popNode(); } if (jjte002 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte002;} } if (jjte002 instanceof ParseException) { {if (true) throw (ParseException)jjte002;} } {if (true) throw (Error)jjte002;} } finally { if (jjtc002) { jjtree.closeNodeScope(jjtn002, 2); } } break; default: jj_la1[9] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } } /* * Compare * For a bunch of them, then Math */ final public void Compare() throws ParseException { Math(); label_6: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case GT0: case GT1: case LT0: case LT1: case GE0: case GE1: case LE0: case LE1: ; break; default: jj_la1[10] = jj_gen; break label_6; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case LT0: case LT1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case LT0: jj_consume_token(LT0); break; case LT1: jj_consume_token(LT1); break; default: jj_la1[11] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstLessThan jjtn001 = new AstLessThan(JJTLESSTHAN); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { Math(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, 2); } } break; case GT0: case GT1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case GT0: jj_consume_token(GT0); break; case GT1: jj_consume_token(GT1); break; default: jj_la1[12] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstGreaterThan jjtn002 = new AstGreaterThan(JJTGREATERTHAN); boolean jjtc002 = true; jjtree.openNodeScope(jjtn002); try { Math(); } catch (Throwable jjte002) { if (jjtc002) { jjtree.clearNodeScope(jjtn002); jjtc002 = false; } else { jjtree.popNode(); } if (jjte002 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte002;} } if (jjte002 instanceof ParseException) { {if (true) throw (ParseException)jjte002;} } {if (true) throw (Error)jjte002;} } finally { if (jjtc002) { jjtree.closeNodeScope(jjtn002, 2); } } break; case LE0: case LE1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case LE0: jj_consume_token(LE0); break; case LE1: jj_consume_token(LE1); break; default: jj_la1[13] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstLessThanEqual jjtn003 = new AstLessThanEqual(JJTLESSTHANEQUAL); boolean jjtc003 = true; jjtree.openNodeScope(jjtn003); try { Math(); } catch (Throwable jjte003) { if (jjtc003) { jjtree.clearNodeScope(jjtn003); jjtc003 = false; } else { jjtree.popNode(); } if (jjte003 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte003;} } if (jjte003 instanceof ParseException) { {if (true) throw (ParseException)jjte003;} } {if (true) throw (Error)jjte003;} } finally { if (jjtc003) { jjtree.closeNodeScope(jjtn003, 2); } } break; case GE0: case GE1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case GE0: jj_consume_token(GE0); break; case GE1: jj_consume_token(GE1); break; default: jj_la1[14] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstGreaterThanEqual jjtn004 = new AstGreaterThanEqual(JJTGREATERTHANEQUAL); boolean jjtc004 = true; jjtree.openNodeScope(jjtn004); try { Math(); } catch (Throwable jjte004) { if (jjtc004) { jjtree.clearNodeScope(jjtn004); jjtc004 = false; } else { jjtree.popNode(); } if (jjte004 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte004;} } if (jjte004 instanceof ParseException) { {if (true) throw (ParseException)jjte004;} } {if (true) throw (Error)jjte004;} } finally { if (jjtc004) { jjtree.closeNodeScope(jjtn004, 2); } } break; default: jj_la1[15] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } } /* * Math * For '+' '-', then Multiplication */ final public void Math() throws ParseException { Multiplication(); label_7: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case PLUS: case MINUS: ; break; default: jj_la1[16] = jj_gen; break label_7; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case PLUS: jj_consume_token(PLUS); AstPlus jjtn001 = new AstPlus(JJTPLUS); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { Multiplication(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, 2); } } break; case MINUS: jj_consume_token(MINUS); AstMinus jjtn002 = new AstMinus(JJTMINUS); boolean jjtc002 = true; jjtree.openNodeScope(jjtn002); try { Multiplication(); } catch (Throwable jjte002) { if (jjtc002) { jjtree.clearNodeScope(jjtn002); jjtc002 = false; } else { jjtree.popNode(); } if (jjte002 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte002;} } if (jjte002 instanceof ParseException) { {if (true) throw (ParseException)jjte002;} } {if (true) throw (Error)jjte002;} } finally { if (jjtc002) { jjtree.closeNodeScope(jjtn002, 2); } } break; default: jj_la1[17] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } } /* * Multiplication * For a bunch of them, then Unary */ final public void Multiplication() throws ParseException { Unary(); label_8: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case MULT: case DIV0: case DIV1: case MOD0: case MOD1: ; break; default: jj_la1[18] = jj_gen; break label_8; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case MULT: jj_consume_token(MULT); AstMult jjtn001 = new AstMult(JJTMULT); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { Unary(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, 2); } } break; case DIV0: case DIV1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case DIV0: jj_consume_token(DIV0); break; case DIV1: jj_consume_token(DIV1); break; default: jj_la1[19] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstDiv jjtn002 = new AstDiv(JJTDIV); boolean jjtc002 = true; jjtree.openNodeScope(jjtn002); try { Unary(); } catch (Throwable jjte002) { if (jjtc002) { jjtree.clearNodeScope(jjtn002); jjtc002 = false; } else { jjtree.popNode(); } if (jjte002 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte002;} } if (jjte002 instanceof ParseException) { {if (true) throw (ParseException)jjte002;} } {if (true) throw (Error)jjte002;} } finally { if (jjtc002) { jjtree.closeNodeScope(jjtn002, 2); } } break; case MOD0: case MOD1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case MOD0: jj_consume_token(MOD0); break; case MOD1: jj_consume_token(MOD1); break; default: jj_la1[20] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstMod jjtn003 = new AstMod(JJTMOD); boolean jjtc003 = true; jjtree.openNodeScope(jjtn003); try { Unary(); } catch (Throwable jjte003) { if (jjtc003) { jjtree.clearNodeScope(jjtn003); jjtc003 = false; } else { jjtree.popNode(); } if (jjte003 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte003;} } if (jjte003 instanceof ParseException) { {if (true) throw (ParseException)jjte003;} } {if (true) throw (Error)jjte003;} } finally { if (jjtc003) { jjtree.closeNodeScope(jjtn003, 2); } } break; default: jj_la1[21] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } } /* * Unary * For '-' '!' 'not' 'empty', then Value */ final public void Unary() throws ParseException { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case MINUS: jj_consume_token(MINUS); AstNegative jjtn001 = new AstNegative(JJTNEGATIVE); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { Unary(); } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, true); } } break; case NOT0: case NOT1: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case NOT0: jj_consume_token(NOT0); break; case NOT1: jj_consume_token(NOT1); break; default: jj_la1[22] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AstNot jjtn002 = new AstNot(JJTNOT); boolean jjtc002 = true; jjtree.openNodeScope(jjtn002); try { Unary(); } catch (Throwable jjte002) { if (jjtc002) { jjtree.clearNodeScope(jjtn002); jjtc002 = false; } else { jjtree.popNode(); } if (jjte002 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte002;} } if (jjte002 instanceof ParseException) { {if (true) throw (ParseException)jjte002;} } {if (true) throw (Error)jjte002;} } finally { if (jjtc002) { jjtree.closeNodeScope(jjtn002, true); } } break; case EMPTY: jj_consume_token(EMPTY); AstEmpty jjtn003 = new AstEmpty(JJTEMPTY); boolean jjtc003 = true; jjtree.openNodeScope(jjtn003); try { Unary(); } catch (Throwable jjte003) { if (jjtc003) { jjtree.clearNodeScope(jjtn003); jjtc003 = false; } else { jjtree.popNode(); } if (jjte003 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte003;} } if (jjte003 instanceof ParseException) { {if (true) throw (ParseException)jjte003;} } {if (true) throw (Error)jjte003;} } finally { if (jjtc003) { jjtree.closeNodeScope(jjtn003, true); } } break; case INTEGER_LITERAL: case FLOATING_POINT_LITERAL: case STRING_LITERAL: case TRUE: case FALSE: case NULL: case LPAREN: case IDENTIFIER: Value(); break; default: jj_la1[23] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } /* * Value * Defines Prefix plus zero or more Suffixes */ final public void Value() throws ParseException { AstValue jjtn001 = new AstValue(JJTVALUE); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { ValuePrefix(); label_9: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case DOT: case LBRACK: ; break; default: jj_la1[24] = jj_gen; break label_9; } ValueSuffix(); } } catch (Throwable jjte001) { if (jjtc001) { jjtree.clearNodeScope(jjtn001); jjtc001 = false; } else { jjtree.popNode(); } if (jjte001 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte001;} } if (jjte001 instanceof ParseException) { {if (true) throw (ParseException)jjte001;} } {if (true) throw (Error)jjte001;} } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, jjtree.nodeArity() > 1); } } } /* * ValuePrefix * For Literals, Variables, and Functions */ final public void ValuePrefix() throws ParseException { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case INTEGER_LITERAL: case FLOATING_POINT_LITERAL: case STRING_LITERAL: case TRUE: case FALSE: case NULL: Literal(); break; case LPAREN: case IDENTIFIER: NonLiteral(); break; default: jj_la1[25] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } /* * ValueSuffix * Either dot or bracket notation */ final public void ValueSuffix() throws ParseException { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case DOT: DotSuffix(); break; case LBRACK: BracketSuffix(); break; default: jj_la1[26] = jj_gen; jj_consume_token(-1); throw new ParseException(); } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case LPAREN: MethodParameters(); break; default: jj_la1[27] = jj_gen; ; } } /* * DotSuffix * Dot Property */ final public void DotSuffix() throws ParseException { /*@bgen(jjtree) DotSuffix */ AstDotSuffix jjtn000 = new AstDotSuffix(JJTDOTSUFFIX); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000);Token t = null; try { jj_consume_token(DOT); t = jj_consume_token(IDENTIFIER); jjtree.closeNodeScope(jjtn000, true); jjtc000 = false; jjtn000.setImage(t.image); } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * BracketSuffix * Sub Expression Suffix */ final public void BracketSuffix() throws ParseException { /*@bgen(jjtree) BracketSuffix */ AstBracketSuffix jjtn000 = new AstBracketSuffix(JJTBRACKETSUFFIX); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000); try { jj_consume_token(LBRACK); Expression(); jj_consume_token(RBRACK); } catch (Throwable jjte000) { if (jjtc000) { jjtree.clearNodeScope(jjtn000); jjtc000 = false; } else { jjtree.popNode(); } if (jjte000 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte000;} } if (jjte000 instanceof ParseException) { {if (true) throw (ParseException)jjte000;} } {if (true) throw (Error)jjte000;} } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * MethodParameters */ final public void MethodParameters() throws ParseException { /*@bgen(jjtree) MethodParameters */ AstMethodParameters jjtn000 = new AstMethodParameters(JJTMETHODPARAMETERS); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000); try { jj_consume_token(LPAREN); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case INTEGER_LITERAL: case FLOATING_POINT_LITERAL: case STRING_LITERAL: case TRUE: case FALSE: case NULL: case LPAREN: case NOT0: case NOT1: case EMPTY: case MINUS: case IDENTIFIER: Expression(); label_10: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: ; break; default: jj_la1[28] = jj_gen; break label_10; } jj_consume_token(COMMA); Expression(); } break; default: jj_la1[29] = jj_gen; ; } jj_consume_token(RPAREN); } catch (Throwable jjte000) { if (jjtc000) { jjtree.clearNodeScope(jjtn000); jjtc000 = false; } else { jjtree.popNode(); } if (jjte000 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte000;} } if (jjte000 instanceof ParseException) { {if (true) throw (ParseException)jjte000;} } {if (true) throw (Error)jjte000;} } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * NonLiteral * For Grouped Operations, Identifiers, and Functions */ final public void NonLiteral() throws ParseException { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case LPAREN: jj_consume_token(LPAREN); Expression(); jj_consume_token(RPAREN); break; default: jj_la1[30] = jj_gen; if (jj_2_2(2147483647)) { Function(); } else { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case IDENTIFIER: Identifier(); break; default: jj_la1[31] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } } } /* * Identifier * Java Language Identifier */ final public void Identifier() throws ParseException { /*@bgen(jjtree) Identifier */ AstIdentifier jjtn000 = new AstIdentifier(JJTIDENTIFIER); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000);Token t = null; try { t = jj_consume_token(IDENTIFIER); jjtree.closeNodeScope(jjtn000, true); jjtc000 = false; jjtn000.setImage(t.image); } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * Function * Namespace:Name(a,b,c) */ final public void Function() throws ParseException { /*@bgen(jjtree) Function */ AstFunction jjtn000 = new AstFunction(JJTFUNCTION); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000);Token t0 = null; Token t1 = null; try { if (jj_2_3(2)) { t0 = jj_consume_token(IDENTIFIER); jj_consume_token(COLON); } else { ; } t1 = jj_consume_token(IDENTIFIER); if (t0 != null) { jjtn000.setPrefix(t0.image); jjtn000.setLocalName(t1.image); } else { jjtn000.setLocalName(t1.image); } jj_consume_token(LPAREN); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case INTEGER_LITERAL: case FLOATING_POINT_LITERAL: case STRING_LITERAL: case TRUE: case FALSE: case NULL: case LPAREN: case NOT0: case NOT1: case EMPTY: case MINUS: case IDENTIFIER: Expression(); label_11: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: ; break; default: jj_la1[32] = jj_gen; break label_11; } jj_consume_token(COMMA); Expression(); } break; default: jj_la1[33] = jj_gen; ; } jj_consume_token(RPAREN); } catch (Throwable jjte000) { if (jjtc000) { jjtree.clearNodeScope(jjtn000); jjtc000 = false; } else { jjtree.popNode(); } if (jjte000 instanceof RuntimeException) { {if (true) throw (RuntimeException)jjte000;} } if (jjte000 instanceof ParseException) { {if (true) throw (ParseException)jjte000;} } {if (true) throw (Error)jjte000;} } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * Literal * Reserved Keywords */ final public void Literal() throws ParseException { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TRUE: case FALSE: Boolean(); break; case FLOATING_POINT_LITERAL: FloatingPoint(); break; case INTEGER_LITERAL: Integer(); break; case STRING_LITERAL: String(); break; case NULL: Null(); break; default: jj_la1[34] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } /* * Boolean * For 'true' 'false' */ final public void Boolean() throws ParseException { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TRUE: AstTrue jjtn001 = new AstTrue(JJTTRUE); boolean jjtc001 = true; jjtree.openNodeScope(jjtn001); try { jj_consume_token(TRUE); } finally { if (jjtc001) { jjtree.closeNodeScope(jjtn001, true); } } break; case FALSE: AstFalse jjtn002 = new AstFalse(JJTFALSE); boolean jjtc002 = true; jjtree.openNodeScope(jjtn002); try { jj_consume_token(FALSE); } finally { if (jjtc002) { jjtree.closeNodeScope(jjtn002, true); } } break; default: jj_la1[35] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } /* * FloatinPoint * For Decimal and Floating Point Literals */ final public void FloatingPoint() throws ParseException { /*@bgen(jjtree) FloatingPoint */ AstFloatingPoint jjtn000 = new AstFloatingPoint(JJTFLOATINGPOINT); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000);Token t = null; try { t = jj_consume_token(FLOATING_POINT_LITERAL); jjtree.closeNodeScope(jjtn000, true); jjtc000 = false; jjtn000.setImage(t.image); } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * Integer * For Simple Numeric Literals */ final public void Integer() throws ParseException { /*@bgen(jjtree) Integer */ AstInteger jjtn000 = new AstInteger(JJTINTEGER); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000);Token t = null; try { t = jj_consume_token(INTEGER_LITERAL); jjtree.closeNodeScope(jjtn000, true); jjtc000 = false; jjtn000.setImage(t.image); } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * String * For Quoted Literals */ final public void String() throws ParseException { /*@bgen(jjtree) String */ AstString jjtn000 = new AstString(JJTSTRING); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000);Token t = null; try { t = jj_consume_token(STRING_LITERAL); jjtree.closeNodeScope(jjtn000, true); jjtc000 = false; jjtn000.setImage(t.image); } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } /* * Null * For 'null' */ final public void Null() throws ParseException { /*@bgen(jjtree) Null */ AstNull jjtn000 = new AstNull(JJTNULL); boolean jjtc000 = true; jjtree.openNodeScope(jjtn000); try { jj_consume_token(NULL); } finally { if (jjtc000) { jjtree.closeNodeScope(jjtn000, true); } } } private boolean jj_2_1(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_1(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(0, xla); } } private boolean jj_2_2(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_2(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(1, xla); } } private boolean jj_2_3(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_3(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(2, xla); } } private boolean jj_3R_13() { if (jj_scan_token(IDENTIFIER)) return true; if (jj_scan_token(COLON)) return true; return false; } private boolean jj_3_2() { Token xsp; xsp = jj_scanpos; if (jj_3R_13()) jj_scanpos = xsp; if (jj_scan_token(IDENTIFIER)) return true; if (jj_scan_token(LPAREN)) return true; return false; } private boolean jj_3R_69() { if (jj_scan_token(IDENTIFIER)) return true; return false; } private boolean jj_3R_25() { if (jj_3R_31()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_32()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3R_59() { if (jj_3R_69()) return true; return false; } private boolean jj_3R_34() { if (jj_scan_token(MINUS)) return true; return false; } private boolean jj_3R_58() { if (jj_3R_68()) return true; return false; } private boolean jj_3R_26() { Token xsp; xsp = jj_scanpos; if (jj_3R_33()) { jj_scanpos = xsp; if (jj_3R_34()) return true; } return false; } private boolean jj_3R_33() { if (jj_scan_token(PLUS)) return true; return false; } private boolean jj_3R_57() { if (jj_scan_token(LPAREN)) return true; if (jj_3R_67()) return true; return false; } private boolean jj_3R_49() { Token xsp; xsp = jj_scanpos; if (jj_3R_57()) { jj_scanpos = xsp; if (jj_3R_58()) { jj_scanpos = xsp; if (jj_3R_59()) return true; } } return false; } private boolean jj_3R_66() { if (jj_scan_token(NULL)) return true; return false; } private boolean jj_3R_21() { if (jj_3R_25()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_26()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3R_30() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(27)) { jj_scanpos = xsp; if (jj_scan_token(28)) return true; } return false; } private boolean jj_3R_65() { if (jj_scan_token(STRING_LITERAL)) return true; return false; } private boolean jj_3R_29() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(29)) { jj_scanpos = xsp; if (jj_scan_token(30)) return true; } return false; } private boolean jj_3R_28() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(23)) { jj_scanpos = xsp; if (jj_scan_token(24)) return true; } return false; } private boolean jj_3R_22() { Token xsp; xsp = jj_scanpos; if (jj_3R_27()) { jj_scanpos = xsp; if (jj_3R_28()) { jj_scanpos = xsp; if (jj_3R_29()) { jj_scanpos = xsp; if (jj_3R_30()) return true; } } } return false; } private boolean jj_3R_27() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(25)) { jj_scanpos = xsp; if (jj_scan_token(26)) return true; } return false; } private boolean jj_3R_61() { if (jj_scan_token(LBRACK)) return true; return false; } private boolean jj_3R_51() { if (jj_3R_61()) return true; return false; } private boolean jj_3R_64() { if (jj_scan_token(INTEGER_LITERAL)) return true; return false; } private boolean jj_3R_19() { if (jj_3R_21()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_22()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3R_60() { if (jj_scan_token(DOT)) return true; return false; } private boolean jj_3R_24() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(33)) { jj_scanpos = xsp; if (jj_scan_token(34)) return true; } return false; } private boolean jj_3R_63() { if (jj_scan_token(FLOATING_POINT_LITERAL)) return true; return false; } private boolean jj_3R_23() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(31)) { jj_scanpos = xsp; if (jj_scan_token(32)) return true; } return false; } private boolean jj_3R_20() { Token xsp; xsp = jj_scanpos; if (jj_3R_23()) { jj_scanpos = xsp; if (jj_3R_24()) return true; } return false; } private boolean jj_3R_50() { if (jj_3R_60()) return true; return false; } private boolean jj_3R_18() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(37)) { jj_scanpos = xsp; if (jj_scan_token(38)) return true; } return false; } private boolean jj_3R_47() { Token xsp; xsp = jj_scanpos; if (jj_3R_50()) { jj_scanpos = xsp; if (jj_3R_51()) return true; } return false; } private boolean jj_3R_71() { if (jj_scan_token(FALSE)) return true; return false; } private boolean jj_3R_17() { if (jj_3R_19()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_20()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3R_44() { if (jj_3R_47()) return true; return false; } private boolean jj_3R_70() { if (jj_scan_token(TRUE)) return true; return false; } private boolean jj_3R_62() { Token xsp; xsp = jj_scanpos; if (jj_3R_70()) { jj_scanpos = xsp; if (jj_3R_71()) return true; } return false; } private boolean jj_3R_46() { if (jj_3R_49()) return true; return false; } private boolean jj_3R_45() { if (jj_3R_48()) return true; return false; } private boolean jj_3R_15() { if (jj_3R_17()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_18()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3R_43() { Token xsp; xsp = jj_scanpos; if (jj_3R_45()) { jj_scanpos = xsp; if (jj_3R_46()) return true; } return false; } private boolean jj_3R_56() { if (jj_3R_66()) return true; return false; } private boolean jj_3R_16() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(39)) { jj_scanpos = xsp; if (jj_scan_token(40)) return true; } return false; } private boolean jj_3R_55() { if (jj_3R_65()) return true; return false; } private boolean jj_3R_54() { if (jj_3R_64()) return true; return false; } private boolean jj_3R_53() { if (jj_3R_63()) return true; return false; } private boolean jj_3R_52() { if (jj_3R_62()) return true; return false; } private boolean jj_3R_48() { Token xsp; xsp = jj_scanpos; if (jj_3R_52()) { jj_scanpos = xsp; if (jj_3R_53()) { jj_scanpos = xsp; if (jj_3R_54()) { jj_scanpos = xsp; if (jj_3R_55()) { jj_scanpos = xsp; if (jj_3R_56()) return true; } } } } return false; } private boolean jj_3R_14() { if (jj_3R_15()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_16()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3R_42() { if (jj_3R_43()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_44()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3_1() { if (jj_scan_token(QUESTIONMARK)) return true; if (jj_3R_12()) return true; if (jj_scan_token(COLON)) return true; return false; } private boolean jj_3R_38() { if (jj_3R_42()) return true; return false; } private boolean jj_3R_37() { if (jj_scan_token(EMPTY)) return true; if (jj_3R_31()) return true; return false; } private boolean jj_3R_12() { if (jj_3R_14()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3_1()) { jj_scanpos = xsp; break; } } return false; } private boolean jj_3R_36() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(35)) { jj_scanpos = xsp; if (jj_scan_token(36)) return true; } if (jj_3R_31()) return true; return false; } private boolean jj_3R_31() { Token xsp; xsp = jj_scanpos; if (jj_3R_35()) { jj_scanpos = xsp; if (jj_3R_36()) { jj_scanpos = xsp; if (jj_3R_37()) { jj_scanpos = xsp; if (jj_3R_38()) return true; } } } return false; } private boolean jj_3R_35() { if (jj_scan_token(MINUS)) return true; if (jj_3R_31()) return true; return false; } private boolean jj_3_3() { if (jj_scan_token(IDENTIFIER)) return true; if (jj_scan_token(COLON)) return true; return false; } private boolean jj_3R_68() { Token xsp; xsp = jj_scanpos; if (jj_3_3()) jj_scanpos = xsp; if (jj_scan_token(IDENTIFIER)) return true; if (jj_scan_token(LPAREN)) return true; return false; } private boolean jj_3R_67() { if (jj_3R_12()) return true; return false; } private boolean jj_3R_41() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(49)) { jj_scanpos = xsp; if (jj_scan_token(50)) return true; } return false; } private boolean jj_3R_40() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(47)) { jj_scanpos = xsp; if (jj_scan_token(48)) return true; } return false; } private boolean jj_3R_32() { Token xsp; xsp = jj_scanpos; if (jj_3R_39()) { jj_scanpos = xsp; if (jj_3R_40()) { jj_scanpos = xsp; if (jj_3R_41()) return true; } } return false; } private boolean jj_3R_39() { if (jj_scan_token(MULT)) return true; return false; } /** Generated Token Manager. */ public ELParserTokenManager token_source; SimpleCharStream jj_input_stream; /** Current token. */ public Token token; /** Next token. */ public Token jj_nt; private int jj_ntk; private Token jj_scanpos, jj_lastpos; private int jj_la; private int jj_gen; final private int[] jj_la1 = new int[36]; static private int[] jj_la1_0; static private int[] jj_la1_1; static { jj_la1_init_0(); jj_la1_init_1(); } private static void jj_la1_init_0() { jj_la1_0 = new int[] {0xe,0xe,0x0,0x0,0x0,0x0,0x80000000,0x80000000,0x0,0x80000000,0x7f800000,0x6000000,0x1800000,0x60000000,0x18000000,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x27b00,0x90000,0x27b00,0x90000,0x20000,0x400000,0x27b00,0x20000,0x0,0x400000,0x27b00,0x7b00,0x3000,}; } private static void jj_la1_init_1() { jj_la1_1 = new int[] {0x0,0x0,0x180,0x180,0x60,0x60,0x7,0x1,0x6,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x3000,0x3000,0x78800,0x18000,0x60000,0x78800,0x18,0x82218,0x0,0x80000,0x0,0x0,0x0,0x82218,0x0,0x80000,0x0,0x82218,0x0,0x0,}; } final private JJCalls[] jj_2_rtns = new JJCalls[3]; private boolean jj_rescan = false; private int jj_gc = 0; /** Constructor with InputStream. */ public ELParser(java.io.InputStream stream) { this(stream, null); } /** Constructor with InputStream and supplied encoding */ public ELParser(java.io.InputStream stream, String encoding) { try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } token_source = new ELParserTokenManager(jj_input_stream); token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 36; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } /** Reinitialise. */ public void ReInit(java.io.InputStream stream) { ReInit(stream, null); } /** Reinitialise. */ public void ReInit(java.io.InputStream stream, String encoding) { try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } token_source.ReInit(jj_input_stream); token = new Token(); jj_ntk = -1; jjtree.reset(); jj_gen = 0; for (int i = 0; i < 36; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } /** Constructor. */ public ELParser(java.io.Reader stream) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new ELParserTokenManager(jj_input_stream); token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 36; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } /** Reinitialise. */ public void ReInit(java.io.Reader stream) { jj_input_stream.ReInit(stream, 1, 1); token_source.ReInit(jj_input_stream); token = new Token(); jj_ntk = -1; jjtree.reset(); jj_gen = 0; for (int i = 0; i < 36; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } /** Constructor with generated Token Manager. */ public ELParser(ELParserTokenManager tm) { token_source = tm; token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 36; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } /** Reinitialise. */ public void ReInit(ELParserTokenManager tm) { token_source = tm; token = new Token(); jj_ntk = -1; jjtree.reset(); jj_gen = 0; for (int i = 0; i < 36; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } private Token jj_consume_token(int kind) throws ParseException { Token oldToken; if ((oldToken = token).next != null) token = token.next; else token = token.next = token_source.getNextToken(); jj_ntk = -1; if (token.kind == kind) { jj_gen++; if (++jj_gc > 100) { jj_gc = 0; for (int i = 0; i < jj_2_rtns.length; i++) { JJCalls c = jj_2_rtns[i]; while (c != null) { if (c.gen < jj_gen) c.first = null; c = c.next; } } } return token; } token = oldToken; jj_kind = kind; throw generateParseException(); } static private final class LookaheadSuccess extends java.lang.Error { } final private LookaheadSuccess jj_ls = new LookaheadSuccess(); private boolean jj_scan_token(int kind) { if (jj_scanpos == jj_lastpos) { jj_la--; if (jj_scanpos.next == null) { jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); } else { jj_lastpos = jj_scanpos = jj_scanpos.next; } } else { jj_scanpos = jj_scanpos.next; } if (jj_rescan) { int i = 0; Token tok = token; while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; } if (tok != null) jj_add_error_token(kind, i); } if (jj_scanpos.kind != kind) return true; if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; return false; } /** Get the next Token. */ final public Token getNextToken() { if (token.next != null) token = token.next; else token = token.next = token_source.getNextToken(); jj_ntk = -1; jj_gen++; return token; } /** Get the specific Token. */ final public Token getToken(int index) { Token t = token; for (int i = 0; i < index; i++) { if (t.next != null) t = t.next; else t = t.next = token_source.getNextToken(); } return t; } private int jj_ntk() { if ((jj_nt=token.next) == null) return (jj_ntk = (token.next=token_source.getNextToken()).kind); else return (jj_ntk = jj_nt.kind); } private java.util.List jj_expentries = new java.util.ArrayList(); private int[] jj_expentry; private int jj_kind = -1; private int[] jj_lasttokens = new int[100]; private int jj_endpos; private void jj_add_error_token(int kind, int pos) { if (pos >= 100) return; if (pos == jj_endpos + 1) { jj_lasttokens[jj_endpos++] = kind; } else if (jj_endpos != 0) { jj_expentry = new int[jj_endpos]; for (int i = 0; i < jj_endpos; i++) { jj_expentry[i] = jj_lasttokens[i]; } jj_entries_loop: for (java.util.Iterator it = jj_expentries.iterator(); it.hasNext();) { int[] oldentry = (int[])(it.next()); if (oldentry.length == jj_expentry.length) { for (int i = 0; i < jj_expentry.length; i++) { if (oldentry[i] != jj_expentry[i]) { continue jj_entries_loop; } } jj_expentries.add(jj_expentry); break jj_entries_loop; } } if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind; } } /** Generate ParseException. */ public ParseException generateParseException() { jj_expentries.clear(); boolean[] la1tokens = new boolean[57]; if (jj_kind >= 0) { la1tokens[jj_kind] = true; jj_kind = -1; } for (int i = 0; i < 36; i++) { if (jj_la1[i] == jj_gen) { for (int j = 0; j < 32; j++) { if ((jj_la1_0[i] & (1< jj_gen) { jj_la = p.arg; jj_lastpos = jj_scanpos = p.first; switch (i) { case 0: jj_3_1(); break; case 1: jj_3_2(); break; case 2: jj_3_3(); break; } } p = p.next; } while (p != null); } catch(LookaheadSuccess ls) { } } jj_rescan = false; } private void jj_save(int index, int xla) { JJCalls p = jj_2_rtns[index]; while (p.gen > jj_gen) { if (p.next == null) { p = p.next = new JJCalls(); break; } p = p.next; } p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla; } static final class JJCalls { int gen; Token first; int arg; JJCalls next; } } tomcat7-7.0.52/java/org/apache/el/parser/AstIdentifier.java0000644000175100017510000001521512271461077023400 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstIdentifier.java */ package org.apache.el.parser; import javax.el.ELException; import javax.el.MethodExpression; import javax.el.MethodInfo; import javax.el.MethodNotFoundException; import javax.el.PropertyNotFoundException; import javax.el.ValueExpression; import javax.el.ValueReference; import javax.el.VariableMapper; import org.apache.el.lang.EvaluationContext; import org.apache.el.util.MessageFactory; import org.apache.el.util.Validation; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstIdentifier extends SimpleNode { public AstIdentifier(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { VariableMapper varMapper = ctx.getVariableMapper(); if (varMapper != null) { ValueExpression expr = varMapper.resolveVariable(this.image); if (expr != null) { return expr.getType(ctx.getELContext()); } } ctx.setPropertyResolved(false); Class result = ctx.getELResolver().getType(ctx, null, this.image); if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled.null", this.image)); } return result; } @Override public Object getValue(EvaluationContext ctx) throws ELException { VariableMapper varMapper = ctx.getVariableMapper(); if (varMapper != null) { ValueExpression expr = varMapper.resolveVariable(this.image); if (expr != null) { return expr.getValue(ctx.getELContext()); } } ctx.setPropertyResolved(false); Object result = ctx.getELResolver().getValue(ctx, null, this.image); if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled.null", this.image)); } return result; } @Override public boolean isReadOnly(EvaluationContext ctx) throws ELException { VariableMapper varMapper = ctx.getVariableMapper(); if (varMapper != null) { ValueExpression expr = varMapper.resolveVariable(this.image); if (expr != null) { return expr.isReadOnly(ctx.getELContext()); } } ctx.setPropertyResolved(false); boolean result = ctx.getELResolver().isReadOnly(ctx, null, this.image); if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled.null", this.image)); } return result; } @Override public void setValue(EvaluationContext ctx, Object value) throws ELException { VariableMapper varMapper = ctx.getVariableMapper(); if (varMapper != null) { ValueExpression expr = varMapper.resolveVariable(this.image); if (expr != null) { expr.setValue(ctx.getELContext(), value); return; } } ctx.setPropertyResolved(false); ctx.getELResolver().setValue(ctx, null, this.image, value); if (!ctx.isPropertyResolved()) { throw new PropertyNotFoundException(MessageFactory.get( "error.resolver.unhandled.null", this.image)); } } @Override public Object invoke(EvaluationContext ctx, Class[] paramTypes, Object[] paramValues) throws ELException { return this.getMethodExpression(ctx).invoke(ctx.getELContext(), paramValues); } @Override public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) throws ELException { return this.getMethodExpression(ctx).getMethodInfo(ctx.getELContext()); } @Override public void setImage(String image) { if (!Validation.isIdentifier(image)) { throw new ELException(MessageFactory.get("error.identifier.notjava", image)); } this.image = image; } @Override public ValueReference getValueReference(EvaluationContext ctx) { VariableMapper varMapper = ctx.getVariableMapper(); if (varMapper == null) { return null; } ValueExpression expr = varMapper.resolveVariable(this.image); if (expr == null) { return null; } return expr.getValueReference(ctx); } private final MethodExpression getMethodExpression(EvaluationContext ctx) throws ELException { Object obj = null; // case A: ValueExpression exists, getValue which must // be a MethodExpression VariableMapper varMapper = ctx.getVariableMapper(); ValueExpression ve = null; if (varMapper != null) { ve = varMapper.resolveVariable(this.image); if (ve != null) { obj = ve.getValue(ctx); } } // case B: evaluate the identity against the ELResolver, again, must be // a MethodExpression to be able to invoke if (ve == null) { ctx.setPropertyResolved(false); obj = ctx.getELResolver().getValue(ctx, null, this.image); } // finally provide helpful hints if (obj instanceof MethodExpression) { return (MethodExpression) obj; } else if (obj == null) { throw new MethodNotFoundException("Identity '" + this.image + "' was null and was unable to invoke"); } else { throw new ELException( "Identity '" + this.image + "' does not reference a MethodExpression instance, returned type: " + obj.getClass().getName()); } } } tomcat7-7.0.52/java/org/apache/el/parser/AstDynamicExpression.java0000644000175100017510000000337512271461077024766 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstDynamicExpression.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstDynamicExpression extends SimpleNode { public AstDynamicExpression(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return this.children[0].getType(ctx); } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.children[0].getValue(ctx); } @Override public boolean isReadOnly(EvaluationContext ctx) throws ELException { return this.children[0].isReadOnly(ctx); } @Override public void setValue(EvaluationContext ctx, Object value) throws ELException { this.children[0].setValue(ctx, value); } } tomcat7-7.0.52/java/org/apache/el/parser/AstNotEqual.java0000644000175100017510000000257712271461077023055 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstNotEqual.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstNotEqual extends BooleanNode { public AstNotEqual(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); return Boolean.valueOf(!equals(obj0, obj1)); } } tomcat7-7.0.52/java/org/apache/el/parser/AstDotSuffix.java0000644000175100017510000000312012271461077023221 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstDotSuffix.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; import org.apache.el.util.MessageFactory; import org.apache.el.util.Validation; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstDotSuffix extends SimpleNode { public AstDotSuffix(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.image; } @Override public void setImage(String image) { if (!Validation.isIdentifier(image)) { throw new ELException(MessageFactory.get("error.identifier.notjava", image)); } this.image = image; } } tomcat7-7.0.52/java/org/apache/el/parser/AstFloatingPoint.java0000644000175100017510000000345112271461077024072 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstFloatingPoint.java */ package org.apache.el.parser; import java.math.BigDecimal; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstFloatingPoint extends SimpleNode { public AstFloatingPoint(int id) { super(id); } private volatile Number number; public Number getFloatingPoint() { if (this.number == null) { try { this.number = new Double(this.image); } catch (ArithmeticException e0) { this.number = new BigDecimal(this.image); } } return this.number; } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.getFloatingPoint(); } @Override public Class getType(EvaluationContext ctx) throws ELException { return this.getFloatingPoint().getClass(); } } tomcat7-7.0.52/java/org/apache/el/parser/AstPlus.java0000644000175100017510000000262612271461077022243 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstPlus.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.ELArithmetic; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstPlus extends ArithmeticNode { public AstPlus(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); return ELArithmetic.add(obj0, obj1); } } tomcat7-7.0.52/java/org/apache/el/parser/ELParserTokenManager.java0000644000175100017510000011253012271461077024615 0ustar locutuslocutus/* Generated By:JJTree&JavaCC: Do not edit this line. ELParserTokenManager.java */ package org.apache.el.parser; /** Token Manager. */ @SuppressWarnings("all") // Ignore warnings in generated code public class ELParserTokenManager implements ELParserConstants { /** Debug output. */ public java.io.PrintStream debugStream = System.out; /** Set debug output. */ public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } private final int jjStopStringLiteralDfa_0(int pos, long active0) { switch (pos) { case 0: if ((active0 & 0xcL) != 0L) { jjmatchedKind = 1; return 5; } return -1; default : return -1; } } private final int jjStartNfa_0(int pos, long active0) { return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); } private int jjStopAtPos(int pos, int kind) { jjmatchedKind = kind; jjmatchedPos = pos; return pos + 1; } private int jjMoveStringLiteralDfa0_0() { switch(curChar) { case 35: return jjMoveStringLiteralDfa1_0(0x8L); case 36: return jjMoveStringLiteralDfa1_0(0x4L); default : return jjMoveNfa_0(7, 0); } } private int jjMoveStringLiteralDfa1_0(long active0) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_0(0, active0); return 1; } switch(curChar) { case 123: if ((active0 & 0x4L) != 0L) return jjStopAtPos(1, 2); else if ((active0 & 0x8L) != 0L) return jjStopAtPos(1, 3); break; default : break; } return jjStartNfa_0(0, active0); } static final long[] jjbitVec0 = { 0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; static final long[] jjbitVec2 = { 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL }; private int jjMoveNfa_0(int startState, int curPos) { int startsAt = 0; jjnewStateCnt = 8; int i = 1; jjstateSet[0] = startState; int kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; do { switch(jjstateSet[--i]) { case 7: if ((0xffffffe7ffffffffL & l) != 0L) { if (kind > 1) kind = 1; jjCheckNAddStates(0, 4); } else if ((0x1800000000L & l) != 0L) { if (kind > 1) kind = 1; jjCheckNAdd(5); } if ((0xffffffe7ffffffffL & l) != 0L) jjCheckNAddTwoStates(0, 1); break; case 0: if ((0xffffffe7ffffffffL & l) != 0L) jjCheckNAddTwoStates(0, 1); break; case 2: if ((0xffffffe7ffffffffL & l) == 0L) break; if (kind > 1) kind = 1; jjCheckNAddStates(0, 4); break; case 3: if ((0xffffffe7ffffffffL & l) != 0L) jjCheckNAddTwoStates(3, 4); break; case 4: if ((0x1800000000L & l) != 0L) jjCheckNAdd(5); break; case 5: if ((0xffffffe7ffffffffL & l) == 0L) break; if (kind > 1) kind = 1; jjCheckNAddStates(5, 8); break; case 6: if ((0x1800000000L & l) == 0L) break; if (kind > 1) kind = 1; jjCheckNAddStates(9, 13); break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); do { switch(jjstateSet[--i]) { case 7: if (kind > 1) kind = 1; jjCheckNAddStates(0, 4); if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddTwoStates(0, 1); else if (curChar == 92) { if (kind > 1) kind = 1; jjCheckNAddStates(14, 17); } break; case 0: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddTwoStates(0, 1); break; case 1: if (curChar != 92) break; if (kind > 1) kind = 1; jjCheckNAddStates(14, 17); break; case 2: if (kind > 1) kind = 1; jjCheckNAddStates(0, 4); break; case 3: jjCheckNAddTwoStates(3, 4); break; case 5: if ((0xf7ffffffffffffffL & l) == 0L) break; if (kind > 1) kind = 1; jjCheckNAddStates(5, 8); break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); do { switch(jjstateSet[--i]) { case 7: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjCheckNAddTwoStates(0, 1); if (jjCanMove_0(hiByte, i1, i2, l1, l2)) { if (kind > 1) kind = 1; jjCheckNAddStates(0, 4); } break; case 0: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjCheckNAddTwoStates(0, 1); break; case 2: if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) break; if (kind > 1) kind = 1; jjCheckNAddStates(0, 4); break; case 3: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjCheckNAddTwoStates(3, 4); break; case 5: if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) break; if (kind > 1) kind = 1; jjCheckNAddStates(5, 8); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 8 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_1(int pos, long active0) { switch (pos) { case 0: if ((active0 & 0x10000L) != 0L) return 1; if ((active0 & 0x5075555007000L) != 0L) { jjmatchedKind = 51; return 30; } return -1; case 1: if ((active0 & 0x5065000007000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 1; return 30; } if ((active0 & 0x10555000000L) != 0L) return 30; return -1; case 2: if ((active0 & 0x5005000000000L) != 0L) return 30; if ((active0 & 0x60000007000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 2; return 30; } return -1; case 3: if ((active0 & 0x5000L) != 0L) return 30; if ((active0 & 0x60000002000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 3; return 30; } return -1; case 4: if ((active0 & 0x40000000000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 4; return 30; } if ((active0 & 0x20000002000L) != 0L) return 30; return -1; case 5: if ((active0 & 0x40000000000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 5; return 30; } return -1; case 6: if ((active0 & 0x40000000000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 6; return 30; } return -1; case 7: if ((active0 & 0x40000000000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 7; return 30; } return -1; case 8: if ((active0 & 0x40000000000L) != 0L) { jjmatchedKind = 51; jjmatchedPos = 8; return 30; } return -1; default : return -1; } } private final int jjStartNfa_1(int pos, long active0) { return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); } private int jjMoveStringLiteralDfa0_1() { switch(curChar) { case 33: jjmatchedKind = 35; return jjMoveStringLiteralDfa1_1(0x200000000L); case 37: return jjStopAtPos(0, 49); case 38: return jjMoveStringLiteralDfa1_1(0x2000000000L); case 40: return jjStopAtPos(0, 17); case 41: return jjStopAtPos(0, 18); case 42: return jjStopAtPos(0, 43); case 43: return jjStopAtPos(0, 44); case 44: return jjStopAtPos(0, 22); case 45: return jjStopAtPos(0, 45); case 46: return jjStartNfaWithStates_1(0, 16, 1); case 47: return jjStopAtPos(0, 47); case 58: return jjStopAtPos(0, 21); case 60: jjmatchedKind = 25; return jjMoveStringLiteralDfa1_1(0x20000000L); case 61: return jjMoveStringLiteralDfa1_1(0x80000000L); case 62: jjmatchedKind = 23; return jjMoveStringLiteralDfa1_1(0x8000000L); case 63: return jjStopAtPos(0, 46); case 91: return jjStopAtPos(0, 19); case 93: return jjStopAtPos(0, 20); case 97: return jjMoveStringLiteralDfa1_1(0x4000000000L); case 100: return jjMoveStringLiteralDfa1_1(0x1000000000000L); case 101: return jjMoveStringLiteralDfa1_1(0x20100000000L); case 102: return jjMoveStringLiteralDfa1_1(0x2000L); case 103: return jjMoveStringLiteralDfa1_1(0x11000000L); case 105: return jjMoveStringLiteralDfa1_1(0x40000000000L); case 108: return jjMoveStringLiteralDfa1_1(0x44000000L); case 109: return jjMoveStringLiteralDfa1_1(0x4000000000000L); case 110: return jjMoveStringLiteralDfa1_1(0x1400004000L); case 111: return jjMoveStringLiteralDfa1_1(0x10000000000L); case 116: return jjMoveStringLiteralDfa1_1(0x1000L); case 124: return jjMoveStringLiteralDfa1_1(0x8000000000L); case 125: return jjStopAtPos(0, 15); default : return jjMoveNfa_1(0, 0); } } private int jjMoveStringLiteralDfa1_1(long active0) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(0, active0); return 1; } switch(curChar) { case 38: if ((active0 & 0x2000000000L) != 0L) return jjStopAtPos(1, 37); break; case 61: if ((active0 & 0x8000000L) != 0L) return jjStopAtPos(1, 27); else if ((active0 & 0x20000000L) != 0L) return jjStopAtPos(1, 29); else if ((active0 & 0x80000000L) != 0L) return jjStopAtPos(1, 31); else if ((active0 & 0x200000000L) != 0L) return jjStopAtPos(1, 33); break; case 97: return jjMoveStringLiteralDfa2_1(active0, 0x2000L); case 101: if ((active0 & 0x10000000L) != 0L) return jjStartNfaWithStates_1(1, 28, 30); else if ((active0 & 0x40000000L) != 0L) return jjStartNfaWithStates_1(1, 30, 30); else if ((active0 & 0x400000000L) != 0L) return jjStartNfaWithStates_1(1, 34, 30); break; case 105: return jjMoveStringLiteralDfa2_1(active0, 0x1000000000000L); case 109: return jjMoveStringLiteralDfa2_1(active0, 0x20000000000L); case 110: return jjMoveStringLiteralDfa2_1(active0, 0x44000000000L); case 111: return jjMoveStringLiteralDfa2_1(active0, 0x4001000000000L); case 113: if ((active0 & 0x100000000L) != 0L) return jjStartNfaWithStates_1(1, 32, 30); break; case 114: if ((active0 & 0x10000000000L) != 0L) return jjStartNfaWithStates_1(1, 40, 30); return jjMoveStringLiteralDfa2_1(active0, 0x1000L); case 116: if ((active0 & 0x1000000L) != 0L) return jjStartNfaWithStates_1(1, 24, 30); else if ((active0 & 0x4000000L) != 0L) return jjStartNfaWithStates_1(1, 26, 30); break; case 117: return jjMoveStringLiteralDfa2_1(active0, 0x4000L); case 124: if ((active0 & 0x8000000000L) != 0L) return jjStopAtPos(1, 39); break; default : break; } return jjStartNfa_1(0, active0); } private int jjMoveStringLiteralDfa2_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(0, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(1, active0); return 2; } switch(curChar) { case 100: if ((active0 & 0x4000000000L) != 0L) return jjStartNfaWithStates_1(2, 38, 30); else if ((active0 & 0x4000000000000L) != 0L) return jjStartNfaWithStates_1(2, 50, 30); break; case 108: return jjMoveStringLiteralDfa3_1(active0, 0x6000L); case 112: return jjMoveStringLiteralDfa3_1(active0, 0x20000000000L); case 115: return jjMoveStringLiteralDfa3_1(active0, 0x40000000000L); case 116: if ((active0 & 0x1000000000L) != 0L) return jjStartNfaWithStates_1(2, 36, 30); break; case 117: return jjMoveStringLiteralDfa3_1(active0, 0x1000L); case 118: if ((active0 & 0x1000000000000L) != 0L) return jjStartNfaWithStates_1(2, 48, 30); break; default : break; } return jjStartNfa_1(1, active0); } private int jjMoveStringLiteralDfa3_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(1, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(2, active0); return 3; } switch(curChar) { case 101: if ((active0 & 0x1000L) != 0L) return jjStartNfaWithStates_1(3, 12, 30); break; case 108: if ((active0 & 0x4000L) != 0L) return jjStartNfaWithStates_1(3, 14, 30); break; case 115: return jjMoveStringLiteralDfa4_1(active0, 0x2000L); case 116: return jjMoveStringLiteralDfa4_1(active0, 0x60000000000L); default : break; } return jjStartNfa_1(2, active0); } private int jjMoveStringLiteralDfa4_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(2, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(3, active0); return 4; } switch(curChar) { case 97: return jjMoveStringLiteralDfa5_1(active0, 0x40000000000L); case 101: if ((active0 & 0x2000L) != 0L) return jjStartNfaWithStates_1(4, 13, 30); break; case 121: if ((active0 & 0x20000000000L) != 0L) return jjStartNfaWithStates_1(4, 41, 30); break; default : break; } return jjStartNfa_1(3, active0); } private int jjMoveStringLiteralDfa5_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(3, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(4, active0); return 5; } switch(curChar) { case 110: return jjMoveStringLiteralDfa6_1(active0, 0x40000000000L); default : break; } return jjStartNfa_1(4, active0); } private int jjMoveStringLiteralDfa6_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(4, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(5, active0); return 6; } switch(curChar) { case 99: return jjMoveStringLiteralDfa7_1(active0, 0x40000000000L); default : break; } return jjStartNfa_1(5, active0); } private int jjMoveStringLiteralDfa7_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(5, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(6, active0); return 7; } switch(curChar) { case 101: return jjMoveStringLiteralDfa8_1(active0, 0x40000000000L); default : break; } return jjStartNfa_1(6, active0); } private int jjMoveStringLiteralDfa8_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(6, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(7, active0); return 8; } switch(curChar) { case 111: return jjMoveStringLiteralDfa9_1(active0, 0x40000000000L); default : break; } return jjStartNfa_1(7, active0); } private int jjMoveStringLiteralDfa9_1(long old0, long active0) { if (((active0 &= old0)) == 0L) return jjStartNfa_1(7, old0); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(8, active0); return 9; } switch(curChar) { case 102: if ((active0 & 0x40000000000L) != 0L) return jjStartNfaWithStates_1(9, 42, 30); break; default : break; } return jjStartNfa_1(8, active0); } private int jjStartNfaWithStates_1(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_1(state, pos + 1); } static final long[] jjbitVec3 = { 0x1ff00000fffffffeL, 0xffffffffffffc000L, 0xffffffffL, 0x600000000000000L }; static final long[] jjbitVec4 = { 0x0L, 0x0L, 0x0L, 0xff7fffffff7fffffL }; static final long[] jjbitVec5 = { 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; static final long[] jjbitVec6 = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffL, 0x0L }; static final long[] jjbitVec7 = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0x0L, 0x0L }; static final long[] jjbitVec8 = { 0x3fffffffffffL, 0x0L, 0x0L, 0x0L }; private int jjMoveNfa_1(int startState, int curPos) { int startsAt = 0; jjnewStateCnt = 30; int i = 1; jjstateSet[0] = startState; int kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; do { switch(jjstateSet[--i]) { case 0: if ((0x3ff000000000000L & l) != 0L) { if (kind > 8) kind = 8; jjCheckNAddStates(18, 22); } else if ((0x1800000000L & l) != 0L) { if (kind > 51) kind = 51; jjCheckNAddTwoStates(28, 29); } else if (curChar == 39) jjCheckNAddStates(23, 25); else if (curChar == 34) jjCheckNAddStates(26, 28); else if (curChar == 46) jjCheckNAdd(1); break; case 30: if ((0x3ff001000000000L & l) != 0L) { if (kind > 52) kind = 52; jjCheckNAdd(29); } if ((0x3ff001000000000L & l) != 0L) { if (kind > 51) kind = 51; jjCheckNAdd(28); } break; case 1: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 9) kind = 9; jjCheckNAddTwoStates(1, 2); break; case 3: if ((0x280000000000L & l) != 0L) jjCheckNAdd(4); break; case 4: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 9) kind = 9; jjCheckNAdd(4); break; case 5: if (curChar == 34) jjCheckNAddStates(26, 28); break; case 6: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddStates(26, 28); break; case 8: if ((0x8400000000L & l) != 0L) jjCheckNAddStates(26, 28); break; case 9: if (curChar == 34 && kind > 11) kind = 11; break; case 10: if (curChar == 39) jjCheckNAddStates(23, 25); break; case 11: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddStates(23, 25); break; case 13: if ((0x8400000000L & l) != 0L) jjCheckNAddStates(23, 25); break; case 14: if (curChar == 39 && kind > 11) kind = 11; break; case 15: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 8) kind = 8; jjCheckNAddStates(18, 22); break; case 16: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 8) kind = 8; jjCheckNAdd(16); break; case 17: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddTwoStates(17, 18); break; case 18: if (curChar != 46) break; if (kind > 9) kind = 9; jjCheckNAddTwoStates(19, 20); break; case 19: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 9) kind = 9; jjCheckNAddTwoStates(19, 20); break; case 21: if ((0x280000000000L & l) != 0L) jjCheckNAdd(22); break; case 22: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 9) kind = 9; jjCheckNAdd(22); break; case 23: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddTwoStates(23, 24); break; case 25: if ((0x280000000000L & l) != 0L) jjCheckNAdd(26); break; case 26: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 9) kind = 9; jjCheckNAdd(26); break; case 27: if ((0x1800000000L & l) == 0L) break; if (kind > 51) kind = 51; jjCheckNAddTwoStates(28, 29); break; case 28: if ((0x3ff001000000000L & l) == 0L) break; if (kind > 51) kind = 51; jjCheckNAdd(28); break; case 29: if ((0x3ff001000000000L & l) == 0L) break; if (kind > 52) kind = 52; jjCheckNAdd(29); break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); do { switch(jjstateSet[--i]) { case 0: if ((0x7fffffe87fffffeL & l) == 0L) break; if (kind > 51) kind = 51; jjCheckNAddTwoStates(28, 29); break; case 30: if ((0x7fffffe87fffffeL & l) != 0L) { if (kind > 52) kind = 52; jjCheckNAdd(29); } if ((0x7fffffe87fffffeL & l) != 0L) { if (kind > 51) kind = 51; jjCheckNAdd(28); } break; case 2: if ((0x2000000020L & l) != 0L) jjAddStates(29, 30); break; case 6: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(26, 28); break; case 7: if (curChar == 92) jjstateSet[jjnewStateCnt++] = 8; break; case 8: if (curChar == 92) jjCheckNAddStates(26, 28); break; case 11: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(23, 25); break; case 12: if (curChar == 92) jjstateSet[jjnewStateCnt++] = 13; break; case 13: if (curChar == 92) jjCheckNAddStates(23, 25); break; case 20: if ((0x2000000020L & l) != 0L) jjAddStates(31, 32); break; case 24: if ((0x2000000020L & l) != 0L) jjAddStates(33, 34); break; case 28: if ((0x7fffffe87fffffeL & l) == 0L) break; if (kind > 51) kind = 51; jjCheckNAdd(28); break; case 29: if ((0x7fffffe87fffffeL & l) == 0L) break; if (kind > 52) kind = 52; jjCheckNAdd(29); break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); do { switch(jjstateSet[--i]) { case 0: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; if (kind > 51) kind = 51; jjCheckNAddTwoStates(28, 29); break; case 30: if (jjCanMove_1(hiByte, i1, i2, l1, l2)) { if (kind > 51) kind = 51; jjCheckNAdd(28); } if (jjCanMove_1(hiByte, i1, i2, l1, l2)) { if (kind > 52) kind = 52; jjCheckNAdd(29); } break; case 6: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(26, 28); break; case 11: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(23, 25); break; case 28: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; if (kind > 51) kind = 51; jjCheckNAdd(28); break; case 29: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; if (kind > 52) kind = 52; jjCheckNAdd(29); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 30 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } static final int[] jjnextStates = { 0, 1, 3, 4, 2, 0, 1, 4, 2, 0, 1, 4, 5, 2, 0, 1, 2, 6, 16, 17, 18, 23, 24, 11, 12, 14, 6, 7, 9, 3, 4, 21, 22, 25, 26, }; private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2) { switch(hiByte) { case 0: return ((jjbitVec2[i2] & l2) != 0L); default : if ((jjbitVec0[i1] & l1) != 0L) return true; return false; } } private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2) { switch(hiByte) { case 0: return ((jjbitVec4[i2] & l2) != 0L); case 48: return ((jjbitVec5[i2] & l2) != 0L); case 49: return ((jjbitVec6[i2] & l2) != 0L); case 51: return ((jjbitVec7[i2] & l2) != 0L); case 61: return ((jjbitVec8[i2] & l2) != 0L); default : if ((jjbitVec3[i1] & l1) != 0L) return true; return false; } } /** Token literal values. */ public static final String[] jjstrLiteralImages = { "", null, "\44\173", "\43\173", null, null, null, null, null, null, null, null, "\164\162\165\145", "\146\141\154\163\145", "\156\165\154\154", "\175", "\56", "\50", "\51", "\133", "\135", "\72", "\54", "\76", "\147\164", "\74", "\154\164", "\76\75", "\147\145", "\74\75", "\154\145", "\75\75", "\145\161", "\41\75", "\156\145", "\41", "\156\157\164", "\46\46", "\141\156\144", "\174\174", "\157\162", "\145\155\160\164\171", "\151\156\163\164\141\156\143\145\157\146", "\52", "\53", "\55", "\77", "\57", "\144\151\166", "\45", "\155\157\144", null, null, null, null, null, null, }; /** Lexer state names. */ public static final String[] lexStateNames = { "DEFAULT", "IN_EXPRESSION", }; /** Lex State array. */ public static final int[] jjnewLexState = { -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; static final long[] jjtoToken = { 0x11ffffffffffb0fL, }; static final long[] jjtoSkip = { 0xf0L, }; protected SimpleCharStream input_stream; private final int[] jjrounds = new int[30]; private final int[] jjstateSet = new int[60]; protected char curChar; /** Constructor. */ public ELParserTokenManager(SimpleCharStream stream){ if (SimpleCharStream.staticFlag) throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); input_stream = stream; } /** Constructor. */ public ELParserTokenManager(SimpleCharStream stream, int lexState){ this(stream); SwitchTo(lexState); } /** Reinitialise parser. */ public void ReInit(SimpleCharStream stream) { jjmatchedPos = jjnewStateCnt = 0; curLexState = defaultLexState; input_stream = stream; ReInitRounds(); } private void ReInitRounds() { int i; jjround = 0x80000001; for (i = 30; i-- > 0;) jjrounds[i] = 0x80000000; } /** Reinitialise parser. */ public void ReInit(SimpleCharStream stream, int lexState) { ReInit(stream); SwitchTo(lexState); } /** Switch to specified lex state. */ public void SwitchTo(int lexState) { if (lexState >= 2 || lexState < 0) throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); else curLexState = lexState; } protected Token jjFillToken() { final Token t; final String curTokenImage; final int beginLine; final int endLine; final int beginColumn; final int endColumn; String im = jjstrLiteralImages[jjmatchedKind]; curTokenImage = (im == null) ? input_stream.GetImage() : im; beginLine = input_stream.getBeginLine(); beginColumn = input_stream.getBeginColumn(); endLine = input_stream.getEndLine(); endColumn = input_stream.getEndColumn(); t = Token.newToken(jjmatchedKind, curTokenImage); t.beginLine = beginLine; t.endLine = endLine; t.beginColumn = beginColumn; t.endColumn = endColumn; return t; } int curLexState = 0; int defaultLexState = 0; int jjnewStateCnt; int jjround; int jjmatchedPos; int jjmatchedKind; /** Get the next Token. */ public Token getNextToken() { Token matchedToken; int curPos = 0; EOFLoop : for (;;) { try { curChar = input_stream.BeginToken(); } catch(java.io.IOException e) { jjmatchedKind = 0; matchedToken = jjFillToken(); return matchedToken; } switch(curLexState) { case 0: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_0(); break; case 1: try { input_stream.backup(0); while (curChar <= 32 && (0x100002600L & (1L << curChar)) != 0L) curChar = input_stream.BeginToken(); } catch (java.io.IOException e1) { continue EOFLoop; } jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_1(); if (jjmatchedPos == 0 && jjmatchedKind > 56) { jjmatchedKind = 56; } break; } if (jjmatchedKind != 0x7fffffff) { if (jjmatchedPos + 1 < curPos) input_stream.backup(curPos - jjmatchedPos - 1); if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) { matchedToken = jjFillToken(); if (jjnewLexState[jjmatchedKind] != -1) curLexState = jjnewLexState[jjmatchedKind]; return matchedToken; } else { if (jjnewLexState[jjmatchedKind] != -1) curLexState = jjnewLexState[jjmatchedKind]; continue EOFLoop; } } int error_line = input_stream.getEndLine(); int error_column = input_stream.getEndColumn(); String error_after = null; boolean EOFSeen = false; try { input_stream.readChar(); input_stream.backup(1); } catch (java.io.IOException e1) { EOFSeen = true; error_after = curPos <= 1 ? "" : input_stream.GetImage(); if (curChar == '\n' || curChar == '\r') { error_line++; error_column = 0; } else error_column++; } if (!EOFSeen) { input_stream.backup(1); error_after = curPos <= 1 ? "" : input_stream.GetImage(); } throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); } } private void jjCheckNAdd(int state) { if (jjrounds[state] != jjround) { jjstateSet[jjnewStateCnt++] = state; jjrounds[state] = jjround; } } private void jjAddStates(int start, int end) { do { jjstateSet[jjnewStateCnt++] = jjnextStates[start]; } while (start++ != end); } private void jjCheckNAddTwoStates(int state1, int state2) { jjCheckNAdd(state1); jjCheckNAdd(state2); } private void jjCheckNAddStates(int start, int end) { do { jjCheckNAdd(jjnextStates[start]); } while (start++ != end); } } tomcat7-7.0.52/java/org/apache/el/parser/AstChoice.java0000644000175100017510000000311412271461077022503 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstChoice.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstChoice extends SimpleNode { public AstChoice(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { Object val = this.getValue(ctx); return (val != null) ? val.getClass() : null; } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Boolean b0 = coerceToBoolean(obj0); return this.children[((b0.booleanValue() ? 1 : 2))].getValue(ctx); } } tomcat7-7.0.52/java/org/apache/el/parser/AstLessThan.java0000644000175100017510000000304312271461077023033 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstLessThan.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstLessThan extends BooleanNode { public AstLessThan(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); if (obj0 == null) { return Boolean.FALSE; } Object obj1 = this.children[1].getValue(ctx); if (obj1 == null) { return Boolean.FALSE; } return (compare(obj0, obj1) < 0) ? Boolean.TRUE : Boolean.FALSE; } } tomcat7-7.0.52/java/org/apache/el/parser/ELParser.jjt0000644000175100017510000002244512271461077022174 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Author: Jacob Hookom Email: jacob at hookom.net */ /* == Option Declaration == */ options { STATIC=false; NODE_PREFIX="Ast"; VISITOR_EXCEPTION="javax.el.ELException"; VISITOR=false; MULTI=true; NODE_DEFAULT_VOID=true; JAVA_UNICODE_ESCAPE=false; UNICODE_INPUT=true; BUILD_NODE_FILES=true; } /* == Parser Declaration == */ PARSER_BEGIN( ELParser ) package org.apache.el.parser; import java.io.StringReader; import javax.el.ELException; public class ELParser { public static Node parse(String ref) throws ELException { try { return (new ELParser(new StringReader(ref))).CompositeExpression(); } catch (ParseException pe) { throw new ELException(pe.getMessage()); } } } PARSER_END( ELParser ) /* * CompositeExpression * Allow most flexible parsing, restrict by examining * type of returned node */ AstCompositeExpression CompositeExpression() #CompositeExpression : {} { (DeferredExpression() | DynamicExpression() | LiteralExpression())* { return jjtThis; } } /* * LiteralExpression * Non-EL Expression blocks */ void LiteralExpression() #LiteralExpression : { Token t = null; } { t= { jjtThis.setImage(t.image); } } /* * DeferredExpression * #{..} Expressions */ void DeferredExpression() #DeferredExpression : {} { Expression() } /* * DynamicExpression * ${..} Expressions */ void DynamicExpression() #DynamicExpression : {} { Expression() } /* * Expression * EL Expression Language Root, goes to Choice */ void Expression() : {} { Choice() } /* * Choice * For Choice markup a ? b : c, then Or */ void Choice() : {} { Or() (LOOKAHEAD(3) Choice() Choice() #Choice(3))* } /* * Or * For 'or' '||', then And */ void Or() : {} { And() ((|) And() #Or(2))* } /* * And * For 'and' '&&', then Equality */ void And() : {} { Equality() ((|) Equality() #And(2))* } /* * Equality * For '==' 'eq' '!=' 'ne', then Compare */ void Equality() : {} { Compare() ( ((|) Compare() #Equal(2)) | ((|) Compare() #NotEqual(2)) )* } /* * Compare * For a bunch of them, then Math */ void Compare() : {} { Math() ( ((|) Math() #LessThan(2)) | ((|) Math() #GreaterThan(2)) | ((|) Math() #LessThanEqual(2)) | ((|) Math() #GreaterThanEqual(2)) )* } /* * Math * For '+' '-', then Multiplication */ void Math() : {} { Multiplication() ( ( Multiplication() #Plus(2)) | ( Multiplication() #Minus(2)) )* } /* * Multiplication * For a bunch of them, then Unary */ void Multiplication() : {} { Unary() ( ( Unary() #Mult(2)) | ((|) Unary() #Div(2)) | ((|) Unary() #Mod(2)) )* } /* * Unary * For '-' '!' 'not' 'empty', then Value */ void Unary() : {} { Unary() #Negative | (|) Unary() #Not | Unary() #Empty | Value() } /* * Value * Defines Prefix plus zero or more Suffixes */ void Value() : {} { (ValuePrefix() (ValueSuffix())*) #Value(>1) } /* * ValuePrefix * For Literals, Variables, and Functions */ void ValuePrefix() : {} { Literal() | NonLiteral() } /* * ValueSuffix * Either dot or bracket notation */ void ValueSuffix() : {} { ( DotSuffix() | BracketSuffix() ) ( MethodParameters())? } /* * DotSuffix * Dot Property */ void DotSuffix() #DotSuffix : { Token t = null; } { t= { jjtThis.setImage(t.image); } } /* * BracketSuffix * Sub Expression Suffix */ void BracketSuffix() #BracketSuffix : {} { Expression() } /* * MethodParameters */ void MethodParameters() #MethodParameters : {} { ( Expression() ( Expression())* )? } /* * NonLiteral * For Grouped Operations, Identifiers, and Functions */ void NonLiteral() : {} { Expression() | LOOKAHEAD(( )? ) Function() | Identifier() } /* * Identifier * Java Language Identifier */ void Identifier() #Identifier : { Token t = null; } { t= { jjtThis.setImage(t.image); } } /* * Function * Namespace:Name(a,b,c) */ void Function() #Function : { Token t0 = null; Token t1 = null; } { (LOOKAHEAD(2) t0= )? t1= { if (t0 != null) { jjtThis.setPrefix(t0.image); jjtThis.setLocalName(t1.image); } else { jjtThis.setLocalName(t1.image); } } (Expression() ( Expression())*)? } /* * Literal * Reserved Keywords */ void Literal() : {} { Boolean() | FloatingPoint() | Integer() | String() | Null() } /* * Boolean * For 'true' 'false' */ void Boolean() : {} { #True | #False } /* * FloatinPoint * For Decimal and Floating Point Literals */ void FloatingPoint() #FloatingPoint : { Token t = null; } { t= { jjtThis.setImage(t.image); } } /* * Integer * For Simple Numeric Literals */ void Integer() #Integer : { Token t = null; } { t= { jjtThis.setImage(t.image); } } /* * String * For Quoted Literals */ void String() #String : { Token t = null; } { t= { jjtThis.setImage(t.image); } } /* * Null * For 'null' */ void Null() #Null : {} { } /* ==================================================================================== */ TOKEN : { /* * The following definition uses + rather than * in two places to prevent * LITERAL_EXPRESSION matching the empty string that could result in the * Parser entering an infinite loop. */ < LITERAL_EXPRESSION: ( (~["$", "#", "\\"])* "\\" (["$", "#"])? | (~["$", "#"])* (["$", "#"] ~["{", "$", "#"]) | (~["$", "#"])+ )+ | "$" | "#" > | < START_DYNAMIC_EXPRESSION: "${" > : IN_EXPRESSION | < START_DEFERRED_EXPRESSION: "#{" > : IN_EXPRESSION } SKIP : { " " | "\t" | "\n" | "\r" } TOKEN : { < INTEGER_LITERAL: ["0"-"9"] (["0"-"9"])* > | < FLOATING_POINT_LITERAL: (["0"-"9"])+ "." (["0"-"9"])* ()? | "." (["0"-"9"])+ ()? | (["0"-"9"])+ > | < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > | < STRING_LITERAL: ("\"" ((~["\"","\\"]) | ("\\" ( ["\\","\"","\'"] )))* "\"") | ("\'" ((~["\'","\\"]) | ("\\" ( ["\\","\"","\'"] )))* "\'") > | < TRUE : "true" > | < FALSE : "false" > | < NULL : "null" > | < END_EXPRESSION : "}" > : DEFAULT | < DOT : "." > | < LPAREN : "(" > | < RPAREN : ")" > | < LBRACK : "[" > | < RBRACK : "]" > | < COLON : ":" > | < COMMA : "," > | < GT0 : ">" > | < GT1 : "gt" > | < LT0 : "<" > | < LT1 : "lt" > | < GE0 : ">=" > | < GE1 : "ge" > | < LE0 : "<=" > | < LE1 : "le" > | < EQ0 : "==" > | < EQ1 : "eq" > | < NE0 : "!=" > | < NE1 : "ne" > | < NOT0 : "!" > | < NOT1 : "not" > | < AND0 : "&&" > | < AND1 : "and" > | < OR0 : "||" > | < OR1 : "or" > | < EMPTY : "empty" > | < INSTANCEOF : "instanceof" > | < MULT : "*" > | < PLUS : "+" > | < MINUS : "-" > | < QUESTIONMARK : "?" > | < DIV0 : "/" > | < DIV1 : "div" > | < MOD0 : "%" > | < MOD1 : "mod" > | < IDENTIFIER : (|) (|)* > | < FUNCTIONSUFFIX : () > | < #IMPL_OBJ_START: "#" > | < #LETTER: [ "\u0024", "\u0041"-"\u005a", "\u005f", "\u0061"-"\u007a", "\u00c0"-"\u00d6", "\u00d8"-"\u00f6", "\u00f8"-"\u00ff", "\u0100"-"\u1fff", "\u3040"-"\u318f", "\u3300"-"\u337f", "\u3400"-"\u3d2d", "\u4e00"-"\u9fff", "\uf900"-"\ufaff" ] > | < #DIGIT: [ "\u0030"-"\u0039", "\u0660"-"\u0669", "\u06f0"-"\u06f9", "\u0966"-"\u096f", "\u09e6"-"\u09ef", "\u0a66"-"\u0a6f", "\u0ae6"-"\u0aef", "\u0b66"-"\u0b6f", "\u0be7"-"\u0bef", "\u0c66"-"\u0c6f", "\u0ce6"-"\u0cef", "\u0d66"-"\u0d6f", "\u0e50"-"\u0e59", "\u0ed0"-"\u0ed9", "\u1040"-"\u1049" ] > | < ILLEGAL_CHARACTER: (~[]) > } tomcat7-7.0.52/java/org/apache/el/parser/AstEmpty.java0000644000175100017510000000375412271461077022421 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstEmpty.java */ package org.apache.el.parser; import java.util.Collection; import java.util.Map; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstEmpty extends SimpleNode { public AstEmpty(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return Boolean.class; } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj = this.children[0].getValue(ctx); if (obj == null) { return Boolean.TRUE; } else if (obj instanceof String) { return Boolean.valueOf(((String) obj).length() == 0); } else if (obj instanceof Object[]) { return Boolean.valueOf(((Object[]) obj).length == 0); } else if (obj instanceof Collection) { return Boolean.valueOf(((Collection) obj).isEmpty()); } else if (obj instanceof Map) { return Boolean.valueOf(((Map) obj).isEmpty()); } return Boolean.FALSE; } } tomcat7-7.0.52/java/org/apache/el/parser/ELParser.html0000644000175100017510000002206312271461077022345 0ustar locutuslocutus BNF for ELParser.jj

    BNF for ELParser.jj

    NON-TERMINALS

    CompositeExpression ::= ( DeferredExpression | DynamicExpression | LiteralExpression )* <EOF>
    LiteralExpression ::= <LITERAL_EXPRESSION>
    DeferredExpression ::= <START_DEFERRED_EXPRESSION> Expression <END_EXPRESSION>
    DynamicExpression ::= <START_DYNAMIC_EXPRESSION> Expression <END_EXPRESSION>
    Expression ::= Choice
    Choice ::= Or ( <QUESTIONMARK> Choice <COLON> Choice )*
    Or ::= And ( ( <OR0> | <OR1> ) And )*
    And ::= Equality ( ( <AND0> | <AND1> ) Equality )*
    Equality ::= Compare ( ( ( <EQ0> | <EQ1> ) Compare ) | ( ( <NE0> | <NE1> ) Compare ) )*
    Compare ::= Math ( ( ( <LT0> | <LT1> ) Math ) | ( ( <GT0> | <GT1> ) Math ) | ( ( <LE0> | <LE1> ) Math ) | ( ( <GE0> | <GE1> ) Math ) )*
    Math ::= Multiplication ( ( <PLUS> Multiplication ) | ( <MINUS> Multiplication ) )*
    Multiplication ::= Unary ( ( <MULT> Unary ) | ( <DIV> Unary ) | ( ( <MOD0> | <MOD1> ) Unary ) )*
    Unary ::= <MINUS> Unary
    | ( <NOT0> | <NOT1> ) Unary
    | <EMPTY> Unary
    | Value
    Value ::= ( ValuePrefix ( ValueSuffix )* )
    ValuePrefix ::= Literal
    | NonLiteral
    ValueSuffix ::= DotSuffix
    | BracketSuffix
    DotSuffix ::= <DOT> <IDENTIFIER>
    BracketSuffix ::= <LBRACK> Expression <RBRACK>
    NonLiteral ::= <LPAREN> Expression <RPAREN>
    | Function
    | Identifier
    Identifier ::= <IDENTIFIER>
    Function ::= <IDENTIFIER> ( <FUNCTIONSUFFIX> )? <LPAREN> ( Expression ( <COMMA> Expression )* )? <RPAREN>
    Literal ::= Boolean
    | FloatingPoint
    | Integer
    | String
    | Null
    Boolean ::= <TRUE>
    | <FALSE>
    FloatingPoint ::= <FLOATING_POINT_LITERAL>
    Integer ::= <INTEGER_LITERAL>
    String ::= <STRING_LITERAL>
    Null ::= <NULL>
    tomcat7-7.0.52/java/org/apache/el/parser/ELParserTreeConstants.java0000644000175100017510000000355512271461077025044 0ustar locutuslocutus/* Generated By:JavaCC: Do not edit this line. ELParserTreeConstants.java Version 5.0 */ package org.apache.el.parser; public interface ELParserTreeConstants { public int JJTCOMPOSITEEXPRESSION = 0; public int JJTLITERALEXPRESSION = 1; public int JJTDEFERREDEXPRESSION = 2; public int JJTDYNAMICEXPRESSION = 3; public int JJTVOID = 4; public int JJTCHOICE = 5; public int JJTOR = 6; public int JJTAND = 7; public int JJTEQUAL = 8; public int JJTNOTEQUAL = 9; public int JJTLESSTHAN = 10; public int JJTGREATERTHAN = 11; public int JJTLESSTHANEQUAL = 12; public int JJTGREATERTHANEQUAL = 13; public int JJTPLUS = 14; public int JJTMINUS = 15; public int JJTMULT = 16; public int JJTDIV = 17; public int JJTMOD = 18; public int JJTNEGATIVE = 19; public int JJTNOT = 20; public int JJTEMPTY = 21; public int JJTVALUE = 22; public int JJTDOTSUFFIX = 23; public int JJTBRACKETSUFFIX = 24; public int JJTMETHODPARAMETERS = 25; public int JJTIDENTIFIER = 26; public int JJTFUNCTION = 27; public int JJTTRUE = 28; public int JJTFALSE = 29; public int JJTFLOATINGPOINT = 30; public int JJTINTEGER = 31; public int JJTSTRING = 32; public int JJTNULL = 33; public String[] jjtNodeName = { "CompositeExpression", "LiteralExpression", "DeferredExpression", "DynamicExpression", "void", "Choice", "Or", "And", "Equal", "NotEqual", "LessThan", "GreaterThan", "LessThanEqual", "GreaterThanEqual", "Plus", "Minus", "Mult", "Div", "Mod", "Negative", "Not", "Empty", "Value", "DotSuffix", "BracketSuffix", "MethodParameters", "Identifier", "Function", "True", "False", "FloatingPoint", "Integer", "String", "Null", }; } /* JavaCC - OriginalChecksum=437008e736f149e8fa6712fb36d831a1 (do not edit this line) */ tomcat7-7.0.52/java/org/apache/el/parser/AstFalse.java0000644000175100017510000000236312271461077022350 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstFalse.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstFalse extends BooleanNode { public AstFalse(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { return Boolean.FALSE; } } tomcat7-7.0.52/java/org/apache/el/parser/NodeVisitor.java0000644000175100017510000000171312271461077023111 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.parser; /** * @author Jacob Hookom [jacob@hookom.net] */ public interface NodeVisitor { public void visit(Node node) throws Exception; } tomcat7-7.0.52/java/org/apache/el/parser/AstInteger.java0000644000175100017510000000340112271461077022705 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstInteger.java */ package org.apache.el.parser; import java.math.BigInteger; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstInteger extends SimpleNode { public AstInteger(int id) { super(id); } private volatile Number number; protected Number getInteger() { if (this.number == null) { try { this.number = new Long(this.image); } catch (ArithmeticException e1) { this.number = new BigInteger(this.image); } } return number; } @Override public Class getType(EvaluationContext ctx) throws ELException { return this.getInteger().getClass(); } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.getInteger(); } } tomcat7-7.0.52/java/org/apache/el/parser/JJTELParserState.java0000644000175100017510000000635312271461077023677 0ustar locutuslocutus/* Generated By:JavaCC: Do not edit this line. JJTELParserState.java Version 5.0 */ package org.apache.el.parser; @SuppressWarnings("all") // Ignore warnings in generated code public class JJTELParserState { private java.util.List nodes; private java.util.List marks; private int sp; // number of nodes on stack private int mk; // current mark private boolean node_created; public JJTELParserState() { nodes = new java.util.ArrayList(); marks = new java.util.ArrayList(); sp = 0; mk = 0; } /* Determines whether the current node was actually closed and pushed. This should only be called in the final user action of a node scope. */ public boolean nodeCreated() { return node_created; } /* Call this to reinitialize the node stack. It is called automatically by the parser's ReInit() method. */ public void reset() { nodes.clear(); marks.clear(); sp = 0; mk = 0; } /* Returns the root node of the AST. It only makes sense to call this after a successful parse. */ public Node rootNode() { return nodes.get(0); } /* Pushes a node on to the stack. */ public void pushNode(Node n) { nodes.add(n); ++sp; } /* Returns the node on the top of the stack, and remove it from the stack. */ public Node popNode() { if (--sp < mk) { mk = marks.remove(marks.size()-1); } return nodes.remove(nodes.size()-1); } /* Returns the node currently on the top of the stack. */ public Node peekNode() { return nodes.get(nodes.size()-1); } /* Returns the number of children on the stack in the current node scope. */ public int nodeArity() { return sp - mk; } public void clearNodeScope(Node n) { while (sp > mk) { popNode(); } mk = marks.remove(marks.size()-1); } public void openNodeScope(Node n) { marks.add(mk); mk = sp; n.jjtOpen(); } /* A definite node is constructed from a specified number of children. That number of nodes are popped from the stack and made the children of the definite node. Then the definite node is pushed on to the stack. */ public void closeNodeScope(Node n, int num) { mk = marks.remove(marks.size()-1); while (num-- > 0) { Node c = popNode(); c.jjtSetParent(n); n.jjtAddChild(c, num); } n.jjtClose(); pushNode(n); node_created = true; } /* A conditional node is constructed if its condition is true. All the nodes that have been pushed since the node was opened are made children of the conditional node, which is then pushed on to the stack. If the condition is false the node is not constructed and they are left on the stack. */ public void closeNodeScope(Node n, boolean condition) { if (condition) { int a = nodeArity(); mk = marks.remove(marks.size()-1); while (a-- > 0) { Node c = popNode(); c.jjtSetParent(n); n.jjtAddChild(c, a); } n.jjtClose(); pushNode(n); node_created = true; } else { mk = marks.remove(marks.size()-1); node_created = false; } } } /* JavaCC - OriginalChecksum=70ac39f1e0e1eed7476e1dae2dfa25fa (do not edit this line) */ tomcat7-7.0.52/java/org/apache/el/parser/ParseException.java0000644000175100017510000001404212271461077023574 0ustar locutuslocutus/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 5.0 */ /* JavaCCOptions:KEEP_LINE_COL=null */ package org.apache.el.parser; /** * This exception is thrown when parse errors are encountered. * You can explicitly create objects of this exception type by * calling the method generateParseException in the generated * parser. * * You can modify this class to customize your error reporting * mechanisms so long as you retain the public fields. */ public class ParseException extends Exception { /** * The version identifier for this Serializable class. * Increment only if the serialized form of the * class changes. */ private static final long serialVersionUID = 1L; /** * This constructor is used by the method "generateParseException" * in the generated parser. Calling this constructor generates * a new object of this type with the fields "currentToken", * "expectedTokenSequences", and "tokenImage" set. */ public ParseException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal ) { super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal)); currentToken = currentTokenVal; expectedTokenSequences = expectedTokenSequencesVal; tokenImage = tokenImageVal; } /** * The following constructors are for use by you for whatever * purpose you can think of. Constructing the exception in this * manner makes the exception behave in the normal way - i.e., as * documented in the class "Throwable". The fields "errorToken", * "expectedTokenSequences", and "tokenImage" do not contain * relevant information. The JavaCC generated code does not use * these constructors. */ public ParseException() { super(); } /** Constructor with message. */ public ParseException(String message) { super(message); } /** * This is the last token that has been consumed successfully. If * this object has been created due to a parse error, the token * followng this token will (therefore) be the first error token. */ public Token currentToken; /** * Each entry in this array is an array of integers. Each array * of integers represents a sequence of tokens (by their ordinal * values) that is expected at this point of the parse. */ public int[][] expectedTokenSequences; /** * This is a reference to the "tokenImage" array of the generated * parser within which the parse error occurred. This array is * defined in the generated ...Constants interface. */ public String[] tokenImage; /** * It uses "currentToken" and "expectedTokenSequences" to generate a parse * error message and returns it. If this object has been created * due to a parse error, and you do not catch it (it gets thrown * from the parser) the correct error message * gets displayed. */ private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage) { String eol = System.getProperty("line.separator", "\n"); StringBuffer expected = new StringBuffer(); int maxSize = 0; for (int i = 0; i < expectedTokenSequences.length; i++) { if (maxSize < expectedTokenSequences[i].length) { maxSize = expectedTokenSequences[i].length; } for (int j = 0; j < expectedTokenSequences[i].length; j++) { expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' '); } if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { expected.append("..."); } expected.append(eol).append(" "); } String retval = "Encountered \""; Token tok = currentToken.next; for (int i = 0; i < maxSize; i++) { if (i != 0) retval += " "; if (tok.kind == 0) { retval += tokenImage[0]; break; } retval += " " + tokenImage[tok.kind]; retval += " \""; retval += add_escapes(tok.image); retval += " \""; tok = tok.next; } retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; retval += "." + eol; if (expectedTokenSequences.length == 1) { retval += "Was expecting:" + eol + " "; } else { retval += "Was expecting one of:" + eol + " "; } retval += expected.toString(); return retval; } /** * The end of line string for this machine. */ protected String eol = System.getProperty("line.separator", "\n"); /** * Used to convert raw characters to their escaped version * when these raw version cannot be used as part of an ASCII * string literal. */ static String add_escapes(String str) { StringBuffer retval = new StringBuffer(); char ch; for (int i = 0; i < str.length(); i++) { switch (str.charAt(i)) { case 0 : continue; case '\b': retval.append("\\b"); continue; case '\t': retval.append("\\t"); continue; case '\n': retval.append("\\n"); continue; case '\f': retval.append("\\f"); continue; case '\r': retval.append("\\r"); continue; case '\"': retval.append("\\\""); continue; case '\'': retval.append("\\\'"); continue; case '\\': retval.append("\\\\"); continue; default: if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { String s = "0000" + Integer.toString(ch, 16); retval.append("\\u" + s.substring(s.length() - 4, s.length())); } else { retval.append(ch); } continue; } } return retval.toString(); } } /* JavaCC - OriginalChecksum=87586a39aa89f164889cc59bc6a7e7ad (do not edit this line) */ tomcat7-7.0.52/java/org/apache/el/parser/AstDiv.java0000644000175100017510000000262612271461077022042 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstDiv.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.ELArithmetic; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstDiv extends ArithmeticNode { public AstDiv(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); return ELArithmetic.divide(obj0, obj1); } } tomcat7-7.0.52/java/org/apache/el/parser/AstMod.java0000644000175100017510000000262312271461077022034 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstMod.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.ELArithmetic; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstMod extends ArithmeticNode { public AstMod(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); return ELArithmetic.mod(obj0, obj1); } } tomcat7-7.0.52/java/org/apache/el/parser/AstNull.java0000644000175100017510000000254412271461077022231 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstNull.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstNull extends SimpleNode { public AstNull(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return null; } @Override public Object getValue(EvaluationContext ctx) throws ELException { return null; } } tomcat7-7.0.52/java/org/apache/el/parser/SimpleCharStream.java0000644000175100017510000002676212271461077024062 0ustar locutuslocutus/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */ /* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ package org.apache.el.parser; /** * An implementation of interface CharStream, where the stream is assumed to * contain only ASCII characters (without unicode processing). */ @SuppressWarnings("all") // Ignore warnings in generated code public class SimpleCharStream { /** Whether parser is static. */ public static final boolean staticFlag = false; int bufsize; int available; int tokenBegin; /** Position in buffer. */ public int bufpos = -1; protected int bufline[]; protected int bufcolumn[]; protected int column = 0; protected int line = 1; protected boolean prevCharIsCR = false; protected boolean prevCharIsLF = false; protected java.io.Reader inputStream; protected char[] buffer; protected int maxNextCharInd = 0; protected int inBuf = 0; protected int tabSize = 8; protected void setTabSize(int i) { tabSize = i; } protected int getTabSize(int i) { return tabSize; } protected void ExpandBuff(boolean wrapAround) { char[] newbuffer = new char[bufsize + 2048]; int newbufline[] = new int[bufsize + 2048]; int newbufcolumn[] = new int[bufsize + 2048]; try { if (wrapAround) { System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos); buffer = newbuffer; System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); bufline = newbufline; System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); bufcolumn = newbufcolumn; maxNextCharInd = (bufpos += (bufsize - tokenBegin)); } else { System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); buffer = newbuffer; System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); bufline = newbufline; System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); bufcolumn = newbufcolumn; maxNextCharInd = (bufpos -= tokenBegin); } } catch (Throwable t) { throw new Error(t.getMessage()); } bufsize += 2048; available = bufsize; tokenBegin = 0; } protected void FillBuff() throws java.io.IOException { if (maxNextCharInd == available) { if (available == bufsize) { if (tokenBegin > 2048) { bufpos = maxNextCharInd = 0; available = tokenBegin; } else if (tokenBegin < 0) bufpos = maxNextCharInd = 0; else ExpandBuff(false); } else if (available > tokenBegin) available = bufsize; else if ((tokenBegin - available) < 2048) ExpandBuff(true); else available = tokenBegin; } int i; try { if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { inputStream.close(); throw new java.io.IOException(); } else maxNextCharInd += i; return; } catch(java.io.IOException e) { --bufpos; backup(0); if (tokenBegin == -1) tokenBegin = bufpos; throw e; } } /** Start. */ public char BeginToken() throws java.io.IOException { tokenBegin = -1; char c = readChar(); tokenBegin = bufpos; return c; } protected void UpdateLineColumn(char c) { column++; if (prevCharIsLF) { prevCharIsLF = false; line += (column = 1); } else if (prevCharIsCR) { prevCharIsCR = false; if (c == '\n') { prevCharIsLF = true; } else line += (column = 1); } switch (c) { case '\r' : prevCharIsCR = true; break; case '\n' : prevCharIsLF = true; break; case '\t' : column--; column += (tabSize - (column % tabSize)); break; default : break; } bufline[bufpos] = line; bufcolumn[bufpos] = column; } /** Read a character. */ public char readChar() throws java.io.IOException { if (inBuf > 0) { --inBuf; if (++bufpos == bufsize) bufpos = 0; return buffer[bufpos]; } if (++bufpos >= maxNextCharInd) FillBuff(); char c = buffer[bufpos]; UpdateLineColumn(c); return c; } @Deprecated /** * @deprecated * @see #getEndColumn */ public int getColumn() { return bufcolumn[bufpos]; } @Deprecated /** * @deprecated * @see #getEndLine */ public int getLine() { return bufline[bufpos]; } /** Get token end column number. */ public int getEndColumn() { return bufcolumn[bufpos]; } /** Get token end line number. */ public int getEndLine() { return bufline[bufpos]; } /** Get token beginning column number. */ public int getBeginColumn() { return bufcolumn[tokenBegin]; } /** Get token beginning line number. */ public int getBeginLine() { return bufline[tokenBegin]; } /** Backup a number of characters. */ public void backup(int amount) { inBuf += amount; if ((bufpos -= amount) < 0) bufpos += bufsize; } /** Constructor. */ public SimpleCharStream(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; line = startline; column = startcolumn - 1; available = bufsize = buffersize; buffer = new char[buffersize]; bufline = new int[buffersize]; bufcolumn = new int[buffersize]; } /** Constructor. */ public SimpleCharStream(java.io.Reader dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } /** Constructor. */ public SimpleCharStream(java.io.Reader dstream) { this(dstream, 1, 1, 4096); } /** Reinitialise. */ public void ReInit(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; line = startline; column = startcolumn - 1; if (buffer == null || buffersize != buffer.length) { available = bufsize = buffersize; buffer = new char[buffersize]; bufline = new int[buffersize]; bufcolumn = new int[buffersize]; } prevCharIsLF = prevCharIsCR = false; tokenBegin = inBuf = maxNextCharInd = 0; bufpos = -1; } /** Reinitialise. */ public void ReInit(java.io.Reader dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } /** Reinitialise. */ public void ReInit(java.io.Reader dstream) { ReInit(dstream, 1, 1, 4096); } /** Constructor. */ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); } /** Constructor. */ public SimpleCharStream(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); } /** Constructor. */ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { this(dstream, encoding, startline, startcolumn, 4096); } /** Constructor. */ public SimpleCharStream(java.io.InputStream dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } /** Constructor. */ public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { this(dstream, encoding, 1, 1, 4096); } /** Constructor. */ public SimpleCharStream(java.io.InputStream dstream) { this(dstream, 1, 1, 4096); } /** Reinitialise. */ public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException { ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize); } /** Reinitialise. */ public void ReInit(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); } /** Reinitialise. */ public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { ReInit(dstream, encoding, 1, 1, 4096); } /** Reinitialise. */ public void ReInit(java.io.InputStream dstream) { ReInit(dstream, 1, 1, 4096); } /** Reinitialise. */ public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { ReInit(dstream, encoding, startline, startcolumn, 4096); } /** Reinitialise. */ public void ReInit(java.io.InputStream dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } /** Get token literal value. */ public String GetImage() { if (bufpos >= tokenBegin) return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); else return new String(buffer, tokenBegin, bufsize - tokenBegin) + new String(buffer, 0, bufpos + 1); } /** Get the suffix. */ public char[] GetSuffix(int len) { char[] ret = new char[len]; if ((bufpos + 1) >= len) System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); else { System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); } return ret; } /** Reset buffer when finished. */ public void Done() { buffer = null; bufline = null; bufcolumn = null; } /** * Method to adjust line and column numbers for the start of a token. */ public void adjustBeginLineColumn(int newLine, int newCol) { int start = tokenBegin; int len; if (bufpos >= tokenBegin) { len = bufpos - tokenBegin + inBuf + 1; } else { len = bufsize - tokenBegin + bufpos + 1 + inBuf; } int i = 0, j = 0, k = 0; int nextColDiff = 0, columnDiff = 0; while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { bufline[j] = newLine; nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; bufcolumn[j] = newCol + columnDiff; columnDiff = nextColDiff; i++; } if (i < len) { bufline[j] = newLine++; bufcolumn[j] = newCol + columnDiff; while (i++ < len) { if (bufline[j = start % bufsize] != bufline[++start % bufsize]) bufline[j] = newLine++; else bufline[j] = newLine; } } line = bufline[j]; column = bufcolumn[j]; } } /* JavaCC - OriginalChecksum=9ba0db3918bffb8019f00da1e421f339 (do not edit this line) */ tomcat7-7.0.52/java/org/apache/el/parser/AstFunction.java0000644000175100017510000001076012271461077023103 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstFunction.java */ package org.apache.el.parser; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.el.ELException; import javax.el.FunctionMapper; import org.apache.el.lang.EvaluationContext; import org.apache.el.util.MessageFactory; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstFunction extends SimpleNode { protected String localName = ""; protected String prefix = ""; public AstFunction(int id) { super(id); } public String getLocalName() { return localName; } public String getOutputName() { if (this.prefix == null) { return this.localName; } else { return this.prefix + ":" + this.localName; } } public String getPrefix() { return prefix; } @Override public Class getType(EvaluationContext ctx) throws ELException { FunctionMapper fnMapper = ctx.getFunctionMapper(); // quickly validate again for this request if (fnMapper == null) { throw new ELException(MessageFactory.get("error.fnMapper.null")); } Method m = fnMapper.resolveFunction(this.prefix, this.localName); if (m == null) { throw new ELException(MessageFactory.get("error.fnMapper.method", this.getOutputName())); } return m.getReturnType(); } @Override public Object getValue(EvaluationContext ctx) throws ELException { FunctionMapper fnMapper = ctx.getFunctionMapper(); // quickly validate again for this request if (fnMapper == null) { throw new ELException(MessageFactory.get("error.fnMapper.null")); } Method m = fnMapper.resolveFunction(this.prefix, this.localName); if (m == null) { throw new ELException(MessageFactory.get("error.fnMapper.method", this.getOutputName())); } Class[] paramTypes = m.getParameterTypes(); Object[] params = null; Object result = null; int numParams = this.jjtGetNumChildren(); if (numParams > 0) { params = new Object[numParams]; try { for (int i = 0; i < numParams; i++) { params[i] = this.children[i].getValue(ctx); params[i] = coerceToType(params[i], paramTypes[i]); } } catch (ELException ele) { throw new ELException(MessageFactory.get("error.function", this .getOutputName()), ele); } } try { result = m.invoke(null, params); } catch (IllegalAccessException iae) { throw new ELException(MessageFactory.get("error.function", this .getOutputName()), iae); } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof ThreadDeath) { throw (ThreadDeath) cause; } if (cause instanceof VirtualMachineError) { throw (VirtualMachineError) cause; } throw new ELException(MessageFactory.get("error.function", this .getOutputName()), cause); } return result; } public void setLocalName(String localName) { this.localName = localName; } public void setPrefix(String prefix) { this.prefix = prefix; } @Override public String toString() { return ELParserTreeConstants.jjtNodeName[id] + "[" + this.getOutputName() + "]"; } } tomcat7-7.0.52/java/org/apache/el/parser/SimpleNode.java0000644000175100017510000001306612271461077022707 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. SimpleNode.java */ package org.apache.el.parser; import java.util.Arrays; import javax.el.ELException; import javax.el.MethodInfo; import javax.el.PropertyNotWritableException; import javax.el.ValueReference; import org.apache.el.lang.ELSupport; import org.apache.el.lang.EvaluationContext; import org.apache.el.util.MessageFactory; /** * @author Jacob Hookom [jacob@hookom.net] */ public abstract class SimpleNode extends ELSupport implements Node { protected Node parent; protected Node[] children; protected int id; protected String image; public SimpleNode(int i) { id = i; } @Override public void jjtOpen() { // NOOP by default } @Override public void jjtClose() { // NOOP by default } @Override public void jjtSetParent(Node n) { parent = n; } @Override public Node jjtGetParent() { return parent; } @Override public void jjtAddChild(Node n, int i) { if (children == null) { children = new Node[i + 1]; } else if (i >= children.length) { Node c[] = new Node[i + 1]; System.arraycopy(children, 0, c, 0, children.length); children = c; } children[i] = n; } @Override public Node jjtGetChild(int i) { return children[i]; } @Override public int jjtGetNumChildren() { return (children == null) ? 0 : children.length; } /* * You can override these two methods in subclasses of SimpleNode to * customize the way the node appears when the tree is dumped. If your * output uses more than one line you should override toString(String), * otherwise overriding toString() is probably all you need to do. */ @Override public String toString() { if (this.image != null) { return ELParserTreeConstants.jjtNodeName[id] + "[" + this.image + "]"; } return ELParserTreeConstants.jjtNodeName[id]; } public String toString(String prefix) { return prefix + toString(); } @Override public String getImage() { return image; } public void setImage(String image) { this.image = image; } @Override public Class getType(EvaluationContext ctx) throws ELException { throw new UnsupportedOperationException(); } @Override public Object getValue(EvaluationContext ctx) throws ELException { throw new UnsupportedOperationException(); } @Override public boolean isReadOnly(EvaluationContext ctx) throws ELException { return true; } @Override public void setValue(EvaluationContext ctx, Object value) throws ELException { throw new PropertyNotWritableException(MessageFactory.get("error.syntax.set")); } @Override public void accept(NodeVisitor visitor) throws Exception { visitor.visit(this); if (this.children != null && this.children.length > 0) { for (int i = 0; i < this.children.length; i++) { this.children[i].accept(visitor); } } } @Override public Object invoke(EvaluationContext ctx, Class[] paramTypes, Object[] paramValues) throws ELException { throw new UnsupportedOperationException(); } @Override public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) throws ELException { throw new UnsupportedOperationException(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(children); result = prime * result + id; result = prime * result + ((image == null) ? 0 : image.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof SimpleNode)) { return false; } SimpleNode other = (SimpleNode) obj; if (!Arrays.equals(children, other.children)) { return false; } if (id != other.id) { return false; } if (image == null) { if (other.image != null) { return false; } } else if (!image.equals(other.image)) { return false; } return true; } /** * @since EL 2.2 */ @Override public ValueReference getValueReference(EvaluationContext ctx) { return null; } /** * @since EL 2.2 */ @Override public boolean isParametersProvided() { return false; } } tomcat7-7.0.52/java/org/apache/el/parser/AstMethodParameters.java0000644000175100017510000000334412271461077024562 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstDotSuffix.java */ package org.apache.el.parser; import java.util.ArrayList; import org.apache.el.lang.EvaluationContext; public final class AstMethodParameters extends SimpleNode { public AstMethodParameters(int id) { super(id); } public Object[] getParameters(EvaluationContext ctx) { ArrayList params = new ArrayList(); for (int i = 0; i < this.jjtGetNumChildren(); i++) { params.add(this.jjtGetChild(i).getValue(ctx)); } return params.toArray(new Object[params.size()]); } public Class[] getParameterTypes(EvaluationContext ctx) { ArrayList> paramTypes = new ArrayList>(); for (int i = 0; i < this.jjtGetNumChildren(); i++) { paramTypes.add(this.jjtGetChild(i).getType(ctx)); } return paramTypes.toArray(new Class[paramTypes.size()]); } } tomcat7-7.0.52/java/org/apache/el/parser/AstTrue.java0000644000175100017510000000235712271461077022240 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstTrue.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstTrue extends BooleanNode { public AstTrue(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { return Boolean.TRUE; } } tomcat7-7.0.52/java/org/apache/el/parser/AstBracketSuffix.java0000644000175100017510000000243312271461077024054 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstBracketSuffix.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstBracketSuffix extends SimpleNode { public AstBracketSuffix(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.children[0].getValue(ctx); } } tomcat7-7.0.52/java/org/apache/el/parser/AstNot.java0000644000175100017510000000274712271461077022064 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstNot.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstNot extends SimpleNode { public AstNot(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return Boolean.class; } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj = this.children[0].getValue(ctx); Boolean b = coerceToBoolean(obj); return Boolean.valueOf(!b.booleanValue()); } } tomcat7-7.0.52/java/org/apache/el/parser/AstAnd.java0000644000175100017510000000270712271461077022022 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstAnd.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstAnd extends BooleanNode { public AstAnd(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj = children[0].getValue(ctx); Boolean b = coerceToBoolean(obj); if (!b.booleanValue()) { return b; } obj = children[1].getValue(ctx); b = coerceToBoolean(obj); return b; } } tomcat7-7.0.52/java/org/apache/el/parser/AstNegative.java0000644000175100017510000000532412271461077023060 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstNegative.java */ package org.apache.el.parser; import java.math.BigDecimal; import java.math.BigInteger; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstNegative extends SimpleNode { public AstNegative(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return Number.class; } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj = this.children[0].getValue(ctx); if (obj == null) { return Long.valueOf(0); } if (obj instanceof BigDecimal) { return ((BigDecimal) obj).negate(); } if (obj instanceof BigInteger) { return ((BigInteger) obj).negate(); } if (obj instanceof String) { if (isStringFloat((String) obj)) { return new Double(-Double.parseDouble((String) obj)); } return Long.valueOf(-Long.parseLong((String) obj)); } if (obj instanceof Long) { return Long.valueOf(-((Long) obj).longValue()); } if (obj instanceof Double) { return new Double(-((Double) obj).doubleValue()); } if (obj instanceof Integer) { return Integer.valueOf(-((Integer) obj).intValue()); } if (obj instanceof Float) { return new Float(-((Float) obj).floatValue()); } if (obj instanceof Short) { return Short.valueOf((short) -((Short) obj).shortValue()); } if (obj instanceof Byte) { return Byte.valueOf((byte) -((Byte) obj).byteValue()); } Long num = (Long) coerceToNumber(obj, Long.class); return Long.valueOf(-num.longValue()); } } tomcat7-7.0.52/java/org/apache/el/parser/Token.java0000644000175100017510000001006312271461077021722 0ustar locutuslocutus/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */ /* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ package org.apache.el.parser; /** * Describes the input token stream. */ @SuppressWarnings("all") // Ignore warnings in generated code public class Token implements java.io.Serializable { /** * The version identifier for this Serializable class. * Increment only if the serialized form of the * class changes. */ private static final long serialVersionUID = 1L; /** * An integer that describes the kind of this token. This numbering * system is determined by JavaCCParser, and a table of these numbers is * stored in the file ...Constants.java. */ public int kind; /** The line number of the first character of this Token. */ public int beginLine; /** The column number of the first character of this Token. */ public int beginColumn; /** The line number of the last character of this Token. */ public int endLine; /** The column number of the last character of this Token. */ public int endColumn; /** * The string image of the token. */ public String image; /** * A reference to the next regular (non-special) token from the input * stream. If this is the last token from the input stream, or if the * token manager has not read tokens beyond this one, this field is * set to null. This is true only if this token is also a regular * token. Otherwise, see below for a description of the contents of * this field. */ public Token next; /** * This field is used to access special tokens that occur prior to this * token, but after the immediately preceding regular (non-special) token. * If there are no such special tokens, this field is set to null. * When there are more than one such special token, this field refers * to the last of these special tokens, which in turn refers to the next * previous special token through its specialToken field, and so on * until the first special token (whose specialToken field is null). * The next fields of special tokens refer to other special tokens that * immediately follow it (without an intervening regular token). If there * is no such token, this field is null. */ public Token specialToken; /** * An optional attribute value of the Token. * Tokens which are not used as syntactic sugar will often contain * meaningful values that will be used later on by the compiler or * interpreter. This attribute value is often different from the image. * Any subclass of Token that actually wants to return a non-null value can * override this method as appropriate. */ public Object getValue() { return null; } /** * No-argument constructor */ public Token() {} /** * Constructs a new token for the specified Image. */ public Token(int kind) { this(kind, null); } /** * Constructs a new token for the specified Image and Kind. */ public Token(int kind, String image) { this.kind = kind; this.image = image; } /** * Returns the image. */ public String toString() { return image; } /** * Returns a new Token object, by default. However, if you want, you * can create and return subclass objects based on the value of ofKind. * Simply add the cases to the switch for all those special cases. * For example, if you have a subclass of Token called IDToken that * you want to create if ofKind is ID, simply add something like : * * case MyParserConstants.ID : return new IDToken(ofKind, image); * * to the following switch statement. Then you can cast matchedToken * variable to the appropriate type and use sit in your lexical actions. */ public static Token newToken(int ofKind, String image) { switch(ofKind) { default : return new Token(ofKind, image); } } public static Token newToken(int ofKind) { return newToken(ofKind, null); } } /* JavaCC - OriginalChecksum=3fc97649fffa8b13e1e03af022020b2f (do not edit this line) */ tomcat7-7.0.52/java/org/apache/el/parser/AstMinus.java0000644000175100017510000000263612271461077022414 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstMinus.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.ELArithmetic; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstMinus extends ArithmeticNode { public AstMinus(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); return ELArithmetic.subtract(obj0, obj1); } } tomcat7-7.0.52/java/org/apache/el/parser/AstEqual.java0000644000175100017510000000256512271461077022371 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstEqual.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstEqual extends BooleanNode { public AstEqual(int id) { super(id); } @Override public Object getValue(EvaluationContext ctx) throws ELException { Object obj0 = this.children[0].getValue(ctx); Object obj1 = this.children[1].getValue(ctx); return Boolean.valueOf(equals(obj0, obj1)); } } tomcat7-7.0.52/java/org/apache/el/parser/Node.java0000644000175100017510000000541212271461077021531 0ustar locutuslocutus/* Generated By:JJTree: Do not edit this line. Node.java */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.parser; import javax.el.ELException; import javax.el.MethodInfo; import javax.el.ValueReference; import org.apache.el.lang.EvaluationContext; /* All AST nodes must implement this interface. It provides basic machinery for constructing the parent and child relationships between nodes. */ /** * @author Jacob Hookom [jacob@hookom.net] */ public interface Node { /** This method is called after the node has been made the current node. It indicates that child nodes can now be added to it. */ public void jjtOpen(); /** This method is called after all the child nodes have been added. */ public void jjtClose(); /** This pair of methods are used to inform the node of its parent. */ public void jjtSetParent(Node n); public Node jjtGetParent(); /** This method tells the node to add its argument to the node's list of children. */ public void jjtAddChild(Node n, int i); /** This method returns a child node. The children are numbered from zero, left to right. */ public Node jjtGetChild(int i); /** Return the number of children the node has. */ public int jjtGetNumChildren(); public String getImage(); public Object getValue(EvaluationContext ctx) throws ELException; public void setValue(EvaluationContext ctx, Object value) throws ELException; public Class getType(EvaluationContext ctx) throws ELException; public boolean isReadOnly(EvaluationContext ctx) throws ELException; public void accept(NodeVisitor visitor) throws Exception; public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) throws ELException; public Object invoke(EvaluationContext ctx, Class[] paramTypes, Object[] paramValues) throws ELException; /** * @since EL 2.2 */ public ValueReference getValueReference(EvaluationContext ctx); /** * @since EL 2.2 */ public boolean isParametersProvided(); } tomcat7-7.0.52/java/org/apache/el/parser/AstLiteralExpression.java0000644000175100017510000000406512271461077024773 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /* Generated By:JJTree: Do not edit this line. AstLiteralExpression.java */ package org.apache.el.parser; import javax.el.ELException; import org.apache.el.lang.EvaluationContext; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class AstLiteralExpression extends SimpleNode { public AstLiteralExpression(int id) { super(id); } @Override public Class getType(EvaluationContext ctx) throws ELException { return String.class; } @Override public Object getValue(EvaluationContext ctx) throws ELException { return this.image; } @Override public void setImage(String image) { if (image.indexOf('\\') == -1) { this.image = image; return; } int size = image.length(); StringBuilder buf = new StringBuilder(size); for (int i = 0; i < size; i++) { char c = image.charAt(i); if (c == '\\' && i + 2 < size) { char c1 = image.charAt(i + 1); char c2 = image.charAt(i + 2); if ((c1 == '#' || c1 == '$') && c2 == '{') { c = c1; i++; } } buf.append(c); } this.image = buf.toString(); } } tomcat7-7.0.52/java/org/apache/el/Messages_es.properties0000644000175100017510000000612612271461077023064 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. error.convert = No puedo convertir {0} desde tipo {1} a {2} error.compare = No puedo comparar {0} con {1} error.function = Problemas llamando a funci\u00F3n ''{0}'' error.unreachable.base = Objetivo inalcanzable, identificador ''{0}'' resuelto a nulo error.unreachable.property = Objetivo inalcanzable, ''{0}'' devolvi\u00F3 nulo error.resolver.unhandled = ELResolver no manej\u00F3 el tipo\: {0} con propiedad de ''{1}'' error.resolver.unhandled.null = ELResolver no puede manejar un Objeto base nulo con identificador de ''{0}'' error.value.literal.write = ValueExpression es un literal y no un grabable\: {0} error.null = La expresi\u00F3n no puede ser nula error.mixed = La expresi\u00F3n no puede contenera la vez '\#{..}' y '${..}' \: {0} error.method = No es una MethodExpression v\u00E1lida\: {0} error.method.nullParms = Los tipos de par\u00E1metro no pueden ser nulo error.value.expectedType = El tipo esperado no puede ser nulo error.eval = Error Evaluando {0} \: {1} error.syntax.set = Sit\u00E1xis ilegal para Operaci\u00F3n de Poner Valor error.method.notfound = M\u00E9todo no hallado\: {0}.{1}({2}) error.method.ambiguous = No pude hallar m\u00E9todo ambiguo\: {0}.{1}({2}) error.property.notfound = Propiedad ''{1}'' no hallada en tipo\: {0} error.fnMapper.null = La expresi\u00F3n usa funciones, pero no se ha suministrado FunctionMapper error.fnMapper.method = Funci\u00F3n "{0}" no hallada error.fnMapper.paramcount = La funci\u00F3n ''{0}'' especifica {1} par\u00E9metros, pero {2} fueron declarados error.context.null = ELContext era nulo error.array.outofbounds = \u00CDndice {0} fuera de l\u00EDmites para arreglo de medida {1} error.list.outofbounds = \u00CDndice {0} fuera de l\u00EDmites para lista de medida {1} error.property.invocation = Propiedad ''{1}'' lanz\u00F3 una excepci\u00F3n desde tipo\: {0} error.property.notreadable = La propiedad ''{1}'' no tiene un 'get' especificado en el tipo\: {0} error.property.notwritable = La propiedad ''{1}'' no tiene un 'set' especificado en el tipo\: {0} error.identifier.notjava = El identificador [{0}] no es un identificado Java v\u00E1lido seg\u00FAn se requiere en la secci\u00F3n 1.9 de la especificaci\u00F3n EL (Identificador \:\:\= identificador de lenguaje Java). Este chequeo se puede desactivar poniendo la propiedad del sistema org.apache.el.parser.SKIP_IDENTIFIER_CHECK a verdad (true). tomcat7-7.0.52/java/org/apache/el/util/0000755000175100017510000000000012301126371017445 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/el/util/Validation.java0000644000175100017510000000747111503171347022421 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.util; import java.security.AccessController; import java.security.PrivilegedAction; public class Validation { // Java keywords, boolean literals & the null literal in alphabetical order private static final String invalidIdentifiers[] = { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while" }; private static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); private static final boolean SKIP_IDENTIFIER_CHECK; static { if (IS_SECURITY_ENABLED) { SKIP_IDENTIFIER_CHECK = AccessController.doPrivileged( new PrivilegedAction(){ @Override public Boolean run() { return Boolean.valueOf(System.getProperty( "org.apache.el.parser.SKIP_IDENTIFIER_CHECK", "false")); } } ).booleanValue(); } else { SKIP_IDENTIFIER_CHECK = Boolean.valueOf(System.getProperty( "org.apache.el.parser.SKIP_IDENTIFIER_CHECK", "false")).booleanValue(); } } private Validation() { // Utility class. Hide default constructor } /** * Test whether the argument is a Java identifier. */ public static boolean isIdentifier(String key) { if (SKIP_IDENTIFIER_CHECK) { return true; } // Should not be the case but check to be sure if (key == null || key.length() == 0) { return false; } // Check the list of known invalid values int i = 0; int j = invalidIdentifiers.length; while (i < j) { int k = (i + j) >>> 1; // Avoid overflow int result = invalidIdentifiers[k].compareTo(key); if (result == 0) { return false; } if (result < 0) { i = k + 1; } else { j = k; } } // Check the start character that has more restrictions if (!Character.isJavaIdentifierStart(key.charAt(0))) { return false; } // Check each remaining character used is permitted for (int idx = 1; idx < key.length(); idx++) { if (!Character.isJavaIdentifierPart(key.charAt(idx))) { return false; } } return true; } } tomcat7-7.0.52/java/org/apache/el/util/ConcurrentCache.java0000644000175100017510000000340212271461077023370 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.util; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; public final class ConcurrentCache { private final int size; private final Map eden; private final Map longterm; public ConcurrentCache(int size) { this.size = size; this.eden = new ConcurrentHashMap(size); this.longterm = new WeakHashMap(size); } public V get(K k) { V v = this.eden.get(k); if (v == null) { synchronized (longterm) { v = this.longterm.get(k); } if (v != null) { this.eden.put(k, v); } } return v; } public void put(K k, V v) { if (this.eden.size() >= size) { synchronized (longterm) { this.longterm.putAll(this.eden); } this.eden.clear(); } this.eden.put(k, v); } } tomcat7-7.0.52/java/org/apache/el/util/ReflectionUtil.java0000644000175100017510000003047412271461077023263 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.util; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.el.ELException; import javax.el.MethodNotFoundException; import org.apache.el.lang.ELSupport; /** * Utilities for Managing Serialization and Reflection * * @author Jacob Hookom [jacob@hookom.net] */ public class ReflectionUtil { protected static final String[] PRIMITIVE_NAMES = new String[] { "boolean", "byte", "char", "double", "float", "int", "long", "short", "void" }; protected static final Class[] PRIMITIVES = new Class[] { boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class, Void.TYPE }; private ReflectionUtil() { super(); } public static Class forName(String name) throws ClassNotFoundException { if (null == name || "".equals(name)) { return null; } Class c = forNamePrimitive(name); if (c == null) { if (name.endsWith("[]")) { String nc = name.substring(0, name.length() - 2); c = Class.forName(nc, true, Thread.currentThread().getContextClassLoader()); c = Array.newInstance(c, 0).getClass(); } else { c = Class.forName(name, true, Thread.currentThread().getContextClassLoader()); } } return c; } protected static Class forNamePrimitive(String name) { if (name.length() <= 8) { int p = Arrays.binarySearch(PRIMITIVE_NAMES, name); if (p >= 0) { return PRIMITIVES[p]; } } return null; } /** * Converts an array of Class names to Class types * @param s * @throws ClassNotFoundException */ public static Class[] toTypeArray(String[] s) throws ClassNotFoundException { if (s == null) return null; Class[] c = new Class[s.length]; for (int i = 0; i < s.length; i++) { c[i] = forName(s[i]); } return c; } /** * Converts an array of Class types to Class names * @param c */ public static String[] toTypeNameArray(Class[] c) { if (c == null) return null; String[] s = new String[c.length]; for (int i = 0; i < c.length; i++) { s[i] = c[i].getName(); } return s; } /** * Returns a method based on the criteria * @param base the object that owns the method * @param property the name of the method * @param paramTypes the parameter types to use * @param paramValues the parameter values * @return the method specified * @throws MethodNotFoundException */ @SuppressWarnings("null") public static Method getMethod(Object base, Object property, Class[] paramTypes, Object[] paramValues) throws MethodNotFoundException { if (base == null || property == null) { throw new MethodNotFoundException(MessageFactory.get( "error.method.notfound", base, property, paramString(paramTypes))); } String methodName = (property instanceof String) ? (String) property : property.toString(); int paramCount; if (paramTypes == null) { paramCount = 0; } else { paramCount = paramTypes.length; } Method[] methods = base.getClass().getMethods(); Map candidates = new HashMap(); for (Method m : methods) { if (!m.getName().equals(methodName)) { // Method name doesn't match continue; } Class[] mParamTypes = m.getParameterTypes(); int mParamCount; if (mParamTypes == null) { mParamCount = 0; } else { mParamCount = mParamTypes.length; } // Check the number of parameters if (!(paramCount == mParamCount || (m.isVarArgs() && paramCount >= mParamCount))) { // Method has wrong number of parameters continue; } // Check the parameters match int exactMatch = 0; boolean noMatch = false; for (int i = 0; i < mParamCount; i++) { // Can't be null if (mParamTypes[i].equals(paramTypes[i])) { exactMatch++; } else if (i == (mParamCount - 1) && m.isVarArgs()) { Class varType = mParamTypes[i].getComponentType(); for (int j = i; j < paramCount; j++) { if (!isAssignableFrom(paramTypes[j], varType)) { if (paramValues == null) { noMatch = true; break; } else { if (!isCoercibleFrom(paramValues[j], varType)) { noMatch = true; break; } } } // Don't treat a varArgs match as an exact match, it can // lead to a varArgs method matching when the result // should be ambiguous } } else if (!isAssignableFrom(paramTypes[i], mParamTypes[i])) { if (paramValues == null) { noMatch = true; break; } else { if (!isCoercibleFrom(paramValues[i], mParamTypes[i])) { noMatch = true; break; } } } } if (noMatch) { continue; } // If a method is found where every parameter matches exactly, // return it if (exactMatch == paramCount) { return m; } candidates.put(m, Integer.valueOf(exactMatch)); } // Look for the method that has the highest number of parameters where // the type matches exactly int bestMatch = 0; Method match = null; boolean multiple = false; for (Map.Entry entry : candidates.entrySet()) { if (entry.getValue().intValue() > bestMatch || match == null) { bestMatch = entry.getValue().intValue(); match = entry.getKey(); multiple = false; } else if (entry.getValue().intValue() == bestMatch) { multiple = true; } } if (multiple) { if (bestMatch == paramCount - 1) { // Only one parameter is not an exact match - try using the // super class match = resolveAmbiguousMethod(candidates.keySet(), paramTypes); } else { match = null; } if (match == null) { // If multiple methods have the same matching number of parameters // the match is ambiguous so throw an exception throw new MethodNotFoundException(MessageFactory.get( "error.method.ambiguous", base, property, paramString(paramTypes))); } } // Handle case where no match at all was found if (match == null) { throw new MethodNotFoundException(MessageFactory.get( "error.method.notfound", base, property, paramString(paramTypes))); } return match; } private static Method resolveAmbiguousMethod(Set candidates, Class[] paramTypes) { // Identify which parameter isn't an exact match Method m = candidates.iterator().next(); int nonMatchIndex = 0; Class nonMatchClass = null; for (int i = 0; i < paramTypes.length; i++) { if (m.getParameterTypes()[i] != paramTypes[i]) { nonMatchIndex = i; nonMatchClass = paramTypes[i]; break; } } if (nonMatchClass == null) { // Null will always be ambiguous return null; } for (Method c : candidates) { if (c.getParameterTypes()[nonMatchIndex] == paramTypes[nonMatchIndex]) { // Methods have different non-matching parameters // Result is ambiguous return null; } } // Can't be null nonMatchClass = nonMatchClass.getSuperclass(); while (nonMatchClass != null) { for (Method c : candidates) { if (c.getParameterTypes()[nonMatchIndex].equals( nonMatchClass)) { // Found a match return c; } } nonMatchClass = nonMatchClass.getSuperclass(); } return null; } // src will always be an object private static boolean isAssignableFrom(Class src, Class target) { // Short-cut. null is always assignable to an object and in EL null // can always be coerced to a valid value for a primitive if (src == null) { return true; } Class targetClass; if (target.isPrimitive()) { if (target == Boolean.TYPE) { targetClass = Boolean.class; } else if (target == Character.TYPE) { targetClass = Character.class; } else if (target == Byte.TYPE) { targetClass = Byte.class; } else if (target == Short.TYPE) { targetClass = Short.class; } else if (target == Integer.TYPE) { targetClass = Integer.class; } else if (target == Long.TYPE) { targetClass = Long.class; } else if (target == Float.TYPE) { targetClass = Float.class; } else { targetClass = Double.class; } } else { targetClass = target; } return targetClass.isAssignableFrom(src); } private static boolean isCoercibleFrom(Object src, Class target) { // TODO: This isn't pretty but it works. Significant refactoring would // be required to avoid the exception. try { ELSupport.coerceToType(src, target); } catch (ELException e) { return false; } return true; } protected static final String paramString(Class[] types) { if (types != null) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < types.length; i++) { if (types[i] == null) { sb.append("null, "); } else { sb.append(types[i].getName()).append(", "); } } if (sb.length() > 2) { sb.setLength(sb.length() - 2); } return sb.toString(); } return null; } } tomcat7-7.0.52/java/org/apache/el/util/MessageFactory.java0000644000175100017510000000301712271461077023240 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el.util; import java.text.MessageFormat; import java.util.ResourceBundle; /** * @author Jacob Hookom [jacob@hookom.net] */ public final class MessageFactory { protected static final ResourceBundle bundle = ResourceBundle.getBundle("org.apache.el.Messages"); public MessageFactory() { super(); } public static String get(final String key) { return bundle.getString(key); } public static String get(final String key, final Object... args) { String value = get(key); if (value == null) { value = key; } MessageFormat mf = new MessageFormat(value); return mf.format(args, new StringBuffer(), null).toString(); } } tomcat7-7.0.52/java/org/apache/el/Messages.properties0000644000175100017510000000613712271461077022377 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # General Errors error.convert=Cannot convert {0} of type {1} to {2} error.compare=Cannot compare {0} to {1} error.function=Problems calling function ''{0}'' error.unreachable.base=Target Unreachable, identifier ''{0}'' resolved to null error.unreachable.property=Target Unreachable, ''{0}'' returned null error.resolver.unhandled=ELResolver did not handle type: {0} with property of ''{1}'' error.resolver.unhandled.null=ELResolver cannot handle a null base Object with identifier ''{0}'' # ValueExpressionLiteral error.value.literal.write=ValueExpression is a literal and not writable: {0} # ExpressionFactoryImpl error.null=Expression cannot be null error.mixed=Expression cannot contain both '#{..}' and '${..}' : {0} error.method=Not a valid MethodExpression : {0} error.method.nullParms=Parameter types cannot be null error.value.expectedType=Expected type cannot be null # ExpressionBuilder error.parseFail=Failed to parse the expression [{0}] # ExpressionMediator error.eval=Error Evaluating {0} : {1} # ValueSetVisitor error.syntax.set=Illegal Syntax for Set Operation # ReflectionUtil error.method.notfound=Method not found: {0}.{1}({2}) error.method.ambiguous=Unable to find unambiguous method: {0}.{1}({2}) error.property.notfound=Property ''{1}'' not found on {0} # ValidatingVisitor error.fnMapper.null=Expression uses functions, but no FunctionMapper was provided error.fnMapper.method=Function ''{0}'' not found error.fnMapper.paramcount=Function ''{0}'' specifies {1} params, but {2} were declared # ExpressionImpl error.context.null=ELContext was null # ArrayELResolver error.array.outofbounds=Index {0} is out of bounds for array of size {1} # ListELResolver error.list.outofbounds=Index {0} is out of bounds for list of size {1} # BeanELResolver error.property.notfound=Property ''{1}'' not found on type: {0} error.property.invocation=Property ''{1}'' threw an exception from type: {0} error.property.notreadable=Property ''{1}'' doesn't have a 'get' specified on type: {0} error.property.notwritable=Property ''{1}'' doesn't have a 'set' specified on type: {0} # Parser error.identifier.notjava=The identifier [{0}] is not a valid Java identifier as required by section 1.19 of the EL specification (Identifier ::= Java language identifier). This check can be disabled by setting the system property org.apache.el.parser.SKIP_IDENTIFIER_CHECK to true.tomcat7-7.0.52/java/org/apache/el/MethodExpressionLiteral.java0000644000175100017510000000614112271461077024165 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.el; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import javax.el.ELContext; import javax.el.ELException; import javax.el.MethodExpression; import javax.el.MethodInfo; import org.apache.el.lang.ELSupport; import org.apache.el.util.ReflectionUtil; public class MethodExpressionLiteral extends MethodExpression implements Externalizable { private Class expectedType; private String expr; private Class[] paramTypes; public MethodExpressionLiteral() { // do nothing } public MethodExpressionLiteral(String expr, Class expectedType, Class[] paramTypes) { this.expr = expr; this.expectedType = expectedType; this.paramTypes = paramTypes; } @Override public MethodInfo getMethodInfo(ELContext context) throws ELException { return new MethodInfo(this.expr, this.expectedType, this.paramTypes); } @Override public Object invoke(ELContext context, Object[] params) throws ELException { if (this.expectedType != null) { return ELSupport.coerceToType(this.expr, this.expectedType); } else { return this.expr; } } @Override public String getExpressionString() { return this.expr; } @Override public boolean equals(Object obj) { return (obj instanceof MethodExpressionLiteral && this.hashCode() == obj.hashCode()); } @Override public int hashCode() { return this.expr.hashCode(); } @Override public boolean isLiteralText() { return true; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.expr = in.readUTF(); String type = in.readUTF(); if (!"".equals(type)) { this.expectedType = ReflectionUtil.forName(type); } this.paramTypes = ReflectionUtil.toTypeArray(((String[]) in .readObject())); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(this.expr); out.writeUTF((this.expectedType != null) ? this.expectedType.getName() : ""); out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes)); } } tomcat7-7.0.52/java/org/apache/catalina/0000755000175100017510000000000012301126371017644 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/Wrapper.java0000644000175100017510000002761412271471332022147 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import javax.servlet.MultipartConfigElement; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.UnavailableException; /** * A Wrapper is a Container that represents an individual servlet * definition from the deployment descriptor of the web application. It * provides a convenient mechanism to use Interceptors that see every single * request to the servlet represented by this definition. *

    * Implementations of Wrapper are responsible for managing the servlet life * cycle for their underlying servlet class, including calling init() and * destroy() at appropriate times, as well as respecting the existence of * the SingleThreadModel declaration on the servlet class itself. *

    * The parent Container attached to a Wrapper will generally be an * implementation of Context, representing the servlet context (and * therefore the web application) within which this servlet executes. *

    * Child Containers are not allowed on Wrapper implementations, so the * addChild() method should throw an * IllegalArgumentException. * * @author Craig R. McClanahan */ public interface Wrapper extends Container { /** * Container event for adding a wrapper. */ public static final String ADD_MAPPING_EVENT = "addMapping"; /** * Container event for removing a wrapper. */ public static final String REMOVE_MAPPING_EVENT = "removeMapping"; // ------------------------------------------------------------- Properties /** * Return the available date/time for this servlet, in milliseconds since * the epoch. If this date/time is in the future, any request for this * servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero, * the servlet is currently available. A value equal to Long.MAX_VALUE * is considered to mean that unavailability is permanent. */ public long getAvailable(); /** * Set the available date/time for this servlet, in milliseconds since the * epoch. If this date/time is in the future, any request for this servlet * will return an SC_SERVICE_UNAVAILABLE error. A value equal to * Long.MAX_VALUE is considered to mean that unavailability is permanent. * * @param available The new available date/time */ public void setAvailable(long available); /** * Return the load-on-startup order value (negative value means * load on first call). */ public int getLoadOnStartup(); /** * Set the load-on-startup order value (negative value means * load on first call). * * @param value New load-on-startup value */ public void setLoadOnStartup(int value); /** * Return the run-as identity for this servlet. */ public String getRunAs(); /** * Set the run-as identity for this servlet. * * @param runAs New run-as identity value */ public void setRunAs(String runAs); /** * Return the fully qualified servlet class name for this servlet. */ public String getServletClass(); /** * Set the fully qualified servlet class name for this servlet. * * @param servletClass Servlet class name */ public void setServletClass(String servletClass); /** * Gets the names of the methods supported by the underlying servlet. * * This is the same set of methods included in the Allow response header * in response to an OPTIONS request method processed by the underlying * servlet. * * @return Array of names of the methods supported by the underlying * servlet */ public String[] getServletMethods() throws ServletException; /** * Is this servlet currently unavailable? */ public boolean isUnavailable(); /** * Return the associated servlet instance. */ public Servlet getServlet(); /** * Set the associated servlet instance */ public void setServlet(Servlet servlet); // --------------------------------------------------------- Public Methods /** * Add a new servlet initialization parameter for this servlet. * * @param name Name of this initialization parameter to add * @param value Value of this initialization parameter to add */ public void addInitParameter(String name, String value); /** * Add a new listener interested in InstanceEvents. * * @param listener The new listener */ public void addInstanceListener(InstanceListener listener); /** * Add a mapping associated with the Wrapper. * * @param mapping The new wrapper mapping */ public void addMapping(String mapping); /** * Add a new security role reference record to the set of records for * this servlet. * * @param name Role name used within this servlet * @param link Role name used within the web application */ public void addSecurityReference(String name, String link); /** * Allocate an initialized instance of this Servlet that is ready to have * its service() method called. If the servlet class does * not implement SingleThreadModel, the (only) initialized * instance may be returned immediately. If the servlet class implements * SingleThreadModel, the Wrapper implementation must ensure * that this instance is not allocated again until it is deallocated by a * call to deallocate(). * * @exception ServletException if the servlet init() method threw * an exception * @exception ServletException if a loading error occurs */ public Servlet allocate() throws ServletException; /** * Return this previously allocated servlet to the pool of available * instances. If this servlet class does not implement SingleThreadModel, * no action is actually required. * * @param servlet The servlet to be returned * * @exception ServletException if a deallocation error occurs */ public void deallocate(Servlet servlet) throws ServletException; /** * Return the value for the specified initialization parameter name, * if any; otherwise return null. * * @param name Name of the requested initialization parameter */ public String findInitParameter(String name); /** * Return the names of all defined initialization parameters for this * servlet. */ public String[] findInitParameters(); /** * Return the mappings associated with this wrapper. */ public String[] findMappings(); /** * Return the security role link for the specified security role * reference name, if any; otherwise return null. * * @param name Security role reference used within this servlet */ public String findSecurityReference(String name); /** * Return the set of security role reference names associated with * this servlet, if any; otherwise return a zero-length array. */ public String[] findSecurityReferences(); /** * Increment the error count value used when monitoring. */ public void incrementErrorCount(); /** * Load and initialize an instance of this servlet, if there is not already * at least one initialized instance. This can be used, for example, to * load servlets that are marked in the deployment descriptor to be loaded * at server startup time. * * @exception ServletException if the servlet init() method threw * an exception * @exception ServletException if some other loading problem occurs */ public void load() throws ServletException; /** * Remove the specified initialization parameter from this servlet. * * @param name Name of the initialization parameter to remove */ public void removeInitParameter(String name); /** * Remove a listener no longer interested in InstanceEvents. * * @param listener The listener to remove */ public void removeInstanceListener(InstanceListener listener); /** * Remove a mapping associated with the wrapper. * * @param mapping The pattern to remove */ public void removeMapping(String mapping); /** * Remove any security role reference for the specified role name. * * @param name Security role used within this servlet to be removed */ public void removeSecurityReference(String name); /** * Process an UnavailableException, marking this servlet as unavailable * for the specified amount of time. * * @param unavailable The exception that occurred, or null * to mark this servlet as permanently unavailable */ public void unavailable(UnavailableException unavailable); /** * Unload all initialized instances of this servlet, after calling the * destroy() method for each instance. This can be used, * for example, prior to shutting down the entire servlet engine, or * prior to reloading all of the classes from the Loader associated with * our Loader's repository. * * @exception ServletException if an unload error occurs */ public void unload() throws ServletException; /** * Get the multi-part configuration for the associated servlet. If no * multi-part configuration has been defined, then null will be * returned. */ public MultipartConfigElement getMultipartConfigElement(); /** * Set the multi-part configuration for the associated servlet. To clear the * multi-part configuration specify null as the new value. */ public void setMultipartConfigElement( MultipartConfigElement multipartConfig); /** * Does the associated Servlet support async processing? Defaults to * true */ public boolean isAsyncSupported(); /** * Set the async support for the associated servlet. */ public void setAsyncSupported(boolean asyncSupport); /** * Is the associated Servlet enabled? Defaults to true. */ public boolean isEnabled(); /** * Sets the enabled attribute for the associated servlet. */ public void setEnabled(boolean enabled); /** * Set the flag that indicates * {@link javax.servlet.annotation.ServletSecurity} annotations must be * scanned when the Servlet is first used. * * @param b The new value of the flag */ public void setServletSecurityAnnotationScanRequired(boolean b); /** * Scan for (if necessary) and process (if found) the * {@link javax.servlet.annotation.ServletSecurity} annotations for the * Servlet associated with this wrapper. */ public void servletSecurityAnnotationScan() throws ServletException; /** * Is the Servlet overridable by a ServletContainerInitializer? */ public boolean isOverridable(); /** * Sets the overridable attribute for this Servlet. */ public void setOverridable(boolean overridable); } tomcat7-7.0.52/java/org/apache/catalina/valves/0000755000175100017510000000000012301126371021144 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/valves/LocalStrings_es.properties0000644000175100017510000001651612271471332026374 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. requestFilterValve.next = No hay ''siguiente'' v\u00E1lvula configurada requestFilterValve.syntax = Error de sint\u00E1xis en petici\u00F3n de filtro patr\u00F3n {0} valveBase.noNext = Error de configuraci\u00F3n\: No hay ''siguiente'' v\u00E1lvula configurada jdbcAccessLogValve.exception = Excepci\u00F3n realizando entrada de acceso a inserci\u00F3n jdbcAccessLogValve.close = Excepci\u00F3n cerrando conexi\u00F3n a base de datos cometConnectionManagerValve.event = Excepci\u00F3n procesando evento cometConnectionManagerValve.listenerEvent = Excepci\u00F3n procesando evento de oyente de sesi\u00F3n accessLogValve.closeFail = No pude cerrar fichero de historial accessLogValve.openDirFail = No pude crear directorio [{0}] para historiales de acceso accessLogValve.rotateFail = No pude rotar historial de acceso # Error report valve errorReportValve.errorReport = Informe de Error errorReportValve.statusHeader = Estado HTTP {0} - {1} errorReportValve.exceptionReport = Informe de Excepci\u00F3n errorReportValve.statusReport = Informe de estado errorReportValve.message = mensaje errorReportValve.description = descripci\u00F3n errorReportValve.exception = excepci\u00F3n errorReportValve.rootCause = causa ra\u00EDz errorReportValve.note = nota errorReportValve.rootCauseInLogs = La traza completa de la causa de este error se encuentra en los archivos de diario de {0}. remoteIpValve.syntax = Se han suministrado expresiones regulares [{0}] no v\u00E1lidas. remoteIpValve.invalidPortHeader = Valor inv\u00E1lido [{0}] hallado para el puerto en cabecera HTTP [{1}] sslValve.certError = No pude procesar cadena de certificado [{0}] para crear un objeto java.security.cert.X509Certificate sslValve.invalidProvider = El proveedor de SSL especificado en el conecto asociado con este requerimiento de [{0}] ies inv\u00E1lido. No se pueden procesar los datos del certificado. stuckThreadDetectionValve.notifyStuckThreadDetected = El hilo "{0}" (id={6}) ha estado activo durante {1} miilisegundos (desde {2}) para servir el mismo requerimiento para {4} y puede estar atascado (el umbral configurado para este StuckThreadDetectionValve es de {5} segundos). Hay {3} hilo(s) en total que son monitorizados por esta V\u00E1lvula y pueden estar atascados. stuckThreadDetectionValve.notifyStuckThreadCompleted = El hilo "{0}" (id={3}), que previamente se report\u00F3 como atascado, se ha completado. Estuvo activo por aproximadamente {1} milisegundos. {2, choice,0\#|0< Hay a\u00FAn {2} hilo(s) que son monitorizados por esta V\u00E1lvula y pueden estar atascados.} # HTTP status reports http.100 = El cliente puede continuar. http.101 = El servidor est\u00E1 conmutando protocolos con arreglo a la cabecera "Upgrade". http.201 = El requerimiento tuvo \u00E9xito y un nuevo recurso ha sido creado en el servidor. http.202 = Este requerimiento ha sido aceptado para ser procesado, pero no ha sido completado. http.203 = La informaci\u00F3n meta presentada por el cliente no se origin\u00F3 desde el servidor. http.204 = El requerimiento tuvo \u00E9xito pero no hay informaci\u00F3n que devolver. http.205 = El cliente no deber\u00EDa de limpiar la vista del documento que caus\u00F3 que este requerimiento fuera enviado. http.206 = El servidor ha rellenado paci\u00E1lmente un requerimiento GET para este recurso. http.207 = Se han devuelto valores m\u00FAltiples de estado. http.300 = El recurso requerido corresponde a una cualquiera de un conjunto de representaciones, cada una con su propia localizaci\u00F3n espec\u00EDfica. http.301 = El recurso requerido ha sido movido perman\u00E9ntemente a una nueva localizaci\u00F3n. http.302 = El recurso requerido ha sido movido tempor\u00E1lmente a una nueva localizaci\u00F3n. http.303 = La respuesta a este requerimiento se puede hallar bajo una URI diferente. http.304 = El recurso requerido est\u00E1 disponible y no ha sido modificado. http.305 = El recurso requerido debe de ser accedido a trav\u00E9s del apoderado (proxy) dado mediante la cabecera "Location". http.400 = El requerimiento enviado por el cliente era sint\u00E1cticamente incorrecto. http.401 = Este requerimiento requiere autenticaci\u00F3n HTTP. http.402 = Se requiere pago para acceder a este recurso. http.403 = El acceso al recurso especificado ha sido prohibido. http.404 = El recurso requerido no est\u00E1 disponible. http.405 = El m\u00E9todo HTTP especificado no est\u00E1 permitido para el recurso requerido. http.406 = El recurso identificado por este requerimiento s\u00F3lo es capaz de generar respuestas con caracter\u00EDsticas no aceptables con arreglo a las cabeceras "accept" de requerimiento. http.407 = El cliente debe de ser primero autenticado en el apoderado. http.408 = El cliente no produjo un requerimiento dentro del tiempo en que el servidor estaba preparado esperando. http.409 = El requerimiento no pudo ser completado debido a un conflicto con el estado actual del recurso. http.410 = El recurso requerido ya no est\u00E1 disponible y no se conoce direcci\u00F3n de reenv\u00EDo. http.411 = Este requerimiento no puede ser manejado sin un tama\u00F1o definido de contenido. http.412 = Una precondici\u00F3n especificada ha fallado para este requerimiento. http.413 = La entidad de requerimiento es mayor de lo que el servidor quiere o puede procesar. http.414 = El servidor rechaz\u00F3 este requerimiento porque la URI requerida era demasiado larga. http.415 = El servidor rechaz\u00F3 este requerimiento porque la entidad requerida se encuentra en un formato no soportado por el recurso requerido para el m\u00E9todo requerido. http.416 = El rango de byte requerido no puede ser satisfecho. http.417 = Lo que se espera dado por la cabecera "Expect" de requerimiento no pudo ser completado. http.422 = El servidor entendi\u00F3 el tipo de contenido y la sint\u00E1xis del requerimiento pero no pudo procesar las instrucciones contenidas. http.423 = La fuente o recurso de destino de un m\u00E9todo est\u00E1 bloqueada. http.500 = El servidor encontr\u00F3 un error interno que hizo que no pudiera rellenar este requerimiento. http.501 = El servidor no soporta la funcionalidad necesaria para rellenar este requerimiento. http.502 = Este servidor recibi\u00F3 una respuesta inv\u00E1lida desde un servidor que consult\u00F3 cuando actuaba como apoderado o pasarela. http.503 = El servicio requerido no est\u00E1 disponible en este momento. http.504 = El servidor recibi\u00F3 un Tiempo Agotado desde un servidor superior cuando actuaba como pasarela o apoderado. http.505 = El servidor no soporta la versi\u00F3n de protocolo HTTP requerida. http.507 = El recurso no tiene espacio suficiente para registrar el estado del recurso tras la ejecuci\u00F3n de este m\u00E9todo. tomcat7-7.0.52/java/org/apache/catalina/valves/ValveBase.java0000644000175100017510000002202012271471332023661 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import javax.servlet.ServletException; import org.apache.catalina.Contained; import org.apache.catalina.Container; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Pipeline; import org.apache.catalina.Valve; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.tomcat.util.res.StringManager; /** * Convenience base class for implementations of the Valve interface. * A subclass MUST implement an invoke() * method to provide the required functionality, and MAY * implement the Lifecycle interface to provide configuration * management and lifecycle support. * * @author Craig R. McClanahan */ public abstract class ValveBase extends LifecycleMBeanBase implements Contained, Valve { //------------------------------------------------------ Constructor public ValveBase() { this(false); } public ValveBase(boolean asyncSupported) { this.asyncSupported = asyncSupported; } //------------------------------------------------------ Instance Variables /** * Does this valve support Servlet 3+ async requests? */ protected boolean asyncSupported; /** * The Container whose pipeline this Valve is a component of. */ protected Container container = null; /** * Container log */ protected Log containerLog = null; /** * Descriptive information about this Valve implementation. This value * should be overridden by subclasses. */ protected static final String info = "org.apache.catalina.core.ValveBase/1.0"; /** * The next Valve in the pipeline this Valve is a component of. */ protected Valve next = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); //-------------------------------------------------------------- Properties /** * Return the Container with which this Valve is associated, if any. */ @Override public Container getContainer() { return (container); } @Override public boolean isAsyncSupported() { return asyncSupported; } public void setAsyncSupported(boolean asyncSupported) { this.asyncSupported = asyncSupported; } /** * Set the Container with which this Valve is associated, if any. * * @param container The new associated container */ @Override public void setContainer(Container container) { this.container = container; } /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Return the next Valve in this pipeline, or null if this * is the last Valve in the pipeline. */ @Override public Valve getNext() { return (next); } /** * Set the Valve that follows this one in the pipeline it is part of. * * @param valve The new next valve */ @Override public void setNext(Valve valve) { this.next = valve; } //---------------------------------------------------------- Public Methods /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ @Override public void backgroundProcess() { // NOOP by default } /** * The implementation-specific logic represented by this Valve. See the * Valve description for the normal design patterns for this method. *

    * This method MUST be provided by a subclass. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public abstract void invoke(Request request, Response response) throws IOException, ServletException; /** * Process a Comet event. This method will rarely need to be provided by * a subclass, unless it needs to reassociate a particular object with * the thread that is processing the request. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet * @exception ServletException if a servlet error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet */ @Override public void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Perform the request getNext().event(request, response, event); } @Override protected void initInternal() throws LifecycleException { super.initInternal(); containerLog = getContainer().getLogger(); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); } /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append('['); if (container == null) { sb.append("Container is null"); } else { sb.append(container.getName()); } sb.append(']'); return sb.toString(); } // -------------------- JMX and Registration -------------------- @Override public String getObjectNameKeyProperties() { StringBuilder name = new StringBuilder("type=Valve"); Container container = getContainer(); name.append(MBeanUtils.getContainerKeyProperties(container)); int seq = 0; // Pipeline may not be present in unit testing Pipeline p = container.getPipeline(); if (p != null) { for (Valve valve : p.getValves()) { // Skip null valves if (valve == null) { continue; } // Only compare valves in pipeline until we find this valve if (valve == this) { break; } if (valve.getClass() == this.getClass()) { // Duplicate valve earlier in pipeline // increment sequence number seq ++; } } } if (seq > 0) { name.append(",seq="); name.append(seq); } String className = this.getClass().getName(); int period = className.lastIndexOf('.'); if (period >= 0) { className = className.substring(period + 1); } name.append(",name="); name.append(className); return name.toString(); } @Override public String getDomainInternal() { return MBeanUtils.getDomain(getContainer()); } } tomcat7-7.0.52/java/org/apache/catalina/valves/AccessLogValve.java0000644000175100017510000020263012271471332024661 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.TimeZone; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpSession; import org.apache.catalina.AccessLog; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.coyote.RequestInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.B2CConverter; /** *

    Implementation of the Valve interface that generates a web server * access log with the detailed line contents matching a configurable pattern. * The syntax of the available patterns is similar to that supported by the * Apache HTTP Server * mod_log_config module. As an additional feature, * automatic rollover of log files when the date changes is also supported.

    * *

    Patterns for the logged message may include constant text or any of the * following replacement strings, for which the corresponding information * from the specified Response is substituted:

    *
      *
    • %a - Remote IP address *
    • %A - Local IP address *
    • %b - Bytes sent, excluding HTTP headers, or '-' if no bytes * were sent *
    • %B - Bytes sent, excluding HTTP headers *
    • %h - Remote host name (or IP address if * enableLookups for the connector is false) *
    • %H - Request protocol *
    • %l - Remote logical username from identd (always returns '-') *
    • %m - Request method *
    • %p - Local port *
    • %q - Query string (prepended with a '?' if it exists, otherwise * an empty string *
    • %r - First line of the request *
    • %s - HTTP status code of the response *
    • %S - User session ID *
    • %t - Date and time, in Common Log Format format *
    • %t{format} - Date and time, in any format supported by SimpleDateFormat *
    • %u - Remote user that was authenticated *
    • %U - Requested URL path *
    • %v - Local server name *
    • %D - Time taken to process the request, in millis *
    • %T - Time taken to process the request, in seconds *
    • %I - current Request thread name (can compare later with stacktraces) *
    *

    In addition, the caller can specify one of the following aliases for * commonly utilized patterns:

    *
      *
    • common - %h %l %u %t "%r" %s %b *
    • combined - * %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" *
    * *

    * There is also support to write information from the cookie, incoming * header, the Session or something else in the ServletRequest.
    * It is modeled after the * Apache HTTP Server log configuration * syntax:

    *
      *
    • %{xxx}i for incoming headers *
    • %{xxx}o for outgoing response headers *
    • %{xxx}c for a specific cookie *
    • %{xxx}r xxx is an attribute in the ServletRequest *
    • %{xxx}s xxx is an attribute in the HttpSession *
    • %{xxx}t xxx is an enhanced SimpleDateFormat pattern * (see Configuration Reference document for details on supported time patterns) *
    * *

    * Log rotation can be on or off. This is dictated by the * rotatable property. *

    * *

    * For UNIX users, another field called checkExists is also * available. If set to true, the log file's existence will be checked before * each logging. This way an external log rotator can move the file * somewhere and Tomcat will start with a new file. *

    * *

    * For JMX junkies, a public method called rotate has * been made available to allow you to tell this instance to move * the existing log file to somewhere else and start writing a new log file. *

    * *

    * Conditional logging is also supported. This can be done with the * conditionUnless and conditionIf properties. * If the value returned from ServletRequest.getAttribute(conditionUnless) * yields a non-null value, the logging will be skipped. * If the value returned from ServletRequest.getAttribute(conditionIf) * yields the null value, the logging will be skipped. * The condition attribute is synonym for * conditionUnless and is provided for backwards compatibility. *

    * *

    * For extended attributes coming from a getAttribute() call, * it is you responsibility to ensure there are no newline or * control characters. *

    * * @author Craig R. McClanahan * @author Jason Brittain * @author Remy Maucherat * @author Takayuki Kaneko * @author Peter Rossbach */ public class AccessLogValve extends ValveBase implements AccessLog { private static final Log log = LogFactory.getLog(AccessLogValve.class); //------------------------------------------------------ Constructor public AccessLogValve() { super(true); } // ----------------------------------------------------- Instance Variables /** * The as-of date for the currently open log file, or a zero-length * string if there is no open log file. */ private volatile String dateStamp = ""; /** * The directory in which log files are created. */ private String directory = "logs"; /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.valves.AccessLogValve/2.2"; /** * enabled this component */ protected boolean enabled = true; /** * The pattern used to format our access log lines. */ protected String pattern = null; /** * The prefix that is added to log file filenames. */ protected String prefix = "access_log."; /** * Should we rotate our log file? Default is true (like old behavior) */ protected boolean rotatable = true; /** * Should we defer inclusion of the date stamp in the file * name until rotate time? Default is false. */ protected boolean renameOnRotate = false; /** * Buffered logging. */ private boolean buffered = true; /** * The suffix that is added to log file filenames. */ protected String suffix = ""; /** * The PrintWriter to which we are currently logging, if any. */ protected PrintWriter writer = null; /** * A date formatter to format a Date using the format * given by fileDateFormat. */ protected SimpleDateFormat fileDateFormatter = null; /** * The size of our global date format cache */ private static final int globalCacheSize = 300; /** * The size of our thread local date format cache */ private static final int localCacheSize = 60; /** * The current log file we are writing to. Helpful when checkExists * is true. */ protected File currentLogFile = null; /** *

    Cache structure for formatted timestamps based on seconds.

    * *

    The cache consists of entries for a consecutive range of * seconds. The length of the range is configurable. It is * implemented based on a cyclic buffer. New entries shift the range.

    * *

    There is one cache for the CLF format (the access log standard * format) and a HashMap of caches for additional formats used by * SimpleDateFormat.

    * *

    Although the cache supports specifying a locale when retrieving a * formatted timestamp, each format will always use the locale given * when the format was first used. New locales can only be used for new formats. * The CLF format will always be formatted using the locale * en_US.

    * *

    The cache is not threadsafe. It can be used without synchronization * via thread local instances, or with synchronization as a global cache.

    * *

    The cache can be created with a parent cache to build a cache hierarchy. * Access to the parent cache is threadsafe.

    * *

    This class uses a small thread local first level cache and a bigger * synchronized global second level cache.

    */ protected static class DateFormatCache { protected class Cache { /* CLF log format */ private static final String cLFFormat = "dd/MMM/yyyy:HH:mm:ss Z"; /* Second used to retrieve CLF format in most recent invocation */ private long previousSeconds = Long.MIN_VALUE; /* Value of CLF format retrieved in most recent invocation */ private String previousFormat = ""; /* First second contained in cache */ private long first = Long.MIN_VALUE; /* Last second contained in cache */ private long last = Long.MIN_VALUE; /* Index of "first" in the cyclic cache */ private int offset = 0; /* Helper object to be able to call SimpleDateFormat.format(). */ private final Date currentDate = new Date(); protected final String cache[]; private SimpleDateFormat formatter; private boolean isCLF = false; private Cache parent = null; private Cache(Cache parent) { this(null, parent); } private Cache(String format, Cache parent) { this(format, null, parent); } private Cache(String format, Locale loc, Cache parent) { cache = new String[cacheSize]; for (int i = 0; i < cacheSize; i++) { cache[i] = null; } if (loc == null) { loc = cacheDefaultLocale; } if (format == null) { isCLF = true; format = cLFFormat; formatter = new SimpleDateFormat(format, Locale.US); } else { formatter = new SimpleDateFormat(format, loc); } formatter.setTimeZone(TimeZone.getDefault()); this.parent = parent; } private String getFormatInternal(long time) { long seconds = time / 1000; /* First step: if we have seen this timestamp during the previous call, and we need CLF, return the previous value. */ if (seconds == previousSeconds) { return previousFormat; } /* Second step: Try to locate in cache */ previousSeconds = seconds; int index = (offset + (int)(seconds - first)) % cacheSize; if (index < 0) { index += cacheSize; } if (seconds >= first && seconds <= last) { if (cache[index] != null) { /* Found, so remember for next call and return.*/ previousFormat = cache[index]; return previousFormat; } /* Third step: not found in cache, adjust cache and add item */ } else if (seconds >= last + cacheSize || seconds <= first - cacheSize) { first = seconds; last = first + cacheSize - 1; index = 0; offset = 0; for (int i = 1; i < cacheSize; i++) { cache[i] = null; } } else if (seconds > last) { for (int i = 1; i < seconds - last; i++) { cache[(index + cacheSize - i) % cacheSize] = null; } first = seconds - (cacheSize - 1); last = seconds; offset = (index + 1) % cacheSize; } else if (seconds < first) { for (int i = 1; i < first - seconds; i++) { cache[(index + i) % cacheSize] = null; } first = seconds; last = seconds + (cacheSize - 1); offset = index; } /* Last step: format new timestamp either using * parent cache or locally. */ if (parent != null) { synchronized(parent) { previousFormat = parent.getFormatInternal(time); } } else { currentDate.setTime(time); previousFormat = formatter.format(currentDate); if (isCLF) { StringBuilder current = new StringBuilder(32); current.append('['); current.append(previousFormat); current.append(']'); previousFormat = current.toString(); } } cache[index] = previousFormat; return previousFormat; } } /* Number of cached entries */ private int cacheSize = 0; private final Locale cacheDefaultLocale; private final DateFormatCache parent; protected final Cache cLFCache; private final HashMap formatCache = new HashMap(); protected DateFormatCache(int size, Locale loc, DateFormatCache parent) { cacheSize = size; cacheDefaultLocale = loc; this.parent = parent; Cache parentCache = null; if (parent != null) { synchronized(parent) { parentCache = parent.getCache(null, null); } } cLFCache = new Cache(parentCache); } private Cache getCache(String format, Locale loc) { Cache cache; if (format == null) { cache = cLFCache; } else { cache = formatCache.get(format); if (cache == null) { Cache parentCache = null; if (parent != null) { synchronized(parent) { parentCache = parent.getCache(format, loc); } } cache = new Cache(format, loc, parentCache); formatCache.put(format, cache); } } return cache; } public String getFormat(long time) { return cLFCache.getFormatInternal(time); } public String getFormat(String format, Locale loc, long time) { return getCache(format, loc).getFormatInternal(time); } } /** * Global date format cache. */ private static final DateFormatCache globalDateCache = new DateFormatCache(globalCacheSize, Locale.getDefault(), null); /** * Thread local date format cache. */ private static final ThreadLocal localDateCache = new ThreadLocal() { @Override protected DateFormatCache initialValue() { return new DateFormatCache(localCacheSize, Locale.getDefault(), globalDateCache); } }; /** * The system time when we last updated the Date that this valve * uses for log lines. */ private static final ThreadLocal localDate = new ThreadLocal() { @Override protected Date initialValue() { return new Date(); } }; /** * The list of our format types. */ private static enum FormatType { CLF, SEC, MSEC, MSEC_FRAC, SDF } /** * Resolve hosts. */ private boolean resolveHosts = false; /** * Instant when the log daily rotation was last checked. */ private volatile long rotationLastChecked = 0L; /** * Do we check for log file existence? Helpful if an external * agent renames the log file so we can automagically recreate it. */ private boolean checkExists = false; /** * Are we doing conditional logging. default null. * It is the value of conditionUnless property. */ protected String condition = null; /** * Are we doing conditional logging. default null. * It is the value of conditionIf property. */ protected String conditionIf = null; /** * Date format to place in log file name. */ protected String fileDateFormat = "yyyy-MM-dd"; /** * Name of locale used to format timestamps in log entries and in * log file name suffix. */ protected String localeName = Locale.getDefault().toString(); /** * Locale used to format timestamps in log entries and in * log file name suffix. */ protected Locale locale = Locale.getDefault(); /** * Character set used by the log file. If it is null, the * system default character set will be used. An empty string will be * treated as null when this property is assigned. */ protected String encoding = null; /** * Array of AccessLogElement, they will be used to make log message. */ protected AccessLogElement[] logElements = null; /** * @see #setRequestAttributesEnabled(boolean) */ protected boolean requestAttributesEnabled = false; // ------------------------------------------------------------- Properties /** * @return Returns the enabled. */ public boolean getEnabled() { return enabled; } /** * {@inheritDoc} */ @Override public void setRequestAttributesEnabled(boolean requestAttributesEnabled) { this.requestAttributesEnabled = requestAttributesEnabled; } /** * {@inheritDoc} */ @Override public boolean getRequestAttributesEnabled() { return requestAttributesEnabled; } /** * @param enabled * The enabled to set. */ public void setEnabled(boolean enabled) { this.enabled = enabled; } /** * Return the directory in which we create log files. */ public String getDirectory() { return (directory); } /** * Set the directory in which we create log files. * * @param directory The new log file directory */ public void setDirectory(String directory) { this.directory = directory; } /** * Return descriptive information about this implementation. */ @Override public String getInfo() { return (info); } /** * Return the format pattern. */ public String getPattern() { return (this.pattern); } /** * Set the format pattern, first translating any recognized alias. * * @param pattern The new pattern */ public void setPattern(String pattern) { if (pattern == null) { this.pattern = ""; } else if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) { this.pattern = Constants.AccessLog.COMMON_PATTERN; } else if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) { this.pattern = Constants.AccessLog.COMBINED_PATTERN; } else { this.pattern = pattern; } logElements = createLogElements(); } /** * Check for file existence before logging. */ public boolean isCheckExists() { return checkExists; } /** * Set whether to check for log file existence before logging. * * @param checkExists true meaning to check for file existence. */ public void setCheckExists(boolean checkExists) { this.checkExists = checkExists; } /** * Return the log file prefix. */ public String getPrefix() { return (prefix); } /** * Set the log file prefix. * * @param prefix The new log file prefix */ public void setPrefix(String prefix) { this.prefix = prefix; } /** * Should we rotate the logs */ public boolean isRotatable() { return rotatable; } /** * Set the value is we should we rotate the logs * * @param rotatable true is we should rotate. */ public void setRotatable(boolean rotatable) { this.rotatable = rotatable; } /** * Should we defer inclusion of the date stamp in the file * name until rotate time */ public boolean isRenameOnRotate() { return renameOnRotate; } /** * Set the value if we should defer inclusion of the date * stamp in the file name until rotate time * * @param renameOnRotate true if defer inclusion of date stamp */ public void setRenameOnRotate(boolean renameOnRotate) { this.renameOnRotate = renameOnRotate; } /** * Is the logging buffered */ public boolean isBuffered() { return buffered; } /** * Set the value if the logging should be buffered * * @param buffered true if buffered. */ public void setBuffered(boolean buffered) { this.buffered = buffered; } /** * Return the log file suffix. */ public String getSuffix() { return (suffix); } /** * Set the log file suffix. * * @param suffix The new log file suffix */ public void setSuffix(String suffix) { this.suffix = suffix; } /** * Set the resolve hosts flag. * * @param resolveHosts The new resolve hosts value * @deprecated Unused, removed in Tomcat 8. * See org.apache.catalina.connector.Connector.setEnableLookups(boolean). */ @Deprecated public void setResolveHosts(boolean resolveHosts) { this.resolveHosts = resolveHosts; } /** * Get the value of the resolve hosts flag. * @deprecated Unused, removed in Tomcat 8. * See org.apache.catalina.connector.Connector.setEnableLookups(boolean). */ @Deprecated public boolean isResolveHosts() { return resolveHosts; } /** * Return whether the attribute name to look for when * performing conditional logging. If null, every * request is logged. */ public String getCondition() { return condition; } /** * Set the ServletRequest.attribute to look for to perform * conditional logging. Set to null to log everything. * * @param condition Set to null to log everything */ public void setCondition(String condition) { this.condition = condition; } /** * Return whether the attribute name to look for when * performing conditional logging. If null, every * request is logged. */ public String getConditionUnless() { return getCondition(); } /** * Set the ServletRequest.attribute to look for to perform * conditional logging. Set to null to log everything. * * @param condition Set to null to log everything */ public void setConditionUnless(String condition) { setCondition(condition); } /** * Return whether the attribute name to look for when * performing conditional logging. If null, every * request is logged. */ public String getConditionIf() { return conditionIf; } /** * Set the ServletRequest.attribute to look for to perform * conditional logging. Set to null to log everything. * * @param condition Set to null to log everything */ public void setConditionIf(String condition) { this.conditionIf = condition; } /** * Return the date format date based log rotation. */ public String getFileDateFormat() { return fileDateFormat; } /** * Set the date format date based log rotation. */ public void setFileDateFormat(String fileDateFormat) { String newFormat; if (fileDateFormat == null) { newFormat = ""; } else { newFormat = fileDateFormat; } this.fileDateFormat = newFormat; synchronized (this) { fileDateFormatter = new SimpleDateFormat(newFormat, Locale.US); fileDateFormatter.setTimeZone(TimeZone.getDefault()); } } /** * Return the locale used to format timestamps in log entries and in * log file name suffix. */ public String getLocale() { return localeName; } /** * Set the locale used to format timestamps in log entries and in * log file name suffix. Changing the locale is only supported * as long as the AccessLogValve has not logged anything. Changing * the locale later can lead to inconsistent formatting. * * @param localeName The locale to use. */ public void setLocale(String localeName) { this.localeName = localeName; locale = findLocale(localeName, locale); } /** * Return the character set name that is used to write the log file. * * @return Character set name, or null if the system default * character set is used. */ public String getEncoding() { return encoding; } /** * Set the character set that is used to write the log file. * * @param encoding The name of the character set. */ public void setEncoding(String encoding) { if (encoding != null && encoding.length() > 0) { this.encoding = encoding; } else { this.encoding = null; } } // --------------------------------------------------------- Public Methods /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ @Override public synchronized void backgroundProcess() { if (getState().isAvailable() && getEnabled() && writer != null && buffered) { writer.flush(); } } /** * Log a message summarizing the specified request and response, according * to the format specified by the pattern property. * * @param request Request being processed * @param response Response being processed * * @exception IOException if an input/output error has occurred * @exception ServletException if a servlet error has occurred */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { getNext().invoke(request, response); } @Override public void log(Request request, Response response, long time) { if (!getState().isAvailable() || !getEnabled() || logElements == null || condition != null && null != request.getRequest().getAttribute(condition) || conditionIf != null && null == request.getRequest().getAttribute(conditionIf)) { return; } /** * XXX This is a bit silly, but we want to have start and stop time and * duration consistent. It would be better to keep start and stop * simply in the request and/or response object and remove time * (duration) from the interface. */ long start = request.getCoyoteRequest().getStartTime(); Date date = getDate(start + time); StringBuilder result = new StringBuilder(128); for (int i = 0; i < logElements.length; i++) { logElements[i].addElement(result, date, request, response, time); } log(result.toString()); } /** * Rotate the log file if necessary. */ public void rotate() { if (rotatable) { // Only do a logfile switch check once a second, max. long systime = System.currentTimeMillis(); if ((systime - rotationLastChecked) > 1000) { synchronized(this) { if ((systime - rotationLastChecked) > 1000) { rotationLastChecked = systime; String tsDate; // Check for a change of date tsDate = fileDateFormatter.format(new Date(systime)); // If the date has changed, switch log files if (!dateStamp.equals(tsDate)) { close(true); dateStamp = tsDate; open(); } } } } } } /** * Rename the existing log file to something else. Then open the * old log file name up once again. Intended to be called by a JMX * agent. * * * @param newFileName The file name to move the log file entry to * @return true if a file was rotated with no error */ public synchronized boolean rotate(String newFileName) { if (currentLogFile != null) { File holder = currentLogFile; close(false); try { holder.renameTo(new File(newFileName)); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); log.error(sm.getString("accessLogValve.rotateFail"), e); } /* Make sure date is correct */ dateStamp = fileDateFormatter.format( new Date(System.currentTimeMillis())); open(); return true; } else { return false; } } // -------------------------------------------------------- Private Methods /** * Create a File object based on the current log file name. * Directories are created as needed but the underlying file * is not created or opened. * * @param useDateStamp include the timestamp in the file name. * @return the log file object */ private File getLogFile(boolean useDateStamp) { // Create the directory if necessary File dir = new File(directory); if (!dir.isAbsolute()) { dir = new File(System.getProperty(Globals.CATALINA_BASE_PROP), directory); } if (!dir.mkdirs() && !dir.isDirectory()) { log.error(sm.getString("accessLogValve.openDirFail", dir)); } // Calculate the current log file name File pathname; if (useDateStamp) { pathname = new File(dir.getAbsoluteFile(), prefix + dateStamp + suffix); } else { pathname = new File(dir.getAbsoluteFile(), prefix + suffix); } File parent = pathname.getParentFile(); if (!parent.mkdirs() && !parent.isDirectory()) { log.error(sm.getString("accessLogValve.openDirFail", parent)); } return pathname; } /** * Move a current but rotated log file back to the unrotated * one. Needed if date stamp inclusion is deferred to rotation * time. */ private void restore() { File newLogFile = getLogFile(false); File rotatedLogFile = getLogFile(true); if (rotatedLogFile.exists() && !newLogFile.exists() && !rotatedLogFile.equals(newLogFile)) { try { if (!rotatedLogFile.renameTo(newLogFile)) { log.error(sm.getString("accessLogValve.renameFail", rotatedLogFile, newLogFile)); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); log.error(sm.getString("accessLogValve.renameFail", rotatedLogFile, newLogFile), e); } } } /** * Close the currently open log file (if any) * * @param rename Rename file to final name after closing */ private synchronized void close(boolean rename) { if (writer == null) { return; } writer.flush(); writer.close(); if (rename && renameOnRotate) { File newLogFile = getLogFile(true); if (!newLogFile.exists()) { try { if (!currentLogFile.renameTo(newLogFile)) { log.error(sm.getString("accessLogValve.renameFail", currentLogFile, newLogFile)); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); log.error(sm.getString("accessLogValve.renameFail", currentLogFile, newLogFile), e); } } else { log.error(sm.getString("accessLogValve.alreadyExists", currentLogFile, newLogFile)); } } writer = null; dateStamp = ""; currentLogFile = null; } /** * Log the specified message to the log file, switching files if the date * has changed since the previous log call. * * @param message Message to be logged */ public void log(String message) { rotate(); /* In case something external rotated the file instead */ if (checkExists) { synchronized (this) { if (currentLogFile != null && !currentLogFile.exists()) { try { close(false); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); log.info(sm.getString("accessLogValve.closeFail"), e); } /* Make sure date is correct */ dateStamp = fileDateFormatter.format( new Date(System.currentTimeMillis())); open(); } } } // Log this message synchronized(this) { if (writer != null) { writer.println(message); if (!buffered) { writer.flush(); } } } } /** * Open the new log file for the date specified by dateStamp. */ protected synchronized void open() { // Open the current log file // If no rotate - no need for dateStamp in fileName File pathname = getLogFile(rotatable && !renameOnRotate); Charset charset = null; if (encoding != null) { try { charset = B2CConverter.getCharset(encoding); } catch (UnsupportedEncodingException ex) { log.error(sm.getString( "accessLogValve.unsupportedEncoding", encoding), ex); } } if (charset == null) { charset = Charset.defaultCharset(); } try { writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter( new FileOutputStream(pathname, true), charset), 128000), false); currentLogFile = pathname; } catch (IOException e) { writer = null; currentLogFile = null; log.error(sm.getString("accessLogValve.openFail", pathname), e); } } /** * This method returns a ThreadLocal Date object that is set to the * specified time. This saves creating a new Date object for every request. * * @return Date */ private static Date getDate(long systime) { Date date = localDate.get(); date.setTime(systime); return date; } /** * Find a locale by name */ protected static Locale findLocale(String name, Locale fallback) { if (name == null || name.isEmpty()) { return Locale.getDefault(); } else { for (Locale l: Locale.getAvailableLocales()) { if (name.equals(l.toString())) { return(l); } } } log.error(sm.getString("accessLogValve.invalidLocale", name)); return fallback; } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Initialize the Date formatters String format = getFileDateFormat(); fileDateFormatter = new SimpleDateFormat(format, Locale.US); fileDateFormatter.setTimeZone(TimeZone.getDefault()); dateStamp = fileDateFormatter.format(new Date(System.currentTimeMillis())); if (rotatable && renameOnRotate) { restore(); } open(); setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); close(false); } /** * AccessLogElement writes the partial message into the buffer. */ protected interface AccessLogElement { public void addElement(StringBuilder buf, Date date, Request request, Response response, long time); } /** * write thread name - %I */ protected static class ThreadNameElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { RequestInfo info = request.getCoyoteRequest().getRequestProcessor(); if(info != null) { buf.append(info.getWorkerThreadName()); } else { buf.append("-"); } } } /** * write local IP address - %A */ protected static class LocalAddrElement implements AccessLogElement { private static final String LOCAL_ADDR_VALUE; static { String init; try { init = InetAddress.getLocalHost().getHostAddress(); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); init = "127.0.0.1"; } LOCAL_ADDR_VALUE = init; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(LOCAL_ADDR_VALUE); } } /** * write remote IP address - %a */ protected class RemoteAddrElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (requestAttributesEnabled) { Object addr = request.getAttribute(REMOTE_ADDR_ATTRIBUTE); if (addr == null) { buf.append(request.getRemoteAddr()); } else { buf.append(addr); } } else { buf.append(request.getRemoteAddr()); } } } /** * write remote host name - %h */ protected class HostElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { String value = null; if (requestAttributesEnabled) { Object host = request.getAttribute(REMOTE_HOST_ATTRIBUTE); if (host != null) { value = host.toString(); } } if (value == null || value.length() == 0) { value = request.getRemoteHost(); } if (value == null || value.length() == 0) { value = "-"; } buf.append(value); } } /** * write remote logical username from identd (always returns '-') - %l */ protected static class LogicalUserNameElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append('-'); } } /** * write request protocol - %H */ protected class ProtocolElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (requestAttributesEnabled) { Object proto = request.getAttribute(PROTOCOL_ATTRIBUTE); if (proto == null) { buf.append(request.getProtocol()); } else { buf.append(proto); } } else { buf.append(request.getProtocol()); } } } /** * write remote user that was authenticated (if any), else '-' - %u */ protected static class UserElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (request != null) { String value = request.getRemoteUser(); if (value != null) { buf.append(value); } else { buf.append('-'); } } else { buf.append('-'); } } } /** * write date and time, in configurable format (default CLF) - %t or %t{format} */ protected class DateAndTimeElement implements AccessLogElement { /** * Format prefix specifying request start time */ private static final String requestStartPrefix = "begin"; /** * Format prefix specifying response end time */ private static final String responseEndPrefix = "end"; /** * Separator between optional prefix and rest of format */ private static final String prefixSeparator = ":"; /** * Special format for seconds since epoch */ private static final String secFormat = "sec"; /** * Special format for milliseconds since epoch */ private static final String msecFormat = "msec"; /** * Special format for millisecond part of timestamp */ private static final String msecFractionFormat = "msec_frac"; /** * The patterns we use to replace "S" and "SSS" millisecond * formatting of SimpleDateFormat by our own handling */ private static final String msecPattern = "{#}"; private static final String trippleMsecPattern = msecPattern + msecPattern + msecPattern; /* Our format description string, null if CLF */ private String format = null; /* Whether to use begin of request or end of response as the timestamp */ private boolean usesBegin = false; /* The format type */ private FormatType type = FormatType.CLF; /* Whether we need to postprocess by adding milliseconds */ private boolean usesMsecs = false; protected DateAndTimeElement() { this(null); } /** * Replace the millisecond formatting character 'S' by * some dummy characters in order to make the resulting * formatted time stamps cacheable. We replace the dummy * chars later with the actual milliseconds because that's * relatively cheap. */ private String tidyFormat(String format) { boolean escape = false; StringBuilder result = new StringBuilder(); int len = format.length(); char x; for (int i = 0; i < len; i++) { x = format.charAt(i); if (escape || x != 'S') { result.append(x); } else { result.append(msecPattern); usesMsecs = true; } if (x == '\'') { escape = !escape; } } return result.toString(); } protected DateAndTimeElement(String header) { format = header; if (format != null) { if (format.equals(requestStartPrefix)) { usesBegin = true; format = ""; } else if (format.startsWith(requestStartPrefix + prefixSeparator)) { usesBegin = true; format = format.substring(6); } else if (format.equals(responseEndPrefix)) { usesBegin = false; format = ""; } else if (format.startsWith(responseEndPrefix + prefixSeparator)) { usesBegin = false; format = format.substring(4); } if (format.length() == 0) { type = FormatType.CLF; } else if (format.equals(secFormat)) { type = FormatType.SEC; } else if (format.equals(msecFormat)) { type = FormatType.MSEC; } else if (format.equals(msecFractionFormat)) { type = FormatType.MSEC_FRAC; } else { type = FormatType.SDF; format = tidyFormat(format); } } } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { long timestamp = date.getTime(); long frac; if (usesBegin) { timestamp -= time; } switch (type) { case CLF: buf.append(localDateCache.get().getFormat(timestamp)); break; case SEC: buf.append(timestamp / 1000); break; case MSEC: buf.append(timestamp); break; case MSEC_FRAC: frac = timestamp % 1000; if (frac < 100) { if (frac < 10) { buf.append('0'); buf.append('0'); } else { buf.append('0'); } } buf.append(frac); break; case SDF: String temp = localDateCache.get().getFormat(format, locale, timestamp); if (usesMsecs) { frac = timestamp % 1000; StringBuilder trippleMsec = new StringBuilder(4); if (frac < 100) { if (frac < 10) { trippleMsec.append('0'); trippleMsec.append('0'); } else { trippleMsec.append('0'); } } trippleMsec.append(frac); temp = temp.replace(trippleMsecPattern, trippleMsec); temp = temp.replace(msecPattern, Long.toString(frac)); } buf.append(temp); break; } } } /** * write first line of the request (method and request URI) - %r */ protected static class RequestElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (request != null) { String method = request.getMethod(); if (method == null) { // No method means no request line buf.append('-'); } else { buf.append(request.getMethod()); buf.append(' '); buf.append(request.getRequestURI()); if (request.getQueryString() != null) { buf.append('?'); buf.append(request.getQueryString()); } buf.append(' '); buf.append(request.getProtocol()); } } else { buf.append('-'); } } } /** * write HTTP status code of the response - %s */ protected static class HttpStatusCodeElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (response != null) { buf.append(response.getStatus()); } else { buf.append('-'); } } } /** * write local port on which this request was received - %p */ protected class LocalPortElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (requestAttributesEnabled) { Object port = request.getAttribute(SERVER_PORT_ATTRIBUTE); if (port == null) { buf.append(request.getServerPort()); } else { buf.append(port); } } else { buf.append(request.getServerPort()); } } } /** * write bytes sent, excluding HTTP headers - %b, %B */ protected static class ByteSentElement implements AccessLogElement { private final boolean conversion; /** * if conversion is true, write '-' instead of 0 - %b */ public ByteSentElement(boolean conversion) { this.conversion = conversion; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { // Don't need to flush since trigger for log message is after the // response has been committed long length = response.getBytesWritten(false); if (length <= 0) { // Protect against nulls and unexpected types as these values // may be set by untrusted applications Object start = request.getAttribute( Globals.SENDFILE_FILE_START_ATTR); if (start instanceof Long) { Object end = request.getAttribute( Globals.SENDFILE_FILE_END_ATTR); if (end instanceof Long) { length = ((Long) end).longValue() - ((Long) start).longValue(); } } } if (length <= 0 && conversion) { buf.append('-'); } else { buf.append(length); } } } /** * write request method (GET, POST, etc.) - %m */ protected static class MethodElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (request != null) { buf.append(request.getMethod()); } } } /** * write time taken to process the request - %D, %T */ protected static class ElapsedTimeElement implements AccessLogElement { private final boolean millis; /** * if millis is true, write time in millis - %D * if millis is false, write time in seconds - %T */ public ElapsedTimeElement(boolean millis) { this.millis = millis; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (millis) { buf.append(time); } else { // second buf.append(time / 1000); buf.append('.'); int remains = (int) (time % 1000); buf.append(remains / 100); remains = remains % 100; buf.append(remains / 10); buf.append(remains % 10); } } } /** * write time until first byte is written (commit time) in millis - %F */ protected static class FirstByteTimeElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { long commitTime = response.getCoyoteResponse().getCommitTime(); if (commitTime == -1) { buf.append('-'); } else { long delta = commitTime - request.getCoyoteRequest().getStartTime(); buf.append(Long.toString(delta)); } } } /** * write Query string (prepended with a '?' if it exists) - %q */ protected static class QueryElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { String query = null; if (request != null) { query = request.getQueryString(); } if (query != null) { buf.append('?'); buf.append(query); } } } /** * write user session ID - %S */ protected static class SessionIdElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (request == null) { buf.append('-'); } else { Session session = request.getSessionInternal(false); if (session == null) { buf.append('-'); } else { buf.append(session.getIdInternal()); } } } } /** * write requested URL path - %U */ protected static class RequestURIElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (request != null) { buf.append(request.getRequestURI()); } else { buf.append('-'); } } } /** * write local server name - %v */ protected static class LocalServerNameElement implements AccessLogElement { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(request.getServerName()); } } /** * write any string */ protected static class StringElement implements AccessLogElement { private final String str; public StringElement(String str) { this.str = str; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(str); } } /** * write incoming headers - %{xxx}i */ protected static class HeaderElement implements AccessLogElement { private final String header; public HeaderElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { Enumeration iter = request.getHeaders(header); if (iter.hasMoreElements()) { buf.append(iter.nextElement()); while (iter.hasMoreElements()) { buf.append(',').append(iter.nextElement()); } return; } buf.append('-'); } } /** * write a specific cookie - %{xxx}c */ protected static class CookieElement implements AccessLogElement { private final String header; public CookieElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { String value = "-"; Cookie[] c = request.getCookies(); if (c != null) { for (int i = 0; i < c.length; i++) { if (header.equals(c[i].getName())) { value = c[i].getValue(); break; } } } buf.append(value); } } /** * write a specific response header - %{xxx}o */ protected static class ResponseHeaderElement implements AccessLogElement { private final String header; public ResponseHeaderElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (null != response) { Iterator iter = response.getHeaders(header).iterator(); if (iter.hasNext()) { buf.append(iter.next()); while (iter.hasNext()) { buf.append(',').append(iter.next()); } return; } } buf.append('-'); } } /** * write an attribute in the ServletRequest - %{xxx}r */ protected static class RequestAttributeElement implements AccessLogElement { private final String header; public RequestAttributeElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { Object value = null; if (request != null) { value = request.getAttribute(header); } else { value = "??"; } if (value != null) { if (value instanceof String) { buf.append((String) value); } else { buf.append(value.toString()); } } else { buf.append('-'); } } } /** * write an attribute in the HttpSession - %{xxx}s */ protected static class SessionAttributeElement implements AccessLogElement { private final String header; public SessionAttributeElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { Object value = null; if (null != request) { HttpSession sess = request.getSession(false); if (null != sess) { value = sess.getAttribute(header); } } else { value = "??"; } if (value != null) { if (value instanceof String) { buf.append((String) value); } else { buf.append(value.toString()); } } else { buf.append('-'); } } } /** * parse pattern string and create the array of AccessLogElement */ protected AccessLogElement[] createLogElements() { List list = new ArrayList(); boolean replace = false; StringBuilder buf = new StringBuilder(); for (int i = 0; i < pattern.length(); i++) { char ch = pattern.charAt(i); if (replace) { /* * For code that processes {, the behavior will be ... if I do * not encounter a closing } - then I ignore the { */ if ('{' == ch) { StringBuilder name = new StringBuilder(); int j = i + 1; for (; j < pattern.length() && '}' != pattern.charAt(j); j++) { name.append(pattern.charAt(j)); } if (j + 1 < pattern.length()) { /* the +1 was to account for } which we increment now */ j++; list.add(createAccessLogElement(name.toString(), pattern.charAt(j))); i = j; /* Since we walked more than one character */ } else { // D'oh - end of string - pretend we never did this // and do processing the "old way" list.add(createAccessLogElement(ch)); } } else { list.add(createAccessLogElement(ch)); } replace = false; } else if (ch == '%') { replace = true; list.add(new StringElement(buf.toString())); buf = new StringBuilder(); } else { buf.append(ch); } } if (buf.length() > 0) { list.add(new StringElement(buf.toString())); } return list.toArray(new AccessLogElement[0]); } /** * create an AccessLogElement implementation which needs header string */ protected AccessLogElement createAccessLogElement(String header, char pattern) { switch (pattern) { case 'i': return new HeaderElement(header); case 'c': return new CookieElement(header); case 'o': return new ResponseHeaderElement(header); case 'r': return new RequestAttributeElement(header); case 's': return new SessionAttributeElement(header); case 't': return new DateAndTimeElement(header); default: return new StringElement("???"); } } /** * create an AccessLogElement implementation */ protected AccessLogElement createAccessLogElement(char pattern) { switch (pattern) { case 'a': return new RemoteAddrElement(); case 'A': return new LocalAddrElement(); case 'b': return new ByteSentElement(true); case 'B': return new ByteSentElement(false); case 'D': return new ElapsedTimeElement(true); case 'F': return new FirstByteTimeElement(); case 'h': return new HostElement(); case 'H': return new ProtocolElement(); case 'l': return new LogicalUserNameElement(); case 'm': return new MethodElement(); case 'p': return new LocalPortElement(); case 'q': return new QueryElement(); case 'r': return new RequestElement(); case 's': return new HttpStatusCodeElement(); case 'S': return new SessionIdElement(); case 't': return new DateAndTimeElement(); case 'T': return new ElapsedTimeElement(false); case 'u': return new UserElement(); case 'U': return new RequestURIElement(); case 'v': return new LocalServerNameElement(); case 'I': return new ThreadNameElement(); default: return new StringElement("???" + pattern + "???"); } } } tomcat7-7.0.52/java/org/apache/catalina/valves/JDBCAccessLogValve.java0000644000175100017510000005034212271471332025305 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.sql.Connection; import java.sql.Driver; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Timestamp; import java.util.Properties; import javax.servlet.ServletException; import org.apache.catalina.AccessLog; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.tomcat.util.ExceptionUtils; /** *

    * This Tomcat extension logs server access directly to a database, and can * be used instead of the regular file-based access log implemented in * AccessLogValve. * To use, copy into the server/classes directory of the Tomcat installation * and configure in server.xml as: *

     *      <Valve className="org.apache.catalina.valves.JDBCAccessLogValve"
     *          driverName="your_jdbc_driver"
     *          connectionURL="your_jdbc_url"
     *          pattern="combined" resolveHosts="false"
     *      />
     * 
    *

    *

    * Many parameters can be configured, such as the database connection (with * driverName and connectionURL), * the table name (tableName) * and the field names (corresponding to the get/set method names). * The same options as AccessLogValve are supported, such as * resolveHosts and pattern ("common" or "combined" * only). *

    *

    * When Tomcat is started, a database connection (with autoReconnect option) * is created and used for all the log activity. When Tomcat is shutdown, the * database connection is closed. * This logger can be used at the level of the Engine context (being shared * by all the defined hosts) or the Host context (one instance of the logger * per host, possibly using different databases). *

    *

    * The database table can be created with the following command: *

    *
     * CREATE TABLE access (
     * id INT UNSIGNED AUTO_INCREMENT NOT NULL,
     * remoteHost CHAR(15) NOT NULL,
     * userName CHAR(15),
     * timestamp TIMESTAMP NOT NULL,
     * virtualHost VARCHAR(64) NOT NULL,
     * method VARCHAR(8) NOT NULL,
     * query VARCHAR(255) NOT NULL,
     * status SMALLINT UNSIGNED NOT NULL,
     * bytes INT UNSIGNED NOT NULL,
     * referer VARCHAR(128),
     * userAgent VARCHAR(128),
     * PRIMARY KEY (id),
     * INDEX (timestamp),
     * INDEX (remoteHost),
     * INDEX (virtualHost),
     * INDEX (query),
     * INDEX (userAgent)
     * );
     * 
    *

    Set JDBCAccessLogValve attribute useLongContentLength="true" as you have more then 4GB outputs. * Please, use long SQL datatype at access.bytes attribute. * The datatype of bytes at oracle is number and other databases use bytes BIGINT NOT NULL. *

    * *

    * If the table is created as above, its name and the field names don't need * to be defined. *

    *

    * If the request method is "common", only these fields are used: * remoteHost, user, timeStamp, query, status, bytes *

    *

    * TO DO: provide option for excluding logging of certain MIME types. *

    * * @author Andre de Jesus * @author Peter Rossbach */ public final class JDBCAccessLogValve extends ValveBase implements AccessLog { // ----------------------------------------------------------- Constructors /** * Class constructor. Initializes the fields with the default values. * The defaults are: *
         *      driverName = null;
         *      connectionURL = null;
         *      tableName = "access";
         *      remoteHostField = "remoteHost";
         *      userField = "userName";
         *      timestampField = "timestamp";
         *      virtualHostField = "virtualHost";
         *      methodField = "method";
         *      queryField = "query";
         *      statusField = "status";
         *      bytesField = "bytes";
         *      refererField = "referer";
         *      userAgentField = "userAgent";
         *      pattern = "common";
         *      resolveHosts = false;
         * 
    */ public JDBCAccessLogValve() { super(true); driverName = null; connectionURL = null; tableName = "access"; remoteHostField = "remoteHost"; userField = "userName"; timestampField = "timestamp"; virtualHostField = "virtualHost"; methodField = "method"; queryField = "query"; statusField = "status"; bytesField = "bytes"; refererField = "referer"; userAgentField = "userAgent"; pattern = "common"; resolveHosts = false; conn = null; ps = null; currentTimeMillis = new java.util.Date().getTime(); } // ----------------------------------------------------- Instance Variables /** * Use long contentLength as you have more 4 GB output. * @since 6.0.15 */ protected boolean useLongContentLength = false ; /** * The connection username to use when trying to connect to the database. */ protected String connectionName = null; /** * The connection URL to use when trying to connect to the database. */ protected String connectionPassword = null; /** * Instance of the JDBC Driver class we use as a connection factory. */ protected Driver driver = null; private String driverName; private String connectionURL; private String tableName; private String remoteHostField; private String userField; private String timestampField; private String virtualHostField; private String methodField; private String queryField; private String statusField; private String bytesField; private String refererField; private String userAgentField; private String pattern; private boolean resolveHosts; private Connection conn; private PreparedStatement ps; private long currentTimeMillis; /** * @see #setRequestAttributesEnabled(boolean) */ protected boolean requestAttributesEnabled = true; /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.valves.JDBCAccessLogValve/1.1"; // ------------------------------------------------------------- Properties /** * {@inheritDoc} */ @Override public void setRequestAttributesEnabled(boolean requestAttributesEnabled) { this.requestAttributesEnabled = requestAttributesEnabled; } /** * {@inheritDoc} */ @Override public boolean getRequestAttributesEnabled() { return requestAttributesEnabled; } /** * Return the username to use to connect to the database. * */ public String getConnectionName() { return connectionName; } /** * Set the username to use to connect to the database. * * @param connectionName Username */ public void setConnectionName(String connectionName) { this.connectionName = connectionName; } /** * Sets the database driver name. * * @param driverName The complete name of the database driver class. */ public void setDriverName(String driverName) { this.driverName = driverName; } /** * Return the password to use to connect to the database. * */ public String getConnectionPassword() { return connectionPassword; } /** * Set the password to use to connect to the database. * * @param connectionPassword User password */ public void setConnectionPassword(String connectionPassword) { this.connectionPassword = connectionPassword; } /** * Sets the JDBC URL for the database where the log is stored. * * @param connectionURL The JDBC URL of the database. */ public void setConnectionURL(String connectionURL) { this.connectionURL = connectionURL; } /** * Sets the name of the table where the logs are stored. * * @param tableName The name of the table. */ public void setTableName(String tableName) { this.tableName = tableName; } /** * Sets the name of the field containing the remote host. * * @param remoteHostField The name of the remote host field. */ public void setRemoteHostField(String remoteHostField) { this.remoteHostField = remoteHostField; } /** * Sets the name of the field containing the remote user name. * * @param userField The name of the remote user field. */ public void setUserField(String userField) { this.userField = userField; } /** * Sets the name of the field containing the server-determined timestamp. * * @param timestampField The name of the server-determined timestamp field. */ public void setTimestampField(String timestampField) { this.timestampField = timestampField; } /** * Sets the name of the field containing the virtual host information * (this is in fact the server name). * * @param virtualHostField The name of the virtual host field. */ public void setVirtualHostField(String virtualHostField) { this.virtualHostField = virtualHostField; } /** * Sets the name of the field containing the HTTP request method. * * @param methodField The name of the HTTP request method field. */ public void setMethodField(String methodField) { this.methodField = methodField; } /** * Sets the name of the field containing the URL part of the HTTP query. * * @param queryField The name of the field containing the URL part of * the HTTP query. */ public void setQueryField(String queryField) { this.queryField = queryField; } /** * Sets the name of the field containing the HTTP response status code. * * @param statusField The name of the HTTP response status code field. */ public void setStatusField(String statusField) { this.statusField = statusField; } /** * Sets the name of the field containing the number of bytes returned. * * @param bytesField The name of the returned bytes field. */ public void setBytesField(String bytesField) { this.bytesField = bytesField; } /** * Sets the name of the field containing the referer. * * @param refererField The referer field name. */ public void setRefererField(String refererField) { this.refererField = refererField; } /** * Sets the name of the field containing the user agent. * * @param userAgentField The name of the user agent field. */ public void setUserAgentField(String userAgentField) { this.userAgentField = userAgentField; } /** * Sets the logging pattern. The patterns supported correspond to the * file-based "common" and "combined". These are translated into the use * of tables containing either set of fields. *

    TO DO: more flexible field choices.

    * * @param pattern The name of the logging pattern. */ public void setPattern(String pattern) { this.pattern = pattern; } /** * Determines whether IP host name resolution is done. * * @param resolveHosts "true" or "false", if host IP resolution * is desired or not. */ public void setResolveHosts(String resolveHosts) { this.resolveHosts = Boolean.valueOf(resolveHosts).booleanValue(); } /** * get useLongContentLength */ public boolean getUseLongContentLength() { return this.useLongContentLength ; } /** * @param useLongContentLength the useLongContentLength to set */ public void setUseLongContentLength(boolean useLongContentLength) { this.useLongContentLength = useLongContentLength; } // --------------------------------------------------------- Public Methods /** * This method is invoked by Tomcat on each query. * * @param request The Request object. * @param response The Response object. * * @exception IOException Should not be thrown. * @exception ServletException Database SQLException is wrapped * in a ServletException. */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { getNext().invoke(request, response); } @Override public void log(Request request, Response response, long time) { if (!getState().isAvailable()) { return; } final String EMPTY = "" ; String remoteHost; if(resolveHosts) { if (requestAttributesEnabled) { Object host = request.getAttribute(REMOTE_HOST_ATTRIBUTE); if (host == null) { remoteHost = request.getRemoteHost(); } else { remoteHost = (String) host; } } else { remoteHost = request.getRemoteHost(); } } else { if (requestAttributesEnabled) { Object addr = request.getAttribute(REMOTE_ADDR_ATTRIBUTE); if (addr == null) { remoteHost = request.getRemoteAddr(); } else { remoteHost = (String) addr; } } else { remoteHost = request.getRemoteAddr(); } } String user = request.getRemoteUser(); String query=request.getRequestURI(); long bytes = response.getBytesWritten(true); if(bytes < 0) { bytes = 0; } int status = response.getStatus(); String virtualHost = EMPTY; String method = EMPTY; String referer = EMPTY; String userAgent = EMPTY; String logPattern = pattern; if (logPattern.equals("combined")) { virtualHost = request.getServerName(); method = request.getMethod(); referer = request.getHeader("referer"); userAgent = request.getHeader("user-agent"); } synchronized (this) { int numberOfTries = 2; while (numberOfTries>0) { try { open(); ps.setString(1, remoteHost); ps.setString(2, user); ps.setTimestamp(3, new Timestamp(getCurrentTimeMillis())); ps.setString(4, query); ps.setInt(5, status); if(useLongContentLength) { ps.setLong(6, bytes); } else { if (bytes > Integer.MAX_VALUE) { bytes = -1 ; } ps.setInt(6, (int) bytes); } if (logPattern.equals("combined")) { ps.setString(7, virtualHost); ps.setString(8, method); ps.setString(9, referer); ps.setString(10, userAgent); } ps.executeUpdate(); return; } catch (SQLException e) { // Log the problem for posterity container.getLogger().error(sm.getString("jdbcAccessLogValve.exception"), e); // Close the connection so that it gets reopened next time if (conn != null) { close(); } } numberOfTries--; } } } /** * Open (if necessary) and return a database connection for use by * this AccessLogValve. * * @exception SQLException if a database error occurs */ protected void open() throws SQLException { // Do nothing if there is a database connection already open if (conn != null) { return ; } // Instantiate our database driver if necessary if (driver == null) { try { Class clazz = Class.forName(driverName); driver = (Driver) clazz.newInstance(); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); throw new SQLException(e.getMessage(), e); } } // Open a new connection Properties props = new Properties(); props.put("autoReconnect", "true"); if (connectionName != null) { props.put("user", connectionName); } if (connectionPassword != null) { props.put("password", connectionPassword); } conn = driver.connect(connectionURL, props); conn.setAutoCommit(true); String logPattern = pattern; if (logPattern.equals("common")) { ps = conn.prepareStatement ("INSERT INTO " + tableName + " (" + remoteHostField + ", " + userField + ", " + timestampField +", " + queryField + ", " + statusField + ", " + bytesField + ") VALUES(?, ?, ?, ?, ?, ?)"); } else if (logPattern.equals("combined")) { ps = conn.prepareStatement ("INSERT INTO " + tableName + " (" + remoteHostField + ", " + userField + ", " + timestampField + ", " + queryField + ", " + statusField + ", " + bytesField + ", " + virtualHostField + ", " + methodField + ", " + refererField + ", " + userAgentField + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); } } /** * Close the specified database connection. */ protected void close() { // Do nothing if the database connection is already closed if (conn == null) { return; } // Close our prepared statements (if any) try { ps.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.ps = null; // Close this database connection, and log any errors try { conn.close(); } catch (SQLException e) { container.getLogger().error(sm.getString("jdbcAccessLogValeve.close"), e); // Just log it here } finally { this.conn = null; } } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { try { open() ; } catch (SQLException e) { throw new LifecycleException(e); } setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); close() ; } public long getCurrentTimeMillis() { long systime = System.currentTimeMillis(); if ((systime - currentTimeMillis) > 1000) { currentTimeMillis = new java.util.Date(systime).getTime(); } return currentTimeMillis; } } tomcat7-7.0.52/java/org/apache/catalina/valves/RemoteAddrValve.java0000644000175100017510000000505312271471332025044 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import javax.servlet.ServletException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** * Concrete implementation of RequestFilterValve that filters * based on the string representation of the remote client's IP address. * * @author Craig R. McClanahan */ public final class RemoteAddrValve extends RequestFilterValve { // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.RemoteAddrValve/1.0"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Extract the desired request property, and pass it (along with the * specified request and response objects) to the protected * process() method to perform the actual filtering. * This method must be implemented by a concrete subclass. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { process(request.getRequest().getRemoteAddr(), request, response); } } tomcat7-7.0.52/java/org/apache/catalina/valves/PersistentValve.java0000644000175100017510000002042412271471332025155 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.Manager; import org.apache.catalina.Session; import org.apache.catalina.Store; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.session.PersistentManager; /** * Valve that implements per-request session persistence. It is intended to be * used with non-sticky load-balancers. *

    * USAGE CONSTRAINT: To work correctly it requires a PersistentManager. *

    * USAGE CONSTRAINT: To work correctly it assumes only one request exists * per session at any one time. * * @author Jean-Frederic Clere */ public class PersistentValve extends ValveBase { //------------------------------------------------------ Constructor public PersistentValve() { super(true); } // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.PersistentValve/1.0"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Select the appropriate child Context to process this request, * based on the specified request URI. If no matching Context can * be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { // Select the Context to be used for this Request Context context = request.getContext(); if (context == null) { response.sendError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getString("standardHost.noContext")); return; } // Bind the context CL to the current thread Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); // Update the session last access time for our session (if any) String sessionId = request.getRequestedSessionId(); Manager manager = context.getManager(); if (sessionId != null && manager != null) { if (manager instanceof PersistentManager) { Store store = ((PersistentManager) manager).getStore(); if (store != null) { Session session = null; try { session = store.load(sessionId); } catch (Exception e) { container.getLogger().error("deserializeError"); } if (session != null) { if (!session.isValid() || isSessionStale(session, System.currentTimeMillis())) { if (container.getLogger().isDebugEnabled()) { container.getLogger().debug("session swapped in is invalid or expired"); } session.expire(); store.remove(sessionId); } else { session.setManager(manager); // session.setId(sessionId); Only if new ??? manager.add(session); // ((StandardSession)session).activate(); session.access(); session.endAccess(); } } } } } if (container.getLogger().isDebugEnabled()) { container.getLogger().debug("sessionId: " + sessionId); } // Ask the next valve to process the request. getNext().invoke(request, response); // If still processing async, don't try to store the session // TODO: Are there some async states where it is would be safe to store // the session? if (!request.isAsync()) { // Read the sessionid after the response. // HttpSession hsess = hreq.getSession(false); Session hsess; try { hsess = request.getSessionInternal(); } catch (Exception ex) { hsess = null; } String newsessionId = null; if (hsess!=null) { newsessionId = hsess.getIdInternal(); } if (container.getLogger().isDebugEnabled()) { container.getLogger().debug("newsessionId: " + newsessionId); } if (newsessionId!=null) { /* store the session and remove it from the manager */ if (manager instanceof PersistentManager) { Session session = manager.findSession(newsessionId); Store store = ((PersistentManager) manager).getStore(); if (store != null && session!=null && session.isValid() && !isSessionStale(session, System.currentTimeMillis())) { // ((StandardSession)session).passivate(); store.save(session); ((PersistentManager) manager).removeSuper(session); session.recycle(); } else { if (container.getLogger().isDebugEnabled()) { container.getLogger().debug("newsessionId store: " + store + " session: " + session + " valid: " + (session == null ? "N/A" : Boolean.toString( session.isValid())) + " stale: " + isSessionStale(session, System.currentTimeMillis())); } } } else { if (container.getLogger().isDebugEnabled()) { container.getLogger().debug("newsessionId Manager: " + manager); } } } } } /** * Indicate whether the session has been idle for longer * than its expiration date as of the supplied time. * * FIXME: Probably belongs in the Session class. */ protected boolean isSessionStale(Session session, long timeNow) { if (session != null) { int maxInactiveInterval = session.getMaxInactiveInterval(); if (maxInactiveInterval >= 0) { int timeIdle = // Truncate, do not round up (int) ((timeNow - session.getThisAccessedTime()) / 1000L); if (timeIdle >= maxInactiveInterval) { return true; } } } return false; } } tomcat7-7.0.52/java/org/apache/catalina/valves/package.html0000644000175100017510000000231112271471332023430 0ustar locutuslocutus

    This package contains a variety of small Valve implementations that do not warrant being packaged separately. In addition, there is a convenience base class (ValveBase) that supports the usual mechanisms for including custom Valves into the corresponding Pipeline.

    Other packages that include Valves include org.apache.tomcat.logger and org.apache.tomcat.security.

    tomcat7-7.0.52/java/org/apache/catalina/valves/ExtendedAccessLogValve.java0000644000175100017510000010075412271471332026346 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.TimeZone; import javax.servlet.http.Cookie; import javax.servlet.http.HttpSession; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.util.ServerInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; /** * An implementation of the W3c Extended Log File Format. See * http://www.w3.org/TR/WD-logfile.html for more information about the format. * * The following fields are supported: *
      *
    • c-dns: Client hostname (or ip address if * enableLookups for the connector is false)
    • *
    • c-ip: Client ip address
    • *
    • bytes: bytes served
    • *
    • cs-method: request method
    • *
    • cs-uri: The full uri requested
    • *
    • cs-uri-query: The query string
    • *
    • cs-uri-stem: The uri without query string
    • *
    • date: The date in yyyy-mm-dd format for GMT
    • *
    • s-dns: The server dns entry
    • *
    • s-ip: The server ip address
    • *
    • cs(XXX): The value of header XXX from client to server
    • *
    • sc(XXX): The value of header XXX from server to client
    • *
    • sc-status: The status code
    • *
    • time: Time the request was served
    • *
    • time-taken: Time (in seconds) taken to serve the request
    • *
    • x-threadname: Current request thread name (can compare later with stacktraces)
    • *
    • x-A(XXX): Pull XXX attribute from the servlet context
    • *
    • x-C(XXX): Pull the first cookie of the name XXX
    • *
    • x-O(XXX): Pull the all response header values XXX
    • *
    • x-R(XXX): Pull XXX attribute from the servlet request
    • *
    • x-S(XXX): Pull XXX attribute from the session
    • *
    • x-P(...): Call request.getParameter(...) * and URLencode it. Helpful to capture * certain POST parameters. *
    • *
    • For any of the x-H(...) the following method will be called from the * HttpServletRequest object
    • *
    • x-H(authType): getAuthType
    • *
    • x-H(characterEncoding): getCharacterEncoding
    • *
    • x-H(contentLength): getContentLength
    • *
    • x-H(locale): getLocale
    • *
    • x-H(protocol): getProtocol
    • *
    • x-H(remoteUser): getRemoteUser
    • *
    • x-H(requestedSessionId): getRequestedSessionId
    • *
    • x-H(requestedSessionIdFromCookie): * isRequestedSessionIdFromCookie
    • *
    • x-H(requestedSessionIdValid): * isRequestedSessionIdValid
    • *
    • x-H(scheme): getScheme
    • *
    • x-H(secure): isSecure
    • *
    * * * *

    * Log rotation can be on or off. This is dictated by the * rotatable property. *

    * *

    * For UNIX users, another field called checkExists is also * available. If set to true, the log file's existence will be checked before * each logging. This way an external log rotator can move the file * somewhere and Tomcat will start with a new file. *

    * *

    * For JMX junkies, a public method called rotate has * been made available to allow you to tell this instance to move * the existing log file to somewhere else and start writing a new log file. *

    * *

    * Conditional logging is also supported. This can be done with the * condition property. * If the value returned from ServletRequest.getAttribute(condition) * yields a non-null value, the logging will be skipped. *

    * *

    * For extended attributes coming from a getAttribute() call, * it is you responsibility to ensure there are no newline or * control characters. *

    * * * @author Tim Funk * @author Peter Rossbach */ public class ExtendedAccessLogValve extends AccessLogValve { private static final Log log = LogFactory.getLog(ExtendedAccessLogValve.class); // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ protected static final String extendedAccessLogInfo = "org.apache.catalina.valves.ExtendedAccessLogValve/2.1"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this implementation. */ @Override public String getInfo() { return (extendedAccessLogInfo); } // --------------------------------------------------------- Public Methods // -------------------------------------------------------- Private Methods /** * Wrap the incoming value into quotes and escape any inner * quotes with double quotes. * * @param value - The value to wrap quotes around * @return '-' if empty of null. Otherwise, toString() will * be called on the object and the value will be wrapped * in quotes and any quotes will be escaped with 2 * sets of quotes. */ private String wrap(Object value) { String svalue; // Does the value contain a " ? If so must encode it if (value == null || "-".equals(value)) { return "-"; } try { svalue = value.toString(); if ("".equals(svalue)) { return "-"; } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); /* Log error */ return "-"; } /* Wrap all quotes in double quotes. */ StringBuilder buffer = new StringBuilder(svalue.length() + 2); buffer.append('\''); int i = 0; while (i < svalue.length()) { int j = svalue.indexOf('\'', i); if (j == -1) { buffer.append(svalue.substring(i)); i = svalue.length(); } else { buffer.append(svalue.substring(i, j + 1)); buffer.append('"'); i = j + 2; } } buffer.append('\''); return buffer.toString(); } /** * Open the new log file for the date specified by dateStamp. */ @Override protected synchronized void open() { super.open(); if (currentLogFile.length()==0) { writer.println("#Fields: " + pattern); writer.println("#Version: 2.0"); writer.println("#Software: " + ServerInfo.getServerInfo()); } } // ------------------------------------------------------ Lifecycle Methods protected static class DateElement implements AccessLogElement { // Milli-seconds in 24 hours private static final long INTERVAL = (1000 * 60 * 60 * 24); private static final ThreadLocal currentDate = new ThreadLocal() { @Override protected ElementTimestampStruct initialValue() { return new ElementTimestampStruct("yyyy-MM-dd"); } }; @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { ElementTimestampStruct eds = currentDate.get(); long millis = eds.currentTimestamp.getTime(); if (date.getTime() > (millis + INTERVAL -1) || date.getTime() < millis) { eds.currentTimestamp.setTime( date.getTime() - (date.getTime() % INTERVAL)); eds.currentTimestampString = eds.currentTimestampFormat.format(eds.currentTimestamp); } buf.append(eds.currentTimestampString); } } protected static class TimeElement implements AccessLogElement { // Milli-seconds in a second private static final long INTERVAL = 1000; private static final ThreadLocal currentTime = new ThreadLocal() { @Override protected ElementTimestampStruct initialValue() { return new ElementTimestampStruct("HH:mm:ss"); } }; @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { ElementTimestampStruct eds = currentTime.get(); long millis = eds.currentTimestamp.getTime(); if (date.getTime() > (millis + INTERVAL -1) || date.getTime() < millis) { eds.currentTimestamp.setTime( date.getTime() - (date.getTime() % INTERVAL)); eds.currentTimestampString = eds.currentTimestampFormat.format(eds.currentTimestamp); } buf.append(eds.currentTimestampString); } } protected class RequestHeaderElement implements AccessLogElement { private final String header; public RequestHeaderElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getHeader(header))); } } protected class ResponseHeaderElement implements AccessLogElement { private final String header; public ResponseHeaderElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(response.getHeader(header))); } } protected class ServletContextElement implements AccessLogElement { private final String attribute; public ServletContextElement(String attribute) { this.attribute = attribute; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getContext().getServletContext() .getAttribute(attribute))); } } protected class CookieElement implements AccessLogElement { private final String name; public CookieElement(String name) { this.name = name; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { Cookie[] c = request.getCookies(); for (int i = 0; c != null && i < c.length; i++) { if (name.equals(c[i].getName())) { buf.append(wrap(c[i].getValue())); } } } } /** * write a specific response header - x-O(xxx) */ protected class ResponseAllHeaderElement implements AccessLogElement { private final String header; public ResponseAllHeaderElement(String header) { this.header = header; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { if (null != response) { Iterator iter = response.getHeaders(header).iterator(); if (iter.hasNext()) { StringBuilder buffer = new StringBuilder(); boolean first = true; while (iter.hasNext()) { if (!first) { buffer.append(","); } buffer.append(iter.next()); } buf.append(wrap(buffer.toString())); } return ; } buf.append("-"); } } protected class RequestAttributeElement implements AccessLogElement { private final String attribute; public RequestAttributeElement(String attribute) { this.attribute = attribute; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getAttribute(attribute))); } } protected class SessionAttributeElement implements AccessLogElement { private final String attribute; public SessionAttributeElement(String attribute) { this.attribute = attribute; } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { HttpSession session = null; if (request != null) { session = request.getSession(false); if (session != null) { buf.append(wrap(session.getAttribute(attribute))); } } } } protected class RequestParameterElement implements AccessLogElement { private final String parameter; public RequestParameterElement(String parameter) { this.parameter = parameter; } /** * urlEncode the given string. If null or empty, return null. */ private String urlEncode(String value) { if (null==value || value.length()==0) { return null; } try { return URLEncoder.encode(value, "UTF-8"); } catch (UnsupportedEncodingException e) { // Should never happen - all JVMs are required to support UTF-8 return null; } } @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(urlEncode(request.getParameter(parameter)))); } } protected static class PatternTokenizer { private StringReader sr = null; private StringBuilder buf = new StringBuilder(); private boolean ended = false; private boolean subToken; private boolean parameter; public PatternTokenizer(String str) { sr = new StringReader(str); } public boolean hasSubToken() { return subToken; } public boolean hasParameter() { return parameter; } public String getToken() throws IOException { if(ended) { return null ; } String result = null; subToken = false; parameter = false; int c = sr.read(); while (c != -1) { switch (c) { case ' ': result = buf.toString(); buf = new StringBuilder(); buf.append((char) c); return result; case '-': result = buf.toString(); buf = new StringBuilder(); subToken = true; return result; case '(': result = buf.toString(); buf = new StringBuilder(); parameter = true; return result; case ')': result = buf.toString(); buf = new StringBuilder(); break; default: buf.append((char) c); } c = sr.read(); } ended = true; if (buf.length() != 0) { return buf.toString(); } else { return null; } } public String getParameter()throws IOException { String result; if (!parameter) { return null; } parameter = false; int c = sr.read(); while (c != -1) { if (c == ')') { result = buf.toString(); buf = new StringBuilder(); return result; } buf.append((char) c); c = sr.read(); } return null; } public String getWhiteSpaces() throws IOException { if(isEnded()) { return "" ; } StringBuilder whiteSpaces = new StringBuilder(); if (buf.length() > 0) { whiteSpaces.append(buf); buf = new StringBuilder(); } int c = sr.read(); while (Character.isWhitespace((char) c)) { whiteSpaces.append((char) c); c = sr.read(); } if (c == -1) { ended = true; } else { buf.append((char) c); } return whiteSpaces.toString(); } public boolean isEnded() { return ended; } public String getRemains() throws IOException { StringBuilder remains = new StringBuilder(); for(int c = sr.read(); c != -1; c = sr.read()) { remains.append((char) c); } return remains.toString(); } } @Override protected AccessLogElement[] createLogElements() { if (log.isDebugEnabled()) { log.debug("decodePattern, pattern =" + pattern); } List list = new ArrayList(); PatternTokenizer tokenizer = new PatternTokenizer(pattern); try { // Ignore leading whitespace. tokenizer.getWhiteSpaces(); if (tokenizer.isEnded()) { log.info("pattern was just empty or whitespace"); return null; } String token = tokenizer.getToken(); while (token != null) { if (log.isDebugEnabled()) { log.debug("token = " + token); } AccessLogElement element = getLogElement(token, tokenizer); if (element == null) { break; } list.add(element); String whiteSpaces = tokenizer.getWhiteSpaces(); if (whiteSpaces.length() > 0) { list.add(new StringElement(whiteSpaces)); } if (tokenizer.isEnded()) { break; } token = tokenizer.getToken(); } if (log.isDebugEnabled()) { log.debug("finished decoding with element size of: " + list.size()); } return list.toArray(new AccessLogElement[0]); } catch (IOException e) { log.error("parse error", e); return null; } } protected AccessLogElement getLogElement(String token, PatternTokenizer tokenizer) throws IOException { if ("date".equals(token)) { return new DateElement(); } else if ("time".equals(token)) { if (tokenizer.hasSubToken()) { String nextToken = tokenizer.getToken(); if ("taken".equals(nextToken)) { return new ElapsedTimeElement(false); } } else { return new TimeElement(); } } else if ("bytes".equals(token)) { return new ByteSentElement(true); } else if ("cached".equals(token)) { /* I don't know how to evaluate this! */ return new StringElement("-"); } else if ("c".equals(token)) { String nextToken = tokenizer.getToken(); if ("ip".equals(nextToken)) { return new RemoteAddrElement(); } else if ("dns".equals(nextToken)) { return new HostElement(); } } else if ("s".equals(token)) { String nextToken = tokenizer.getToken(); if ("ip".equals(nextToken)) { return new LocalAddrElement(); } else if ("dns".equals(nextToken)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { String value; try { value = InetAddress.getLocalHost().getHostName(); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); value = "localhost"; } buf.append(value); } }; } } else if ("cs".equals(token)) { return getClientToServerElement(tokenizer); } else if ("sc".equals(token)) { return getServerToClientElement(tokenizer); } else if ("sr".equals(token) || "rs".equals(token)) { return getProxyElement(tokenizer); } else if ("x".equals(token)) { return getXParameterElement(tokenizer); } log.error("unable to decode with rest of chars starting: " + token); return null; } protected AccessLogElement getClientToServerElement( PatternTokenizer tokenizer) throws IOException { if (tokenizer.hasSubToken()) { String token = tokenizer.getToken(); if ("method".equals(token)) { return new MethodElement(); } else if ("uri".equals(token)) { if (tokenizer.hasSubToken()) { token = tokenizer.getToken(); if ("stem".equals(token)) { return new RequestURIElement(); } else if ("query".equals(token)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { String query = request.getQueryString(); if (query != null) { buf.append(query); } else { buf.append('-'); } } }; } } else { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { String query = request.getQueryString(); if (query == null) { buf.append(request.getRequestURI()); } else { buf.append(request.getRequestURI()); buf.append('?'); buf.append(request.getQueryString()); } } }; } } } else if (tokenizer.hasParameter()) { String parameter = tokenizer.getParameter(); if (parameter == null) { log.error("No closing ) found for in decode"); return null; } return new RequestHeaderElement(parameter); } log.error("The next characters couldn't be decoded: " + tokenizer.getRemains()); return null; } protected AccessLogElement getServerToClientElement( PatternTokenizer tokenizer) throws IOException { if (tokenizer.hasSubToken()) { String token = tokenizer.getToken(); if ("status".equals(token)) { return new HttpStatusCodeElement(); } else if ("comment".equals(token)) { return new StringElement("?"); } } else if (tokenizer.hasParameter()) { String parameter = tokenizer.getParameter(); if (parameter == null) { log.error("No closing ) found for in decode"); return null; } return new ResponseHeaderElement(parameter); } log.error("The next characters couldn't be decoded: " + tokenizer.getRemains()); return null; } protected AccessLogElement getProxyElement(PatternTokenizer tokenizer) throws IOException { String token = null; if (tokenizer.hasSubToken()) { tokenizer.getToken(); return new StringElement("-"); } else if (tokenizer.hasParameter()) { tokenizer.getParameter(); return new StringElement("-"); } log.error("The next characters couldn't be decoded: " + token); return null; } protected AccessLogElement getXParameterElement(PatternTokenizer tokenizer) throws IOException { if (!tokenizer.hasSubToken()) { log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!"); return null; } String token = tokenizer.getToken(); if ("threadname".equals(token)) { return new ThreadNameElement(); } if (!tokenizer.hasParameter()) { log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!"); return null; } String parameter = tokenizer.getParameter(); if (parameter == null) { log.error("No closing ) found for in decode"); return null; } if ("A".equals(token)) { return new ServletContextElement(parameter); } else if ("C".equals(token)) { return new CookieElement(parameter); } else if ("R".equals(token)) { return new RequestAttributeElement(parameter); } else if ("S".equals(token)) { return new SessionAttributeElement(parameter); } else if ("H".equals(token)) { return getServletRequestElement(parameter); } else if ("P".equals(token)) { return new RequestParameterElement(parameter); } else if ("O".equals(token)) { return new ResponseAllHeaderElement(parameter); } log.error("x param for servlet request, couldn't decode value: " + token); return null; } protected AccessLogElement getServletRequestElement(String parameter) { if ("authType".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getAuthType())); } }; } else if ("remoteUser".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getRemoteUser())); } }; } else if ("requestedSessionId".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getRequestedSessionId())); } }; } else if ("requestedSessionIdFromCookie".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap("" + request.isRequestedSessionIdFromCookie())); } }; } else if ("requestedSessionIdValid".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap("" + request.isRequestedSessionIdValid())); } }; } else if ("contentLength".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap("" + request.getContentLength())); } }; } else if ("characterEncoding".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getCharacterEncoding())); } }; } else if ("locale".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getLocale())); } }; } else if ("protocol".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap(request.getProtocol())); } }; } else if ("scheme".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(request.getScheme()); } }; } else if ("secure".equals(parameter)) { return new AccessLogElement() { @Override public void addElement(StringBuilder buf, Date date, Request request, Response response, long time) { buf.append(wrap("" + request.isSecure())); } }; } log.error("x param for servlet request, couldn't decode value: " + parameter); return null; } private static class ElementTimestampStruct { private final Date currentTimestamp = new Date(0); private final SimpleDateFormat currentTimestampFormat; private String currentTimestampString; ElementTimestampStruct(String format) { currentTimestampFormat = new SimpleDateFormat(format, Locale.US); currentTimestampFormat.setTimeZone(TimeZone.getTimeZone("GMT")); } } } tomcat7-7.0.52/java/org/apache/catalina/valves/RemoteIpValve.java0000644000175100017510000007323412267226511024552 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; import javax.servlet.ServletException; import org.apache.catalina.AccessLog; import org.apache.catalina.Globals; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    * Tomcat port of mod_remoteip, this valve replaces the apparent * client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request * headers (e.g. "X-Forwarded-For"). *

    *

    * Another feature of this valve is to replace the apparent scheme (http/https) and server port with the scheme presented by a proxy or a * load balancer via a request header (e.g. "X-Forwarded-Proto"). *

    *

    * This valve proceeds as follows: *

    *

    * If the incoming request.getRemoteAddr() matches the valve's list of internal proxies : *

      *
    • Loop on the comma delimited list of IPs and hostnames passed by the preceding load balancer or proxy in the given request's Http * header named $remoteIpHeader (default value x-forwarded-for). Values are processed in right-to-left order.
    • *
    • For each ip/host of the list: *
        *
      • if it matches the internal proxies list, the ip/host is swallowed
      • *
      • if it matches the trusted proxies list, the ip/host is added to the created proxies header
      • *
      • otherwise, the ip/host is declared to be the remote ip and looping is stopped.
      • *
      *
    • *
    • If the request http header named $protocolHeader (e.g. x-forwarded-for) equals to the value of * protocolHeaderHttpsValue configuration parameter (default https) then request.isSecure = true, * request.scheme = https and request.serverPort = 443. Note that 443 can be overwritten with the * $httpsServerPort configuration parameter.
    • *
    *

    *

    * Configuration parameters: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    RemoteIpValve propertyDescriptionEquivalent mod_remoteip directiveFormatDefault Value
    remoteIpHeaderName of the Http Header read by this valve that holds the list of traversed IP addresses starting from the requesting clientRemoteIPHeaderCompliant http header namex-forwarded-for
    internalProxiesRegular expression that matches the IP addresses of internal proxies. * If they appear in the remoteIpHeader value, they will be * trusted and will not appear * in the proxiesHeader valueRemoteIPInternalProxyRegular expression (in the syntax supported by * {@link java.util.regex.Pattern java.util.regex})10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3}
    * By default, 10/8, 192.168/16, 169.254/16 and 127/8 are allowed ; 172.16/12 has not been enabled by default because it is complex to * describe with regular expressions
    proxiesHeaderName of the http header created by this valve to hold the list of proxies that have been processed in the incoming * remoteIpHeaderproxiesHeaderCompliant http header namex-forwarded-by
    trustedProxiesRegular expression that matches the IP addresses of trusted proxies. * If they appear in the remoteIpHeader value, they will be * trusted and will appear in the proxiesHeader valueRemoteIPTrustedProxyRegular expression (in the syntax supported by * {@link java.util.regex.Pattern java.util.regex}) 
    protocolHeaderName of the http header read by this valve that holds the flag that this request N/ACompliant http header name like X-Forwarded-Proto, X-Forwarded-Ssl or Front-End-Httpsnull
    protocolHeaderHttpsValueValue of the protocolHeader to indicate that it is an Https requestN/AString like https or ONhttps
    httpServerPortValue returned by {@link javax.servlet.ServletRequest#getServerPort()} when the protocolHeader indicates http protocolN/Ainteger80
    httpsServerPortValue returned by {@link javax.servlet.ServletRequest#getServerPort()} when the protocolHeader indicates https protocolN/Ainteger443
    *

    *

    *

    * This Valve may be attached to any Container, depending on the granularity of the filtering you wish to perform. *

    *

    * Regular expression vs. IP address blocks: mod_remoteip allows to use address blocks (e.g. * 192.168/16) to configure RemoteIPInternalProxy and RemoteIPTrustedProxy ; as Tomcat doesn't have a * library similar to apr_ipsubnet_test, * RemoteIpValve uses regular expression to configure internalProxies and trustedProxies in the same * fashion as {@link RequestFilterValve} does. *

    *
    *

    * Sample with internal proxies *

    *

    * RemoteIpValve configuration: *

    *
     * <Valve
     *   className="org.apache.catalina.valves.RemoteIpValve"
     *   internalProxies="192\.168\.0\.10|192\.168\.0\.11"
     *   remoteIpHeader="x-forwarded-for"
     *   proxiesHeader="x-forwarded-by"
     *   protocolHeader="x-forwarded-proto"
     *   />
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpValveValue After RemoteIpValve
    request.remoteAddr192.168.0.10140.211.11.130
    request.header['x-forwarded-for']140.211.11.130, 192.168.0.10null
    request.header['x-forwarded-by']nullnull
    request.header['x-forwarded-proto']httpshttps
    request.schemehttphttps
    request.securefalsetrue
    request.serverPort80443
    * Note : x-forwarded-by header is null because only internal proxies as been traversed by the request. * x-forwarded-by is null because all the proxies are trusted or internal. *

    *
    *

    * Sample with trusted proxies *

    *

    * RemoteIpValve configuration: *

    *
     * <Valve
     *   className="org.apache.catalina.valves.RemoteIpValve"
     *   internalProxies="192\.168\.0\.10|192\.168\.0\.11"
     *   remoteIpHeader="x-forwarded-for"
     *   proxiesHeader="x-forwarded-by"
     *   trustedProxies="proxy1|proxy2"
     *   />
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpValveValue After RemoteIpValve
    request.remoteAddr192.168.0.10140.211.11.130
    request.header['x-forwarded-for']140.211.11.130, proxy1, proxy2null
    request.header['x-forwarded-by']nullproxy1, proxy2
    * Note : proxy1 and proxy2 are both trusted proxies that come in x-forwarded-for header, they both * are migrated in x-forwarded-by header. x-forwarded-by is null because all the proxies are trusted or internal. *

    *
    *

    * Sample with internal and trusted proxies *

    *

    * RemoteIpValve configuration: *

    *
     * <Valve
     *   className="org.apache.catalina.valves.RemoteIpValve"
     *   internalProxies="192\.168\.0\.10|192\.168\.0\.11"
     *   remoteIpHeader="x-forwarded-for"
     *   proxiesHeader="x-forwarded-by"
     *   trustedProxies="proxy1|proxy2"
     *   />
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpValveValue After RemoteIpValve
    request.remoteAddr192.168.0.10140.211.11.130
    request.header['x-forwarded-for']140.211.11.130, proxy1, proxy2, 192.168.0.10null
    request.header['x-forwarded-by']nullproxy1, proxy2
    * Note : proxy1 and proxy2 are both trusted proxies that come in x-forwarded-for header, they both * are migrated in x-forwarded-by header. As 192.168.0.10 is an internal proxy, it does not appear in * x-forwarded-by. x-forwarded-by is null because all the proxies are trusted or internal. *

    *
    *

    * Sample with an untrusted proxy *

    *

    * RemoteIpValve configuration: *

    *
     * <Valve
     *   className="org.apache.catalina.valves.RemoteIpValve"
     *   internalProxies="192\.168\.0\.10|192\.168\.0\.11"
     *   remoteIpHeader="x-forwarded-for"
     *   proxiesHeader="x-forwarded-by"
     *   trustedProxies="proxy1|proxy2"
     *   />
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpValveValue After RemoteIpValve
    request.remoteAddr192.168.0.10untrusted-proxy
    request.header['x-forwarded-for']140.211.11.130, untrusted-proxy, proxy1140.211.11.130
    request.header['x-forwarded-by']nullproxy1
    * Note : x-forwarded-by holds the trusted proxy proxy1. x-forwarded-by holds * 140.211.11.130 because untrusted-proxy is not trusted and thus, we can not trust that * untrusted-proxy is the actual remote ip. request.remoteAddr is untrusted-proxy that is an IP * verified by proxy1. *

    */ public class RemoteIpValve extends ValveBase { /** * {@link Pattern} for a comma delimited string that support whitespace characters */ private static final Pattern commaSeparatedValuesPattern = Pattern.compile("\\s*,\\s*"); /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.RemoteIpValve/1.0"; /** * Logger */ private static final Log log = LogFactory.getLog(RemoteIpValve.class); /** * Convert a given comma delimited String into an array of String * * @return array of String (non null) */ protected static String[] commaDelimitedListToStringArray(String commaDelimitedStrings) { return (commaDelimitedStrings == null || commaDelimitedStrings.length() == 0) ? new String[0] : commaSeparatedValuesPattern .split(commaDelimitedStrings); } /** * Convert an array of strings in a comma delimited string */ protected static String listToCommaDelimitedString(List stringList) { if (stringList == null) { return ""; } StringBuilder result = new StringBuilder(); for (Iterator it = stringList.iterator(); it.hasNext();) { Object element = it.next(); if (element != null) { result.append(element); if (it.hasNext()) { result.append(", "); } } } return result.toString(); } /** * @see #setHttpServerPort(int) */ private int httpServerPort = 80; /** * @see #setHttpsServerPort(int) */ private int httpsServerPort = 443; private boolean changeLocalPort = false; /** * @see #setInternalProxies(String) */ private Pattern internalProxies = Pattern.compile( "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" + "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" + "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" + "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); /** * @see #setProtocolHeader(String) */ private String protocolHeader = null; /** * @see #setProtocolHeaderHttpsValue(String) */ private String protocolHeaderHttpsValue = "https"; private String portHeader = null; /** * @see #setProxiesHeader(String) */ private String proxiesHeader = "X-Forwarded-By"; /** * @see #setRemoteIpHeader(String) */ private String remoteIpHeader = "X-Forwarded-For"; /** * @see #setRequestAttributesEnabled(boolean) */ private boolean requestAttributesEnabled = true; /** * @see RemoteIpValve#setTrustedProxies(String) */ private Pattern trustedProxies = null; /** * Default constructor that ensures {@link ValveBase#ValveBase(boolean)} is * called with true. */ public RemoteIpValve() { // Async requests are supported with this valve super(true); } public int getHttpsServerPort() { return httpsServerPort; } public int getHttpServerPort() { return httpServerPort; } public boolean isChangeLocalPort() { return changeLocalPort; } public void setChangeLocalPort(boolean changeLocalPort) { this.changeLocalPort = changeLocalPort; } /** * Obtain the name of the HTTP header used to override the value returned * by {@link Request#getServerPort()} and (optionally depending on {link * {@link #isChangeLocalPort()} {@link Request#getLocalPort()}. * * @return The HTTP header name */ public String getPortHeader() { return portHeader; } /** * Set the name of the HTTP header used to override the value returned * by {@link Request#getServerPort()} and (optionally depending on {link * {@link #isChangeLocalPort()} {@link Request#getLocalPort()}. * * @param portHeader The HTTP header name */ public void setPortHeader(String portHeader) { this.portHeader = portHeader; } /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return info; } /** * @see #setInternalProxies(String) * @return Regular expression that defines the internal proxies */ public String getInternalProxies() { if (internalProxies == null) { return null; } return internalProxies.toString(); } /** * @see #setProtocolHeader(String) * @return the protocol header (e.g. "X-Forwarded-Proto") */ public String getProtocolHeader() { return protocolHeader; } /** * @see RemoteIpValve#setProtocolHeaderHttpsValue(String) * @return the value of the protocol header for incoming https request (e.g. "https") */ public String getProtocolHeaderHttpsValue() { return protocolHeaderHttpsValue; } /** * @see #setProxiesHeader(String) * @return the proxies header name (e.g. "X-Forwarded-By") */ public String getProxiesHeader() { return proxiesHeader; } /** * @see #setRemoteIpHeader(String) * @return the remote IP header name (e.g. "X-Forwarded-For") */ public String getRemoteIpHeader() { return remoteIpHeader; } /** * @see #setRequestAttributesEnabled(boolean) * @return true if the attributes will be logged, otherwise * false */ public boolean getRequestAttributesEnabled() { return requestAttributesEnabled; } /** * @see #setTrustedProxies(String) * @return Regular expression that defines the trusted proxies */ public String getTrustedProxies() { if (trustedProxies == null) { return null; } return trustedProxies.toString(); } /** * {@inheritDoc} */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { final String originalRemoteAddr = request.getRemoteAddr(); final String originalRemoteHost = request.getRemoteHost(); final String originalScheme = request.getScheme(); final boolean originalSecure = request.isSecure(); final int originalServerPort = request.getServerPort(); if (internalProxies !=null && internalProxies.matcher(originalRemoteAddr).matches()) { String remoteIp = null; // In java 6, proxiesHeaderValue should be declared as a java.util.Deque LinkedList proxiesHeaderValue = new LinkedList(); StringBuilder concatRemoteIpHeaderValue = new StringBuilder(); for (Enumeration e = request.getHeaders(remoteIpHeader); e.hasMoreElements();) { if (concatRemoteIpHeaderValue.length() > 0) { concatRemoteIpHeaderValue.append(", "); } concatRemoteIpHeaderValue.append(e.nextElement()); } String[] remoteIpHeaderValue = commaDelimitedListToStringArray(concatRemoteIpHeaderValue.toString()); int idx; // loop on remoteIpHeaderValue to find the first trusted remote ip and to build the proxies chain for (idx = remoteIpHeaderValue.length - 1; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; remoteIp = currentRemoteIp; if (internalProxies.matcher(currentRemoteIp).matches()) { // do nothing, internalProxies IPs are not appended to the } else if (trustedProxies != null && trustedProxies.matcher(currentRemoteIp).matches()) { proxiesHeaderValue.addFirst(currentRemoteIp); } else { idx--; // decrement idx because break statement doesn't do it break; } } // continue to loop on remoteIpHeaderValue to build the new value of the remoteIpHeader LinkedList newRemoteIpHeaderValue = new LinkedList(); for (; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; newRemoteIpHeaderValue.addFirst(currentRemoteIp); } if (remoteIp != null) { request.setRemoteAddr(remoteIp); request.setRemoteHost(remoteIp); // use request.coyoteRequest.mimeHeaders.setValue(str).setString(str) because request.addHeader(str, str) is no-op in Tomcat // 6.0 if (proxiesHeaderValue.size() == 0) { request.getCoyoteRequest().getMimeHeaders().removeHeader(proxiesHeader); } else { String commaDelimitedListOfProxies = listToCommaDelimitedString(proxiesHeaderValue); request.getCoyoteRequest().getMimeHeaders().setValue(proxiesHeader).setString(commaDelimitedListOfProxies); } if (newRemoteIpHeaderValue.size() == 0) { request.getCoyoteRequest().getMimeHeaders().removeHeader(remoteIpHeader); } else { String commaDelimitedRemoteIpHeaderValue = listToCommaDelimitedString(newRemoteIpHeaderValue); request.getCoyoteRequest().getMimeHeaders().setValue(remoteIpHeader).setString(commaDelimitedRemoteIpHeaderValue); } } if (protocolHeader != null) { String protocolHeaderValue = request.getHeader(protocolHeader); if (protocolHeaderValue == null) { // don't modify the secure,scheme and serverPort attributes // of the request } else if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) { request.setSecure(true); // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0 request.getCoyoteRequest().scheme().setString("https"); setPorts(request, httpsServerPort); } else { request.setSecure(false); // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0 request.getCoyoteRequest().scheme().setString("http"); setPorts(request, httpServerPort); } } if (log.isDebugEnabled()) { log.debug("Incoming request " + request.getRequestURI() + " with originalRemoteAddr '" + originalRemoteAddr + "', originalRemoteHost='" + originalRemoteHost + "', originalSecure='" + originalSecure + "', originalScheme='" + originalScheme + "' will be seen as newRemoteAddr='" + request.getRemoteAddr() + "', newRemoteHost='" + request.getRemoteHost() + "', newScheme='" + request.getScheme() + "', newSecure='" + request.isSecure() + "'"); } } else { if (log.isDebugEnabled()) { log.debug("Skip RemoteIpValve for request " + request.getRequestURI() + " with originalRemoteAddr '" + request.getRemoteAddr() + "'"); } } if (requestAttributesEnabled) { request.setAttribute(AccessLog.REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr()); request.setAttribute(Globals.REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr()); request.setAttribute(AccessLog.REMOTE_HOST_ATTRIBUTE, request.getRemoteHost()); request.setAttribute(AccessLog.PROTOCOL_ATTRIBUTE, request.getProtocol()); request.setAttribute(AccessLog.SERVER_PORT_ATTRIBUTE, Integer.valueOf(request.getServerPort())); } try { getNext().invoke(request, response); } finally { request.setRemoteAddr(originalRemoteAddr); request.setRemoteHost(originalRemoteHost); request.setSecure(originalSecure); // use request.coyoteRequest.scheme instead of request.setScheme() because request.setScheme() is no-op in Tomcat 6.0 request.getCoyoteRequest().scheme().setString(originalScheme); request.setServerPort(originalServerPort); } } private void setPorts(Request request, int defaultPort) { int port = defaultPort; if (portHeader != null) { String portHeaderValue = request.getHeader(portHeader); if (portHeaderValue != null) { try { port = Integer.parseInt(portHeaderValue); } catch (NumberFormatException nfe) { if (log.isDebugEnabled()) { log.debug(sm.getString( "remoteIpValve.invalidPortHeader", portHeaderValue, portHeader), nfe); } } } } request.setServerPort(port); if (changeLocalPort) { request.setLocalPort(port); } } /** *

    * Server Port value if the {@link #protocolHeader} is not null and does not indicate HTTP *

    *

    * Default value : 80 *

    */ public void setHttpServerPort(int httpServerPort) { this.httpServerPort = httpServerPort; } /** *

    * Server Port value if the {@link #protocolHeader} indicates HTTPS *

    *

    * Default value : 443 *

    */ public void setHttpsServerPort(int httpsServerPort) { this.httpsServerPort = httpsServerPort; } /** *

    * Regular expression that defines the internal proxies. *

    *

    * Default value : 10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254.\d{1,3}.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3} *

    */ public void setInternalProxies(String internalProxies) { if (internalProxies == null || internalProxies.length() == 0) { this.internalProxies = null; } else { this.internalProxies = Pattern.compile(internalProxies); } } /** *

    * Header that holds the incoming protocol, usally named X-Forwarded-Proto. If null, request.scheme and * request.secure will not be modified. *

    *

    * Default value : null *

    */ public void setProtocolHeader(String protocolHeader) { this.protocolHeader = protocolHeader; } /** *

    * Case insensitive value of the protocol header to indicate that the incoming http request uses SSL. *

    *

    * Default value : https *

    */ public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) { this.protocolHeaderHttpsValue = protocolHeaderHttpsValue; } /** *

    * The proxiesHeader directive specifies a header into which mod_remoteip will collect a list of all of the intermediate client IP * addresses trusted to resolve the actual remote IP. Note that intermediate RemoteIPTrustedProxy addresses are recorded in this header, * while any intermediate RemoteIPInternalProxy addresses are discarded. *

    *

    * Name of the http header that holds the list of trusted proxies that has been traversed by the http request. *

    *

    * The value of this header can be comma delimited. *

    *

    * Default value : X-Forwarded-By *

    */ public void setProxiesHeader(String proxiesHeader) { this.proxiesHeader = proxiesHeader; } /** *

    * Name of the http header from which the remote ip is extracted. *

    *

    * The value of this header can be comma delimited. *

    *

    * Default value : X-Forwarded-For *

    * * @param remoteIpHeader */ public void setRemoteIpHeader(String remoteIpHeader) { this.remoteIpHeader = remoteIpHeader; } /** * Should this valve set request attributes for IP address, Hostname, * protocol and port used for the request? This are typically used in * conjunction with the {@link AccessLog} which will otherwise log the * original values. Default is true. * * The attributes set are: *
      *
    • org.apache.catalina.AccessLog.RemoteAddr
    • *
    • org.apache.catalina.AccessLog.RemoteHost
    • *
    • org.apache.catalina.AccessLog.Protocol
    • *
    • org.apache.catalina.AccessLog.ServerPort
    • *
    • org.apache.tomcat.remoteAddr
    • *
    * * @param requestAttributesEnabled true causes the attributes * to be set, false disables * the setting of the attributes. */ public void setRequestAttributesEnabled(boolean requestAttributesEnabled) { this.requestAttributesEnabled = requestAttributesEnabled; } /** *

    * Regular expression defining proxies that are trusted when they appear in * the {@link #remoteIpHeader} header. *

    *

    * Default value : empty list, no external proxy is trusted. *

    */ public void setTrustedProxies(String trustedProxies) { if (trustedProxies == null || trustedProxies.length() == 0) { this.trustedProxies = null; } else { this.trustedProxies = Pattern.compile(trustedProxies); } } } tomcat7-7.0.52/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java0000644000175100017510000001676611650076271027274 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.util.Enumeration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Web crawlers can trigger the creation of many thousands of sessions as they * crawl a site which may result in significant memory consumption. This Valve * ensures that crawlers are associated with a single session - just like normal * users - regardless of whether or not they provide a session token with their * requests. */ public class CrawlerSessionManagerValve extends ValveBase implements HttpSessionBindingListener { private static final Log log = LogFactory.getLog(CrawlerSessionManagerValve.class); private final Map clientIpSessionId = new ConcurrentHashMap(); private final Map sessionIdClientIp = new ConcurrentHashMap(); private String crawlerUserAgents = ".*[bB]ot.*|.*Yahoo! Slurp.*|.*Feedfetcher-Google.*"; private Pattern uaPattern = null; private int sessionInactiveInterval = 60; /** * Specifies a default constructor so async support can be configured. */ public CrawlerSessionManagerValve() { super(true); } /** * Specify the regular expression (using {@link Pattern}) that will be used * to identify crawlers based in the User-Agent header provided. The default * is ".*GoogleBot.*|.*bingbot.*|.*Yahoo! Slurp.*" * * @param crawlerUserAgents The regular expression using {@link Pattern} */ public void setCrawlerUserAgents(String crawlerUserAgents) { this.crawlerUserAgents = crawlerUserAgents; if (crawlerUserAgents == null || crawlerUserAgents.length() == 0) { uaPattern = null; } else { uaPattern = Pattern.compile(crawlerUserAgents); } } /** * @see #setCrawlerUserAgents(String) * @return The current regular expression being used to match user agents. */ public String getCrawlerUserAgents() { return crawlerUserAgents; } /** * Specify the session timeout (in seconds) for a crawler's session. This is * typically lower than that for a user session. The default is 60 seconds. * * @param sessionInactiveInterval The new timeout for crawler sessions */ public void setSessionInactiveInterval(int sessionInactiveInterval) { this.sessionInactiveInterval = sessionInactiveInterval; } /** * @see #setSessionInactiveInterval(int) * @return The current timeout in seconds */ public int getSessionInactiveInterval() { return sessionInactiveInterval; } public Map getClientIpSessionId() { return clientIpSessionId; } @Override protected void initInternal() throws LifecycleException { super.initInternal(); uaPattern = Pattern.compile(crawlerUserAgents); } @Override public void invoke(Request request, Response response) throws IOException, ServletException { boolean isBot = false; String sessionId = null; String clientIp = null; if (log.isDebugEnabled()) { log.debug(request.hashCode() + ": ClientIp=" + request.getRemoteAddr() + ", RequestedSessionId=" + request.getRequestedSessionId()); } // If the incoming request has a valid session ID, no action is required if (request.getSession(false) == null) { // Is this a crawler - check the UA headers Enumeration uaHeaders = request.getHeaders("user-agent"); String uaHeader = null; if (uaHeaders.hasMoreElements()) { uaHeader = uaHeaders.nextElement(); } // If more than one UA header - assume not a bot if (uaHeader != null && !uaHeaders.hasMoreElements()) { if (log.isDebugEnabled()) { log.debug(request.hashCode() + ": UserAgent=" + uaHeader); } if (uaPattern.matcher(uaHeader).matches()) { isBot = true; if (log.isDebugEnabled()) { log.debug(request.hashCode() + ": Bot found. UserAgent=" + uaHeader); } } } // If this is a bot, is the session ID known? if (isBot) { clientIp = request.getRemoteAddr(); sessionId = clientIpSessionId.get(clientIp); if (sessionId != null) { request.setRequestedSessionId(sessionId); if (log.isDebugEnabled()) { log.debug(request.hashCode() + ": SessionID=" + sessionId); } } } } getNext().invoke(request, response); if (isBot) { if (sessionId == null) { // Has bot just created a session, if so make a note of it HttpSession s = request.getSession(false); if (s != null) { clientIpSessionId.put(clientIp, s.getId()); sessionIdClientIp.put(s.getId(), clientIp); // #valueUnbound() will be called on session expiration s.setAttribute(this.getClass().getName(), this); s.setMaxInactiveInterval(sessionInactiveInterval); if (log.isDebugEnabled()) { log.debug(request.hashCode() + ": New bot session. SessionID=" + s.getId()); } } } else { if (log.isDebugEnabled()) { log.debug(request.hashCode() + ": Bot session accessed. SessionID=" + sessionId); } } } } @Override public void valueBound(HttpSessionBindingEvent event) { // NOOP } @Override public void valueUnbound(HttpSessionBindingEvent event) { String clientIp = sessionIdClientIp.remove(event.getSession().getId()); if (clientIp != null) { clientIpSessionId.remove(clientIp); } } } tomcat7-7.0.52/java/org/apache/catalina/valves/mbeans-descriptors.xml0000644000175100017510000005121212271471332025501 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/valves/Constants.java0000644000175100017510000000272012271471332023772 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; /** * Manifest constants for the org.apache.catalina.valves * package. * * @author Craig R. McClanahan */ public final class Constants { public static final String Package = "org.apache.catalina.valves"; // Constants for the AccessLogValve class public static final class AccessLog { public static final String COMMON_ALIAS = "common"; public static final String COMMON_PATTERN = "%h %l %u %t \"%r\" %s %b"; public static final String COMBINED_ALIAS = "combined"; public static final String COMBINED_PATTERN = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\""; } } tomcat7-7.0.52/java/org/apache/catalina/valves/LocalStrings.properties0000644000175100017510000002117512271471332025702 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. requestFilterValve.next=No ''next'' valve has been configured requestFilterValve.syntax=Syntax error in request filter pattern {0} valveBase.noNext=Configuration error: No ''next'' valve configured jdbcAccessLogValve.exception=Exception performing insert access entry jdbcAccessLogValve.close=Exception closing database connection cometConnectionManagerValve.event=Exception processing event cometConnectionManagerValve.listenerEvent=Exception processing session listener event # Access log valve accessLogValve.openFail=Failed to open access log file [{0}] accessLogValve.closeFail=Failed to close access log file accessLogValve.openDirFail=Failed to create directory [{0}] for access logs accessLogValve.rotateFail=Failed to rotate access log accessLogValve.renameFail=Failed to rename access log from [{0}] to [{1}] accessLogValve.alreadyExists=Failed to rename access log from [{0}] to [{1}], file already exists. accessLogValve.invalidLocale=Failed to set locale to [{0}] accessLogValve.unsupportedEncoding=Failed to set encoding to [{0}], will use the system default character set. # Error report valve errorReportValve.errorReport=Error report errorReportValve.statusHeader=HTTP Status {0} - {1} errorReportValve.exceptionReport=Exception report errorReportValve.statusReport=Status report errorReportValve.message=message errorReportValve.description=description errorReportValve.exception=exception errorReportValve.rootCause=root cause errorReportValve.note=note errorReportValve.rootCauseInLogs=The full stack trace of the root cause is available in the {0} logs. errorReportValve.noDescription=No description available # Remote IP valve remoteIpValve.syntax=Invalid regular expressions [{0}] provided. remoteIpValve.invalidPortHeader=Invalid value [{0}] found for port in HTTP header [{1}] # Request filter valve - RemoteAddrValve, RemoteHostValve requestFilterValve.configInvalid=One or more invalid configuration settings were provided for the Remote[Addr|Host]Valve which prevented the Valve and its parent containers from starting sslValve.certError=Failed to process certificate string [{0}] to create a java.security.cert.X509Certificate object sslValve.invalidProvider=The SSL provider specified on the connector associated with this request of [{0}] is invalid. The certificate data could not be processed. #Stuck thread detection Valve stuckThreadDetectionValve.notifyStuckThreadDetected=Thread "{0}" (id={6}) has been active for {1} milliseconds (since {2}) to serve the same request for {4} and may be stuck (configured threshold for this StuckThreadDetectionValve is {5} seconds). There is/are {3} thread(s) in total that are monitored by this Valve and may be stuck. stuckThreadDetectionValve.notifyStuckThreadCompleted=Thread "{0}" (id={3}) was previously reported to be stuck but has completed. It was active for approximately {1} milliseconds.{2,choice,0#|0< There is/are still {2} thread(s) that are monitored by this Valve and may be stuck.} # HTTP status reports # All status codes registered with IANA can be found at # http://www.iana.org/assignments/http-status-codes/http-status-codes.xml # The list might be kept in sync with the one in # org/apache/tomcat/util/http/res/LocalStrings.properties. http.100=The client may continue. http.101=The server is switching protocols according to the "Upgrade" header. http.102=The server has accepted the complete request, but has not yet completed it. http.201=The request succeeded and a new resource has been created on the server. http.202=This request was accepted for processing, but has not been completed. http.203=The meta information presented by the client did not originate from the server. http.204=The request succeeded but there is no information to return. http.205=The client should reset the document view which caused this request to be sent. http.206=The server has fulfilled a partial GET request for this resource. http.207=Multiple status values have been returned. http.208=This collection binding was already reported. http.226=The response is a representation of the result of one or more instance-manipulations applied to the current instance. http.300=The requested resource corresponds to any one of a set of representations, each with its own specific location. http.301=The requested resource has moved permanently to a new location. http.302=The requested resource has moved temporarily to a new location. http.303=The response to this request can be found under a different URI. http.304=The requested resource is available and has not been modified. http.305=The requested resource must be accessed through the proxy given by the "Location" header. http.307=The requested resource resides temporarily under a different URI. http.308=The target resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. http.400=The request sent by the client was syntactically incorrect. http.401=This request requires HTTP authentication. http.402=Payment is required for access to this resource. http.403=Access to the specified resource has been forbidden. http.404=The requested resource is not available. http.405=The specified HTTP method is not allowed for the requested resource. http.406=The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers. http.407=The client must first authenticate itself with the proxy. http.408=The client did not produce a request within the time that the server was prepared to wait. http.409=The request could not be completed due to a conflict with the current state of the resource. http.410=The requested resource is no longer available, and no forwarding address is known. http.411=This request cannot be handled without a defined content length. http.412=A specified precondition has failed for this request. http.413=The request entity is larger than the server is willing or able to process. http.414=The server refused this request because the request URI was too long. http.415=The server refused this request because the request entity is in a format not supported by the requested resource for the requested method. http.416=The requested byte range cannot be satisfied. http.417=The expectation given in the "Expect" request header could not be fulfilled. http.422=The server understood the content type and syntax of the request but was unable to process the contained instructions. http.423=The source or destination resource of a method is locked. http.424=The method could not be performed on the resource because the requested action depended on another action and that action failed. http.426=The request can only be completed after a protocol upgrade. http.428=The request is required to be conditional. http.429=The user has sent too many requests in a given amount of time. http.431=The server refused this request because the request header fields are too large. http.500=The server encountered an internal error that prevented it from fulfilling this request. http.501=The server does not support the functionality needed to fulfill this request. http.502=This server received an invalid response from a server it consulted when acting as a proxy or gateway. http.503=The requested service is not currently available. http.504=The server received a timeout from an upstream server while acting as a gateway or proxy. http.505=The server does not support the requested HTTP protocol version. http.506=The chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process. http.507=The resource does not have sufficient space to record the state of the resource after execution of this method. http.508=The server terminated an operation because it encountered an infinite loop. http.510=The policy for accessing the resource has not been met in the request. http.511=The client needs to authenticate to gain network access. tomcat7-7.0.52/java/org/apache/catalina/valves/SemaphoreValve.java0000644000175100017510000001441312271471332024741 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.util.concurrent.Semaphore; import javax.servlet.ServletException; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** *

    Implementation of a Valve that limits concurrency.

    * *

    This Valve may be attached to any Container, depending on the granularity * of the concurrency control you wish to perform. Note that internally, some * async requests may require multiple serial requests to complete what - to the * user - appears as a single request.

    * * @author Remy Maucherat */ public class SemaphoreValve extends ValveBase { //------------------------------------------------------ Constructor public SemaphoreValve() { super(true); } // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.SemaphoreValve/1.0"; /** * Semaphore. */ protected Semaphore semaphore = null; // ------------------------------------------------------------- Properties /** * Concurrency level of the semaphore. */ protected int concurrency = 10; public int getConcurrency() { return concurrency; } public void setConcurrency(int concurrency) { this.concurrency = concurrency; } /** * Fairness of the semaphore. */ protected boolean fairness = false; public boolean getFairness() { return fairness; } public void setFairness(boolean fairness) { this.fairness = fairness; } /** * Block until a permit is available. */ protected boolean block = true; public boolean getBlock() { return block; } public void setBlock(boolean block) { this.block = block; } /** * Block interruptibly until a permit is available. */ protected boolean interruptible = false; public boolean getInterruptible() { return interruptible; } public void setInterruptible(boolean interruptible) { this.interruptible = interruptible; } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { semaphore = new Semaphore(concurrency, fairness); setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); semaphore = null; } // --------------------------------------------------------- Public Methods /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Do concurrency control on the request using the semaphore. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { if (controlConcurrency(request, response)) { boolean shouldRelease = true; try { if (block) { if (interruptible) { try { semaphore.acquire(); } catch (InterruptedException e) { shouldRelease = false; permitDenied(request, response); return; } } else { semaphore.acquireUninterruptibly(); } } else { if (!semaphore.tryAcquire()) { shouldRelease = false; permitDenied(request, response); return; } } getNext().invoke(request, response); } finally { if (shouldRelease) { semaphore.release(); } } } else { getNext().invoke(request, response); } } /** * Subclass friendly method to add conditions. * @param request * @param response */ public boolean controlConcurrency(Request request, Response response) { return true; } /** * Subclass friendly method to add error handling when a permit isn't * granted. * @param request * @param response * @throws IOException * @throws ServletException */ public void permitDenied(Request request, Response response) throws IOException, ServletException { // NO-OP by default } } tomcat7-7.0.52/java/org/apache/catalina/valves/ErrorReportValve.java0000644000175100017510000002517512271471332025312 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.io.Writer; import java.util.Scanner; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** *

    Implementation of a Valve that outputs HTML error pages.

    * *

    This Valve should be attached at the Host level, although it will work * if attached to a Context.

    * *

    HTML code from the Cocoon 2 project.

    * * @author Remy Maucherat * @author Craig R. McClanahan * @author Nicola Ken Barozzi Aisa * @author Stefano Mazzocchi * @author Yoav Shapira */ public class ErrorReportValve extends ValveBase { //------------------------------------------------------ Constructor public ErrorReportValve() { super(true); } // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.ErrorReportValve/1.0"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Invoke the next Valve in the sequence. When the invoke returns, check * the response state, and output an error report is necessary. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { // Perform the request getNext().invoke(request, response); if (response.isCommitted()) { return; } Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); if (request.isAsyncStarted() && ((response.getStatus() < 400 && throwable == null) || request.isAsyncDispatching())) { return; } if (throwable != null) { // The response is an error response.setError(); // Reset the response (if possible) try { response.reset(); } catch (IllegalStateException e) { // Ignore } response.sendError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } response.setSuspended(false); try { report(request, response, throwable); } catch (Throwable tt) { ExceptionUtils.handleThrowable(tt); } if (request.isAsyncStarted()) { request.getAsyncContext().complete(); } } // ------------------------------------------------------ Protected Methods /** * Prints out an error report. * * @param request The request being processed * @param response The response being generated * @param throwable The exception that occurred (which possibly wraps * a root cause exception */ protected void report(Request request, Response response, Throwable throwable) { // Do nothing on non-HTTP responses int statusCode = response.getStatus(); // Do nothing on a 1xx, 2xx and 3xx status // Do nothing if anything has been written already if (statusCode < 400 || response.getContentWritten() > 0 || !response.isError()) { return; } String message = RequestUtil.filter(response.getMessage()); if (message == null) { if (throwable != null) { String exceptionMessage = throwable.getMessage(); if (exceptionMessage != null && exceptionMessage.length() > 0) { message = RequestUtil.filter( (new Scanner(exceptionMessage)).nextLine()); } } if (message == null) { message = ""; } } // Do nothing if there is no report for the specified status code and // no error message provided String report = null; StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); response.setLocale(smClient.getLocale()); try { report = smClient.getString("http." + statusCode); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } if (report == null) { if (message.length() == 0) { return; } else { report = smClient.getString("errorReportValve.noDescription"); } } StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(ServerInfo.getServerInfo()).append(" - "); sb.append(smClient.getString("errorReportValve.errorReport")); sb.append(""); sb.append(" "); sb.append(""); sb.append("

    "); sb.append(smClient.getString("errorReportValve.statusHeader", "" + statusCode, message)).append("

    "); sb.append("
    "); sb.append("

    type "); if (throwable != null) { sb.append(smClient.getString("errorReportValve.exceptionReport")); } else { sb.append(smClient.getString("errorReportValve.statusReport")); } sb.append("

    "); sb.append("

    "); sb.append(smClient.getString("errorReportValve.message")); sb.append(" "); sb.append(message).append("

    "); sb.append("

    "); sb.append(smClient.getString("errorReportValve.description")); sb.append(" "); sb.append(report); sb.append("

    "); if (throwable != null) { String stackTrace = getPartialServletStackTrace(throwable); sb.append("

    "); sb.append(smClient.getString("errorReportValve.exception")); sb.append("

    ");
                sb.append(RequestUtil.filter(stackTrace));
                sb.append("

    "); int loops = 0; Throwable rootCause = throwable.getCause(); while (rootCause != null && (loops < 10)) { stackTrace = getPartialServletStackTrace(rootCause); sb.append("

    "); sb.append(smClient.getString("errorReportValve.rootCause")); sb.append("

    ");
                    sb.append(RequestUtil.filter(stackTrace));
                    sb.append("

    "); // In case root cause is somehow heavily nested rootCause = rootCause.getCause(); loops++; } sb.append("

    "); sb.append(smClient.getString("errorReportValve.note")); sb.append(" "); sb.append(smClient.getString("errorReportValve.rootCauseInLogs", ServerInfo.getServerInfo())); sb.append("

    "); } sb.append("
    "); sb.append("

    ").append(ServerInfo.getServerInfo()).append("

    "); sb.append(""); try { try { response.setContentType("text/html"); response.setCharacterEncoding("utf-8"); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (container.getLogger().isDebugEnabled()) { container.getLogger().debug("status.setContentType", t); } } Writer writer = response.getReporter(); if (writer != null) { // If writer is null, it's an indication that the response has // been hard committed already, which should never happen writer.write(sb.toString()); } } catch (IOException e) { // Ignore } catch (IllegalStateException e) { // Ignore } } /** * Print out a partial servlet stack trace (truncating at the last * occurrence of javax.servlet.). */ protected String getPartialServletStackTrace(Throwable t) { StringBuilder trace = new StringBuilder(); trace.append(t.toString()).append('\n'); StackTraceElement[] elements = t.getStackTrace(); int pos = elements.length; for (int i = elements.length - 1; i >= 0; i--) { if ((elements[i].getClassName().startsWith ("org.apache.catalina.core.ApplicationFilterChain")) && (elements[i].getMethodName().equals("internalDoFilter"))) { pos = i; break; } } for (int i = 0; i < pos; i++) { if (!(elements[i].getClassName().startsWith ("org.apache.catalina.core."))) { trace.append('\t').append(elements[i].toString()).append('\n'); } } return trace.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/valves/CometConnectionManagerValve.java0000644000175100017510000003026212271471332027400 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.apache.catalina.Context; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.LifecycleState; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometProcessor; import org.apache.catalina.connector.CometEventImpl; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** *

    Implementation of a Valve that tracks Comet connections, and closes them * when the associated session expires or the webapp is reloaded.

    * *

    This Valve should be attached to a Context.

    * * @author Remy Maucherat */ public class CometConnectionManagerValve extends ValveBase implements HttpSessionListener, LifecycleListener { //------------------------------------------------------ Constructor public CometConnectionManagerValve() { super(false); } // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ protected static final String info = "org.apache.catalina.valves.CometConnectionManagerValve/1.0"; /** * List of current Comet connections. */ protected final List cometRequests = Collections.synchronizedList(new ArrayList()); /** * Name of session attribute used to store list of comet connections. */ protected final String cometRequestsAttribute = "org.apache.tomcat.comet.connectionList"; /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { if (container instanceof Context) { container.addLifecycleListener(this); } setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); if (container instanceof Context) { container.removeLifecycleListener(this); } } @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) { // The container is getting stopped, close all current connections Iterator iterator = cometRequests.iterator(); while (iterator.hasNext()) { Request request = iterator.next(); // Remove the session tracking attribute as it isn't // serializable or required. HttpSession session = request.getSession(false); if (session != null) { session.removeAttribute(cometRequestsAttribute); } // Close the comet connection CometEventImpl cometEvent = request.getEvent(); try { cometEvent.setEventType(CometEvent.EventType.END); cometEvent.setEventSubType( CometEvent.EventSubType.WEBAPP_RELOAD); getNext().event(request, request.getResponse(), cometEvent); } catch (Exception e) { container.getLogger().warn( sm.getString("cometConnectionManagerValve.event"), e); } finally { try { cometEvent.close(); } catch (IOException e) { container.getLogger().warn(sm.getString( "cometConnectionManagerValve.event"), e); } } } cometRequests.clear(); } } // --------------------------------------------------------- Public Methods /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Register requests for tracking, whenever needed. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { // Perform the request getNext().invoke(request, response); if (request.isComet() && !response.isClosed()) { // Start tracking this connection, since this is a // begin event, and Comet mode is on HttpSession session = request.getSession(true); // Track the connection for webapp reload cometRequests.add(request); // Track the connection for session expiration synchronized (session) { Request[] requests = (Request[]) session.getAttribute(cometRequestsAttribute); if (requests == null) { requests = new Request[1]; requests[0] = request; session.setAttribute(cometRequestsAttribute, requests); } else { Request[] newRequests = new Request[requests.length + 1]; for (int i = 0; i < requests.length; i++) { newRequests[i] = requests[i]; } newRequests[requests.length] = request; session.setAttribute(cometRequestsAttribute, newRequests); } } } } /** * Use events to update the connection state. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Perform the request boolean ok = false; try { getNext().event(request, response, event); ok = true; } finally { if (!ok || response.isClosed() || (event.getEventType() == CometEvent.EventType.END) || (event.getEventType() == CometEvent.EventType.ERROR && !(event.getEventSubType() == CometEvent.EventSubType.TIMEOUT))) { // Remove the connection from webapp reload tracking cometRequests.remove(request); // Remove connection from session expiration tracking // Note: can't get the session if it has been invalidated but // OK since session listener will have done clean-up HttpSession session = request.getSession(false); if (session != null) { synchronized (session) { Request[] reqs = null; try { reqs = (Request[]) session.getAttribute(cometRequestsAttribute); } catch (IllegalStateException ise) { // Ignore - session has been invalidated // Listener will have cleaned up } if (reqs != null) { boolean found = false; for (int i = 0; !found && (i < reqs.length); i++) { found = (reqs[i] == request); } if (found) { if (reqs.length > 1) { Request[] newConnectionInfos = new Request[reqs.length - 1]; int pos = 0; for (int i = 0; i < reqs.length; i++) { if (reqs[i] != request) { newConnectionInfos[pos++] = reqs[i]; } } try { session.setAttribute( cometRequestsAttribute, newConnectionInfos); } catch (IllegalStateException ise) { // Ignore - session has been invalidated // Listener will have cleaned up } } else { try { session.removeAttribute( cometRequestsAttribute); } catch (IllegalStateException ise) { // Ignore - session has been invalidated // Listener will have cleaned up } } } } } } } } } @Override public void sessionCreated(HttpSessionEvent se) { // NOOP } @Override public void sessionDestroyed(HttpSessionEvent se) { // Close all Comet connections associated with this session Request[] reqs = (Request[]) se.getSession().getAttribute(cometRequestsAttribute); if (reqs != null) { for (int i = 0; i < reqs.length; i++) { Request req = reqs[i]; try { CometEventImpl event = req.getEvent(); event.setEventType(CometEvent.EventType.END); event.setEventSubType(CometEvent.EventSubType.SESSION_END); ((CometProcessor) req.getWrapper().getServlet()).event(event); event.close(); } catch (Exception e) { req.getWrapper().getParent().getLogger().warn(sm.getString( "cometConnectionManagerValve.listenerEvent"), e); } } } } } tomcat7-7.0.52/java/org/apache/catalina/valves/LocalStrings_ja.properties0000644000175100017510000000420312271471332026345 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. requestFilterValve.next=\u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 requestFilterValve.syntax=\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u30d1\u30bf\u30fc\u30f3 {0} \u306b\u69cb\u6587\u30a8\u30e9\u30fc\u304c\u3042\u308a\u307e\u3059 jdbcAccessLogValve.exception=\u30a2\u30af\u30bb\u30b9\u30a8\u30f3\u30c8\u30ea\u306e\u633f\u5165\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 jdbcAccessLogValve.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 # Error report valve valveBase.noNext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 errorReportValve.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1} errorReportValve.exceptionReport=\u4f8b\u5916\u30ec\u30dd\u30fc\u30c8 errorReportValve.statusReport=\u30b9\u30c6\u30fc\u30bf\u30b9\u30ec\u30dd\u30fc\u30c8 errorReportValve.message=\u30e1\u30c3\u30bb\u30fc\u30b8 errorReportValve.description=\u8aac\u660e errorReportValve.exception=\u4f8b\u5916 errorReportValve.rootCause=\u539f\u56e0 errorReportValve.note=\u6ce8\u610f errorReportValve.rootCauseInLogs=\u539f\u56e0\u306e\u3059\u3079\u3066\u306e\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9\u306f\u3001{0}\u306e\u30ed\u30b0\u306b\u8a18\u9332\u3055\u308c\u3066\u3044\u307e\u3059 tomcat7-7.0.52/java/org/apache/catalina/valves/StuckThreadDetectionValve.java0000644000175100017510000002553712271471332027107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.ServletException; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * This valve allows to detect requests that take a long time to process, which * might indicate that the thread that is processing it is stuck. */ public class StuckThreadDetectionValve extends ValveBase { /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.StuckThreadDetectionValve/1.0"; /** * Logger */ private static final Log log = LogFactory.getLog(StuckThreadDetectionValve.class); /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * Keeps count of the number of stuck threads detected */ private final AtomicInteger stuckCount = new AtomicInteger(0); /** * In seconds. Default 600 (10 minutes). */ private int threshold = 600; /** * The only references we keep to actual running Thread objects are in * this Map (which is automatically cleaned in invoke()s finally clause). * That way, Threads can be GC'ed, eventhough the Valve still thinks they * are stuck (caused by a long monitor interval) */ private final ConcurrentHashMap activeThreads = new ConcurrentHashMap(); /** * */ private final Queue completedStuckThreadsQueue = new ConcurrentLinkedQueue(); /** * Specify the threshold (in seconds) used when checking for stuck threads. * If <=0, the detection is disabled. The default is 600 seconds. * * @param threshold * The new threshold in seconds */ public void setThreshold(int threshold) { this.threshold = threshold; } /** * @see #setThreshold(int) * @return The current threshold in seconds */ public int getThreshold() { return threshold; } /** * Required to enable async support. */ public StuckThreadDetectionValve() { super(true); } @Override protected void initInternal() throws LifecycleException { super.initInternal(); if (log.isDebugEnabled()) { log.debug("Monitoring stuck threads with threshold = " + threshold + " sec"); } } /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return info; } private void notifyStuckThreadDetected(MonitoredThread monitoredThread, long activeTime, int numStuckThreads) { if (log.isWarnEnabled()) { String msg = sm.getString( "stuckThreadDetectionValve.notifyStuckThreadDetected", monitoredThread.getThread().getName(), Long.valueOf(activeTime), monitoredThread.getStartTime(), Integer.valueOf(numStuckThreads), monitoredThread.getRequestUri(), Integer.valueOf(threshold), String.valueOf(monitoredThread.getThread().getId()) ); // msg += "\n" + getStackTraceAsString(trace); Throwable th = new Throwable(); th.setStackTrace(monitoredThread.getThread().getStackTrace()); log.warn(msg, th); } } private void notifyStuckThreadCompleted(CompletedStuckThread thread, int numStuckThreads) { if (log.isWarnEnabled()) { String msg = sm.getString( "stuckThreadDetectionValve.notifyStuckThreadCompleted", thread.getName(), Long.valueOf(thread.getTotalActiveTime()), Integer.valueOf(numStuckThreads), String.valueOf(thread.getId())); // Since the "stuck thread notification" is warn, this should also // be warn log.warn(msg); } } /** * {@inheritDoc} */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { if (threshold <= 0) { // short-circuit if not monitoring stuck threads getNext().invoke(request, response); return; } // Save the thread/runnable // Keeping a reference to the thread object here does not prevent // GC'ing, as the reference is removed from the Map in the finally clause Long key = Long.valueOf(Thread.currentThread().getId()); StringBuffer requestUrl = request.getRequestURL(); if(request.getQueryString()!=null) { requestUrl.append("?"); requestUrl.append(request.getQueryString()); } MonitoredThread monitoredThread = new MonitoredThread(Thread.currentThread(), requestUrl.toString()); activeThreads.put(key, monitoredThread); try { getNext().invoke(request, response); } finally { activeThreads.remove(key); if (monitoredThread.markAsDone() == MonitoredThreadState.STUCK) { completedStuckThreadsQueue.add( new CompletedStuckThread(monitoredThread.getThread(), monitoredThread.getActiveTimeInMillis())); } } } @Override public void backgroundProcess() { super.backgroundProcess(); long thresholdInMillis = threshold * 1000; // Check monitored threads, being careful that the request might have // completed by the time we examine it for (MonitoredThread monitoredThread : activeThreads.values()) { long activeTime = monitoredThread.getActiveTimeInMillis(); if (activeTime >= thresholdInMillis && monitoredThread.markAsStuckIfStillRunning()) { int numStuckThreads = stuckCount.incrementAndGet(); notifyStuckThreadDetected(monitoredThread, activeTime, numStuckThreads); } } // Check if any threads previously reported as stuck, have finished. for (CompletedStuckThread completedStuckThread = completedStuckThreadsQueue.poll(); completedStuckThread != null; completedStuckThread = completedStuckThreadsQueue.poll()) { int numStuckThreads = stuckCount.decrementAndGet(); notifyStuckThreadCompleted(completedStuckThread, numStuckThreads); } } public long[] getStuckThreadIds() { List idList = new ArrayList(); for (MonitoredThread monitoredThread : activeThreads.values()) { if (monitoredThread.isMarkedAsStuck()) { idList.add(Long.valueOf(monitoredThread.getThread().getId())); } } long[] result = new long[idList.size()]; for (int i = 0; i < result.length; i++) { result[i] = idList.get(i).longValue(); } return result; } public String[] getStuckThreadNames() { List nameList = new ArrayList(); for (MonitoredThread monitoredThread : activeThreads.values()) { if (monitoredThread.isMarkedAsStuck()) { nameList.add(monitoredThread.getThread().getName()); } } return nameList.toArray(new String[nameList.size()]); } private static class MonitoredThread { /** * Reference to the thread to get a stack trace from background task */ private final Thread thread; private final String requestUri; private final long start; private final AtomicInteger state = new AtomicInteger( MonitoredThreadState.RUNNING.ordinal()); public MonitoredThread(Thread thread, String requestUri) { this.thread = thread; this.requestUri = requestUri; this.start = System.currentTimeMillis(); } public Thread getThread() { return this.thread; } public String getRequestUri() { return requestUri; } public long getActiveTimeInMillis() { return System.currentTimeMillis() - start; } public Date getStartTime() { return new Date(start); } public boolean markAsStuckIfStillRunning() { return this.state.compareAndSet(MonitoredThreadState.RUNNING.ordinal(), MonitoredThreadState.STUCK.ordinal()); } public MonitoredThreadState markAsDone() { int val = this.state.getAndSet(MonitoredThreadState.DONE.ordinal()); return MonitoredThreadState.values()[val]; } boolean isMarkedAsStuck() { return this.state.get() == MonitoredThreadState.STUCK.ordinal(); } } private static class CompletedStuckThread { private final String threadName; private final long threadId; private final long totalActiveTime; public CompletedStuckThread(Thread thread, long totalActiveTime) { this.threadName = thread.getName(); this.threadId = thread.getId(); this.totalActiveTime = totalActiveTime; } public String getName() { return this.threadName; } public long getId() { return this.threadId; } public long getTotalActiveTime() { return this.totalActiveTime; } } private enum MonitoredThreadState { RUNNING, STUCK, DONE; } } tomcat7-7.0.52/java/org/apache/catalina/valves/LocalStrings_fr.properties0000644000175100017510000001405512271471332026370 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. requestFilterValve.next=Aucune Valve ''suivante'' n''a \u00e9t\u00e9 configur\u00e9e requestFilterValve.syntax=Erreur de syntaxe dans le pattern de filtre de requ\u00eate {0} valveBase.noNext=Erreur de configuration: aucune Valve ''suivante'' n''a \u00e9t\u00e9 configur\u00e9e # Error report valve errorReportValve.errorReport=Rapport d''erreur errorReportValve.statusHeader=Etat HTTP {0} - {1} errorReportValve.exceptionReport=Rapport d''exception errorReportValve.statusReport=Rapport d''\u00e9tat errorReportValve.message=message errorReportValve.description=description errorReportValve.exception=exception errorReportValve.rootCause=cause m\u00e8re errorReportValve.note=note errorReportValve.rootCauseInLogs=La trace compl\u00e8te de la cause m\u00e8re de cette erreur est disponible dans les fichiers journaux de {0}. # HTTP status reports http.100=Le client peut continuer. http.101=Le serveur change de protocoles suivant la directive "Upgrade" de l''ent\u00eate. http.201=La requ\u00eate a r\u00e9ussi et une nouvelle ressource a \u00e9t\u00e9 cr\u00e9\u00e9e sur le serveur. http.202=La requ\u00eate a \u00e9t\u00e9 accept\u00e9e pour traitement, mais n''a pas \u00e9t\u00e9 termin\u00e9e. http.203=L''information meta pr\u00e9sent\u00e9e par le client n''a pas pour origine ce serveur. http.204=La requ\u00eate a r\u00e9ussi mais il n''y a aucune information \u00e0 retourner. http.205=Le client doit remettre \u00e0 z\u00e9ro la vue de document qui a caus\u00e9 l''envoi de cette requ\u00eate. http.206=Le serveur a satisfait une requ\u00eate GET partielle pour cette ressource. http.207=Plusieurs valeurs d''\u00e9tats ont \u00e9t\u00e9 retourn\u00e9es. http.300=La ressource demand\u00e9e correspond \u00e0 plusieurs repr\u00e9sentations, chacune avec sa propre localisation. http.301=La ressource demand\u00e9e a \u00e9t\u00e9 d\u00e9plac\u00e9e de fa\u00e7on permanente vers une nouvelle localisation. http.302=La ressource demand\u00e9e a \u00e9t\u00e9 d\u00e9plac\u00e9e de fa\u00e7on temporaire vers une nouvelle localisation. http.303=La r\u00e9ponse \u00e0 cette requ\u00eate peut \u00eatre trouv\u00e9e \u00e0 une URI diff\u00e9rente. http.304=La ressource demand\u00e9e est disponible et n''a pas \u00e9t\u00e9 modifi\u00e9e. http.305=La ressource demand\u00e9e doit \u00eatre acc\u00e9d\u00e9e au travers du relais indiqu\u00e9 par la directive "Location" de l''ent\u00eate. http.400=La requ\u00eate envoy\u00e9e par le client \u00e9tait syntaxiquement incorrecte. http.401=La requ\u00eate n\u00e9cessite une authentification HTTP. http.402=Un paiement est demand\u00e9 pour acc\u00e9der \u00e0 cette ressource. http.403=L''acc\u00e8s \u00e0 la ressource demand\u00e9e a \u00e9t\u00e9 interdit. http.404=La ressource demand\u00e9e n''est pas disponible. http.405=La m\u00e9thode HTTP sp\u00e9cifi\u00e9e n''est pas autoris\u00e9e pour la ressource demand\u00e9e. http.406=La ressource identifi\u00e9e par cette requ\u00eate n''est capable de g\u00e9n\u00e9rer des r\u00e9ponses qu''avec des caract\u00e9ristiques incompatible avec la directive "accept" pr\u00e9sente dans l''ent\u00eate de requ\u00eate. http.407=Le client doit d''abord s''authentifier aupr\u00e8s du relais. http.408=Le client n''a pas produit de requ\u00eate pendant le temps d''attente du serveur. http.409=La requ\u00eate ne peut \u00eatre finalis\u00e9e suite \u00e0 un conflit li\u00e9 \u00e0 l''\u00e9tat de la ressource. http.410=La ressource demand\u00e9e n''est pas disponible, et aucune addresse de rebond (forwarding) n''est connue. http.411=La requ\u00eate ne peut \u00eatre trait\u00e9e sans d\u00e9finition d''une taille de contenu (content length). http.412=Une condition pr\u00e9alable demand\u00e9e n''est pas satisfaite pour cette requ\u00eate. http.413=L''entit\u00e9 de requ\u00eate est plus importante que ce que le serveur veut ou peut traiter. http.414=Le serveur a refus\u00e9 cette requ\u00eate car l''URI de requ\u00eate est trop longue. http.415=Le serveur a refus\u00e9 cette requ\u00eate car l''entit\u00e9 de requ\u00eate est dans un format non support\u00e9 par la ressource demand\u00e9e avec la m\u00e9thode sp\u00e9cifi\u00e9e. http.416=La plage d''octets demand\u00e9e (byte range) ne peut \u00eatre satisfaite. http.417=L''attente indiqu\u00e9e dans la directive "Expect" de l''ent\u00eate de requ\u00eate ne peut \u00eatre satisfaite. http.422=Le serveur a compris le type de contenu (content type) ainsi que la syntaxe de la requ\u00eate mais a \u00e9t\u00e9 incapable de traiter les instructions contenues. http.423=La ressource source ou destination de la m\u00e9thode est verrouill\u00e9e. http.500=Le serveur a rencontr\u00e9 une erreur interne qui l''a emp\u00each\u00e9 de satisfaire la requ\u00eate. http.501=Le serveur ne supporte pas la fonctionnalit\u00e9 demand\u00e9e pour satisfaire cette requ\u00eate. http.502=Le serveur a re\u00e7u une r\u00e9ponse invalide d''un serveur qu''il consultait en tant que relais ou passerelle. http.503=Le service demand\u00e9 n''est pas disponible actuellement. http.504=Le serveur a re\u00e7u un d\u00e9passement de delai (timeout) d''un serveur amont qu''il consultait en tant que relais ou passerelle. http.505=Le serveur ne supporte pas la version demand\u00e9e du protocole HTTP. http.507=L''espace disponible est insuffisant pour enregistrer l''\u00e9tat de la ressource apr\u00e8s ex\u00e9cution de cette m\u00e9thode. tomcat7-7.0.52/java/org/apache/catalina/valves/RequestFilterValve.java0000644000175100017510000002557012271471332025622 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** * Implementation of a Valve that performs filtering based on comparing the * appropriate request property (selected based on which subclass you choose * to configure into your Container's pipeline) against the regular expressions * configured for this Valve. *

    * This valve is configured by setting the allow and/or * deny properties to a regular expressions (in the syntax * supported by {@link Pattern}) to which the appropriate request property will * be compared. Evaluation proceeds as follows: *

      *
    • The subclass extracts the request property to be filtered, and * calls the common process() method. *
    • If there is a deny expression configured, the property will be compared * to the expression. If a match is found, this request will be rejected * with a "Forbidden" HTTP response.
    • *
    • If there is a allow expression configured, the property will be compared * to each such expression. If a match is found, this request will be * allowed to pass through to the next Valve in the current pipeline.
    • *
    • If a deny expression was specified but no allow expression, allow this * request to pass through (because none of the deny expressions matched * it). *
    • The request will be rejected with a "Forbidden" HTTP response.
    • *
    *

    * This Valve may be attached to any Container, depending on the granularity * of the filtering you wish to perform. * * @author Craig R. McClanahan */ public abstract class RequestFilterValve extends ValveBase { //------------------------------------------------------ Constructor public RequestFilterValve() { super(true); } // ----------------------------------------------------- Class Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.RequestFilterValve/1.0"; // ----------------------------------------------------- Instance Variables /** * The regular expression used to test for allowed requests. */ protected volatile Pattern allow = null; /** * The current allow configuration value that may or may not compile into a * valid {@link Pattern}. */ protected volatile String allowValue = null; /** * Helper variable to catch configuration errors. * It is true by default, but becomes false * if there was an attempt to assign an invalid value to the * allow pattern. */ protected volatile boolean allowValid = true; /** * The regular expression used to test for denied requests. */ protected volatile Pattern deny = null; /** * The current deny configuration value that may or may not compile into a * valid {@link Pattern}. */ protected volatile String denyValue = null; /** * Helper variable to catch configuration errors. * It is true by default, but becomes false * if there was an attempt to assign an invalid value to the * deny pattern. */ protected volatile boolean denyValid = true; /** * The HTTP response status code that is used when rejecting denied * request. It is 403 by default, but may be changed to be 404. */ protected int denyStatus = HttpServletResponse.SC_FORBIDDEN; // ------------------------------------------------------------- Properties /** * Return the regular expression used to test for allowed requests for this * Valve, if any; otherwise, return null. */ public String getAllow() { return allowValue; } /** * Set the regular expression used to test for allowed requests for this * Valve, if any. * * @param allow The new allow expression */ public void setAllow(String allow) { if (allow == null || allow.length() == 0) { this.allow = null; allowValue = null; allowValid = true; } else { boolean success = false; try { allowValue = allow; this.allow = Pattern.compile(allow); success = true; } finally { allowValid = success; } } } /** * Return the regular expression used to test for denied requests for this * Valve, if any; otherwise, return null. */ public String getDeny() { return denyValue; } /** * Set the regular expression used to test for denied requests for this * Valve, if any. * * @param deny The new deny expression */ public void setDeny(String deny) { if (deny == null || deny.length() == 0) { this.deny = null; denyValue = null; denyValid = true; } else { boolean success = false; try { denyValue = deny; this.deny = Pattern.compile(deny); success = true; } finally { denyValid = success; } } } /** * Returns {@code false} if the last change to the {@code allow} pattern did * not apply successfully. E.g. if the pattern is syntactically * invalid. */ public final boolean isAllowValid() { return allowValid; } /** * Returns {@code false} if the last change to the {@code deny} pattern did * not apply successfully. E.g. if the pattern is syntactically * invalid. */ public final boolean isDenyValid() { return denyValid; } /** * Return response status code that is used to reject denied request. */ public int getDenyStatus() { return denyStatus; } /** * Set response status code that is used to reject denied request. */ public void setDenyStatus(int denyStatus) { this.denyStatus = denyStatus; } /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Extract the desired request property, and pass it (along with the * specified request and response objects) to the protected * process() method to perform the actual filtering. * This method must be implemented by a concrete subclass. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public abstract void invoke(Request request, Response response) throws IOException, ServletException; // ------------------------------------------------------ Protected Methods @Override protected void initInternal() throws LifecycleException { super.initInternal(); if (!allowValid || !denyValid) { throw new LifecycleException( sm.getString("requestFilterValve.configInvalid")); } } @Override protected synchronized void startInternal() throws LifecycleException { if (!allowValid || !denyValid) { throw new LifecycleException( sm.getString("requestFilterValve.configInvalid")); } super.startInternal(); } /** * Perform the filtering that has been configured for this Valve, matching * against the specified request property. * * @param property The request property on which to filter * @param request The servlet request to be processed * @param response The servlet response to be processed * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ protected void process(String property, Request request, Response response) throws IOException, ServletException { if (isAllowed(property)) { getNext().invoke(request, response); return; } // Deny this request denyRequest(request, response); } /** * Reject the request that was denied by this valve. * * @param request The servlet request to be processed * @param response The servlet response to be processed * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ protected void denyRequest(Request request, Response response) throws IOException, ServletException { response.sendError(denyStatus); } /** * Perform the test implemented by this Valve, matching against the * specified request property value. This method is public so that it can be * called through JMX, e.g. to test whether certain IP address is allowed or * denied by the valve configuration. * * @param property * The request property value on which to filter */ public boolean isAllowed(String property) { // Use local copies for thread safety Pattern deny = this.deny; Pattern allow = this.allow; // Check the deny patterns, if any if (deny != null && deny.matcher(property).matches()) { return false; } // Check the allow patterns, if any if (allow != null && allow.matcher(property).matches()) { return true; } // Allow if denies specified but not allows if (deny != null && allow == null) { return true; } // Deny this request return false; } } tomcat7-7.0.52/java/org/apache/catalina/valves/RemoteHostValve.java0000644000175100017510000000501512271471332025105 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.IOException; import javax.servlet.ServletException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** * Concrete implementation of RequestFilterValve that filters * based on the remote client's host name. * * @author Craig R. McClanahan */ public final class RemoteHostValve extends RequestFilterValve { // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.valves.RemoteHostValve/1.0"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Extract the desired request property, and pass it (along with the * specified request and response objects) to the protected * process() method to perform the actual filtering. * This method must be implemented by a concrete subclass. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { process(request.getRequest().getRemoteHost(), request, response); } } tomcat7-7.0.52/java/org/apache/catalina/valves/SSLValve.java0000644000175100017510000001315312271471332023457 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.valves; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.Charset; import java.security.NoSuchProviderException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import javax.servlet.ServletException; import org.apache.catalina.Globals; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * When using mod_proxy_http, the client SSL information is not included in the * protocol (unlike mod_jk and mod_proxy_ajp). To make the client SSL * information available to Tomcat, some additional configuration is required. * In httpd, mod_headers is used to add the SSL information as HTTP headers. In * Tomcat, this valve is used to read the information from the HTTP headers and * insert it into the request.

    * * Note: Ensure that the headers are always set by httpd for all requests to * prevent a client spoofing SSL information by sending fake headers.

    * * In httpd.conf add the following: *

     * <IfModule ssl_module>
     *   RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"
     *   RequestHeader set SSL_CIPHER "%{SSL_CIPHER}s"
     *   RequestHeader set SSL_SESSION_ID "%{SSL_SESSION_ID}s"
     *   RequestHeader set SSL_CIPHER_USEKEYSIZE "%{SSL_CIPHER_USEKEYSIZE}s"
     * </IfModule>
     * 
    * * In server.xml, configure this valve under the Engine element in server.xml: *
     * <Engine ...>
     *   <Valve className="org.apache.catalina.valves.SSLValve" />
     *   <Host ... />
     * </Engine>
     * 
    */ public class SSLValve extends ValveBase { private static final Log log = LogFactory.getLog(SSLValve.class); //------------------------------------------------------ Constructor public SSLValve() { super(true); } public String mygetHeader(Request request, String header) { String strcert0 = request.getHeader(header); if (strcert0 == null) { return null; } /* mod_header writes "(null)" when the ssl variable is no filled */ if ("(null)".equals(strcert0)) { return null; } return strcert0; } @Override public void invoke(Request request, Response response) throws IOException, ServletException { /* mod_header converts the '\n' into ' ' so we have to rebuild the client certificate */ String strcert0 = mygetHeader(request, "ssl_client_cert"); if (strcert0 != null && strcert0.length()>28) { String strcert1 = strcert0.replace(' ', '\n'); String strcert2 = strcert1.substring(28, strcert1.length()-26); String strcert3 = "-----BEGIN CERTIFICATE-----\n"; String strcert4 = strcert3.concat(strcert2); String strcerts = strcert4.concat("\n-----END CERTIFICATE-----\n"); // ByteArrayInputStream bais = new ByteArrayInputStream(strcerts.getBytes("UTF-8")); ByteArrayInputStream bais = new ByteArrayInputStream( strcerts.getBytes(Charset.defaultCharset())); X509Certificate jsseCerts[] = null; String providerName = (String) request.getConnector().getProperty( "clientCertProvider"); try { CertificateFactory cf; if (providerName == null) { cf = CertificateFactory.getInstance("X.509"); } else { cf = CertificateFactory.getInstance("X.509", providerName); } X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); jsseCerts = new X509Certificate[1]; jsseCerts[0] = cert; } catch (java.security.cert.CertificateException e) { log.warn(sm.getString("sslValve.certError", strcerts), e); } catch (NoSuchProviderException e) { log.error(sm.getString( "sslValve.invalidProvider", providerName), e); } request.setAttribute(Globals.CERTIFICATES_ATTR, jsseCerts); } strcert0 = mygetHeader(request, "ssl_cipher"); if (strcert0 != null) { request.setAttribute(Globals.CIPHER_SUITE_ATTR, strcert0); } strcert0 = mygetHeader(request, "ssl_session_id"); if (strcert0 != null) { request.setAttribute(Globals.SSL_SESSION_ID_ATTR, strcert0); request.setAttribute(Globals.SSL_SESSION_ID_TOMCAT_ATTR, strcert0); } strcert0 = mygetHeader(request, "ssl_cipher_usekeysize"); if (strcert0 != null) { request.setAttribute(Globals.KEY_SIZE_ATTR, Integer.valueOf(strcert0)); } getNext().invoke(request, response); } } tomcat7-7.0.52/java/org/apache/catalina/Context.java0000644000175100017510000013465612271471332022160 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.net.URL; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletRequest; import javax.servlet.ServletSecurityElement; import javax.servlet.descriptor.JspConfigDescriptor; import org.apache.catalina.core.ApplicationServletRegistration; import org.apache.catalina.deploy.ApplicationListener; import org.apache.catalina.deploy.ApplicationParameter; import org.apache.catalina.deploy.ErrorPage; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.deploy.NamingResources; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.catalina.util.CharsetMapper; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.JarScanner; import org.apache.tomcat.util.http.mapper.Mapper; /** * A Context is a Container that represents a servlet context, and * therefore an individual web application, in the Catalina servlet engine. * It is therefore useful in almost every deployment of Catalina (even if a * Connector attached to a web server (such as Apache) uses the web server's * facilities to identify the appropriate Wrapper to handle this request. * It also provides a convenient mechanism to use Interceptors that see * every request processed by this particular web application. *

    * The parent Container attached to a Context is generally a Host, but may * be some other implementation, or may be omitted if it is not necessary. *

    * The child containers attached to a Context are generally implementations * of Wrapper (representing individual servlet definitions). *

    * * @author Craig R. McClanahan */ public interface Context extends Container { // ----------------------------------------------------- Manifest Constants /** * The LifecycleEvent type sent when a context is reloaded. * @deprecated Will be removed in Tomcat 8.0.x onwards. */ @Deprecated public static final String RELOAD_EVENT = "reload"; /** * Container event for adding a welcome file. */ public static final String ADD_WELCOME_FILE_EVENT = "addWelcomeFile"; /** * Container event for removing a wrapper. */ public static final String REMOVE_WELCOME_FILE_EVENT = "removeWelcomeFile"; /** * Container event for clearing welcome files. */ public static final String CLEAR_WELCOME_FILES_EVENT = "clearWelcomeFiles"; /** * Container event for changing the ID of a session. */ public static final String CHANGE_SESSION_ID_EVENT = "changeSessionId"; // ------------------------------------------------------------- Properties /** * Returns true if requests mapped to servlets without * "multipart config" to parse multipart/form-data requests anyway. * * @return true if requests mapped to servlets without * "multipart config" to parse multipart/form-data requests, * false otherwise. */ public boolean getAllowCasualMultipartParsing(); /** * Set to true to allow requests mapped to servlets that * do not explicitly declare @MultipartConfig or have * <multipart-config> specified in web.xml to parse * multipart/form-data requests. * * @param allowCasualMultipartParsing true to allow such * casual parsing, false otherwise. */ public void setAllowCasualMultipartParsing(boolean allowCasualMultipartParsing); /** * Return the set of initialized application event listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @exception IllegalStateException if this method is called before * this application has started, or after it has been stopped */ public Object[] getApplicationEventListeners(); /** * Store the set of initialized application event listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @param listeners The set of instantiated listener objects. */ public void setApplicationEventListeners(Object listeners[]); /** * Return the set of initialized application lifecycle listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @exception IllegalStateException if this method is called before * this application has started, or after it has been stopped */ public Object[] getApplicationLifecycleListeners(); /** * Store the set of initialized application lifecycle listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @param listeners The set of instantiated listener objects. */ public void setApplicationLifecycleListeners(Object listeners[]); /** * Return the application available flag for this Context. * * @deprecated This will be removed in Tomcat 8.0.x onwards. Use * {@link #getState()}.{@link LifecycleState#isAvailable() * isAvailable()} instead */ @Deprecated public boolean getAvailable(); /** * Return the Locale to character set mapper for this Context. * @deprecated Use {@link #getCharset(Locale)} */ @Deprecated public CharsetMapper getCharsetMapper(); /** * Set the Locale to character set mapper for this Context. * * @param mapper The new mapper * * @deprecated */ @Deprecated public void setCharsetMapper(CharsetMapper mapper); /** * Obtain the character set name to use with the given Locale. Note that * different Contexts may have different mappings of Locale to character * set. */ public String getCharset(Locale locale); /** * Return the URL of the XML descriptor for this context. */ public URL getConfigFile(); /** * Set the URL of the XML descriptor for this context. * * @param configFile The URL of the XML descriptor for this context. */ public void setConfigFile(URL configFile); /** * Return the "correctly configured" flag for this Context. */ public boolean getConfigured(); /** * Set the "correctly configured" flag for this Context. This can be * set to false by startup listeners that detect a fatal configuration * error to avoid the application from being made available. * * @param configured The new correctly configured flag */ public void setConfigured(boolean configured); /** * Return the "use cookies for session ids" flag. */ public boolean getCookies(); /** * Set the "use cookies for session ids" flag. * * @param cookies The new flag */ public void setCookies(boolean cookies); /** * Gets the name to use for session cookies. Overrides any setting that * may be specified by the application. * * @return The value of the default session cookie name or null if not * specified */ public String getSessionCookieName(); /** * Sets the name to use for session cookies. Overrides any setting that * may be specified by the application. * * @param sessionCookieName The name to use */ public void setSessionCookieName(String sessionCookieName); /** * Gets the value of the use HttpOnly cookies for session cookies flag. * * @return true if the HttpOnly flag should be set on session * cookies */ public boolean getUseHttpOnly(); /** * Sets the use HttpOnly cookies for session cookies flag. * * @param useHttpOnly Set to true to use HttpOnly cookies * for session cookies */ public void setUseHttpOnly(boolean useHttpOnly); /** * Gets the domain to use for session cookies. Overrides any setting that * may be specified by the application. * * @return The value of the default session cookie domain or null if not * specified */ public String getSessionCookieDomain(); /** * Sets the domain to use for session cookies. Overrides any setting that * may be specified by the application. * * @param sessionCookieDomain The domain to use */ public void setSessionCookieDomain(String sessionCookieDomain); /** * Gets the path to use for session cookies. Overrides any setting that * may be specified by the application. * * @return The value of the default session cookie path or null if not * specified */ public String getSessionCookiePath(); /** * Sets the path to use for session cookies. Overrides any setting that * may be specified by the application. * * @param sessionCookiePath The path to use */ public void setSessionCookiePath(String sessionCookiePath); /** * Is a / added to the end of the session cookie path to ensure browsers, * particularly IE, don't send a session cookie for context /foo with * requests intended for context /foobar. * * @return true if the slash is added, otherwise * false */ public boolean getSessionCookiePathUsesTrailingSlash(); /** * Configures if a / is added to the end of the session cookie path to * ensure browsers, particularly IE, don't send a session cookie for context * /foo with requests intended for context /foobar. * * @param sessionCookiePathUsesTrailingSlash true if the * slash is should be added, * otherwise false */ public void setSessionCookiePathUsesTrailingSlash( boolean sessionCookiePathUsesTrailingSlash); /** * Return the "allow crossing servlet contexts" flag. */ public boolean getCrossContext(); /** * Return the alternate Deployment Descriptor name. */ public String getAltDDName(); /** * Set an alternate Deployment Descriptor name. */ public void setAltDDName(String altDDName) ; /** * Set the "allow crossing servlet contexts" flag. * * @param crossContext The new cross contexts flag */ public void setCrossContext(boolean crossContext); /** * Return the display name of this web application. */ public String getDisplayName(); /** * Set the display name of this web application. * * @param displayName The new display name */ public void setDisplayName(String displayName); /** * Return the distributable flag for this web application. */ public boolean getDistributable(); /** * Set the distributable flag for this web application. * * @param distributable The new distributable flag */ public void setDistributable(boolean distributable); /** * Return the document root for this Context. This can be an absolute * pathname, a relative pathname, or a URL. */ public String getDocBase(); /** * Set the document root for this Context. This can be an absolute * pathname, a relative pathname, or a URL. * * @param docBase The new document root */ public void setDocBase(String docBase); /** * Return the URL encoded context path, using UTF-8. */ public String getEncodedPath(); /** * Return the boolean on the annotations parsing. */ public boolean getIgnoreAnnotations(); /** * Set the boolean on the annotations parsing for this web * application. * * @param ignoreAnnotations The boolean on the annotations parsing */ public void setIgnoreAnnotations(boolean ignoreAnnotations); /** * Return the login configuration descriptor for this web application. */ public LoginConfig getLoginConfig(); /** * Set the login configuration descriptor for this web application. * * @param config The new login configuration */ public void setLoginConfig(LoginConfig config); /** * Get the request dispatcher mapper. */ public Mapper getMapper(); /** * Return the naming resources associated with this web application. */ public NamingResources getNamingResources(); /** * Set the naming resources for this web application. * * @param namingResources The new naming resources */ public void setNamingResources(NamingResources namingResources); /** * Return the context path for this web application. */ public String getPath(); /** * Set the context path for this web application. * * @param path The new context path */ public void setPath(String path); /** * Return the public identifier of the deployment descriptor DTD that is * currently being parsed. */ public String getPublicId(); /** * Set the public identifier of the deployment descriptor DTD that is * currently being parsed. * * @param publicId The public identifier */ public void setPublicId(String publicId); /** * Return the reloadable flag for this web application. */ public boolean getReloadable(); /** * Set the reloadable flag for this web application. * * @param reloadable The new reloadable flag */ public void setReloadable(boolean reloadable); /** * Return the override flag for this web application. */ public boolean getOverride(); /** * Set the override flag for this web application. * * @param override The new override flag */ public void setOverride(boolean override); /** * Return the privileged flag for this web application. */ public boolean getPrivileged(); /** * Set the privileged flag for this web application. * * @param privileged The new privileged flag */ public void setPrivileged(boolean privileged); /** * Return the servlet context for which this Context is a facade. */ public ServletContext getServletContext(); /** * Return the default session timeout (in minutes) for this * web application. */ public int getSessionTimeout(); /** * Set the default session timeout (in minutes) for this * web application. * * @param timeout The new default session timeout */ public void setSessionTimeout(int timeout); /** * Returns true if remaining request data will be read * (swallowed) even the request violates a data size constraint. * * @return true if data will be swallowed (default), * false otherwise. */ public boolean getSwallowAbortedUploads(); /** * Set to false to disable request data swallowing * after an upload was aborted due to size constraints. * * @param swallowAbortedUploads false to disable * swallowing, true otherwise (default). */ public void setSwallowAbortedUploads(boolean swallowAbortedUploads); /** * Return the value of the swallowOutput flag. */ public boolean getSwallowOutput(); /** * Set the value of the swallowOutput flag. If set to true, the system.out * and system.err will be redirected to the logger during a servlet * execution. * * @param swallowOutput The new value */ public void setSwallowOutput(boolean swallowOutput); /** * Return the Java class name of the Wrapper implementation used * for servlets registered in this Context. */ public String getWrapperClass(); /** * Set the Java class name of the Wrapper implementation used * for servlets registered in this Context. * * @param wrapperClass The new wrapper class */ public void setWrapperClass(String wrapperClass); /** * Will the parsing of web.xml and web-fragment.xml files for this Context * be performed by a namespace aware parser? * * @return true if namespace awareness is enabled. */ public boolean getXmlNamespaceAware(); /** * Controls whether the parsing of web.xml and web-fragment.xml files for * this Context will be performed by a namespace aware parser. * * @param xmlNamespaceAware true to enable namespace awareness */ public void setXmlNamespaceAware(boolean xmlNamespaceAware); /** * Will the parsing of web.xml and web-fragment.xml files for this Context * be performed by a validating parser? * * @return true if validation is enabled. */ public boolean getXmlValidation(); /** * Controls whether the parsing of web.xml and web-fragment.xml files * for this Context will be performed by a validating parser. * * @param xmlValidation true to enable xml validation */ public void setXmlValidation(boolean xmlValidation); /** * *.tld files are always parsed using a namespace aware parser. * * @return Always true * * @deprecated This option will be removed in 8.0.x. */ @Deprecated public boolean getTldNamespaceAware(); /** * *.tld files are always parsed using a namespace aware parser. * * @param tldNamespaceAware ignored * * @deprecated This option will be removed in 8.0.x. */ @Deprecated public void setTldNamespaceAware(boolean tldNamespaceAware); /** * Will the parsing of web.xml, web-fragment.xml, *.tld, *.jspx, *.tagx and * tagplugin.xml files for this Context block the use of external entities? * * @return true if access to external entities is blocked */ public boolean getXmlBlockExternal(); /** * Controls whether the parsing of web.xml, web-fragment.xml, *.tld, *.jspx, * *.tagx and tagplugin.xml files for this Context will block the use of * external entities. * * @param xmlBlockExternal true to block external entities */ public void setXmlBlockExternal(boolean xmlBlockExternal); /** * Will the parsing of *.tld files for this Context be performed by a * validating parser? * * @return true if validation is enabled. */ public boolean getTldValidation(); /** * Controls whether the parsing of *.tld files for this Context will be * performed by a validating parser. * * @param tldValidation true to enable xml validation */ public void setTldValidation(boolean tldValidation); /** * Get the Jar Scanner to be used to scan for JAR resources for this * context. * @return The Jar Scanner configured for this context. */ public JarScanner getJarScanner(); /** * Set the Jar Scanner to be used to scan for JAR resources for this * context. * @param jarScanner The Jar Scanner to be used for this context. */ public void setJarScanner(JarScanner jarScanner); /** * Obtain the {@link Authenticator} that is used by this context or * null if none is used. */ public Authenticator getAuthenticator(); /** * Set whether or not the effective web.xml for this context should be * logged on context start. */ public void setLogEffectiveWebXml(boolean logEffectiveWebXml); /** * Should the effective web.xml for this context be logged on context start? */ public boolean getLogEffectiveWebXml(); /** * Get the instance manager associated with this context. */ public InstanceManager getInstanceManager(); /** * Set the instance manager associated with this context. */ public void setInstanceManager(InstanceManager instanceManager); /** * Sets the regular expression that specifies which container provided SCIs * should be filtered out and not used for this context. Matching uses * {@link java.util.regex.Matcher#find()} so the regular expression only has * to match a sub-string of the fully qualified class name of the container * provided SCI for it to be filtered out. * * @param containerSciFilter The regular expression against which the fully * qualified class name of each container provided * SCI should be checked */ public void setContainerSciFilter(String containerSciFilter); /** * Obtains the regular expression that specifies which container provided * SCIs should be filtered out and not used for this context. Matching uses * {@link java.util.regex.Matcher#find()} so the regular expression only has * to match a sub-string of the fully qualified class name of the container * provided SCI for it to be filtered out. * * @return The regular expression against which the fully qualified class * name of each container provided SCI will be checked */ public String getContainerSciFilter(); // --------------------------------------------------------- Public Methods /** * Add a new Listener class name to the set of Listeners * configured for this application. * * @param listener Java class name of a listener class */ public void addApplicationListener(ApplicationListener listener); /** * Add a new Listener class name to the set of Listeners * configured for this application. * * @param listener Java class name of a listener class * * @deprecated Use {@link #addApplicationListener(ApplicationListener)} */ @Deprecated public void addApplicationListener(String listener); /** * Add a new application parameter for this application. * * @param parameter The new application parameter */ public void addApplicationParameter(ApplicationParameter parameter); /** * Add a security constraint to the set for this web application. */ public void addConstraint(SecurityConstraint constraint); /** * Add an error page for the specified error or Java exception. * * @param errorPage The error page definition to be added */ public void addErrorPage(ErrorPage errorPage); /** * Add a filter definition to this Context. * * @param filterDef The filter definition to be added */ public void addFilterDef(FilterDef filterDef); /** * Add a filter mapping to this Context. * * @param filterMap The filter mapping to be added */ public void addFilterMap(FilterMap filterMap); /** * Add a filter mapping to this Context before the mappings defined in the * deployment descriptor but after any other mappings added via this method. * * @param filterMap The filter mapping to be added * * @exception IllegalArgumentException if the specified filter name * does not match an existing filter definition, or the filter mapping * is malformed */ public void addFilterMapBefore(FilterMap filterMap); /** * Add the classname of an InstanceListener to be added to each * Wrapper appended to this Context. * * @param listener Java class name of an InstanceListener class */ public void addInstanceListener(String listener); /** * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4) * * @param locale locale to map an encoding for * @param encoding encoding to be used for a give locale */ public void addLocaleEncodingMappingParameter(String locale, String encoding); /** * Add a new MIME mapping, replacing any existing mapping for * the specified extension. * * @param extension Filename extension being mapped * @param mimeType Corresponding MIME type */ public void addMimeMapping(String extension, String mimeType); /** * Add a new context initialization parameter, replacing any existing * value for the specified name. * * @param name Name of the new parameter * @param value Value of the new parameter */ public void addParameter(String name, String value); /** * Add a security role reference for this web application. * * @param role Security role used in the application * @param link Actual security role to check for */ public void addRoleMapping(String role, String link); /** * Add a new security role for this web application. * * @param role New security role */ public void addSecurityRole(String role); /** * Add a new servlet mapping, replacing any existing mapping for * the specified pattern. * * @param pattern URL pattern to be mapped * @param name Name of the corresponding servlet to execute */ public void addServletMapping(String pattern, String name); /** * Add a new servlet mapping, replacing any existing mapping for * the specified pattern. * * @param pattern URL pattern to be mapped * @param name Name of the corresponding servlet to execute * @param jspWildcard true if name identifies the JspServlet * and pattern contains a wildcard; false otherwise */ public void addServletMapping(String pattern, String name, boolean jspWildcard); /** * Add a resource which will be watched for reloading by the host auto * deployer. Note: this will not be used in embedded mode. * * @param name Path to the resource, relative to docBase */ public void addWatchedResource(String name); /** * Add a new welcome file to the set recognized by this Context. * * @param name New welcome file name */ public void addWelcomeFile(String name); /** * Add the classname of a LifecycleListener to be added to each * Wrapper appended to this Context. * * @param listener Java class name of a LifecycleListener class */ public void addWrapperLifecycle(String listener); /** * Add the classname of a ContainerListener to be added to each * Wrapper appended to this Context. * * @param listener Java class name of a ContainerListener class */ public void addWrapperListener(String listener); /** * Factory method to create and return a new Wrapper instance, of * the Java implementation class appropriate for this Context * implementation. The constructor of the instantiated Wrapper * will have been called, but no properties will have been set. */ public Wrapper createWrapper(); /** * Return the set of application listener class names configured * for this application. * * @deprecated The return type of this method will be changing to * {@link ApplicationListener}[] in Tomcat 8 */ @Deprecated public String[] findApplicationListeners(); /** * Return the set of application parameters for this application. */ public ApplicationParameter[] findApplicationParameters(); /** * Return the set of security constraints for this web application. * If there are none, a zero-length array is returned. */ public SecurityConstraint[] findConstraints(); /** * Return the error page entry for the specified HTTP error code, * if any; otherwise return null. * * @param errorCode Error code to look up */ public ErrorPage findErrorPage(int errorCode); /** * Return the error page entry for the specified Java exception type, * if any; otherwise return null. * * @param exceptionType Exception type to look up */ public ErrorPage findErrorPage(String exceptionType); /** * Return the set of defined error pages for all specified error codes * and exception types. */ public ErrorPage[] findErrorPages(); /** * Return the filter definition for the specified filter name, if any; * otherwise return null. * * @param filterName Filter name to look up */ public FilterDef findFilterDef(String filterName); /** * Return the set of defined filters for this Context. */ public FilterDef[] findFilterDefs(); /** * Return the set of filter mappings for this Context. */ public FilterMap[] findFilterMaps(); /** * Return the set of InstanceListener classes that will be added to * newly created Wrappers automatically. */ public String[] findInstanceListeners(); /** * Return the MIME type to which the specified extension is mapped, * if any; otherwise return null. * * @param extension Extension to map to a MIME type */ public String findMimeMapping(String extension); /** * Return the extensions for which MIME mappings are defined. If there * are none, a zero-length array is returned. */ public String[] findMimeMappings(); /** * Return the value for the specified context initialization * parameter name, if any; otherwise return null. * * @param name Name of the parameter to return */ public String findParameter(String name); /** * Return the names of all defined context initialization parameters * for this Context. If no parameters are defined, a zero-length * array is returned. */ public String[] findParameters(); /** * For the given security role (as used by an application), return the * corresponding role name (as defined by the underlying Realm) if there * is one. Otherwise, return the specified role unchanged. * * @param role Security role to map */ public String findRoleMapping(String role); /** * Return true if the specified security role is defined * for this application; otherwise return false. * * @param role Security role to verify */ public boolean findSecurityRole(String role); /** * Return the security roles defined for this application. If none * have been defined, a zero-length array is returned. */ public String[] findSecurityRoles(); /** * Return the servlet name mapped by the specified pattern (if any); * otherwise return null. * * @param pattern Pattern for which a mapping is requested */ public String findServletMapping(String pattern); /** * Return the patterns of all defined servlet mappings for this * Context. If no mappings are defined, a zero-length array is returned. */ public String[] findServletMappings(); /** * Return the context-relative URI of the error page for the specified * HTTP status code, if any; otherwise return null. * * @param status HTTP status code to look up */ public String findStatusPage(int status); /** * Return the set of HTTP status codes for which error pages have * been specified. If none are specified, a zero-length array * is returned. */ public int[] findStatusPages(); /** * Return the set of watched resources for this Context. If none are * defined, a zero length array will be returned. */ public String[] findWatchedResources(); /** * Return true if the specified welcome file is defined * for this Context; otherwise return false. * * @param name Welcome file to verify */ public boolean findWelcomeFile(String name); /** * Return the set of welcome files defined for this Context. If none are * defined, a zero-length array is returned. */ public String[] findWelcomeFiles(); /** * Return the set of LifecycleListener classes that will be added to * newly created Wrappers automatically. */ public String[] findWrapperLifecycles(); /** * Return the set of ContainerListener classes that will be added to * newly created Wrappers automatically. */ public String[] findWrapperListeners(); /** * Notify all {@link javax.servlet.ServletRequestListener}s that a request * has started. * @return true if the listeners fire successfully, else * false */ public boolean fireRequestInitEvent(ServletRequest request); /** * Notify all {@link javax.servlet.ServletRequestListener}s that a request * has ended. * @return true if the listeners fire successfully, else * false */ public boolean fireRequestDestroyEvent(ServletRequest request); /** * Reload this web application, if reloading is supported. * * @exception IllegalStateException if the reloadable * property is set to false. */ public void reload(); /** * Remove the specified application listener class from the set of * listeners for this application. * * @param listener Java class name of the listener to be removed */ public void removeApplicationListener(String listener); /** * Remove the application parameter with the specified name from * the set for this application. * * @param name Name of the application parameter to remove */ public void removeApplicationParameter(String name); /** * Remove the specified security constraint from this web application. * * @param constraint Constraint to be removed */ public void removeConstraint(SecurityConstraint constraint); /** * Remove the error page for the specified error code or * Java language exception, if it exists; otherwise, no action is taken. * * @param errorPage The error page definition to be removed */ public void removeErrorPage(ErrorPage errorPage); /** * Remove the specified filter definition from this Context, if it exists; * otherwise, no action is taken. * * @param filterDef Filter definition to be removed */ public void removeFilterDef(FilterDef filterDef); /** * Remove a filter mapping from this Context. * * @param filterMap The filter mapping to be removed */ public void removeFilterMap(FilterMap filterMap); /** * Remove a class name from the set of InstanceListener classes that * will be added to newly created Wrappers. * * @param listener Class name of an InstanceListener class to be removed */ public void removeInstanceListener(String listener); /** * Remove the MIME mapping for the specified extension, if it exists; * otherwise, no action is taken. * * @param extension Extension to remove the mapping for */ public void removeMimeMapping(String extension); /** * Remove the context initialization parameter with the specified * name, if it exists; otherwise, no action is taken. * * @param name Name of the parameter to remove */ public void removeParameter(String name); /** * Remove any security role reference for the specified name * * @param role Security role (as used in the application) to remove */ public void removeRoleMapping(String role); /** * Remove any security role with the specified name. * * @param role Security role to remove */ public void removeSecurityRole(String role); /** * Remove any servlet mapping for the specified pattern, if it exists; * otherwise, no action is taken. * * @param pattern URL pattern of the mapping to remove */ public void removeServletMapping(String pattern); /** * Remove the specified watched resource name from the list associated * with this Context. * * @param name Name of the watched resource to be removed */ public void removeWatchedResource(String name); /** * Remove the specified welcome file name from the list recognized * by this Context. * * @param name Name of the welcome file to be removed */ public void removeWelcomeFile(String name); /** * Remove a class name from the set of LifecycleListener classes that * will be added to newly created Wrappers. * * @param listener Class name of a LifecycleListener class to be removed */ public void removeWrapperLifecycle(String listener); /** * Remove a class name from the set of ContainerListener classes that * will be added to newly created Wrappers. * * @param listener Class name of a ContainerListener class to be removed */ public void removeWrapperListener(String listener); /** * Return the real path for a given virtual path, if possible; otherwise * return null. * * @param path The path to the desired resource */ public String getRealPath(String path); /** * Return the effective major version of the Servlet spec used by this * context. */ public int getEffectiveMajorVersion(); /** * Set the effective major version of the Servlet spec used by this * context. */ public void setEffectiveMajorVersion(int major); /** * Return the effective minor version of the Servlet spec used by this * context. */ public int getEffectiveMinorVersion(); /** * Set the effective minor version of the Servlet spec used by this * context. */ public void setEffectiveMinorVersion(int minor); /** * Obtain the JSP configuration for this context. */ public JspConfigDescriptor getJspConfigDescriptor(); /** * Add a URL for a JAR that contains static resources in a * META-INF/resources directory that should be included in the static * resources for this context. */ public void addResourceJarUrl(URL url); /** * Add a ServletContainerInitializer instance to this web application. * * @param sci The instance to add * @param classes The classes in which the initializer expressed an * interest */ public void addServletContainerInitializer( ServletContainerInitializer sci, Set> classes); /** * Is this Context paused whilst it is reloaded? */ public boolean getPaused(); /** * Is this context using version 2.2 of the Servlet spec? */ boolean isServlet22(); /** * Notification that servlet security has been dynamically set in a * {@link javax.servlet.ServletRegistration.Dynamic} * @param registration servlet security was modified for * @param servletSecurityElement new security constraints for this servlet * @return urls currently mapped to this registration that are already * present in web.xml */ Set addServletSecurity(ApplicationServletRegistration registration, ServletSecurityElement servletSecurityElement); /** * Sets the (comma separated) list of Servlets that expect a resource to be * present. Used to ensure that welcome files associated with Servlets that * expect a resource to be present are not mapped when there is no resource. */ public void setResourceOnlyServlets(String resourceOnlyServlets); /** * Obtains the list of Servlets that expect a resource to be present. * * @return A comma separated list of Servlet names as used in web.xml */ public String getResourceOnlyServlets(); /** * Checks the named Servlet to see if it expects a resource to be present. * * @param servletName Name of the Servlet (as per web.xml) to check * @return true if the Servlet expects a resource, * otherwise false */ public boolean isResourceOnlyServlet(String servletName); /** * Return the base name to use for WARs, directories or context.xml files * for this context. */ public String getBaseName(); /** * Set the version of this web application - used to differentiate * different versions of the same web application when using parallel * deployment. */ public void setWebappVersion(String webappVersion); /** * Set the version of this web application - used to differentiate * different versions of the same web application when using parallel * deployment. If not specified, defaults to the empty string. */ public String getWebappVersion(); /** * Configure whether or not requests listeners will be fired on forwards for * this Context. */ public void setFireRequestListenersOnForwards(boolean enable); /** * Determine whether or not requests listeners will be fired on forwards for * this Context. */ public boolean getFireRequestListenersOnForwards(); /** * Configures if a user presents authentication credentials, whether the * context will process them when the request is for a non-protected * resource. */ public void setPreemptiveAuthentication(boolean enable); /** * Determines if a user presents authentication credentials, will the * context will process them when the request is for a non-protected * resource. */ public boolean getPreemptiveAuthentication(); /** * Configures if a response body is included when a redirect response is * sent to the client. */ public void setSendRedirectBody(boolean enable); /** * Determines if the context is configured to include a response body as * part of a redirect response. */ public boolean getSendRedirectBody(); /** * Add a post construct method definition for the given class, if there is * an existing definition for the specified class - IllegalArgumentException * will be thrown. * * @param clazz Fully qualified class name * @param method * Post construct method name * @throws IllegalArgumentException * if the fully qualified class name or method name are * NULL; if there is already post construct method * definition for the given class */ public void addPostConstructMethod(String clazz, String method); /** * Add a pre destroy method definition for the given class, if there is an * existing definition for the specified class - IllegalArgumentException * will be thrown. * * @param clazz Fully qualified class name * @param method * Post construct method name * @throws IllegalArgumentException * if the fully qualified class name or method name are * NULL; if there is already pre destroy method * definition for the given class */ public void addPreDestroyMethod(String clazz, String method); /** * Removes the post construct method definition for the given class, if it * exists; otherwise, no action is taken. * * @param clazz * Fully qualified class name */ public void removePostConstructMethod(String clazz); /** * Removes the pre destroy method definition for the given class, if it * exists; otherwise, no action is taken. * * @param clazz * Fully qualified class name */ public void removePreDestroyMethod(String clazz); /** * Returns the method name that is specified as post construct method for * the given class, if it exists; otherwise NULL will be * returned. * * @param clazz * Fully qualified class name * * @return the method name that is specified as post construct method for * the given class, if it exists; otherwise NULL will * be returned. */ public String findPostConstructMethod(String clazz); /** * Returns the method name that is specified as pre destroy method for the * given class, if it exists; otherwise NULL will be returned. * * @param clazz * Fully qualified class name * * @return the method name that is specified as pre destroy method for the * given class, if it exists; otherwise NULL will be * returned. */ public String findPreDestroyMethod(String clazz); /** * Returns a map with keys - fully qualified class names of the classes that * have post construct methods and the values are the corresponding method * names. If there are no such classes an empty map will be returned. * * @return a map with keys - fully qualified class names of the classes that * have post construct methods and the values are the corresponding * method names. */ public Map findPostConstructMethods(); /** * Returns a map with keys - fully qualified class names of the classes that * have pre destroy methods and the values are the corresponding method * names. If there are no such classes an empty map will be returned. * * @return a map with keys - fully qualified class names of the classes that * have pre destroy methods and the values are the corresponding * method names. */ public Map findPreDestroyMethods(); } tomcat7-7.0.52/java/org/apache/catalina/manager/0000755000175100017510000000000012301126370021255 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/manager/LocalStrings_es.properties0000644000175100017510000002132412271471332026477 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. htmlManagerServlet.appsAvailable = Ejecut\u00E1ndose htmlManagerServlet.appsName = Nombre a Mostrar htmlManagerServlet.appsPath = Trayectoria htmlManagerServlet.appsReload = Recargar htmlManagerServlet.appsUndeploy = Replegar htmlManagerServlet.appsVersion = Versi\u00F3n htmlManagerServlet.appsExpire = Expirar sesiones htmlManagerServlet.appsSessions = Sesiones htmlManagerServlet.appsStart = Arrancar htmlManagerServlet.appsStop = Parar htmlManagerServlet.appsTasks = Comandos htmlManagerServlet.appsTitle = Aplicaciones htmlManagerServlet.noVersion = Ninguno especificado htmlManagerServlet.expire.explain = sin trabajar ≥ htmlManagerServlet.expire.unit = minutos htmlManagerServlet.helpHtmlManager = Ayuda HTML de Gestor htmlManagerServlet.helpHtmlManagerFile = ../docs/html-manager-howto.html htmlManagerServlet.helpManager = Ayuda de Gestor htmlManagerServlet.helpManagerFile = ../docs/manager-howto.html htmlManagerServlet.deployButton = Desplegar htmlManagerServlet.deployConfig = URL de archivo de Configuraci\u00F3n XML\: htmlManagerServlet.deployPath = Trayectoria de Contexto (opcional)\: htmlManagerServlet.deployServer = Desplegar directorio o archivo WAR localizado en servidor htmlManagerServlet.deployTitle = Desplegar htmlManagerServlet.deployUpload = Archivo WAR a desplegar htmlManagerServlet.deployUploadFail = FALLO - Fall\u00F3 Carga de Despliegue, Excepci\u00F3n\: {0} htmlManagerServlet.deployUploadFile = Seleccione archivo WAR a cargar htmlManagerServlet.deployUploadInServerXml = FALLO - El fichero war "{0}" no se puede cargar si se define el contexto en server.xml htmlManagerServlet.deployUploadNotWar = FALLO - El fichero cargado "{0}" debe de ser un .war htmlManagerServlet.deployUploadNoFile = FALLO - Fall\u00F3 la carga del fichero, no hay fichero htmlManagerServlet.deployUploadWarExists = FALLO - El fichero war "{0}" ya existe en el servidor htmlManagerServlet.deployWar = URL de WAR o Directorio\: htmlManagerServlet.diagnosticsLeak = Revisa a ver si una aplicaci\u00F3n web ha causado fallos de memoria al parar, recargar o replegarse. htmlManagerServlet.diagnosticsLeakButton = Halla fallos de memoria htmlManagerServlet.diagnosticsLeakWarning = Este chequeo de diagn\u00F3stico disparar\u00E1 una colecci\u00F3n completa de basura. Util\u00EDzalo con extremo cuidado en sistemas en producci\u00F3n. htmlManagerServlet.diagnosticsTitle = Diagn\u00F3sticos htmlManagerServlet.findleaksList = Las siguientes aplicaciones web fueron paradas (recargadas, replegadas), pero sus clases de las ejecuciones previas a\u00FAn se encuentran en memoria, causando as\u00ED un fallo de memoria (usa un perfilador para confirmarlo)\:\n htmlManagerServlet.findleaksNone = No parece haber aplicaciones web que hayan disparado un fallo de memoria al ser paradas, recargadas o replegadas. htmlManagerServlet.list = Listar Aplicaciones htmlManagerServlet.manager = Gestor htmlManagerServlet.messageLabel = Mensaje\: htmlManagerServlet.noManager = - htmlManagerServlet.serverHostname = NombreDeM\u00E1quina htmlManagerServlet.serverIPAddress = Direcci\u00F3n IP htmlManagerServlet.serverJVMVendor = Vendedor JVM htmlManagerServlet.serverJVMVersion = Versi\u00F3n JVM htmlManagerServlet.serverOSArch = Arquitectura de SO htmlManagerServlet.serverOSName = Nombre de SO htmlManagerServlet.serverOSVersion = Versi\u00F3n de SO htmlManagerServlet.serverTitle = Informaci\u00F3n de Servidor htmlManagerServlet.serverVersion = Versi\u00F3n de Tomcat htmlManagerServlet.title = Gestor de Aplicaciones Web de Tomcat managerServlet.alreadyContext = FALLO - Ya existe la aplicaci\u00F3n en la trayectoria {0} managerServlet.alreadyDocBase = FALLO - Directorio {0} ya est\u00E1 siendo usado managerServlet.configured = OK - Desplegada aplicaci\u00F3n desde archivo de contexto {0} managerServlet.deleteFail = FALLO - No pude borrar [{0}]. La presencia continua de este fichero puede causar problemas. managerServlet.deployed = OK - Desplegada aplicaci\u00F3n en trayectoria de contexto {0} managerServlet.deployFailed = FALLO - No pude desplegar la aplicaci\u00F3n en ruta de contexto {0} managerServlet.deployedButNotStarted = FALLO - Apliaci\u00F3n desplegada en la ruta de contexto {0}, pero el contexto no pudo arrancar managerServlet.exception = FALLO - Encontrada excepci\u00F3n {0} managerServlet.findleaksFail = FALLO - Ha fallado la b\u00FAsqueda de fallos\: La M\u00E1quina no es una instancia de StandardHost managerServlet.findleaksList = OK - Hallados fallos potenciales de memoria en las siguientes aplicaciones\: managerServlet.findleaksNone = OK - No se han hallado fallos de memoria managerServlet.invalidPath = FALLO - Se ha especificado una trayectoria inv\u00E1lida de contexto {0} managerServlet.invalidWar = FALLO - Se ha especificado una URL de aplicaci\u00F3n inv\u00E1lida {0} managerServlet.listed = OK - Aplicaciones listadas para m\u00E1quinda virutal {0} managerServlet.listitem = {0}\:{1}\:{2}\:{3} managerServlet.mkdirFail = FALLO - No pude crear directorio [{0}] managerServlet.noAppBase = FALLO - No puedo identificar aplicaci\u00F3n base para trayectoria de contexto {0} managerServlet.noCommand = FALLO - No se ha especificado comando managerServlet.noContext = FALLO - No existe contexto para trayectoria {0} managerServlet.noDirectory = FALLO - Documento base No-directorio para trayectoria {0} managerServlet.noDocBase = FALLO - No puedo replegar documento base para trayectoria {0} managerServlet.noGlobal = FALLO - No hay disponibles recursos globales JNDI managerServlet.noManager = FALLO - No existe gestor para ruta {0} managerServlet.noReload = FALLO - Recarga no soportada en WAR desplegado en trayectoria {0} managerServlet.noRename = FALLO - No pudeo desplegar WAR cargado para trayectoria {0} managerServlet.noRole = FALLO - El usuario no desempe\u00F1a el papel de {0} managerServlet.noSelf = FALLO - El gestor no puede recargarse, replegarse, pararse o replegarse a s\u00ED mismo managerServlet.noWrapper = El Contenedor no ha llamado a setWrapper() para este servlet managerServlet.notDeployed = FALLO - El contexto {0} est\u00E1 definido en server.xml y puede que no est\u00E9 desplegado managerServlet.objectNameFail = FALLO - No pude registrar objeto de nombre [{0}] para Gestor de Servlet managerServlet.postCommand = FALLO - Intent\u00E9 usar el comando {0} v\u00EDa un requerimiento GET pero se necesita POST managerServlet.reloaded = OK - Recargada aplicaci\u00F3n en trayectoria de contexto {0} managerServlet.resourcesAll = OK - Listados recursos globales de todos los tipos managerServlet.resourcesType = OK - Listados recursos globales de tipo {0} managerServlet.saveFail = FAIL - Fallo al guardar la configuraci\u00F3n\: {0} managerServlet.saved = OK - Configuraci\u00F3n de Servidor guardada managerServlet.savedContext = OK - Configuraci\u00F3n de Contexto {0} guardada managerServlet.sessiondefaultmax = Intervalo m\u00E1ximo por defecto de sesi\u00F3n inactiva {0} minutos #TODO: Please review the following three messages. These are displayed when "Expire sessions" button is pressed in the Manager webapp: managerServlet.sessiontimeout = {0} minutos\: {1} sesiones managerServlet.sessiontimeout.unlimited = unlimited minutos\: {0} sesiones managerServlet.sessiontimeout.expired = {0} minutos\: expired {1} sesiones managerServlet.sessions = OK - Informaci\u00F3n de sesi\u00F3n para aplicaci\u00F3n en trayectoria de contexto {0} managerServlet.started = OK - Arrancada aplicaci\u00F3n en trayectoria de contexto {0} managerServlet.startFailed = FALLO - No se pudo arrancar la aplicaci\u00F3n en trayectoria de contexto {0} managerServlet.stopped = OK - Parada aplicaci\u00F3n en trayectoria de contexto {0} managerServlet.undeployed = OK - Replegada aplicaci\u00F3n en trayectoria de contexto {0} managerServlet.unknownCommand = FALLO - Comando desconocido {0} managerServlet.userDatabaseError = FALLO - No puedo resolver referencia de base de datos de usuario managerServlet.userDatabaseMissing = FALLO - No se encuentra disponible base de datos de usuario statusServlet.title = Estado de Servidor statusServlet.complete = Estado Completo de Servidor tomcat7-7.0.52/java/org/apache/catalina/manager/DummyProxySession.java0000644000175100017510000000767511552413530025644 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; import java.security.Principal; import java.util.Iterator; import javax.servlet.http.HttpSession; import org.apache.catalina.Manager; import org.apache.catalina.Session; import org.apache.catalina.SessionListener; public class DummyProxySession implements Session { private String sessionId; public DummyProxySession(String sessionId) { this.sessionId = sessionId; } @Override public void access() { // NOOP } @Override public void addSessionListener(SessionListener listener) { // NOOP } @Override public void endAccess() { // NOOP } @Override public void expire() { // NOOP } @Override public String getAuthType() { return null; } @Override public long getCreationTime() { return 0; } @Override public long getCreationTimeInternal() { return 0; } @Override public String getId() { return sessionId; } @Override public String getIdInternal() { return sessionId; } @Override public String getInfo() { return null; } @Override public long getLastAccessedTime() { return 0; } @Override public long getLastAccessedTimeInternal() { return 0; } @Override public Manager getManager() { return null; } @Override public int getMaxInactiveInterval() { return 0; } @Override public Object getNote(String name) { return null; } @Override public Iterator getNoteNames() { return null; } @Override public Principal getPrincipal() { return null; } @Override public HttpSession getSession() { return null; } @Override public long getThisAccessedTime() { return 0; } @Override public long getThisAccessedTimeInternal() { return 0; } @Override public boolean isValid() { return false; } @Override public void recycle() { // NOOP } @Override public void removeNote(String name) { // NOOP } @Override public void removeSessionListener(SessionListener listener) { // NOOP } @Override public void setAuthType(String authType) { // NOOP } @Override public void setCreationTime(long time) { // NOOP } @Override public void setId(String id) { this.sessionId = id; } @Override public void setId(String id, boolean notify) { this.sessionId = id; // Ignore notify } @Override public void setManager(Manager manager) { // NOOP } @Override public void setMaxInactiveInterval(int interval) { // NOOP } @Override public void setNew(boolean isNew) { // NOOP } @Override public void setNote(String name, Object value) { // NOOP } @Override public void setPrincipal(Principal principal) { // NOOP } @Override public void setValid(boolean isValid) { // NOOP } } tomcat7-7.0.52/java/org/apache/catalina/manager/StatusManagerServlet.java0000644000175100017510000003226512271471332026262 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.Iterator; import java.util.Set; import java.util.Vector; import javax.management.MBeanServer; import javax.management.MBeanServerNotification; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.util.ServerInfo; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; /** * This servlet will display a complete status of the HTTP/1.1 connector. * * @author Remy Maucherat */ public class StatusManagerServlet extends HttpServlet implements NotificationListener { private static final long serialVersionUID = 1L; // ----------------------------------------------------- Instance Variables /** * MBean server. */ protected MBeanServer mBeanServer = null; /** * Vector of protocol handlers object names. */ protected Vector protocolHandlers = new Vector(); /** * Vector of thread pools object names. */ protected Vector threadPools = new Vector(); /** * Vector of request processors object names. */ protected Vector requestProcessors = new Vector(); /** * Vector of global request processors object names. */ protected Vector globalRequestProcessors = new Vector(); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // --------------------------------------------------------- Public Methods /** * Initialize this servlet. */ @Override public void init() throws ServletException { // Retrieve the MBean server mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); try { // Query protocol handlers String onStr = "*:type=ProtocolHandler,*"; ObjectName objectName = new ObjectName(onStr); Set set = mBeanServer.queryMBeans(objectName, null); Iterator iterator = set.iterator(); while (iterator.hasNext()) { ObjectInstance oi = iterator.next(); protocolHandlers.addElement(oi.getObjectName()); } // Query Thread Pools onStr = "*:type=ThreadPool,*"; objectName = new ObjectName(onStr); set = mBeanServer.queryMBeans(objectName, null); iterator = set.iterator(); while (iterator.hasNext()) { ObjectInstance oi = iterator.next(); threadPools.addElement(oi.getObjectName()); } // Query Global Request Processors onStr = "*:type=GlobalRequestProcessor,*"; objectName = new ObjectName(onStr); set = mBeanServer.queryMBeans(objectName, null); iterator = set.iterator(); while (iterator.hasNext()) { ObjectInstance oi = iterator.next(); globalRequestProcessors.addElement(oi.getObjectName()); } // Query Request Processors onStr = "*:type=RequestProcessor,*"; objectName = new ObjectName(onStr); set = mBeanServer.queryMBeans(objectName, null); iterator = set.iterator(); while (iterator.hasNext()) { ObjectInstance oi = iterator.next(); requestProcessors.addElement(oi.getObjectName()); } // Register with MBean server onStr = "JMImplementation:type=MBeanServerDelegate"; objectName = new ObjectName(onStr); mBeanServer.addNotificationListener(objectName, this, null, null); } catch (Exception e) { e.printStackTrace(); } } /** * Finalize this servlet. */ @Override public void destroy() { // Unregister with MBean server String onStr = "JMImplementation:type=MBeanServerDelegate"; ObjectName objectName; try { objectName = new ObjectName(onStr); mBeanServer.removeNotificationListener(objectName, this, null, null); } catch (Exception e) { e.printStackTrace(); } } /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // mode is flag for HTML or XML output int mode = 0; // if ?XML=true, set the mode to XML if (request.getParameter("XML") != null && request.getParameter("XML").equals("true")) { mode = 1; } StatusTransformer.setContentType(response, mode); PrintWriter writer = response.getWriter(); boolean completeStatus = false; if ((request.getPathInfo() != null) && (request.getPathInfo().equals("/all"))) { completeStatus = true; } // use StatusTransformer to output status Object[] args = new Object[1]; args[0] = request.getContextPath(); StatusTransformer.writeHeader(writer,args,mode); // Body Header Section args = new Object[2]; args[0] = request.getContextPath(); if (completeStatus) { args[1] = sm.getString("statusServlet.complete"); } else { args[1] = sm.getString("statusServlet.title"); } // use StatusTransformer to output status StatusTransformer.writeBody(writer,args,mode); // Manager Section args = new Object[9]; args[0] = sm.getString("htmlManagerServlet.manager"); args[1] = response.encodeURL(request.getContextPath() + "/html/list"); args[2] = sm.getString("htmlManagerServlet.list"); args[3] = response.encodeURL (request.getContextPath() + "/" + sm.getString("htmlManagerServlet.helpHtmlManagerFile")); args[4] = sm.getString("htmlManagerServlet.helpHtmlManager"); args[5] = response.encodeURL (request.getContextPath() + "/" + sm.getString("htmlManagerServlet.helpManagerFile")); args[6] = sm.getString("htmlManagerServlet.helpManager"); if (completeStatus) { args[7] = response.encodeURL (request.getContextPath() + "/status"); args[8] = sm.getString("statusServlet.title"); } else { args[7] = response.encodeURL (request.getContextPath() + "/status/all"); args[8] = sm.getString("statusServlet.complete"); } // use StatusTransformer to output status StatusTransformer.writeManager(writer,args,mode); // Server Header Section args = new Object[9]; args[0] = sm.getString("htmlManagerServlet.serverTitle"); args[1] = sm.getString("htmlManagerServlet.serverVersion"); args[2] = sm.getString("htmlManagerServlet.serverJVMVersion"); args[3] = sm.getString("htmlManagerServlet.serverJVMVendor"); args[4] = sm.getString("htmlManagerServlet.serverOSName"); args[5] = sm.getString("htmlManagerServlet.serverOSVersion"); args[6] = sm.getString("htmlManagerServlet.serverOSArch"); args[7] = sm.getString("htmlManagerServlet.serverHostname"); args[8] = sm.getString("htmlManagerServlet.serverIPAddress"); // use StatusTransformer to output status StatusTransformer.writePageHeading(writer,args,mode); // Server Row Section args = new Object[8]; args[0] = ServerInfo.getServerInfo(); args[1] = System.getProperty("java.runtime.version"); args[2] = System.getProperty("java.vm.vendor"); args[3] = System.getProperty("os.name"); args[4] = System.getProperty("os.version"); args[5] = System.getProperty("os.arch"); try { InetAddress address = InetAddress.getLocalHost(); args[6] = address.getHostName(); args[7] = address.getHostAddress(); } catch (UnknownHostException e) { args[6] = "-"; args[7] = "-"; } // use StatusTransformer to output status StatusTransformer.writeServerInfo(writer, args, mode); try { // Display operating system statistics using APR if available StatusTransformer.writeOSState(writer,mode); // Display virtual machine statistics StatusTransformer.writeVMState(writer,mode); Enumeration enumeration = threadPools.elements(); while (enumeration.hasMoreElements()) { ObjectName objectName = enumeration.nextElement(); String name = objectName.getKeyProperty("name"); // use StatusTransformer to output status StatusTransformer.writeConnectorState (writer, objectName, name, mBeanServer, globalRequestProcessors, requestProcessors, mode); } if ((request.getPathInfo() != null) && (request.getPathInfo().equals("/all"))) { // Note: Retrieving the full status is much slower // use StatusTransformer to output status StatusTransformer.writeDetailedState (writer, mBeanServer, mode); } } catch (Exception e) { throw new ServletException(e); } // use StatusTransformer to output status StatusTransformer.writeFooter(writer, mode); } // ------------------------------------------- NotificationListener Methods @Override public void handleNotification(Notification notification, java.lang.Object handback) { if (notification instanceof MBeanServerNotification) { ObjectName objectName = ((MBeanServerNotification) notification).getMBeanName(); if (notification.getType().equals (MBeanServerNotification.REGISTRATION_NOTIFICATION)) { String type = objectName.getKeyProperty("type"); if (type != null) { if (type.equals("ProtocolHandler")) { protocolHandlers.addElement(objectName); } else if (type.equals("ThreadPool")) { threadPools.addElement(objectName); } else if (type.equals("GlobalRequestProcessor")) { globalRequestProcessors.addElement(objectName); } else if (type.equals("RequestProcessor")) { requestProcessors.addElement(objectName); } } } else if (notification.getType().equals (MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) { String type = objectName.getKeyProperty("type"); if (type != null) { if (type.equals("ProtocolHandler")) { protocolHandlers.removeElement(objectName); } else if (type.equals("ThreadPool")) { threadPools.removeElement(objectName); } else if (type.equals("GlobalRequestProcessor")) { globalRequestProcessors.removeElement(objectName); } else if (type.equals("RequestProcessor")) { requestProcessors.removeElement(objectName); } } String j2eeType = objectName.getKeyProperty("j2eeType"); if (j2eeType != null) { } } } } } tomcat7-7.0.52/java/org/apache/catalina/manager/StatusTransformer.java0000644000175100017510000011153412271471332025642 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; import java.io.PrintWriter; import java.lang.management.ManagementFactory; import java.lang.management.MemoryPoolMXBean; import java.lang.management.MemoryUsage; import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.Date; import java.util.Enumeration; import java.util.Iterator; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.Vector; import javax.management.MBeanServer; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.util.RequestUtil; import org.apache.tomcat.util.ExceptionUtils; /** * This is a refactoring of the servlet to externalize * the output into a simple class. Although we could * use XSLT, that is unnecessarily complex. * * @author Peter Lin */ public class StatusTransformer { // --------------------------------------------------------- Public Methods public static void setContentType(HttpServletResponse response, int mode) { if (mode == 0){ response.setContentType("text/html;charset="+Constants.CHARSET); } else if (mode == 1){ response.setContentType("text/xml;charset="+Constants.CHARSET); } } /** * Write an HTML or XML header. * * @param writer the PrintWriter to use * @param args Path prefix for URLs * @param mode - 0 = HTML header, 1 = XML declaration * */ public static void writeHeader(PrintWriter writer, Object[] args, int mode) { if (mode == 0){ // HTML Header Section writer.print(Constants.HTML_HEADER_SECTION); } else if (mode == 1){ writer.write(Constants.XML_DECLARATION); writer.print(MessageFormat.format (Constants.XML_STYLE, args)); writer.write(""); } } /** * Write the header body. XML output doesn't bother * to output this stuff, since it's just title. * * @param writer The output writer * @param args What to write * @param mode 0 means write */ public static void writeBody(PrintWriter writer, Object[] args, int mode) { if (mode == 0){ writer.print(MessageFormat.format (Constants.BODY_HEADER_SECTION, args)); } } /** * Write the manager webapp information. * * @param writer The output writer * @param args What to write * @param mode 0 means write */ public static void writeManager(PrintWriter writer, Object[] args, int mode) { if (mode == 0){ writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args)); } } public static void writePageHeading(PrintWriter writer, Object[] args, int mode) { if (mode == 0){ writer.print(MessageFormat.format (Constants.SERVER_HEADER_SECTION, args)); } } public static void writeServerInfo(PrintWriter writer, Object[] args, int mode){ if (mode == 0){ writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args)); } } /** * */ public static void writeFooter(PrintWriter writer, int mode) { if (mode == 0){ // HTML Tail Section writer.print(Constants.HTML_TAIL_SECTION); } else if (mode == 1){ writer.write(""); } } /** * Write the OS state. Mode 0 will generate HTML. * Mode 1 will generate XML. */ public static void writeOSState(PrintWriter writer, int mode) { long[] result = new long[16]; boolean ok = false; try { String methodName = "info"; Class paramTypes[] = new Class[1]; paramTypes[0] = result.getClass(); Object paramValues[] = new Object[1]; paramValues[0] = result; Method method = Class.forName("org.apache.tomcat.jni.OS") .getMethod(methodName, paramTypes); method.invoke(null, paramValues); ok = true; } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); } if (ok) { if (mode == 0){ writer.print("

    OS

    "); writer.print("

    "); writer.print(" Physical memory: "); writer.print(formatSize(Long.valueOf(result[0]), true)); writer.print(" Available memory: "); writer.print(formatSize(Long.valueOf(result[1]), true)); writer.print(" Total page file: "); writer.print(formatSize(Long.valueOf(result[2]), true)); writer.print(" Free page file: "); writer.print(formatSize(Long.valueOf(result[3]), true)); writer.print(" Memory load: "); writer.print(Long.valueOf(result[6])); writer.print("
    "); writer.print(" Process kernel time: "); writer.print(formatTime(Long.valueOf(result[11] / 1000), true)); writer.print(" Process user time: "); writer.print(formatTime(Long.valueOf(result[12] / 1000), true)); writer.print("

    "); } else if (mode == 1){ // NO-OP } } } /** * Write the VM state. Mode 0 will generate HTML. * Mode 1 will generate XML. */ public static void writeVMState(PrintWriter writer, int mode) throws Exception { SortedMap memoryPoolMBeans = new TreeMap(); for (MemoryPoolMXBean mbean: ManagementFactory.getMemoryPoolMXBeans()) { String sortKey = mbean.getType() + ":" + mbean.getName(); memoryPoolMBeans.put(sortKey, mbean); } if (mode == 0){ writer.print("

    JVM

    "); writer.print("

    "); writer.print(" Free memory: "); writer.print(formatSize( Long.valueOf(Runtime.getRuntime().freeMemory()), true)); writer.print(" Total memory: "); writer.print(formatSize( Long.valueOf(Runtime.getRuntime().totalMemory()), true)); writer.print(" Max memory: "); writer.print(formatSize( Long.valueOf(Runtime.getRuntime().maxMemory()), true)); writer.print("

    "); writer.write(""); for (MemoryPoolMXBean memoryPoolMBean : memoryPoolMBeans.values()) { MemoryUsage usage = memoryPoolMBean.getUsage(); writer.write(""); } writer.write("
    Memory PoolTypeInitialTotalMaximumUsed
    "); writer.print(memoryPoolMBean.getName()); writer.write(""); writer.print(memoryPoolMBean.getType()); writer.write(""); writer.print(formatSize(Long.valueOf(usage.getInit()), true)); writer.write(""); writer.print(formatSize(Long.valueOf(usage.getCommitted()), true)); writer.write(""); writer.print(formatSize(Long.valueOf(usage.getMax()), true)); writer.write(""); writer.print(formatSize(Long.valueOf(usage.getUsed()), true)); if (usage.getMax() > 0) { writer.write(" (" + (usage.getUsed() * 100 / usage.getMax()) + "%)"); } writer.write("
    "); } else if (mode == 1){ writer.write(""); writer.write(""); for (MemoryPoolMXBean memoryPoolMBean : memoryPoolMBeans.values()) { MemoryUsage usage = memoryPoolMBean.getUsage(); writer.write(""); } writer.write(""); } } /** * Write connector state. */ public static void writeConnectorState(PrintWriter writer, ObjectName tpName, String name, MBeanServer mBeanServer, Vector globalRequestProcessors, Vector requestProcessors, int mode) throws Exception { if (mode == 0) { writer.print("

    "); writer.print(name); writer.print("

    "); writer.print("

    "); writer.print(" Max threads: "); writer.print(mBeanServer.getAttribute(tpName, "maxThreads")); writer.print(" Current thread count: "); writer.print(mBeanServer.getAttribute(tpName, "currentThreadCount")); writer.print(" Current thread busy: "); writer.print(mBeanServer.getAttribute(tpName, "currentThreadsBusy")); try { Object value = mBeanServer.getAttribute(tpName, "keepAliveCount"); writer.print(" Keeped alive sockets count: "); writer.print(value); } catch (Exception e) { // Ignore } writer.print("
    "); ObjectName grpName = null; Enumeration enumeration = globalRequestProcessors.elements(); while (enumeration.hasMoreElements()) { ObjectName objectName = enumeration.nextElement(); if (name.equals(objectName.getKeyProperty("name"))) { grpName = objectName; } } if (grpName == null) { return; } writer.print(" Max processing time: "); writer.print(formatTime(mBeanServer.getAttribute (grpName, "maxTime"), false)); writer.print(" Processing time: "); writer.print(formatTime(mBeanServer.getAttribute (grpName, "processingTime"), true)); writer.print(" Request count: "); writer.print(mBeanServer.getAttribute(grpName, "requestCount")); writer.print(" Error count: "); writer.print(mBeanServer.getAttribute(grpName, "errorCount")); writer.print(" Bytes received: "); writer.print(formatSize(mBeanServer.getAttribute (grpName, "bytesReceived"), true)); writer.print(" Bytes sent: "); writer.print(formatSize(mBeanServer.getAttribute (grpName, "bytesSent"), true)); writer.print("

    "); writer.print(""); enumeration = requestProcessors.elements(); while (enumeration.hasMoreElements()) { ObjectName objectName = enumeration.nextElement(); if (name.equals(objectName.getKeyProperty("worker"))) { writer.print(""); writeProcessorState(writer, objectName, mBeanServer, mode); writer.print(""); } } writer.print("
    StageTimeB SentB RecvClient (Forwarded)Client (Actual)VHostRequest
    "); writer.print("

    "); writer.print("P: Parse and prepare request S: Service F: Finishing R: Ready K: Keepalive"); writer.print("

    "); } else if (mode == 1){ writer.write(""); writer.write(""); ObjectName grpName = null; Enumeration enumeration = globalRequestProcessors.elements(); while (enumeration.hasMoreElements()) { ObjectName objectName = enumeration.nextElement(); if (name.equals(objectName.getKeyProperty("name"))) { grpName = objectName; } } if (grpName != null) { writer.write(""); writer.write(""); enumeration = requestProcessors.elements(); while (enumeration.hasMoreElements()) { ObjectName objectName = enumeration.nextElement(); if (name.equals(objectName.getKeyProperty("worker"))) { writeProcessorState(writer, objectName, mBeanServer, mode); } } writer.write(""); } writer.write(""); } } /** * Write processor state. */ protected static void writeProcessorState(PrintWriter writer, ObjectName pName, MBeanServer mBeanServer, int mode) throws Exception { Integer stageValue = (Integer) mBeanServer.getAttribute(pName, "stage"); int stage = stageValue.intValue(); boolean fullStatus = true; boolean showRequest = true; String stageStr = null; switch (stage) { case (1/*org.apache.coyote.Constants.STAGE_PARSE*/): stageStr = "P"; fullStatus = false; break; case (2/*org.apache.coyote.Constants.STAGE_PREPARE*/): stageStr = "P"; fullStatus = false; break; case (3/*org.apache.coyote.Constants.STAGE_SERVICE*/): stageStr = "S"; break; case (4/*org.apache.coyote.Constants.STAGE_ENDINPUT*/): stageStr = "F"; break; case (5/*org.apache.coyote.Constants.STAGE_ENDOUTPUT*/): stageStr = "F"; break; case (7/*org.apache.coyote.Constants.STAGE_ENDED*/): stageStr = "R"; fullStatus = false; break; case (6/*org.apache.coyote.Constants.STAGE_KEEPALIVE*/): stageStr = "K"; fullStatus = true; showRequest = false; break; case (0/*org.apache.coyote.Constants.STAGE_NEW*/): stageStr = "R"; fullStatus = false; break; default: // Unknown stage stageStr = "?"; fullStatus = false; } if (mode == 0) { writer.write(""); writer.write(stageStr); writer.write(""); if (fullStatus) { writer.write(""); writer.print(formatTime(mBeanServer.getAttribute (pName, "requestProcessingTime"), false)); writer.write(""); writer.write(""); if (showRequest) { writer.print(formatSize(mBeanServer.getAttribute (pName, "requestBytesSent"), false)); } else { writer.write("?"); } writer.write(""); writer.write(""); if (showRequest) { writer.print(formatSize(mBeanServer.getAttribute (pName, "requestBytesReceived"), false)); } else { writer.write("?"); } writer.write(""); writer.write(""); writer.print(filter(mBeanServer.getAttribute (pName, "remoteAddrForwarded"))); writer.write(""); writer.write(""); writer.print(filter(mBeanServer.getAttribute (pName, "remoteAddr"))); writer.write(""); writer.write(""); writer.write(filter(mBeanServer.getAttribute (pName, "virtualHost"))); writer.write(""); writer.write(""); if (showRequest) { writer.write(filter(mBeanServer.getAttribute (pName, "method"))); writer.write(" "); writer.write(filter(mBeanServer.getAttribute (pName, "currentUri"))); String queryString = (String) mBeanServer.getAttribute (pName, "currentQueryString"); if ((queryString != null) && (!queryString.equals(""))) { writer.write("?"); writer.print(RequestUtil.filter(queryString)); } writer.write(" "); writer.write(filter(mBeanServer.getAttribute (pName, "protocol"))); } else { writer.write("?"); } writer.write(""); } else { writer.write("??????"); } } else if (mode == 1){ writer.write(""); } } /** * Write applications state. */ public static void writeDetailedState(PrintWriter writer, MBeanServer mBeanServer, int mode) throws Exception { if (mode == 0){ ObjectName queryHosts = new ObjectName("*:j2eeType=WebModule,*"); Set hostsON = mBeanServer.queryNames(queryHosts, null); // Navigation menu writer.print("

    "); writer.print("Application list"); writer.print("

    "); writer.print("

    "); int count = 0; Iterator iterator = hostsON.iterator(); while (iterator.hasNext()) { ObjectName contextON = iterator.next(); String webModuleName = contextON.getKeyProperty("name"); if (webModuleName.startsWith("//")) { webModuleName = webModuleName.substring(2); } int slash = webModuleName.indexOf("/"); if (slash == -1) { count++; continue; } writer.print(""); writer.print(filter(webModuleName)); writer.print(""); if (iterator.hasNext()) { writer.print("
    "); } } writer.print("

    "); // Webapp list count = 0; iterator = hostsON.iterator(); while (iterator.hasNext()) { ObjectName contextON = iterator.next(); writer.print(""); writeContext(writer, contextON, mBeanServer, mode); } } else if (mode == 1){ // for now we don't write out the Detailed state in XML } } /** * Write context state. */ protected static void writeContext(PrintWriter writer, ObjectName objectName, MBeanServer mBeanServer, int mode) throws Exception { if (mode == 0){ String webModuleName = objectName.getKeyProperty("name"); String name = webModuleName; if (name == null) { return; } String hostName = null; String contextName = null; if (name.startsWith("//")) { name = name.substring(2); } int slash = name.indexOf("/"); if (slash != -1) { hostName = name.substring(0, slash); contextName = name.substring(slash); } else { return; } ObjectName queryManager = new ObjectName (objectName.getDomain() + ":type=Manager,context=" + contextName + ",host=" + hostName + ",*"); Set managersON = mBeanServer.queryNames(queryManager, null); ObjectName managerON = null; Iterator iterator2 = managersON.iterator(); while (iterator2.hasNext()) { managerON = iterator2.next(); } ObjectName queryJspMonitor = new ObjectName (objectName.getDomain() + ":type=JspMonitor,WebModule=" + webModuleName + ",*"); Set jspMonitorONs = mBeanServer.queryNames(queryJspMonitor, null); // Special case for the root context if (contextName.equals("/")) { contextName = ""; } writer.print("

    "); writer.print(filter(name)); writer.print("

    "); writer.print("
    "); writer.print("

    "); Object startTime = mBeanServer.getAttribute(objectName, "startTime"); writer.print(" Start time: " + new Date(((Long) startTime).longValue())); writer.print(" Startup time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "startupTime"), false)); writer.print(" TLD scan time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "tldScanTime"), false)); if (managerON != null) { writeManager(writer, managerON, mBeanServer, mode); } if (jspMonitorONs != null) { writeJspMonitor(writer, jspMonitorONs, mBeanServer, mode); } writer.print("

    "); String onStr = objectName.getDomain() + ":j2eeType=Servlet,WebModule=" + webModuleName + ",*"; ObjectName servletObjectName = new ObjectName(onStr); Set set = mBeanServer.queryMBeans(servletObjectName, null); Iterator iterator = set.iterator(); while (iterator.hasNext()) { ObjectInstance oi = iterator.next(); writeWrapper(writer, oi.getObjectName(), mBeanServer, mode); } } else if (mode == 1){ // for now we don't write out the context in XML } } /** * Write detailed information about a manager. */ public static void writeManager(PrintWriter writer, ObjectName objectName, MBeanServer mBeanServer, int mode) throws Exception { if (mode == 0) { writer.print("
    "); writer.print(" Active sessions: "); writer.print(mBeanServer.getAttribute (objectName, "activeSessions")); writer.print(" Session count: "); writer.print(mBeanServer.getAttribute (objectName, "sessionCounter")); writer.print(" Max active sessions: "); writer.print(mBeanServer.getAttribute(objectName, "maxActive")); writer.print(" Rejected session creations: "); writer.print(mBeanServer.getAttribute (objectName, "rejectedSessions")); writer.print(" Expired sessions: "); writer.print(mBeanServer.getAttribute (objectName, "expiredSessions")); writer.print(" Longest session alive time: "); writer.print(formatSeconds(mBeanServer.getAttribute( objectName, "sessionMaxAliveTime"))); writer.print(" Average session alive time: "); writer.print(formatSeconds(mBeanServer.getAttribute( objectName, "sessionAverageAliveTime"))); writer.print(" Processing time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "processingTime"), false)); } else if (mode == 1) { // for now we don't write out the wrapper details } } /** * Write JSP monitoring information. */ public static void writeJspMonitor(PrintWriter writer, Set jspMonitorONs, MBeanServer mBeanServer, int mode) throws Exception { int jspCount = 0; int jspReloadCount = 0; Iterator iter = jspMonitorONs.iterator(); while (iter.hasNext()) { ObjectName jspMonitorON = iter.next(); Object obj = mBeanServer.getAttribute(jspMonitorON, "jspCount"); jspCount += ((Integer) obj).intValue(); obj = mBeanServer.getAttribute(jspMonitorON, "jspReloadCount"); jspReloadCount += ((Integer) obj).intValue(); } if (mode == 0) { writer.print("
    "); writer.print(" JSPs loaded: "); writer.print(jspCount); writer.print(" JSPs reloaded: "); writer.print(jspReloadCount); } else if (mode == 1) { // for now we don't write out anything } } /** * Write detailed information about a wrapper. */ public static void writeWrapper(PrintWriter writer, ObjectName objectName, MBeanServer mBeanServer, int mode) throws Exception { if (mode == 0) { String servletName = objectName.getKeyProperty("name"); String[] mappings = (String[]) mBeanServer.invoke(objectName, "findMappings", null, null); writer.print("

    "); writer.print(filter(servletName)); if ((mappings != null) && (mappings.length > 0)) { writer.print(" [ "); for (int i = 0; i < mappings.length; i++) { writer.print(filter(mappings[i])); if (i < mappings.length - 1) { writer.print(" , "); } } writer.print(" ] "); } writer.print("

    "); writer.print("

    "); writer.print(" Processing time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "processingTime"), true)); writer.print(" Max time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "maxTime"), false)); writer.print(" Request count: "); writer.print(mBeanServer.getAttribute(objectName, "requestCount")); writer.print(" Error count: "); writer.print(mBeanServer.getAttribute(objectName, "errorCount")); writer.print(" Load time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "loadTime"), false)); writer.print(" Classloading time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "classLoadTime"), false)); writer.print("

    "); } else if (mode == 1){ // for now we don't write out the wrapper details } } /** * Filter the specified message string for characters that are sensitive * in HTML. This avoids potential attacks caused by including JavaScript * codes in the request URL that is often reported in error messages. * * @param obj The message string to be filtered */ public static String filter(Object obj) { if (obj == null) return ("?"); String message = obj.toString(); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); } /** * Display the given size in bytes, either as KB or MB. * * @param mb true to display megabytes, false for kilobytes */ public static String formatSize(Object obj, boolean mb) { long bytes = -1L; if (obj instanceof Long) { bytes = ((Long) obj).longValue(); } else if (obj instanceof Integer) { bytes = ((Integer) obj).intValue(); } if (mb) { StringBuilder buff = new StringBuilder(); if (bytes < 0) { buff.append('-'); bytes = -bytes; } long mbytes = bytes / (1024 * 1024); long rest = ((bytes - (mbytes * (1024 * 1024))) * 100) / (1024 * 1024); buff.append(mbytes).append('.'); if (rest < 10) { buff.append('0'); } buff.append(rest).append(" MB"); return buff.toString(); } else { return ((bytes / 1024) + " KB"); } } /** * Display the given time in ms, either as ms or s. * * @param seconds true to display seconds, false for milliseconds */ public static String formatTime(Object obj, boolean seconds) { long time = -1L; if (obj instanceof Long) { time = ((Long) obj).longValue(); } else if (obj instanceof Integer) { time = ((Integer) obj).intValue(); } if (seconds) { return ((((float) time ) / 1000) + " s"); } else { return (time + " ms"); } } /** * Formats the given time (given in seconds) as a string. * * @param obj Time object to be formatted as string * * @return String formatted time */ public static String formatSeconds(Object obj) { long time = -1L; if (obj instanceof Long) { time = ((Long) obj).longValue(); } else if (obj instanceof Integer) { time = ((Integer) obj).intValue(); } return (time + " s"); } } tomcat7-7.0.52/java/org/apache/catalina/manager/JMXProxyServlet.java0000644000175100017510000002360212271471332025177 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; import java.io.IOException; import java.io.PrintWriter; import java.util.Set; import javax.management.Attribute; import javax.management.MBeanException; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.OperationsException; import javax.management.ReflectionException; import javax.management.openmbean.CompositeData; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.mbeans.MBeanDumper; import org.apache.tomcat.util.modeler.Registry; /** * This servlet will dump JMX attributes in a simple format * and implement proxy services for modeler. * * @author Costin Manolache */ public class JMXProxyServlet extends HttpServlet { private static final long serialVersionUID = 1L; // Constant for "no parameters" when invoking a JMX operation // without any parameters. private static final String[] NO_PARAMETERS = new String[0]; // ----------------------------------------------------- Instance Variables /** * MBean server. */ protected transient MBeanServer mBeanServer = null; protected transient Registry registry; // --------------------------------------------------------- Public Methods /** * Initialize this servlet. */ @Override public void init() throws ServletException { // Retrieve the MBean server registry = Registry.getRegistry(null, null); mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); } /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/plain"); PrintWriter writer = response.getWriter(); if( mBeanServer==null ) { writer.println("Error - No mbean server"); return; } String qry=request.getParameter("set"); if( qry!= null ) { String name=request.getParameter("att"); String val=request.getParameter("val"); setAttribute( writer, qry, name, val ); return; } qry=request.getParameter("get"); if( qry!= null ) { String name=request.getParameter("att"); getAttribute( writer, qry, name, request.getParameter("key") ); return; } qry = request.getParameter("invoke"); if(qry != null) { String opName=request.getParameter("op"); String[] params = getInvokeParameters(request.getParameter("ps")); invokeOperation(writer, qry, opName, params); return; } qry=request.getParameter("qry"); if( qry == null ) { qry = "*:*"; } listBeans( writer, qry ); } public void getAttribute(PrintWriter writer, String onameStr, String att, String key) { try { ObjectName oname = new ObjectName(onameStr); Object value = mBeanServer.getAttribute(oname, att); if(null != key && value instanceof CompositeData) value = ((CompositeData)value).get(key); String valueStr; if (value != null) { valueStr = value.toString(); } else { valueStr = ""; } writer.print("OK - Attribute get '"); writer.print(onameStr); writer.print("' - "); writer.print(att); if(null != key) { writer.print(" - key '"); writer.print(key); writer.print("'"); } writer.print(" = "); writer.println(MBeanDumper.escape(valueStr)); } catch (Exception ex) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); } } public void setAttribute( PrintWriter writer, String onameStr, String att, String val ) { try { setAttributeInternal(onameStr, att, val); writer.println("OK - Attribute set"); } catch( Exception ex ) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); } } public void listBeans( PrintWriter writer, String qry ) { Set names = null; try { names=mBeanServer.queryNames(new ObjectName(qry), null); writer.println("OK - Number of results: " + names.size()); writer.println(); } catch (Exception ex) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); return; } String dump = MBeanDumper.dumpBeans(mBeanServer, names); writer.print(dump); } /** * Determines if a type is supported by the {@link JMXProxyServlet}. * * @param type The type to check * @return Always returns true */ public boolean isSupported(String type) { return true; } private void invokeOperation(PrintWriter writer, String onameStr, String op, String[] valuesStr) { try { Object retVal = invokeOperationInternal(onameStr, op, valuesStr); if (retVal != null) { writer.println("OK - Operation " + op + " returned:"); output("", writer, retVal); } else { writer.println("OK - Operation " + op + " without return value"); } } catch( Exception ex ) { writer.println("Error - " + ex.toString()); ex.printStackTrace(writer); } } /** * Parses parameter values from a parameter string. * @param paramString The string containing comma-separated * operation-invocation parameters, or * null if there are no parameters. * @return An array of String parameters (empty array if * paramString was null). */ private String[] getInvokeParameters(String paramString) { if (paramString == null) return NO_PARAMETERS; else return paramString.split(","); } /** * Sets an MBean attribute's value. */ private void setAttributeInternal(String onameStr, String attributeName, String value) throws OperationsException, MBeanException, ReflectionException { ObjectName oname=new ObjectName( onameStr ); String type=registry.getType(oname, attributeName); Object valueObj=registry.convertValue(type, value ); mBeanServer.setAttribute( oname, new Attribute(attributeName, valueObj)); } /** * Invokes an operation on an MBean. * @param onameStr The name of the MBean. * @param operation The name of the operation to invoke. * @param parameters An array of Strings containing the parameters to the * operation. They will be converted to the appropriate * types to call the reuested operation. * @return The value returned by the requested operation. */ private Object invokeOperationInternal(String onameStr, String operation, String[] parameters) throws OperationsException, MBeanException, ReflectionException { ObjectName oname=new ObjectName( onameStr ); MBeanOperationInfo methodInfo = registry.getMethodInfo(oname,operation); MBeanParameterInfo[] signature = methodInfo.getSignature(); String[] signatureTypes = new String[signature.length]; Object[] values = new Object[signature.length]; for (int i = 0; i < signature.length; i++) { MBeanParameterInfo pi = signature[i]; signatureTypes[i] = pi.getType(); values[i] = registry.convertValue(pi.getType(), parameters[i] ); } return mBeanServer.invoke(oname,operation,values,signatureTypes); } private void output(String indent, PrintWriter writer, Object result) { if (result instanceof Object[]) { for (Object obj : (Object[]) result) { output(" " + indent, writer, obj); } } else { String strValue; if (result != null) { strValue = result.toString(); } else { strValue = ""; } writer.println(indent + strValue); } } } tomcat7-7.0.52/java/org/apache/catalina/manager/JspHelper.java0000644000175100017510000001755012271471332024033 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; import java.text.DateFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import org.apache.catalina.Session; import org.apache.catalina.manager.util.SessionUtils; /** * Helper JavaBean for JSPs, because JSTL 1.1/EL 2.0 is too dumb to * to what I need (call methods with parameters), or I am too dumb to use it correctly. :) * @author Cédrik LIME */ public class JspHelper { private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; /** * Public constructor, so that this class can be considered a JavaBean */ private JspHelper() { super(); } /** * Try to get user locale from the session, if possible. * IMPLEMENTATION NOTE: this method has explicit support for Tapestry 3 and Struts 1.x * @param in_session * @return String */ public static String guessDisplayLocaleFromSession(Session in_session) { return localeToString(SessionUtils.guessLocaleFromSession(in_session)); } private static String localeToString(Locale locale) { if (locale != null) { return escapeXml(locale.toString());//locale.getDisplayName(); } else { return ""; } } /** * Try to get user name from the session, if possible. * @param in_session * @return String */ public static String guessDisplayUserFromSession(Session in_session) { Object user = SessionUtils.guessUserFromSession(in_session); return escapeXml(user); } public static String getDisplayCreationTimeForSession(Session in_session) { try { if (in_session.getCreationTime() == 0) { return ""; } DateFormat formatter = new SimpleDateFormat(DATE_TIME_FORMAT); return formatter.format(new Date(in_session.getCreationTime())); } catch (IllegalStateException ise) { //ignore: invalidated session return ""; } } public static String getDisplayLastAccessedTimeForSession(Session in_session) { try { if (in_session.getLastAccessedTime() == 0) { return ""; } DateFormat formatter = new SimpleDateFormat(DATE_TIME_FORMAT); return formatter.format(new Date(in_session.getLastAccessedTime())); } catch (IllegalStateException ise) { //ignore: invalidated session return ""; } } public static String getDisplayUsedTimeForSession(Session in_session) { try { if (in_session.getCreationTime() == 0) { return ""; } } catch (IllegalStateException ise) { //ignore: invalidated session return ""; } return secondsToTimeString(SessionUtils.getUsedTimeForSession(in_session)/1000); } public static String getDisplayTTLForSession(Session in_session) { try { if (in_session.getCreationTime() == 0) { return ""; } } catch (IllegalStateException ise) { //ignore: invalidated session return ""; } return secondsToTimeString(SessionUtils.getTTLForSession(in_session)/1000); } public static String getDisplayInactiveTimeForSession(Session in_session) { try { if (in_session.getCreationTime() == 0) { return ""; } } catch (IllegalStateException ise) { //ignore: invalidated session return ""; } return secondsToTimeString(SessionUtils.getInactiveTimeForSession(in_session)/1000); } public static String secondsToTimeString(long in_seconds) { StringBuilder buff = new StringBuilder(9); if (in_seconds < 0) { buff.append('-'); in_seconds = -in_seconds; } long rest = in_seconds; long hour = rest / 3600; rest = rest % 3600; long minute = rest / 60; rest = rest % 60; long second = rest; if (hour < 10) { buff.append('0'); } buff.append(hour); buff.append(':'); if (minute < 10) { buff.append('0'); } buff.append(minute); buff.append(':'); if (second < 10) { buff.append('0'); } buff.append(second); return buff.toString(); } /* * Following copied from org.apache.taglibs.standard.tag.common.core.Util v1.1.2 */ private static final int HIGHEST_SPECIAL = '>'; private static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][]; static { specialCharactersRepresentation['&'] = "&".toCharArray(); specialCharactersRepresentation['<'] = "<".toCharArray(); specialCharactersRepresentation['>'] = ">".toCharArray(); specialCharactersRepresentation['"'] = """.toCharArray(); specialCharactersRepresentation['\''] = "'".toCharArray(); } public static String escapeXml(Object obj) { String value = null; try { value = (obj == null) ? null : obj.toString(); } catch (Exception e) { // Ignore } return escapeXml(value); } /** * Performs the following substring replacements * (to facilitate output to XML/HTML pages): * * & -> & * < -> < * > -> > * " -> " * ' -> ' * * See also OutSupport.writeEscapedXml(). */ @SuppressWarnings("null") // escapedBuffer cannot be null public static String escapeXml(String buffer) { if (buffer == null) { return ""; } int start = 0; int length = buffer.length(); char[] arrayBuffer = buffer.toCharArray(); StringBuilder escapedBuffer = null; for (int i = 0; i < length; i++) { char c = arrayBuffer[i]; if (c <= HIGHEST_SPECIAL) { char[] escaped = specialCharactersRepresentation[c]; if (escaped != null) { // create StringBuilder to hold escaped xml string if (start == 0) { escapedBuffer = new StringBuilder(length + 5); } // add unescaped portion if (start < i) { escapedBuffer.append(arrayBuffer,start,i-start); } start = i + 1; // add escaped xml escapedBuffer.append(escaped); } } } // no xml escaping was necessary if (start == 0) { return buffer; } // add rest of unescaped portion if (start < length) { escapedBuffer.append(arrayBuffer,start,length-start); } return escapedBuffer.toString(); } public static String formatNumber(long number) { return NumberFormat.getNumberInstance().format(number); } } tomcat7-7.0.52/java/org/apache/catalina/manager/HTMLManagerServlet.java0000644000175100017510000015105712274762622025554 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Part; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.DistributedManager; import org.apache.catalina.Manager; import org.apache.catalina.Session; import org.apache.catalina.manager.util.BaseSessionComparator; import org.apache.catalina.manager.util.ReverseComparator; import org.apache.catalina.manager.util.SessionUtils; import org.apache.catalina.util.ContextName; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.catalina.util.URLEncoder; import org.apache.tomcat.util.http.fileupload.ParameterParser; import org.apache.tomcat.util.res.StringManager; /** * Servlet that enables remote management of the web applications deployed * within the same virtual host as this web application is. Normally, this * functionality will be protected by a security constraint in the web * application deployment descriptor. However, this requirement can be * relaxed during testing. *

    * The difference between the ManagerServlet and this * Servlet is that this Servlet prints out a HTML interface which * makes it easier to administrate. *

    * However if you use a software that parses the output of * ManagerServlet you won't be able to upgrade * to this Servlet since the output are not in the * same format ar from ManagerServlet * * @author Bip Thelin * @author Malcolm Edgar * @author Glenn L. Nielsen * @see ManagerServlet */ public final class HTMLManagerServlet extends ManagerServlet { private static final long serialVersionUID = 1L; protected static final URLEncoder URL_ENCODER; protected static final String APPLICATION_MESSAGE = "message"; protected static final String APPLICATION_ERROR = "error"; protected static final String sessionsListJspPath = "/WEB-INF/jsp/sessionsList.jsp"; protected static final String sessionDetailJspPath = "/WEB-INF/jsp/sessionDetail.jsp"; static { URL_ENCODER = new URLEncoder(); // '/' should not be encoded in context paths URL_ENCODER.addSafeCharacter('/'); } private boolean showProxySessions = false; // --------------------------------------------------------- Public Methods /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need // By obtaining the command from the pathInfo, per-command security can // be configured in web.xml String command = request.getPathInfo(); String path = request.getParameter("path"); ContextName cn = null; if (path != null) { cn = new ContextName(path, request.getParameter("version")); } // Prepare our output writer to generate the response message response.setContentType("text/html; charset=" + Constants.CHARSET); String message = ""; // Process the requested command if (command == null || command.equals("/")) { // No command == list } else if (command.equals("/list")) { // List always displayed - nothing to do here } else if (command.equals("/sessions")) { try { doSessions(cn, request, response, smClient); return; } catch (Exception e) { log("HTMLManagerServlet.sessions[" + cn + "]", e); message = smClient.getString("managerServlet.exception", e.toString()); } } else if (command.equals("/upload") || command.equals("/deploy") || command.equals("/reload") || command.equals("/undeploy") || command.equals("/expire") || command.equals("/start") || command.equals("/stop")) { message = smClient.getString("managerServlet.postCommand", command); } else { message = smClient.getString("managerServlet.unknownCommand", command); } list(request, response, message, smClient); } /** * Process a POST request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need // By obtaining the command from the pathInfo, per-command security can // be configured in web.xml String command = request.getPathInfo(); String path = request.getParameter("path"); ContextName cn = null; if (path != null) { cn = new ContextName(path, request.getParameter("version")); } String deployPath = request.getParameter("deployPath"); ContextName deployCn = null; if (deployPath != null) { deployCn = new ContextName(deployPath, request.getParameter("deployVersion")); } String deployConfig = request.getParameter("deployConfig"); String deployWar = request.getParameter("deployWar"); // Prepare our output writer to generate the response message response.setContentType("text/html; charset=" + Constants.CHARSET); String message = ""; if (command == null || command.length() == 0) { // No command == list // List always displayed -> do nothing } else if (command.equals("/upload")) { message = upload(request, smClient); } else if (command.equals("/deploy")) { message = deployInternal(deployConfig, deployCn, deployWar, smClient); } else if (command.equals("/reload")) { message = reload(cn, smClient); } else if (command.equals("/undeploy")) { message = undeploy(cn, smClient); } else if (command.equals("/expire")) { message = expireSessions(cn, request, smClient); } else if (command.equals("/start")) { message = start(cn, smClient); } else if (command.equals("/stop")) { message = stop(cn, smClient); } else if (command.equals("/findleaks")) { message = findleaks(smClient); } else { // Try GET doGet(request,response); return; } list(request, response, message, smClient); } protected String upload(HttpServletRequest request, StringManager smClient) { String message = ""; try { while (true) { Part warPart = request.getPart("deployWar"); if (warPart == null) { message = smClient.getString( "htmlManagerServlet.deployUploadNoFile"); break; } String filename = extractFilename(warPart.getHeader("Content-Disposition")); if (!filename.toLowerCase(Locale.ENGLISH).endsWith(".war")) { message = smClient.getString( "htmlManagerServlet.deployUploadNotWar", filename); break; } // Get the filename if uploaded name includes a path if (filename.lastIndexOf('\\') >= 0) { filename = filename.substring(filename.lastIndexOf('\\') + 1); } if (filename.lastIndexOf('/') >= 0) { filename = filename.substring(filename.lastIndexOf('/') + 1); } // Identify the appBase of the owning Host of this Context // (if any) File file = new File(getAppBase(), filename); if (file.exists()) { message = smClient.getString( "htmlManagerServlet.deployUploadWarExists", filename); break; } ContextName cn = new ContextName(filename, true); String name = cn.getName(); if ((host.findChild(name) != null) && !isDeployed(name)) { message = smClient.getString( "htmlManagerServlet.deployUploadInServerXml", filename); break; } if (!isServiced(name)) { addServiced(name); try { warPart.write(file.getAbsolutePath()); // Perform new deployment check(name); } finally { removeServiced(name); } } break; } } catch(Exception e) { message = smClient.getString ("htmlManagerServlet.deployUploadFail", e.getMessage()); log(message, e); } return message; } /* * Adapted from FileUploadBase.getFileName() */ private String extractFilename(String cd) { String fileName = null; if (cd != null) { String cdl = cd.toLowerCase(Locale.ENGLISH); if (cdl.startsWith("form-data") || cdl.startsWith("attachment")) { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = parser.parse(cd, ';'); if (params.containsKey("filename")) { fileName = params.get("filename"); if (fileName != null) { fileName = fileName.trim(); } else { // Even if there is no value, the parameter is present, // so we return an empty file name rather than no file // name. fileName = ""; } } } } return fileName; } /** * Deploy an application for the specified path from the specified * web application archive. * * @param config URL of the context configuration file to be deployed * @param cn Name of the application to be deployed * @param war URL of the web application archive to be deployed * @return message String */ protected String deployInternal(String config, ContextName cn, String war, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.deploy(printWriter, config, cn, war, false, smClient); return stringWriter.toString(); } /** * Render a HTML list of the currently active Contexts in our virtual host, * and memory and server status information. * * @param request The request * @param response The response * @param message a message to display */ protected void list(HttpServletRequest request, HttpServletResponse response, String message, StringManager smClient) throws IOException { if (debug >= 1) log("list: Listing contexts for virtual host '" + host.getName() + "'"); PrintWriter writer = response.getWriter(); // HTML Header Section writer.print(Constants.HTML_HEADER_SECTION); // Body Header Section Object[] args = new Object[2]; args[0] = request.getContextPath(); args[1] = smClient.getString("htmlManagerServlet.title"); writer.print(MessageFormat.format (Constants.BODY_HEADER_SECTION, args)); // Message Section args = new Object[3]; args[0] = smClient.getString("htmlManagerServlet.messageLabel"); if (message == null || message.length() == 0) { args[1] = "OK"; } else { args[1] = RequestUtil.filter(message); } writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args)); // Manager Section args = new Object[9]; args[0] = smClient.getString("htmlManagerServlet.manager"); args[1] = response.encodeURL(request.getContextPath() + "/html/list"); args[2] = smClient.getString("htmlManagerServlet.list"); args[3] = response.encodeURL (request.getContextPath() + "/" + smClient.getString("htmlManagerServlet.helpHtmlManagerFile")); args[4] = smClient.getString("htmlManagerServlet.helpHtmlManager"); args[5] = response.encodeURL (request.getContextPath() + "/" + smClient.getString("htmlManagerServlet.helpManagerFile")); args[6] = smClient.getString("htmlManagerServlet.helpManager"); args[7] = response.encodeURL (request.getContextPath() + "/status"); args[8] = smClient.getString("statusServlet.title"); writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args)); // Apps Header Section args = new Object[7]; args[0] = smClient.getString("htmlManagerServlet.appsTitle"); args[1] = smClient.getString("htmlManagerServlet.appsPath"); args[2] = smClient.getString("htmlManagerServlet.appsVersion"); args[3] = smClient.getString("htmlManagerServlet.appsName"); args[4] = smClient.getString("htmlManagerServlet.appsAvailable"); args[5] = smClient.getString("htmlManagerServlet.appsSessions"); args[6] = smClient.getString("htmlManagerServlet.appsTasks"); writer.print(MessageFormat.format(APPS_HEADER_SECTION, args)); // Apps Row Section // Create sorted map of deployed applications by context name. Container children[] = host.findChildren(); String contextNames[] = new String[children.length]; for (int i = 0; i < children.length; i++) contextNames[i] = children[i].getName(); Arrays.sort(contextNames); String appsStart = smClient.getString("htmlManagerServlet.appsStart"); String appsStop = smClient.getString("htmlManagerServlet.appsStop"); String appsReload = smClient.getString("htmlManagerServlet.appsReload"); String appsUndeploy = smClient.getString("htmlManagerServlet.appsUndeploy"); String appsExpire = smClient.getString("htmlManagerServlet.appsExpire"); String noVersion = "" + smClient.getString("htmlManagerServlet.noVersion") + ""; boolean isHighlighted = true; boolean isDeployed = true; String highlightColor = null; for (String contextName : contextNames) { Context ctxt = (Context) host.findChild(contextName); if (ctxt != null) { // Bugzilla 34818, alternating row colors isHighlighted = !isHighlighted; if(isHighlighted) { highlightColor = "#C3F3C3"; } else { highlightColor = "#FFFFFF"; } String contextPath = ctxt.getPath(); String displayPath = contextPath; if (displayPath.equals("")) { displayPath = "/"; } StringBuilder tmp = new StringBuilder(); tmp.append("path="); tmp.append(URL_ENCODER.encode(displayPath)); if (ctxt.getWebappVersion().length() > 0) { tmp.append("&version="); tmp.append(URL_ENCODER.encode(ctxt.getWebappVersion())); } String pathVersion = tmp.toString(); try { isDeployed = isDeployed(contextName); } catch (Exception e) { // Assume false on failure for safety isDeployed = false; } args = new Object[7]; args[0] = "" + RequestUtil.filter(displayPath) + ""; if ("".equals(ctxt.getWebappVersion())) { args[1] = noVersion; } else { args[1] = RequestUtil.filter(ctxt.getWebappVersion()); } if (ctxt.getDisplayName() == null) { args[2] = " "; } else { args[2] = RequestUtil.filter(ctxt.getDisplayName()); } args[3] = Boolean.valueOf(ctxt.getState().isAvailable()); args[4] = RequestUtil.filter(response.encodeURL(request.getContextPath() + "/html/sessions?" + pathVersion)); Manager manager = ctxt.getManager(); if (manager instanceof DistributedManager && showProxySessions) { args[5] = Integer.valueOf( ((DistributedManager)manager).getActiveSessionsFull()); } else if (manager != null){ args[5] = Integer.valueOf(manager.getActiveSessions()); } else { args[5] = Integer.valueOf(0); } args[6] = highlightColor; writer.print (MessageFormat.format(APPS_ROW_DETAILS_SECTION, args)); args = new Object[14]; args[0] = RequestUtil.filter(response.encodeURL(request .getContextPath() + "/html/start?" + pathVersion)); args[1] = appsStart; args[2] = RequestUtil.filter(response.encodeURL(request .getContextPath() + "/html/stop?" + pathVersion)); args[3] = appsStop; args[4] = RequestUtil.filter(response.encodeURL(request .getContextPath() + "/html/reload?" + pathVersion)); args[5] = appsReload; args[6] = RequestUtil.filter(response.encodeURL(request .getContextPath() + "/html/undeploy?" + pathVersion)); args[7] = appsUndeploy; args[8] = RequestUtil.filter(response.encodeURL(request .getContextPath() + "/html/expire?" + pathVersion)); args[9] = appsExpire; args[10] = smClient.getString( "htmlManagerServlet.expire.explain"); if (manager == null) { args[11] = smClient.getString( "htmlManagerServlet.noManager"); } else { args[11] = Integer.valueOf( ctxt.getManager().getMaxInactiveInterval()/60); } args[12] = smClient.getString("htmlManagerServlet.expire.unit"); args[13] = highlightColor; if (ctxt.getName().equals(this.context.getName())) { writer.print(MessageFormat.format( MANAGER_APP_ROW_BUTTON_SECTION, args)); } else if (ctxt.getState().isAvailable() && isDeployed) { writer.print(MessageFormat.format( STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } else if (ctxt.getState().isAvailable() && !isDeployed) { writer.print(MessageFormat.format( STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } else if (!ctxt.getState().isAvailable() && isDeployed) { writer.print(MessageFormat.format( STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } else { writer.print(MessageFormat.format( STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } } } // Deploy Section args = new Object[7]; args[0] = smClient.getString("htmlManagerServlet.deployTitle"); args[1] = smClient.getString("htmlManagerServlet.deployServer"); args[2] = response.encodeURL(request.getContextPath() + "/html/deploy"); args[3] = smClient.getString("htmlManagerServlet.deployPath"); args[4] = smClient.getString("htmlManagerServlet.deployConfig"); args[5] = smClient.getString("htmlManagerServlet.deployWar"); args[6] = smClient.getString("htmlManagerServlet.deployButton"); writer.print(MessageFormat.format(DEPLOY_SECTION, args)); args = new Object[4]; args[0] = smClient.getString("htmlManagerServlet.deployUpload"); args[1] = response.encodeURL(request.getContextPath() + "/html/upload"); args[2] = smClient.getString("htmlManagerServlet.deployUploadFile"); args[3] = smClient.getString("htmlManagerServlet.deployButton"); writer.print(MessageFormat.format(UPLOAD_SECTION, args)); // Diagnostics section args = new Object[5]; args[0] = smClient.getString("htmlManagerServlet.diagnosticsTitle"); args[1] = smClient.getString("htmlManagerServlet.diagnosticsLeak"); args[2] = response.encodeURL( request.getContextPath() + "/html/findleaks"); args[3] = smClient.getString("htmlManagerServlet.diagnosticsLeakWarning"); args[4] = smClient.getString("htmlManagerServlet.diagnosticsLeakButton"); writer.print(MessageFormat.format(DIAGNOSTICS_SECTION, args)); // Server Header Section args = new Object[9]; args[0] = smClient.getString("htmlManagerServlet.serverTitle"); args[1] = smClient.getString("htmlManagerServlet.serverVersion"); args[2] = smClient.getString("htmlManagerServlet.serverJVMVersion"); args[3] = smClient.getString("htmlManagerServlet.serverJVMVendor"); args[4] = smClient.getString("htmlManagerServlet.serverOSName"); args[5] = smClient.getString("htmlManagerServlet.serverOSVersion"); args[6] = smClient.getString("htmlManagerServlet.serverOSArch"); args[7] = sm.getString("htmlManagerServlet.serverHostname"); args[8] = sm.getString("htmlManagerServlet.serverIPAddress"); writer.print(MessageFormat.format (Constants.SERVER_HEADER_SECTION, args)); // Server Row Section args = new Object[8]; args[0] = ServerInfo.getServerInfo(); args[1] = System.getProperty("java.runtime.version"); args[2] = System.getProperty("java.vm.vendor"); args[3] = System.getProperty("os.name"); args[4] = System.getProperty("os.version"); args[5] = System.getProperty("os.arch"); try { InetAddress address = InetAddress.getLocalHost(); args[6] = address.getHostName(); args[7] = address.getHostAddress(); } catch (UnknownHostException e) { args[6] = "-"; args[7] = "-"; } writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args)); // HTML Tail Section writer.print(Constants.HTML_TAIL_SECTION); // Finish up the response writer.flush(); writer.close(); } /** * Reload the web application at the specified context path. * * @see ManagerServlet#reload(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be restarted * @param smClient StringManager for the client's locale * @return message String */ protected String reload(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.reload(printWriter, cn, smClient); return stringWriter.toString(); } /** * Undeploy the web application at the specified context path. * * @see ManagerServlet#undeploy(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be undeployed * @param smClient StringManager for the client's locale * @return message String */ protected String undeploy(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.undeploy(printWriter, cn, smClient); return stringWriter.toString(); } /** * Display session information and invoke list. * * @see ManagerServlet#sessions(PrintWriter, ContextName, int, * StringManager) * * @param cn Name of the application to list session information * @param idle Expire all sessions with idle time ≥ idle for this context * @param smClient StringManager for the client's locale * @return message String */ protected String sessions(ContextName cn, int idle, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.sessions(printWriter, cn, idle, smClient); return stringWriter.toString(); } /** * Start the web application at the specified context path. * * @see ManagerServlet#start(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be started * @param smClient StringManager for the client's locale * @return message String */ protected String start(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.start(printWriter, cn, smClient); return stringWriter.toString(); } /** * Stop the web application at the specified context path. * * @see ManagerServlet#stop(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be stopped * @param smClient StringManager for the client's locale * @return message String */ protected String stop(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.stop(printWriter, cn, smClient); return stringWriter.toString(); } /** * Find potential memory leaks caused by web application reload. * * @see ManagerServlet#findleaks(boolean, PrintWriter, StringManager) * * @param smClient StringManager for the client's locale * * @return message String */ protected String findleaks(StringManager smClient) { StringBuilder msg = new StringBuilder(); StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.findleaks(false, printWriter, smClient); String writerText = stringWriter.toString(); if (writerText.length() > 0) { if (!writerText.startsWith("FAIL -")) { msg.append(smClient.getString( "htmlManagerServlet.findleaksList")); } msg.append(writerText); } else { msg.append(smClient.getString("htmlManagerServlet.findleaksNone")); } return msg.toString(); } /** * @see javax.servlet.Servlet#getServletInfo() */ @Override public String getServletInfo() { return "HTMLManagerServlet, Copyright (c) 1999-2014, The Apache Software Foundation"; } /** * @see javax.servlet.GenericServlet#init() */ @Override public void init() throws ServletException { super.init(); // Set our properties from the initialization parameters String value = null; value = getServletConfig().getInitParameter("showProxySessions"); showProxySessions = Boolean.parseBoolean(value); } // ------------------------------------------------ Sessions administration /** * * Extract the expiration request parameter * * @param cn Name of the application from which to expire sessions * @param req * @param smClient StringManager for the client's locale */ protected String expireSessions(ContextName cn, HttpServletRequest req, StringManager smClient) { int idle = -1; String idleParam = req.getParameter("idle"); if (idleParam != null) { try { idle = Integer.parseInt(idleParam); } catch (NumberFormatException e) { log("Could not parse idle parameter to an int: " + idleParam); } } return sessions(cn, idle, smClient); } /** * * @param req * @param resp * @param smClient StringManager for the client's locale * @throws ServletException * @throws IOException */ protected void doSessions(ContextName cn, HttpServletRequest req, HttpServletResponse resp, StringManager smClient) throws ServletException, IOException { req.setAttribute("path", cn.getPath()); req.setAttribute("version", cn.getVersion()); String action = req.getParameter("action"); if (debug >= 1) { log("sessions: Session action '" + action + "' for web application '" + cn.getDisplayName() + "'"); } if ("sessionDetail".equals(action)) { String sessionId = req.getParameter("sessionId"); displaySessionDetailPage(req, resp, cn, sessionId, smClient); return; } else if ("invalidateSessions".equals(action)) { String[] sessionIds = req.getParameterValues("sessionIds"); int i = invalidateSessions(cn, sessionIds, smClient); req.setAttribute(APPLICATION_MESSAGE, "" + i + " sessions invalidated."); } else if ("removeSessionAttribute".equals(action)) { String sessionId = req.getParameter("sessionId"); String name = req.getParameter("attributeName"); boolean removed = removeSessionAttribute(cn, sessionId, name, smClient); String outMessage = removed ? "Session attribute '" + name + "' removed." : "Session did not contain any attribute named '" + name + "'"; req.setAttribute(APPLICATION_MESSAGE, outMessage); displaySessionDetailPage(req, resp, cn, sessionId, smClient); return; } // else displaySessionsListPage(cn, req, resp, smClient); } protected List getSessionsForName(ContextName cn, StringManager smClient) { if ((cn == null) || !(cn.getPath().startsWith("/") || cn.getPath().equals(""))) { String path = null; if (cn != null) { path = cn.getPath(); } throw new IllegalArgumentException(smClient.getString( "managerServlet.invalidPath", RequestUtil.filter(path))); } Context ctxt = (Context) host.findChild(cn.getName()); if (null == ctxt) { throw new IllegalArgumentException(smClient.getString( "managerServlet.noContext", RequestUtil.filter(cn.getDisplayName()))); } Manager manager = ctxt.getManager(); List sessions = new ArrayList(); sessions.addAll(Arrays.asList(manager.findSessions())); if (manager instanceof DistributedManager && showProxySessions) { // Add dummy proxy sessions Set sessionIds = ((DistributedManager) manager).getSessionIdsFull(); // Remove active (primary and backup) session IDs from full list for (Session session : sessions) { sessionIds.remove(session.getId()); } // Left with just proxy sessions - add them for (String sessionId : sessionIds) { sessions.add(new DummyProxySession(sessionId)); } } return sessions; } protected Session getSessionForNameAndId(ContextName cn, String id, StringManager smClient) { List sessions = getSessionsForName(cn, smClient); if (sessions == null || sessions.isEmpty()) return null; for(Session session : sessions) { if (session.getId().equals(id)) { return session; } } return null; } /** * * @param cn Name of the application for which the sessions will be listed * @param req * @param resp * @param smClient StringManager for the client's locale * @throws ServletException * @throws IOException */ protected void displaySessionsListPage(ContextName cn, HttpServletRequest req, HttpServletResponse resp, StringManager smClient) throws ServletException, IOException { List sessions = getSessionsForName(cn, smClient); String sortBy = req.getParameter("sort"); String orderBy = null; if (null != sortBy && !"".equals(sortBy.trim())) { Comparator comparator = getComparator(sortBy); if (comparator != null) { orderBy = req.getParameter("order"); if ("DESC".equalsIgnoreCase(orderBy)) { comparator = new ReverseComparator(comparator); orderBy = "ASC"; } else { orderBy = "DESC"; } try { Collections.sort(sessions, comparator); } catch (IllegalStateException ise) { // at least 1 of the sessions is invalidated req.setAttribute(APPLICATION_ERROR, "Can't sort session list: one session is invalidated"); } } else { log("WARNING: unknown sort order: " + sortBy); } } // keep sort order req.setAttribute("sort", sortBy); req.setAttribute("order", orderBy); req.setAttribute("activeSessions", sessions); //strong>NOTE - This header will be overridden // automatically if a RequestDispatcher.forward() call is // ultimately invoked. resp.setHeader("Pragma", "No-cache"); // HTTP 1.0 resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1 resp.setDateHeader("Expires", 0); // 0 means now getServletContext().getRequestDispatcher(sessionsListJspPath).include(req, resp); } /** * * @param req * @param resp * @param smClient StringManager for the client's locale * @throws ServletException * @throws IOException */ protected void displaySessionDetailPage(HttpServletRequest req, HttpServletResponse resp, ContextName cn, String sessionId, StringManager smClient) throws ServletException, IOException { Session session = getSessionForNameAndId(cn, sessionId, smClient); //strong>NOTE - This header will be overridden // automatically if a RequestDispatcher.forward() call is // ultimately invoked. resp.setHeader("Pragma", "No-cache"); // HTTP 1.0 resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1 resp.setDateHeader("Expires", 0); // 0 means now req.setAttribute("currentSession", session); getServletContext().getRequestDispatcher(resp.encodeURL(sessionDetailJspPath)).include(req, resp); } /** * Invalidate HttpSessions * @param cn Name of the application for which sessions are to be * invalidated * @param sessionIds * @param smClient StringManager for the client's locale * @return number of invalidated sessions * @throws IOException */ protected int invalidateSessions(ContextName cn, String[] sessionIds, StringManager smClient) throws IOException { if (null == sessionIds) { return 0; } int nbAffectedSessions = 0; for (int i = 0; i < sessionIds.length; ++i) { String sessionId = sessionIds[i]; HttpSession session = getSessionForNameAndId(cn, sessionId, smClient).getSession(); if (null == session) { // Shouldn't happen, but let's play nice... if (debug >= 1) { log("WARNING: can't invalidate null session " + sessionId); } continue; } try { session.invalidate(); ++nbAffectedSessions; if (debug >= 1) { log("Invalidating session id " + sessionId); } } catch (IllegalStateException ise) { if (debug >= 1) { log("Can't invalidate already invalidated session id " + sessionId); } } } return nbAffectedSessions; } /** * Removes an attribute from an HttpSession * @param cn Name of the application hosting the session from which the * attribute is to be removed * @param sessionId * @param attributeName * @param smClient StringManager for the client's locale * @return true if there was an attribute removed, false otherwise * @throws IOException */ protected boolean removeSessionAttribute(ContextName cn, String sessionId, String attributeName, StringManager smClient) throws IOException { HttpSession session = getSessionForNameAndId(cn, sessionId, smClient).getSession(); if (null == session) { // Shouldn't happen, but let's play nice... if (debug >= 1) { log("WARNING: can't remove attribute '" + attributeName + "' for null session " + sessionId); } return false; } boolean wasPresent = (null != session.getAttribute(attributeName)); try { session.removeAttribute(attributeName); } catch (IllegalStateException ise) { if (debug >= 1) { log("Can't remote attribute '" + attributeName + "' for invalidated session id " + sessionId); } } return wasPresent; } protected Comparator getComparator(String sortBy) { Comparator comparator = null; if ("CreationTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return new Date(session.getCreationTime()); } }; } else if ("id".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return session.getId(); } }; } else if ("LastAccessedTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return new Date(session.getLastAccessedTime()); } }; } else if ("MaxInactiveInterval".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return new Date(session.getMaxInactiveInterval()); } }; } else if ("new".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return Boolean.valueOf(session.getSession().isNew()); } }; } else if ("locale".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return JspHelper.guessDisplayLocaleFromSession(session); } }; } else if ("user".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return JspHelper.guessDisplayUserFromSession(session); } }; } else if ("UsedTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return new Date(SessionUtils.getUsedTimeForSession(session)); } }; } else if ("InactiveTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return new Date(SessionUtils.getInactiveTimeForSession(session)); } }; } else if ("TTL".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator() { @Override public Comparable getComparableObject(Session session) { return new Date(SessionUtils.getTTLForSession(session)); } }; } //TODO: complete this to TTL, etc. return comparator; } // ------------------------------------------------------ Private Constants // These HTML sections are broken in relatively small sections, because of // limited number of substitutions MessageFormat can process // (maximum of 10). private static final String APPS_HEADER_SECTION = "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; private static final String APPS_ROW_DETAILS_SECTION = "\n" + " \n" + " \n" + " \n" + " \n" + " \n"; private static final String MANAGER_APP_ROW_BUTTON_SECTION = " \n" + "\n" + " \n" + "\n"; private static final String STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION = " \n" + " \n" + " \n" + "\n"; private static final String STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION = " \n" + "\n\n"; private static final String STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION = " \n" + " \n" + " \n" + "\n"; private static final String STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION = " \n" + "\n\n"; private static final String DEPLOY_SECTION = "
    {0}
    {1}{2}{3}{4}{5}{6}
    {0}{1}{2}{3}" + "{5}\n" + " \n" + "  {1} \n" + "  {3} \n" + "  {5} \n" + "  {7} \n" + " \n" + "
    \n" + "
    \n" + " \n" + "   {10}  {12} \n" + " \n" + "
    \n" + "
    \n" + "  {1} \n" + "
    " + " " + "
    \n" + "
    " + " " + "
    \n" + "
    " + " " + "
    \n" + "
    \n" + "
    \n" + " \n" + "   {10}  {12} \n" + " \n" + "
    \n" + "
    \n" + "
    " + " " + "
    \n" + "  {3} \n" + "  {5} \n" + "
    " + " " + "
    \n" + "
    \n" + "  {1} \n" + "
    " + " " + "
    \n" + "
    " + " " + "
    \n" + "  {7} \n" + "
    \n" + "
    \n" + " \n" + "   {10}  {12} \n" + " \n" + "
    \n" + "
    \n" + "
    " + " " + "
    \n" + "  {3} \n" + "  {5} \n" + "  {7} \n" + "
    \n" + "
    \n" + "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + "\n"; private static final String UPLOAD_SECTION = "\n" + " \n" + "\n" + "\n" + " \n" + "\n" + "
    {0}
    {1}
    \n" + "
    \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "
    \n" + " {3}\n" + " \n" + " \n" + "
    \n" + " {4}\n" + " \n" + " \n" + "
    \n" + " {5}\n" + " \n" + " \n" + "
    \n" + "  \n" + " \n" + " \n" + "
    \n" + "
    \n" + "
    {0}
    \n" + "
    \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "
    \n" + " {2}\n" + " \n" + " \n" + "
    \n" + "  \n" + " \n" + " \n" + "
    \n" + "
    \n" + "
    \n" + "
    \n" + "\n"; private static final String DIAGNOSTICS_SECTION = "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + "\n" + "
    {0}
    {1}
    \n" + "
    \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "
    \n" + " \n" + " \n" + " {3}\n" + "
    \n" + "
    \n" + "
    \n" + "
    "; } tomcat7-7.0.52/java/org/apache/catalina/manager/Constants.java0000644000175100017510000002073212271471332024107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; public class Constants { public static final String Package = "org.apache.catalina.manager"; public static final String HTML_HEADER_SECTION; public static final String BODY_HEADER_SECTION; public static final String MESSAGE_SECTION; public static final String MANAGER_SECTION; public static final String SERVER_HEADER_SECTION; public static final String SERVER_ROW_SECTION; public static final String HTML_TAIL_SECTION; static { HTML_HEADER_SECTION = "\n" + "\n" + "\n"; BODY_HEADER_SECTION = "{0}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + " \n" + " \n" + " \n" + "
    \n" + " \n" + " \"The\n" + " \n" + " \n" + " \"The\n" + " \n" + "
    \n" + "


    \n" + "\n" + " \n" + " \n" + " \n" + "
    \n" + " {1}\n" + "
    \n" + "
    \n" + "\n"; MESSAGE_SECTION = "\n" + " \n" + " \n" + " \n" + " \n" + "
    " + "{0} 
    {1}
    \n" + "
    \n" + "\n"; MANAGER_SECTION = "\n" + "\n" + " \n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
    {0}
    {2}{4}{6}{8}
    \n" + "
    \n" + "\n"; SERVER_HEADER_SECTION = "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; SERVER_ROW_SECTION = "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + "
    {0}
    {1}{2}{3}{4}{5}{6}{7}{8}
    {0}{1}{2}{3}{4}{5}{6}{7}
    \n" + "
    \n" + "\n"; HTML_TAIL_SECTION = "
    \n" + "
    \n" + " Copyright © 1999-2014, Apache Software Foundation" + "
    \n" + "\n" + "\n" + ""; } public static final String CHARSET="utf-8"; public static final String XML_DECLARATION = ""; public static final String XML_STYLE = "\n"; } tomcat7-7.0.52/java/org/apache/catalina/manager/LocalStrings.properties0000644000175100017510000001663112271471332026015 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. htmlManagerServlet.appsAvailable=Running htmlManagerServlet.appsName=Display Name htmlManagerServlet.appsPath=Path htmlManagerServlet.appsReload=Reload htmlManagerServlet.appsUndeploy=Undeploy htmlManagerServlet.appsVersion=Version htmlManagerServlet.appsExpire=Expire sessions htmlManagerServlet.appsSessions=Sessions htmlManagerServlet.appsStart=Start htmlManagerServlet.appsStop=Stop htmlManagerServlet.appsTasks=Commands htmlManagerServlet.appsTitle=Applications htmlManagerServlet.noVersion=None specified htmlManagerServlet.expire.explain=with idle ≥ htmlManagerServlet.expire.unit=minutes htmlManagerServlet.helpHtmlManager=HTML Manager Help htmlManagerServlet.helpHtmlManagerFile=../docs/html-manager-howto.html htmlManagerServlet.helpManager=Manager Help htmlManagerServlet.helpManagerFile=../docs/manager-howto.html htmlManagerServlet.deployButton=Deploy htmlManagerServlet.deployConfig=XML Configuration file URL: htmlManagerServlet.deployPath=Context Path (required): htmlManagerServlet.deployServer=Deploy directory or WAR file located on server htmlManagerServlet.deployTitle=Deploy htmlManagerServlet.deployUpload=WAR file to deploy htmlManagerServlet.deployUploadFail=FAIL - Deploy Upload Failed, Exception: {0} htmlManagerServlet.deployUploadFile=Select WAR file to upload htmlManagerServlet.deployUploadInServerXml=FAIL - War file \"{0}\" cannot be uploaded if context is defined in server.xml htmlManagerServlet.deployUploadNotWar=FAIL - File uploaded \"{0}\" must be a .war htmlManagerServlet.deployUploadNoFile=FAIL - File upload failed, no file htmlManagerServlet.deployUploadWarExists=FAIL - War file \"{0}\" already exists on server htmlManagerServlet.deployWar=WAR or Directory URL: htmlManagerServlet.diagnosticsLeak=Check to see if a web application has caused a memory leak on stop, reload or undeploy htmlManagerServlet.diagnosticsLeakButton=Find leaks htmlManagerServlet.diagnosticsLeakWarning=This diagnostic check will trigger a full garbage collection. Use it with extreme caution on production systems. htmlManagerServlet.diagnosticsTitle=Diagnostics htmlManagerServlet.findleaksList=\ The following web applications were stopped (reloaded, undeployed), but their\n\ classes from previous runs are still loaded in memory, thus causing a memory\n\ leak (use a profiler to confirm):\n htmlManagerServlet.findleaksNone=No web applications appear to have triggered a memory leak on stop, reload or undeploy. htmlManagerServlet.list=List Applications htmlManagerServlet.manager=Manager htmlManagerServlet.messageLabel=Message: htmlManagerServlet.noManager=- htmlManagerServlet.serverHostname=Hostname htmlManagerServlet.serverIPAddress=IP Address htmlManagerServlet.serverJVMVendor=JVM Vendor htmlManagerServlet.serverJVMVersion=JVM Version htmlManagerServlet.serverOSArch=OS Architecture htmlManagerServlet.serverOSName=OS Name htmlManagerServlet.serverOSVersion=OS Version htmlManagerServlet.serverTitle=Server Information htmlManagerServlet.serverVersion=Tomcat Version htmlManagerServlet.title=Tomcat Web Application Manager managerServlet.alreadyContext=FAIL - Application already exists at path {0} managerServlet.alreadyDocBase=FAIL - Directory {0} is already in use managerServlet.configured=OK - Deployed application from context file {0} managerServlet.deleteFail=FAIL - Unable to delete [{0}]. The continued presence of this file may cause problems. managerServlet.deployed=OK - Deployed application at context path {0} managerServlet.deployFailed=FAIL - Failed to deploy application at context path {0} managerServlet.deployedButNotStarted=FAIL - Deployed application at context path {0} but context failed to start managerServlet.exception=FAIL - Encountered exception {0} managerServlet.findleaksFail=FAIL - Find leaks failed: Host not instance of StandardHost managerServlet.findleaksList=OK - Found potential memory leaks in the following applications: managerServlet.findleaksNone=OK - No memory leaks found managerServlet.invalidPath=FAIL - Invalid context path {0} was specified managerServlet.invalidWar=FAIL - Invalid application URL {0} was specified managerServlet.listed=OK - Listed applications for virtual host {0} managerServlet.listitem={0}:{1}:{2}:{3} managerServlet.mkdirFail=FAIL - Unable to create directory [{0}] managerServlet.noAppBase=FAIL - Cannot identify application base for context path {0} managerServlet.noCommand=FAIL - No command was specified managerServlet.noContext=FAIL - No context exists for path {0} managerServlet.noDirectory=FAIL - Non-directory document base for path {0} managerServlet.noDocBase=FAIL - Cannot undeploy document base for path {0} managerServlet.noGlobal=FAIL - No global JNDI resources are available managerServlet.noManager=FAIL - No manager exists for path {0} managerServlet.noReload=FAIL - Reload not supported on WAR deployed at path {0} managerServlet.noRename=FAIL - Cannot deploy uploaded WAR for path {0} managerServlet.noRole=FAIL - User does not possess role {0} managerServlet.noSelf=FAIL - The manager can not reload, undeploy, stop, or undeploy itself managerServlet.noWrapper=Container has not called setWrapper() for this servlet managerServlet.notDeployed=FAIL - Context {0} is defined in server.xml and may not be undeployed managerServlet.objectNameFail=FAIL - Unable to register object name [{0}] for Manager Servlet managerServlet.postCommand=FAIL - Tried to use command {0} via a GET request but POST is required managerServlet.reloaded=OK - Reloaded application at context path {0} managerServlet.resourcesAll=OK - Listed global resources of all types managerServlet.resourcesType=OK - Listed global resources of type {0} managerServlet.saveFail=FAIL - Configuration save failed: {0} managerServlet.saved=OK - Server configuration saved managerServlet.savedContext=OK - Context {0} configuration saved managerServlet.sessiondefaultmax=Default maximum session inactive interval {0} minutes managerServlet.sessiontimeout={0} minutes: {1} sessions managerServlet.sessiontimeout.unlimited=unlimited time: {0} sessions managerServlet.sessiontimeout.expired={0} minutes: {1} sessions were expired managerServlet.sessions=OK - Session information for application at context path {0} managerServlet.started=OK - Started application at context path {0} managerServlet.startFailed=FAIL - Application at context path {0} could not be started managerServlet.stopped=OK - Stopped application at context path {0} managerServlet.undeployed=OK - Undeployed application at context path {0} managerServlet.unknownCommand=FAIL - Unknown command {0} managerServlet.userDatabaseError=FAIL - Cannot resolve user database reference managerServlet.userDatabaseMissing=FAIL - No user database is available statusServlet.title=Server Status statusServlet.complete=Complete Server Status tomcat7-7.0.52/java/org/apache/catalina/manager/LocalStrings_ja.properties0000644000175100017510000002403712271471332026466 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. htmlManagerServlet.appsAvailable=\u5b9f\u884c\u4e2d htmlManagerServlet.appsName=\u8868\u793a\u540d htmlManagerServlet.appsPath=\u30d1\u30b9 htmlManagerServlet.appsReload=\u518d\u30ed\u30fc\u30c9 htmlManagerServlet.appsUndeploy=\u914d\u5099\u89e3\u9664 htmlManagerServlet.appsSessions=\u30bb\u30c3\u30b7\u30e7\u30f3 htmlManagerServlet.appsStart=\u8d77\u52d5 htmlManagerServlet.appsStop=\u505c\u6b62 htmlManagerServlet.appsTasks=\u30b3\u30de\u30f3\u30c9 htmlManagerServlet.appsTitle=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3 htmlManagerServlet.helpHtmlManager=HTML\u30de\u30cd\u30fc\u30b8\u30e3\u30d8\u30eb\u30d7 htmlManagerServlet.helpHtmlManagerFile=../docs/html-manager-howto.html htmlManagerServlet.helpManager=\u30de\u30cd\u30fc\u30b8\u30e3\u30d8\u30eb\u30d7 htmlManagerServlet.helpManagerFile=../docs/manager-howto.html htmlManagerServlet.deployButton=\u914d\u5099 htmlManagerServlet.deployConfig=XML\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eURL: htmlManagerServlet.deployPath=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 (\u7701\u7565\u53ef): htmlManagerServlet.deployServer=\u30b5\u30fc\u30d0\u4e0a\u306eWAR\u30d5\u30a1\u30a4\u30eb\u53c8\u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u914d\u5099 htmlManagerServlet.deployTitle=\u914d\u5099 htmlManagerServlet.deployUpload=WAR\u30d5\u30a1\u30a4\u30eb\u306e\u914d\u5099 htmlManagerServlet.deployUploadFail=FAIL - \u914d\u5099\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3001\u4f8b\u5916: {0} htmlManagerServlet.deployUploadFile=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308bWAR\u30d5\u30a1\u30a4\u30eb\u306e\u9078\u629e htmlManagerServlet.deployUploadNotWar=FAIL - \u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308b\u30d5\u30a1\u30a4\u30eb \"{0}\" \u306fWAR\u30d5\u30a1\u30a4\u30eb\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 htmlManagerServlet.deployUploadNoFile=FAIL - \u30d5\u30a1\u30a4\u30eb\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3001\u30d5\u30a1\u30a4\u30eb\u304c\u5b58\u5728\u3057\u307e\u305b\u3093 htmlManagerServlet.deployUploadWarExists=FAIL - WAR\u30d5\u30a1\u30a4\u30eb \"{0}\" \u306f\u65e2\u306b\u30b5\u30fc\u30d0\u4e0a\u306b\u5b58\u5728\u3057\u307e\u3059 htmlManagerServlet.deployWar=WAR\u30d5\u30a1\u30a4\u30eb\u53c8\u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306eURL: htmlManagerServlet.list=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u4e00\u89a7 htmlManagerServlet.manager=\u30de\u30cd\u30fc\u30b8\u30e3 htmlManagerServlet.messageLabel=\u30e1\u30c3\u30bb\u30fc\u30b8 htmlManagerServlet.serverJVMVendor=JVM\u30d9\u30f3\u30c0 htmlManagerServlet.serverJVMVersion=JVM\u30d0\u30fc\u30b8\u30e7\u30f3 htmlManagerServlet.serverOSArch=OS\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3 htmlManagerServlet.serverOSName=OS\u540d htmlManagerServlet.serverOSVersion=OS\u30d0\u30fc\u30b8\u30e7\u30f3 htmlManagerServlet.serverTitle=\u30b5\u30fc\u30d0\u60c5\u5831 htmlManagerServlet.serverVersion=Tomcat\u30d0\u30fc\u30b8\u30e7\u30f3 htmlManagerServlet.title=Tomcat Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30de\u30cd\u30fc\u30b8\u30e3 managerServlet.alreadyContext=FAIL - \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u3001\u65e2\u306b\u30d1\u30b9 {0} \u306b\u5b58\u5728\u3057\u307e\u3059 managerServlet.alreadyDocBase=FAIL - \u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306f\u65e2\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059 managerServlet.cannotInvoke=\u30a4\u30f3\u30dc\u30fc\u30ab\u3067\u30de\u30cd\u30fc\u30b8\u30e3\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u8d77\u52d5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f managerServlet.configured=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb {0} \u304b\u3089\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3057\u305f managerServlet.deployed=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3057\u305f managerServlet.exception=FAIL - \u4f8b\u5916 {0} \u304c\u767a\u751f\u3057\u307e\u3057\u305f managerServlet.invalidPath=FAIL - \u7121\u52b9\u306a\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f managerServlet.invalidWar=FAIL - \u7121\u52b9\u306a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eURL {0} \u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f managerServlet.listed=OK - \u30d0\u30fc\u30c1\u30e3\u30eb\u30db\u30b9\u30c8 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u4e00\u89a7\u3067\u3059 managerServlet.listitem={0}:{1}:{2}:{3} managerServlet.noAppBase=FAIL - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306b\u5bfe\u3057\u3066\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u3092\u78ba\u8a8d\u3067\u304d\u307e\u305b\u3093 managerServlet.noCommand=FAIL - \u30b3\u30de\u30f3\u30c9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 managerServlet.noContext=FAIL - \u30d1\u30b9 {0} \u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u5b58\u5728\u3057\u307e\u305b\u3093 managerServlet.noDirectory=FAIL - \u30d1\u30b9 {0} \u306b\u5bfe\u3059\u308b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093 managerServlet.noDocBase=FAIL - \u30d1\u30b9 {0} \u306b\u5bfe\u3059\u308b\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093 managerServlet.noGlobal=FAIL - \u30b0\u30ed\u30fc\u30d0\u30eb\u306aJNDI\u30ea\u30bd\u30fc\u30b9\u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093 managerServlet.noReload=FAIL - \u30d1\u30b9 {0} \u306b\u914d\u5099\u3055\u308c\u305fWAR\u30d5\u30a1\u30a4\u30eb\u3067\u306f\u518d\u30ed\u30fc\u30c9\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093 managerServlet.noRename=FAIL - \u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3055\u308c\u305fWAR\u30d5\u30a1\u30a4\u30eb\u3092\u30d1\u30b9 {0} \u306b\u914d\u5099\u3067\u304d\u307e\u305b\u3093 managerServlet.noRole=FAIL - \u30e6\u30fc\u30b6\u306f\u30ed\u30fc\u30eb {0} \u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093 managerServlet.noSelf=FAIL - \u30de\u30cd\u30fc\u30b8\u30e3\u81ea\u8eab\u3092\u518d\u30ed\u30fc\u30c9\u3001\u524a\u9664\u3001\u505c\u6b62\u3001\u53c8\u306f\u914d\u5099\u89e3\u9664\u3067\u304d\u307e\u305b\u3093 managerServlet.noWrapper=\u30b3\u30f3\u30c6\u30ca\u306f\u3053\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306b\u5bfe\u3057\u3066\u547c\u3073\u51fa\u3055\u308c\u305fsetWrapper()\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093 managerServlet.reloaded=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u518d\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f managerServlet.resourcesAll=OK - \u3059\u3079\u3066\u306e\u30bf\u30a4\u30d7\u306e\u30b0\u30ed\u30fc\u30d0\u30eb\u30ea\u30bd\u30fc\u30b9\u3092\u5217\u6319\u3057\u307e\u3057\u305f managerServlet.resourcesType=OK - \u30bf\u30a4\u30d7 {0} \u306e\u30b0\u30ed\u30fc\u30d0\u30eb\u30ea\u30bd\u30fc\u30b9\u3092\u5217\u6319\u3057\u307e\u3057\u305f managerServlet.saveFail=FAIL - \u8a2d\u5b9a\u306e\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} managerServlet.saved=OK - \u30b5\u30fc\u30d0\u306e\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f managerServlet.savedContext=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f managerServlet.sessiondefaultmax=\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u6700\u5927\u30bb\u30c3\u30b7\u30e7\u30f3\u505c\u6b62\u9593\u9694\u306f{0}\u5206\u3067\u3059 #TODO: Please review the following three messages. These are displayed when "Expire sessions" button is pressed in the Manager webapp: managerServlet.sessiontimeout={0}\u5206: {1}\u30bb\u30c3\u30b7\u30e7\u30f3 managerServlet.sessiontimeout.unlimited=unlimited \u5206: {0}\u30bb\u30c3\u30b7\u30e7\u30f3 managerServlet.sessiontimeout.expired={0}\u5206: expired {1}\u30bb\u30c3\u30b7\u30e7\u30f3 managerServlet.sessions=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30bb\u30c3\u30b7\u30e7\u30f3\u60c5\u5831\u3067\u3059 managerServlet.started=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u307e\u3057\u305f managerServlet.startFailed=FAIL - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c\u8d77\u52d5\u3067\u304d\u307e\u305b\u3093 managerServlet.stopped=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u505c\u6b62\u3057\u307e\u3057\u305f managerServlet.undeployed=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u89e3\u9664\u3057\u307e\u3057\u305f managerServlet.unknownCommand=FAIL - \u672a\u77e5\u306e\u30b3\u30de\u30f3\u30c9 {0} \u3067\u3059 managerServlet.userDatabaseError=FAIL - \u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u53c2\u7167\u3092\u89e3\u6c7a\u3067\u304d\u307e\u305b\u3093 managerServlet.userDatabaseMissing=FAIL - \u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093 statusServlet.title=\u30b5\u30fc\u30d0\u306e\u72b6\u614b statusServlet.complete=\u30b5\u30fc\u30d0\u306e\u5168\u72b6\u614b tomcat7-7.0.52/java/org/apache/catalina/manager/util/0000755000175100017510000000000012301126370022232 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/manager/util/ReverseComparator.java0000644000175100017510000000276012271471332026554 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager.util; import java.util.Comparator; import org.apache.catalina.Session; /** * Comparator which reverse the sort order * @author Cédrik LIME */ public class ReverseComparator implements Comparator { protected Comparator comparator; /** * */ public ReverseComparator(Comparator comparator) { super(); this.comparator = comparator; } /* (non-Javadoc) * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @Override public int compare(Session o1, Session o2) { int returnValue = comparator.compare(o1, o2); return (- returnValue); } } tomcat7-7.0.52/java/org/apache/catalina/manager/util/SessionUtils.java0000644000175100017510000002503412271471332025554 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager.util; import java.lang.reflect.Method; import java.security.Principal; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Locale; import javax.security.auth.Subject; import javax.servlet.http.HttpSession; import org.apache.catalina.Session; import org.apache.tomcat.util.ExceptionUtils; /** * Utility methods on HttpSessions... * @author Cédrik LIME */ public class SessionUtils { /** * */ private SessionUtils() { super(); } /** * The session attributes key under which the user's selected * java.util.Locale is stored, if any. */ // org.apache.struts.Globals.LOCALE_KEY private static final String STRUTS_LOCALE_KEY = "org.apache.struts.action.LOCALE";//$NON-NLS-1$ // javax.servlet.jsp.jstl.core.Config.FMT_LOCALE private static final String JSTL_LOCALE_KEY = "javax.servlet.jsp.jstl.fmt.locale";//$NON-NLS-1$ // org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME private static final String SPRING_LOCALE_KEY = "org.springframework.web.servlet.i18n.SessionLocaleResolver.LOCALE";//$NON-NLS-1$ /** * Lower and upper-case strings will be dynamically generated. Put mid-capitalised strings here! */ private static final String[] LOCALE_TEST_ATTRIBUTES = new String[] { STRUTS_LOCALE_KEY, SPRING_LOCALE_KEY, JSTL_LOCALE_KEY, "Locale", "java.util.Locale" }; /** * For efficient operation, list the attributes here with the typically used * capitalisation. This will be tried first and then the auto-generated * upper and lower case versions will be tried. */ private static final String[] USER_TEST_ATTRIBUTES = new String[] { "Login", "User", "userName", "UserName", "Utilisateur", "SPRING_SECURITY_LAST_USERNAME"}; /** * Try to get user locale from the session, if possible. * IMPLEMENTATION NOTE: this method has explicit support for Tapestry 3, Struts 1.x and Spring * JSF check the browser meta tag "accept languages" to choose what language to display. * @param in_session * @return String */ public static Locale guessLocaleFromSession(final Session in_session) { return guessLocaleFromSession(in_session.getSession()); } public static Locale guessLocaleFromSession(final HttpSession in_session) { if (null == in_session) { return null; } try { Locale locale = null; // First search "known locations" for (int i = 0; i < LOCALE_TEST_ATTRIBUTES.length; ++i) { Object obj = in_session.getAttribute(LOCALE_TEST_ATTRIBUTES[i]); if (null != obj && obj instanceof Locale) { locale = (Locale) obj; break; } obj = in_session.getAttribute(LOCALE_TEST_ATTRIBUTES[i].toLowerCase(Locale.ENGLISH)); if (null != obj && obj instanceof Locale) { locale = (Locale) obj; break; } obj = in_session.getAttribute(LOCALE_TEST_ATTRIBUTES[i].toUpperCase(Locale.ENGLISH)); if (null != obj && obj instanceof Locale) { locale = (Locale) obj; break; } } if (null != locale) { return locale; } // Tapestry 3.0: Engine stored in session under "org.apache.tapestry.engine:" + config.getServletName() // TODO: Tapestry 4+ { final List tapestryArray = new ArrayList(); for (Enumeration enumeration = in_session.getAttributeNames(); enumeration.hasMoreElements();) { String name = enumeration.nextElement(); if (name.indexOf("tapestry") > -1 && name.indexOf("engine") > -1 && null != in_session.getAttribute(name)) {//$NON-NLS-1$ //$NON-NLS-2$ tapestryArray.add(in_session.getAttribute(name)); } } if (tapestryArray.size() == 1) { // found a potential Engine! Let's call getLocale() on it. Object probableEngine = tapestryArray.get(0); if (null != probableEngine) { try { Method readMethod = probableEngine.getClass().getMethod("getLocale", (Class[])null);//$NON-NLS-1$ if (null != readMethod) { // Call the property getter and return the value Object possibleLocale = readMethod.invoke(probableEngine, (Object[]) null); if (null != possibleLocale && possibleLocale instanceof Locale) { locale = (Locale) possibleLocale; } } } catch (Exception e) { Throwable t = ExceptionUtils .unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); // stay silent } } } } if (null != locale) { return locale; } // Last guess: iterate over all attributes, to find a Locale // If there is only one, consider it to be /the/ locale { final List localeArray = new ArrayList(); for (Enumeration enumeration = in_session.getAttributeNames(); enumeration.hasMoreElements();) { String name = enumeration.nextElement(); Object obj = in_session.getAttribute(name); if (null != obj && obj instanceof Locale) { localeArray.add(obj); } } if (localeArray.size() == 1) { locale = (Locale) localeArray.get(0); } } return locale; } catch (IllegalStateException ise) { //ignore: invalidated session return null; } } /** * Try to get user from the session, if possible. * @param in_session * @return Object */ public static Object guessUserFromSession(final Session in_session) { if (null == in_session) { return null; } if (in_session.getPrincipal() != null) { return in_session.getPrincipal().getName(); } HttpSession httpSession = in_session.getSession(); if (httpSession == null) return null; try { Object user = null; // First search "known locations" for (int i = 0; i < USER_TEST_ATTRIBUTES.length; ++i) { Object obj = httpSession.getAttribute(USER_TEST_ATTRIBUTES[i]); if (null != obj) { user = obj; break; } obj = httpSession.getAttribute(USER_TEST_ATTRIBUTES[i].toLowerCase(Locale.ENGLISH)); if (null != obj) { user = obj; break; } obj = httpSession.getAttribute(USER_TEST_ATTRIBUTES[i].toUpperCase(Locale.ENGLISH)); if (null != obj) { user = obj; break; } } if (null != user) { return user; } // Last guess: iterate over all attributes, to find a java.security.Principal or javax.security.auth.Subject // If there is only one, consider it to be /the/ user { final List principalArray = new ArrayList(); for (Enumeration enumeration = httpSession.getAttributeNames(); enumeration.hasMoreElements();) { String name = enumeration.nextElement(); Object obj = httpSession.getAttribute(name); if (null != obj && (obj instanceof Principal || obj instanceof Subject)) { principalArray.add(obj); } } if (principalArray.size() == 1) { user = principalArray.get(0); } } if (null != user) { return user; } return user; } catch (IllegalStateException ise) { //ignore: invalidated session return null; } } public static long getUsedTimeForSession(Session in_session) { try { long diffMilliSeconds = in_session.getThisAccessedTime() - in_session.getCreationTime(); return diffMilliSeconds; } catch (IllegalStateException ise) { //ignore: invalidated session return -1; } } public static long getTTLForSession(Session in_session) { try { long diffMilliSeconds = (1000*in_session.getMaxInactiveInterval()) - (System.currentTimeMillis() - in_session.getThisAccessedTime()); return diffMilliSeconds; } catch (IllegalStateException ise) { //ignore: invalidated session return -1; } } public static long getInactiveTimeForSession(Session in_session) { try { long diffMilliSeconds = System.currentTimeMillis() - in_session.getThisAccessedTime(); return diffMilliSeconds; } catch (IllegalStateException ise) { //ignore: invalidated session return -1; } } } tomcat7-7.0.52/java/org/apache/catalina/manager/util/BaseSessionComparator.java0000644000175100017510000000317712271471332027362 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager.util; import java.util.Comparator; import org.apache.catalina.Session; /** * Comparator which permits to compare on a session's content * @author Cédrik LIME */ public abstract class BaseSessionComparator implements Comparator { /** * */ public BaseSessionComparator() { super(); } public abstract Comparable getComparableObject(Session session); /* (non-Javadoc) * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @SuppressWarnings("unchecked") @Override public final int compare(Session s1, Session s2) { Comparable c1 = getComparableObject(s1); Comparable c2 = getComparableObject(s2); return c1==null ? (c2==null ? 0 : -1) : (c2==null ? 1 : c1.compareTo((T)c2)); } } tomcat7-7.0.52/java/org/apache/catalina/manager/ManagerServlet.java0000644000175100017510000016542412271471332025062 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import java.util.Locale; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.naming.Binding; import javax.naming.NamingEnumeration; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Container; import org.apache.catalina.ContainerServlet; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Manager; import org.apache.catalina.Server; import org.apache.catalina.Session; import org.apache.catalina.Wrapper; import org.apache.catalina.core.StandardHost; import org.apache.catalina.core.StandardServer; import org.apache.catalina.util.ContextName; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; /** * Servlet that enables remote management of the web applications installed * within the same virtual host as this web application is. Normally, this * functionality will be protected by a security constraint in the web * application deployment descriptor. However, this requirement can be * relaxed during testing. *

    * This servlet examines the value returned by getPathInfo() * and related query parameters to determine what action is being requested. * The following actions and parameters (starting after the servlet path) * are supported: *

      *
    • /deploy?config={config-url} - Install and start a new * web application, based on the contents of the context configuration * file found at the specified URL. The docBase attribute * of the context configuration file is used to locate the actual * WAR or directory containing the application.
    • *
    • /deploy?config={config-url}&war={war-url}/ - Install and start * a new web application, based on the contents of the context * configuration file found at {config-url}, overriding the * docBase attribute with the contents of the web * application archive found at {war-url}.
    • *
    • /deploy?path=/xxx&war={war-url} - Install and start a new * web application attached to context path /xxx, based * on the contents of the web application archive found at the * specified URL.
    • *
    • /list - List the context paths of all currently installed web * applications for this virtual host. Each context will be listed with * the following format path:status:sessions. * Where path is the context path. Status is either running or stopped. * Sessions is the number of active Sessions.
    • *
    • /reload?path=/xxx - Reload the Java classes and resources for * the application at the specified path.
    • *
    • /resources?type=xxxx - Enumerate the available global JNDI * resources, optionally limited to those of the specified type * (fully qualified Java class name), if available.
    • *
    • /serverinfo - Display system OS and JVM properties. *
    • /sessions - Deprecated. Use expire. *
    • /expire?path=/xxx - List session idle timeinformation about the * web application attached to context path /xxx for this * virtual host.
    • *
    • /expire?path=/xxx&idle=mm - Expire sessions * for the context path /xxx which were idle for at * least mm minutes.
    • *
    • /start?path=/xxx - Start the web application attached to * context path /xxx for this virtual host.
    • *
    • /stop?path=/xxx - Stop the web application attached to * context path /xxx for this virtual host.
    • *
    • /undeploy?path=/xxx - Shutdown and remove the web application * attached to context path /xxx for this virtual host, * and remove the underlying WAR file or document base directory. * (NOTE - This is only allowed if the WAR file or document * base is stored in the appBase directory of this host, * typically as a result of being placed there via the /deploy * command.
    • *
    *

    Use path=/ for the ROOT context.

    *

    The syntax of the URL for a web application archive must conform to one * of the following patterns to be successfully deployed:

    *
      *
    • file:/absolute/path/to/a/directory - You can specify the absolute * path of a directory that contains the unpacked version of a web * application. This directory will be attached to the context path you * specify without any changes.
    • *
    • jar:file:/absolute/path/to/a/warfile.war!/ - You can specify a * URL to a local web application archive file. The syntax must conform to * the rules specified by the JarURLConnection class for a * reference to an entire JAR file.
    • *
    • jar:http://hostname:port/path/to/a/warfile.war!/ - You can specify * a URL to a remote (HTTP-accessible) web application archive file. The * syntax must conform to the rules specified by the * JarURLConnection class for a reference to an entire * JAR file.
    • *
    *

    * NOTE - Attempting to reload or remove the application containing * this servlet itself will not succeed. Therefore, this servlet should * generally be deployed as a separate web application within the virtual host * to be managed. *

    * The following servlet initialization parameters are recognized: *

      *
    • debug - The debugging detail level that controls the amount * of information that is logged by this servlet. Default is zero. *
    * * @author Craig R. McClanahan * @author Remy Maucherat */ public class ManagerServlet extends HttpServlet implements ContainerServlet { private static final long serialVersionUID = 1L; // ----------------------------------------------------- Instance Variables /** * Path where context descriptors should be deployed. */ protected File configBase = null; /** * The Context container associated with our web application. */ protected transient Context context = null; /** * The debugging detail level for this servlet. */ protected int debug = 1; /** * File object representing the directory into which the deploy() command * will store the WAR and context configuration files that have been * uploaded. */ protected File deployed = null; /** * Path used to store revisions of webapps. */ protected File versioned = null; /** * Path used to store context descriptors. * @deprecated Unused */ @Deprecated protected File contextDescriptors = null; /** * The associated host. */ protected transient Host host = null; /** * The host appBase. * @deprecated Unused */ @Deprecated protected File appBase = null; /** * MBean server. */ protected transient MBeanServer mBeanServer = null; /** * The associated deployer ObjectName. */ protected ObjectName oname = null; /** * The global JNDI NamingContext for this server, * if available. */ protected transient javax.naming.Context global = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The Wrapper container associated with this servlet. */ protected transient Wrapper wrapper = null; // ----------------------------------------------- ContainerServlet Methods /** * Return the Wrapper with which we are associated. */ @Override public Wrapper getWrapper() { return (this.wrapper); } /** * Set the Wrapper with which we are associated. * * @param wrapper The new wrapper */ @Override public void setWrapper(Wrapper wrapper) { this.wrapper = wrapper; if (wrapper == null) { context = null; host = null; oname = null; } else { context = (Context) wrapper.getParent(); host = (Host) context.getParent(); Engine engine = (Engine) host.getParent(); String name = engine.getName() + ":type=Deployer,host=" + host.getName(); try { oname = new ObjectName(name); } catch (Exception e) { log(sm.getString("managerServlet.objectNameFail", name), e); } } // Retrieve the MBean server mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); } // --------------------------------------------------------- Public Methods /** * Finalize this servlet. */ @Override public void destroy() { // No actions necessary } /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need String command = request.getPathInfo(); if (command == null) command = request.getServletPath(); String config = request.getParameter("config"); String path = request.getParameter("path"); ContextName cn = null; if (path != null) { cn = new ContextName(path, request.getParameter("version")); } String type = request.getParameter("type"); String war = request.getParameter("war"); String tag = request.getParameter("tag"); boolean update = false; if ((request.getParameter("update") != null) && (request.getParameter("update").equals("true"))) { update = true; } boolean statusLine = false; if ("true".equals(request.getParameter("statusLine"))) { statusLine = true; } // Prepare our output writer to generate the response message response.setContentType("text/plain; charset=" + Constants.CHARSET); PrintWriter writer = response.getWriter(); // Process the requested command (note - "/deploy" is not listed here) if (command == null) { writer.println(smClient.getString("managerServlet.noCommand")); } else if (command.equals("/deploy")) { if (war != null || config != null) { deploy(writer, config, cn, war, update, smClient); } else { deploy(writer, cn, tag, smClient); } } else if (command.equals("/list")) { list(writer, smClient); } else if (command.equals("/reload")) { reload(writer, cn, smClient); } else if (command.equals("/resources")) { resources(writer, type, smClient); } else if (command.equals("/save")) { save(writer, path, smClient); } else if (command.equals("/serverinfo")) { serverinfo(writer, smClient); } else if (command.equals("/sessions")) { expireSessions(writer, cn, request, smClient); } else if (command.equals("/expire")) { expireSessions(writer, cn, request, smClient); } else if (command.equals("/start")) { start(writer, cn, smClient); } else if (command.equals("/stop")) { stop(writer, cn, smClient); } else if (command.equals("/undeploy")) { undeploy(writer, cn, smClient); } else if (command.equals("/findleaks")) { findleaks(statusLine, writer, smClient); } else { writer.println(smClient.getString("managerServlet.unknownCommand", command)); } // Finish up the response writer.flush(); writer.close(); } /** * Process a PUT request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need String command = request.getPathInfo(); if (command == null) command = request.getServletPath(); String path = request.getParameter("path"); ContextName cn = null; if (path != null) { cn = new ContextName(path, request.getParameter("version")); } String tag = request.getParameter("tag"); boolean update = false; if ((request.getParameter("update") != null) && (request.getParameter("update").equals("true"))) { update = true; } // Prepare our output writer to generate the response message response.setContentType("text/plain;charset="+Constants.CHARSET); PrintWriter writer = response.getWriter(); // Process the requested command if (command == null) { writer.println(smClient.getString("managerServlet.noCommand")); } else if (command.equals("/deploy")) { deploy(writer, cn, tag, update, request, smClient); } else { writer.println(smClient.getString("managerServlet.unknownCommand", command)); } // Finish up the response writer.flush(); writer.close(); } /** * Initialize this servlet. */ @Override public void init() throws ServletException { // Ensure that our ContainerServlet properties have been set if ((wrapper == null) || (context == null)) throw new UnavailableException( sm.getString("managerServlet.noWrapper")); // Set our properties from the initialization parameters String value = null; try { value = getServletConfig().getInitParameter("debug"); debug = Integer.parseInt(value); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } // Acquire global JNDI resources if available Server server = ((Engine)host.getParent()).getService().getServer(); if (server != null) { global = server.getGlobalNamingContext(); } // Calculate the directory into which we will be deploying applications versioned = (File) getServletContext().getAttribute (ServletContext.TEMPDIR); // Identify the appBase of the owning Host of this Context // (if any) String appBase = ((Host) context.getParent()).getAppBase(); deployed = new File(appBase); if (!deployed.isAbsolute()) { deployed = new File(System.getProperty(Globals.CATALINA_BASE_PROP), appBase); } configBase = new File(System.getProperty(Globals.CATALINA_BASE_PROP), "conf"); Container container = context; Container host = null; Container engine = null; while (container != null) { if (container instanceof Host) host = container; if (container instanceof Engine) engine = container; container = container.getParent(); } if (engine != null) { configBase = new File(configBase, engine.getName()); } if (host != null) { configBase = new File(configBase, host.getName()); } // Note: The directory must exist for this to work. // Log debugging messages as necessary if (debug >= 1) { log("init: Associated with Deployer '" + oname + "'"); if (global != null) { log("init: Global resources are available"); } } } // -------------------------------------------------------- Private Methods /** * Find potential memory leaks caused by web application reload. */ protected void findleaks(boolean statusLine, PrintWriter writer, StringManager smClient) { if (!(host instanceof StandardHost)) { writer.println(smClient.getString("managerServlet.findleaksFail")); return; } String[] results = ((StandardHost) host).findReloadedContextMemoryLeaks(); if (results.length > 0) { if (statusLine) { writer.println( smClient.getString("managerServlet.findleaksList")); } for (String result : results) { if ("".equals(result)) { result = "/"; } writer.println(result); } } else if (statusLine) { writer.println(smClient.getString("managerServlet.findleaksNone")); } } /** * Store server configuration. * * @param path Optional context path to save */ protected synchronized void save(PrintWriter writer, String path, StringManager smClient) { Server server = ((Engine)host.getParent()).getService().getServer(); if (!(server instanceof StandardServer)) { writer.println(smClient.getString("managerServlet.saveFail", server)); return; } if ((path == null) || path.length() == 0 || !path.startsWith("/")) { try { ((StandardServer) server).storeConfig(); writer.println(smClient.getString("managerServlet.saved")); } catch (Exception e) { log("managerServlet.storeConfig", e); writer.println(smClient.getString("managerServlet.exception", e.toString())); return; } } else { String contextPath = path; if (path.equals("/")) { contextPath = ""; } Context context = (Context) host.findChild(contextPath); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", path)); return; } try { ((StandardServer) server).storeContext(context); writer.println(smClient.getString("managerServlet.savedContext", path)); } catch (Exception e) { log("managerServlet.save[" + path + "]", e); writer.println(smClient.getString("managerServlet.exception", e.toString())); return; } } } /** * Deploy a web application archive (included in the current request) * at the specified context path. * * @param writer Writer to render results to * @param cn Name of the application to be installed * @param tag Tag to be associated with the webapp * @param request Servlet request we are processing */ protected synchronized void deploy (PrintWriter writer, ContextName cn, String tag, boolean update, HttpServletRequest request, StringManager smClient) { if (debug >= 1) { log("deploy: Deploying web application '" + cn + "'"); } // Validate the requested context path if (!validateContextName(cn, writer, smClient)) { return; } String name = cn.getName(); String baseName = cn.getBaseName(); String displayPath = cn.getDisplayName(); // Check if app already exists, or undeploy it if updating Context context = (Context) host.findChild(name); if (update) { if (context != null) { undeploy(writer, cn, smClient); } context = (Context) host.findChild(name); } if (context != null) { writer.println(smClient.getString("managerServlet.alreadyContext", displayPath)); return; } // Calculate the base path File deployedPath = deployed; if (tag != null) { deployedPath = new File(versioned, tag); if (!deployedPath.mkdirs() && !deployedPath.isDirectory()) { writer.println(smClient.getString("managerServlet.mkdirFail", deployedPath)); return; } } // Upload the web application archive to a local WAR file File localWar = new File(deployedPath, baseName + ".war"); if (debug >= 2) { log("Uploading WAR file to " + localWar); } // Copy WAR to appBase try { if (!isServiced(name)) { addServiced(name); try { // Upload WAR uploadWar(writer, request, localWar, smClient); // Copy WAR and XML to the host app base if needed if (tag != null) { deployedPath = deployed; File localWarCopy = new File(deployedPath, baseName + ".war"); copy(localWar, localWarCopy); localWar = localWarCopy; copy(localWar, new File(getAppBase(), baseName + ".war")); } // Perform new deployment check(name); } finally { removeServiced(name); } } } catch (Exception e) { log("managerServlet.check[" + displayPath + "]", e); writer.println(smClient.getString("managerServlet.exception", e.toString())); return; } context = (Context) host.findChild(name); if (context != null && context.getConfigured()) { writer.println(smClient.getString( "managerServlet.deployed", displayPath)); } else { // Something failed writer.println(smClient.getString( "managerServlet.deployFailed", displayPath)); } } /** * Install an application for the specified path from the specified * web application archive. * * @param writer Writer to render results to * @param tag Revision tag to deploy from * @param cn Name of the application to be installed */ protected void deploy(PrintWriter writer, ContextName cn, String tag, StringManager smClient) { // Validate the requested context path if (!validateContextName(cn, writer, smClient)) { return; } String baseName = cn.getBaseName(); String name = cn.getName(); String displayPath = cn.getDisplayName(); // Calculate the base path File deployedPath = versioned; if (tag != null) { deployedPath = new File(deployedPath, tag); } // Find the local WAR file File localWar = new File(deployedPath, baseName + ".war"); // Check if app already exists, or undeploy it if updating Context context = (Context) host.findChild(name); if (context != null) { undeploy(writer, cn, smClient); } // Copy WAR to appBase try { if (!isServiced(name)) { addServiced(name); try { copy(localWar, new File(getAppBase(), baseName + ".war")); // Perform new deployment check(name); } finally { removeServiced(name); } } } catch (Exception e) { log("managerServlet.check[" + displayPath + "]", e); writer.println(smClient.getString("managerServlet.exception", e.toString())); return; } context = (Context) host.findChild(name); if (context != null && context.getConfigured()) { writer.println(smClient.getString("managerServlet.deployed", displayPath)); } else { // Something failed writer.println(smClient.getString("managerServlet.deployFailed", displayPath)); } } /** * Install an application for the specified path from the specified * web application archive. * * @param writer Writer to render results to * @param config URL of the context configuration file to be installed * @param cn Name of the application to be installed * @param war URL of the web application archive to be installed * @param update true to override any existing webapp on the path */ protected void deploy(PrintWriter writer, String config, ContextName cn, String war, boolean update, StringManager smClient) { if (config != null && config.length() == 0) { config = null; } if (war != null && war.length() == 0) { war = null; } if (debug >= 1) { if (config != null && config.length() > 0) { if (war != null) { log("install: Installing context configuration at '" + config + "' from '" + war + "'"); } else { log("install: Installing context configuration at '" + config + "'"); } } else { if (cn != null) { log("install: Installing web application '" + cn + "' from '" + war + "'"); } else { log("install: Installing web application from '" + war + "'"); } } } if (!validateContextName(cn, writer, smClient)) { return; } @SuppressWarnings("null") // checked in call above String name = cn.getName(); String baseName = cn.getBaseName(); String displayPath = cn.getDisplayName(); // Check if app already exists, or undeploy it if updating Context context = (Context) host.findChild(name); if (update) { if (context != null) { undeploy(writer, cn, smClient); } context = (Context) host.findChild(name); } if (context != null) { writer.println(smClient.getString("managerServlet.alreadyContext", displayPath)); return; } if (config != null && (config.startsWith("file:"))) { config = config.substring("file:".length()); } if (war != null && (war.startsWith("file:"))) { war = war.substring("file:".length()); } try { if (!isServiced(name)) { addServiced(name); try { if (config != null) { if (!configBase.mkdirs() && !configBase.isDirectory()) { writer.println(smClient.getString( "managerServlet.mkdirFail",configBase)); return; } copy(new File(config), new File(configBase, baseName + ".xml")); } if (war != null) { if (war.endsWith(".war")) { copy(new File(war), new File(getAppBase(), baseName + ".war")); } else { copy(new File(war), new File(getAppBase(), baseName)); } } // Perform new deployment check(name); } finally { removeServiced(name); } } context = (Context) host.findChild(name); if (context != null && context.getConfigured() && context.getState().isAvailable()) { writer.println(smClient.getString( "managerServlet.deployed", displayPath)); } else if (context!=null && !context.getState().isAvailable()) { writer.println(smClient.getString( "managerServlet.deployedButNotStarted", displayPath)); } else { // Something failed writer.println(smClient.getString( "managerServlet.deployFailed", displayPath)); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log("ManagerServlet.install[" + displayPath + "]", t); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } /** * Render a list of the currently active Contexts in our virtual host. * * @param writer Writer to render to */ protected void list(PrintWriter writer, StringManager smClient) { if (debug >= 1) log("list: Listing contexts for virtual host '" + host.getName() + "'"); writer.println(smClient.getString("managerServlet.listed", host.getName())); Container[] contexts = host.findChildren(); for (int i = 0; i < contexts.length; i++) { Context context = (Context) contexts[i]; if (context != null ) { String displayPath = context.getPath(); if( displayPath.equals("") ) displayPath = "/"; if (context.getState().isAvailable()) { writer.println(smClient.getString("managerServlet.listitem", displayPath, "running", "" + context.getManager().findSessions().length, context.getDocBase())); } else { writer.println(smClient.getString("managerServlet.listitem", displayPath, "stopped", "0", context.getDocBase())); } } } } /** * Reload the web application at the specified context path. * * @param writer Writer to render to * @param cn Name of the application to be restarted */ protected void reload(PrintWriter writer, ContextName cn, StringManager smClient) { if (debug >= 1) log("restart: Reloading web application '" + cn + "'"); if (!validateContextName(cn, writer, smClient)) { return; } try { Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", RequestUtil.filter(cn.getDisplayName()))); return; } // It isn't possible for the manager to reload itself if (context.getName().equals(this.context.getName())) { writer.println(smClient.getString("managerServlet.noSelf")); return; } context.reload(); writer.println(smClient.getString("managerServlet.reloaded", cn.getDisplayName())); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log("ManagerServlet.reload[" + cn.getDisplayName() + "]", t); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } /** * Render a list of available global JNDI resources. * * @param type Fully qualified class name of the resource type of interest, * or null to list resources of all types */ protected void resources(PrintWriter writer, String type, StringManager smClient) { if (debug >= 1) { if (type != null) { log("resources: Listing resources of type " + type); } else { log("resources: Listing resources of all types"); } } // Is the global JNDI resources context available? if (global == null) { writer.println(smClient.getString("managerServlet.noGlobal")); return; } // Enumerate the global JNDI resources of the requested type if (type != null) { writer.println(smClient.getString("managerServlet.resourcesType", type)); } else { writer.println(smClient.getString("managerServlet.resourcesAll")); } Class clazz = null; try { if (type != null) { clazz = Class.forName(type); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log("ManagerServlet.resources[" + type + "]", t); writer.println(smClient.getString("managerServlet.exception", t.toString())); return; } printResources(writer, "", global, type, clazz, smClient); } /** * List the resources of the given context. */ protected void printResources(PrintWriter writer, String prefix, javax.naming.Context namingContext, String type, Class clazz, StringManager smClient) { try { NamingEnumeration items = namingContext.listBindings(""); while (items.hasMore()) { Binding item = items.next(); if (item.getObject() instanceof javax.naming.Context) { printResources (writer, prefix + item.getName() + "/", (javax.naming.Context) item.getObject(), type, clazz, smClient); } else { if ((clazz != null) && (!(clazz.isInstance(item.getObject())))) { continue; } writer.print(prefix + item.getName()); writer.print(':'); writer.print(item.getClassName()); // Do we want a description if available? writer.println(); } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log("ManagerServlet.resources[" + type + "]", t); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } /** * Writes System OS and JVM properties. * @param writer Writer to render to */ protected void serverinfo(PrintWriter writer, StringManager smClient) { if (debug >= 1) log("serverinfo"); try { StringBuilder props = new StringBuilder(); props.append("OK - Server info"); props.append("\nTomcat Version: "); props.append(ServerInfo.getServerInfo()); props.append("\nOS Name: "); props.append(System.getProperty("os.name")); props.append("\nOS Version: "); props.append(System.getProperty("os.version")); props.append("\nOS Architecture: "); props.append(System.getProperty("os.arch")); props.append("\nJVM Version: "); props.append(System.getProperty("java.runtime.version")); props.append("\nJVM Vendor: "); props.append(System.getProperty("java.vm.vendor")); writer.println(props.toString()); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getServletContext().log("ManagerServlet.serverinfo",t); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } /** * Session information for the web application at the specified context path. * Displays a profile of session thisAccessedTime listing number * of sessions for each 10 minute interval up to 10 hours. * * @param writer Writer to render to * @param cn Name of the application to list session information for * @param idle Expire all sessions with idle time > idle for this context */ protected void sessions(PrintWriter writer, ContextName cn, int idle, StringManager smClient) { if (debug >= 1) { log("sessions: Session information for web application '" + cn + "'"); if (idle >= 0) log("sessions: Session expiration for " + idle + " minutes '" + cn + "'"); } if (!validateContextName(cn, writer, smClient)) { return; } String displayPath = cn.getDisplayName(); try { Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", RequestUtil.filter(displayPath))); return; } Manager manager = context.getManager() ; if(manager == null) { writer.println(smClient.getString("managerServlet.noManager", RequestUtil.filter(displayPath))); return; } int maxCount = 60; int maxInactiveInterval = manager.getMaxInactiveInterval()/60; int histoInterval = maxInactiveInterval / maxCount; if ( histoInterval * maxCount < maxInactiveInterval ) histoInterval++; if (0==histoInterval) histoInterval=1; maxCount = maxInactiveInterval / histoInterval; if ( histoInterval * maxCount < maxInactiveInterval ) maxCount++; writer.println(smClient.getString("managerServlet.sessions", displayPath)); writer.println(smClient.getString( "managerServlet.sessiondefaultmax", "" + maxInactiveInterval)); Session [] sessions = manager.findSessions(); int [] timeout = new int[maxCount]; int notimeout = 0; int expired = 0; long now = System.currentTimeMillis(); for (int i = 0; i < sessions.length; i++) { int time = (int)((now-sessions[i].getThisAccessedTimeInternal())/1000); if (idle >= 0 && time >= idle*60) { sessions[i].expire(); expired++; } time=time/60/histoInterval; if (time < 0) notimeout++; else if (time >= maxCount) timeout[maxCount-1]++; else timeout[time]++; } if (timeout[0] > 0) writer.println(smClient.getString( "managerServlet.sessiontimeout", "<" + histoInterval, "" + timeout[0])); for (int i = 1; i < maxCount-1; i++) { if (timeout[i] > 0) writer.println(smClient.getString( "managerServlet.sessiontimeout", "" + (i)*histoInterval + " - <" + (i+1)*histoInterval, "" + timeout[i])); } if (timeout[maxCount-1] > 0) writer.println(smClient.getString( "managerServlet.sessiontimeout", ">=" + maxCount*histoInterval, "" + timeout[maxCount-1])); if (notimeout > 0) writer.println(smClient.getString( "managerServlet.sessiontimeout.unlimited", "" + notimeout)); if (idle >= 0) writer.println(smClient.getString( "managerServlet.sessiontimeout.expired", "" + idle,"" + expired)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log("ManagerServlet.sessions[" + displayPath + "]", t); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } /** * Session information for the web application at the specified context path. * Displays a profile of session thisAccessedTime listing number * of sessions for each 10 minute interval up to 10 hours. * * @param writer Writer to render to * @param cn Name of the application to list session information for * * @deprecated Use {@link #sessions(PrintWriter, ContextName, int, * StringManager)} */ @Deprecated protected void sessions(PrintWriter writer, ContextName cn, StringManager smClient) { sessions(writer, cn, -1, smClient); } /** * * Extract the expiration request parameter * * @param cn * @param req */ protected void expireSessions(PrintWriter writer, ContextName cn, HttpServletRequest req, StringManager smClient) { int idle = -1; String idleParam = req.getParameter("idle"); if (idleParam != null) { try { idle = Integer.parseInt(idleParam); } catch (NumberFormatException e) { log("Could not parse idle parameter to an int: " + idleParam); } } sessions(writer, cn, idle, smClient); } /** * Start the web application at the specified context path. * * @param writer Writer to render to * @param cn Name of the application to be started */ protected void start(PrintWriter writer, ContextName cn, StringManager smClient) { if (debug >= 1) log("start: Starting web application '" + cn + "'"); if (!validateContextName(cn, writer, smClient)) { return; } String displayPath = cn.getDisplayName(); try { Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", RequestUtil.filter(displayPath))); return; } context.start(); if (context.getState().isAvailable()) writer.println(smClient.getString("managerServlet.started", displayPath)); else writer.println(smClient.getString("managerServlet.startFailed", displayPath)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getServletContext().log(sm.getString("managerServlet.startFailed", displayPath), t); writer.println(smClient.getString("managerServlet.startFailed", displayPath)); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } /** * Stop the web application at the specified context path. * * @param writer Writer to render to * @param cn Name of the application to be stopped */ protected void stop(PrintWriter writer, ContextName cn, StringManager smClient) { if (debug >= 1) log("stop: Stopping web application '" + cn + "'"); if (!validateContextName(cn, writer, smClient)) { return; } String displayPath = cn.getDisplayName(); try { Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", RequestUtil.filter(displayPath))); return; } // It isn't possible for the manager to stop itself if (context.getName().equals(this.context.getName())) { writer.println(smClient.getString("managerServlet.noSelf")); return; } context.stop(); writer.println(smClient.getString( "managerServlet.stopped", displayPath)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log("ManagerServlet.stop[" + displayPath + "]", t); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } /** * Undeploy the web application at the specified context path. * * @param writer Writer to render to * @param cn Name of the application to be removed */ protected void undeploy(PrintWriter writer, ContextName cn, StringManager smClient) { if (debug >= 1) log("undeploy: Undeploying web application at '" + cn + "'"); if (!validateContextName(cn, writer, smClient)) { return; } String name = cn.getName(); String baseName = cn.getBaseName(); String displayPath = cn.getDisplayName(); try { // Validate the Context of the specified application Context context = (Context) host.findChild(name); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", RequestUtil.filter(displayPath))); return; } if (!isDeployed(name)) { writer.println(smClient.getString("managerServlet.notDeployed", RequestUtil.filter(displayPath))); return; } if (!isServiced(name)) { addServiced(name); try { // Try to stop the context first to be nicer context.stop(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } try { File war = new File(getAppBase(), baseName + ".war"); File dir = new File(getAppBase(), baseName); File xml = new File(configBase, baseName + ".xml"); if (war.exists() && !war.delete()) { writer.println(smClient.getString( "managerServlet.deleteFail", war)); return; } else if (dir.exists() && !undeployDir(dir)) { writer.println(smClient.getString( "managerServlet.deleteFail", dir)); return; } else if (xml.exists() && !xml.delete()) { writer.println(smClient.getString( "managerServlet.deleteFail", xml)); return; } // Perform new deployment check(name); } finally { removeServiced(name); } } writer.println(smClient.getString("managerServlet.undeployed", displayPath)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log("ManagerServlet.undeploy[" + displayPath + "]", t); writer.println(smClient.getString("managerServlet.exception", t.toString())); } } // -------------------------------------------------------- Support Methods /** * Return a File object representing the "application root" directory * for our associated Host. */ protected File getAppBase() { if (appBase != null) { return appBase; } File file = new File(host.getAppBase()); if (!file.isAbsolute()) file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), host.getAppBase()); try { appBase = file.getCanonicalFile(); } catch (IOException e) { appBase = file; } return (appBase); } /** * Invoke the isDeployed method on the deployer. */ protected boolean isDeployed(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; Boolean result = (Boolean) mBeanServer.invoke(oname, "isDeployed", params, signature); return result.booleanValue(); } /** * Invoke the check method on the deployer. */ protected void check(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; mBeanServer.invoke(oname, "check", params, signature); } /** * Invoke the isServiced method on the deployer. */ protected boolean isServiced(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced", params, signature); return result.booleanValue(); } /** * Invoke the addServiced method on the deployer. */ protected void addServiced(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; mBeanServer.invoke(oname, "addServiced", params, signature); } /** * Invoke the removeServiced method on the deployer. */ protected void removeServiced(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; mBeanServer.invoke(oname, "removeServiced", params, signature); } /** * Delete the specified directory, including all of its contents and * subdirectories recursively. The code assumes that the directory exists. * * @param dir File object representing the directory to be deleted. */ protected boolean undeployDir(File dir) { String files[] = dir.list(); if (files == null) { files = new String[0]; } for (int i = 0; i < files.length; i++) { File file = new File(dir, files[i]); if (file.isDirectory()) { if (!undeployDir(file)) { return false; } } else { if (!file.delete()) { return false; } } } return dir.delete(); } /** * Upload the WAR file included in this request, and store it at the * specified file location. * * @param writer Writer to render to * @param request The servlet request we are processing * @param war The file into which we should store the uploaded WAR * @param smClient The StringManager used to construct i18n messages based * on the Locale of the client * * @exception IOException if an I/O error occurs during processing */ protected void uploadWar(PrintWriter writer, HttpServletRequest request, File war, StringManager smClient) throws IOException { if (war.exists() && !war.delete()) { String msg = smClient.getString("managerServlet.deleteFail", war); throw new IOException(msg); } ServletInputStream istream = null; BufferedOutputStream ostream = null; try { istream = request.getInputStream(); ostream = new BufferedOutputStream(new FileOutputStream(war), 1024); byte buffer[] = new byte[1024]; while (true) { int n = istream.read(buffer); if (n < 0) { break; } ostream.write(buffer, 0, n); } ostream.flush(); ostream.close(); ostream = null; istream.close(); istream = null; } catch (IOException e) { if (war.exists() && !war.delete()) { writer.println( smClient.getString("managerServlet.deleteFail", war)); } throw e; } finally { if (ostream != null) { try { ostream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } ostream = null; } if (istream != null) { try { istream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } istream = null; } } } /** * @deprecated Use {@link StringManager#getManager(String, Enumeration)}. * This method will be removed in Tomcat 8. */ @Deprecated protected StringManager getStringManager(HttpServletRequest req) { Enumeration requestedLocales = req.getLocales(); while (requestedLocales.hasMoreElements()) { Locale locale = requestedLocales.nextElement(); StringManager result = StringManager.getManager(Constants.Package, locale); if (result.getLocale().equals(locale)) { return result; } } // Return the default return sm; } protected static boolean validateContextName(ContextName cn, PrintWriter writer, StringManager sm) { // ContextName should be non-null with a path that is empty or starts // with / if (cn != null && (cn.getPath().startsWith("/") || cn.getPath().equals(""))) { return true; } String path = null; if (cn != null) { path = RequestUtil.filter(cn.getPath()); } writer.println(sm.getString("managerServlet.invalidPath", path)); return false; } /** * Copy the specified file or directory to the destination. * * @param src File object representing the source * @param dest File object representing the destination */ public static boolean copy(File src, File dest) { boolean result = false; try { if( src != null && !src.getCanonicalPath().equals(dest.getCanonicalPath()) ) { result = copyInternal(src, dest, new byte[4096]); } } catch (IOException e) { e.printStackTrace(); } return result; } /** * Copy the specified file or directory to the destination. * * @param src File object representing the source * @param dest File object representing the destination */ public static boolean copyInternal(File src, File dest, byte[] buf) { boolean result = true; String files[] = null; if (src.isDirectory()) { files = src.list(); result = dest.mkdir(); } else { files = new String[1]; files[0] = ""; } if (files == null) { files = new String[0]; } for (int i = 0; (i < files.length) && result; i++) { File fileSrc = new File(src, files[i]); File fileDest = new File(dest, files[i]); if (fileSrc.isDirectory()) { result = copyInternal(fileSrc, fileDest, buf); } else { FileInputStream is = null; FileOutputStream os = null; try { is = new FileInputStream(fileSrc); os = new FileOutputStream(fileDest); int len = 0; while (true) { len = is.read(buf); if (len == -1) break; os.write(buf, 0, len); } } catch (IOException e) { e.printStackTrace(); result = false; } finally { if (is != null) { try { is.close(); } catch (IOException e) { // Ignore } } if (os != null) { try { os.close(); } catch (IOException e) { // Ignore } } } } } return result; } } tomcat7-7.0.52/java/org/apache/catalina/manager/LocalStrings_fr.properties0000644000175100017510000001716312271471332026505 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. htmlManagerServlet.appsAvailable=Fonctionnelle htmlManagerServlet.appsName=Nom d''affichage htmlManagerServlet.appsPath=Chemin htmlManagerServlet.appsReload=Recharger htmlManagerServlet.appsUndeploy=Retirer htmlManagerServlet.appsExpire=Expirer les sessions htmlManagerServlet.appsSessions=Sessions htmlManagerServlet.appsStart=D\u00e9marrer htmlManagerServlet.appsStop=Arr\u00eater htmlManagerServlet.appsTasks=Commandes htmlManagerServlet.appsTitle=Applications htmlManagerServlet.expire.explain=inactives depuis ≥ htmlManagerServlet.expire.unit=minutes htmlManagerServlet.helpHtmlManager=Aide HTML Gestionnaire htmlManagerServlet.helpHtmlManagerFile=../docs/html-manager-howto.html htmlManagerServlet.helpManager=Aide Gestionnaire htmlManagerServlet.helpManagerFile=../docs/manager-howto.html htmlManagerServlet.deployButton=Deployer htmlManagerServlet.deployConfig=URL du fichier XML de configuration: htmlManagerServlet.deployPath=Chemin de context (requis): htmlManagerServlet.deployServer=Emplacement du r\u00e9pertoire ou fichier WAR de d\u00e9ploiement sur le serveur htmlManagerServlet.deployTitle=Deployer htmlManagerServlet.deployUpload=Fichier WAR \u00e0 d\u00e9ployer htmlManagerServlet.deployUploadFail=ECHEC - T\u00e9l\u00e9versement pour d\u00e9ploiement a \u00e9chou\u00e9, exception: {0} htmlManagerServlet.deployUploadFile=Choisir le fichier WAR \u00e0 t\u00e9l\u00e9verser htmlManagerServlet.deployUploadInServerXml=ECHEC - Fichier WAR \"{0}\" ne peut \u00eatre t\u00e9l\u00e9vers\u00e9 lorsque le contexte est d\u00e9fini dans server.xml htmlManagerServlet.deployUploadNotWar=ECHEC - Fichier \u00e0 t\u00e9l\u00e9verser, \"{0}\", doit \u00eatre un .war htmlManagerServlet.deployUploadNoFile=ECHEC - T\u00e9l\u00e9versement a \u00e9chou\u00e9, aucun fichier htmlManagerServlet.deployUploadWarExists=ECHEC - Fichier War \"{0}\" d\u00e9j\u00ea existant sur le serveur htmlManagerServlet.deployWar=URL vers WAR ou r\u00e9pertoire: htmlManagerServlet.list=Lister les applications htmlManagerServlet.manager=Gestionnaire htmlManagerServlet.messageLabel=Message: htmlManagerServlet.noManager=- htmlManagerServlet.serverJVMVendor=Fournisseur de la JVM htmlManagerServlet.serverJVMVersion=Version de la JVM htmlManagerServlet.serverOSArch=Architecture d''OS htmlManagerServlet.serverOSName=Nom d''OS htmlManagerServlet.serverOSVersion=Version d''OS htmlManagerServlet.serverTitle=Serveur htmlManagerServlet.serverVersion=Version de serveur htmlManagerServlet.title=Gestionnaire d''applications WEB Tomcat managerServlet.alreadyContext=ECHEC - l''application existe d\u00e9j\u00e0 dans le chemin {0} managerServlet.alreadyDocBase=ECHEC - Le r\u00e9pertoire {0} est d\u00e9j\u00e0 utilis\u00e9 managerServlet.configured=OK - Application configur\u00e9e depuis le fichier contexte {0} managerServlet.deployed=OK - Application d\u00e9ploy\u00e9e pour le chemin de contexte {0} managerServlet.deployFailed=ECHEC - Echec au d\u00e9ploiement de l''application pour le chemin de contexte {0} managerServlet.deployedButNotStarted=ECHEC - Application d\u00e9ploy\u00e9e pour le chemin de contexte {0} mais le d\u00e9marrage du contexte a \u00e9chou\u00e9 managerServlet.exception=ECHEC - L''exception {0} a \u00e9t\u00e9 rencontr\u00e9e managerServlet.invalidPath=ECHEC - Un chemin de contexte invalide {0} a \u00e9t\u00e9 sp\u00e9cifi\u00e9 managerServlet.invalidWar=ECHEC - Une URL d''application invalide {0} a \u00e9t\u00e9 sp\u00e9cifi\u00e9e managerServlet.listed=OK - Applications list\u00e9es pour l''h\u00f4te virtuel (virtual host) {0} managerServlet.listitem={0}:{1}:{2}:{3} managerServlet.noAppBase=ECHEC - Impossible d''identifier la base de l''application base pour le chemin de contexte {0} managerServlet.noCommand=ECHEC - Aucune commande n''a \u00e9t\u00e9 sp\u00e9cifi\u00e9e managerServlet.noContext=ECHEC - Aucun contexte n''existe pour le chemin {0} managerServlet.noDirectory=ECHEC - La base de document n''est pas un r\u00e9pertoire pour le chemin {0} managerServlet.noDocBase=ECHEC - Impossible de retirer la base de document pour le chemin {0} managerServlet.noGlobal=ECHEC - Aucune ressource JNDI globale n''est disponible managerServlet.noManager=ECHEC - Aucun gestionnaire n''existe pour le chemin {0} managerServlet.noReload=ECHEC - Rechargement non support\u00e9 par le WAR d\u00e9ploy\u00e9 au chemin {0} managerServlet.noRename=ECHEC - Impossible de d\u00e9ployer un WAR t\u00e9l\u00e9charg\u00e9 pour le chemin {0} managerServlet.noRole=ECHEC - L''utilisateur ne poss\u00e8de pas le r\u00f4le {0} managerServlet.noSelf=ECHEC - Le gestionnaire ne peut se recharger, se retirer, s''arr\u00eater, ou se d\u00e9ployer lui-m\u00eame managerServlet.noWrapper=Le conteneur n''a pas appel\u00e9 "setWrapper()" pour cette servlet managerServlet.notDeployed=ECHEC - Le contexte {0} est d\u00e9fini dans server.xml et ne peut \u00eatre retir\u00e9 managerServlet.reloaded=OK - L''application associ\u00e9e au chemin de contexte {0} a \u00e9t\u00e9 recharg\u00e9e managerServlet.resourcesAll=OK - Liste des ressources globales de tout type managerServlet.resourcesType=OK - Liste des ressources globales de type {0} managerServlet.saveFail=ECHEC - La sauvegarde de la configuration a \u00e9chou\u00e9: {0} managerServlet.saved=OK - Configuration serveur sauvegard\u00e9e managerServlet.savedContext=OK - Configuration du contexte {0} sauvegard\u00e9e managerServlet.sessiondefaultmax=Interval par d\u00e9faut de maximum de session inactive {0} minutes #TODO: Please review the following three messages. These are displayed when "Expire sessions" button is pressed in the Manager webapp: managerServlet.sessiontimeout={0} minutes: {1} sessions managerServlet.sessiontimeout.unlimited=unlimited time: {0} sessions managerServlet.sessiontimeout.expired={0} minutes: {1} sessions were expired managerServlet.sessions=OK - Information de session pour l''application au chemin de contexte {0} managerServlet.started=OK - Application d\u00e9marr\u00e9e pour le chemin de contexte {0} managerServlet.startFailed=ECHEC - L''application pour le chemin de contexte {0} n''a pas pu \u00eatre d\u00e9marr\u00e9e managerServlet.stopped=OK - Application arr\u00eat\u00e9e pour le chemin de contexte {0} managerServlet.undeployed=OK - L''application associ\u00e9e au chemin de contexte {0} a \u00e9t\u00e9 retir\u00e9e managerServlet.startFailed=ECHEC - L''application pour le chemin de contexte {0} n''a pas pu \u00eatre d\u00e9marr\u00e9e managerServlet.stopped=OK - Application arr\u00eat\u00e9e pour le chemin de contexte {0} managerServlet.undeployed=OK - Application non d\u00e9ploy\u00e9e pour le chemin de contexte {0} managerServlet.unknownCommand=ECHEC - Commande inconnue {0} managerServlet.userDatabaseError=ECHEC - Impossible de r\u00e9soudre la base de donn\u00e9es utilisateurs de r\u00e9f\u00e9rence managerServlet.userDatabaseMissing=ECHEC - Aucune base de donn\u00e9es utilisateurs n''est disponible statusServlet.title=Etat du serveur statusServlet.complete=Etat complet du serveur tomcat7-7.0.52/java/org/apache/catalina/manager/LocalStrings_de.properties0000644000175100017510000001365412271471332026467 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. htmlManagerServlet.appsAvailable=Verf\u00fcgbar htmlManagerServlet.appsName=Anzeigename htmlManagerServlet.appsPath=Kontext Pfad htmlManagerServlet.appsReload=Neu laden htmlManagerServlet.appsUndeploy=Entfernen htmlManagerServlet.appsExpire=L\u00f6sche Sitzungen htmlManagerServlet.appsSessions=Sitzungen htmlManagerServlet.appsStart=Start htmlManagerServlet.appsStop=Stop htmlManagerServlet.appsTasks=Kommandos htmlManagerServlet.appsTitle=Anwendungen htmlManagerServlet.expire.explain=mit Inaktivit\u00e4t ≥ htmlManagerServlet.expire.unit=Minuten htmlManagerServlet.helpHtmlManager=Hilfeseite HTML Manager (englisch) htmlManagerServlet.helpHtmlManagerFile=../docs/html-manager-howto.html htmlManagerServlet.helpManager=Hilfeseite Manager (englisch) htmlManagerServlet.helpManagerFile=../docs/manager-howto.html htmlManagerServlet.deployButton=Installieren htmlManagerServlet.deployConfig=XML Konfigurationsdatei URL: htmlManagerServlet.deployPath=Kontext Pfad (optional): htmlManagerServlet.deployServer=Verzeichnis oder WAR Datei auf Server installieren htmlManagerServlet.deployTitle=Installieren htmlManagerServlet.deployUpload=Lokale WAR Datei zur Installation hochladen htmlManagerServlet.deployUploadFail=FEHLER - Hochladen zur Installation fehlgeschlagen, Ausnahme: {0} htmlManagerServlet.deployUploadFile=WAR Datei ausw\u00e4hlen htmlManagerServlet.deployUploadNotWar=FEHLER - Hochgeladene Datei \"{0}\" muss ein .war sein htmlManagerServlet.deployUploadNoFile=FEHLER - Hochladen fehlgeschlagen, keine Datei vorhanden htmlManagerServlet.deployUploadWarExists=FEHLER - WAR Datei \"{0}\" existiert bereits auf Server htmlManagerServlet.deployWar=WAR oder Verzeichnis URL: htmlManagerServlet.list=Anwendungen auflisten htmlManagerServlet.manager=Manager htmlManagerServlet.messageLabel=Nachricht: htmlManagerServlet.serverJVMVendor=JVM Hersteller htmlManagerServlet.serverJVMVersion=JVM Version htmlManagerServlet.serverOSArch=OS Architektur htmlManagerServlet.serverOSName=OS Name htmlManagerServlet.serverOSVersion=OS Version htmlManagerServlet.serverTitle=Server Informationen htmlManagerServlet.serverVersion=Tomcat Version htmlManagerServlet.title=Tomcat Webanwendungs-Manager managerServlet.alreadyContext=FEHLER - Anwendung existiert bereits f\u00fcr Kontext Pfad {0} managerServlet.alreadyDocBase=FEHLER - Verzeichnis {0} bereits in Benutzung managerServlet.configured=OK - Anwendung von Kontext-Datei {0} installiert managerServlet.deployed=OK - Anwendung mit Kontext Pfad {0} installiert managerServlet.exception=FEHLER - Ausnahme aufgetreten {0} managerServlet.invalidPath=FEHLER - Ung\u00fcltiger Kontext Pfad {0} angegeben managerServlet.invalidWar=FEHLER - Ung\u00fcltige URL {0} f\u00fcr Anwendung angegeben managerServlet.listed=OK - Auflistung der Webanwendungen f\u00fcr virtuellen Server {0} managerServlet.listitem={0}:{1}:{2}:{3} managerServlet.noAppBase=FEHLER - Kann Verzeichnis f\u00fcr Kontext Pfad {0} nicht finden managerServlet.noCommand=FEHLER - Es wurde kein Kommando angegeben managerServlet.noContext=FEHLER - Es existiert kein Kontext f\u00fcr Pfad {0} managerServlet.noDirectory=FEHLER - Pfad {0} ist kein Verzeichnis managerServlet.noDocBase=FEHLER - Kann Webanwendungs-Verzeichnis nicht entfernen f\u00fcr Kontext Pfad {0} managerServlet.noGlobal=FEHLER - Keine globalen JNDI Ressourcen verf\u00fcgbar managerServlet.noReload=FEHLER - Neu laden nicht unterst\u00fctzt f\u00fcr WAR mit Pfad {0} managerServlet.noRename=FEHLER - Kann hochgeladenes WAR mit Pfad {0} nicht installieren managerServlet.noRole=FEHLER - Benutzer nicht in Rolle {0} managerServlet.noSelf=FEHLER - Manager-Kommandos k\u00f6nnen nicht auf die Manager-Anwendung selbst angewendet werden managerServlet.noWrapper=Container hat setWrapper() f\u00fcr dieses Servlet nicht aufgerufen managerServlet.reloaded=OK - Anwendung mit Kontext Pfad {0} neu geladen managerServlet.resourcesAll=OK - Auflistung globaler Ressourcen (alle Typen) managerServlet.resourcesType=OK - Auflistung globaler Ressourcen von Typ {0} managerServlet.saveFail=FEHLER - Speichern der Konfiguration fehlgeschlagen: {0} managerServlet.sessiondefaultmax=Voreingestellter Sitzungsablauf nach maximal {0} Minuten Inaktivit\u00e4t #TODO: Please review the following three messages. These are displayed when "Expire sessions" button is pressed in the Manager webapp: managerServlet.sessiontimeout={0} Minuten: {1} Sitzungen managerServlet.sessiontimeout.unlimited=unlimited Minuten: {0} Sitzungen managerServlet.sessiontimeout.expired={0} Minuten: expired {1} Sitzungen managerServlet.sessions=OK - Sitzungs-Informationen f\u00fcr Anwendung mit Kontext Pfad {0} managerServlet.started=OK - Anwendung mit Kontext Pfad {0} gestartet managerServlet.startFailed=FEHLER - Anwendung mit Kontext Pfad {0} konnte nicht gestartet werden managerServlet.stopped=OK - Anwendung mit Kontext Pfad {0} gestoppt managerServlet.undeployed=OK - Anwendung mit Kontext Pfad {0} entfernt managerServlet.unknownCommand=FEHLER - Unbekanntes Kommando {0} managerServlet.userDatabaseError=FEHLER - Kann Referenz auf Benutzerdatendank nicht aufl\u00f6sen managerServlet.userDatabaseMissing=FEHLER - Keine Benutzerdatenbank vorhanden statusServlet.title=Server Status statusServlet.complete=Ausf\u00fchrlicher Server Status tomcat7-7.0.52/java/org/apache/catalina/manager/host/0000755000175100017510000000000012301126370022232 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/manager/host/LocalStrings_es.properties0000644000175100017510000001211612271471332027453 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. hostManagerServlet.alreadyStarted = FALLO - La m\u00E1qiuina [{0}] ya ha arrancado hostManagerServlet.alreadyStopped = FALLO - La m\u00E1quina [{0}] ya se ha parado hostManagerServlet.appBaseCreateFail = FALLO - No pude crear appBase [{0}] para la m\u00E1quina [{1}] hostManagerServlet.configBaseCreateFail = FALLO - No pude identificar configBase para la m\u00E1quina [{0}] hostManagerServlet.noCommand = FALLO - No se ha especificado comando hostManagerServlet.postCommand = FALLO - Intent\u00E9 usar el comando {0} v\u00EDa un requerimiento GET pero es necesario POST hostManagerServlet.unknownCommand = FALLO - Comando desconocido {0} hostManagerServlet.noWrapper = El contenedor no ha llamado a setWrapper() para este servlet hostManagerServlet.invalidHostName = FALLO - Se ha especificado un nombre inv\u00E1lido de m\u00E1quina {0} hostManagerServlet.noHost = FALLO - El nombre de m\u00E1quina {0} no existe hostManagerServlet.alreadyHost = FALLO - Ya existe m\u00E1quina con nombre de m\u00E1quina {0} hostManagerServlet.managerXml = FALLO - no pude instalar manager.xml hostManagerServlet.exception = FALLO - Encontrada excepci\u00F3n {0} hostManagerServlet.add = a\u00F1adir\: A\u00F1adiendo m\u00E1quina [{0}] hostManagerServlet.addFailed = FALLO - No pude a\u00F1adir m\u00E1quina {0} hostManagerServlet.cannotRemoveOwnHost = FALLO - No puedo quitar m\u00E1quina propia {0} hostManagerServlet.remove = quitar\: Quitando m\u00E1quina [{0}] hostManagerServlet.removeFailed = FALLO - No pude quitar m\u00E1quina {0} hostManagerServlet.listed = OK - M\u00E1quinas listadas hostManagerServlet.listitem = {0}\:{1} hostManagerServlet.cannotStartOwnHost = FALLO - No puedo empezar m\u00E1quina propia {0} hostManagerServlet.started = OK - M\u00E1quina {0} arrancada hostManagerServlet.startFailed = FALLO - No pude arrancar m\u00E1quina {0} hostManagerServlet.cannotStopOwnHost = FALLO - No puedo para m\u00E1quina propia {0} hostManagerServlet.stopped = OK - M\u00E1quina {0} parada hostManagerServlet.stopFailed = FALLO - No pude parar m\u00E1quina {0} hostManagerServlet.add = a\u00F1adir\: A\u00F1adiendo m\u00E1quina [{0}] hostManagerServlet.remove = quitar\: Quitando m\u00E1quina [{0}] hostManagerServlet.list = listar\: Listando m\u00E1quinas para motor [{0}] hostManagerServlet.start = arrancar\: Arrancando m\u00E1quina con nombre [{0}] hostManagerServlet.stop = parar\: Parando m\u00E1quina con nombre [{0}] htmlHostManagerServlet.title = Gestor de M\u00E1quina Virtual de Tomcat htmlHostManagerServlet.messageLabel = Mensaje\: htmlHostManagerServlet.manager = Gestor de M\u00E1quina htmlHostManagerServlet.list = Lista de M\u00E1quinas Virtuales htmlHostManagerServlet.helpHtmlManagerFile = html-host-manager-howto.html htmlHostManagerServlet.helpHtmlManager = Ayuda de Gestor de M\u00E1quina HTML (\u00A1En breve\!) htmlHostManagerServlet.helpManagerFile = ../docs/host-manager-howto.html htmlHostManagerServlet.helpManager = Ayuda de Gestor de M\u00E1quina htmlHostManagerServlet.hostName = Nombre de M\u00E1quina htmlHostManagerServlet.hostAliases = Aliases de M\u00E1quina htmlHostManagerServlet.hostTasks = Comandos htmlHostManagerServlet.hostsStart = Iniciar htmlHostManagerServlet.hostsStop = Parar htmlHostManagerServlet.hostsRemove = Quitar htmlHostManagerServlet.hostThis = Instalado Gestor de M\u00E1quinas - comandos deactivados htmlHostManagerServlet.addTitle = A\u00F1adir M\u00E1quina Virtual htmlHostManagerServlet.addHost = M\u00E1quina htmlHostManagerServlet.addName = Nombre\: htmlHostManagerServlet.addAliases = Aliases\: htmlHostManagerServlet.addAppBase = App base\: htmlHostManagerServlet.addManager = App de Gestor htmlHostManagerServlet.addAutoDeploy = AutoDeploy htmlHostManagerServlet.addDeployOnStartup = DeployOnStartup htmlHostManagerServlet.addDeployXML = DeployXML htmlHostManagerServlet.addUnpackWARs = UnpackWARs htmlHostManagerServlet.addButton = A\u00F1adir htmlHostManagerServlet.serverTitle = Informaci\u00F3n de Servidor htmlHostManagerServlet.serverVersion = Versi\u00F3n de Tomcat htmlHostManagerServlet.serverJVMVersion = Versi\u00F3n de JVM htmlHostManagerServlet.serverJVMVendor = Vendedor JVM htmlHostManagerServlet.serverOSName = Nombre de SO htmlHostManagerServlet.serverOSVersion = Versi\u00F3n de SO htmlHostManagerServlet.serverOSArch = Arquitectura de SO statusServlet.title = Estado de Servidor statusServlet.complete = Completar Estado de Servidor tomcat7-7.0.52/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java0000644000175100017510000004715712271471332027364 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager.host; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URLEncoder; import java.text.MessageFormat; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Container; import org.apache.catalina.Host; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.tomcat.util.res.StringManager; /** * Servlet that enables remote management of the virtual hosts deployed * on the server. Normally, this functionality will be protected by a security * constraint in the web application deployment descriptor. However, * this requirement can be relaxed during testing. *

    * The difference between the HostManagerServlet and this * Servlet is that this Servlet prints out a HTML interface which * makes it easier to administrate. *

    * However if you use a software that parses the output of * HostManagerServlet you won't be able to upgrade * to this Servlet since the output are not in the * same format as from HostManagerServlet * * @author Bip Thelin * @author Malcolm Edgar * @author Glenn L. Nielsen * @author Peter Rossbach * @see org.apache.catalina.manager.ManagerServlet */ public final class HTMLHostManagerServlet extends HostManagerServlet { private static final long serialVersionUID = 1L; // --------------------------------------------------------- Public Methods /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need String command = request.getPathInfo(); // Prepare our output writer to generate the response message response.setContentType("text/html; charset=" + Constants.CHARSET); String message = ""; // Process the requested command if (command == null) { // No command == list } else if (command.equals("/list")) { // Nothing to do - always generate list } else if (command.equals("/add") || command.equals("/remove") || command.equals("/start") || command.equals("/stop")) { message = smClient.getString( "hostManagerServlet.postCommand", command); } else { message = smClient.getString( "hostManagerServlet.unknownCommand", command); } list(request, response, message, smClient); } /** * Process a POST request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need String command = request.getPathInfo(); String name = request.getParameter("name"); // Prepare our output writer to generate the response message response.setContentType("text/html; charset=" + Constants.CHARSET); String message = ""; // Process the requested command if (command == null) { // No command == list } else if (command.equals("/add")) { message = add(request, name, smClient); } else if (command.equals("/remove")) { message = remove(name, smClient); } else if (command.equals("/start")) { message = start(name, smClient); } else if (command.equals("/stop")) { message = stop(name, smClient); } else { //Try GET doGet(request, response); } list(request, response, message, smClient); } /** * Add a host using the specified parameters. * * @param name host name */ protected String add(HttpServletRequest request,String name, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.add(request,printWriter,name,true, smClient); return stringWriter.toString(); } /** * Remove the specified host. * * @param name host name */ protected String remove(String name, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.remove(printWriter, name, smClient); return stringWriter.toString(); } /** * Start the host with the specified name. * * @param name Host name */ protected String start(String name, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.start(printWriter, name, smClient); return stringWriter.toString(); } /** * Stop the host with the specified name. * * @param name Host name */ protected String stop(String name, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.stop(printWriter, name, smClient); return stringWriter.toString(); } /** * Render a HTML list of the currently active Contexts in our virtual host, * and memory and server status information. * * @param request The request * @param response The response * @param message a message to display */ public void list(HttpServletRequest request, HttpServletResponse response, String message, StringManager smClient) throws IOException { if (debug >= 1) { log(sm.getString("hostManagerServlet.list", engine.getName())); } PrintWriter writer = response.getWriter(); // HTML Header Section writer.print(org.apache.catalina.manager.Constants.HTML_HEADER_SECTION); // Body Header Section Object[] args = new Object[2]; args[0] = request.getContextPath(); args[1] = smClient.getString("htmlHostManagerServlet.title"); writer.print(MessageFormat.format (Constants.BODY_HEADER_SECTION, args)); // Message Section args = new Object[3]; args[0] = smClient.getString("htmlHostManagerServlet.messageLabel"); if (message == null || message.length() == 0) { args[1] = "OK"; } else { args[1] = RequestUtil.filter(message); } writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args)); // Manager Section args = new Object[9]; args[0] = smClient.getString("htmlHostManagerServlet.manager"); args[1] = response.encodeURL(request.getContextPath() + "/html/list"); args[2] = smClient.getString("htmlHostManagerServlet.list"); args[3] = response.encodeURL (request.getContextPath() + "/" + smClient.getString("htmlHostManagerServlet.helpHtmlManagerFile")); args[4] = smClient.getString("htmlHostManagerServlet.helpHtmlManager"); args[5] = response.encodeURL (request.getContextPath() + "/" + smClient.getString("htmlHostManagerServlet.helpManagerFile")); args[6] = smClient.getString("htmlHostManagerServlet.helpManager"); args[7] = response.encodeURL("/manager/status"); args[8] = smClient.getString("statusServlet.title"); writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args)); // Hosts Header Section args = new Object[3]; args[0] = smClient.getString("htmlHostManagerServlet.hostName"); args[1] = smClient.getString("htmlHostManagerServlet.hostAliases"); args[2] = smClient.getString("htmlHostManagerServlet.hostTasks"); writer.print(MessageFormat.format(HOSTS_HEADER_SECTION, args)); // Hosts Row Section // Create sorted map of host names. Container[] children = engine.findChildren(); String hostNames[] = new String[children.length]; for (int i = 0; i < children.length; i++) hostNames[i] = children[i].getName(); TreeMap sortedHostNamesMap = new TreeMap(); for (int i = 0; i < hostNames.length; i++) { String displayPath = hostNames[i]; sortedHostNamesMap.put(displayPath, hostNames[i]); } String hostsStart = smClient.getString("htmlHostManagerServlet.hostsStart"); String hostsStop = smClient.getString("htmlHostManagerServlet.hostsStop"); String hostsRemove = smClient.getString("htmlHostManagerServlet.hostsRemove"); Iterator> iterator = sortedHostNamesMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); String hostName = entry.getKey(); Host host = (Host) engine.findChild(hostName); if (host != null ) { args = new Object[2]; args[0] = RequestUtil.filter(hostName); String[] aliases = host.findAliases(); StringBuilder buf = new StringBuilder(); if (aliases.length > 0) { buf.append(aliases[0]); for (int j = 1; j < aliases.length; j++) { buf.append(", ").append(aliases[j]); } } if (buf.length() == 0) { buf.append(" "); args[1] = buf.toString(); } else { args[1] = RequestUtil.filter(buf.toString()); } writer.print (MessageFormat.format(HOSTS_ROW_DETAILS_SECTION, args)); args = new Object[4]; if (host.getState().isAvailable()) { args[0] = response.encodeURL (request.getContextPath() + "/html/stop?name=" + URLEncoder.encode(hostName, "UTF-8")); args[1] = hostsStop; } else { args[0] = response.encodeURL (request.getContextPath() + "/html/start?name=" + URLEncoder.encode(hostName, "UTF-8")); args[1] = hostsStart; } args[2] = response.encodeURL (request.getContextPath() + "/html/remove?name=" + URLEncoder.encode(hostName, "UTF-8")); args[3] = hostsRemove; if (host == this.installedHost) { writer.print(MessageFormat.format( MANAGER_HOST_ROW_BUTTON_SECTION, args)); } else { writer.print(MessageFormat.format( HOSTS_ROW_BUTTON_SECTION, args)); } } } // Add Section args = new Object[6]; args[0] = smClient.getString("htmlHostManagerServlet.addTitle"); args[1] = smClient.getString("htmlHostManagerServlet.addHost"); args[2] = response.encodeURL(request.getContextPath() + "/html/add"); args[3] = smClient.getString("htmlHostManagerServlet.addName"); args[4] = smClient.getString("htmlHostManagerServlet.addAliases"); args[5] = smClient.getString("htmlHostManagerServlet.addAppBase"); writer.print(MessageFormat.format(ADD_SECTION_START, args)); args = new Object[3]; args[0] = smClient.getString("htmlHostManagerServlet.addAutoDeploy"); args[1] = "autoDeploy"; args[2] = "checked"; writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args)); args[0] = smClient.getString( "htmlHostManagerServlet.addDeployOnStartup"); args[1] = "deployOnStartup"; args[2] = "checked"; writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args)); args[0] = smClient.getString("htmlHostManagerServlet.addDeployXML"); args[1] = "deployXML"; args[2] = "checked"; writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args)); args[0] = smClient.getString("htmlHostManagerServlet.addUnpackWARs"); args[1] = "unpackWARs"; args[2] = "checked"; writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args)); args[0] = smClient.getString("htmlHostManagerServlet.addManager"); args[1] = "manager"; args[2] = "checked"; writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args)); args = new Object[1]; args[0] = smClient.getString("htmlHostManagerServlet.addButton"); writer.print(MessageFormat.format(ADD_SECTION_END, args)); // Server Header Section args = new Object[7]; args[0] = smClient.getString("htmlHostManagerServlet.serverTitle"); args[1] = smClient.getString("htmlHostManagerServlet.serverVersion"); args[2] = smClient.getString("htmlHostManagerServlet.serverJVMVersion"); args[3] = smClient.getString("htmlHostManagerServlet.serverJVMVendor"); args[4] = smClient.getString("htmlHostManagerServlet.serverOSName"); args[5] = smClient.getString("htmlHostManagerServlet.serverOSVersion"); args[6] = smClient.getString("htmlHostManagerServlet.serverOSArch"); writer.print(MessageFormat.format (Constants.SERVER_HEADER_SECTION, args)); // Server Row Section args = new Object[6]; args[0] = ServerInfo.getServerInfo(); args[1] = System.getProperty("java.runtime.version"); args[2] = System.getProperty("java.vm.vendor"); args[3] = System.getProperty("os.name"); args[4] = System.getProperty("os.version"); args[5] = System.getProperty("os.arch"); writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args)); // HTML Tail Section writer.print(Constants.HTML_TAIL_SECTION); // Finish up the response writer.flush(); writer.close(); } // ------------------------------------------------------ Private Constants // These HTML sections are broken in relatively small sections, because of // limited number of substitutions MessageFormat can process // (maximum of 10). private static final String HOSTS_HEADER_SECTION = "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + " \n" + " \n" + "\n"; private static final String HOSTS_ROW_DETAILS_SECTION = "\n" + " \n" + " \n"; private static final String MANAGER_HOST_ROW_BUTTON_SECTION = " \n" + "\n"; private static final String HOSTS_ROW_BUTTON_SECTION = " \n" + "\n"; private static final String ADD_SECTION_START = "
    {0}
    {0}{1}{2}
    {0}" + "{1}\n" + " \n" + sm.getString("htmlHostManagerServlet.hostThis") + " \n" + "
    \n" + "
    " + " " + "
    \n" + "
    " + " " + "
    \n" + "
    \n" + "
    \n" + "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + "\n" + "
    {0}
    {1}
    \n" + "
    \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " \n" + "\n" + "\n" + " \n" + " \n" + "\n" ; private static final String ADD_SECTION_BOOLEAN = "\n" + " \n" + " \n" + "\n" ; private static final String ADD_SECTION_END = "\n" + " \n" + " \n" + "\n" + "
    \n" + " {3}\n" + " \n" + " \n" + "
    \n" + " {4}\n" + " \n" + " \n" + "
    \n" + " {5}\n" + " \n" + " \n" + "
    \n" + " {0}\n" + " \n" + " \n" + "
    \n" + "  \n" + " \n" + " \n" + "
    \n" + "
    \n" + "
    \n" + "
    \n" + "\n"; } tomcat7-7.0.52/java/org/apache/catalina/manager/host/HostManagerServlet.java0000644000175100017510000005607312271471332026674 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager.host; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Enumeration; import java.util.Locale; import java.util.StringTokenizer; import javax.management.MBeanServer; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Container; import org.apache.catalina.ContainerServlet; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Wrapper; import org.apache.catalina.core.ContainerBase; import org.apache.catalina.core.StandardHost; import org.apache.catalina.startup.HostConfig; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; /** * Servlet that enables remote management of the virtual hosts installed * on the server. Normally, this functionality will be protected by * a security constraint in the web application deployment descriptor. * However, this requirement can be relaxed during testing. *

    * This servlet examines the value returned by getPathInfo() * and related query parameters to determine what action is being requested. * The following actions and parameters (starting after the servlet path) * are supported: *

      *
    • /add?name={host-name}&aliases={host-aliases}&manager={manager} - * Create and add a new virtual host. The host-name attribute * indicates the name of the new host. The host-aliases * attribute is a comma separated list of the host alias names. * The manager attribute is a boolean value indicating if the * webapp manager will be installed in the newly created host (optional, * false by default).
    • *
    • /remove?name={host-name} - Remove a virtual host. * The host-name attribute indicates the name of the host. *
    • *
    • /list - List the virtual hosts installed on the server. * Each host will be listed with the following format * host-name#host-aliases.
    • *
    • /start?name={host-name} - Start the virtual host.
    • *
    • /stop?name={host-name} - Stop the virtual host.
    • *
    *

    * NOTE - Attempting to stop or remove the host containing * this servlet itself will not succeed. Therefore, this servlet should * generally be deployed in a separate virtual host. *

    * The following servlet initialization parameters are recognized: *

      *
    • debug - The debugging detail level that controls the amount * of information that is logged by this servlet. Default is zero. *
    * * @author Craig R. McClanahan * @author Remy Maucherat */ public class HostManagerServlet extends HttpServlet implements ContainerServlet { private static final long serialVersionUID = 1L; // ----------------------------------------------------- Instance Variables /** * The Context container associated with our web application. */ protected transient Context context = null; /** * The debugging detail level for this servlet. */ protected int debug = 1; /** * The associated host. */ protected transient Host installedHost = null; /** * The associated engine. */ protected transient Engine engine = null; /** * MBean server. */ protected transient MBeanServer mBeanServer = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The Wrapper container associated with this servlet. */ protected transient Wrapper wrapper = null; // ----------------------------------------------- ContainerServlet Methods /** * Return the Wrapper with which we are associated. */ @Override public Wrapper getWrapper() { return (this.wrapper); } /** * Set the Wrapper with which we are associated. * * @param wrapper The new wrapper */ @Override public void setWrapper(Wrapper wrapper) { this.wrapper = wrapper; if (wrapper == null) { context = null; installedHost = null; engine = null; } else { context = (Context) wrapper.getParent(); installedHost = (Host) context.getParent(); engine = (Engine) installedHost.getParent(); } // Retrieve the MBean server mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); } // --------------------------------------------------------- Public Methods /** * Finalize this servlet. */ @Override public void destroy() { // No actions necessary } /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need String command = request.getPathInfo(); if (command == null) command = request.getServletPath(); String name = request.getParameter("name"); // Prepare our output writer to generate the response message response.setContentType("text/plain; charset=" + Constants.CHARSET); PrintWriter writer = response.getWriter(); // Process the requested command if (command == null) { writer.println(sm.getString("hostManagerServlet.noCommand")); } else if (command.equals("/add")) { add(request, writer, name, false, smClient); } else if (command.equals("/remove")) { remove(writer, name, smClient); } else if (command.equals("/list")) { list(writer, smClient); } else if (command.equals("/start")) { start(writer, name, smClient); } else if (command.equals("/stop")) { stop(writer, name, smClient); } else { writer.println(sm.getString("hostManagerServlet.unknownCommand", command)); } // Finish up the response writer.flush(); writer.close(); } /** * Add host with the given parameters. * * @param request The request * @param writer The output writer * @param name The host name * @param htmlMode Flag value */ protected void add(HttpServletRequest request, PrintWriter writer, String name, boolean htmlMode, StringManager smClient) { String aliases = request.getParameter("aliases"); String appBase = request.getParameter("appBase"); boolean manager = booleanParameter(request, "manager", false, htmlMode); boolean autoDeploy = booleanParameter(request, "autoDeploy", true, htmlMode); boolean deployOnStartup = booleanParameter(request, "deployOnStartup", true, htmlMode); boolean deployXML = booleanParameter(request, "deployXML", true, htmlMode); boolean unpackWARs = booleanParameter(request, "unpackWARs", true, htmlMode); add(writer, name, aliases, appBase, manager, autoDeploy, deployOnStartup, deployXML, unpackWARs, smClient); } /** * Extract boolean value from checkbox with default. * @param request * @param parameter * @param theDefault * @param htmlMode */ protected boolean booleanParameter(HttpServletRequest request, String parameter, boolean theDefault, boolean htmlMode) { String value = request.getParameter(parameter); boolean booleanValue = theDefault; if (value != null) { if (htmlMode) { if (value.equals("on")) { booleanValue = true; } } else if (theDefault) { if (value.equals("false")) { booleanValue = false; } } else if (value.equals("true")) { booleanValue = true; } } else if (htmlMode) booleanValue = false; return booleanValue; } /** * Initialize this servlet. */ @Override public void init() throws ServletException { // Ensure that our ContainerServlet properties have been set if ((wrapper == null) || (context == null)) throw new UnavailableException (sm.getString("hostManagerServlet.noWrapper")); // Set our properties from the initialization parameters String value = null; try { value = getServletConfig().getInitParameter("debug"); debug = Integer.parseInt(value); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } // -------------------------------------------------------- Private Methods /** * Add a host using the specified parameters. * * @param writer Writer to render results to * @param name host name * @param aliases comma separated alias list * @param appBase application base for the host * @param manager should the manager webapp be deployed to the new host ? */ protected synchronized void add (PrintWriter writer, String name, String aliases, String appBase, boolean manager, boolean autoDeploy, boolean deployOnStartup, boolean deployXML, boolean unpackWARs, StringManager smClient) { if (debug >= 1) { log(sm.getString("hostManagerServlet.add", name)); } // Validate the requested host name if ((name == null) || name.length() == 0) { writer.println(smClient.getString( "hostManagerServlet.invalidHostName", name)); return; } // Check if host already exists if (engine.findChild(name) != null) { writer.println(smClient.getString( "hostManagerServlet.alreadyHost", name)); return; } // Validate and create appBase File appBaseFile = null; File file = null; if (appBase == null || appBase.length() == 0) { file = new File(name); } else { file = new File(appBase); } if (!file.isAbsolute()) file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), file.getPath()); try { appBaseFile = file.getCanonicalFile(); } catch (IOException e) { appBaseFile = file; } if (!appBaseFile.mkdirs() && !appBaseFile.isDirectory()) { writer.println(smClient.getString( "hostManagerServlet.appBaseCreateFail", appBaseFile.toString(), name)); return; } // Create base for config files File configBaseFile = getConfigBase(name); // Copy manager.xml if requested if (manager) { if (configBaseFile == null) { writer.println(smClient.getString( "hostManagerServlet.configBaseCreateFail", name)); return; } InputStream is = null; OutputStream os = null; try { is = getServletContext().getResourceAsStream("/manager.xml"); os = new FileOutputStream(new File(configBaseFile, "manager.xml")); byte buffer[] = new byte[512]; int len = buffer.length; while (true) { len = is.read(buffer); if (len == -1) break; os.write(buffer, 0, len); } } catch (IOException e) { writer.println(smClient.getString( "hostManagerServlet.managerXml")); return; } finally { if (is != null) { try { is.close(); } catch (IOException e) { // Ignore } } if (os != null) { try { os.close(); } catch (IOException e) { // Ignore } } } } StandardHost host = new StandardHost(); host.setAppBase(appBase); host.setName(name); host.addLifecycleListener(new HostConfig()); // Add host aliases if ((aliases != null) && !("".equals(aliases))) { StringTokenizer tok = new StringTokenizer(aliases, ", "); while (tok.hasMoreTokens()) { host.addAlias(tok.nextToken()); } } host.setAutoDeploy(autoDeploy); host.setDeployOnStartup(deployOnStartup); host.setDeployXML(deployXML); host.setUnpackWARs(unpackWARs); // Add new host try { engine.addChild(host); } catch (Exception e) { writer.println(smClient.getString("hostManagerServlet.exception", e.toString())); return; } host = (StandardHost) engine.findChild(name); if (host != null) { writer.println(smClient.getString("hostManagerServlet.add", name)); } else { // Something failed writer.println(smClient.getString( "hostManagerServlet.addFailed", name)); } } /** * Remove the specified host. * * @param writer Writer to render results to * @param name host name */ protected synchronized void remove(PrintWriter writer, String name, StringManager smClient) { if (debug >= 1) { log(sm.getString("hostManagerServlet.remove", name)); } // Validate the requested host name if ((name == null) || name.length() == 0) { writer.println(smClient.getString( "hostManagerServlet.invalidHostName", name)); return; } // Check if host exists if (engine.findChild(name) == null) { writer.println(smClient.getString( "hostManagerServlet.noHost", name)); return; } // Prevent removing our own host if (engine.findChild(name) == installedHost) { writer.println(smClient.getString( "hostManagerServlet.cannotRemoveOwnHost", name)); return; } // Remove host // Note that the host will not get physically removed try { Container child = engine.findChild(name); engine.removeChild(child); if ( child instanceof ContainerBase ) ((ContainerBase)child).destroy(); } catch (Exception e) { writer.println(smClient.getString("hostManagerServlet.exception", e.toString())); return; } Host host = (StandardHost) engine.findChild(name); if (host == null) { writer.println(smClient.getString( "hostManagerServlet.remove", name)); } else { // Something failed writer.println(smClient.getString( "hostManagerServlet.removeFailed", name)); } } /** * Render a list of the currently active Contexts in our virtual host. * * @param writer Writer to render to */ protected void list(PrintWriter writer, StringManager smClient) { if (debug >= 1) { log(sm.getString("hostManagerServlet.list", engine.getName())); } writer.println(smClient.getString("hostManagerServlet.listed", engine.getName())); Container[] hosts = engine.findChildren(); for (int i = 0; i < hosts.length; i++) { Host host = (Host) hosts[i]; String name = host.getName(); String[] aliases = host.findAliases(); StringBuilder buf = new StringBuilder(); if (aliases.length > 0) { buf.append(aliases[0]); for (int j = 1; j < aliases.length; j++) { buf.append(',').append(aliases[j]); } } writer.println(smClient.getString("hostManagerServlet.listitem", name, buf.toString())); } } /** * Start the host with the specified name. * * @param writer Writer to render to * @param name Host name */ protected void start(PrintWriter writer, String name, StringManager smClient) { if (debug >= 1) { log(sm.getString("hostManagerServlet.start", name)); } // Validate the requested host name if ((name == null) || name.length() == 0) { writer.println(smClient.getString( "hostManagerServlet.invalidHostName", name)); return; } Container host = engine.findChild(name); // Check if host exists if (host == null) { writer.println(smClient.getString( "hostManagerServlet.noHost", name)); return; } // Prevent starting our own host if (host == installedHost) { writer.println(smClient.getString( "hostManagerServlet.cannotStartOwnHost", name)); return; } // Don't start host if already started if (host.getState().isAvailable()) { writer.println(smClient.getString( "hostManagerServlet.alreadyStarted", name)); return; } // Start host try { host.start(); writer.println(smClient.getString( "hostManagerServlet.started", name)); } catch (Exception e) { getServletContext().log (sm.getString("hostManagerServlet.startFailed", name), e); writer.println(smClient.getString( "hostManagerServlet.startFailed", name)); writer.println(smClient.getString( "hostManagerServlet.exception", e.toString())); return; } } /** * Stop the host with the specified name. * * @param writer Writer to render to * @param name Host name */ protected void stop(PrintWriter writer, String name, StringManager smClient) { if (debug >= 1) { log(sm.getString("hostManagerServlet.stop", name)); } // Validate the requested host name if ((name == null) || name.length() == 0) { writer.println(smClient.getString( "hostManagerServlet.invalidHostName", name)); return; } Container host = engine.findChild(name); // Check if host exists if (host == null) { writer.println(smClient.getString("hostManagerServlet.noHost", name)); return; } // Prevent stopping our own host if (host == installedHost) { writer.println(smClient.getString( "hostManagerServlet.cannotStopOwnHost", name)); return; } // Don't stop host if already stopped if (!host.getState().isAvailable()) { writer.println(smClient.getString( "hostManagerServlet.alreadyStopped", name)); return; } // Stop host try { host.stop(); writer.println(smClient.getString("hostManagerServlet.stopped", name)); } catch (Exception e) { getServletContext().log(sm.getString( "hostManagerServlet.stopFailed", name), e); writer.println(smClient.getString("hostManagerServlet.stopFailed", name)); writer.println(smClient.getString("hostManagerServlet.exception", e.toString())); return; } } // -------------------------------------------------------- Support Methods /** * Get config base. */ protected File getConfigBase(String hostName) { File configBase = new File(System.getProperty(Globals.CATALINA_BASE_PROP), "conf"); if (!configBase.exists()) { return null; } if (engine != null) { configBase = new File(configBase, engine.getName()); } if (installedHost != null) { configBase = new File(configBase, hostName); } if (!configBase.mkdirs() && !configBase.isDirectory()) { return null; } return configBase; } /** * @deprecated Use {@link StringManager#getManager(String, Enumeration)}. * This method will be removed in Tomcat 8. */ @Deprecated protected StringManager getStringManager(HttpServletRequest req) { Enumeration requestedLocales = req.getLocales(); while (requestedLocales.hasMoreElements()) { Locale locale = requestedLocales.nextElement(); StringManager result = StringManager.getManager(Constants.Package, locale); if (result.getLocale().equals(locale)) { return result; } } // Return the default return sm; } } tomcat7-7.0.52/java/org/apache/catalina/manager/host/Constants.java0000644000175100017510000001110612271471332025057 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.manager.host; public class Constants { public static final String Package = "org.apache.catalina.manager.host"; public static final String BODY_HEADER_SECTION = "{0}\n" + "\n" + "\n" + "\n" + "\n" + "\n" + " \n" + " \n" + " \n" + "
    \n" + " \n" + " \"The\n" + " \n" + " \n" + " \"The\n" + " \n" + "
    \n" + "
    \n" + "\n" + " \n" + " \n" + " \n" + "
    \n" + " {1}\n" + "
    \n" + "
    \n" + "\n"; public static final String MESSAGE_SECTION = "\n" + " \n" + " \n" + " \n" + " \n" + "
    " + "{0} 
    {1}
    \n" + "
    \n" + "\n"; public static final String MANAGER_SECTION = "\n" + "\n" + " \n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
    {0}
    {2}{4}{6}{8}
    \n" + "
    \n" + "\n"; public static final String SERVER_HEADER_SECTION = "\n" + "\n" + " \n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; public static final String SERVER_ROW_SECTION = "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" + "
    {0}
    {1}{2}{3}{4}{5}{6}
    {0}{1}{2}{3}{4}{5}
    \n" + "
    \n" + "\n"; public static final String HTML_TAIL_SECTION = "
    \n" + "
    \n" + " Copyright © 1999-2014, Apache Software Foundation" + "
    \n" + "\n" + "\n" + ""; public static final String CHARSET="utf-8"; } tomcat7-7.0.52/java/org/apache/catalina/manager/host/LocalStrings.properties0000644000175100017510000001062412271471332026766 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. hostManagerServlet.alreadyStarted=FAIL - Host [{0}] is already started hostManagerServlet.alreadyStopped=FAIL - Host [{0}] is already stopped hostManagerServlet.appBaseCreateFail=FAIL - Failed to create appBase [{0}] for host [{1}] hostManagerServlet.configBaseCreateFail=FAIL - Failed to identify configBase for host [{0}] hostManagerServlet.noCommand=FAIL - No command was specified hostManagerServlet.postCommand=FAIL - Tried to use command {0} via a GET request but POST is required hostManagerServlet.unknownCommand=FAIL - Unknown command {0} hostManagerServlet.noWrapper=Container has not called setWrapper() for this servlet hostManagerServlet.invalidHostName=FAIL - Invalid host name {0} was specified hostManagerServlet.noHost=FAIL - Host name {0} does not exist hostManagerServlet.alreadyHost=FAIL - Host already exists with host name {0} hostManagerServlet.managerXml=FAIL - Couldn't install manager.xml hostManagerServlet.exception=FAIL - Encountered exception {0} hostManagerServlet.add=OK - Host {0} added hostManagerServlet.addFailed=FAIL - Failed to add host {0} hostManagerServlet.cannotRemoveOwnHost=FAIL - Cannot remove own host {0} hostManagerServlet.remove=OK - Removed host {0} hostManagerServlet.removeFailed=FAIL - Failed to remove host {0} hostManagerServlet.listed=OK - Listed hosts hostManagerServlet.listitem={0}:{1} hostManagerServlet.cannotStartOwnHost=FAIL - Cannot start own host {0} hostManagerServlet.started=OK - Host {0} started hostManagerServlet.startFailed=FAIL - Failed to start host {0} hostManagerServlet.cannotStopOwnHost=FAIL - Cannot stop own host {0} hostManagerServlet.stopped=OK - Host {0} stopped hostManagerServlet.stopFailed=FAIL - Failed to stop host {0} hostManagerServlet.add=add: Adding host [{0}] hostManagerServlet.remove=remove: Removing host [{0}] hostManagerServlet.list=list: Listing hosts for engine [{0}] hostManagerServlet.start=start: Starting host with name [{0}] hostManagerServlet.stop=stop: Stopping host with name [{0}] htmlHostManagerServlet.title=Tomcat Virtual Host Manager htmlHostManagerServlet.messageLabel=Message: htmlHostManagerServlet.manager=Host Manager htmlHostManagerServlet.list=List Virtual Hosts htmlHostManagerServlet.helpHtmlManagerFile=../docs/html-host-manager-howto.html htmlHostManagerServlet.helpHtmlManager=HTML Host Manager Help (TODO) htmlHostManagerServlet.helpManagerFile=../docs/host-manager-howto.html htmlHostManagerServlet.helpManager=Host Manager Help (TODO) htmlHostManagerServlet.hostName=Host name htmlHostManagerServlet.hostAliases=Host aliases htmlHostManagerServlet.hostTasks=Commands htmlHostManagerServlet.hostsStart=Start htmlHostManagerServlet.hostsStop=Stop htmlHostManagerServlet.hostsRemove=Remove htmlHostManagerServlet.hostThis=Host Manager installed - commands disabled htmlHostManagerServlet.addTitle=Add Virtual Host htmlHostManagerServlet.addHost=Host htmlHostManagerServlet.addName=Name: htmlHostManagerServlet.addAliases=Aliases: htmlHostManagerServlet.addAppBase=App base: htmlHostManagerServlet.addManager=Manager App htmlHostManagerServlet.addAutoDeploy=AutoDeploy htmlHostManagerServlet.addDeployOnStartup=DeployOnStartup htmlHostManagerServlet.addDeployXML=DeployXML htmlHostManagerServlet.addUnpackWARs=UnpackWARs htmlHostManagerServlet.addButton=Add htmlHostManagerServlet.serverTitle=Server Information htmlHostManagerServlet.serverVersion=Tomcat Version htmlHostManagerServlet.serverJVMVersion=JVM Version htmlHostManagerServlet.serverJVMVendor=JVM Vendor htmlHostManagerServlet.serverOSName=OS Name htmlHostManagerServlet.serverOSVersion=OS Version htmlHostManagerServlet.serverOSArch=OS Architecture statusServlet.title=Server Status statusServlet.complete=Complete Server Status tomcat7-7.0.52/java/org/apache/catalina/AccessLog.java0000644000175100017510000000767411656660564022413 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** * Intended for use by a {@link Valve} to indicate that the {@link Valve} * provides access logging. It is used by the Tomcat internals to identify a * Valve that logs access requests so requests that are rejected * earlier in the processing chain can still be added to the access log. * Implementations of this interface should be robust against the provided * {@link Request} and {@link Response} objects being null, having null * attributes or any other 'oddness' that may result from attempting to log * a request that was almost certainly rejected because it was mal-formed. */ public interface AccessLog { /** * Name of request attribute used to override the remote address recorded by * the AccessLog. */ public static final String REMOTE_ADDR_ATTRIBUTE = "org.apache.catalina.AccessLog.RemoteAddr"; /** * Name of request attribute used to override remote host name recorded by * the AccessLog. */ public static final String REMOTE_HOST_ATTRIBUTE = "org.apache.catalina.AccessLog.RemoteHost"; /** * Name of request attribute used to override the protocol recorded by the * AccessLog. */ public static final String PROTOCOL_ATTRIBUTE = "org.apache.catalina.AccessLog.Protocol"; /** * Name of request attribute used to override the server port recorded by * the AccessLog. */ public static final String SERVER_PORT_ATTRIBUTE = "org.apache.catalina.AccessLog.ServerPort"; /** * Add the request/response to the access log using the specified processing * time. * * @param request Request (associated with the response) to log * @param response Response (associated with the request) to log * @param time Time taken to process the request/response in * milliseconds (use 0 if not known) */ public void log(Request request, Response response, long time); /** * Should this valve set request attributes for IP address, Hostname, * protocol and port used for the request? This are typically used in * conjunction with the {@link org.apache.catalina.valves.AccessLogValve} * which will otherwise log the original values. * Default is true. * * The attributes set are: *
      *
    • org.apache.catalina.RemoteAddr
    • *
    • org.apache.catalina.RemoteHost
    • *
    • org.apache.catalina.Protocol
    • *
    • org.apache.catalina.ServerPost
    • *
    * * @param requestAttributesEnabled true causes the attributes * to be set, false disables * the setting of the attributes. */ public void setRequestAttributesEnabled(boolean requestAttributesEnabled); /** * @see #setRequestAttributesEnabled(boolean) * @return true if the attributes will be logged, otherwise * false */ public boolean getRequestAttributesEnabled(); } tomcat7-7.0.52/java/org/apache/catalina/DistributedManager.java0000644000175100017510000000365612023367215024303 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.Set; /** * Interface implemented by session managers that do not keep a complete copy * of all sessions in memory but do know where every session is. The * BackupManager is an example of such a Manager as are implementations of the * StoreManager interface. *

    * With the BackupManager, sessions can be primary (master copy on this node), * backup (backup copy on this node) or proxy (only the session ID on this * node). The identity of the primary and backup nodes are known for all * sessions, including proxy sessions. *

    * With StoreManager implementations, sessions can be primary (session is in * memory) or proxy (session is in the Store). */ public interface DistributedManager { /** * Returns the total session count for primary, backup and proxy. * * @return The total session count across the cluster. */ public int getActiveSessionsFull(); /** * Returns the list of all sessions IDS (primary, backup and proxy). * * @return The complete set of sessions IDs across the cluster. */ public Set getSessionIdsFull(); } tomcat7-7.0.52/java/org/apache/catalina/realm/0000755000175100017510000000000012301126370020743 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/realm/LocalStrings_es.properties0000644000175100017510000001713512271471332026172 0ustar locutuslocutusjaasRealm.beginLogin = JAASRealm login requerido para nombre de usuario "{0}" usando LoginContext para aplicaci\u00F3n "{1}" # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # language es # package org.apache.catalina.realm jaasRealm.accountExpired = El usuario {0} NO ha sido autentificado porque ha expirado su cuenta jaasRealm.authenticateFailure = Nombre de usuario "{0}" NO autenticado con \u00E9xito jaasRealm.authenticateSuccess = Nombre de usuario "{0}" autenticado con \u00E9xito como Principal "{1}" -- Tambi\u00E9n se ha creado el Asunto jaasRealm.credentialExpired = El usuario {0} NO ha sido autentificado porque ha expirado su credencial jaasRealm.failedLogin = El usuario {0} NO ha sido autentificado porque ha fallado el login jaasRealm.loginException = Excepci\u00F3n de Login autenticando nombre de usuario {0} jaasRealm.unexpectedError = Error inesperado jaasRealm.loginContextCreated = JAAS LoginContext creado para nombre de usuario "{0}" jaasRealm.cachePrincipal = Usuario Principal "{0}" en cach\u00E9; tiene {1} papel de Principal jaasRealm.checkPrincipal = Revisando Principal "{0}" [{1}] jaasRealm.userPrincipalSuccess = El Principal "{0}" es una clase v\u00E1lida de usuario. La vamos a usar como usuario Principal. jaasRealm.userPrincipalFailure = No se ha hallado usuario Principal jaasRealm.rolePrincipalAdd = A\u00F1adiend papel Principal "{0}" a los papeles de este usuario Principal jaasRealm.rolePrincipalSuccess = hallado {0} papeles de Principal jaasRealm.rolePrincipalFailure = No se han hallado papeles de Principal v\u00E1lidos. jaasRealm.isInRole.start = Revisando si el usuario Principal "{0}" tiene el papel "{1}" jaasRealm.isInRole.noPrincipalOrRole = No se han hallado papeles de Principal. El usuario Principal o el Asunto es nulo o el usuario Principal no est\u00E1 en cach\u00E9 jaasRealm.isInRole.principalCached = El Usuario Principal tiene {0} papeles de Principal jaasRealm.isInRole.possessesRole = El Usuario Principal tiene un papele de Principal llamado "{0}" jaasRealm.isInRole.match = Hallado papel de Principal coincidente. jaasRealm.isInRole.noMatch = NO hallado papel de Principal coincidente. jaasCallback.digestpassword = Resumida contrase\u00F1a "{0}" como "{1}" jaasCallback.username = Devuelto nombre de usuario "{0}" jaasCallback.password = Devuelta contrase\u00F1a "{0}" jdbcRealm.authenticateFailure = El usuario {0} NO ha sido autentificado correctamente jdbcRealm.authenticateSuccess = El usuario {0} ha sido autentificado correctamente jdbcRealm.close = Excepci\u00F3n al cerrar la conexi\u00F3n a la base de datos jdbcRealm.exception = Excepci\u00F3n al realizar la autentificaci\u00F3n jdbcRealm.getPassword.exception = Excepci\u00F3n recuperando contrase\u00F1a para "{0}" jdbcRealm.getRoles.exception = Excepci\u00F3n recuperando papeles para "{0}" jdbcRealm.open = Excepci\u00F3n abriendo la conexi\u00F3n a la base de datos jdbcRealm.open.invalidurl = El conductor "{0}" no soporta la url "{1}" jndiRealm.authenticateFailure = Autentificaci\u00F3n fallida para el usuario {0} jndiRealm.authenticateSuccess = Autentificaci\u00F3n correcta para el usuario {0} jndiRealm.close = Excepci\u00F3n al cerrar la conexi\u00F3n al servidor de directorio jndiRealm.exception = Excepci\u00F3n al realizar la autentificaci\u00F3n jndiRealm.open = Excepci\u00F3n al abrir la conexi\u00F3n al servidor de directorio memoryRealm.authenticateFailure = Autentificaci\u00F3n fallida para el usuario {0} memoryRealm.authenticateSuccess = Autentificaci\u00F3n correcta para el usuario {0} memoryRealm.loadExist = El fichero de usuarios {0} no ha podido ser le\u00EDdo memoryRealm.loadPath = Cargando los usuarios desde el fichero {0} memoryRealm.readXml = Excepci\u00F3n mientras se le\u00EDa el fichero de usuarios memoryRealm.xmlFeatureEncoding = Excepci\u00F3n al configurar resumidor para permitir nombres con codificaci\u00F3n java en ficheros XML. S\u00F3llo se soportan nombres con codificaci\u00F3n IANA. realmBase.algorithm = El algoritmo resumen (digest) {0} es inv\u00E1lido realmBase.alreadyStarted = Este dominio ya ha sido inicializado realmBase.delegatedCredentialFail = No pude obtener credenciales de delegado para el usuario [{0}] realmBase.digest = Error procesando las credenciales del usuario realmBase.forbidden = El acceso al recurso pedido ha sido denegado realmBase.hasRoleFailure = El usuario {0} NO desempe\u00F1a el papel de {1} realmBase.hasRoleSuccess = El usuario {0} desempe\u00F1a el papel de {1} realmBase.notAuthenticated = Error de Configuraci\u00F3n\: No se pueden realizar funciones de control de acceso sin un principal autentificado realmBase.notStarted = Este dominio a\u00FAn no ha sido inicializado realmBase.authenticateFailure = Nombre de usuario {0} NO autenticado con \u00E9xito realmBase.authenticateSuccess = Nombre de usuario {0} autenticado con \u00E9xito realmBase.gssNameFail = No pude extraer el nombre desde el GSSContext establecido userDatabaseRealm.authenticateError = Error de configuraci\u00F3n de Login autenticando nombre de usuario {0} userDatabaseRealm.lookup = Excepci\u00F3n buscando en Base de datos de Usuario mediante la clave {0} userDatabaseRealm.noDatabase = No se ha hallado componente de Base de datos de Usuario mediante la clave {0} userDatabaseRealm.noEngine = No se ha hallado componente de Motor en jerarqu\u00EDa de contenedor userDatabaseRealm.noGlobal = No se ha hallado contexto de recursos globales JNDI dataSourceRealm.authenticateFailure = Nombre de usuario {0} NO autenticado con \u00E9xito dataSourceRealm.authenticateSuccess = Nombre de usuario {0} autenticado con \u00E9xito dataSourceRealm.close = Excepci\u00F3n cerrando conexi\u00F3n a base de datos dataSourceRealm.exception = Excepci\u00F3n realizando autenticaci\u00F3n dataSourceRealm.getPassword.exception = Excepci\u00F3n recuperando contrase\u00F1a para "{0}" dataSourceRealm.getRoles.exception = Excepci\u00F3n recuperando papeles para "{0}" dataSourceRealm.open = Excepci\u00F3n abriendo conexi\u00F3n a base de datos combinedRealm.unexpectedMethod = Una llamada inesperada se realiz\u00F3 a un m\u00E9todo del reino combinado combinedRealm.getName = No se deber\u00EDa de llamar nunca al m\u00E9todo getName() combinedRealm.getPassword = No se deber\u00EDa de llamar nunca al m\u00E9todo getPassword() combinedRealm.getPrincipal = No se deber\u00EDa de llamar nunca al m\u00E9todo getPrincipal() combinedRealm.authStart = Intentando autentica al usuario "{0}" con el reino "{1}" combinedRealm.authFailed = No pude autenticar al usuario "{0}" con el reino "{1}" combinedRealm.authSuccess = Usuario autenticado "{0}" con reino "{1}" combinedRealm.addRealm = A\u00F1adir reino "{0}", totalizando "{1}" reinos combinedRealm.realmStartFail = No pude arrancar reino "{0}" lockOutRealm.authLockedUser = Se ha intentado autentica al usuario bloqueado "{0}" lockOutRealm.removeWarning = Se ha quitado al usuario "{0}" de la cach\u00E9 de usuarios fallidos tras {1} secgundos para mantener la medida de cach\u00E9 dentro de los l\u00EDmites tomcat7-7.0.52/java/org/apache/catalina/realm/X509UsernameRetriever.java0000644000175100017510000000243111726217101025646 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.cert.X509Certificate; /** * Provides an interface for retrieving a user name from an X509Certificate. */ public interface X509UsernameRetriever { /** * Gets a user name from an X509Certificate. * * @param cert The certificate containing the user name. * @return An appropriate user name obtained from one or more fields * in the certificate. */ public String getUsername(X509Certificate cert); } tomcat7-7.0.52/java/org/apache/catalina/realm/MemoryRealm.java0000644000175100017510000002142712271471332024054 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.io.File; import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.digester.Digester; /** * Simple implementation of Realm that reads an XML file to configure * the valid users, passwords, and roles. The file format (and default file * location) are identical to those currently supported by Tomcat 3.X. *

    * IMPLEMENTATION NOTE: It is assumed that the in-memory * collection representing our defined users (and their roles) is initialized * at application startup and never modified again. Therefore, no thread * synchronization is performed around accesses to the principals collection. * * @author Craig R. McClanahan */ public class MemoryRealm extends RealmBase { private static final Log log = LogFactory.getLog(MemoryRealm.class); // ----------------------------------------------------- Instance Variables /** * The Digester we will use to process in-memory database files. */ private static Digester digester = null; /** * Descriptive information about this Realm implementation. */ protected static final String info = "org.apache.catalina.realm.MemoryRealm/1.0"; /** * Descriptive information about this Realm implementation. */ protected static final String name = "MemoryRealm"; /** * The pathname (absolute or relative to Catalina's current working * directory) of the XML file containing our database information. */ private String pathname = "conf/tomcat-users.xml"; /** * The set of valid Principals for this Realm, keyed by user name. */ private Map principals = new HashMap(); // ------------------------------------------------------------- Properties /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } /** * Return the pathname of our XML file containing user definitions. */ public String getPathname() { return pathname; } /** * Set the pathname of our XML file containing user definitions. If a * relative pathname is specified, it is resolved against "catalina.base". * * @param pathname The new pathname */ public void setPathname(String pathname) { this.pathname = pathname; } // --------------------------------------------------------- Public Methods /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public Principal authenticate(String username, String credentials) { GenericPrincipal principal = principals.get(username); boolean validated = compareCredentials(credentials, principal.getPassword()); if (validated) { if (log.isDebugEnabled()) log.debug(sm.getString("memoryRealm.authenticateSuccess", username)); return (principal); } else { if (log.isDebugEnabled()) log.debug(sm.getString("memoryRealm.authenticateFailure", username)); return (null); } } // -------------------------------------------------------- Package Methods /** * Add a new user to the in-memory database. * * @param username User's username * @param password User's password (clear text) * @param roles Comma-delimited set of roles associated with this user */ void addUser(String username, String password, String roles) { // Accumulate the list of roles for this user ArrayList list = new ArrayList(); roles += ","; while (true) { int comma = roles.indexOf(','); if (comma < 0) break; String role = roles.substring(0, comma).trim(); list.add(role); roles = roles.substring(comma + 1); } // Construct and cache the Principal for this user GenericPrincipal principal = new GenericPrincipal(username, password, list); principals.put(username, principal); } // ------------------------------------------------------ Protected Methods /** * Return a configured Digester to use for processing * the XML input file, creating a new one if necessary. */ protected synchronized Digester getDigester() { if (digester == null) { digester = new Digester(); digester.setValidating(false); try { digester.setFeature( "http://apache.org/xml/features/allow-java-encodings", true); } catch (Exception e) { log.warn(sm.getString("memoryRealm.xmlFeatureEncoding"), e); } digester.addRuleSet(new MemoryRuleSet()); } return (digester); } /** * Return a short name for this Realm implementation. */ @Override protected String getName() { return (name); } /** * Return the password associated with the given principal's user name. */ @Override protected String getPassword(String username) { GenericPrincipal principal = principals.get(username); if (principal != null) { return (principal.getPassword()); } else { return (null); } } /** * Return the Principal associated with the given user name. */ @Override protected Principal getPrincipal(String username) { return principals.get(username); } /** * Returns the principals for this realm. * * @return The principals, keyed by user name (a String) * * @deprecated Unused */ @Deprecated protected Map getPrincipals() { return principals; } // ------------------------------------------------------ Lifecycle Methods /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // Validate the existence of our database file File file = new File(pathname); if (!file.isAbsolute()) file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname); if (!file.exists() || !file.canRead()) throw new LifecycleException (sm.getString("memoryRealm.loadExist", file.getAbsolutePath())); // Load the contents of the database file if (log.isDebugEnabled()) log.debug(sm.getString("memoryRealm.loadPath", file.getAbsolutePath())); Digester digester = getDigester(); try { synchronized (digester) { digester.push(this); digester.parse(file); } } catch (Exception e) { throw new LifecycleException (sm.getString("memoryRealm.readXml"), e); } finally { digester.reset(); } super.startInternal(); } } tomcat7-7.0.52/java/org/apache/catalina/realm/NullRealm.java0000644000175100017510000000276411704121216023512 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.Principal; /** * Minimal Realm implementation that always returns null when an attempt is made * to validate a user name and password. It is intended to be used as a default * Realm implementation when no other Realm is specified. */ public class NullRealm extends RealmBase { private static final String NAME = "NullRealm"; @Override protected String getName() { return NAME; } @Override protected String getPassword(String username) { // Always return null return null; } @Override protected Principal getPrincipal(String username) { // Always return null return null; } } tomcat7-7.0.52/java/org/apache/catalina/realm/CombinedRealm.java0000644000175100017510000003000512271471332024314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.Principal; import java.security.cert.X509Certificate; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.management.ObjectName; import org.apache.catalina.Container; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.Realm; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSName; /** * Realm implementation that contains one or more realms. Authentication is * attempted for each realm in the order they were configured. If any realm * authenticates the user then the authentication succeeds. When combining * realms usernames should be unique across all combined realms. */ public class CombinedRealm extends RealmBase { private static final Log log = LogFactory.getLog(CombinedRealm.class); /** * The list of Realms contained by this Realm. */ protected List realms = new LinkedList(); /** * Descriptive information about this Realm implementation. */ protected static final String name = "CombinedRealm"; /** * Add a realm to the list of realms that will be used to authenticate * users. */ public void addRealm(Realm theRealm) { realms.add(theRealm); if (log.isDebugEnabled()) { sm.getString("combinedRealm.addRealm", theRealm.getInfo(), Integer.toString(realms.size())); } } /** * Return the set of Realms that this Realm is wrapping */ public ObjectName[] getRealms() { ObjectName[] result = new ObjectName[realms.size()]; for (Realm realm : realms) { if (realm instanceof RealmBase) { result[realms.indexOf(realm)] = ((RealmBase) realm).getObjectName(); } } return result; } /** * Return the Principal associated with the specified username, which * matches the digest calculated using the given parameters using the * method described in RFC 2069; otherwise return null. * * @param username Username of the Principal to look up * @param clientDigest Digest which has been submitted by the client * @param nonce Unique (or supposedly unique) token which has been used * for this request * @param realmName Realm name * @param md5a2 Second MD5 digest used to calculate the digest : * MD5(Method + ":" + uri) */ @Override public Principal authenticate(String username, String clientDigest, String nonce, String nc, String cnonce, String qop, String realmName, String md5a2) { Principal authenticatedUser = null; for (Realm realm : realms) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo())); } authenticatedUser = realm.authenticate(username, clientDigest, nonce, nc, cnonce, qop, realmName, md5a2); if (authenticatedUser == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo())); } } else { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authSuccess", username, realm.getInfo())); } break; } } return authenticatedUser; } /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public Principal authenticate(String username, String credentials) { Principal authenticatedUser = null; for (Realm realm : realms) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo())); } authenticatedUser = realm.authenticate(username, credentials); if (authenticatedUser == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo())); } } else { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authSuccess", username, realm.getInfo())); } break; } } return authenticatedUser; } /** * Set the Container with which this Realm has been associated. * * @param container The associated Container */ @Override public void setContainer(Container container) { for(Realm realm : realms) { // Set the realmPath for JMX naming if (realm instanceof RealmBase) { ((RealmBase) realm).setRealmPath( getRealmPath() + "/realm" + realms.indexOf(realm)); } // Set the container for sub-realms. Mainly so logging works. realm.setContainer(container); } super.setContainer(container); } /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // Start 'sub-realms' then this one Iterator iter = realms.iterator(); while (iter.hasNext()) { Realm realm = iter.next(); if (realm instanceof Lifecycle) { try { ((Lifecycle) realm).start(); } catch (LifecycleException e) { // If realm doesn't start can't authenticate against it iter.remove(); log.error(sm.getString("combinedRealm.realmStartFail", realm.getInfo()), e); } } } super.startInternal(); } /** * Gracefully terminate the active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { // Stop this realm, then the sub-realms (reverse order to start) super.stopInternal(); for (Realm realm : realms) { if (realm instanceof Lifecycle) { ((Lifecycle) realm).stop(); } } } /** * Ensure child Realms are destroyed when this Realm is destroyed. */ @Override protected void destroyInternal() throws LifecycleException { for (Realm realm : realms) { if (realm instanceof Lifecycle) { ((Lifecycle) realm).destroy(); } } super.destroyInternal(); } /** * Return the Principal associated with the specified chain of X509 * client certificates. If there is none, return null. * * @param certs Array of client certificates, with the first one in * the array being the certificate of the client itself. */ @Override public Principal authenticate(X509Certificate[] certs) { Principal authenticatedUser = null; String username = null; if (certs != null && certs.length >0) { username = certs[0].getSubjectDN().getName(); } for (Realm realm : realms) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo())); } authenticatedUser = realm.authenticate(certs); if (authenticatedUser == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo())); } } else { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authSuccess", username, realm.getInfo())); } break; } } return authenticatedUser; } /** * {@inheritDoc} */ @Override public Principal authenticate(GSSContext gssContext, boolean storeCreds) { if (gssContext.isEstablished()) { Principal authenticatedUser = null; String username = null; GSSName name = null; try { name = gssContext.getSrcName(); } catch (GSSException e) { log.warn(sm.getString("realmBase.gssNameFail"), e); return null; } username = name.toString(); for (Realm realm : realms) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authStart", username, realm.getInfo())); } authenticatedUser = realm.authenticate(gssContext, storeCreds); if (authenticatedUser == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authFail", username, realm.getInfo())); } } else { if (log.isDebugEnabled()) { log.debug(sm.getString("combinedRealm.authSuccess", username, realm.getInfo())); } break; } } return authenticatedUser; } // Fail in all other cases return null; } @Override protected String getName() { return name; } @Override protected String getPassword(String username) { // This method should never be called // Stack trace will show where this was called from UnsupportedOperationException uoe = new UnsupportedOperationException( sm.getString("combinedRealm.getPassword")); log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe); throw uoe; } @Override protected Principal getPrincipal(String username) { // This method should never be called // Stack trace will show where this was called from UnsupportedOperationException uoe = new UnsupportedOperationException( sm.getString("combinedRealm.getPrincipal")); log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe); throw uoe; } } tomcat7-7.0.52/java/org/apache/catalina/realm/GenericPrincipal.java0000644000175100017510000002027112271471332025035 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.Principal; import java.util.Arrays; import java.util.List; import javax.security.auth.login.LoginContext; import org.ietf.jgss.GSSCredential; /** * Generic implementation of java.security.Principal that * is available for use by Realm implementations. * * @author Craig R. McClanahan */ public class GenericPrincipal implements Principal { // ----------------------------------------------------------- Constructors /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password. * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user * * @deprecated Unused */ @Deprecated public GenericPrincipal(String name, String password) { this(name, password, null); } /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password, with the specified role names * (as Strings). * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user * @param roles List of roles (must be Strings) possessed by this user */ public GenericPrincipal(String name, String password, List roles) { this(name, password, roles, null); } /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password, with the specified role names * (as Strings). * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user * @param roles List of roles (must be Strings) possessed by this user * @param userPrincipal - the principal to be returned from the request * getUserPrincipal call if not null; if null, this will be returned */ public GenericPrincipal(String name, String password, List roles, Principal userPrincipal) { this(name, password, roles, userPrincipal, null); } /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password, with the specified role names * (as Strings). * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user * @param roles List of roles (must be Strings) possessed by this user * @param userPrincipal - the principal to be returned from the request * getUserPrincipal call if not null; if null, this will be returned * @param loginContext - If provided, this will be used to log out the user * at the appropriate time */ public GenericPrincipal(String name, String password, List roles, Principal userPrincipal, LoginContext loginContext) { this(name, password, roles, userPrincipal, loginContext, null); } /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password, with the specified role names * (as Strings). * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user * @param roles List of roles (must be Strings) possessed by this user * @param userPrincipal - the principal to be returned from the request * getUserPrincipal call if not null; if null, this will be returned * @param loginContext - If provided, this will be used to log out the user * at the appropriate time * @param gssCredential - If provided, the user's delegated credentials */ public GenericPrincipal(String name, String password, List roles, Principal userPrincipal, LoginContext loginContext, GSSCredential gssCredential) { super(); this.name = name; this.password = password; this.userPrincipal = userPrincipal; if (roles != null) { this.roles = new String[roles.size()]; this.roles = roles.toArray(this.roles); if (this.roles.length > 1) Arrays.sort(this.roles); } this.loginContext = loginContext; this.gssCredential = gssCredential; } // ------------------------------------------------------------- Properties /** * The username of the user represented by this Principal. */ protected String name = null; @Override public String getName() { return (this.name); } /** * The authentication credentials for the user represented by * this Principal. */ protected String password = null; public String getPassword() { return (this.password); } /** * The set of roles associated with this user. */ protected String roles[] = new String[0]; public String[] getRoles() { return (this.roles); } /** * The authenticated Principal to be exposed to applications. */ protected Principal userPrincipal = null; public Principal getUserPrincipal() { if (userPrincipal != null) { return userPrincipal; } else { return this; } } /** * The JAAS LoginContext, if any, used to authenticate this Principal. * Kept so we can call logout(). */ protected LoginContext loginContext = null; /** * The user's delegated credentials. */ protected GSSCredential gssCredential = null; public GSSCredential getGssCredential() { return this.gssCredential; } protected void setGssCredential(GSSCredential gssCredential) { this.gssCredential = gssCredential; } // --------------------------------------------------------- Public Methods /** * Does the user represented by this Principal possess the specified role? * * @param role Role to be tested */ public boolean hasRole(String role) { if("*".equals(role)) // Special 2.4 role meaning everyone return true; if (role == null) return (false); return (Arrays.binarySearch(roles, role) >= 0); } /** * Return a String representation of this object, which exposes only * information that should be public. */ @Override public String toString() { StringBuilder sb = new StringBuilder("GenericPrincipal["); sb.append(this.name); sb.append("("); for( int i=0;iRealm that reads an XML file to configure * the valid users, passwords, and roles. The file format (and default file * location) are identical to those currently supported by Tomcat 3.X. * * @author Craig R. McClanahan */ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { private static final Log log = LogFactory.getLog(RealmBase.class); // ----------------------------------------------------- Instance Variables /** * The Container with which this Realm is associated. */ protected Container container = null; /** * Container log */ protected Log containerLog = null; /** * Digest algorithm used in storing passwords in a non-plaintext format. * Valid values are those accepted for the algorithm name by the * MessageDigest class, or null if no digesting should * be performed. */ protected String digest = null; /** * The encoding charset for the digest. */ protected String digestEncoding = null; /** * Descriptive information about this Realm implementation. */ protected static final String info = "org.apache.catalina.realm.RealmBase/1.0"; /** * The MessageDigest object for digesting user credentials (passwords). */ protected volatile MessageDigest md = null; /** * The MD5 helper object for this class. * * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected static final MD5Encoder md5Encoder = new MD5Encoder(); /** * MD5 message digest provider. */ protected static volatile MessageDigest md5Helper; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); /** * Should we validate client certificate chains when they are presented? */ protected boolean validate = true; /** * The name of the class to use for retrieving user names from X509 * certificates. */ protected String x509UsernameRetrieverClassName; /** * The object that will extract user names from X509 client certificates. */ protected X509UsernameRetriever x509UsernameRetriever; /** * The all role mode. */ protected AllRolesMode allRolesMode = AllRolesMode.STRICT_MODE; /** * When processing users authenticated via the GSS-API, should any * "@..." be stripped from the end of the user name? */ protected boolean stripRealmForGss = true; // ------------------------------------------------------------- Properties /** * Return the Container with which this Realm has been associated. */ @Override public Container getContainer() { return (container); } /** * Set the Container with which this Realm has been associated. * * @param container The associated Container */ @Override public void setContainer(Container container) { Container oldContainer = this.container; this.container = container; support.firePropertyChange("container", oldContainer, this.container); } /** * Return the all roles mode. */ public String getAllRolesMode() { return allRolesMode.toString(); } /** * Set the all roles mode. */ public void setAllRolesMode(String allRolesMode) { this.allRolesMode = AllRolesMode.toMode(allRolesMode); } /** * Return the digest algorithm used for storing credentials. */ public String getDigest() { return digest; } /** * Set the digest algorithm used for storing credentials. * * @param digest The new digest algorithm */ public void setDigest(String digest) { this.digest = digest; } /** * Returns the digest encoding charset. * * @return The charset (may be null) for platform default */ public String getDigestEncoding() { return digestEncoding; } /** * Sets the digest encoding charset. * * @param charset The charset (null for platform default) */ public void setDigestEncoding(String charset) { digestEncoding = charset; } protected Charset getDigestCharset() throws UnsupportedEncodingException { if (digestEncoding == null) { return Charset.defaultCharset(); } else { return B2CConverter.getCharset(getDigestEncoding()); } } /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } /** * Return the "validate certificate chains" flag. */ public boolean getValidate() { return (this.validate); } /** * Set the "validate certificate chains" flag. * * @param validate The new validate certificate chains flag */ public void setValidate(boolean validate) { this.validate = validate; } /** * Gets the name of the class that will be used to extract user names * from X509 client certificates. * @return The name of the class that will be used to extract user names * from X509 client certificates. */ public String getX509UsernameRetrieverClassName() { return x509UsernameRetrieverClassName; } /** * Sets the name of the class that will be used to extract user names * from X509 client certificates. The class must implement * (@link X509UsernameRetriever}. * * @param className The name of the class that will be used to extract user names * from X509 client certificates. */ public void setX509UsernameRetrieverClassName(String className) { this.x509UsernameRetrieverClassName = className; } public boolean isStripRealmForGss() { return stripRealmForGss; } public void setStripRealmForGss(boolean stripRealmForGss) { this.stripRealmForGss = stripRealmForGss; } // --------------------------------------------------------- Public Methods /** * Add a property change listener to this component. * * @param listener The listener to add */ @Override public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public Principal authenticate(String username, String credentials) { String serverCredentials = getPassword(username); boolean validated = compareCredentials(credentials, serverCredentials); if (!validated) { if (containerLog.isTraceEnabled()) { containerLog.trace(sm.getString("realmBase.authenticateFailure", username)); } return null; } if (containerLog.isTraceEnabled()) { containerLog.trace(sm.getString("realmBase.authenticateSuccess", username)); } return getPrincipal(username); } /** * Return the Principal associated with the specified username, which * matches the digest calculated using the given parameters using the * method described in RFC 2069; otherwise return null. * * @param username Username of the Principal to look up * @param clientDigest Digest which has been submitted by the client * @param nonce Unique (or supposedly unique) token which has been used * for this request * @param realm Realm name * @param md5a2 Second MD5 digest used to calculate the digest : * MD5(Method + ":" + uri) */ @Override public Principal authenticate(String username, String clientDigest, String nonce, String nc, String cnonce, String qop, String realm, String md5a2) { // In digest auth, digests are always lower case String md5a1 = getDigest(username, realm); if (md5a1 == null) return null; md5a1 = md5a1.toLowerCase(Locale.ENGLISH); String serverDigestValue; if (qop == null) { serverDigestValue = md5a1 + ":" + nonce + ":" + md5a2; } else { serverDigestValue = md5a1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + md5a2; } byte[] valueBytes = null; try { valueBytes = serverDigestValue.getBytes(getDigestCharset()); } catch (UnsupportedEncodingException uee) { log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); throw new IllegalArgumentException(uee.getMessage()); } String serverDigest = null; // Bugzilla 32137 synchronized(md5Helper) { serverDigest = MD5Encoder.encode(md5Helper.digest(valueBytes)); } if (log.isDebugEnabled()) { log.debug("Digest : " + clientDigest + " Username:" + username + " ClientSigest:" + clientDigest + " nonce:" + nonce + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop + " realm:" + realm + "md5a2:" + md5a2 + " Server digest:" + serverDigest); } if (serverDigest.equals(clientDigest)) { return getPrincipal(username); } return null; } /** * Return the Principal associated with the specified chain of X509 * client certificates. If there is none, return null. * * @param certs Array of client certificates, with the first one in * the array being the certificate of the client itself. */ @Override public Principal authenticate(X509Certificate certs[]) { if ((certs == null) || (certs.length < 1)) return (null); // Check the validity of each certificate in the chain if (log.isDebugEnabled()) log.debug("Authenticating client certificate chain"); if (validate) { for (int i = 0; i < certs.length; i++) { if (log.isDebugEnabled()) log.debug(" Checking validity for '" + certs[i].getSubjectDN().getName() + "'"); try { certs[i].checkValidity(); } catch (Exception e) { if (log.isDebugEnabled()) log.debug(" Validity exception", e); return (null); } } } // Check the existence of the client Principal in our database return (getPrincipal(certs[0])); } /** * {@inheritDoc} */ @Override public Principal authenticate(GSSContext gssContext, boolean storeCred) { if (gssContext.isEstablished()) { GSSName gssName = null; try { gssName = gssContext.getSrcName(); } catch (GSSException e) { log.warn(sm.getString("realmBase.gssNameFail"), e); } if (gssName!= null) { String name = gssName.toString(); if (isStripRealmForGss()) { int i = name.indexOf('@'); if (i > 0) { // Zero so we don;t leave a zero length name name = name.substring(0, i); } } GSSCredential gssCredential = null; if (storeCred && gssContext.getCredDelegState()) { try { gssCredential = gssContext.getDelegCred(); } catch (GSSException e) { if (log.isDebugEnabled()) { log.debug(sm.getString( "realmBase.delegatedCredentialFail", name), e); } } } return getPrincipal(name, gssCredential); } } // Fail in all other cases return null; } protected boolean compareCredentials(String userCredentials, String serverCredentials) { if (serverCredentials == null) { return false; } if (hasMessageDigest()) { // Some directories and databases prefix the password with the hash // type. The string is in a format compatible with Base64.encode not // the normal hex encoding of the digest if (serverCredentials.startsWith("{MD5}") || serverCredentials.startsWith("{SHA}")) { // Server is storing digested passwords with a prefix indicating // the digest type String serverDigest = serverCredentials.substring(5); String userDigest; synchronized (this) { md.reset(); md.update(userCredentials.getBytes(B2CConverter.ISO_8859_1)); userDigest = Base64.encodeBase64String(md.digest()); } return userDigest.equals(serverDigest); } else if (serverCredentials.startsWith("{SSHA}")) { // Server is storing digested passwords with a prefix indicating // the digest type and the salt used when creating that digest String serverDigestPlusSalt = serverCredentials.substring(6); // Need to convert the salt to bytes to apply it to the user's // digested password. byte[] serverDigestPlusSaltBytes = Base64.decodeBase64(serverDigestPlusSalt); final int saltPos = 20; byte[] serverDigestBytes = new byte[saltPos]; System.arraycopy(serverDigestPlusSaltBytes, 0, serverDigestBytes, 0, saltPos); // Generate the digested form of the user provided password // using the salt byte[] userDigestBytes; synchronized (this) { md.reset(); // User provided password md.update(userCredentials.getBytes(B2CConverter.ISO_8859_1)); // Add the salt md.update(serverDigestPlusSaltBytes, saltPos, serverDigestPlusSaltBytes.length - saltPos); userDigestBytes = md.digest(); } return Arrays.equals(userDigestBytes, serverDigestBytes); } else { // Hex hashes should be compared case-insensitively String userDigest = digest(userCredentials); return serverCredentials.equalsIgnoreCase(userDigest); } } else { // No digests, compare directly return serverCredentials.equals(userCredentials); } } /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ @Override public void backgroundProcess() { // NOOP in base class } /** * Return the SecurityConstraints configured to guard the request URI for * this request, or null if there is no such constraint. * * @param request Request we are processing * @param context Context the Request is mapped to */ @Override public SecurityConstraint [] findSecurityConstraints(Request request, Context context) { ArrayList results = null; // Are there any defined security constraints? SecurityConstraint constraints[] = context.findConstraints(); if ((constraints == null) || (constraints.length == 0)) { if (log.isDebugEnabled()) log.debug(" No applicable constraints defined"); return (null); } // Check each defined security constraint String uri = request.getRequestPathMB().toString(); // Bug47080 - in rare cases this may be null // Mapper treats as '/' do the same to prevent NPE if (uri == null) { uri = "/"; } String method = request.getMethod(); int i; boolean found = false; for (i = 0; i < constraints.length; i++) { SecurityCollection [] collection = constraints[i].findCollections(); // If collection is null, continue to avoid an NPE // See Bugzilla 30624 if ( collection == null) { continue; } if (log.isDebugEnabled()) { log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " + constraints[i].included(uri, method)); } for(int j=0; j < collection.length; j++){ String [] patterns = collection[j].findPatterns(); // If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if ( patterns == null) { continue; } for(int k=0; k < patterns.length; k++) { if(uri.equals(patterns[k])) { found = true; if(collection[j].findMethod(method)) { if(results == null) { results = new ArrayList(); } results.add(constraints[i]); } } } } } if(found) { return resultsToArray(results); } int longest = -1; for (i = 0; i < constraints.length; i++) { SecurityCollection [] collection = constraints[i].findCollections(); // If collection is null, continue to avoid an NPE // See Bugzilla 30624 if ( collection == null) { continue; } if (log.isDebugEnabled()) { log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " + constraints[i].included(uri, method)); } for(int j=0; j < collection.length; j++){ String [] patterns = collection[j].findPatterns(); // If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if ( patterns == null) { continue; } boolean matched = false; int length = -1; for(int k=0; k < patterns.length; k++) { String pattern = patterns[k]; if(pattern.startsWith("/") && pattern.endsWith("/*") && pattern.length() >= longest) { if(pattern.length() == 2) { matched = true; length = pattern.length(); } else if(pattern.regionMatches(0,uri,0, pattern.length()-1) || (pattern.length()-2 == uri.length() && pattern.regionMatches(0,uri,0, pattern.length()-2))) { matched = true; length = pattern.length(); } } } if(matched) { if(length > longest) { found = false; if(results != null) { results.clear(); } longest = length; } if(collection[j].findMethod(method)) { found = true; if(results == null) { results = new ArrayList(); } results.add(constraints[i]); } } } } if(found) { return resultsToArray(results); } for (i = 0; i < constraints.length; i++) { SecurityCollection [] collection = constraints[i].findCollections(); // If collection is null, continue to avoid an NPE // See Bugzilla 30624 if ( collection == null) { continue; } if (log.isDebugEnabled()) { log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " + constraints[i].included(uri, method)); } boolean matched = false; int pos = -1; for(int j=0; j < collection.length; j++){ String [] patterns = collection[j].findPatterns(); // If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if ( patterns == null) { continue; } for(int k=0; k < patterns.length && !matched; k++) { String pattern = patterns[k]; if(pattern.startsWith("*.")){ int slash = uri.lastIndexOf("/"); int dot = uri.lastIndexOf("."); if(slash >= 0 && dot > slash && dot != uri.length()-1 && uri.length()-dot == pattern.length()-1) { if(pattern.regionMatches(1,uri,dot,uri.length()-dot)) { matched = true; pos = j; } } } } } if(matched) { found = true; if(collection[pos].findMethod(method)) { if(results == null) { results = new ArrayList(); } results.add(constraints[i]); } } } if(found) { return resultsToArray(results); } for (i = 0; i < constraints.length; i++) { SecurityCollection [] collection = constraints[i].findCollections(); // If collection is null, continue to avoid an NPE // See Bugzilla 30624 if ( collection == null) { continue; } if (log.isDebugEnabled()) { log.debug(" Checking constraint '" + constraints[i] + "' against " + method + " " + uri + " --> " + constraints[i].included(uri, method)); } for(int j=0; j < collection.length; j++){ String [] patterns = collection[j].findPatterns(); // If patterns is null, continue to avoid an NPE // See Bugzilla 30624 if ( patterns == null) { continue; } boolean matched = false; for(int k=0; k < patterns.length && !matched; k++) { String pattern = patterns[k]; if(pattern.equals("/")){ matched = true; } } if(matched) { if(results == null) { results = new ArrayList(); } results.add(constraints[i]); } } } if(results == null) { // No applicable security constraint was found if (log.isDebugEnabled()) log.debug(" No applicable constraint located"); } return resultsToArray(results); } /** * Convert an ArrayList to a SecurityContraint []. */ private SecurityConstraint [] resultsToArray( ArrayList results) { if(results == null || results.size() == 0) { return null; } SecurityConstraint [] array = new SecurityConstraint[results.size()]; results.toArray(array); return array; } /** * Perform access control based on the specified authorization constraint. * Return true if this constraint is satisfied and processing * should continue, or false otherwise. * * @param request Request we are processing * @param response Response we are creating * @param constraints Security constraint we are enforcing * @param context The Context to which client of this class is attached. * * @exception IOException if an input/output error occurs */ @Override public boolean hasResourcePermission(Request request, Response response, SecurityConstraint []constraints, Context context) throws IOException { if (constraints == null || constraints.length == 0) return (true); // Which user principal have we already authenticated? Principal principal = request.getPrincipal(); boolean status = false; boolean denyfromall = false; for(int i=0; i < constraints.length; i++) { SecurityConstraint constraint = constraints[i]; String roles[]; if (constraint.getAllRoles()) { // * means all roles defined in web.xml roles = request.getContext().findSecurityRoles(); } else { roles = constraint.findAuthRoles(); } if (roles == null) roles = new String[0]; if (log.isDebugEnabled()) log.debug(" Checking roles " + principal); if (roles.length == 0 && !constraint.getAllRoles()) { if(constraint.getAuthConstraint()) { if( log.isDebugEnabled() ) log.debug("No roles"); status = false; // No listed roles means no access at all denyfromall = true; break; } if(log.isDebugEnabled()) log.debug("Passing all access"); status = true; } else if (principal == null) { if (log.isDebugEnabled()) log.debug(" No user authenticated, cannot grant access"); } else { for (int j = 0; j < roles.length; j++) { if (hasRole(null, principal, roles[j])) { status = true; if( log.isDebugEnabled() ) log.debug( "Role found: " + roles[j]); } else if( log.isDebugEnabled() ) log.debug( "No role found: " + roles[j]); } } } if (!denyfromall && allRolesMode != AllRolesMode.STRICT_MODE && !status && principal != null) { if (log.isDebugEnabled()) { log.debug("Checking for all roles mode: " + allRolesMode); } // Check for an all roles(role-name="*") for (int i = 0; i < constraints.length; i++) { SecurityConstraint constraint = constraints[i]; String roles[]; // If the all roles mode exists, sets if (constraint.getAllRoles()) { if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) { if (log.isDebugEnabled()) { log.debug("Granting access for role-name=*, auth-only"); } status = true; break; } // For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles roles = request.getContext().findSecurityRoles(); if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) { if (log.isDebugEnabled()) { log.debug("Granting access for role-name=*, strict auth-only"); } status = true; break; } } } } // Return a "Forbidden" message denying access to this resource if(!status) { response.sendError (HttpServletResponse.SC_FORBIDDEN, sm.getString("realmBase.forbidden")); } return status; } /** * Return true if the specified Principal has the specified * security role, within the context of this Realm; otherwise return * false. This method can be overridden by Realm * implementations, but the default is adequate when an instance of * GenericPrincipal is used to represent authenticated * Principals from this Realm. * * @param principal Principal for whom the role is to be checked * @param role Security role to be checked */ @Override public boolean hasRole(Wrapper wrapper, Principal principal, String role) { // Check for a role alias defined in a element if (wrapper != null) { String realRole = wrapper.findSecurityReference(role); if (realRole != null) role = realRole; } // Should be overridden in JAASRealm - to avoid pretty inefficient conversions if ((principal == null) || (role == null) || !(principal instanceof GenericPrincipal)) return (false); GenericPrincipal gp = (GenericPrincipal) principal; boolean result = gp.hasRole(role); if (log.isDebugEnabled()) { String name = principal.getName(); if (result) log.debug(sm.getString("realmBase.hasRoleSuccess", name, role)); else log.debug(sm.getString("realmBase.hasRoleFailure", name, role)); } return (result); } /** * Enforce any user data constraint required by the security constraint * guarding this request URI. Return true if this constraint * was not violated and processing should continue, or false * if we have created a response already. * * @param request Request we are processing * @param response Response we are creating * @param constraints Security constraint being checked * * @exception IOException if an input/output error occurs */ @Override public boolean hasUserDataPermission(Request request, Response response, SecurityConstraint []constraints) throws IOException { // Is there a relevant user data constraint? if (constraints == null || constraints.length == 0) { if (log.isDebugEnabled()) log.debug(" No applicable security constraint defined"); return (true); } for(int i=0; i < constraints.length; i++) { SecurityConstraint constraint = constraints[i]; String userConstraint = constraint.getUserConstraint(); if (userConstraint == null) { if (log.isDebugEnabled()) log.debug(" No applicable user data constraint defined"); return (true); } if (userConstraint.equals(Constants.NONE_TRANSPORT)) { if (log.isDebugEnabled()) log.debug(" User data constraint has no restrictions"); return (true); } } // Validate the request against the user data constraint if (request.getRequest().isSecure()) { if (log.isDebugEnabled()) log.debug(" User data constraint already satisfied"); return (true); } // Initialize variables we need to determine the appropriate action int redirectPort = request.getConnector().getRedirectPort(); // Is redirecting disabled? if (redirectPort <= 0) { if (log.isDebugEnabled()) log.debug(" SSL redirect is disabled"); response.sendError (HttpServletResponse.SC_FORBIDDEN, request.getRequestURI()); return (false); } // Redirect to the corresponding SSL port StringBuilder file = new StringBuilder(); String protocol = "https"; String host = request.getServerName(); // Protocol file.append(protocol).append("://").append(host); // Host with port if(redirectPort != 443) { file.append(":").append(redirectPort); } // URI file.append(request.getRequestURI()); String requestedSessionId = request.getRequestedSessionId(); if ((requestedSessionId != null) && request.isRequestedSessionIdFromURL()) { file.append(";"); file.append(SessionConfig.getSessionUriParamName( request.getContext())); file.append("="); file.append(requestedSessionId); } String queryString = request.getQueryString(); if (queryString != null) { file.append('?'); file.append(queryString); } if (log.isDebugEnabled()) log.debug(" Redirecting to " + file.toString()); response.sendRedirect(file.toString()); return (false); } /** * Remove a property change listener from this component. * * @param listener The listener to remove */ @Override public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } @Override protected void initInternal() throws LifecycleException { super.initInternal(); // We want logger as soon as possible if (container != null) { this.containerLog = container.getLogger(); } x509UsernameRetriever = createUsernameRetriever(x509UsernameRetrieverClassName); } /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // Create a MessageDigest instance for credentials, if desired if (digest != null) { try { md = MessageDigest.getInstance(digest); } catch (NoSuchAlgorithmException e) { throw new LifecycleException (sm.getString("realmBase.algorithm", digest), e); } } setState(LifecycleState.STARTING); } /** * Gracefully terminate the active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); // Clean up allocated resources md = null; } /** * Return a String representation of this component. */ @Override public String toString() { StringBuilder sb = new StringBuilder("Realm["); sb.append(getName()); sb.append(']'); return sb.toString(); } // ------------------------------------------------------ Protected Methods /** * Digest the password using the specified algorithm and * convert the result to a corresponding hexadecimal string. * If exception, the plain credentials string is returned. * * @param credentials Password or other credentials to use in * authenticating this username */ protected String digest(String credentials) { // If no MessageDigest instance is specified, return unchanged if (hasMessageDigest() == false) return (credentials); // Digest the user credentials and return as hexadecimal synchronized (this) { try { md.reset(); byte[] bytes = null; try { bytes = credentials.getBytes(getDigestCharset()); } catch (UnsupportedEncodingException uee) { log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); throw new IllegalArgumentException(uee.getMessage()); } md.update(bytes); return (HexUtils.toHexString(md.digest())); } catch (Exception e) { log.error(sm.getString("realmBase.digest"), e); return (credentials); } } } protected boolean hasMessageDigest() { return !(md == null); } /** * Return the digest associated with given principal's user name. */ protected String getDigest(String username, String realmName) { if (md5Helper == null) { try { md5Helper = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { log.error("Couldn't get MD5 digest: ", e); throw new IllegalStateException(e.getMessage()); } } if (hasMessageDigest()) { // Use pre-generated digest return getPassword(username); } String digestValue = username + ":" + realmName + ":" + getPassword(username); byte[] valueBytes = null; try { valueBytes = digestValue.getBytes(getDigestCharset()); } catch (UnsupportedEncodingException uee) { log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); throw new IllegalArgumentException(uee.getMessage()); } byte[] digest = null; // Bugzilla 32137 synchronized(md5Helper) { digest = md5Helper.digest(valueBytes); } return MD5Encoder.encode(digest); } /** * Return a short name for this Realm implementation, for use in * log messages. */ protected abstract String getName(); /** * Return the password associated with the given principal's user name. */ protected abstract String getPassword(String username); /** * Return the Principal associated with the given certificate. */ protected Principal getPrincipal(X509Certificate usercert) { String username = x509UsernameRetriever.getUsername(usercert); if(log.isDebugEnabled()) log.debug(sm.getString("realmBase.gotX509Username", username)); return(getPrincipal(username)); } /** * Return the Principal associated with the given user name. */ protected abstract Principal getPrincipal(String username); protected Principal getPrincipal(String username, GSSCredential gssCredential) { Principal p = getPrincipal(username); if (p instanceof GenericPrincipal) { ((GenericPrincipal) p).setGssCredential(gssCredential); } return p; } /** * Return the Server object that is the ultimate parent for the container * with which this Realm is associated. If the server cannot be found (eg * because the container hierarchy is not complete), null is * returned. */ protected Server getServer() { Container c = container; if (c instanceof Context) { c = c.getParent(); } if (c instanceof Host) { c = c.getParent(); } if (c instanceof Engine) { Service s = ((Engine)c).getService(); if (s != null) { return s.getServer(); } } return null; } // --------------------------------------------------------- Static Methods /** * Digest password using the algorithm specified and * convert the result to a corresponding hex string. * If exception, the plain credentials string is returned * * @param credentials Password or other credentials to use in * authenticating this username * @param algorithm Algorithm used to do the digest * @param encoding Character encoding of the string to digest */ public static final String Digest(String credentials, String algorithm, String encoding) { try { // Obtain a new message digest with "digest" encryption MessageDigest md = (MessageDigest) MessageDigest.getInstance(algorithm).clone(); // encode the credentials // Should use the digestEncoding, but that's not a static field if (encoding == null) { md.update(credentials.getBytes()); } else { md.update(credentials.getBytes(encoding)); } // Digest the credentials and return as hexadecimal return (HexUtils.toHexString(md.digest())); } catch(Exception ex) { log.error(ex); return credentials; } } /** * Digest password using the algorithm specified and * convert the result to a corresponding hex string. * If exception, the plain credentials string is returned */ public static void main(String args[]) { String encoding = null; int firstCredentialArg = 2; if (args.length > 4 && args[2].equalsIgnoreCase("-e")) { encoding = args[3]; firstCredentialArg = 4; } if(args.length > firstCredentialArg && args[0].equalsIgnoreCase("-a")) { for(int i=firstCredentialArg; i < args.length ; i++){ System.out.print(args[i]+":"); System.out.println(Digest(args[i], args[1], encoding)); } } else { System.out.println ("Usage: RealmBase -a [-e ] "); } } // -------------------- JMX and Registration -------------------- @Override public String getObjectNameKeyProperties() { StringBuilder keyProperties = new StringBuilder("type=Realm"); keyProperties.append(getRealmSuffix()); keyProperties.append(MBeanUtils.getContainerKeyProperties(container)); return keyProperties.toString(); } @Override public String getDomainInternal() { return MBeanUtils.getDomain(container); } protected String realmPath = "/realm0"; public String getRealmPath() { return realmPath; } public void setRealmPath(String theRealmPath) { realmPath = theRealmPath; } protected String getRealmSuffix() { return ",realmPath=" + getRealmPath(); } protected static class AllRolesMode { private String name; /** Use the strict servlet spec interpretation which requires that the user * have one of the web-app/security-role/role-name */ public static final AllRolesMode STRICT_MODE = new AllRolesMode("strict"); /** Allow any authenticated user */ public static final AllRolesMode AUTH_ONLY_MODE = new AllRolesMode("authOnly"); /** Allow any authenticated user only if there are no web-app/security-roles */ public static final AllRolesMode STRICT_AUTH_ONLY_MODE = new AllRolesMode("strictAuthOnly"); static AllRolesMode toMode(String name) { AllRolesMode mode; if( name.equalsIgnoreCase(STRICT_MODE.name) ) mode = STRICT_MODE; else if( name.equalsIgnoreCase(AUTH_ONLY_MODE.name) ) mode = AUTH_ONLY_MODE; else if( name.equalsIgnoreCase(STRICT_AUTH_ONLY_MODE.name) ) mode = STRICT_AUTH_ONLY_MODE; else throw new IllegalStateException("Unknown mode, must be one of: strict, authOnly, strictAuthOnly"); return mode; } private AllRolesMode(String name) { this.name = name; } @Override public boolean equals(Object o) { boolean equals = false; if( o instanceof AllRolesMode ) { AllRolesMode mode = (AllRolesMode) o; equals = name.equals(mode.name); } return equals; } @Override public int hashCode() { return name.hashCode(); } @Override public String toString() { return name; } } private static X509UsernameRetriever createUsernameRetriever(String className) throws LifecycleException { if(null == className || "".equals(className.trim())) return new X509SubjectDnRetriever(); try { @SuppressWarnings("unchecked") Class clazz = (Class)Class.forName(className); return clazz.newInstance(); } catch (ClassNotFoundException e) { throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.ClassNotFoundException", className), e); } catch (InstantiationException e) { throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.InstantiationException", className), e); } catch (IllegalAccessException e) { throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.IllegalAccessException", className), e); } catch (ClassCastException e) { throw new LifecycleException(sm.getString("realmBase.createUsernameRetriever.ClassCastException", className), e); } } } tomcat7-7.0.52/java/org/apache/catalina/realm/JAASCallbackHandler.java0000644000175100017510000001744212271471332025256 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.TextInputCallback; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.tomcat.util.res.StringManager; /** *

    Implementation of the JAAS CallbackHandler interface, * used to negotiate delivery of the username and credentials that were * specified to our constructor. No interaction with the user is required * (or possible).

    * *

    This CallbackHandler will pre-digest the supplied * password, if required by the <Realm> element in * server.xml.

    *

    At present, JAASCallbackHandler knows how to handle callbacks of * type javax.security.auth.callback.NameCallback and * javax.security.auth.callback.PasswordCallback.

    * * @author Craig R. McClanahan * @author Andrew R. Jaquith */ public class JAASCallbackHandler implements CallbackHandler { // ------------------------------------------------------------ Constructor /** * Construct a callback handler configured with the specified values. * Note that if the JAASRealm instance specifies digested passwords, * the password parameter will be pre-digested here. * * @param realm Our associated JAASRealm instance * @param username Username to be authenticated with * @param password Password to be authenticated with */ public JAASCallbackHandler(JAASRealm realm, String username, String password) { super(); this.realm = realm; this.username = username; if (realm.hasMessageDigest()) { this.password = realm.digest(password); } else { this.password = password; } } /** * Construct a callback handler for DIGEST authentication. * * @param realm Our associated JAASRealm instance * @param username Username to be authenticated with * @param password Password to be authenticated with * @param nonce Server generated nonce * @param nc Nonce count * @param cnonce Client generated nonce * @param qop Quality of protection applied to the message * @param realmName Realm name * @param md5a2 Second MD5 digest used to calculate the digest * MD5(Method + ":" + uri) * @param authMethod The authentication method in use */ public JAASCallbackHandler(JAASRealm realm, String username, String password, String nonce, String nc, String cnonce, String qop, String realmName, String md5a2, String authMethod) { this(realm, username, password); this.nonce = nonce; this.nc = nc; this.cnonce = cnonce; this.qop = qop; this.realmName = realmName; this.md5a2 = md5a2; this.authMethod = authMethod; } // ----------------------------------------------------- Instance Variables /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The password to be authenticated with. */ protected String password = null; /** * The associated JAASRealm instance. */ protected JAASRealm realm = null; /** * The username to be authenticated with. */ protected String username = null; /** * Server generated nonce. */ protected String nonce = null; /** * Nonce count. */ protected String nc = null; /** * Client generated nonce. */ protected String cnonce = null; /** * Quality of protection applied to the message. */ protected String qop; /** * Realm name. */ protected String realmName; /** * Second MD5 digest. */ protected String md5a2; /** * The authentication method to be used. If null, assume BASIC/FORM. */ protected String authMethod; // --------------------------------------------------------- Public Methods /** * Retrieve the information requested in the provided Callbacks. * This implementation only recognizes {@link NameCallback}, * {@link PasswordCallback} and {@link TextInputCallback}. * {@link TextInputCallback} is used to pass the various additional * parameters required for DIGEST authentication. * * @param callbacks The set of Callbacks to be processed * * @exception IOException if an input/output error occurs * @exception UnsupportedCallbackException if the login method requests * an unsupported callback type */ @Override public void handle(Callback callbacks[]) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { if (realm.getContainer().getLogger().isTraceEnabled()) realm.getContainer().getLogger().trace(sm.getString("jaasCallback.username", username)); ((NameCallback) callbacks[i]).setName(username); } else if (callbacks[i] instanceof PasswordCallback) { final char[] passwordcontents; if (password != null) { passwordcontents = password.toCharArray(); } else { passwordcontents = new char[0]; } ((PasswordCallback) callbacks[i]).setPassword (passwordcontents); } else if (callbacks[i] instanceof TextInputCallback) { TextInputCallback cb = ((TextInputCallback) callbacks[i]); if (cb.getPrompt().equals("nonce")) { cb.setText(nonce); } else if (cb.getPrompt().equals("nc")) { cb.setText(nc); } else if (cb.getPrompt().equals("cnonce")) { cb.setText(cnonce); } else if (cb.getPrompt().equals("qop")) { cb.setText(qop); } else if (cb.getPrompt().equals("realmName")) { cb.setText(realmName); } else if (cb.getPrompt().equals("md5a2")) { cb.setText(md5a2); } else if (cb.getPrompt().equals("authMethod")) { cb.setText(authMethod); } else { throw new UnsupportedCallbackException(callbacks[i]); } } else { throw new UnsupportedCallbackException(callbacks[i]); } } } } tomcat7-7.0.52/java/org/apache/catalina/realm/DataSourceRealm.java0000644000175100017510000004410712271471332024636 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.Principal; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import javax.naming.Context; import javax.sql.DataSource; import org.apache.catalina.LifecycleException; import org.apache.naming.ContextBindings; /** * * Implementation of Realm that works with any JDBC JNDI DataSource. * See the JDBCRealm.howto for more details on how to set up the database and * for configuration options. * * @author Glenn L. Nielsen * @author Craig R. McClanahan * @author Carson McDonald * @author Ignacio Ortega */ public class DataSourceRealm extends RealmBase { // ----------------------------------------------------- Instance Variables /** * The generated string for the roles PreparedStatement */ private String preparedRoles = null; /** * The generated string for the credentials PreparedStatement */ private String preparedCredentials = null; /** * The name of the JNDI JDBC DataSource */ protected String dataSourceName = null; /** * Descriptive information about this Realm implementation. */ protected static final String info = "org.apache.catalina.realm.DataSourceRealm/1.0"; /** * Context local datasource. */ protected boolean localDataSource = false; /** * Descriptive information about this Realm implementation. */ protected static final String name = "DataSourceRealm"; /** * The column in the user role table that names a role */ protected String roleNameCol = null; /** * The column in the user table that holds the user's credentials */ protected String userCredCol = null; /** * The column in the user table that holds the user's name */ protected String userNameCol = null; /** * The table that holds the relation between user's and roles */ protected String userRoleTable = null; /** * The table that holds user data. */ protected String userTable = null; // ------------------------------------------------------------- Properties /** * Return the name of the JNDI JDBC DataSource. * */ public String getDataSourceName() { return dataSourceName; } /** * Set the name of the JNDI JDBC DataSource. * * @param dataSourceName the name of the JNDI JDBC DataSource */ public void setDataSourceName( String dataSourceName) { this.dataSourceName = dataSourceName; } /** * Return if the datasource will be looked up in the webapp JNDI Context. */ public boolean getLocalDataSource() { return localDataSource; } /** * Set to true to cause the datasource to be looked up in the webapp JNDI * Context. * * @param localDataSource the new flag value */ public void setLocalDataSource(boolean localDataSource) { this.localDataSource = localDataSource; } /** * Return the column in the user role table that names a role. * */ public String getRoleNameCol() { return roleNameCol; } /** * Set the column in the user role table that names a role. * * @param roleNameCol The column name */ public void setRoleNameCol( String roleNameCol ) { this.roleNameCol = roleNameCol; } /** * Return the column in the user table that holds the user's credentials. * */ public String getUserCredCol() { return userCredCol; } /** * Set the column in the user table that holds the user's credentials. * * @param userCredCol The column name */ public void setUserCredCol( String userCredCol ) { this.userCredCol = userCredCol; } /** * Return the column in the user table that holds the user's name. * */ public String getUserNameCol() { return userNameCol; } /** * Set the column in the user table that holds the user's name. * * @param userNameCol The column name */ public void setUserNameCol( String userNameCol ) { this.userNameCol = userNameCol; } /** * Return the table that holds the relation between user's and roles. * */ public String getUserRoleTable() { return userRoleTable; } /** * Set the table that holds the relation between user's and roles. * * @param userRoleTable The table name */ public void setUserRoleTable( String userRoleTable ) { this.userRoleTable = userRoleTable; } /** * Return the table that holds user data.. * */ public String getUserTable() { return userTable; } /** * Set the table that holds user data. * * @param userTable The table name */ public void setUserTable( String userTable ) { this.userTable = userTable; } /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } // --------------------------------------------------------- Public Methods /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * If there are any errors with the JDBC connection, executing * the query or anything we return null (don't authenticate). This * event is also logged, and the connection will be closed so that * a subsequent request will automatically re-open it. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public Principal authenticate(String username, String credentials) { // No user or no credentials // Can't possibly authenticate, don't bother the database then if (username == null || credentials == null) { return null; } Connection dbConnection = null; // Ensure that we have an open database connection dbConnection = open(); if (dbConnection == null) { // If the db connection open fails, return "not authenticated" return null; } // Acquire a Principal object for this user Principal principal = authenticate(dbConnection, username, credentials); close(dbConnection); return principal; } // -------------------------------------------------------- Package Methods // ------------------------------------------------------ Protected Methods /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param dbConnection The database connection to be used * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ protected Principal authenticate(Connection dbConnection, String username, String credentials) { String dbCredentials = getPassword(dbConnection, username); // Validate the user's credentials boolean validated = compareCredentials(credentials, dbCredentials); if (validated) { if (containerLog.isTraceEnabled()) containerLog.trace( sm.getString("dataSourceRealm.authenticateSuccess", username)); } else { if (containerLog.isTraceEnabled()) containerLog.trace( sm.getString("dataSourceRealm.authenticateFailure", username)); return (null); } ArrayList list = getRoles(dbConnection, username); // Create and return a suitable Principal for this user return new GenericPrincipal(username, credentials, list); } /** * Close the specified database connection. * * @param dbConnection The connection to be closed */ protected void close(Connection dbConnection) { // Do nothing if the database connection is already closed if (dbConnection == null) return; // Commit if not auto committed try { if (!dbConnection.getAutoCommit()) { dbConnection.commit(); } } catch (SQLException e) { containerLog.error("Exception committing connection before closing:", e); } // Close this database connection, and log any errors try { dbConnection.close(); } catch (SQLException e) { containerLog.error(sm.getString("dataSourceRealm.close"), e); // Just log it here } } /** * Open the specified database connection. * * @return Connection to the database */ protected Connection open() { try { Context context = null; if (localDataSource) { context = ContextBindings.getClassLoader(); context = (Context) context.lookup("comp/env"); } else { context = getServer().getGlobalNamingContext(); } DataSource dataSource = (DataSource)context.lookup(dataSourceName); return dataSource.getConnection(); } catch (Exception e) { // Log the problem for posterity containerLog.error(sm.getString("dataSourceRealm.exception"), e); } return null; } /** * Return a short name for this Realm implementation. */ @Override protected String getName() { return (name); } /** * Return the password associated with the given principal's user name. */ @Override protected String getPassword(String username) { Connection dbConnection = null; // Ensure that we have an open database connection dbConnection = open(); if (dbConnection == null) { return null; } try { return getPassword(dbConnection, username); } finally { close(dbConnection); } } /** * Return the password associated with the given principal's user name. * @param dbConnection The database connection to be used * @param username Username for which password should be retrieved */ protected String getPassword(Connection dbConnection, String username) { ResultSet rs = null; PreparedStatement stmt = null; String dbCredentials = null; try { stmt = credentials(dbConnection, username); rs = stmt.executeQuery(); if (rs.next()) { dbCredentials = rs.getString(1); } return (dbCredentials != null) ? dbCredentials.trim() : null; } catch(SQLException e) { containerLog.error( sm.getString("dataSourceRealm.getPassword.exception", username), e); } finally { try { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } } catch (SQLException e) { containerLog.error( sm.getString("dataSourceRealm.getPassword.exception", username), e); } } return null; } /** * Return the Principal associated with the given user name. */ @Override protected Principal getPrincipal(String username) { Connection dbConnection = open(); if (dbConnection == null) { return new GenericPrincipal(username, null, null); } try { return (new GenericPrincipal(username, getPassword(dbConnection, username), getRoles(dbConnection, username))); } finally { close(dbConnection); } } /** * Return the roles associated with the given user name. * @param username Username for which roles should be retrieved */ protected ArrayList getRoles(String username) { Connection dbConnection = null; // Ensure that we have an open database connection dbConnection = open(); if (dbConnection == null) { return null; } try { return getRoles(dbConnection, username); } finally { close(dbConnection); } } /** * Return the roles associated with the given user name * @param dbConnection The database connection to be used * @param username Username for which roles should be retrieved */ protected ArrayList getRoles(Connection dbConnection, String username) { if (allRolesMode != AllRolesMode.STRICT_MODE && !isRoleStoreDefined()) { // Using an authentication only configuration and no role store has // been defined so don't spend cycles looking return null; } ResultSet rs = null; PreparedStatement stmt = null; ArrayList list = null; try { stmt = roles(dbConnection, username); rs = stmt.executeQuery(); list = new ArrayList(); while (rs.next()) { String role = rs.getString(1); if (role != null) { list.add(role.trim()); } } return list; } catch(SQLException e) { containerLog.error( sm.getString("dataSourceRealm.getRoles.exception", username), e); } finally { try { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } } catch (SQLException e) { containerLog.error( sm.getString("dataSourceRealm.getRoles.exception", username), e); } } return null; } /** * Return a PreparedStatement configured to perform the SELECT required * to retrieve user credentials for the specified username. * * @param dbConnection The database connection to be used * @param username Username for which credentials should be retrieved * * @exception SQLException if a database error occurs */ private PreparedStatement credentials(Connection dbConnection, String username) throws SQLException { PreparedStatement credentials = dbConnection.prepareStatement(preparedCredentials); credentials.setString(1, username); return (credentials); } /** * Return a PreparedStatement configured to perform the SELECT required * to retrieve user roles for the specified username. * * @param dbConnection The database connection to be used * @param username Username for which roles should be retrieved * * @exception SQLException if a database error occurs */ private PreparedStatement roles(Connection dbConnection, String username) throws SQLException { PreparedStatement roles = dbConnection.prepareStatement(preparedRoles); roles.setString(1, username); return (roles); } private boolean isRoleStoreDefined() { return userRoleTable != null || roleNameCol != null; } // ------------------------------------------------------ Lifecycle Methods /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // Create the roles PreparedStatement string StringBuilder temp = new StringBuilder("SELECT "); temp.append(roleNameCol); temp.append(" FROM "); temp.append(userRoleTable); temp.append(" WHERE "); temp.append(userNameCol); temp.append(" = ?"); preparedRoles = temp.toString(); // Create the credentials PreparedStatement string temp = new StringBuilder("SELECT "); temp.append(userCredCol); temp.append(" FROM "); temp.append(userTable); temp.append(" WHERE "); temp.append(userNameCol); temp.append(" = ?"); preparedCredentials = temp.toString(); super.startInternal(); } } tomcat7-7.0.52/java/org/apache/catalina/realm/package.html0000644000175100017510000000774412271471332023247 0ustar locutuslocutus

    This package contains Realm implementations for the various supported realm technologies for authenticating users and identifying their associated roles. The Realm that is associated with a web application's Context (or a hierarchically superior Container) is used to resolve authentication and role presence questions when a web application uses container managed security as described in the Servlet API Specification, version 2.2.

    The implementations share a common base class that supports basic functionality for all of the standard Realm implementations, and can be configured by setting the following properties (default values are in square brackets):

    • debug - Debugging detail level for this component. [0]

    The standard Realm implementations that are currently available include the following (with additional configuration properties as specified):

    • JDBCRealm - Implementation of Realm that operates from data stored in a relational database that is accessed via a JDBC driver. The name of the driver, database connection information, and the names of the relevant tables and columns are configured with the following additional properties:
      • connectionURL - The URL to use when connecting to this database. [REQUIRED - NO DEFAULT]
      • driverName - Fully qualified Java class name of the JDBC driver to be used. [REQUIRED - NO DEFAULT]
      • roleNameCol - Name of the database column that contains role names. [REQUIRED - NO DEFAULT]
      • userCredCol - Name of the database column that contains the user's credentials (i.e. password) in cleartext. [REQUIRED - NO DEFAULT]
      • userNameCol - Name of the database column that contains the user's logon username. [REQUIRED - NO DEFAULT]
      • userRoleTable - Name of the database table containing user role information. This table must include the columns specified by the userNameCol and roleNameCol properties. [REQUIRED - NO DEFAULT]
      • userTable - Name of the database table containing user information. This table must include the columns specified by the userNameCol and userCredCol properties. [REQUIRED - NO DEFAULT]
    • MemoryRealm - Implementation of Realm that uses the contents of a simple XML file (conf/tomcat-users.xml) as the list of valid users and their roles. This implementation is primarily to demonstrate that the authentication technology functions correctly, and is not anticipated as adequate for general purpose use. This component supports the following additional properties:
      • pathname - Pathname of the XML file containing our user and role information. If a relative pathname is specified, it is resolved against the pathname specified by the "catalina.home" system property. [conf/tomcat-users.xml]
    tomcat7-7.0.52/java/org/apache/catalina/realm/UserDatabaseRealm.java0000644000175100017510000002036012271471332025142 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.Principal; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.naming.Context; import org.apache.catalina.Group; import org.apache.catalina.LifecycleException; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; import org.apache.catalina.Wrapper; import org.apache.tomcat.util.ExceptionUtils; /** *

    Implementation of {@link org.apache.catalina.Realm} that is based on an implementation of * {@link UserDatabase} made available through the global JNDI resources * configured for this instance of Catalina. Set the resourceName * parameter to the global JNDI resources name for the configured instance * of UserDatabase that we should consult.

    * * @author Craig R. McClanahan * @since 4.1 */ public class UserDatabaseRealm extends RealmBase { // ----------------------------------------------------- Instance Variables /** * The UserDatabase we will use to authenticate users * and identify associated roles. */ protected UserDatabase database = null; /** * Descriptive information about this Realm implementation. */ protected static final String info = "org.apache.catalina.realm.UserDatabaseRealm/1.0"; /** * Descriptive information about this Realm implementation. */ protected static final String name = "UserDatabaseRealm"; /** * The global JNDI name of the UserDatabase resource * we will be utilizing. */ protected String resourceName = "UserDatabase"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } /** * Return the global JNDI name of the UserDatabase resource * we will be using. */ public String getResourceName() { return resourceName; } /** * Set the global JNDI name of the UserDatabase resource * we will be using. * * @param resourceName The new global JNDI name */ public void setResourceName(String resourceName) { this.resourceName = resourceName; } // --------------------------------------------------------- Public Methods /** * Return true if the specified Principal has the specified * security role, within the context of this Realm; otherwise return * false. This implementation returns true * if the User has the role, or if any Group * that the User is a member of has the role. * * @param principal Principal for whom the role is to be checked * @param role Security role to be checked */ @Override public boolean hasRole(Wrapper wrapper, Principal principal, String role) { // Check for a role alias defined in a element if (wrapper != null) { String realRole = wrapper.findSecurityReference(role); if (realRole != null) role = realRole; } if( principal instanceof GenericPrincipal) { GenericPrincipal gp = (GenericPrincipal)principal; if(gp.getUserPrincipal() instanceof User) { principal = gp.getUserPrincipal(); } } if(! (principal instanceof User) ) { //Play nice with SSO and mixed Realms return super.hasRole(null, principal, role); } if("*".equals(role)) { return true; } else if(role == null) { return false; } User user = (User)principal; Role dbrole = database.findRole(role); if(dbrole == null) { return false; } if(user.isInRole(dbrole)) { return true; } Iterator groups = user.getGroups(); while(groups.hasNext()) { Group group = groups.next(); if(group.isInRole(dbrole)) { return true; } } return false; } // ------------------------------------------------------ Protected Methods /** * Return a short name for this Realm implementation. */ @Override protected String getName() { return (name); } /** * Return the password associated with the given principal's user name. */ @Override protected String getPassword(String username) { User user = database.findUser(username); if (user == null) { return null; } return (user.getPassword()); } /** * Return the Principal associated with the given user name. */ @Override protected Principal getPrincipal(String username) { User user = database.findUser(username); if(user == null) { return null; } List roles = new ArrayList(); Iterator uroles = user.getRoles(); while(uroles.hasNext()) { Role role = uroles.next(); roles.add(role.getName()); } Iterator groups = user.getGroups(); while(groups.hasNext()) { Group group = groups.next(); uroles = group.getRoles(); while(uroles.hasNext()) { Role role = uroles.next(); roles.add(role.getName()); } } return new GenericPrincipal(username, user.getPassword(), roles, user); } // ------------------------------------------------------ Lifecycle Methods /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { try { Context context = getServer().getGlobalNamingContext(); database = (UserDatabase) context.lookup(resourceName); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); containerLog.error(sm.getString("userDatabaseRealm.lookup", resourceName), e); database = null; } if (database == null) { throw new LifecycleException (sm.getString("userDatabaseRealm.noDatabase", resourceName)); } super.startInternal(); } /** * Gracefully terminate the active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { // Perform normal superclass finalization super.stopInternal(); // Release reference to our user database database = null; } } tomcat7-7.0.52/java/org/apache/catalina/realm/JDBCRealm.java0000644000175100017510000005570012271471332023307 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.Principal; import java.sql.Connection; import java.sql.Driver; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Properties; import org.apache.catalina.LifecycleException; import org.apache.tomcat.util.ExceptionUtils; /** * * Implementation of Realm that works with any JDBC supported database. * See the JDBCRealm.howto for more details on how to set up the database and * for configuration options. * *

    For a Realm implementation that supports connection pooling and * doesn't require synchronisation of authenticate(), * getPassword(), roles() and * getPrincipal() or the ugly connection logic use the * DataSourceRealm.

    * * @author Craig R. McClanahan * @author Carson McDonald * @author Ignacio Ortega */ public class JDBCRealm extends RealmBase { // ----------------------------------------------------- Instance Variables /** * The connection username to use when trying to connect to the database. */ protected String connectionName = null; /** * The connection URL to use when trying to connect to the database. */ protected String connectionPassword = null; /** * The connection URL to use when trying to connect to the database. */ protected String connectionURL = null; /** * The connection to the database. */ protected Connection dbConnection = null; /** * Instance of the JDBC Driver class we use as a connection factory. */ protected Driver driver = null; /** * The JDBC driver to use. */ protected String driverName = null; /** * Descriptive information about this Realm implementation. */ protected static final String info = "org.apache.catalina.realm.JDBCRealm/1.0"; /** * Descriptive information about this Realm implementation. */ protected static final String name = "JDBCRealm"; /** * The PreparedStatement to use for authenticating users. */ protected PreparedStatement preparedCredentials = null; /** * The PreparedStatement to use for identifying the roles for * a specified user. */ protected PreparedStatement preparedRoles = null; /** * The column in the user role table that names a role */ protected String roleNameCol = null; /** * The column in the user table that holds the user's credentials */ protected String userCredCol = null; /** * The column in the user table that holds the user's name */ protected String userNameCol = null; /** * The table that holds the relation between user's and roles */ protected String userRoleTable = null; /** * The table that holds user data. */ protected String userTable = null; // ------------------------------------------------------------- Properties /** * Return the username to use to connect to the database. * */ public String getConnectionName() { return connectionName; } /** * Set the username to use to connect to the database. * * @param connectionName Username */ public void setConnectionName(String connectionName) { this.connectionName = connectionName; } /** * Return the password to use to connect to the database. * */ public String getConnectionPassword() { return connectionPassword; } /** * Set the password to use to connect to the database. * * @param connectionPassword User password */ public void setConnectionPassword(String connectionPassword) { this.connectionPassword = connectionPassword; } /** * Return the URL to use to connect to the database. * */ public String getConnectionURL() { return connectionURL; } /** * Set the URL to use to connect to the database. * * @param connectionURL The new connection URL */ public void setConnectionURL( String connectionURL ) { this.connectionURL = connectionURL; } /** * Return the JDBC driver that will be used. * */ public String getDriverName() { return driverName; } /** * Set the JDBC driver that will be used. * * @param driverName The driver name */ public void setDriverName( String driverName ) { this.driverName = driverName; } /** * Return the column in the user role table that names a role. * */ public String getRoleNameCol() { return roleNameCol; } /** * Set the column in the user role table that names a role. * * @param roleNameCol The column name */ public void setRoleNameCol( String roleNameCol ) { this.roleNameCol = roleNameCol; } /** * Return the column in the user table that holds the user's credentials. * */ public String getUserCredCol() { return userCredCol; } /** * Set the column in the user table that holds the user's credentials. * * @param userCredCol The column name */ public void setUserCredCol( String userCredCol ) { this.userCredCol = userCredCol; } /** * Return the column in the user table that holds the user's name. * */ public String getUserNameCol() { return userNameCol; } /** * Set the column in the user table that holds the user's name. * * @param userNameCol The column name */ public void setUserNameCol( String userNameCol ) { this.userNameCol = userNameCol; } /** * Return the table that holds the relation between user's and roles. * */ public String getUserRoleTable() { return userRoleTable; } /** * Set the table that holds the relation between user's and roles. * * @param userRoleTable The table name */ public void setUserRoleTable( String userRoleTable ) { this.userRoleTable = userRoleTable; } /** * Return the table that holds user data.. * */ public String getUserTable() { return userTable; } /** * Set the table that holds user data. * * @param userTable The table name */ public void setUserTable( String userTable ) { this.userTable = userTable; } /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } // --------------------------------------------------------- Public Methods /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * If there are any errors with the JDBC connection, executing * the query or anything we return null (don't authenticate). This * event is also logged, and the connection will be closed so that * a subsequent request will automatically re-open it. * * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public synchronized Principal authenticate(String username, String credentials) { // Number of tries is the number of attempts to connect to the database // during this login attempt (if we need to open the database) // This needs rewritten with better pooling support, the existing code // needs signature changes since the Prepared statements needs cached // with the connections. // The code below will try twice if there is a SQLException so the // connection may try to be opened again. On normal conditions (including // invalid login - the above is only used once. int numberOfTries = 2; while (numberOfTries>0) { try { // Ensure that we have an open database connection open(); // Acquire a Principal object for this user Principal principal = authenticate(dbConnection, username, credentials); // Return the Principal (if any) return (principal); } catch (SQLException e) { // Log the problem for posterity containerLog.error(sm.getString("jdbcRealm.exception"), e); // Close the connection so that it gets reopened next time if (dbConnection != null) close(dbConnection); } numberOfTries--; } // Worst case scenario return null; } // -------------------------------------------------------- Package Methods // ------------------------------------------------------ Protected Methods /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param dbConnection The database connection to be used * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ public synchronized Principal authenticate(Connection dbConnection, String username, String credentials) { // No user or no credentials // Can't possibly authenticate, don't bother the database then if (username == null || credentials == null) { return null; } // Look up the user's credentials String dbCredentials = getPassword(username); // Validate the user's credentials boolean validated = compareCredentials(credentials, dbCredentials); if (validated) { if (containerLog.isTraceEnabled()) containerLog.trace(sm.getString("jdbcRealm.authenticateSuccess", username)); } else { if (containerLog.isTraceEnabled()) containerLog.trace(sm.getString("jdbcRealm.authenticateFailure", username)); return (null); } ArrayList roles = getRoles(username); // Create and return a suitable Principal for this user return (new GenericPrincipal(username, credentials, roles)); } /** * Close the specified database connection. * * @param dbConnection The connection to be closed */ protected void close(Connection dbConnection) { // Do nothing if the database connection is already closed if (dbConnection == null) return; // Close our prepared statements (if any) try { preparedCredentials.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.preparedCredentials = null; try { preparedRoles.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.preparedRoles = null; // Close this database connection, and log any errors try { dbConnection.close(); } catch (SQLException e) { containerLog.warn(sm.getString("jdbcRealm.close"), e); // Just log it here } finally { this.dbConnection = null; } } /** * Return a PreparedStatement configured to perform the SELECT required * to retrieve user credentials for the specified username. * * @param dbConnection The database connection to be used * @param username Username for which credentials should be retrieved * * @exception SQLException if a database error occurs */ protected PreparedStatement credentials(Connection dbConnection, String username) throws SQLException { if (preparedCredentials == null) { StringBuilder sb = new StringBuilder("SELECT "); sb.append(userCredCol); sb.append(" FROM "); sb.append(userTable); sb.append(" WHERE "); sb.append(userNameCol); sb.append(" = ?"); if(containerLog.isDebugEnabled()) { containerLog.debug("credentials query: " + sb.toString()); } preparedCredentials = dbConnection.prepareStatement(sb.toString()); } if (username == null) { preparedCredentials.setNull(1,java.sql.Types.VARCHAR); } else { preparedCredentials.setString(1, username); } return (preparedCredentials); } /** * Return a short name for this Realm implementation. */ @Override protected String getName() { return (name); } /** * Return the password associated with the given principal's user name. */ @Override protected synchronized String getPassword(String username) { // Look up the user's credentials String dbCredentials = null; PreparedStatement stmt = null; ResultSet rs = null; // Number of tries is the number of attempts to connect to the database // during this login attempt (if we need to open the database) // This needs rewritten with better pooling support, the existing code // needs signature changes since the Prepared statements needs cached // with the connections. // The code below will try twice if there is a SQLException so the // connection may try to be opened again. On normal conditions (including // invalid login - the above is only used once. int numberOfTries = 2; while (numberOfTries > 0) { try { // Ensure that we have an open database connection open(); stmt = credentials(dbConnection, username); rs = stmt.executeQuery(); if (rs.next()) { dbCredentials = rs.getString(1); } dbConnection.commit(); if (dbCredentials != null) { dbCredentials = dbCredentials.trim(); } return dbCredentials; } catch (SQLException e) { // Log the problem for posterity containerLog.error(sm.getString("jdbcRealm.exception"), e); } finally { if (rs != null) { try { rs.close(); } catch(SQLException e) { containerLog.warn(sm.getString( "jdbcRealm.abnormalCloseResultSet")); } } } // Close the connection so that it gets reopened next time if (dbConnection != null) { close(dbConnection); } numberOfTries--; } return (null); } /** * Return the Principal associated with the given user name. */ @Override protected synchronized Principal getPrincipal(String username) { return (new GenericPrincipal(username, getPassword(username), getRoles(username))); } /** * Return the roles associated with the gven user name. */ protected ArrayList getRoles(String username) { if (allRolesMode != AllRolesMode.STRICT_MODE && !isRoleStoreDefined()) { // Using an authentication only configuration and no role store has // been defined so don't spend cycles looking return null; } PreparedStatement stmt = null; ResultSet rs = null; // Number of tries is the number of attempts to connect to the database // during this login attempt (if we need to open the database) // This needs rewritten wuth better pooling support, the existing code // needs signature changes since the Prepared statements needs cached // with the connections. // The code below will try twice if there is a SQLException so the // connection may try to be opened again. On normal conditions (including // invalid login - the above is only used once. int numberOfTries = 2; while (numberOfTries>0) { try { // Ensure that we have an open database connection open(); try { // Accumulate the user's roles ArrayList roleList = new ArrayList(); stmt = roles(dbConnection, username); rs = stmt.executeQuery(); while (rs.next()) { String role = rs.getString(1); if (null!=role) { roleList.add(role.trim()); } } rs.close(); rs = null; return (roleList); } finally { if (rs!=null) { try { rs.close(); } catch(SQLException e) { containerLog.warn(sm.getString("jdbcRealm.abnormalCloseResultSet")); } } dbConnection.commit(); } } catch (SQLException e) { // Log the problem for posterity containerLog.error(sm.getString("jdbcRealm.exception"), e); // Close the connection so that it gets reopened next time if (dbConnection != null) close(dbConnection); } numberOfTries--; } return null; } /** * Open (if necessary) and return a database connection for use by * this Realm. * * @exception SQLException if a database error occurs */ protected Connection open() throws SQLException { // Do nothing if there is a database connection already open if (dbConnection != null) return (dbConnection); // Instantiate our database driver if necessary if (driver == null) { try { Class clazz = Class.forName(driverName); driver = (Driver) clazz.newInstance(); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); throw new SQLException(e.getMessage(), e); } } // Open a new connection Properties props = new Properties(); if (connectionName != null) props.put("user", connectionName); if (connectionPassword != null) props.put("password", connectionPassword); dbConnection = driver.connect(connectionURL, props); if (dbConnection == null) { throw new SQLException(sm.getString( "jdbcRealm.open.invalidurl",driverName, connectionURL)); } dbConnection.setAutoCommit(false); return (dbConnection); } /** * Release our use of this connection so that it can be recycled. * * @param dbConnection The connection to be released * * @deprecated Unused */ @Deprecated protected void release(Connection dbConnection) { // NO-OP since we are not pooling anything } /** * Return a PreparedStatement configured to perform the SELECT required * to retrieve user roles for the specified username. * * @param dbConnection The database connection to be used * @param username Username for which roles should be retrieved * * @exception SQLException if a database error occurs */ protected synchronized PreparedStatement roles(Connection dbConnection, String username) throws SQLException { if (preparedRoles == null) { StringBuilder sb = new StringBuilder("SELECT "); sb.append(roleNameCol); sb.append(" FROM "); sb.append(userRoleTable); sb.append(" WHERE "); sb.append(userNameCol); sb.append(" = ?"); preparedRoles = dbConnection.prepareStatement(sb.toString()); } preparedRoles.setString(1, username); return (preparedRoles); } private boolean isRoleStoreDefined() { return userRoleTable != null || roleNameCol != null; } // ------------------------------------------------------ Lifecycle Methods /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // Validate that we can open our connection - but let tomcat // startup in case the database is temporarily unavailable try { open(); } catch (SQLException e) { containerLog.error(sm.getString("jdbcRealm.open"), e); } super.startInternal(); } /** * Gracefully terminate the active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { super.stopInternal(); // Close any open DB connection close(this.dbConnection); } } tomcat7-7.0.52/java/org/apache/catalina/realm/MemoryRuleSet.java0000644000175100017510000000710712271471332024376 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.Rule; import org.apache.tomcat.util.digester.RuleSetBase; import org.xml.sax.Attributes; /** *

    RuleSet for recognizing the users defined in the * XML file processed by MemoryRealm.

    * * @author Craig R. McClanahan */ public class MemoryRuleSet extends RuleSetBase { // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public MemoryRuleSet() { this("tomcat-users/"); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public MemoryRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { digester.addRule(prefix + "user", new MemoryUserRule()); } } /** * Private class used when parsing the XML database file. */ final class MemoryUserRule extends Rule { /** * Construct a new instance of this Rule. */ public MemoryUserRule() { // No initialisation required } /** * Process a <user> element from the XML database file. * * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { String username = attributes.getValue("name"); if (username == null) { username = attributes.getValue("username"); } String password = attributes.getValue("password"); String roles = attributes.getValue("roles"); MemoryRealm realm = (MemoryRealm) digester.peek(digester.getCount() - 1); realm.addUser(username, password, roles); } } tomcat7-7.0.52/java/org/apache/catalina/realm/mbeans-descriptors.xml0000644000175100017510000005715012271471332025310 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/realm/Constants.java0000644000175100017510000000274712271471332023603 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; /** * Manifest constants for this Java package. * * * @author Craig R. McClanahan */ public final class Constants { public static final String Package = "org.apache.catalina.realm"; // Authentication methods for login configuration public static final String FORM_METHOD = "FORM"; // Form based authentication constants public static final String FORM_ACTION = "/j_security_check"; // User data constraints for transport guarantee public static final String NONE_TRANSPORT = "NONE"; public static final String INTEGRAL_TRANSPORT = "INTEGRAL"; public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL"; } tomcat7-7.0.52/java/org/apache/catalina/realm/LocalStrings.properties0000644000175100017510000001573612271471332025510 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # language # package org.apache.catalina.realm jaasRealm.beginLogin=JAASRealm login requested for username "{0}" using LoginContext for application "{1}" jaasRealm.accountExpired=Username "{0}" NOT authenticated due to expired account jaasRealm.authenticateFailure=Username "{0}" NOT successfully authenticated jaasRealm.authenticateSuccess=Username "{0}" successfully authenticated as Principal "{1}" -- Subject was created too jaasRealm.credentialExpired=Username "{0}" NOT authenticated due to expired credential jaasRealm.failedLogin=Username "{0}" NOT authenticated due to failed login jaasRealm.loginException=Login exception authenticating username "{0}" jaasRealm.unexpectedError=Unexpected error jaasRealm.loginContextCreated=JAAS LoginContext created for username "{0}" jaasRealm.cachePrincipal=User Principal "{0}" cached; has {1} role Principal(s) jaasRealm.checkPrincipal=Checking Principal "{0}" [{1}] jaasRealm.userPrincipalSuccess=Principal "{0}" is a valid user class. We will use this as the user Principal. jaasRealm.userPrincipalFailure=No valid user Principal found jaasRealm.rolePrincipalAdd=Adding role Principal "{0}" to this user Principal''s roles jaasRealm.rolePrincipalSuccess={0} role Principal(s) found jaasRealm.rolePrincipalFailure=No valid role Principals found. jaasRealm.isInRole.start=Checking if user Principal "{0}" possesses role "{1}" jaasRealm.isInRole.noPrincipalOrRole=No roles Principals found. User Principal or Subject is null, or user Principal not in cache jaasRealm.isInRole.principalCached=User Principal has {0} role Principal(s) jaasRealm.isInRole.possessesRole=User Principal has a role Principal called "{0}" jaasRealm.isInRole.match=Matching role Principal found. jaasRealm.isInRole.noMatch=Matching role Principal NOT found. jaasCallback.digestpassword=Digested password "{0}" as "{1}" jaasCallback.username=Returned username "{0}" jaasCallback.password=Returned password "{0}" jdbcRealm.authenticateFailure=Username {0} NOT successfully authenticated jdbcRealm.authenticateSuccess=Username {0} successfully authenticated jdbcRealm.close=Exception closing database connection jdbcRealm.exception=Exception performing authentication jdbcRealm.getPassword.exception=Exception retrieving password for "{0}" jdbcRealm.getRoles.exception=Exception retrieving roles for "{0}" jdbcRealm.open=Exception opening database connection jdbcRealm.open.invalidurl=Driver "{0}" does not support the url "{1}" jndiRealm.authenticateFailure=Username {0} NOT successfully authenticated jndiRealm.authenticateSuccess=Username {0} successfully authenticated jndiRealm.close=Exception closing directory server connection jndiRealm.exception=Exception performing authentication jndiRealm.exception.retry=Exception performing authentication. Retrying... jndiRealm.open=Exception opening directory server connection memoryRealm.authenticateFailure=Username {0} NOT successfully authenticated memoryRealm.authenticateSuccess=Username {0} successfully authenticated memoryRealm.loadExist=Memory database file {0} cannot be read memoryRealm.loadPath=Loading users from memory database file {0} memoryRealm.readXml=Exception while reading memory database file memoryRealm.xmlFeatureEncoding=Exception configuring digester to permit java encoding names in XML files. Only IANA encoding names will be supported. realmBase.algorithm=Invalid message digest algorithm {0} specified realmBase.alreadyStarted=This Realm has already been started realmBase.delegatedCredentialFail=Unable to obtain delegated credentials for user [{0}] realmBase.digest=Error digesting user credentials realmBase.forbidden=Access to the requested resource has been denied realmBase.hasRoleFailure=Username {0} does NOT have role {1} realmBase.hasRoleSuccess=Username {0} has role {1} realmBase.notAuthenticated=Configuration error: Cannot perform access control without an authenticated principal realmBase.notStarted=This Realm has not yet been started realmBase.authenticateFailure=Username {0} NOT successfully authenticated realmBase.authenticateSuccess=Username {0} successfully authenticated realmBase.gssNameFail=Failed to extract name from established GSSContext userDatabaseRealm.authenticateError=Login configuration error authenticating username {0} realmBase.gotX509Username=Got user name from X509 certificate: {0} realmBase.createUsernameRetriever.ClassCastException=Class {0} is not an X509UsernameRetriever. realmBase.createUsernameRetriever.ClassNotFoundException=Cannot find class {0}. realmBase.createUsernameRetriever.InstantiationException=Cannot create object of type {0}. realmBase.createUsernameRetriever.IllegalAccessException=Cannot create object of type {0}. userDatabaseRealm.lookup=Exception looking up UserDatabase under key {0} userDatabaseRealm.noDatabase=No UserDatabase component found under key {0} userDatabaseRealm.noEngine=No Engine component found in container hierarchy userDatabaseRealm.noGlobal=No global JNDI resources context found dataSourceRealm.authenticateFailure=Username {0} NOT successfully authenticated dataSourceRealm.authenticateSuccess=Username {0} successfully authenticated dataSourceRealm.close=Exception closing database connection dataSourceRealm.exception=Exception performing authentication dataSourceRealm.getPassword.exception=Exception retrieving password for "{0}" dataSourceRealm.getRoles.exception=Exception retrieving roles for "{0}" dataSourceRealm.open=Exception opening database connection combinedRealm.unexpectedMethod=An unexpected call was made to a method on the combined realm combinedRealm.getName=The getName() method should never be called combinedRealm.getPassword=The getPassword() method should never be called combinedRealm.getPrincipal=The getPrincipal() method should never be called combinedRealm.authStart=Attempting to authenticate user "{0}" with realm "{1}" combinedRealm.authFailed=Failed to authenticate user "{0}" with realm "{1}" combinedRealm.authSuccess=Authenticated user "{0}" with realm "{1}" combinedRealm.addRealm=Add "{0}" realm, making a total of "{1}" realms combinedRealm.realmStartFail=Failed to start "{0}" realm lockOutRealm.authLockedUser=An attempt was made to authenticate the locked user "{0}" lockOutRealm.removeWarning=User "{0}" was removed from the failed users cache after {1} seconds to keep the cache size within the limit set tomcat7-7.0.52/java/org/apache/catalina/realm/JAASMemoryLoginModule.java0000644000175100017510000003064012271471332025666 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.io.File; import java.io.IOException; import java.security.Principal; import java.util.Map; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.TextInputCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.Globals; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.digester.Digester; /** *

    Implementation of the JAAS LoginModule interface, * primarily for use in testing JAASRealm. It utilizes an * XML-format data file of username/password/role information identical to * that supported by org.apache.catalina.realm.MemoryRealm * (except that digested passwords are not supported).

    * *

    This class recognizes the following string-valued options, which are * specified in the configuration file (and passed to our constructor in * the options argument:

    *
      *
    • debug - Set to "true" to get debugging messages * generated to System.out. The default value is false.
    • *
    • pathname - Relative (to the pathname specified by the * "catalina.base" system property) or absolute pathname to the * XML file containing our user information, in the format supported by * {@link MemoryRealm}. The default value matches the MemoryRealm * default.
    • *
    * *

    IMPLEMENTATION NOTE - This class implements * Realm only to satisfy the calling requirements of the * GenericPrincipal constructor. It does not actually perform * the functionality required of a Realm implementation.

    * * @author Craig R. McClanahan */ public class JAASMemoryLoginModule extends MemoryRealm implements LoginModule { // We need to extend MemoryRealm to avoid class cast private static final Log log = LogFactory.getLog(JAASMemoryLoginModule.class); // ----------------------------------------------------- Instance Variables /** * The callback handler responsible for answering our requests. */ protected CallbackHandler callbackHandler = null; /** * Has our own commit() returned successfully? */ protected boolean committed = false; /** * The configuration information for this LoginModule. */ protected Map options = null; /** * The absolute or relative pathname to the XML configuration file. */ protected String pathname = "conf/tomcat-users.xml"; /** * The Principal identified by our validation, or * null if validation failed. */ protected Principal principal = null; /** * The state information that is shared with other configured * LoginModule instances. */ protected Map sharedState = null; /** * The subject for which we are performing authentication. */ protected Subject subject = null; // --------------------------------------------------------- Public Methods public JAASMemoryLoginModule() { log.debug("MEMORY LOGIN MODULE"); } /** * Phase 2 of authenticating a Subject when Phase 1 * fails. This method is called if the LoginContext * failed somewhere in the overall authentication chain. * * @return true if this method succeeded, or * false if this LoginModule should be * ignored * * @exception LoginException if the abort fails */ @Override public boolean abort() throws LoginException { // If our authentication was not successful, just return false if (principal == null) return (false); // Clean up if overall authentication failed if (committed) logout(); else { committed = false; principal = null; } log.debug("Abort"); return (true); } /** * Phase 2 of authenticating a Subject when Phase 1 * was successful. This method is called if the LoginContext * succeeded in the overall authentication chain. * * @return true if the authentication succeeded, or * false if this LoginModule should be * ignored * * @exception LoginException if the commit fails */ @Override public boolean commit() throws LoginException { log.debug("commit " + principal); // If authentication was not successful, just return false if (principal == null) return (false); // Add our Principal to the Subject if needed if (!subject.getPrincipals().contains(principal)) { subject.getPrincipals().add(principal); // Add the roles as additional subjects as per the contract with the // JAASRealm if (principal instanceof GenericPrincipal) { String roles[] = ((GenericPrincipal) principal).getRoles(); for (int i = 0; i < roles.length; i++) { subject.getPrincipals().add( new GenericPrincipal(null, roles[i], null)); } } } committed = true; return (true); } /** * Initialize this LoginModule with the specified * configuration information. * * @param subject The Subject to be authenticated * @param callbackHandler A CallbackHandler for communicating * with the end user as necessary * @param sharedState State information shared with other * LoginModule instances * @param options Configuration information for this specific * LoginModule instance */ @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { log.debug("Init"); // Save configuration values this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = options; // Perform instance-specific initialization if (options.get("pathname") != null) this.pathname = (String) options.get("pathname"); // Load our defined Principals load(); } /** * Phase 1 of authenticating a Subject. * * @return true if the authentication succeeded, or * false if this LoginModule should be * ignored * * @exception LoginException if the authentication fails */ @Override public boolean login() throws LoginException { // Set up our CallbackHandler requests if (callbackHandler == null) throw new LoginException("No CallbackHandler specified"); Callback callbacks[] = new Callback[9]; callbacks[0] = new NameCallback("Username: "); callbacks[1] = new PasswordCallback("Password: ", false); callbacks[2] = new TextInputCallback("nonce"); callbacks[3] = new TextInputCallback("nc"); callbacks[4] = new TextInputCallback("cnonce"); callbacks[5] = new TextInputCallback("qop"); callbacks[6] = new TextInputCallback("realmName"); callbacks[7] = new TextInputCallback("md5a2"); callbacks[8] = new TextInputCallback("authMethod"); // Interact with the user to retrieve the username and password String username = null; String password = null; String nonce = null; String nc = null; String cnonce = null; String qop = null; String realmName = null; String md5a2 = null; String authMethod = null; try { callbackHandler.handle(callbacks); username = ((NameCallback) callbacks[0]).getName(); password = new String(((PasswordCallback) callbacks[1]).getPassword()); nonce = ((TextInputCallback) callbacks[2]).getText(); nc = ((TextInputCallback) callbacks[3]).getText(); cnonce = ((TextInputCallback) callbacks[4]).getText(); qop = ((TextInputCallback) callbacks[5]).getText(); realmName = ((TextInputCallback) callbacks[6]).getText(); md5a2 = ((TextInputCallback) callbacks[7]).getText(); authMethod = ((TextInputCallback) callbacks[8]).getText(); } catch (IOException e) { throw new LoginException(e.toString()); } catch (UnsupportedCallbackException e) { throw new LoginException(e.toString()); } // Validate the username and password we have received if (authMethod == null) { // BASIC or FORM principal = super.authenticate(username, password); } else if (authMethod.equals(HttpServletRequest.DIGEST_AUTH)) { principal = super.authenticate(username, password, nonce, nc, cnonce, qop, realmName, md5a2); } else if (authMethod.equals(HttpServletRequest.CLIENT_CERT_AUTH)) { principal = super.getPrincipal(username); } else { throw new LoginException("Unknown authentication method"); } log.debug("login " + username + " " + principal); // Report results based on success or failure if (principal != null) { return (true); } else { throw new FailedLoginException("Username or password is incorrect"); } } /** * Log out this user. * * @return true in all cases because the * LoginModule should not be ignored * * @exception LoginException if logging out failed */ @Override public boolean logout() throws LoginException { subject.getPrincipals().remove(principal); committed = false; principal = null; return (true); } // ---------------------------------------------------------- Realm Methods // ------------------------------------------------------ Protected Methods /** * Load the contents of our configuration file. */ protected void load() { // Validate the existence of our configuration file File file = new File(pathname); if (!file.isAbsolute()) file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname); if (!file.exists() || !file.canRead()) { log.warn("Cannot load configuration file " + file.getAbsolutePath()); return; } // Load the contents of our configuration file Digester digester = new Digester(); digester.setValidating(false); digester.addRuleSet(new MemoryRuleSet()); try { digester.push(this); digester.parse(file); } catch (Exception e) { log.warn("Error processing configuration file " + file.getAbsolutePath(), e); return; } finally { digester.reset(); } } } tomcat7-7.0.52/java/org/apache/catalina/realm/LockOutRealm.java0000644000175100017510000003501012271471332024155 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.Principal; import java.security.cert.X509Certificate; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.apache.catalina.LifecycleException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSName; /** * This class extends the CombinedRealm (hence it can wrap other Realms) to * provide a user lock out mechanism if there are too many failed * authentication attempts in a given period of time. To ensure correct * operation, there is a reasonable degree of synchronisation in this Realm. * This Realm does not require modification to the underlying Realms or the * associated user storage mechanisms. It achieves this by recording all failed * logins, including those for users that do not exist. To prevent a DOS by * deliberating making requests with invalid users (and hence causing this cache * to grow) the size of the list of users that have failed authentication is * limited. */ public class LockOutRealm extends CombinedRealm { private static final Log log = LogFactory.getLog(LockOutRealm.class); /** * Descriptive information about this Realm implementation. */ protected static final String name = "LockOutRealm"; /** * The number of times in a row a user has to fail authentication to be * locked out. Defaults to 5. */ protected int failureCount = 5; /** * The time (in seconds) a user is locked out for after too many * authentication failures. Defaults to 300 (5 minutes). */ protected int lockOutTime = 300; /** * Number of users that have failed authentication to keep in cache. Over * time the cache will grow to this size and may not shrink. Defaults to * 1000. */ protected int cacheSize = 1000; /** * If a failed user is removed from the cache because the cache is too big * before it has been in the cache for at least this period of time (in * seconds) a warning message will be logged. Defaults to 3600 (1 hour). */ protected int cacheRemovalWarningTime = 3600; /** * Users whose last authentication attempt failed. Entries will be ordered * in access order from least recent to most recent. */ protected Map failedUsers = null; /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // Configure the list of failed users to delete the oldest entry once it // exceeds the specified size failedUsers = new LinkedHashMap(cacheSize, 0.75f, true) { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry( Map.Entry eldest) { if (size() > cacheSize) { // Check to see if this element has been removed too quickly long timeInCache = (System.currentTimeMillis() - eldest.getValue().getLastFailureTime())/1000; if (timeInCache < cacheRemovalWarningTime) { log.warn(sm.getString("lockOutRealm.removeWarning", eldest.getKey(), Long.valueOf(timeInCache))); } return true; } return false; } }; super.startInternal(); } /** * Return the Principal associated with the specified username, which * matches the digest calculated using the given parameters using the * method described in RFC 2069; otherwise return null. * * @param username Username of the Principal to look up * @param clientDigest Digest which has been submitted by the client * @param nonce Unique (or supposedly unique) token which has been used * for this request * @param realmName Realm name * @param md5a2 Second MD5 digest used to calculate the digest : * MD5(Method + ":" + uri) */ @Override public Principal authenticate(String username, String clientDigest, String nonce, String nc, String cnonce, String qop, String realmName, String md5a2) { if (isLocked(username)) { // Trying to authenticate a locked user is an automatic failure registerAuthFailure(username); log.warn(sm.getString("lockOutRealm.authLockedUser", username)); return null; } Principal authenticatedUser = super.authenticate(username, clientDigest, nonce, nc, cnonce, qop, realmName, md5a2); if (authenticatedUser == null) { registerAuthFailure(username); } else { registerAuthSuccess(username); } return authenticatedUser; } /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public Principal authenticate(String username, String credentials) { if (isLocked(username)) { // Trying to authenticate a locked user is an automatic failure registerAuthFailure(username); log.warn(sm.getString("lockOutRealm.authLockedUser", username)); return null; } Principal authenticatedUser = super.authenticate(username, credentials); if (authenticatedUser == null) { registerAuthFailure(username); } else { registerAuthSuccess(username); } return authenticatedUser; } /** * Return the Principal associated with the specified chain of X509 * client certificates. If there is none, return null. * * @param certs Array of client certificates, with the first one in * the array being the certificate of the client itself. */ @Override public Principal authenticate(X509Certificate[] certs) { String username = null; if (certs != null && certs.length >0) { username = certs[0].getSubjectDN().getName(); } if (isLocked(username)) { // Trying to authenticate a locked user is an automatic failure registerAuthFailure(username); log.warn(sm.getString("lockOutRealm.authLockedUser", username)); return null; } Principal authenticatedUser = super.authenticate(certs); if (authenticatedUser == null) { registerAuthFailure(username); } else { registerAuthSuccess(username); } return authenticatedUser; } /** * {@inheritDoc} */ @Override public Principal authenticate(GSSContext gssContext, boolean storeCreds) { if (gssContext.isEstablished()) { String username = null; GSSName name = null; try { name = gssContext.getSrcName(); } catch (GSSException e) { log.warn(sm.getString("realmBase.gssNameFail"), e); return null; } username = name.toString(); if (isLocked(username)) { // Trying to authenticate a locked user is an automatic failure registerAuthFailure(username); log.warn(sm.getString("lockOutRealm.authLockedUser", username)); return null; } Principal authenticatedUser = super.authenticate(gssContext, storeCreds); if (authenticatedUser == null) { registerAuthFailure(username); } else { registerAuthSuccess(username); } return authenticatedUser; } // Fail in all other cases return null; } /** * Unlock the specified username. This will remove all records of * authentication failures for this user. * * @param username The user to unlock */ public void unlock(String username) { // Auth success clears the lock record so... registerAuthSuccess(username); } /* * Checks to see if the current user is locked. If this is associated with * a login attempt, then the last access time will be recorded and any * attempt to authenticated a locked user will log a warning. */ private boolean isLocked(String username) { LockRecord lockRecord = null; synchronized (this) { lockRecord = failedUsers.get(username); } // No lock record means user can't be locked if (lockRecord == null) { return false; } // Check to see if user is locked if (lockRecord.getFailures() >= failureCount && (System.currentTimeMillis() - lockRecord.getLastFailureTime())/1000 < lockOutTime) { return true; } // User has not, yet, exceeded lock thresholds return false; } /* * After successful authentication, any record of previous authentication * failure is removed. */ private synchronized void registerAuthSuccess(String username) { // Successful authentication means removal from the list of failed users failedUsers.remove(username); } /* * After a failed authentication, add the record of the failed * authentication. */ private void registerAuthFailure(String username) { LockRecord lockRecord = null; synchronized (this) { if (!failedUsers.containsKey(username)) { lockRecord = new LockRecord(); failedUsers.put(username, lockRecord); } else { lockRecord = failedUsers.get(username); if (lockRecord.getFailures() >= failureCount && ((System.currentTimeMillis() - lockRecord.getLastFailureTime())/1000) > lockOutTime) { // User was previously locked out but lockout has now // expired so reset failure count lockRecord.setFailures(0); } } } lockRecord.registerFailure(); } /** * Get the number of failed authentication attempts required to lock the * user account. * @return the failureCount */ public int getFailureCount() { return failureCount; } /** * Set the number of failed authentication attempts required to lock the * user account. * @param failureCount the failureCount to set */ public void setFailureCount(int failureCount) { this.failureCount = failureCount; } /** * Get the period for which an account will be locked. * @return the lockOutTime */ public int getLockOutTime() { return lockOutTime; } @Override protected String getName() { return name; } /** * Set the period for which an account will be locked. * @param lockOutTime the lockOutTime to set */ public void setLockOutTime(int lockOutTime) { this.lockOutTime = lockOutTime; } /** * Get the maximum number of users for which authentication failure will be * kept in the cache. * @return the cacheSize */ public int getCacheSize() { return cacheSize; } /** * Set the maximum number of users for which authentication failure will be * kept in the cache. * @param cacheSize the cacheSize to set */ public void setCacheSize(int cacheSize) { this.cacheSize = cacheSize; } /** * Get the minimum period a failed authentication must remain in the cache * to avoid generating a warning if it is removed from the cache to make * space for a new entry. * @return the cacheRemovalWarningTime */ public int getCacheRemovalWarningTime() { return cacheRemovalWarningTime; } /** * Set the minimum period a failed authentication must remain in the cache * to avoid generating a warning if it is removed from the cache to make * space for a new entry. * @param cacheRemovalWarningTime the cacheRemovalWarningTime to set */ public void setCacheRemovalWarningTime(int cacheRemovalWarningTime) { this.cacheRemovalWarningTime = cacheRemovalWarningTime; } protected static class LockRecord { private AtomicInteger failures = new AtomicInteger(0); private long lastFailureTime = 0; public int getFailures() { return failures.get(); } public void setFailures(int theFailures) { failures.set(theFailures); } public long getLastFailureTime() { return lastFailureTime; } public void registerFailure() { failures.incrementAndGet(); lastFailureTime = System.currentTimeMillis(); } } } tomcat7-7.0.52/java/org/apache/catalina/realm/LocalStrings_ja.properties0000644000175100017510000001506712271471332026157 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # language ja # package org.apache.catalina.realm jaasRealm.accountExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u671f\u9650\u304c\u5207\u308c\u3066\u3044\u308b\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093 jaasRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f jaasRealm.credentialExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a3c\u660e\u66f8\u306e\u671f\u9650\u304c\u5207\u308c\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093 jaasRealm.failedLogin=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30b0\u30a4\u30f3\u306b\u5931\u6557\u3057\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f jaasRealm.loginException=\u30e6\u30fc\u30b6\u540d {0} \u306e\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f jaasRealm.unexpectedError=\u4e88\u6e2c\u3057\u306a\u3044\u30a8\u30e9\u30fc\u3067\u3059 jdbcRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f jdbcRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f jdbcRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 jdbcRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 jdbcRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f jndiRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f jndiRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f jndiRealm.close=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 jndiRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 jndiRealm.open=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059 memoryRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f memoryRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f memoryRealm.loadExist=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092\u8aad\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 memoryRealm.loadPath=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u304b\u3089\u30e6\u30fc\u30b6\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 memoryRealm.readXml=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u4f8b\u5916\u3067\u3059 realmBase.algorithm=\u7121\u52b9\u306a\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 realmBase.alreadyStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 realmBase.digest=\u30e6\u30fc\u30b6\u306e\u8a3c\u660e\u66f8\u306e\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a8\u30e9\u30fc realmBase.forbidden=\u8981\u6c42\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f realmBase.hasRoleFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093 realmBase.hasRoleSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u3059 realmBase.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u3067\u306f\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u304c\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 realmBase.notStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 realmBase.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f realmBase.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f userDatabaseRealm.authenticateError=\u30e6\u30fc\u30b6\u540d {0} \u3092\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u8a2d\u5b9a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f userDatabaseRealm.lookup=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u691c\u7d22\u4e2d\u306e\u4f8b\u5916\u3067\u3059 userDatabaseRealm.noDatabase=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 userDatabaseRealm.noEngine=\u30b3\u30f3\u30c6\u30ca\u968e\u5c64\u4e2d\u306b\u30a8\u30f3\u30b8\u30f3\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 userDatabaseRealm.noGlobal=\u30b0\u30ed\u30fc\u30d0\u30eb\u306aJNDI\u30ea\u30bd\u30fc\u30b9\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 dataSourceRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f dataSourceRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f dataSourceRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 dataSourceRealm.exception=\u8a8d\u8a3c\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 dataSourceRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059 tomcat7-7.0.52/java/org/apache/catalina/realm/JAASRealm.java0000644000175100017510000006167612271471332023334 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.security.Principal; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.AccountExpiredException; import javax.security.auth.login.Configuration; import javax.security.auth.login.CredentialExpiredException; import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.Container; import org.apache.catalina.LifecycleException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; /** *

    Implementation of Realm that authenticates users via the Java * Authentication and Authorization Service (JAAS). JAAS support requires * either JDK 1.4 (which includes it as part of the standard platform) or * JDK 1.3 (with the plug-in jaas.jar file).

    * *

    The value configured for the appName property is passed to * the javax.security.auth.login.LoginContext constructor, to * specify the application name used to select the set of relevant * LoginModules required.

    * *

    The JAAS Specification describes the result of a successful login as a * javax.security.auth.Subject instance, which can contain zero * or more java.security.Principal objects in the return value * of the Subject.getPrincipals() method. However, it provides * no guidance on how to distinguish Principals that describe the individual * user (and are thus appropriate to return as the value of * request.getUserPrincipal() in a web application) from the Principal(s) * that describe the authorized roles for this user. To maintain as much * independence as possible from the underlying LoginMethod * implementation executed by JAAS, the following policy is implemented by * this Realm:

    *
      *
    • The JAAS LoginModule is assumed to return a * Subject with at least one Principal instance * representing the user himself or herself, and zero or more separate * Principals representing the security roles authorized * for this user.
    • *
    • On the Principal representing the user, the Principal * name is an appropriate value to return via the Servlet API method * HttpServletRequest.getRemoteUser().
    • *
    • On the Principals representing the security roles, the * name is the name of the authorized security role.
    • *
    • This Realm will be configured with two lists of fully qualified Java * class names of classes that implement * java.security.Principal - one that identifies class(es) * representing a user, and one that identifies class(es) representing * a security role.
    • *
    • As this Realm iterates over the Principals returned by * Subject.getPrincipals(), it will identify the first * Principal that matches the "user classes" list as the * Principal for this user.
    • *
    • As this Realm iterates over the Principals returned by * Subject.getPrincipals(), it will accumulate the set of * all Principals matching the "role classes" list as * identifying the security roles for this user.
    • *
    • It is a configuration error for the JAAS login method to return a * validated Subject without a Principal that * matches the "user classes" list.
    • *
    • By default, the enclosing Container's name serves as the * application name used to obtain the JAAS LoginContext ("Catalina" in * a default installation). Tomcat must be able to find an application * with this name in the JAAS configuration file. Here is a hypothetical * JAAS configuration file entry for a database-oriented login module that uses * a Tomcat-managed JNDI database resource: *
      Catalina {
      org.foobar.auth.DatabaseLoginModule REQUIRED
          JNDI_RESOURCE=jdbc/AuthDB
        USER_TABLE=users
        USER_ID_COLUMN=id
        USER_NAME_COLUMN=name
        USER_CREDENTIAL_COLUMN=password
        ROLE_TABLE=roles
        ROLE_NAME_COLUMN=name
        PRINCIPAL_FACTORY=org.foobar.auth.impl.SimplePrincipalFactory;
      };
    • *
    • To set the JAAS configuration file * location, set the CATALINA_OPTS environment variable * similar to the following:
      CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"
      *
    • *
    • As part of the login process, JAASRealm registers its own CallbackHandler, * called (unsurprisingly) JAASCallbackHandler. This handler supplies the * HTTP requests's username and credentials to the user-supplied LoginModule
    • *
    • As with other Realm implementations, digested passwords are supported if * the <Realm> element in server.xml contains a * digest attribute; JAASCallbackHandler will digest the password * prior to passing it back to the LoginModule
    • *
    * * @author Craig R. McClanahan * @author Yoav Shapira */ public class JAASRealm extends RealmBase { private static final Log log = LogFactory.getLog(JAASRealm.class); // ----------------------------------------------------- Instance Variables /** * The application name passed to the JAAS LoginContext, * which uses it to select the set of relevant LoginModules. */ protected String appName = null; /** * Descriptive information about this Realm implementation. */ protected static final String info = "org.apache.catalina.realm.JAASRealm/1.0"; /** * Descriptive information about this Realm implementation. */ protected static final String name = "JAASRealm"; /** * The list of role class names, split out for easy processing. */ protected List roleClasses = new ArrayList(); /** * The set of user class names, split out for easy processing. */ protected List userClasses = new ArrayList(); /** * Whether to use context ClassLoader or default ClassLoader. * True means use context ClassLoader, and True is the default * value. */ protected boolean useContextClassLoader = true; /** * Path to find a JAAS configuration file, if not set global JVM JAAS * configuration will be used. */ protected String configFile; protected Configuration jaasConfiguration; protected volatile boolean jaasConfigurationLoaded = false; // ------------------------------------------------------------- Properties /** * Getter for the configfile member variable. */ public String getConfigFile() { return configFile; } /** * Setter for the configfile member variable. */ public void setConfigFile(String configFile) { this.configFile = configFile; } /** * setter for the appName member variable */ public void setAppName(String name) { appName = name; } /** * getter for the appName member variable */ public String getAppName() { return appName; } /** * Sets whether to use the context or default ClassLoader. * True means use context ClassLoader. * * @param useContext True means use context ClassLoader */ public void setUseContextClassLoader(boolean useContext) { useContextClassLoader = useContext; log.info("Setting useContextClassLoader = " + useContext); } /** * Returns whether to use the context or default ClassLoader. * True means to use the context ClassLoader. * * @return The value of useContextClassLoader */ public boolean isUseContextClassLoader() { return useContextClassLoader; } @Override public void setContainer(Container container) { super.setContainer(container); if( appName==null ) { String name = container.getName(); if (!name.startsWith("/")) { name = "/" + name; } name = makeLegalForJAAS(name); appName=name; log.info("Set JAAS app name " + appName); } } /** * Comma-delimited list of java.security.Principal classes * that represent security roles. */ protected String roleClassNames = null; public String getRoleClassNames() { return (this.roleClassNames); } /** * Sets the list of comma-delimited classes that represent roles. The * classes in the list must implement java.security.Principal. * The supplied list of classes will be parsed when {@link #start()} is * called. */ public void setRoleClassNames(String roleClassNames) { this.roleClassNames = roleClassNames; } /** * Parses a comma-delimited list of class names, and store the class names * in the provided List. Each class must implement * java.security.Principal. * * @param classNamesString a comma-delimited list of fully qualified class names. * @param classNamesList the list in which the class names will be stored. * The list is cleared before being populated. */ protected void parseClassNames(String classNamesString, List classNamesList) { classNamesList.clear(); if (classNamesString == null) return; ClassLoader loader = this.getClass().getClassLoader(); if (isUseContextClassLoader()) loader = Thread.currentThread().getContextClassLoader(); String[] classNames = classNamesString.split("[ ]*,[ ]*"); for (int i=0; i principalClass = Class.forName(classNames[i], false, loader); if (Principal.class.isAssignableFrom(principalClass)) { classNamesList.add(classNames[i]); } else { log.error("Class "+classNames[i]+" is not implementing "+ "java.security.Principal! Class not added."); } } catch (ClassNotFoundException e) { log.error("Class "+classNames[i]+" not found! Class not added."); } } } /** * Comma-delimited list of java.security.Principal classes * that represent individual users. */ protected String userClassNames = null; public String getUserClassNames() { return (this.userClassNames); } /** * Sets the list of comma-delimited classes that represent individual * users. The classes in the list must implement * java.security.Principal. The supplied list of classes will * be parsed when {@link #start()} is called. */ public void setUserClassNames(String userClassNames) { this.userClassNames = userClassNames; } /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } // --------------------------------------------------------- Public Methods /** * Return the Principal associated with the specified username * and credentials, if there is one; otherwise return null. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public Principal authenticate(String username, String credentials) { return authenticate(username, new JAASCallbackHandler(this, username, credentials)); } /** * Return the Principal associated with the specified username * and digest, if there is one; otherwise return null. * * @param username Username of the Principal to look up * @param clientDigest Digest to use in authenticating this username * @param nonce Server generated nonce * @param nc Nonce count * @param cnonce Client generated nonce * @param qop Quality of protection applied to the message * @param realmName Realm name * @param md5a2 Second MD5 digest used to calculate the digest * MD5(Method + ":" + uri) */ @Override public Principal authenticate(String username, String clientDigest, String nonce, String nc, String cnonce, String qop, String realmName, String md5a2) { return authenticate(username, new JAASCallbackHandler(this, username, clientDigest, nonce, nc, cnonce, qop, realmName, md5a2, HttpServletRequest.DIGEST_AUTH)); } // -------------------------------------------------------- Package Methods // ------------------------------------------------------ Protected Methods /** * Perform the actual JAAS authentication */ protected Principal authenticate(String username, CallbackHandler callbackHandler) { // Establish a LoginContext to use for authentication try { LoginContext loginContext = null; if( appName==null ) appName="Tomcat"; if( log.isDebugEnabled()) log.debug(sm.getString("jaasRealm.beginLogin", username, appName)); // What if the LoginModule is in the container class loader ? ClassLoader ocl = null; if (!isUseContextClassLoader()) { ocl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader()); } try { Configuration config = getConfig(); loginContext = new LoginContext( appName, null, callbackHandler, config); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); log.error(sm.getString("jaasRealm.unexpectedError"), e); return (null); } finally { if(!isUseContextClassLoader()) { Thread.currentThread().setContextClassLoader(ocl); } } if( log.isDebugEnabled()) log.debug("Login context created " + username); // Negotiate a login via this LoginContext Subject subject = null; try { loginContext.login(); subject = loginContext.getSubject(); if (subject == null) { if( log.isDebugEnabled()) log.debug(sm.getString("jaasRealm.failedLogin", username)); return (null); } } catch (AccountExpiredException e) { if (log.isDebugEnabled()) log.debug(sm.getString("jaasRealm.accountExpired", username)); return (null); } catch (CredentialExpiredException e) { if (log.isDebugEnabled()) log.debug(sm.getString("jaasRealm.credentialExpired", username)); return (null); } catch (FailedLoginException e) { if (log.isDebugEnabled()) log.debug(sm.getString("jaasRealm.failedLogin", username)); return (null); } catch (LoginException e) { log.warn(sm.getString("jaasRealm.loginException", username), e); return (null); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); log.error(sm.getString("jaasRealm.unexpectedError"), e); return (null); } if( log.isDebugEnabled()) log.debug(sm.getString("jaasRealm.loginContextCreated", username)); // Return the appropriate Principal for this authenticated Subject Principal principal = createPrincipal(username, subject, loginContext); if (principal == null) { log.debug(sm.getString("jaasRealm.authenticateFailure", username)); return (null); } if (log.isDebugEnabled()) { log.debug(sm.getString("jaasRealm.authenticateSuccess", username)); } return (principal); } catch( Throwable t) { log.error( "error ", t); return null; } } /** * Return a short name for this Realm implementation. */ @Override protected String getName() { return (name); } /** * Return the password associated with the given principal's user name. This * always returns null as the JAASRealm has no way of obtaining this * information. */ @Override protected String getPassword(String username) { return (null); } /** * Return the Principal associated with the given user name. */ @Override protected Principal getPrincipal(String username) { return authenticate(username, new JAASCallbackHandler(this, username, null, null, null, null, null, null, null, HttpServletRequest.CLIENT_CERT_AUTH)); } /** * Identify and return a java.security.Principal instance * representing the authenticated user for the specified Subject. * The Principal is constructed by scanning the list of Principals returned * by the JAASLoginModule. The first Principal object that matches * one of the class names supplied as a "user class" is the user Principal. * This object is returned to the caller. * Any remaining principal objects returned by the LoginModules are mapped to * roles, but only if their respective classes match one of the "role class" classes. * If a user Principal cannot be constructed, return null. * @param subject The Subject representing the logged-in user * @param loginContext Associated with the Principal so * {@link LoginContext#logout()} can be called later */ protected Principal createPrincipal(String username, Subject subject, LoginContext loginContext) { // Prepare to scan the Principals for this Subject List roles = new ArrayList(); Principal userPrincipal = null; // Scan the Principals for this Subject Iterator principals = subject.getPrincipals().iterator(); while (principals.hasNext()) { Principal principal = principals.next(); String principalClass = principal.getClass().getName(); if( log.isDebugEnabled() ) { log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass)); } if (userPrincipal == null && userClasses.contains(principalClass)) { userPrincipal = principal; if( log.isDebugEnabled() ) { log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName())); } } if (roleClasses.contains(principalClass)) { roles.add(principal.getName()); if( log.isDebugEnabled() ) { log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName())); } } } // Print failure message if needed if (userPrincipal == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("jaasRealm.userPrincipalFailure")); log.debug(sm.getString("jaasRealm.rolePrincipalFailure")); } } else { if (roles.size() == 0) { if (log.isDebugEnabled()) { log.debug(sm.getString("jaasRealm.rolePrincipalFailure")); } } } // Return the resulting Principal for our authenticated user return new GenericPrincipal(username, null, roles, userPrincipal, loginContext); } /** * Ensure the given name is legal for JAAS configuration. * Added for Bugzilla 30869, made protected for easy customization * in case my implementation is insufficient, which I think is * very likely. * * @param src The name to validate * @return A string that's a valid JAAS realm name */ protected String makeLegalForJAAS(final String src) { String result = src; // Default name is "other" per JAAS spec if(result == null) { result = "other"; } // Strip leading slash if present, as Sun JAAS impl // barfs on it (see Bugzilla 30869 bug report). if(result.startsWith("/")) { result = result.substring(1); } return result; } // ------------------------------------------------------ Lifecycle Methods /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // These need to be called after loading configuration, in case // useContextClassLoader appears after them in xml config parseClassNames(userClassNames, userClasses); parseClassNames(roleClassNames, roleClasses); super.startInternal(); } /** * Load custom JAAS Configuration */ protected Configuration getConfig() { try { if (jaasConfigurationLoaded) { return jaasConfiguration; } synchronized (this) { if (configFile == null) { jaasConfigurationLoaded = true; return null; } URL resource = Thread.currentThread().getContextClassLoader(). getResource(configFile); URI uri = resource.toURI(); @SuppressWarnings("unchecked") Class sunConfigFile = (Class) Class.forName("com.sun.security.auth.login.ConfigFile"); Constructor constructor = sunConfigFile.getConstructor(URI.class); Configuration config = constructor.newInstance(uri); this.jaasConfiguration = config; this.jaasConfigurationLoaded = true; return this.jaasConfiguration; } } catch (URISyntaxException ex) { throw new RuntimeException(ex); } catch (NoSuchMethodException ex) { throw new RuntimeException(ex); } catch (SecurityException ex) { throw new RuntimeException(ex); } catch (InstantiationException ex) { throw new RuntimeException(ex); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { throw new RuntimeException(ex.getCause()); } catch (ClassNotFoundException ex) { throw new RuntimeException(ex); } } } tomcat7-7.0.52/java/org/apache/catalina/realm/LocalStrings_fr.properties0000644000175100017510000001065712271471332026174 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # language # package org.apache.catalina.realm jaasRealm.accountExpired=le nom d''utilisateur {0} N''A PAS \u00e9t\u00e9 authentifi\u00e9 car le compte a expir\u00e9 jaasRealm.authenticateSuccess=le nom d''utilisateur {0} a \u00e9t\u00e9 authentifi\u00e9 avec succ\u00e8s jaasRealm.credentialExpired=le nom d''utilisateur {0} N''A PAS \u00e9t\u00e9 authentifi\u00e9 car son cr\u00e9dit a expir\u00e9 (expired credential) jaasRealm.failedLogin=le nom d''utilisateur {0} N''A PAS \u00e9t\u00e9 authentifi\u00e9 car son contr\u00f4le d''acc\u00e8s (login) a \u00e9chou\u00e9 jaasRealm.loginException=Exception lors de l''authentification par login du nom d''utilisateur {0} jdbcRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS \u00e9t\u00e9 authentifi\u00e9 jdbcRealm.authenticateSuccess=le nom d''utilisateur {0} a \u00e9t\u00e9 authentifi\u00e9 avec succ\u00e8s jdbcRealm.close=Exception lors de la fermeture de la connexion \u00e0 la base de donn\u00e9es jdbcRealm.exception=Exception pendant le traitement de l''authentification jdbcRealm.open=Exception lors de l''ouverture de la base de donn\u00e9es jndiRealm.authenticateFailure=Le nom d''utilisateur {0} N''A PAS \u00e9t\u00e9 authentifi\u00e9 jndiRealm.authenticateSuccess=Le nom d''utilisateur {0} a \u00e9t\u00e9 authentifi\u00e9 avec succ\u00e8s jndiRealm.close=Exception lors de la fermeture de la connexion au serveur d''acc\u00e8s (directory server) jndiRealm.exception=Exception pendant le traitement de l''authentification jndiRealm.open=Exception lors de l''ouverture de la connexion au serveur d''acc\u00e8s (directory server) memoryRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS \u00e9t\u00e9 authentifi\u00e9 memoryRealm.authenticateSuccess=le nom d''utilisateur {0} a \u00e9t\u00e9 authentifi\u00e9 avec succ\u00e8s memoryRealm.loadExist=Le fichier base de donn\u00e9es m\u00e9moire (memory database) {0} ne peut \u00eatre lu memoryRealm.loadPath=Chargement des utilisateurs depuis le fichier base de donn\u00e9es m\u00e9moire (memory database) {0} memoryRealm.readXml=Exception lors de la lecture du fichier base de donn\u00e9es m\u00e9moire (memory database) realmBase.algorithm=L''algorithme d''empreinte de message (message digest) {0} indiqu\u00e9 est invalide realmBase.alreadyStarted=Ce royaume (Realm) a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9 realmBase.digest=Erreur lors du traitement des empreintes (digest) des cr\u00e9dits utilisateur (user credentials) realmBase.forbidden=L''acc\u00e8s \u00e0 la ressource demand\u00e9e a \u00e9t\u00e9 interdit realmBase.hasRoleFailure=Le nom d''utilisateur {0} N''A PAS de r\u00f4le {1} realmBase.hasRoleSuccess=Le nom d''utilisateur {0} a pour r\u00f4le {1} realmBase.notAuthenticated=Erreur de configuration: Impossible de conduire un contr\u00f4le d''acc\u00e8s sans un principal authentifi\u00e9 (authenticated principal) realmBase.notStarted=Ce royaume (Realm) n''a pas encore \u00e9t\u00e9 d\u00e9marr\u00e9 realmBase.authenticateFailure=Le nom d''utilisateur {0} N''A PAS \u00e9t\u00e9 authentifi\u00e9 realmBase.authenticateSuccess=Le nom d''utilisateur {0} a \u00e9t\u00e9 authentifi\u00e9 avec succ\u00e8s userDatabaseRealm.authenticateError=Erreur de configuration du contr\u00f4le d''acc\u00e8s (login) lors de l''authentification du nom d''utilisateur {0} userDatabaseRealm.lookup=Exception lors de la recherche dans la base de donn\u00e9es utilisateurs avec la cl\u00e9 {0} userDatabaseRealm.noDatabase=Aucun composant base de donn\u00e9es utilisateurs trouv\u00e9 pour la cl\u00e9 {0} userDatabaseRealm.noEngine=Aucun composant moteur (engine component) trouv\u00e9 dans la hi\u00e9rarchie des conteneurs userDatabaseRealm.noGlobal=Aucune ressource globale JNDI trouv\u00e9e tomcat7-7.0.52/java/org/apache/catalina/realm/X509SubjectDnRetriever.java0000644000175100017510000000224711726446665026000 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.security.cert.X509Certificate; /** * An X509UsernameRetriever that returns a certificate's entire * SubjectDN as the username. */ public class X509SubjectDnRetriever implements X509UsernameRetriever { @Override public String getUsername(X509Certificate clientCert) { return clientCert.getSubjectDN().getName(); } } tomcat7-7.0.52/java/org/apache/catalina/realm/JNDIRealm.java0000644000175100017510000022403212271471332023325 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.realm; import java.net.URI; import java.net.URISyntaxException; import java.security.Principal; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.naming.AuthenticationException; import javax.naming.CommunicationException; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.InvalidNameException; import javax.naming.Name; import javax.naming.NameNotFoundException; import javax.naming.NameParser; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.PartialResultException; import javax.naming.ServiceUnavailableException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import org.apache.catalina.LifecycleException; import org.ietf.jgss.GSSCredential; /** *

    Implementation of Realm that works with a directory * server accessed via the Java Naming and Directory Interface (JNDI) APIs. * The following constraints are imposed on the data structure in the * underlying directory server:

    *
      * *
    • Each user that can be authenticated is represented by an individual * element in the top level DirContext that is accessed * via the connectionURL property.
    • * *
    • If a socket connection can not be made to the connectURL * an attempt will be made to use the alternateURL if it * exists.
    • * *
    • Each user element has a distinguished name that can be formed by * substituting the presented username into a pattern configured by the * userPattern property.
    • * *
    • Alternatively, if the userPattern property is not * specified, a unique element can be located by searching the directory * context. In this case: *
        *
      • The userSearch pattern specifies the search filter * after substitution of the username.
      • *
      • The userBase property can be set to the element that * is the base of the subtree containing users. If not specified, * the search base is the top-level context.
      • *
      • The userSubtree property can be set to * true if you wish to search the entire subtree of the * directory context. The default value of false * requests a search of only the current level.
      • *
      *
    • * *
    • The user may be authenticated by binding to the directory with the * username and password presented. This method is used when the * userPassword property is not specified.
    • * *
    • The user may be authenticated by retrieving the value of an attribute * from the directory and comparing it explicitly with the value presented * by the user. This method is used when the userPassword * property is specified, in which case: *
        *
      • The element for this user must contain an attribute named by the * userPassword property. *
      • The value of the user password attribute is either a cleartext * String, or the result of passing a cleartext String through the * RealmBase.digest() method (using the standard digest * support included in RealmBase). *
      • The user is considered to be authenticated if the presented * credentials (after being passed through * RealmBase.digest()) are equal to the retrieved value * for the user password attribute.
      • *
    • * *
    • Each group of users that has been assigned a particular role may be * represented by an individual element in the top level * DirContext that is accessed via the * connectionURL property. This element has the following * characteristics: *
        *
      • The set of all possible groups of interest can be selected by a * search pattern configured by the roleSearch * property.
      • *
      • The roleSearch pattern optionally includes pattern * replacements "{0}" for the distinguished name, and/or "{1}" for * the username, and/or "{2}" the value of an attribute from the * user's directory entry (the attribute is specified by the * userRoleAttribute property), of the authenticated user * for which roles will be retrieved.
      • *
      • The roleBase property can be set to the element that * is the base of the search for matching roles. If not specified, * the entire context will be searched.
      • *
      • The roleSubtree property can be set to * true if you wish to search the entire subtree of the * directory context. The default value of false * requests a search of only the current level.
      • *
      • The element includes an attribute (whose name is configured by * the roleName property) containing the name of the * role represented by this element.
      • *
    • * *
    • In addition, roles may be represented by the values of an attribute * in the user's element whose name is configured by the * userRoleName property.
    • * *
    • A default role can be assigned to each user that was successfully * authenticated by setting the commonRole property to the * name of this role. The role doesn't have to exist in the directory.
    • * *
    • If the directory server contains nested roles, you can search for them * by setting roleNested to true. * The default value is false, so role searches will not find * nested roles.
    • * *
    • Note that the standard <security-role-ref> element in * the web application deployment descriptor allows applications to refer * to roles programmatically by names other than those used in the * directory server itself.
    • *
    * *

    TODO - Support connection pooling (including message * format objects) so that authenticate() does not have to be * synchronized.

    * *

    WARNING - There is a reported bug against the Netscape * provider code (com.netscape.jndi.ldap.LdapContextFactory) with respect to * successfully authenticated a non-existing user. The * report is here: http://issues.apache.org/bugzilla/show_bug.cgi?id=11210 . * With luck, Netscape has updated their provider code and this is not an * issue.

    * * @author John Holman * @author Craig R. McClanahan */ public class JNDIRealm extends RealmBase { // ----------------------------------------------------- Instance Variables /** * The type of authentication to use */ protected String authentication = null; /** * The connection username for the server we will contact. */ protected String connectionName = null; /** * The connection password for the server we will contact. */ protected String connectionPassword = null; /** * The connection URL for the server we will contact. */ protected String connectionURL = null; /** * The directory context linking us to our directory server. */ protected DirContext context = null; /** * The JNDI context factory used to acquire our InitialContext. By * default, assumes use of an LDAP server using the standard JNDI LDAP * provider. */ protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; /** * How aliases should be dereferenced during search operations. */ protected String derefAliases = null; /** * Constant that holds the name of the environment property for specifying * the manner in which aliases should be dereferenced. */ public static final String DEREF_ALIASES = "java.naming.ldap.derefAliases"; /** * Descriptive information about this Realm implementation. */ protected static final String info = "org.apache.catalina.realm.JNDIRealm/1.0"; /** * Descriptive information about this Realm implementation. */ protected static final String name = "JNDIRealm"; /** * The protocol that will be used in the communication with the * directory server. */ protected String protocol = null; /** * Should we ignore PartialResultExceptions when iterating over NamingEnumerations? * Microsoft Active Directory often returns referrals, which lead * to PartialResultExceptions. Unfortunately there's no stable way to detect, * if the Exceptions really come from an AD referral. * Set to true to ignore PartialResultExceptions. */ protected boolean adCompat = false; /** * How should we handle referrals? Microsoft Active Directory often returns * referrals. If you need to follow them set referrals to "follow". * Caution: if your DNS is not part of AD, the LDAP client lib might try * to resolve your domain name in DNS to find another LDAP server. */ protected String referrals = null; /** * The base element for user searches. */ protected String userBase = ""; /** * The message format used to search for a user, with "{0}" marking * the spot where the username goes. */ protected String userSearch = null; /** * The MessageFormat object associated with the current * userSearch. */ protected MessageFormat userSearchFormat = null; /** * Should we search the entire subtree for matching users? */ protected boolean userSubtree = false; /** * The attribute name used to retrieve the user password. */ protected String userPassword = null; /** * The name of the attribute inside the users * directory entry where the value will be * taken to search for roles * This attribute is not used during a nested search */ protected String userRoleAttribute = null; /** * A string of LDAP user patterns or paths, ":"-separated * These will be used to form the distinguished name of a * user, with "{0}" marking the spot where the specified username * goes. * This is similar to userPattern, but allows for multiple searches * for a user. */ protected String[] userPatternArray = null; /** * The message format used to form the distinguished name of a * user, with "{0}" marking the spot where the specified username * goes. */ protected String userPattern = null; /** * An array of MessageFormat objects associated with the current * userPatternArray. */ protected MessageFormat[] userPatternFormatArray = null; /** * The base element for role searches. */ protected String roleBase = ""; /** * The MessageFormat object associated with the current * roleBase. */ protected MessageFormat roleBaseFormat = null; /** * The MessageFormat object associated with the current * roleSearch. */ protected MessageFormat roleFormat = null; /** * The name of an attribute in the user's entry containing * roles for that user */ protected String userRoleName = null; /** * The name of the attribute containing roles held elsewhere */ protected String roleName = null; /** * The message format used to select roles for a user, with "{0}" marking * the spot where the distinguished name of the user goes. The "{1}" * and "{2}" are described in the Configuration Reference. */ protected String roleSearch = null; /** * Should we search the entire subtree for matching memberships? */ protected boolean roleSubtree = false; /** * Should we look for nested group in order to determine roles? */ protected boolean roleNested = false; /** * When searching for user roles, should the search be performed as the user * currently being authenticated? If false, {@link #connectionName} and * {@link #connectionPassword} will be used if specified, else an anonymous * connection will be used. */ protected boolean roleSearchAsUser = false; /** * An alternate URL, to which, we should connect if connectionURL fails. */ protected String alternateURL; /** * The number of connection attempts. If greater than zero we use the * alternate url. */ protected int connectionAttempt = 0; /** * Add this role to every authenticated user */ protected String commonRole = null; /** * The timeout, in milliseconds, to use when trying to create a connection * to the directory. The default is 5000 (5 seconds). */ protected String connectionTimeout = "5000"; /** * The sizeLimit (also known as the countLimit) to use when the realm is * configured with {@link #userSearch}. Zero for no limit. */ protected long sizeLimit = 0; /** * The timeLimit (in milliseconds) to use when the realm is configured with * {@link #userSearch}. Zero for no limit. */ protected int timeLimit = 0; /** * Should delegated credentials from the SPNEGO authenticator be used if * available */ protected boolean useDelegatedCredential = true; /** * The QOP that should be used for the connection to the LDAP server after * authentication. This value is used to set the * javax.security.sasl.qop environment property for the LDAP * connection. */ protected String spnegoDelegationQop = "auth-conf"; // ------------------------------------------------------------- Properties /** * Return the type of authentication to use. */ public String getAuthentication() { return authentication; } /** * Set the type of authentication to use. * * @param authentication The authentication */ public void setAuthentication(String authentication) { this.authentication = authentication; } /** * Return the connection username for this Realm. */ public String getConnectionName() { return (this.connectionName); } /** * Set the connection username for this Realm. * * @param connectionName The new connection username */ public void setConnectionName(String connectionName) { this.connectionName = connectionName; } /** * Return the connection password for this Realm. */ public String getConnectionPassword() { return (this.connectionPassword); } /** * Set the connection password for this Realm. * * @param connectionPassword The new connection password */ public void setConnectionPassword(String connectionPassword) { this.connectionPassword = connectionPassword; } /** * Return the connection URL for this Realm. */ public String getConnectionURL() { return (this.connectionURL); } /** * Set the connection URL for this Realm. * * @param connectionURL The new connection URL */ public void setConnectionURL(String connectionURL) { this.connectionURL = connectionURL; } /** * Return the JNDI context factory for this Realm. */ public String getContextFactory() { return (this.contextFactory); } /** * Set the JNDI context factory for this Realm. * * @param contextFactory The new context factory */ public void setContextFactory(String contextFactory) { this.contextFactory = contextFactory; } /** * Return the derefAliases setting to be used. */ public java.lang.String getDerefAliases() { return derefAliases; } /** * Set the value for derefAliases to be used when searching the directory. * * @param derefAliases New value of property derefAliases. */ public void setDerefAliases(java.lang.String derefAliases) { this.derefAliases = derefAliases; } /** * Return the protocol to be used. */ public String getProtocol() { return protocol; } /** * Set the protocol for this Realm. * * @param protocol The new protocol. */ public void setProtocol(String protocol) { this.protocol = protocol; } /** * Returns the current settings for handling PartialResultExceptions */ public boolean getAdCompat () { return adCompat; } /** * How do we handle PartialResultExceptions? * True: ignore all PartialResultExceptions. */ public void setAdCompat (boolean adCompat) { this.adCompat = adCompat; } /** * Returns the current settings for handling JNDI referrals. */ public String getReferrals () { return referrals; } /** * How do we handle JNDI referrals? ignore, follow, or throw * (see javax.naming.Context.REFERRAL for more information). */ public void setReferrals (String referrals) { this.referrals = referrals; } /** * Return the base element for user searches. */ public String getUserBase() { return (this.userBase); } /** * Set the base element for user searches. * * @param userBase The new base element */ public void setUserBase(String userBase) { this.userBase = userBase; } /** * Return the message format pattern for selecting users in this Realm. */ public String getUserSearch() { return (this.userSearch); } /** * Set the message format pattern for selecting users in this Realm. * * @param userSearch The new user search pattern */ public void setUserSearch(String userSearch) { this.userSearch = userSearch; if (userSearch == null) userSearchFormat = null; else userSearchFormat = new MessageFormat(userSearch); } /** * Return the "search subtree for users" flag. */ public boolean getUserSubtree() { return (this.userSubtree); } /** * Set the "search subtree for users" flag. * * @param userSubtree The new search flag */ public void setUserSubtree(boolean userSubtree) { this.userSubtree = userSubtree; } /** * Return the user role name attribute name for this Realm. */ public String getUserRoleName() { return userRoleName; } /** * Set the user role name attribute name for this Realm. * * @param userRoleName The new userRole name attribute name */ public void setUserRoleName(String userRoleName) { this.userRoleName = userRoleName; } /** * Return the base element for role searches. */ public String getRoleBase() { return (this.roleBase); } /** * Set the base element for role searches. * * @param roleBase The new base element */ public void setRoleBase(String roleBase) { this.roleBase = roleBase; if (roleBase == null) roleBaseFormat = null; else roleBaseFormat = new MessageFormat(roleBase); } /** * Return the role name attribute name for this Realm. */ public String getRoleName() { return (this.roleName); } /** * Set the role name attribute name for this Realm. * * @param roleName The new role name attribute name */ public void setRoleName(String roleName) { this.roleName = roleName; } /** * Return the message format pattern for selecting roles in this Realm. */ public String getRoleSearch() { return (this.roleSearch); } /** * Set the message format pattern for selecting roles in this Realm. * * @param roleSearch The new role search pattern */ public void setRoleSearch(String roleSearch) { this.roleSearch = roleSearch; if (roleSearch == null) roleFormat = null; else roleFormat = new MessageFormat(roleSearch); } public boolean isRoleSearchAsUser() { return roleSearchAsUser; } public void setRoleSearchAsUser(boolean roleSearchAsUser) { this.roleSearchAsUser = roleSearchAsUser; } /** * Return the "search subtree for roles" flag. */ public boolean getRoleSubtree() { return (this.roleSubtree); } /** * Set the "search subtree for roles" flag. * * @param roleSubtree The new search flag */ public void setRoleSubtree(boolean roleSubtree) { this.roleSubtree = roleSubtree; } /** * Return the "The nested group search flag" flag. */ public boolean getRoleNested() { return (this.roleNested); } /** * Set the "search subtree for roles" flag. * * @param roleNested The nested group search flag */ public void setRoleNested(boolean roleNested) { this.roleNested = roleNested; } /** * Return the password attribute used to retrieve the user password. */ public String getUserPassword() { return (this.userPassword); } /** * Set the password attribute used to retrieve the user password. * * @param userPassword The new password attribute */ public void setUserPassword(String userPassword) { this.userPassword = userPassword; } public String getUserRoleAttribute() { return userRoleAttribute; } public void setUserRoleAttribute(String userRoleAttribute) { this.userRoleAttribute = userRoleAttribute; } /** * Return the message format pattern for selecting users in this Realm. */ public String getUserPattern() { return (this.userPattern); } /** * Set the message format pattern for selecting users in this Realm. * This may be one simple pattern, or multiple patterns to be tried, * separated by parentheses. (for example, either "cn={0}", or * "(cn={0})(cn={0},o=myorg)" Full LDAP search strings are also supported, * but only the "OR", "|" syntax, so "(|(cn={0})(cn={0},o=myorg))" is * also valid. Complex search strings with &, etc are NOT supported. * * @param userPattern The new user pattern */ public void setUserPattern(String userPattern) { this.userPattern = userPattern; if (userPattern == null) userPatternArray = null; else { userPatternArray = parseUserPatternString(userPattern); int len = this.userPatternArray.length; userPatternFormatArray = new MessageFormat[len]; for (int i=0; i < len; i++) { userPatternFormatArray[i] = new MessageFormat(userPatternArray[i]); } } } /** * Getter for property alternateURL. * * @return Value of property alternateURL. */ public String getAlternateURL() { return this.alternateURL; } /** * Setter for property alternateURL. * * @param alternateURL New value of property alternateURL. */ public void setAlternateURL(String alternateURL) { this.alternateURL = alternateURL; } /** * Return the common role */ public String getCommonRole() { return commonRole; } /** * Set the common role * * @param commonRole The common role */ public void setCommonRole(String commonRole) { this.commonRole = commonRole; } /** * Return the connection timeout. */ public String getConnectionTimeout() { return connectionTimeout; } /** * Set the connection timeout. * * @param timeout The new connection timeout */ public void setConnectionTimeout(String timeout) { this.connectionTimeout = timeout; } public long getSizeLimit() { return sizeLimit; } public void setSizeLimit(long sizeLimit) { this.sizeLimit = sizeLimit; } public int getTimeLimit() { return timeLimit; } public void setTimeLimit(int timeLimit) { this.timeLimit = timeLimit; } public boolean isUseDelegatedCredential() { return useDelegatedCredential; } public void setUseDelegatedCredential(boolean useDelegatedCredential) { this.useDelegatedCredential = useDelegatedCredential; } public String getSpnegoDelegationQop() { return spnegoDelegationQop; } public void setSpnegoDelegationQop(String spnegoDelegationQop) { this.spnegoDelegationQop = spnegoDelegationQop; } /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } // ---------------------------------------------------------- Realm Methods /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * If there are any errors with the JDBC connection, executing * the query or anything we return null (don't authenticate). This * event is also logged, and the connection will be closed so that * a subsequent request will automatically re-open it. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ @Override public Principal authenticate(String username, String credentials) { DirContext context = null; Principal principal = null; try { // Ensure that we have a directory context available context = open(); // Occassionally the directory context will timeout. Try one more // time before giving up. try { // Authenticate the specified username if possible principal = authenticate(context, username, credentials); } catch (NullPointerException e) { /* BZ 42449 - Kludge Sun's LDAP provider with broken SSL */ // log the exception so we know it's there. containerLog.info(sm.getString("jndiRealm.exception.retry"), e); // close the connection so we know it will be reopened. if (context != null) close(context); // open a new directory context. context = open(); // Try the authentication again. principal = authenticate(context, username, credentials); } catch (CommunicationException e) { // log the exception so we know it's there. containerLog.info(sm.getString("jndiRealm.exception.retry"), e); // close the connection so we know it will be reopened. if (context != null) close(context); // open a new directory context. context = open(); // Try the authentication again. principal = authenticate(context, username, credentials); } catch (ServiceUnavailableException e) { // log the exception so we know it's there. containerLog.info(sm.getString("jndiRealm.exception.retry"), e); // close the connection so we know it will be reopened. if (context != null) close(context); // open a new directory context. context = open(); // Try the authentication again. principal = authenticate(context, username, credentials); } // Release this context release(context); // Return the authenticated Principal (if any) return (principal); } catch (NamingException e) { // Log the problem for posterity containerLog.error(sm.getString("jndiRealm.exception"), e); // Close the connection so that it gets reopened next time if (context != null) close(context); // Return "not authenticated" for this request if (containerLog.isDebugEnabled()) containerLog.debug("Returning null principal."); return (null); } } // -------------------------------------------------------- Package Methods // ------------------------------------------------------ Protected Methods /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param context The directory context * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username * * @exception NamingException if a directory server error occurs */ public synchronized Principal authenticate(DirContext context, String username, String credentials) throws NamingException { if (username == null || username.equals("") || credentials == null || credentials.equals("")) { if (containerLog.isDebugEnabled()) containerLog.debug("username null or empty: returning null principal."); return (null); } if (userPatternArray != null) { for (int curUserPattern = 0; curUserPattern < userPatternFormatArray.length; curUserPattern++) { // Retrieve user information User user = getUser(context, username, credentials, curUserPattern); if (user != null) { try { // Check the user's credentials if (checkCredentials(context, user, credentials)) { // Search for additional roles List roles = getRoles(context, user); if (containerLog.isDebugEnabled()) { Iterator it = roles.iterator(); // TODO: Use a single log message while (it.hasNext()) { containerLog.debug("Found role: " + it.next()); } } return (new GenericPrincipal(username, credentials, roles)); } } catch (InvalidNameException ine) { // Log the problem for posterity containerLog.warn(sm.getString("jndiRealm.exception"), ine); // ignore; this is probably due to a name not fitting // the search path format exactly, as in a fully- // qualified name being munged into a search path // that already contains cn= or vice-versa } } } return null; } else { // Retrieve user information User user = getUser(context, username, credentials); if (user == null) return (null); // Check the user's credentials if (!checkCredentials(context, user, credentials)) return (null); // Search for additional roles List roles = getRoles(context, user); if (containerLog.isDebugEnabled()) { Iterator it = roles.iterator(); // TODO: Use a single log message while (it.hasNext()) { containerLog.debug("Found role: " + it.next()); } } // Create and return a suitable Principal for this user return (new GenericPrincipal(username, credentials, roles)); } } /** * Return a User object containing information about the user * with the specified username, if found in the directory; * otherwise return null. * * @param context The directory context * @param username Username to be looked up * * @exception NamingException if a directory server error occurs * * @see #getUser(DirContext, String, String, int) */ protected User getUser(DirContext context, String username) throws NamingException { return getUser(context, username, null, -1); } /** * Return a User object containing information about the user * with the specified username, if found in the directory; * otherwise return null. * * @param context The directory context * @param username Username to be looked up * @param credentials User credentials (optional) * * @exception NamingException if a directory server error occurs * * @see #getUser(DirContext, String, String, int) */ protected User getUser(DirContext context, String username, String credentials) throws NamingException { return getUser(context, username, credentials, -1); } /** * Return a User object containing information about the user * with the specified username, if found in the directory; * otherwise return null. * * If the userPassword configuration attribute is * specified, the value of that attribute is retrieved from the * user's directory entry. If the userRoleName * configuration attribute is specified, all values of that * attribute are retrieved from the directory entry. * * @param context The directory context * @param username Username to be looked up * @param credentials User credentials (optional) * @param curUserPattern Index into userPatternFormatArray * * @exception NamingException if a directory server error occurs */ protected User getUser(DirContext context, String username, String credentials, int curUserPattern) throws NamingException { User user = null; // Get attributes to retrieve from user entry ArrayList list = new ArrayList(); if (userPassword != null) list.add(userPassword); if (userRoleName != null) list.add(userRoleName); if (userRoleAttribute != null) { list.add(userRoleAttribute); } String[] attrIds = new String[list.size()]; list.toArray(attrIds); // Use pattern or search for user entry if (userPatternFormatArray != null && curUserPattern >= 0) { user = getUserByPattern(context, username, credentials, attrIds, curUserPattern); } else { user = getUserBySearch(context, username, attrIds); } return user; } /** * Use the distinguished name to locate the directory * entry for the user with the specified username and * return a User object; otherwise return null. * * @param context The directory context * @param username The username * @param attrIds String[]containing names of attributes to * @param dn Distinguished name of the user * retrieve. * * @exception NamingException if a directory server error occurs */ protected User getUserByPattern(DirContext context, String username, String[] attrIds, String dn) throws NamingException { // If no attributes are requested, no need to look for them if (attrIds == null || attrIds.length == 0) { return new User(username, dn, null, null,null); } // Get required attributes from user entry Attributes attrs = null; try { attrs = context.getAttributes(dn, attrIds); } catch (NameNotFoundException e) { return (null); } if (attrs == null) return (null); // Retrieve value of userPassword String password = null; if (userPassword != null) password = getAttributeValue(userPassword, attrs); String userRoleAttrValue = null; if (userRoleAttribute != null) { userRoleAttrValue = getAttributeValue(userRoleAttribute, attrs); } // Retrieve values of userRoleName attribute ArrayList roles = null; if (userRoleName != null) roles = addAttributeValues(userRoleName, attrs, roles); return new User(username, dn, password, roles, userRoleAttrValue); } /** * Use the UserPattern configuration attribute to * locate the directory entry for the user with the specified * username and return a User object; otherwise return * null. * * @param context The directory context * @param username The username * @param credentials User credentials (optional) * @param attrIds String[]containing names of attributes to * @param curUserPattern Index into userPatternFormatArray * * @exception NamingException if a directory server error occurs * @see #getUserByPattern(DirContext, String, String[], String) */ protected User getUserByPattern(DirContext context, String username, String credentials, String[] attrIds, int curUserPattern) throws NamingException { User user = null; if (username == null || userPatternFormatArray[curUserPattern] == null) return (null); // Form the dn from the user pattern String dn = userPatternFormatArray[curUserPattern].format(new String[] { username }); try { user = getUserByPattern(context, username, attrIds, dn); } catch (NameNotFoundException e) { return (null); } catch (NamingException e) { // If the getUserByPattern() call fails, try it again with the // credentials of the user that we're searching for try { userCredentialsAdd(context, dn, credentials); user = getUserByPattern(context, username, attrIds, dn); } finally { userCredentialsRemove(context); } } return user; } /** * Search the directory to return a User object containing * information about the user with the specified username, if * found in the directory; otherwise return null. * * @param context The directory context * @param username The username * @param attrIds String[]containing names of attributes to retrieve. * * @exception NamingException if a directory server error occurs */ protected User getUserBySearch(DirContext context, String username, String[] attrIds) throws NamingException { if (username == null || userSearchFormat == null) return (null); // Form the search filter String filter = userSearchFormat.format(new String[] { username }); // Set up the search controls SearchControls constraints = new SearchControls(); if (userSubtree) { constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); } else { constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE); } constraints.setCountLimit(sizeLimit); constraints.setTimeLimit(timeLimit); // Specify the attributes to be retrieved if (attrIds == null) attrIds = new String[0]; constraints.setReturningAttributes(attrIds); NamingEnumeration results = context.search(userBase, filter, constraints); // Fail if no entries found try { if (results == null || !results.hasMore()) { return (null); } } catch (PartialResultException ex) { if (!adCompat) throw ex; else return (null); } // Get result for the first entry found SearchResult result = results.next(); // Check no further entries were found try { if (results.hasMore()) { if(containerLog.isInfoEnabled()) containerLog.info("username " + username + " has multiple entries"); return (null); } } catch (PartialResultException ex) { if (!adCompat) throw ex; } String dn = getDistinguishedName(context, userBase, result); if (containerLog.isTraceEnabled()) containerLog.trace(" entry found for " + username + " with dn " + dn); // Get the entry's attributes Attributes attrs = result.getAttributes(); if (attrs == null) return null; // Retrieve value of userPassword String password = null; if (userPassword != null) password = getAttributeValue(userPassword, attrs); String userRoleAttrValue = null; if (userRoleAttribute != null) { userRoleAttrValue = getAttributeValue(userRoleAttribute, attrs); } // Retrieve values of userRoleName attribute ArrayList roles = null; if (userRoleName != null) roles = addAttributeValues(userRoleName, attrs, roles); return new User(username, dn, password, roles, userRoleAttrValue); } /** * Check whether the given User can be authenticated with the * given credentials. If the userPassword * configuration attribute is specified, the credentials * previously retrieved from the directory are compared explicitly * with those presented by the user. Otherwise the presented * credentials are checked by binding to the directory as the * user. * * @param context The directory context * @param user The User to be authenticated * @param credentials The credentials presented by the user * * @exception NamingException if a directory server error occurs */ protected boolean checkCredentials(DirContext context, User user, String credentials) throws NamingException { boolean validated = false; if (userPassword == null) { validated = bindAsUser(context, user, credentials); } else { validated = compareCredentials(context, user, credentials); } if (containerLog.isTraceEnabled()) { if (validated) { containerLog.trace(sm.getString("jndiRealm.authenticateSuccess", user.getUserName())); } else { containerLog.trace(sm.getString("jndiRealm.authenticateFailure", user.getUserName())); } } return (validated); } /** * Check whether the credentials presented by the user match those * retrieved from the directory. * * @param context The directory context * @param info The User to be authenticated * @param credentials Authentication credentials * * @exception NamingException if a directory server error occurs */ protected boolean compareCredentials(DirContext context, User info, String credentials) throws NamingException { // Validate the credentials specified by the user if (containerLog.isTraceEnabled()) containerLog.trace(" validating credentials"); if (info == null || credentials == null) return (false); String password = info.getPassword(); return compareCredentials(credentials, password); } /** * Check credentials by binding to the directory as the user * * @param context The directory context * @param user The User to be authenticated * @param credentials Authentication credentials * * @exception NamingException if a directory server error occurs */ protected boolean bindAsUser(DirContext context, User user, String credentials) throws NamingException { if (credentials == null || user == null) return (false); String dn = user.getDN(); if (dn == null) return (false); // Validate the credentials specified by the user if (containerLog.isTraceEnabled()) { containerLog.trace(" validating credentials by binding as the user"); } userCredentialsAdd(context, dn, credentials); // Elicit an LDAP bind operation boolean validated = false; try { if (containerLog.isTraceEnabled()) { containerLog.trace(" binding as " + dn); } context.getAttributes("", null); validated = true; } catch (AuthenticationException e) { if (containerLog.isTraceEnabled()) { containerLog.trace(" bind attempt failed"); } } userCredentialsRemove(context); return (validated); } /** * Configure the context to use the provided credentials for * authentication. * * @param context DirContext to configure * @param dn Distinguished name of user * @param credentials Credentials of user */ private void userCredentialsAdd(DirContext context, String dn, String credentials) throws NamingException { // Set up security environment to bind as the user context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn); context.addToEnvironment(Context.SECURITY_CREDENTIALS, credentials); } /** * Configure the context to use {@link #connectionName} and * {@link #connectionPassword} if specified or an anonymous connection if * those attributes are not specified. * * @param context DirContext to configure */ private void userCredentialsRemove(DirContext context) throws NamingException { // Restore the original security environment if (connectionName != null) { context.addToEnvironment(Context.SECURITY_PRINCIPAL, connectionName); } else { context.removeFromEnvironment(Context.SECURITY_PRINCIPAL); } if (connectionPassword != null) { context.addToEnvironment(Context.SECURITY_CREDENTIALS, connectionPassword); } else { context.removeFromEnvironment(Context.SECURITY_CREDENTIALS); } } /** * Return a List of roles associated with the given User. Any * roles present in the user's directory entry are supplemented by * a directory search. If no roles are associated with this user, * a zero-length List is returned. * * @param context The directory context we are searching * @param user The User to be checked * * @exception NamingException if a directory server error occurs */ protected List getRoles(DirContext context, User user) throws NamingException { if (user == null) return (null); String dn = user.getDN(); String username = user.getUserName(); String userRoleId = user.getUserRoleId(); if (dn == null || username == null) return (null); if (containerLog.isTraceEnabled()) containerLog.trace(" getRoles(" + dn + ")"); // Start with roles retrieved from the user entry List list = new ArrayList(); List userRoles = user.getRoles(); if (userRoles != null) { list.addAll(userRoles); } if (commonRole != null) list.add(commonRole); if (containerLog.isTraceEnabled()) { containerLog.trace(" Found " + list.size() + " user internal roles"); for (int i=0; i results = null; try { if (roleSearchAsUser) { userCredentialsAdd(context, dn, user.getPassword()); } results = context.search(base, filter, controls); } finally { if (roleSearchAsUser) { userCredentialsRemove(context); } } if (results == null) return (list); // Should never happen, but just in case ... HashMap groupMap = new HashMap(); try { while (results.hasMore()) { SearchResult result = results.next(); Attributes attrs = result.getAttributes(); if (attrs == null) continue; String dname = getDistinguishedName(context, roleBase, result); String name = getAttributeValue(roleName, attrs); if (name != null && dname != null) { groupMap.put(dname, name); } } } catch (PartialResultException ex) { if (!adCompat) throw ex; } Set keys = groupMap.keySet(); if (containerLog.isTraceEnabled()) { containerLog.trace(" Found " + keys.size() + " direct roles"); for (String key: keys) { containerLog.trace( " Found direct role " + key + " -> " + groupMap.get(key)); } } // if nested group search is enabled, perform searches for nested groups until no new group is found if (getRoleNested()) { // The following efficient algorithm is known as memberOf Algorithm, as described in "Practices in // Directory Groups". It avoids group slurping and handles cyclic group memberships as well. // See http://middleware.internet2.edu/dir/ for details Map newGroups = new HashMap(groupMap); while (!newGroups.isEmpty()) { Map newThisRound = new HashMap(); // Stores the groups we find in this iteration for (Entry group : newGroups.entrySet()) { filter = roleFormat.format(new String[] { group.getKey(), group.getValue(), group.getValue() }); if (containerLog.isTraceEnabled()) { containerLog.trace("Perform a nested group search with base "+ roleBase + " and filter " + filter); } results = context.search(roleBase, filter, controls); try { while (results.hasMore()) { SearchResult result = results.next(); Attributes attrs = result.getAttributes(); if (attrs == null) continue; String dname = getDistinguishedName(context, roleBase, result); String name = getAttributeValue(roleName, attrs); if (name != null && dname != null && !groupMap.keySet().contains(dname)) { groupMap.put(dname, name); newThisRound.put(dname, name); if (containerLog.isTraceEnabled()) { containerLog.trace(" Found nested role " + dname + " -> " + name); } } } } catch (PartialResultException ex) { if (!adCompat) throw ex; } } newGroups = newThisRound; } } list.addAll(groupMap.values()); return list; } /** * Return a String representing the value of the specified attribute. * * @param attrId Attribute name * @param attrs Attributes containing the required value * * @exception NamingException if a directory server error occurs */ private String getAttributeValue(String attrId, Attributes attrs) throws NamingException { if (containerLog.isTraceEnabled()) containerLog.trace(" retrieving attribute " + attrId); if (attrId == null || attrs == null) return null; Attribute attr = attrs.get(attrId); if (attr == null) return (null); Object value = attr.get(); if (value == null) return (null); String valueString = null; if (value instanceof byte[]) valueString = new String((byte[]) value); else valueString = value.toString(); return valueString; } /** * Add values of a specified attribute to a list * * @param attrId Attribute name * @param attrs Attributes containing the new values * @param values ArrayList containing values found so far * * @exception NamingException if a directory server error occurs */ private ArrayList addAttributeValues(String attrId, Attributes attrs, ArrayList values) throws NamingException{ if (containerLog.isTraceEnabled()) containerLog.trace(" retrieving values for attribute " + attrId); if (attrId == null || attrs == null) return values; if (values == null) values = new ArrayList(); Attribute attr = attrs.get(attrId); if (attr == null) return (values); NamingEnumeration e = attr.getAll(); try { while(e.hasMore()) { String value = (String)e.next(); values.add(value); } } catch (PartialResultException ex) { if (!adCompat) throw ex; } return values; } /** * Close any open connection to the directory server for this Realm. * * @param context The directory context to be closed */ protected void close(DirContext context) { // Do nothing if there is no opened connection if (context == null) return; // Close our opened connection try { if (containerLog.isDebugEnabled()) containerLog.debug("Closing directory context"); context.close(); } catch (NamingException e) { containerLog.error(sm.getString("jndiRealm.close"), e); } this.context = null; } /** * Return a short name for this Realm implementation. */ @Override protected String getName() { return (name); } /** * Return the password associated with the given principal's user name. */ @Override protected String getPassword(String username) { return (null); } /** * Return the Principal associated with the given user name. */ @Override protected Principal getPrincipal(String username) { return getPrincipal(username, null); } @Override protected Principal getPrincipal(String username, GSSCredential gssCredential) { DirContext context = null; Principal principal = null; try { // Ensure that we have a directory context available context = open(); // Occasionally the directory context will timeout. Try one more // time before giving up. try { // Authenticate the specified username if possible principal = getPrincipal(context, username, gssCredential); } catch (CommunicationException e) { // log the exception so we know it's there. containerLog.info(sm.getString("jndiRealm.exception.retry"), e); // close the connection so we know it will be reopened. if (context != null) close(context); // open a new directory context. context = open(); // Try the authentication again. principal = getPrincipal(context, username, gssCredential); } catch (ServiceUnavailableException e) { // log the exception so we know it's there. containerLog.info(sm.getString("jndiRealm.exception.retry"), e); // close the connection so we know it will be reopened. if (context != null) close(context); // open a new directory context. context = open(); // Try the authentication again. principal = getPrincipal(context, username, gssCredential); } // Release this context release(context); // Return the authenticated Principal (if any) return (principal); } catch (NamingException e) { // Log the problem for posterity containerLog.error(sm.getString("jndiRealm.exception"), e); // Close the connection so that it gets reopened next time if (context != null) close(context); // Return "not authenticated" for this request return (null); } } /** * Return the Principal associated with the given user name. */ protected synchronized Principal getPrincipal(DirContext context, String username, GSSCredential gssCredential) throws NamingException { User user = null; List roles = null; Hashtable preservedEnvironment = null; try { if (gssCredential != null && isUseDelegatedCredential()) { // Preserve the current context environment parameters preservedEnvironment = context.getEnvironment(); // Set up context context.addToEnvironment( Context.SECURITY_AUTHENTICATION, "GSSAPI"); context.addToEnvironment( "javax.security.sasl.server.authentication", "true"); context.addToEnvironment( "javax.security.sasl.qop", spnegoDelegationQop); // Note: Subject already set in SPNEGO authenticator so no need // for Subject.doAs() here } user = getUser(context, username); if (user != null) { roles = getRoles(context, user); } } finally { restoreEnvironmentParameter(context, Context.SECURITY_AUTHENTICATION, preservedEnvironment); restoreEnvironmentParameter(context, "javax.security.sasl.server.authentication", preservedEnvironment); restoreEnvironmentParameter(context, "javax.security.sasl.qop", preservedEnvironment); } if (user != null) { return new GenericPrincipal(user.getUserName(), user.getPassword(), roles, null, null, gssCredential); } return null; } private void restoreEnvironmentParameter(DirContext context, String parameterName, Hashtable preservedEnvironment) { try { context.removeFromEnvironment(parameterName); if (preservedEnvironment != null && preservedEnvironment.containsKey(parameterName)) { context.addToEnvironment(parameterName, preservedEnvironment.get(parameterName)); } } catch (NamingException e) { // Ignore } } /** * Open (if necessary) and return a connection to the configured * directory server for this Realm. * * @exception NamingException if a directory server error occurs */ protected DirContext open() throws NamingException { // Do nothing if there is a directory server connection already open if (context != null) return (context); try { // Ensure that we have a directory context available context = new InitialDirContext(getDirectoryContextEnvironment()); } catch (Exception e) { connectionAttempt = 1; // log the first exception. containerLog.info(sm.getString("jndiRealm.exception.retry"), e); // Try connecting to the alternate url. context = new InitialDirContext(getDirectoryContextEnvironment()); } finally { // reset it in case the connection times out. // the primary may come back. connectionAttempt = 0; } return (context); } /** * Create our directory context configuration. * * @return java.util.Hashtable the configuration for the directory context. */ protected Hashtable getDirectoryContextEnvironment() { Hashtable env = new Hashtable(); // Configure our directory context environment. if (containerLog.isDebugEnabled() && connectionAttempt == 0) containerLog.debug("Connecting to URL " + connectionURL); else if (containerLog.isDebugEnabled() && connectionAttempt > 0) containerLog.debug("Connecting to URL " + alternateURL); env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); if (connectionName != null) env.put(Context.SECURITY_PRINCIPAL, connectionName); if (connectionPassword != null) env.put(Context.SECURITY_CREDENTIALS, connectionPassword); if (connectionURL != null && connectionAttempt == 0) env.put(Context.PROVIDER_URL, connectionURL); else if (alternateURL != null && connectionAttempt > 0) env.put(Context.PROVIDER_URL, alternateURL); if (authentication != null) env.put(Context.SECURITY_AUTHENTICATION, authentication); if (protocol != null) env.put(Context.SECURITY_PROTOCOL, protocol); if (referrals != null) env.put(Context.REFERRAL, referrals); if (derefAliases != null) env.put(JNDIRealm.DEREF_ALIASES, derefAliases); if (connectionTimeout != null) env.put("com.sun.jndi.ldap.connect.timeout", connectionTimeout); return env; } /** * Release our use of this connection so that it can be recycled. * * @param context The directory context to release */ protected void release(DirContext context) { // NO-OP since we are not pooling anything } // ------------------------------------------------------ Lifecycle Methods /** * Prepare for the beginning of active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { // Validate that we can open our connection try { open(); } catch (NamingException e) { throw new LifecycleException(sm.getString("jndiRealm.open"), e); } super.startInternal(); } /** * Gracefully terminate the active use of the public methods of this * component and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { super.stopInternal(); // Close any open directory server connection close(this.context); } /** * Given a string containing LDAP patterns for user locations (separated by * parentheses in a pseudo-LDAP search string format - * "(location1)(location2)", returns an array of those paths. Real LDAP * search strings are supported as well (though only the "|" "OR" type). * * @param userPatternString - a string LDAP search paths surrounded by * parentheses */ protected String[] parseUserPatternString(String userPatternString) { if (userPatternString != null) { ArrayList pathList = new ArrayList(); int startParenLoc = userPatternString.indexOf('('); if (startParenLoc == -1) { // no parens here; return whole thing return new String[] {userPatternString}; } int startingPoint = 0; while (startParenLoc > -1) { int endParenLoc = 0; // weed out escaped open parens and parens enclosing the // whole statement (in the case of valid LDAP search // strings: (|(something)(somethingelse)) while ( (userPatternString.charAt(startParenLoc + 1) == '|') || (startParenLoc != 0 && userPatternString.charAt(startParenLoc - 1) == '\\') ) { startParenLoc = userPatternString.indexOf("(", startParenLoc+1); } endParenLoc = userPatternString.indexOf(")", startParenLoc+1); // weed out escaped end-parens while (userPatternString.charAt(endParenLoc - 1) == '\\') { endParenLoc = userPatternString.indexOf(")", endParenLoc+1); } String nextPathPart = userPatternString.substring (startParenLoc+1, endParenLoc); pathList.add(nextPathPart); startingPoint = endParenLoc+1; startParenLoc = userPatternString.indexOf('(', startingPoint); } return pathList.toArray(new String[] {}); } return null; } /** * Given an LDAP search string, returns the string with certain characters * escaped according to RFC 2254 guidelines. * The character mapping is as follows: * char -> Replacement * --------------------------- * * -> \2a * ( -> \28 * ) -> \29 * \ -> \5c * \0 -> \00 * @param inString string to escape according to RFC 2254 guidelines * @return String the escaped/encoded result */ protected String doRFC2254Encoding(String inString) { StringBuilder buf = new StringBuilder(inString.length()); for (int i = 0; i < inString.length(); i++) { char c = inString.charAt(i); switch (c) { case '\\': buf.append("\\5c"); break; case '*': buf.append("\\2a"); break; case '(': buf.append("\\28"); break; case ')': buf.append("\\29"); break; case '\0': buf.append("\\00"); break; default: buf.append(c); break; } } return buf.toString(); } /** * Returns the distinguished name of a search result. * * @param context Our DirContext * @param base The base DN * @param result The search result * @return String containing the distinguished name */ protected String getDistinguishedName(DirContext context, String base, SearchResult result) throws NamingException { // Get the entry's distinguished name. For relative results, this means // we need to composite a name with the base name, the context name, and // the result name. For non-relative names, use the returned name. if (result.isRelative()) { if (containerLog.isTraceEnabled()) { containerLog.trace(" search returned relative name: " + result.getName()); } NameParser parser = context.getNameParser(""); Name contextName = parser.parse(context.getNameInNamespace()); Name baseName = parser.parse(base); // Bugzilla 32269 Name entryName = parser.parse(new CompositeName(result.getName()).get(0)); Name name = contextName.addAll(baseName); name = name.addAll(entryName); return name.toString(); } else { String absoluteName = result.getName(); if (containerLog.isTraceEnabled()) containerLog.trace(" search returned absolute name: " + result.getName()); try { // Normalize the name by running it through the name parser. NameParser parser = context.getNameParser(""); URI userNameUri = new URI(absoluteName); String pathComponent = userNameUri.getPath(); // Should not ever have an empty path component, since that is /{DN} if (pathComponent.length() < 1 ) { throw new InvalidNameException( "Search returned unparseable absolute name: " + absoluteName ); } Name name = parser.parse(pathComponent.substring(1)); return name.toString(); } catch ( URISyntaxException e ) { throw new InvalidNameException( "Search returned unparseable absolute name: " + absoluteName ); } } } // ------------------------------------------------------ Private Classes /** * A protected class representing a User */ protected static class User { private final String username; private final String dn; private final String password; private final List roles; private final String userRoleId; public User(String username, String dn, String password, List roles, String userRoleId) { this.username = username; this.dn = dn; this.password = password; if (roles == null) { this.roles = Collections.emptyList(); } else { this.roles = Collections.unmodifiableList(roles); } this.userRoleId = userRoleId; } public String getUserName() { return username; } public String getDN() { return dn; } public String getPassword() { return password; } public List getRoles() { return roles; } public String getUserRoleId() { return userRoleId; } } } tomcat7-7.0.52/java/org/apache/catalina/Realm.java0000644000175100017510000001634512271471332021566 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.beans.PropertyChangeListener; import java.io.IOException; import java.security.Principal; import java.security.cert.X509Certificate; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.deploy.SecurityConstraint; import org.ietf.jgss.GSSContext; /** * A Realm is a read-only facade for an underlying security realm * used to authenticate individual users, and identify the security roles * associated with those users. Realms can be attached at any Container * level, but will typically only be attached to a Context, or higher level, * Container. * * @author Craig R. McClanahan */ public interface Realm { // ------------------------------------------------------------- Properties /** * Return the Container with which this Realm has been associated. */ public Container getContainer(); /** * Set the Container with which this Realm has been associated. * * @param container The associated Container */ public void setContainer(Container container); /** * Return descriptive information about this Realm implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo(); // --------------------------------------------------------- Public Methods /** * Add a property change listener to this component. * * @param listener The listener to add */ public void addPropertyChangeListener(PropertyChangeListener listener); /** * Return the Principal associated with the specified username and * credentials, if there is one; otherwise return null. * * @param username Username of the Principal to look up * @param credentials Password or other credentials to use in * authenticating this username */ public Principal authenticate(String username, String credentials); /** * Return the Principal associated with the specified username, which * matches the digest calculated using the given parameters using the * method described in RFC 2069; otherwise return null. * * @param username Username of the Principal to look up * @param digest Digest which has been submitted by the client * @param nonce Unique (or supposedly unique) token which has been used * for this request * @param realm Realm name * @param md5a2 Second MD5 digest used to calculate the digest : * MD5(Method + ":" + uri) */ public Principal authenticate(String username, String digest, String nonce, String nc, String cnonce, String qop, String realm, String md5a2); /** * Return the Principal associated with the specified {@link GSSContext}. * If there is none, return null. * * @param gssContext The gssContext processed by the {@link Authenticator}. * @param storeCreds Should the realm attempt to store the delegated * credentials in the returned Principal? */ public Principal authenticate(GSSContext gssContext, boolean storeCreds); /** * Return the Principal associated with the specified chain of X509 * client certificates. If there is none, return null. * * @param certs Array of client certificates, with the first one in * the array being the certificate of the client itself. */ public Principal authenticate(X509Certificate certs[]); /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ public void backgroundProcess(); /** * Return the SecurityConstraints configured to guard the request URI for * this request, or null if there is no such constraint. * * @param request Request we are processing */ public SecurityConstraint [] findSecurityConstraints(Request request, Context context); /** * Perform access control based on the specified authorization constraint. * Return true if this constraint is satisfied and processing * should continue, or false otherwise. * * @param request Request we are processing * @param response Response we are creating * @param constraint Security constraint we are enforcing * @param context The Context to which client of this class is attached. * * @exception IOException if an input/output error occurs */ public boolean hasResourcePermission(Request request, Response response, SecurityConstraint [] constraint, Context context) throws IOException; /** * Return true if the specified Principal has the specified * security role, within the context of this Realm; otherwise return * false. * * @param wrapper wrapper context for evaluating role * @param principal Principal for whom the role is to be checked * @param role Security role to be checked */ public boolean hasRole(Wrapper wrapper, Principal principal, String role); /** * Enforce any user data constraint required by the security constraint * guarding this request URI. Return true if this constraint * was not violated and processing should continue, or false * if we have created a response already. * * @param request Request we are processing * @param response Response we are creating * @param constraint Security constraint being checked * * @exception IOException if an input/output error occurs */ public boolean hasUserDataPermission(Request request, Response response, SecurityConstraint []constraint) throws IOException; /** * Remove a property change listener from this component. * * @param listener The listener to remove */ public void removePropertyChangeListener(PropertyChangeListener listener); } tomcat7-7.0.52/java/org/apache/catalina/LifecycleState.java0000644000175100017510000000460011656661221023421 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * The list of valid states for components that implement {@link Lifecycle}. * See {@link Lifecycle} for the state transition diagram. */ public enum LifecycleState { NEW(false, null), INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT), INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT), STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT), STARTING(true, Lifecycle.START_EVENT), STARTED(true, Lifecycle.AFTER_START_EVENT), STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT), STOPPING(false, Lifecycle.STOP_EVENT), STOPPED(false, Lifecycle.AFTER_STOP_EVENT), DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT), DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT), FAILED(false, null), MUST_STOP(true, null), MUST_DESTROY(false, null); private final boolean available; private final String lifecycleEvent; private LifecycleState(boolean available, String lifecycleEvent) { this.available = available; this.lifecycleEvent = lifecycleEvent; } /** * May the public methods other than property getters/setters and lifecycle * methods be called for a component in this state? It returns * true for any component in any of the following states: *
      *
    • {@link #STARTING}
    • *
    • {@link #STARTED}
    • *
    • {@link #STOPPING_PREP}
    • *
    • {@link #MUST_STOP}
    • *
    */ public boolean isAvailable() { return available; } /** * */ public String getLifecycleEvent() { return lifecycleEvent; } } tomcat7-7.0.52/java/org/apache/catalina/ant/0000755000175100017510000000000012301126370020425 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ant/FindLeaksTask.java0000644000175100017510000000341511566753370024000 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /findleaks command, supported by * the Tomcat manager application. */ public class FindLeaksTask extends AbstractCatalinaTask { private boolean statusLine = true; /** * Sets the statusLine parameter that controls if the response includes a * status line or not. */ public void setStatusLine(boolean statusLine) { this.statusLine = statusLine; } /** * Returns the statusLine parameter that controls if the response includes a * status line or not. */ public boolean getStatusLine() { return statusLine; } /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute("/findleaks?statusLine=" + Boolean.toString(statusLine)); } } tomcat7-7.0.52/java/org/apache/catalina/ant/ValidatorTask.java0000644000175100017510000000734212271471332024055 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import org.apache.catalina.Globals; import org.apache.catalina.startup.Constants; import org.apache.tomcat.util.descriptor.DigesterFactory; import org.apache.tomcat.util.digester.Digester; import org.apache.tools.ant.BuildException; import org.xml.sax.InputSource; /** * Task for validating a web application deployment descriptor, using XML * schema validation. * * @author Remy Maucherat * @since 5.0 */ public class ValidatorTask extends BaseRedirectorHelperTask { // ----------------------------------------------------- Instance Variables // ------------------------------------------------------------- Properties /** * The path to the webapp directory. */ protected String path = null; public String getPath() { return (this.path); } public void setPath(String path) { this.path = path; } // --------------------------------------------------------- Public Methods /** * Execute the specified command. This logic only performs the common * attribute validation required by all subclasses; it does not perform * any functional logic directly. * * @exception BuildException if a validation error occurs */ @Override public void execute() throws BuildException { if (path == null) { throw new BuildException("Must specify 'path'"); } File file = new File(path, Constants.ApplicationWebXml); if ((!file.exists()) || (!file.canRead())) { throw new BuildException("Cannot find web.xml"); } // Commons-logging likes having the context classloader set ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader (ValidatorTask.class.getClassLoader()); // Called through trusted manager interface. If running under a // SecurityManager assume that untrusted applications may be deployed. Digester digester = DigesterFactory.newDigester( true, true, null, Globals.IS_SECURITY_ENABLED); try { file = file.getCanonicalFile(); InputStream stream = new BufferedInputStream(new FileInputStream(file)); InputSource is = new InputSource(file.toURI().toURL().toExternalForm()); is.setByteStream(stream); digester.parse(is); handleOutput("web.xml validated"); } catch (Exception e) { if (isFailOnError()) { throw new BuildException("Validation failure", e); } else { handleErrorOutput("Validation failure: " + e); } } finally { Thread.currentThread().setContextClassLoader(oldCL); closeRedirector(); } } } tomcat7-7.0.52/java/org/apache/catalina/ant/UndeployTask.java0000644000175100017510000000256512271471332023731 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /undeploy command, supported by * the Tomcat manager application. * * @author Craig R. McClanahan * @since 4.1 */ public class UndeployTask extends AbstractCatalinaCommandTask { /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute(createQueryString("/undeploy").toString()); } } tomcat7-7.0.52/java/org/apache/catalina/ant/JMXGetTask.java0000644000175100017510000000543412271471332023226 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the JMX Get command (/jmxproxy/?get) * supported by the Tomcat manager application. * * @author Peter Rossbach */ public class JMXGetTask extends AbstractCatalinaTask { // Properties /** * The full bean name */ protected String bean = null; /** * The attribute you wish to alter */ protected String attribute = null; // Public Methods /** * Get method for the bean name * @return Bean name */ public String getBean () { return this.bean; } /** * Set method for the bean name * @param bean Bean name */ public void setBean (String bean) { this.bean = bean; } /** * Get method for the attribute name * @return Attribute name */ public String getAttribute () { return this.attribute; } /** * Set method for the attribute name * @param attribute Attribute name */ public void setAttribute (String attribute) { this.attribute = attribute; } /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); if (bean == null || attribute == null) { throw new BuildException ("Must specify 'bean' and 'attribute' attributes"); } log("Getting attribute " + attribute + " in bean " + bean ); try { execute("/jmxproxy/?get=" + URLEncoder.encode(bean, getCharset()) + "&att=" + URLEncoder.encode(attribute, getCharset())); } catch (UnsupportedEncodingException e) { throw new BuildException ("Invalid 'charset' attribute: " + getCharset()); } } } tomcat7-7.0.52/java/org/apache/catalina/ant/ResourcesTask.java0000644000175100017510000000431112271471332024073 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /resources command, supported by * the Tomcat manager application. * * @author Craig R. McClanahan * @since 4.1 */ public class ResourcesTask extends AbstractCatalinaTask { // ------------------------------------------------------------- Properties /** * The fully qualified class name of the resource type being requested * (if any). */ protected String type = null; public String getType() { return (this.type); } public void setType(String type) { this.type = type; } // --------------------------------------------------------- Public Methods /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); if (type != null) { try { execute("/resources?type=" + URLEncoder.encode(type, getCharset())); } catch (UnsupportedEncodingException e) { throw new BuildException ("Invalid 'charset' attribute: " + getCharset()); } } else { execute("/resources"); } } } tomcat7-7.0.52/java/org/apache/catalina/ant/SessionsTask.java0000644000175100017510000000351412271471332023733 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /sessions command * supported by the Tomcat manager application. * * @author Vivek Chopra */ public class SessionsTask extends AbstractCatalinaCommandTask { protected String idle = null; public String getIdle() { return this.idle; } public void setIdle(String idle) { this.idle = idle; } @Override public StringBuilder createQueryString(String command) { StringBuilder buffer = super.createQueryString(command); if (path != null && idle != null) { buffer.append("&idle="); buffer.append(this.idle); } return buffer; } /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute(createQueryString("/sessions").toString()); } } tomcat7-7.0.52/java/org/apache/catalina/ant/ReloadTask.java0000644000175100017510000000256012271471332023333 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /reload command, supported by the * Tomcat manager application. * * @author Craig R. McClanahan * @since 4.1 */ public class ReloadTask extends AbstractCatalinaCommandTask { /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute(createQueryString("/reload").toString()); } } tomcat7-7.0.52/java/org/apache/catalina/ant/JMXSetTask.java0000644000175100017510000000653312271471332023243 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the JMX Set command (/jmxproxy/?set) * supported by the Tomcat manager application. * * @author Vivek Chopra */ public class JMXSetTask extends AbstractCatalinaTask { // Properties /** * The full bean name */ protected String bean = null; /** * The attribute you wish to alter */ protected String attribute = null; /** * The new value for the attribute */ protected String value = null; // Public Methods /** * Get method for the bean name * @return Bean name */ public String getBean () { return this.bean; } /** * Set method for the bean name * @param bean Bean name */ public void setBean (String bean) { this.bean = bean; } /** * Get method for the attribute name * @return Attribute name */ public String getAttribute () { return this.attribute; } /** * Set method for the attribute name * @param attribute Attribute name */ public void setAttribute (String attribute) { this.attribute = attribute; } /** * Get method for the attribute value * @return Attribute value */ public String getValue () { return this.value; } /** * Set method for the attribute value. * @param value Attribute value */ public void setValue (String value) { this.value = value; } /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); if (bean == null || attribute == null || value == null) { throw new BuildException ("Must specify 'bean', 'attribute' and 'value' attributes"); } log("Setting attribute " + attribute + " in bean " + bean + " to " + value); try { execute("/jmxproxy/?set=" + URLEncoder.encode(bean, getCharset()) + "&att=" + URLEncoder.encode(attribute, getCharset()) + "&val=" + URLEncoder.encode(value, getCharset())); } catch (UnsupportedEncodingException e) { throw new BuildException ("Invalid 'charset' attribute: " + getCharset()); } } } tomcat7-7.0.52/java/org/apache/catalina/ant/package.html0000644000175100017510000001021112271471332022710 0ustar locutuslocutus

    This package contains a set of Task implementations for Ant (version 1.6.x or later) that can be used to interact with the Manager application to deploy, undeploy, list, reload, start and stop web applications from a running instance of Tomcat. For more information, see http://tomcat.apache.org/tomcat-7.0-doc/manager-howto.html.

    The attributes of each task element correspond exactly to the request parameters that are included with an HTTP request sent directly to the Manager application. They are summarized as follows:

    Attribute Description
    url The URL of the Manager web application you will use to perform the requested operations. If not specified, defaults to http://localhost:8080/manager/text (which corresponds to a standard installation of Tomcat 7).
    username The username of a Tomcat user that has been configured with the manager-script role, as required to execute Manager application commands. This attribute is required.
    password The password of a Tomcat user that has been configured with the manager-script role, as required to execute Manager application commands. This attribute is required.
    config A URL pointing at the context configuration file (i.e. a file containing only the <Context> element, and its nested elements, from server.xml for a particular web application). This attribute is supported only on the install target, and is required only if you wish to install an application with non-default configuration characteristics.
    path The context path (including the leading slash) of the web application this command is intended to manage, or a zero-length string for the ROOT web application. This attribute is valid for the install, reload, remove, start, and stop tasks only, and is required in all of those cases.
    war A jar: URL that points at a web application archive (WAR) file, or a file: URL that points at an unpacked directory containing the web application. This attribute is supported only on the install target. You must specify at least one of the config and war attributes; if you specify both, the war attribute overrides the docBase attribute in the context configuration file.

    NOTE - Commands executed through the Manager application are NOT reflected in updates to the Tomcat server.xml configuration file, so they do not persist past the next time you restart the entire Tomcat container.

    tomcat7-7.0.52/java/org/apache/catalina/ant/JMXQueryTask.java0000644000175100017510000000507612271471332023616 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the JMX Query command * (/jmxproxy/?qry) supported by the Tomcat manager application. * * @author Vivek Chopra */ public class JMXQueryTask extends AbstractCatalinaTask { // Properties /** * The JMX query string * @see #setQuery(String) */ protected String query = null; // Public Methods /** * Get method for the JMX query string * @return Query string */ public String getQuery () { return this.query; } /** * Set method for the JMX query string. *

    Examples of query format: *

      *
    • *:*
    • *
    • *:type=RequestProcessor,*
    • *
    • *:j2eeType=Servlet,*
    • *
    • Catalina:type=Environment,resourcetype=Global,name=simpleValue
    • *
    *

    * @param query JMX Query string */ public void setQuery (String query) { this.query = query; } /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); String queryString; if (query == null) { queryString = ""; } else { try { queryString = "?qry=" + URLEncoder.encode(query, getCharset()); } catch (UnsupportedEncodingException e) { throw new BuildException ("Invalid 'charset' attribute: " + getCharset()); } } log("Query string is " + queryString); execute ("/jmxproxy/" + queryString); } } tomcat7-7.0.52/java/org/apache/catalina/ant/ListTask.java0000644000175100017510000000275112271471332023042 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /list command, supported by the * Tomcat manager application. * * @author Craig R. McClanahan * @since 4.1 */ public class ListTask extends AbstractCatalinaTask { // ------------------------------------------------------------- Properties // --------------------------------------------------------- Public Methods /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute("/list"); } } tomcat7-7.0.52/java/org/apache/catalina/ant/ServerinfoTask.java0000644000175100017510000000252612271471332024251 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /serverinfo command * supported by the Tomcat manager application. * * @author Vivek Chopra */ public class ServerinfoTask extends AbstractCatalinaTask { // Public Methods /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute("/serverinfo"); } } tomcat7-7.0.52/java/org/apache/catalina/ant/AbstractCatalinaTask.java0000644000175100017510000002206712271471332025331 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.codec.binary.Base64; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * Abstract base class for Ant tasks that interact with the * Manager web application for dynamically deploying and * undeploying applications. These tasks require Ant 1.4 or later. * * @author Craig R. McClanahan * @since 4.1 */ public abstract class AbstractCatalinaTask extends BaseRedirectorHelperTask { // ----------------------------------------------------- Instance Variables /** * manager webapp's encoding. */ private static String CHARSET = "utf-8"; // ------------------------------------------------------------- Properties /** * The charset used during URL encoding. */ protected String charset = "ISO-8859-1"; public String getCharset() { return (this.charset); } public void setCharset(String charset) { this.charset = charset; } /** * The login password for the Manager application. */ protected String password = null; public String getPassword() { return (this.password); } public void setPassword(String password) { this.password = password; } /** * The URL of the Manager application to be used. */ protected String url = "http://localhost:8080/manager/text"; public String getUrl() { return (this.url); } public void setUrl(String url) { this.url = url; } /** * The login username for the Manager application. */ protected String username = null; public String getUsername() { return (this.username); } public void setUsername(String username) { this.username = username; } // --------------------------------------------------------- Public Methods /** * Execute the specified command. This logic only performs the common * attribute validation required by all subclasses; it does not perform * any functional logic directly. * * @exception BuildException if a validation error occurs */ @Override public void execute() throws BuildException { if ((username == null) || (password == null) || (url == null)) { throw new BuildException ("Must specify all of 'username', 'password', and 'url'"); } } // ------------------------------------------------------ Protected Methods /** * Execute the specified command, based on the configured properties. * * @param command Command to be executed * * @exception BuildException if an error occurs */ public void execute(String command) throws BuildException { execute(command, null, null, -1); } /** * Execute the specified command, based on the configured properties. * The input stream will be closed upon completion of this task, whether * it was executed successfully or not. * * @param command Command to be executed * @param istream InputStream to include in an HTTP PUT, if any * @param contentType Content type to specify for the input, if any * @param contentLength Content length to specify for the input, if any * * @exception BuildException if an error occurs */ public void execute(String command, InputStream istream, String contentType, int contentLength) throws BuildException { URLConnection conn = null; InputStreamReader reader = null; try { // Create a connection for this command conn = (new URL(url + command)).openConnection(); HttpURLConnection hconn = (HttpURLConnection) conn; // Set up standard connection characteristics hconn.setAllowUserInteraction(false); hconn.setDoInput(true); hconn.setUseCaches(false); if (istream != null) { hconn.setDoOutput(true); hconn.setRequestMethod("PUT"); if (contentType != null) { hconn.setRequestProperty("Content-Type", contentType); } if (contentLength >= 0) { hconn.setRequestProperty("Content-Length", "" + contentLength); hconn.setFixedLengthStreamingMode(contentLength); } } else { hconn.setDoOutput(false); hconn.setRequestMethod("GET"); } hconn.setRequestProperty("User-Agent", "Catalina-Ant-Task/1.0"); // Set up an authorization header with our credentials String input = username + ":" + password; String output = Base64.encodeBase64String( input.getBytes(B2CConverter.ISO_8859_1)); hconn.setRequestProperty("Authorization", "Basic " + output); // Establish the connection with the server hconn.connect(); // Send the request data (if any) if (istream != null) { BufferedOutputStream ostream = new BufferedOutputStream(hconn.getOutputStream(), 1024); byte buffer[] = new byte[1024]; while (true) { int n = istream.read(buffer); if (n < 0) { break; } ostream.write(buffer, 0, n); } ostream.flush(); ostream.close(); istream.close(); } // Process the response message reader = new InputStreamReader(hconn.getInputStream(), CHARSET); StringBuilder buff = new StringBuilder(); String error = null; int msgPriority = Project.MSG_INFO; boolean first = true; while (true) { int ch = reader.read(); if (ch < 0) { break; } else if ((ch == '\r') || (ch == '\n')) { // in Win \r\n would cause handleOutput() to be called // twice, the second time with an empty string, // producing blank lines if (buff.length() > 0) { String line = buff.toString(); buff.setLength(0); if (first) { if (!line.startsWith("OK -")) { error = line; msgPriority = Project.MSG_ERR; } first = false; } handleOutput(line, msgPriority); } } else { buff.append((char) ch); } } if (buff.length() > 0) { handleOutput(buff.toString(), msgPriority); } if (error != null && isFailOnError()) { // exception should be thrown only if failOnError == true // or error line will be logged twice throw new BuildException(error); } } catch (Exception e) { if (isFailOnError()) { throw new BuildException(e); } else { handleErrorOutput(e.getMessage()); } } finally { closeRedirector(); if (reader != null) { try { reader.close(); } catch (IOException ioe) { // Ignore } reader = null; } if (istream != null) { try { istream.close(); } catch (IOException ioe) { // Ignore } } } } } tomcat7-7.0.52/java/org/apache/catalina/ant/antlib.xml0000644000175100017510000000504512271471332022433 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/ant/DeployTask.java0000644000175100017510000001302612271471332023360 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /deploy command, supported by * the Tomcat manager application. * * @author Craig R. McClanahan * @since 4.1 */ public class DeployTask extends AbstractCatalinaCommandTask { // ------------------------------------------------------------- Properties /** * URL of the context configuration file for this application, if any. */ protected String config = null; public String getConfig() { return (this.config); } public void setConfig(String config) { this.config = config; } /** * URL of the server local web application archive (WAR) file * to be deployed. */ protected String localWar = null; public String getLocalWar() { return (this.localWar); } public void setLocalWar(String localWar) { this.localWar = localWar; } /** * Tag to associate with this to be deployed webapp. */ protected String tag = null; public String getTag() { return (this.tag); } public void setTag(String tag) { this.tag = tag; } /** * Update existing webapps. */ protected boolean update = false; public boolean getUpdate() { return (this.update); } public void setUpdate(boolean update) { this.update = update; } /** * URL of the web application archive (WAR) file to be deployed. */ protected String war = null; public String getWar() { return (this.war); } public void setWar(String war) { this.war = war; } // --------------------------------------------------------- Public Methods /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); if (path == null) { throw new BuildException ("Must specify 'path' attribute"); } if ((war == null) && (localWar == null) && (config == null) && (tag == null)) { throw new BuildException ("Must specify either 'war', 'localWar', 'config', or 'tag' attribute"); } // Building an input stream on the WAR to upload, if any BufferedInputStream stream = null; String contentType = null; int contentLength = -1; if (war != null) { if (war.startsWith("file:")) { try { URL url = new URL(war); URLConnection conn = url.openConnection(); contentLength = conn.getContentLength(); stream = new BufferedInputStream (conn.getInputStream(), 1024); } catch (IOException e) { throw new BuildException(e); } } else { try { FileInputStream fsInput = new FileInputStream(war); long size = fsInput.getChannel().size(); if (size > Integer.MAX_VALUE) throw new UnsupportedOperationException( "DeployTask does not support WAR files " + "greater than 2 Gb"); contentLength = (int) size; stream = new BufferedInputStream(fsInput, 1024); } catch (IOException e) { throw new BuildException(e); } } contentType = "application/octet-stream"; } // Building URL StringBuilder sb = createQueryString("/deploy"); try { if ((war == null) && (config != null)) { sb.append("&config="); sb.append(URLEncoder.encode(config, getCharset())); } if ((war == null) && (localWar != null)) { sb.append("&war="); sb.append(URLEncoder.encode(localWar, getCharset())); } if (update) { sb.append("&update=true"); } if (tag != null) { sb.append("&tag="); sb.append(URLEncoder.encode(tag, getCharset())); } } catch (UnsupportedEncodingException e) { throw new BuildException("Invalid 'charset' attribute: " + getCharset()); } execute(sb.toString(), stream, contentType, contentLength); } } tomcat7-7.0.52/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java0000644000175100017510000002617012271471332026165 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Redirector; import org.apache.tools.ant.types.RedirectorElement; /** * Abstract base class to add output redirection support for Catalina * Ant tasks. These tasks require Ant 1.5 or later. *
    * WARNING: due to depends chain, Ant could call a Task * more than once and this can affect the output redirection when configured. * If you are collecting the output in a property, it will collect the output * of only the first run, since Ant properties are immutable and once created * they cannot be changed. *
    * If you are collecting output in a file the file will be overwritten with the * output of the last run, unless you set append="true", in which case each run * will append it's output to the file. * * * @author Gabriele Garuglieri * @since 5.5 */ public abstract class BaseRedirectorHelperTask extends Task { // ------------------------------------------------------------- Properties /** Redirector helper */ protected Redirector redirector = new Redirector(this); //protected Redirector redirector = null; /** Redirector element for this task */ protected RedirectorElement redirectorElement = null; /** The stream for info output */ protected OutputStream redirectOutStream = null; /** The stream for error output */ protected OutputStream redirectErrStream = null; /** The print stream for info output */ PrintStream redirectOutPrintStream = null; /** The print stream for error output */ PrintStream redirectErrPrintStream = null; /** * Whether to fail (with a BuildException) if * ManagerServlet returns an error. The default behavior is * to do so. * * This flag does not control parameters checking. If the task is called * with wrong or invalid parameters, it will throw BuildException * independently from the setting of this flag. */ protected boolean failOnError = true; /** * true true when output redirection is requested for this task . * Default is to log on Ant log. */ protected boolean redirectOutput = false; /** * will be set to true when the configuration of the Redirector is * complete. */ protected boolean redirectorConfigured = false; /** * Flag which indicates that, if redirected, output should also be * always sent to the log. Default is that output is sent only to * redirected streams. */ protected boolean alwaysLog = false; /** * Whether to fail (with a BuildException) if * ManagerServlet returns an error. The default behavior is * to do so. */ public void setFailonerror(boolean fail) { failOnError = fail; } /** * Returns the value of the failOnError * property. */ public boolean isFailOnError() { return failOnError; } /** * File the output of the task is redirected to. * * @param out name of the output file */ public void setOutput(File out) { redirector.setOutput(out); redirectOutput = true; } /** * File the error output of the task is redirected to. * * @param error name of the error file * */ public void setError(File error) { redirector.setError(error); redirectOutput = true; } /** * Controls whether error output is logged. This is only useful * when output is being redirected and error output is desired in the * Ant log * * @param logError if true the standard error is sent to the Ant log system * and not sent to output stream. */ public void setLogError(boolean logError) { redirector.setLogError(logError); redirectOutput = true; } /** * Property name whose value should be set to the output of * the task. * * @param outputProperty property name * */ public void setOutputproperty(String outputProperty) { redirector.setOutputProperty(outputProperty); redirectOutput = true; } /** * Property name whose value should be set to the error of * the task.. * * @param errorProperty property name * */ public void setErrorProperty(String errorProperty) { redirector.setErrorProperty(errorProperty); redirectOutput = true; } /** * If true, append output to existing file. * * @param append if true, append output to existing file * */ public void setAppend(boolean append) { redirector.setAppend(append); redirectOutput = true; } /** * If true, (error and non-error) output will be redirected * as specified while being sent to Ant's logging mechanism as if no * redirection had taken place. Defaults to false. *
    * Actually handled internally, with Ant 1.6.3 it will be handled by * the Redirector itself. * @param alwaysLog boolean */ public void setAlwaysLog(boolean alwaysLog) { this.alwaysLog = alwaysLog; //redirector.setAlwaysLog(alwaysLog); redirectOutput = true; } /** * Whether output and error files should be created even when empty. * Defaults to true. * @param createEmptyFiles boolean. */ public void setCreateEmptyFiles(boolean createEmptyFiles) { redirector.setCreateEmptyFiles(createEmptyFiles); redirectOutput = true; } /** * Add a RedirectorElement to this task. * @param redirectorElement RedirectorElement. */ public void addConfiguredRedirector(RedirectorElement redirectorElement) { if (this.redirectorElement != null) { throw new BuildException("Cannot have > 1 nested s"); } else { this.redirectorElement = redirectorElement; } } /** * Set up properties on the Redirector from RedirectorElement if present. */ private void configureRedirector() { if (redirectorElement != null) { redirectorElement.configure(redirector); redirectOutput = true; } /* * Due to depends chain, Ant could call the Task more than once, * this is to prevent that we attempt to configure uselessly * more than once the Redirector. */ redirectorConfigured = true; } /** * Set up properties on the Redirector and create output streams. */ protected void openRedirector() { if (! redirectorConfigured) { configureRedirector(); } if (redirectOutput) { redirector.createStreams(); redirectOutStream = redirector.getOutputStream(); redirectOutPrintStream = new PrintStream(redirectOutStream); redirectErrStream = redirector.getErrorStream(); redirectErrPrintStream = new PrintStream(redirectErrStream); } } /** * Ask redirector to close all the streams. It is necessary to call this method * before leaving the Task to have the Streams flush their contents. If you are * collecting output in a property, it will be created only if this method is * called, otherwise you'll find it unset. */ protected void closeRedirector() { try { if (redirectOutput && redirectOutPrintStream != null) { redirector.complete(); } } catch (IOException ioe) { log("Error closing redirector: " + ioe.getMessage(), Project.MSG_ERR); } /* * Due to depends chain, Ant could call the Task more than once, * this is to prevent that we attempt to reuse the previously * closed Streams. */ redirectOutStream = null; redirectOutPrintStream = null; redirectErrStream = null; redirectErrPrintStream = null; } /** * Handles output with the INFO priority. * * @param output The output to log. Should not be null. */ @Override protected void handleOutput(String output) { if (redirectOutput) { if (redirectOutPrintStream == null) { openRedirector(); } redirectOutPrintStream.println(output); if (alwaysLog) { log(output, Project.MSG_INFO); } } else { log(output, Project.MSG_INFO); } } /** * Handles output with the INFO priority and flushes the stream. * * @param output The output to log. Should not be null. * */ @Override protected void handleFlush(String output) { handleOutput(output); redirectOutPrintStream.flush(); } /** * Handles error output with the ERR priority. * * @param output The error output to log. Should not be null. */ @Override protected void handleErrorOutput(String output) { if (redirectOutput) { if (redirectErrPrintStream == null) { openRedirector(); } redirectErrPrintStream.println(output); if (alwaysLog) { log(output, Project.MSG_ERR); } } else { log(output, Project.MSG_ERR); } } /** * Handles error output with the ERR priority and flushes the stream. * * @param output The error output to log. Should not be null. * */ @Override protected void handleErrorFlush(String output) { handleErrorOutput(output); redirectErrPrintStream.flush(); } /** * Handles output with ERR priority to error stream and all other * priorities to output stream. * * @param output The output to log. Should not be null. */ protected void handleOutput(String output, int priority) { if (priority == Project.MSG_ERR) { handleErrorOutput(output); } else { handleOutput(output); } } } tomcat7-7.0.52/java/org/apache/catalina/ant/catalina.tasks0000644000175100017510000000301512271471332023256 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # Pure catalina tasks deploy=org.apache.catalina.ant.DeployTask list=org.apache.catalina.ant.ListTask reload=org.apache.catalina.ant.ReloadTask sessions=org.apache.catalina.ant.SessionsTask resources=org.apache.catalina.ant.ResourcesTask start=org.apache.catalina.ant.StartTask stop=org.apache.catalina.ant.StopTask undeploy=org.apache.catalina.ant.UndeployTask validator=org.apache.catalina.ant.ValidatorTask #Jk Task jkstatus=org.apache.catalina.ant.JKStatusUpdateTask jkupdate=org.apache.catalina.ant.JKStatusUpdateTask # Manager JMX jmxManagerSet=org.apache.catalina.ant.JMXSetTask jmxManagerGet=org.apache.catalina.ant.JMXGetTask jmxManagerQuery=org.apache.catalina.ant.JMXQueryTask # Jasper tasks jasper=org.apache.jasper.JspC jasper2=org.apache.jasper.JspC tomcat7-7.0.52/java/org/apache/catalina/ant/StartTask.java0000644000175100017510000000255412271471332023225 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /start command, supported by the * Tomcat manager application. * * @author Craig R. McClanahan * @since 4.1 */ public class StartTask extends AbstractCatalinaCommandTask { /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute(createQueryString("/start").toString()); } } tomcat7-7.0.52/java/org/apache/catalina/ant/StopTask.java0000644000175100017510000000255512271471332023056 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /stop command, supported by the * Tomcat manager application. * * @author Craig R. McClanahan * @since 4.1 */ public class StopTask extends AbstractCatalinaCommandTask { /** * Execute the requested operation. * * @exception BuildException if an error occurs */ @Override public void execute() throws BuildException { super.execute(); execute(createQueryString("/stop").toString()); } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/0000755000175100017510000000000012301126370021223 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java0000644000175100017510000001567412271471332026104 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import java.util.Iterator; import java.util.Set; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.apache.tools.ant.BuildException; /** * Query for Mbeans. *
      *
    • open no existing JSR 160 rmi jmx connection
    • *
    • Get all Mbeans attributes
    • *
    • Get only the Query Mbeans ObjectNames
    • *
    • Show query result as Ant console log
    • *
    • Bind query result as Ant properties
    • *
    *
    * Query a list of Mbeans. *
     *   <jmxQuery
     *           host="127.0.0.1"
     *           port="9014"
     *           name="Catalina:type=Manager,* 
     *           resultproperty="manager" />
     * 
    * with attribute attributebinding="true" you can get * all attributes also from result objects.
    * The property manager.lenght show the size of the result * and with manager.[0..length].name the * resulted ObjectNames are saved. * These tasks require Ant 1.6 or later interface. * * @author Peter Rossbach * @since 5.5.10 */ public class JMXAccessorQueryTask extends JMXAccessorTask { // ----------------------------------------------------- Instance Variables private boolean attributebinding = false; // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorQueryTask/1.0"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } // ------------------------------------------------------------- Properties /** * @return Returns the attributebinding. */ public boolean isAttributebinding() { return attributebinding; } /** * @param attributeBinding The attributebinding to set. */ public void setAttributebinding(boolean attributeBinding) { this.attributebinding = attributeBinding; } // ------------------------------------------------------ protected Methods /** * Execute the specified command, based on the configured properties. The * input stream will be closed upon completion of this task, whether it was * executed successfully or not. * * @exception Exception * if an error occurs */ @Override public String jmxExecute(MBeanServerConnection jmxServerConnection) throws Exception { if (getName() == null) { throw new BuildException("Must specify a 'name'"); } return jmxQuery(jmxServerConnection, getName()); } /** * Call Mbean server for some mbeans with same domain, attributes. * with attributebinding=true you can save all attributes from all found objects * as your ant properties * @param jmxServerConnection * @param qry * @return The query result */ protected String jmxQuery(MBeanServerConnection jmxServerConnection, String qry) { String isError = null; Set names = null; String resultproperty = getResultproperty(); try { names = jmxServerConnection.queryNames(new ObjectName(qry), null); if (resultproperty != null) { setProperty(resultproperty + ".Length",Integer.toString(names.size())); } } catch (Exception e) { if (isEcho()) handleErrorOutput(e.getMessage()); return "Can't query mbeans " + qry; } if (resultproperty != null) { Iterator it = names.iterator(); int oindex = 0; String pname = null; while (it.hasNext()) { ObjectName oname = it.next(); pname = resultproperty + "." + Integer.toString(oindex) + "."; oindex++; setProperty(pname + "Name", oname.toString()); if (isAttributebinding()) { bindAttributes(jmxServerConnection, resultproperty, pname, oname); } } } return isError; } /** * @param jmxServerConnection * @param resultproperty * @param pname * @param oname */ protected void bindAttributes(MBeanServerConnection jmxServerConnection, String resultproperty, String pname, ObjectName oname) { if (jmxServerConnection != null && resultproperty != null && pname != null && oname != null ) { try { MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname); MBeanAttributeInfo attrs[] = minfo.getAttributes(); Object value = null; for (int i = 0; i < attrs.length; i++) { if (!attrs[i].isReadable()) continue; String attName = attrs[i].getName(); if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 || attName.indexOf(" ") >= 0) { continue; } try { value = jmxServerConnection .getAttribute(oname, attName); } catch (Exception e) { if (isEcho()) handleErrorOutput("Error getting attribute " + oname + " " + pname + attName + " " + e.toString()); continue; } if (value == null) continue; if ("modelerType".equals(attName)) continue; createProperty(pname + attName, value); } } catch (Exception e) { // Ignore } } } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/Arg.java0000644000175100017510000000274712271471332022620 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; /** * * @author Peter Rossbach * @since 5.5.10 */ public class Arg { /** * @deprecated Use getter/setter */ @Deprecated String type; /** * @deprecated Use getter/setter */ @Deprecated String value; public void setType( String type) { this.type=type; } public void setValue( String value ) { this.value=value; } /** * @deprecated Use {@link #setValue(String)} */ @Deprecated public void addText( String text ) { this.value=text; } public String getValue() { return value; } public String getType() { return type; } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java0000644000175100017510000001551112271471332027243 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import java.io.IOException; import java.net.MalformedURLException; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.taskdefs.condition.Condition; /** * * Definition *
     
     *   <path id="catalina_ant">
     *       <fileset dir="${catalina.home}/server/lib">
     *           <include name="catalina-ant.jar"/>
     *       </fileset>
     *   </path>
     *
     *   <typedef
     *       name="jmxEquals"
     *       classname="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition"
     *       classpathref="catalina_ant"/>
     * 
    * * usage: Wait for start backup node *
     *     <target name="wait">
     *        <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
     *           <and>
     *               <socket server="${server.name}" port="${server.port}"/>
     *               <http url="${url}"/>
     *               <jmxEquals 
     *                   host="localhost" port="9014" username="controlRole" password="tomcat"
     *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
     *                   attribute="connected" value="true"
     *               />
     *           </and>
     *       </waitfor>
     *       <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
     *       <echo message="Server ${url} alive" />
     *   </target>
     *
     * 
    * * @author Peter Rossbach * @since 5.5.10 */ public class JMXAccessorEqualsCondition extends ProjectComponent implements Condition { // ----------------------------------------------------- Instance Variables private String url = null; private String host = "localhost"; private String port = "8050"; private String password = null; private String username = null; private String name = null; private String attribute; private String value; private String ref = "jmx.server" ; // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorEqualsCondition/1.1"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } // ----------------------------------------------------- Properties /** * @return Returns the attribute. */ public String getAttribute() { return attribute; } /** * @param attribute The attribute to set. */ public void setAttribute(String attribute) { this.attribute = attribute; } /** * @return Returns the host. */ public String getHost() { return host; } /** * @param host The host to set. */ public void setHost(String host) { this.host = host; } /** * @return Returns the name. */ public String getName() { return name; } /** * @param objectName The name to set. */ public void setName(String objectName) { this.name = objectName; } /** * @return Returns the password. */ public String getPassword() { return password; } /** * @param password The password to set. */ public void setPassword(String password) { this.password = password; } /** * @return Returns the port. */ public String getPort() { return port; } /** * @param port The port to set. */ public void setPort(String port) { this.port = port; } /** * @return Returns the url. */ public String getUrl() { return url; } /** * @param url The url to set. */ public void setUrl(String url) { this.url = url; } /** * @return Returns the username. */ public String getUsername() { return username; } /** * @param username The username to set. */ public void setUsername(String username) { this.username = username; } /** * @return Returns the value. */ public String getValue() { return value; } // The setter for the "value" attribute public void setValue(String value) { this.value = value; } /** * @return Returns the ref. */ public String getRef() { return ref; } /** * @param refId The ref to set. */ public void setRef(String refId) { this.ref = refId; } protected MBeanServerConnection getJMXConnection() throws MalformedURLException, IOException { return JMXAccessorTask.accessJMXConnection( getProject(), getUrl(), getHost(), getPort(), getUsername(), getPassword(), ref); } /** * @return The value */ protected String accessJMXValue() { try { Object result = getJMXConnection().getAttribute( new ObjectName(name), attribute); if(result != null) return result.toString(); } catch (Exception e) { // ignore access or connection open errors } return null; } // This method evaluates the condition @Override public boolean eval() { if (value == null) { throw new BuildException("value attribute is not set"); } if ((name == null || attribute == null)) { throw new BuildException( "Must specify a 'attribute', name for equals condition"); } //FIXME check url or host/parameter String jmxValue = accessJMXValue(); if(jmxValue != null) return jmxValue.equals(value); return false; } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/package.html0000644000175100017510000000446112271471332023520 0ustar locutuslocutus

    This package contains a set of JMX Task implementations for Ant (version 1.6 or later) that can be used to interact with the Remote JMX JSR 160 RMI Adaptor to get/set attributes, invoke MBean operations and query for Mbeans inside a running instance of Tomcat. For more information, see http://tomcat.apache.org/tomcat-7.0-doc/monitoring.html.

    Each task element can open a new jmx connection or reference an existing one. The following attribute are exists in every tasks:

    Attribute Description
    url The JMX Connection URL of the remote Tomcat MBeansServer.
    username The username of a MBeanServer auth, when configured.
    password The password of a MBeanServer auth, when configured.
    host The JMX Connection host.
    port The JMX Connection port.
    ref The name of the ant internal reference for a jmx connection.

    NOTE - This Tasks only work, when JSR 160 MBean Adaptor as remote jvm is configured.

    tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java0000644000175100017510000002760612271471332026100 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import java.io.IOException; import java.net.MalformedURLException; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.taskdefs.condition.Condition; /** * * Definition: *
     
     *   <path id="catalina_ant">
     *       <fileset dir="${catalina.home}/server/lib">
     *           <include name="catalina-ant.jar"/>
     *       </fileset>
     *   </path>
     *
     *   <typedef
     *       name="jmxCondition"
     *       classname="org.apache.catalina.ant.jmx.JMXAccessorCondition"
     *       classpathref="catalina_ant"/>
     *   <taskdef
     *       name="jmxOpen"
     *       classname="org.apache.catalina.ant.jmx.JMXAccessorTask"
     *       classpathref="catalina_ant"/>
     * 
    * * Usage: Wait for start backup node *
     *     <target name="wait">
     *       <jmxOpen
     *               host="${jmx.host}" port="${jmx.port}" username="${jmx.username}" password="${jmx.password}" />
     *        <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
     *           <and>
     *               <socket server="${server.name}" port="${server.port}"/>
     *               <http url="${url}"/>
     *               <jmxCondition
     *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
     *                   operation="==" 
     *                   attribute="connected" value="true"
     *               />
     *               <jmxCondition
     *                   operation="&lt;"
     *                   name="Catalina:j2eeType=WebModule,name=//${tomcat.application.host}${tomcat.application.path},J2EEApplication=none,J2EEServer=none"
     *                   attribute="startupTime" value="250"
     *               />
     *           </and>
     *       </waitfor>
     *       <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
     *       <echo message="Server ${url} alive" />
     *   </target>
     *
     * 
    * Allowed operation between jmx attribute and reference value: *
      *
    • == equals
    • *
    • != not equals
    • *
    • > greater than (&gt;)
    • *
    • >= greater than or equals (&gt;=)
    • *
    • < lesser than (&lt;)
    • *
    • <= lesser than or equals (&lt;=)
    • *
    * NOTE: For numeric expressions the type must be set and use xml entities as operations.
    * As type we currently support long and double. * @author Peter Rossbach * @since 5.5.10 */ public class JMXAccessorCondition extends ProjectComponent implements Condition { // ----------------------------------------------------- Instance Variables private String url = null; private String host = "localhost"; private String port = "8050"; private String password = null; private String username = null; private String name = null; private String attribute; private String value; private String operation = "==" ; private String type = "long" ; private String ref = "jmx.server"; private String unlessCondition; private String ifCondition; // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorCondition/1.1"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } // ----------------------------------------------------- Properties /** * @return Returns the operation. */ public String getOperation() { return operation; } /** * @param operation The operation to set. */ public void setOperation(String operation) { this.operation = operation; } /** * @return Returns the type. */ public String getType() { return type; } /** * @param type The type to set. */ public void setType(String type) { this.type = type; } /** * @return Returns the attribute. */ public String getAttribute() { return attribute; } /** * @param attribute The attribute to set. */ public void setAttribute(String attribute) { this.attribute = attribute; } /** * @return Returns the host. */ public String getHost() { return host; } /** * @param host The host to set. */ public void setHost(String host) { this.host = host; } /** * @return Returns the name. */ public String getName() { return name; } /** * @param objectName The name to set. */ public void setName(String objectName) { this.name = objectName; } /** * @return Returns the password. */ public String getPassword() { return password; } /** * @param password The password to set. */ public void setPassword(String password) { this.password = password; } /** * @return Returns the port. */ public String getPort() { return port; } /** * @param port The port to set. */ public void setPort(String port) { this.port = port; } /** * @return Returns the url. */ public String getUrl() { return url; } /** * @param url The url to set. */ public void setUrl(String url) { this.url = url; } /** * @return Returns the username. */ public String getUsername() { return username; } /** * @param username The username to set. */ public void setUsername(String username) { this.username = username; } /** * @return Returns the value. */ public String getValue() { return value; } // The setter for the "value" attribute public void setValue(String value) { this.value = value; } /** * @return Returns the ref. */ public String getRef() { return ref; } /** * @param refId The ref to set. */ public void setRef(String refId) { this.ref = refId; } /** * @return Returns the ifCondition. */ public String getIf() { return ifCondition; } /** * Only execute if a property of the given name exists in the current project. * @param c property name */ public void setIf(String c) { ifCondition = c; } /** * @return Returns the unlessCondition. */ public String getUnless() { return unlessCondition; } /** * Only execute if a property of the given name does not * exist in the current project. * @param c property name */ public void setUnless(String c) { unlessCondition = c; } /** * Get JMXConnection (default look at jmx.server project reference from jmxOpen Task) * @return active JMXConnection * @throws MalformedURLException * @throws IOException */ protected MBeanServerConnection getJMXConnection() throws MalformedURLException, IOException { return JMXAccessorTask.accessJMXConnection( getProject(), getUrl(), getHost(), getPort(), getUsername(), getPassword(), ref); } /** * Get value from MBeans attribute * @return The value */ protected String accessJMXValue() { try { Object result = getJMXConnection().getAttribute( new ObjectName(name), attribute); if(result != null) return result.toString(); } catch (Exception e) { // ignore access or connection open errors } return null; } /** * test the if condition * @return true if there is no if condition, or the named property exists */ protected boolean testIfCondition() { if (ifCondition == null || "".equals(ifCondition)) { return true; } return getProject().getProperty(ifCondition) != null; } /** * test the unless condition * @return true if there is no unless condition, * or there is a named property but it doesn't exist */ protected boolean testUnlessCondition() { if (unlessCondition == null || "".equals(unlessCondition)) { return true; } return getProject().getProperty(unlessCondition) == null; } /** * This method evaluates the condition * It support for operation ">,>=,<,<=" the types long and double. * @return expression jmxValue operation value */ @Override public boolean eval() { if (operation == null) { throw new BuildException("operation attribute is not set"); } if (value == null) { throw new BuildException("value attribute is not set"); } if ((name == null || attribute == null)) { throw new BuildException( "Must specify a 'attribute', name for equals condition"); } if (testIfCondition() && testUnlessCondition()) { String jmxValue = accessJMXValue(); if (jmxValue != null) { String op = getOperation(); if ("==".equals(op)) { return jmxValue.equals(value); } else if ("!=".equals(op)) { return !jmxValue.equals(value); } else { if ("long".equals(type)) { long jvalue = Long.parseLong(jmxValue); long lvalue = Long.parseLong(value); if (">".equals(op)) { return jvalue > lvalue; } else if (">=".equals(op)) { return jvalue >= lvalue; } else if ("<".equals(op)) { return jvalue < lvalue; } else if ("<=".equals(op)) { return jvalue <= lvalue; } } else if ("double".equals(type)) { double jvalue = Double.parseDouble(jmxValue); double dvalue = Double.parseDouble(value); if (">".equals(op)) { return jvalue > dvalue; } else if (">=".equals(op)) { return jvalue >= dvalue; } else if ("<".equals(op)) { return jvalue < dvalue; } else if ("<=".equals(op)) { return jvalue <= dvalue; } } } } return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/antlib.xml0000644000175100017510000000340012271471332023222 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java0000644000175100017510000001051012271471332025476 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.apache.tools.ant.BuildException; /** * Access JMX JSR 160 MBeans Server. *
      *
    • Get Mbeans attributes
    • *
    • Show Get result as Ant console log
    • *
    • Bind Get result as Ant properties
    • *
    *

    * Examples: *
    * Get a Mbean IDataSender attribute nrOfRequests and create a new ant property IDataSender.9025.nrOfRequests *

     *   <jmx:get
     *           ref="jmx.server"
     *           name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.1.2,senderPort=9025" 
     *           attribute="nrOfRequests"
     *           resultproperty="IDataSender.9025.nrOfRequests"
     *           echo="false">
     *       />
     * 
    *

    *

    * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server *

    * These tasks require Ant 1.6 or later interface. * * @author Peter Rossbach * @since 5.5.10 */ public class JMXAccessorGetTask extends JMXAccessorTask { // ----------------------------------------------------- Instance Variables private String attribute; // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorGetTask/1.0"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } // ------------------------------------------------------------- Properties /** * @return Returns the attribute. */ public String getAttribute() { return attribute; } /** * @param attribute The attribute to set. */ public void setAttribute(String attribute) { this.attribute = attribute; } // ------------------------------------------------------ protected Methods /** * Execute the specified command, based on the configured properties. The * input stream will be closed upon completion of this task, whether it was * executed successfully or not. * * @exception BuildException * if an error occurs */ @Override public String jmxExecute(MBeanServerConnection jmxServerConnection) throws Exception { if (getName() == null) { throw new BuildException("Must specify a 'name'"); } if ((attribute == null)) { throw new BuildException( "Must specify a 'attribute' for get"); } return jmxGet(jmxServerConnection, getName()); } /** * @param jmxServerConnection * @param name * @return The value of the given named attribute * @throws Exception */ protected String jmxGet(MBeanServerConnection jmxServerConnection,String name) throws Exception { String error = null; if(isEcho()) { handleOutput("MBean " + name + " get attribute " + attribute ); } Object result = jmxServerConnection.getAttribute( new ObjectName(name), attribute); if (result != null) { echoResult(attribute,result); createProperty(result); } else error = "Attribute " + attribute + " is empty"; return error; } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/jmxaccessor.tasks0000644000175100017510000000245112271471332024624 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # JMX jmxOpen=org.apache.catalina.ant.jmx.JMXAccessorTask jmxSet=org.apache.catalina.ant.jmx.JMXAccessorSetTask jmxGet=org.apache.catalina.ant.jmx.JMXAccessorGetTask jmxInvoke=org.apache.catalina.ant.jmx.JMXAccessorInvokeTask jmxQuery=org.apache.catalina.ant.jmx.JMXAccessorQueryTask jmxCreate=org.apache.catalina.ant.jmx.JMXAccessorCreateTask jmxUnregister=org.apache.catalina.ant.jmx.JMXAccessorUnregisterTask jmxEquals=org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition jmxCondition=org.apache.catalina.ant.jmx.JMXAccessorCondition tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java0000644000175100017510000005453112271471332025051 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import java.io.IOException; import java.lang.reflect.Array; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import javax.management.MBeanServerConnection; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenType; import javax.management.openmbean.SimpleType; import javax.management.openmbean.TabularDataSupport; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import org.apache.catalina.ant.BaseRedirectorHelperTask; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * Access JMX JSR 160 MBeans Server. *
      *
    • open more then one JSR 160 rmi connection
    • *
    • Get/Set Mbeans attributes
    • *
    • Call Mbean Operation with arguments
    • *
    • Argument values can be converted from string to * int,long,float,double,boolean,ObjectName or InetAddress
    • *
    • Query Mbeans
    • *
    • Show Get, Call, Query result at Ant console log
    • *
    • Bind Get, Call, Query result at Ant properties
    • *
    * * Examples: open server with reference and autorisation * *
     * 
     *    <jmxOpen
     *            host="127.0.0.1"
     *            port="9014"
     *            username="monitorRole"
     *            password="mysecret"
     *            ref="jmx.myserver" 
     *        />
     *  
     * 
    * * All calls after opening with same refid reuse the connection. *

    * First call to a remote MBeanserver save the JMXConnection a referenz * jmx.server *

    * All JMXAccessorXXXTask support the attribute if and * unless. With if the task is only execute when property * exist and with unless when property not exists.
    NOTE * : These tasks require Ant 1.6 or later interface. * * @author Peter Rossbach * @since 5.5.10 */ public class JMXAccessorTask extends BaseRedirectorHelperTask { public static final String JMX_SERVICE_PREFIX = "service:jmx:rmi:///jndi/rmi://"; public static final String JMX_SERVICE_SUFFIX = "/jmxrmi"; // ----------------------------------------------------- Instance Variables private String name = null; private String resultproperty; private String url = null; private String host = "localhost"; private String port = "8050"; private String password = null; private String username = null; private String ref = "jmx.server"; private boolean echo = false; private boolean separatearrayresults = true; private String delimiter; private String unlessCondition; private String ifCondition; private Properties properties = new Properties(); // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorTask/1.1"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } // ------------------------------------------------------------- Properties /** * The name used at remote MbeanServer */ public String getName() { return (this.name); } public void setName(String objectName) { this.name = objectName; } /** * @return Returns the resultproperty. */ public String getResultproperty() { return resultproperty; } /** * @param propertyName The resultproperty to set. */ public void setResultproperty(String propertyName) { this.resultproperty = propertyName; } /** * @return Returns the delimiter. */ public String getDelimiter() { return delimiter; } /** * @param separator The delimiter to set. */ public void setDelimiter(String separator) { this.delimiter = separator; } /** * @return Returns the echo. */ public boolean isEcho() { return echo; } /** * @param echo * The echo to set. */ public void setEcho(boolean echo) { this.echo = echo; } /** * @return Returns the separatearrayresults. */ public boolean isSeparatearrayresults() { return separatearrayresults; } /** * @param separateArrayResults * The separatearrayresults to set. */ public void setSeparatearrayresults(boolean separateArrayResults) { this.separatearrayresults = separateArrayResults; } /** * The login password for the Manager application. */ public String getPassword() { return (this.password); } public void setPassword(String password) { this.password = password; } /** * The login username for the JMX MBeanServer. */ public String getUsername() { return (this.username); } public void setUsername(String username) { this.username = username; } /** * The URL of the JMX JSR 160 MBeanServer to be used. */ public String getUrl() { return (this.url); } public void setUrl(String url) { this.url = url; } /** * The Host of the JMX JSR 160 MBeanServer to be used. */ public String getHost() { return (this.host); } public void setHost(String host) { this.host = host; } /** * The Port of the JMX JSR 160 MBeanServer to be used. */ public String getPort() { return (this.port); } public void setPort(String port) { this.port = port; } /** * @return Returns the useRef. */ public boolean isUseRef() { return ref != null && !"".equals(ref); } /** * @return Returns the ref. */ public String getRef() { return ref; } /** * @param refId The ref to set. */ public void setRef(String refId) { this.ref = refId; } /** * @return Returns the ifCondition. */ public String getIf() { return ifCondition; } /** * Only execute if a property of the given name exists in the current * project. * * @param c property name */ public void setIf(String c) { ifCondition = c; } /** * @return Returns the unlessCondition. */ public String getUnless() { return unlessCondition; } /** * Only execute if a property of the given name does not exist in the * current project. * * @param c property name */ public void setUnless(String c) { unlessCondition = c; } // --------------------------------------------------------- Public Methods /** * Execute the specified command. This logic only performs the common * attribute validation required by all subclasses; it does not perform any * functional logic directly. * * @exception BuildException * if a validation error occurs */ @Override public void execute() throws BuildException { if (testIfCondition() && testUnlessCondition()) { try { String error = null; MBeanServerConnection jmxServerConnection = getJMXConnection(); error = jmxExecute(jmxServerConnection); if (error != null && isFailOnError()) { // exception should be thrown only if failOnError == true // or error line will be logged twice throw new BuildException(error); } } catch (Exception e) { if (isFailOnError()) { throw new BuildException(e); } else { handleErrorOutput(e.getMessage()); } } finally { closeRedirector(); } } } /** * create a new JMX Connection with auth when username and password is set. */ public static MBeanServerConnection createJMXConnection(String url, String host, String port, String username, String password) throws MalformedURLException, IOException { String urlForJMX; if (url != null) urlForJMX = url; else urlForJMX = JMX_SERVICE_PREFIX + host + ":" + port + JMX_SERVICE_SUFFIX; Map environment = null; if (username != null && password != null) { String[] credentials = new String[2]; credentials[0] = username; credentials[1] = password; environment = new HashMap(); environment.put(JMXConnector.CREDENTIALS, credentials); } return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX), environment).getMBeanServerConnection(); } /** * test the if condition * * @return true if there is no if condition, or the named property exists */ protected boolean testIfCondition() { if (ifCondition == null || "".equals(ifCondition)) { return true; } return getProperty(ifCondition) != null; } /** * test the unless condition * * @return true if there is no unless condition, or there is a named * property but it doesn't exist */ protected boolean testUnlessCondition() { if (unlessCondition == null || "".equals(unlessCondition)) { return true; } return getProperty(unlessCondition) == null; } /** * Get Current Connection from ref parameter or create a new one! * * @return The server connection * @throws MalformedURLException * @throws IOException */ @SuppressWarnings("null") public static MBeanServerConnection accessJMXConnection(Project project, String url, String host, String port, String username, String password, String refId) throws MalformedURLException, IOException { MBeanServerConnection jmxServerConnection = null; boolean isRef = project != null && refId != null && refId.length() > 0; if (isRef) { Object pref = project.getReference(refId); try { jmxServerConnection = (MBeanServerConnection) pref; } catch (ClassCastException cce) { project.log("wrong object reference " + refId + " - " + pref.getClass()); return null; } } if (jmxServerConnection == null) { jmxServerConnection = createJMXConnection(url, host, port, username, password); } if (isRef && jmxServerConnection != null) { project.addReference(refId, jmxServerConnection); } return jmxServerConnection; } // ------------------------------------------------------ protected Methods /** * get JMXConnection * * @return The connection * @throws MalformedURLException * @throws IOException */ protected MBeanServerConnection getJMXConnection() throws MalformedURLException, IOException { MBeanServerConnection jmxServerConnection = null; if (isUseRef()) { Object pref = null ; if(getProject() != null) { pref = getProject().getReference(getRef()); if (pref != null) { try { jmxServerConnection = (MBeanServerConnection) pref; } catch (ClassCastException cce) { getProject().log( "Wrong object reference " + getRef() + " - " + pref.getClass()); return null; } } } if (jmxServerConnection == null) { jmxServerConnection = accessJMXConnection(getProject(), getUrl(), getHost(), getPort(), getUsername(), getPassword(), getRef()); } } else { jmxServerConnection = accessJMXConnection(getProject(), getUrl(), getHost(), getPort(), getUsername(), getPassword(), null); } return jmxServerConnection; } /** * Execute the specified command, based on the configured properties. The * input stream will be closed upon completion of this task, whether it was * executed successfully or not. * * @exception Exception * if an error occurs */ public String jmxExecute(MBeanServerConnection jmxServerConnection) throws Exception { if ((jmxServerConnection == null)) { throw new BuildException("Must open a connection!"); } else if (isEcho()) { handleOutput("JMX Connection ref=" + ref + " is open!"); } return null; } /** * Convert string to datatype FIXME How we can transfer values from ant * project reference store (ref)? * * @param value The value * @param valueType The type * @return The converted object */ protected Object convertStringToType(String value, String valueType) { if ("java.lang.String".equals(valueType)) return value; Object convertValue = value; if ("java.lang.Integer".equals(valueType) || "int".equals(valueType)) { try { convertValue = new Integer(value); } catch (NumberFormatException ex) { if (isEcho()) handleErrorOutput("Unable to convert to integer:" + value); } } else if ("java.lang.Long".equals(valueType) || "long".equals(valueType)) { try { convertValue = new Long(value); } catch (NumberFormatException ex) { if (isEcho()) handleErrorOutput("Unable to convert to long:" + value); } } else if ("java.lang.Boolean".equals(valueType) || "boolean".equals(valueType)) { convertValue = Boolean.valueOf(value); } else if ("java.lang.Float".equals(valueType) || "float".equals(valueType)) { try { convertValue = new Float(value); } catch (NumberFormatException ex) { if (isEcho()) handleErrorOutput("Unable to convert to float:" + value); } } else if ("java.lang.Double".equals(valueType) || "double".equals(valueType)) { try { convertValue = new Double(value); } catch (NumberFormatException ex) { if (isEcho()) handleErrorOutput("Unable to convert to double:" + value); } } else if ("javax.management.ObjectName".equals(valueType) || "name".equals(valueType)) { try { convertValue = new ObjectName(value); } catch (MalformedObjectNameException e) { if (isEcho()) handleErrorOutput("Unable to convert to ObjectName:" + value); } } else if ("java.net.InetAddress".equals(valueType)) { try { convertValue = InetAddress.getByName(value); } catch (UnknownHostException exc) { if (isEcho()) handleErrorOutput("Unable to resolve host name:" + value); } } return convertValue; } /** * @param name context of result * @param result */ protected void echoResult(String name, Object result) { if (isEcho()) { if (result.getClass().isArray()) { for (int i = 0; i < Array.getLength(result); i++) { handleOutput(name + "." + i + "=" + Array.get(result, i)); } } else handleOutput(name + "=" + result); } } /** * create result as property with name from attribute resultproperty * * @param result The result * @see #createProperty(String, Object) */ protected void createProperty(Object result) { if (resultproperty != null) { createProperty(resultproperty, result); } } /** * create result as property with name from property prefix When result is * an array and isSeparateArrayResults is true, resultproperty used as * prefix (resultproperty.0-array.length and store the * result array length at resultproperty.length. Other * option is that you delimit your result with a delimiter * (java.util.StringTokenizer is used). * * @param propertyPrefix * @param result */ protected void createProperty(String propertyPrefix, Object result) { if (propertyPrefix == null) propertyPrefix = ""; if (result instanceof CompositeDataSupport) { CompositeDataSupport data = (CompositeDataSupport) result; CompositeType compositeType = data.getCompositeType(); Set keys = compositeType.keySet(); for (Iterator iter = keys.iterator(); iter.hasNext();) { String key = iter.next(); Object value = data.get(key); OpenType type = compositeType.getType(key); if (type instanceof SimpleType) { setProperty(propertyPrefix + "." + key, value); } else { createProperty(propertyPrefix + "." + key, value); } } } else if (result instanceof TabularDataSupport) { TabularDataSupport data = (TabularDataSupport) result; for (Iterator iter = data.keySet().iterator(); iter.hasNext();) { Object key = iter.next(); for (Iterator iter1 = ((List) key).iterator(); iter1.hasNext();) { Object key1 = iter1.next(); CompositeData valuedata = data.get(new Object[] { key1 }); Object value = valuedata.get("value"); OpenType type = valuedata.getCompositeType().getType( "value"); if (type instanceof SimpleType) { setProperty(propertyPrefix + "." + key1, value); } else { createProperty(propertyPrefix + "." + key1, value); } } } } else if (result.getClass().isArray()) { if (isSeparatearrayresults()) { int size = 0; for (int i = 0; i < Array.getLength(result); i++) { if (setProperty(propertyPrefix + "." + size, Array.get( result, i))) { size++; } } if (size > 0) { setProperty(propertyPrefix + ".Length", Integer .toString(size)); } } } else { String delim = getDelimiter(); if (delim != null) { StringTokenizer tokenizer = new StringTokenizer(result .toString(), delim); int size = 0; for (; tokenizer.hasMoreTokens();) { String token = tokenizer.nextToken(); if (setProperty(propertyPrefix + "." + size, token)) { size++; } } if (size > 0) setProperty(propertyPrefix + ".Length", Integer .toString(size)); } else { setProperty(propertyPrefix, result.toString()); } } } /** * Get Property * @param property name * @return The property value */ public String getProperty(String property) { Project currentProject = getProject(); if (currentProject != null) { return currentProject.getProperty(property); } else { return properties.getProperty(property); } } /** * @param property The property * @param value The value * @return True if successful */ public boolean setProperty(String property, Object value) { if (property != null) { if (value == null) value = ""; if (isEcho()) { handleOutput(property + "=" + value.toString()); } Project currentProject = getProject(); if (currentProject != null) { currentProject.setNewProperty(property, value.toString()); } else { properties.setProperty(property, value.toString()); } return true; } return false; } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java0000644000175100017510000001424612271471332025524 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import javax.management.Attribute; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.apache.tools.ant.BuildException; /** * Access JMX JSR 160 MBeans Server. *
      *
    • Get Mbeans attributes
    • *
    • Show Get result as Ant console log
    • *
    • Bind Get result as Ant properties
    • *
    *

    * Examples: * Set a Mbean Manager attribute maxActiveSessions. * Set this attribute with fresh jmx connection without save reference *

     *   <jmx:set
     *           host="127.0.0.1"
     *           port="9014"
     *           ref=""
     *           name="Catalina:type=Manager,context="/ClusterTest",host=localhost" 
     *           attribute="maxActiveSessions"
     *           value="100"
     *           type="int"
     *           echo="false">
     *       />
     * 
    *

    *

    * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server *

    * These tasks require Ant 1.6 or later interface. * * @author Peter Rossbach * @since 5.5.10 */ public class JMXAccessorSetTask extends JMXAccessorTask { // ----------------------------------------------------- Instance Variables private String attribute; private String value; private String type; private boolean convert = false ; // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorSetTask/1.0"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } // ------------------------------------------------------------- Properties /** * @return Returns the attribute. */ public String getAttribute() { return attribute; } /** * @param attribute The attribute to set. */ public void setAttribute(String attribute) { this.attribute = attribute; } /** * @return Returns the value. */ public String getValue() { return value; } /** * @param value The value to set. */ public void setValue(String value) { this.value = value; } /** * @return Returns the type. */ public String getType() { return type; } /** * @param valueType The type to set. */ public void setType(String valueType) { this.type = valueType; } /** * @return Returns the convert. */ public boolean isConvert() { return convert; } /** * @param convert The convert to set. */ public void setConvert(boolean convert) { this.convert = convert; } // ------------------------------------------------------ protected Methods /** * Execute the specified command, based on the configured properties. The * input stream will be closed upon completion of this task, whether it was * executed successfully or not. * * @exception Exception * if an error occurs */ @Override public String jmxExecute(MBeanServerConnection jmxServerConnection) throws Exception { if (getName() == null) { throw new BuildException("Must specify a 'name'"); } if ((attribute == null || value == null)) { throw new BuildException( "Must specify a 'attribute' and 'value' for set"); } return jmxSet(jmxServerConnection, getName()); } /** * @param jmxServerConnection * @param name * @throws Exception */ protected String jmxSet(MBeanServerConnection jmxServerConnection, String name) throws Exception { Object realValue; if (type != null) { realValue = convertStringToType(value, type); } else { if (isConvert()) { String mType = getMBeanAttributeType(jmxServerConnection, name, attribute); realValue = convertStringToType(value, mType); } else realValue = value; } jmxServerConnection.setAttribute(new ObjectName(name), new Attribute( attribute, realValue)); return null; } /** * Get MBean Attribute from Mbean Server * @param jmxServerConnection * @param name * @param attribute * @return The type * @throws Exception */ protected String getMBeanAttributeType( MBeanServerConnection jmxServerConnection, String name, String attribute) throws Exception { ObjectName oname = new ObjectName(name); String mattrType = null; MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname); MBeanAttributeInfo attrs[] = minfo.getAttributes(); if (attrs != null) { for (int i = 0; mattrType == null && i < attrs.length; i++) { if (attribute.equals(attrs[i].getName())) mattrType = attrs[i].getType(); } } return mattrType; } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java0000644000175100017510000000675312271471332027124 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.apache.tools.ant.BuildException; /** * unregister a MBean at JMX JSR 160 MBeans Server. *
      *
    • unregister Mbeans
    • *
    *

    * Examples: *
    * unregister an existing Mbean at jmx.server connection *

     *   <jmx:unregister
     *           ref="jmx.server"
     *           name="Catalina:type=MBeanFactory" />
     * 
    *

    *

    * WARNINGNot all Tomcat MBeans can successfully unregister remotely. The mbean * unregistration don't remove valves, realm, .. from parent class. * Please, use the MBeanFactory operation to remove valves and realms. *

    *

    * First call to a remote MBeanserver save the JMXConnection a reference jmx.server *

    * These tasks require Ant 1.6 or later interface. * * @author Peter Rossbach * @since 5.5.12 */ public class JMXAccessorUnregisterTask extends JMXAccessorTask { // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorUnregisterTask/1.0"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. * @return Returns the class info. */ @Override public String getInfo() { return (info); } // ------------------------------------------------------ protected Methods /** * Execute the specified command, based on the configured properties. The * input stream will be closed upon completion of this task, whether it was * executed successfully or not. * * @exception Exception * if an error occurs */ @Override public String jmxExecute(MBeanServerConnection jmxServerConnection) throws Exception { if (getName() == null) { throw new BuildException("Must specify a 'name'"); } return jmxUuregister(jmxServerConnection, getName()); } /** * Unregister Mbean * @param jmxServerConnection * @param name * @return The value of the given named attribute * @throws Exception */ protected String jmxUuregister(MBeanServerConnection jmxServerConnection,String name) throws Exception { String error = null; if(isEcho()) { handleOutput("Unregister MBean " + name ); } jmxServerConnection.unregisterMBean( new ObjectName(name)); return error; } } tomcat7-7.0.52/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java0000644000175100017510000001476112271471332026176 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant.jmx; import java.util.ArrayList; import java.util.List; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.apache.tools.ant.BuildException; /** * Create new MBean at JMX JSR 160 MBeans Server. *
      *
    • Create Mbeans
    • *
    • Create Mbeans with parameter
    • *
    • Create remote Mbeans with different classloader
    • *
    *

    * Examples: *
    * create a new Mbean at jmx.server connection *

     *   <jmx:create
     *           ref="jmx.server"
     *           name="Catalina:type=MBeanFactory"
     *           className="org.apache.catalina.mbeans.MBeanFactory"
     *           classLoader="Catalina:type=ServerClassLoader,name=server">
     *            <Arg value="org.apache.catalina.mbeans.MBeanFactory" />
     *   </jmxCreate/>
     * 
    *

    *

    * WARNINGNot all Tomcat MBeans can create remotely and autoregister by its parents! * Please, use the MBeanFactory operation to generate valves and realms. *

    *

    * First call to a remote MBeanserver save the JMXConnection a reference jmx.server *

    * These tasks require Ant 1.6 or later interface. * * @author Peter Rossbach * @since 5.5.12 */ public class JMXAccessorCreateTask extends JMXAccessorTask { // ----------------------------------------------------- Instance Variables private String className; private String classLoader; private List args=new ArrayList(); // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorCreateTask/1.0"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. * @return Returns the class info. */ @Override public String getInfo() { return (info); } // ------------------------------------------------------------- Properties /** * @return Returns the classLoader. */ public String getClassLoader() { return classLoader; } /** * @param classLoaderName The classLoader to set. */ public void setClassLoader(String classLoaderName) { this.classLoader = classLoaderName; } /** * @return Returns the className. */ public String getClassName() { return className; } /** * @param className The className to set. */ public void setClassName(String className) { this.className = className; } public void addArg(Arg arg ) { args.add(arg); } /** * @return Returns the args. */ public List getArgs() { return args; } /** * @param args The args to set. */ public void setArgs(List args) { this.args = args; } // ------------------------------------------------------ protected Methods /** * Execute the specified command, based on the configured properties. The * input stream will be closed upon completion of this task, whether it was * executed successfully or not. * * @exception Exception * if an error occurs */ @Override public String jmxExecute(MBeanServerConnection jmxServerConnection) throws Exception { if (getName() == null) { throw new BuildException("Must specify a 'name'"); } if ((className == null)) { throw new BuildException( "Must specify a 'className' for get"); } return jmxCreate(jmxServerConnection, getName()); } /** * create new Mbean and when set from ClassLoader Objectname * @param jmxServerConnection * @param name * @return The value of the given named attribute * @throws Exception */ protected String jmxCreate(MBeanServerConnection jmxServerConnection, String name) throws Exception { String error = null; Object argsA[] = null; String sigA[] = null; if (args != null) { argsA = new Object[ args.size()]; sigA = new String[args.size()]; for( int i=0; iJMX JSR 160 MBeans Server. *
      *
    • open more then one JSR 160 rmi connection
    • *
    • Get/Set Mbeans attributes
    • *
    • Call Mbean Operation with arguments
    • *
    • Argument values can be converted from string to int,long,float,double,boolean,ObjectName or InetAddress
    • *
    • Query Mbeans
    • *
    • Show Get, Call, Query result at Ant console log
    • *
    • Bind Get, Call, Query result at Ant properties
    • *
    * * Examples: *
      *
    • * Get a session attribute hello from session with ref ${sessionid.0} form * app Catalina:type=Manager,context=/ClusterTest,host=localhost *
       *   <jmx:invoke
       *           name="Catalina:type=Manager,context=/ClusterTest,host=localhost" 
       *           operation="getSessionAttribute"
       *           resultproperty="hello">
       *         <arg value="${sessionid.0}"/>
       *         <arg value="Hello"/>
       *   </jmx:invoke>
       * 
      *
    • *
    • * Create new AccessLogger at localhost * * <jmx:invoke * name="Catalina:type=MBeanFactory" * operation="createAccessLoggerValve" * resultproperty="accessLoggerObjectName" * > * <arg value="Catalina:type=Host,host=localhost"/> * </jmx:invoke> * * *
    • *
    • * Remove existing AccessLogger at localhost * * <jmx:invoke * name="Catalina:type=MBeanFactory" * operation="removeValve" * > * <arg value="Catalina:type=Valve,name=AccessLogValve,host=localhost"/> * </jmx:invoke> * * *
    • *
    *

    * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server *

    * These tasks require Ant 1.6 or later interface. * * @author Peter Rossbach * @since 5.5.10 */ public class JMXAccessorInvokeTask extends JMXAccessorTask { // ----------------------------------------------------- Instance Variables private String operation ; private List args=new ArrayList(); // ----------------------------------------------------- Instance Info /** * Descriptive information describing this implementation. */ private static final String info = "org.apache.catalina.ant.JMXAccessorInvokeTask/1.0"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } // ------------------------------------------------------------- Properties /** * @return Returns the operation. */ public String getOperation() { return operation; } /** * @param operation The operation to set. */ public void setOperation(String operation) { this.operation = operation; } public void addArg(Arg arg ) { args.add(arg); } /** * @return Returns the args. */ public List getArgs() { return args; } /** * @param args The args to set. */ public void setArgs(List args) { this.args = args; } // ------------------------------------------------------ protected Methods /** * Execute the specified command, based on the configured properties. The * input stream will be closed upon completion of this task, whether it was * executed successfully or not. * * @exception BuildException * if an error occurs */ @Override public String jmxExecute(MBeanServerConnection jmxServerConnection) throws Exception { if (getName() == null) { throw new BuildException("Must specify a 'name'"); } if ((operation == null)) { throw new BuildException( "Must specify a 'operation' for call"); } return jmxInvoke(jmxServerConnection, getName()); } /** * @param jmxServerConnection * @throws Exception */ protected String jmxInvoke(MBeanServerConnection jmxServerConnection, String name) throws Exception { Object result ; if (args == null) { result = jmxServerConnection.invoke(new ObjectName(name), operation, null, null); } else { Object argsA[]=new Object[ args.size()]; String sigA[]=new String[args.size()]; for( int i=0; i/status command, supported by the * mod_jk status (1.2.9) application. * * @author Peter Rossbach * @since 5.5.9 */ public class JKStatusUpdateTask extends AbstractCatalinaTask { private String worker = "lb"; private String workerType = "lb"; private int internalid = 0; private Integer lbRetries; private Integer lbRecovertime; private Boolean lbStickySession = Boolean.TRUE; private Boolean lbForceSession = Boolean.FALSE; private Integer workerLoadFactor; private String workerRedirect; private String workerClusterDomain; private Boolean workerDisabled = Boolean.FALSE; private Boolean workerStopped = Boolean.FALSE; private boolean isLBMode = true; private String workerLb; /** * */ public JKStatusUpdateTask() { super(); setUrl("http://localhost/status"); } /** * @return Returns the internalid. */ public int getInternalid() { return internalid; } /** * @param internalid * The internalid to set. */ public void setInternalid(int internalid) { this.internalid = internalid; } /** * @return Returns the lbForceSession. */ public Boolean getLbForceSession() { return lbForceSession; } /** * @param lbForceSession * The lbForceSession to set. */ public void setLbForceSession(Boolean lbForceSession) { this.lbForceSession = lbForceSession; } /** * @return Returns the lbRecovertime. */ public Integer getLbRecovertime() { return lbRecovertime; } /** * @param lbRecovertime * The lbRecovertime to set. */ public void setLbRecovertime(Integer lbRecovertime) { this.lbRecovertime = lbRecovertime; } /** * @return Returns the lbRetries. */ public Integer getLbRetries() { return lbRetries; } /** * @param lbRetries * The lbRetries to set. */ public void setLbRetries(Integer lbRetries) { this.lbRetries = lbRetries; } /** * @return Returns the lbStickySession. */ public Boolean getLbStickySession() { return lbStickySession; } /** * @param lbStickySession * The lbStickySession to set. */ public void setLbStickySession(Boolean lbStickySession) { this.lbStickySession = lbStickySession; } /** * @return Returns the worker. */ public String getWorker() { return worker; } /** * @param worker * The worker to set. */ public void setWorker(String worker) { this.worker = worker; } /** * @return Returns the workerType. */ public String getWorkerType() { return workerType; } /** * @param workerType * The workerType to set. */ public void setWorkerType(String workerType) { this.workerType = workerType; } /** * @return Returns the workerLb. */ public String getWorkerLb() { return workerLb; } /** * @param workerLb * The workerLb to set. */ public void setWorkerLb(String workerLb) { this.workerLb = workerLb; } /** * @return Returns the workerClusterDomain. */ public String getWorkerClusterDomain() { return workerClusterDomain; } /** * @param workerClusterDomain * The workerClusterDomain to set. */ public void setWorkerClusterDomain(String workerClusterDomain) { this.workerClusterDomain = workerClusterDomain; } /** * @return Returns the workerDisabled. */ public Boolean getWorkerDisabled() { return workerDisabled; } /** * @param workerDisabled * The workerDisabled to set. */ public void setWorkerDisabled(Boolean workerDisabled) { this.workerDisabled = workerDisabled; } /** * @return Returns the workerStopped. */ public Boolean getWorkerStopped() { return workerStopped; } /** * @param workerStopped The workerStopped to set. */ public void setWorkerStopped(Boolean workerStopped) { this.workerStopped = workerStopped; } /** * @return Returns the workerLoadFactor. */ public Integer getWorkerLoadFactor() { return workerLoadFactor; } /** * @param workerLoadFactor * The workerLoadFactor to set. */ public void setWorkerLoadFactor(Integer workerLoadFactor) { this.workerLoadFactor = workerLoadFactor; } /** * @return Returns the workerRedirect. */ public String getWorkerRedirect() { return workerRedirect; } /** * @param workerRedirect * The workerRedirect to set. */ public void setWorkerRedirect(String workerRedirect) { this.workerRedirect = workerRedirect; } /** * Execute the requested operation. * * @exception BuildException * if an error occurs */ @Override public void execute() throws BuildException { super.execute(); checkParameter(); StringBuilder sb = createLink(); execute(sb.toString(), null, null, -1); } /** * Create JkStatus link *
      *
    • load balance example: * http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true
    • *
    • worker example: * http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false *
    • *
    * * @return create jkstatus link */ private StringBuilder createLink() { // Building URL StringBuilder sb = new StringBuilder(); try { sb.append("?cmd=update&mime=txt"); sb.append("&w="); sb.append(URLEncoder.encode(worker, getCharset())); if (isLBMode) { //http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true if ((lbRetries != null)) { // > 0 sb.append("&lr="); sb.append(lbRetries); } if ((lbRecovertime != null)) { // > 59 sb.append("<="); sb.append(lbRecovertime); } if ((lbStickySession != null)) { sb.append("&ls="); sb.append(lbStickySession); } if ((lbForceSession != null)) { sb.append("&lf="); sb.append(lbForceSession); } } else { //http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false if ((workerLb != null)) { // must be configured sb.append("&l="); sb.append(URLEncoder.encode(workerLb, getCharset())); } if ((workerLoadFactor != null)) { // >= 1 sb.append("&wf="); sb.append(workerLoadFactor); } if ((workerDisabled != null)) { sb.append("&wd="); sb.append(workerDisabled); } if ((workerStopped != null)) { sb.append("&ws="); sb.append(workerStopped); } if ((workerRedirect != null)) { // other worker conrecte lb's sb.append("&wr="); } if ((workerClusterDomain != null)) { sb.append("&wc="); sb.append(URLEncoder.encode(workerClusterDomain, getCharset())); } } } catch (UnsupportedEncodingException e) { throw new BuildException("Invalid 'charset' attribute: " + getCharset()); } return sb; } /** * check correct lb and worker parameter */ protected void checkParameter() { if (worker == null) { throw new BuildException("Must specify 'worker' attribute"); } if (workerType == null) { throw new BuildException("Must specify 'workerType' attribute"); } if ("lb".equals(workerType)) { if (lbRecovertime == null && lbRetries == null) { throw new BuildException( "Must specify at a lb worker either 'lbRecovertime' or" + "'lbRetries' attribute"); } if (lbStickySession == null || lbForceSession == null) { throw new BuildException("Must specify at a lb worker either" + "'lbStickySession' and 'lbForceSession' attribute"); } if (null != lbRecovertime && 60 < lbRecovertime.intValue()) { throw new BuildException( "The 'lbRecovertime' must be greater than 59"); } if (null != lbRetries && 1 < lbRetries.intValue()) { throw new BuildException( "The 'lbRetries' must be greater than 1"); } isLBMode = true; } else if ("worker".equals(workerType)) { if (workerDisabled == null) { throw new BuildException( "Must specify at a node worker 'workerDisabled' attribute"); } if (workerStopped == null) { throw new BuildException( "Must specify at a node worker 'workerStopped' attribute"); } if (workerLoadFactor == null ) { throw new BuildException( "Must specify at a node worker 'workerLoadFactor' attribute"); } if (workerClusterDomain == null) { throw new BuildException( "Must specify at a node worker 'workerClusterDomain' attribute"); } if (workerRedirect == null) { throw new BuildException( "Must specify at a node worker 'workerRedirect' attribute"); } if (workerLb == null) { throw new BuildException("Must specify 'workerLb' attribute"); } if (workerLoadFactor.intValue() < 1) { throw new BuildException( "The 'workerLoadFactor' must be greater or equal 1"); } isLBMode = false; } else { throw new BuildException( "Only 'lb' and 'worker' supported as workerType attribute"); } } }tomcat7-7.0.52/java/org/apache/catalina/ant/AbstractCatalinaCommandTask.java0000644000175100017510000000516211572257253026634 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ant; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; public abstract class AbstractCatalinaCommandTask extends AbstractCatalinaTask { /** * The context path of the web application we are managing. */ protected String path = null; public String getPath() { return (this.path); } public void setPath(String path) { this.path = path; } /** * The context version of the web application we are managing. */ protected String version = null; public String getVersion() { return (this.version); } public void setVersion(String version) { this.version = version; } // --------------------------------------------------------- Public Methods /** * Create query string for the specified command. * * @param command Command to be executed * * @exception BuildException if an error occurs */ public StringBuilder createQueryString(String command) throws BuildException { StringBuilder buffer = new StringBuilder(); try { buffer.append(command); if (path == null) { throw new BuildException("Must specify 'path' attribute"); } else { buffer.append("?path="); buffer.append(URLEncoder.encode(this.path, getCharset())); if (this.version != null) { buffer.append("&version="); buffer.append(URLEncoder.encode(this.version, getCharset())); } } } catch (UnsupportedEncodingException e) { throw new BuildException ("Invalid 'charset' attribute: " + getCharset()); } return buffer; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/0000755000175100017510000000000012301126370020441 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ssi/SSISet.java0000644000175100017510000000473512271471332022436 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.PrintWriter; /** * Implements the Server-side #set command * * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public class SSISet implements SSICommand { /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) throws SSIStopProcessingException { long lastModified = 0; String errorMessage = ssiMediator.getConfigErrMsg(); String variableName = null; for (int i = 0; i < paramNames.length; i++) { String paramName = paramNames[i]; String paramValue = paramValues[i]; if (paramName.equalsIgnoreCase("var")) { variableName = paramValue; } else if (paramName.equalsIgnoreCase("value")) { if (variableName != null) { String substitutedValue = ssiMediator .substituteVariables(paramValue); ssiMediator.setVariableValue(variableName, substitutedValue); lastModified = System.currentTimeMillis(); } else { ssiMediator.log("#set--no variable specified"); writer.write(errorMessage); throw new SSIStopProcessingException(); } } else { ssiMediator.log("#set--Invalid attribute: " + paramName); writer.write(errorMessage); throw new SSIStopProcessingException(); } } return lastModified; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIServletExternalResolver.java0000644000175100017510000005377612271471332026565 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.Locale; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.Request; import org.apache.coyote.Constants; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.http.RequestUtil; /** * An implementation of SSIExternalResolver that is used with servlets. * * @author Dan Sandberg * @author David Becker */ public class SSIServletExternalResolver implements SSIExternalResolver { protected final String VARIABLE_NAMES[] = {"AUTH_TYPE", "CONTENT_LENGTH", "CONTENT_TYPE", "DOCUMENT_NAME", "DOCUMENT_URI", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR", "REMOTE_HOST", "REMOTE_PORT", "REMOTE_USER", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR", "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE", "UNIQUE_ID"}; protected ServletContext context; protected HttpServletRequest req; protected HttpServletResponse res; protected boolean isVirtualWebappRelative; protected int debug; protected String inputEncoding; public SSIServletExternalResolver(ServletContext context, HttpServletRequest req, HttpServletResponse res, boolean isVirtualWebappRelative, int debug, String inputEncoding) { this.context = context; this.req = req; this.res = res; this.isVirtualWebappRelative = isVirtualWebappRelative; this.debug = debug; this.inputEncoding = inputEncoding; } @Override public void log(String message, Throwable throwable) { //We can't assume that Servlet.log( message, null ) //is the same as Servlet.log( message ), since API //doesn't seem to say so. if (throwable != null) { context.log(message, throwable); } else { context.log(message); } } @Override public void addVariableNames(Collection variableNames) { for (int i = 0; i < VARIABLE_NAMES.length; i++) { String variableName = VARIABLE_NAMES[i]; String variableValue = getVariableValue(variableName); if (variableValue != null) { variableNames.add(variableName); } } Enumeration e = req.getAttributeNames(); while (e.hasMoreElements()) { String name = e.nextElement(); if (!isNameReserved(name)) { variableNames.add(name); } } } protected Object getReqAttributeIgnoreCase(String targetName) { Object object = null; if (!isNameReserved(targetName)) { object = req.getAttribute(targetName); if (object == null) { Enumeration e = req.getAttributeNames(); while (e.hasMoreElements()) { String name = e.nextElement(); if (targetName.equalsIgnoreCase(name) && !isNameReserved(name)) { object = req.getAttribute(name); if (object != null) { break; } } } } } return object; } protected boolean isNameReserved(String name) { return name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("sun."); } @Override public void setVariableValue(String name, String value) { if (!isNameReserved(name)) { req.setAttribute(name, value); } } @Override public String getVariableValue(String name) { String retVal = null; Object object = getReqAttributeIgnoreCase(name); if (object != null) { retVal = object.toString(); } else { retVal = getCGIVariable(name); } return retVal; } protected String getCGIVariable(String name) { String retVal = null; String[] nameParts = name.toUpperCase(Locale.ENGLISH).split("_"); int requiredParts = 2; if (nameParts.length == 1) { if (nameParts[0].equals("PATH")) { requiredParts = 1; } } else if (nameParts[0].equals("AUTH")) { if (nameParts[1].equals("TYPE")) { retVal = req.getAuthType(); } } else if(nameParts[0].equals("CONTENT")) { if (nameParts[1].equals("LENGTH")) { int contentLength = req.getContentLength(); if (contentLength >= 0) { retVal = Integer.toString(contentLength); } } else if (nameParts[1].equals("TYPE")) { retVal = req.getContentType(); } } else if (nameParts[0].equals("DOCUMENT")) { if (nameParts[1].equals("NAME")) { String requestURI = req.getRequestURI(); retVal = requestURI.substring(requestURI.lastIndexOf('/') + 1); } else if (nameParts[1].equals("URI")) { retVal = req.getRequestURI(); } } else if (name.equalsIgnoreCase("GATEWAY_INTERFACE")) { retVal = "CGI/1.1"; } else if (nameParts[0].equals("HTTP")) { if (nameParts[1].equals("ACCEPT")) { String accept = null; if (nameParts.length == 2) { accept = "Accept"; } else if (nameParts[2].equals("ENCODING")) { requiredParts = 3; accept = "Accept-Encoding"; } else if (nameParts[2].equals("LANGUAGE")) { requiredParts = 3; accept = "Accept-Language"; } if (accept != null) { Enumeration acceptHeaders = req.getHeaders(accept); if (acceptHeaders != null) if (acceptHeaders.hasMoreElements()) { StringBuilder rv = new StringBuilder( acceptHeaders.nextElement()); while (acceptHeaders.hasMoreElements()) { rv.append(", "); rv.append(acceptHeaders.nextElement()); } retVal = rv.toString(); } } } else if (nameParts[1].equals("CONNECTION")) { retVal = req.getHeader("Connection"); } else if (nameParts[1].equals("HOST")) { retVal = req.getHeader("Host"); } else if (nameParts[1].equals("REFERER")) { retVal = req.getHeader("Referer"); } else if (nameParts[1].equals("USER")) if (nameParts.length == 3) if (nameParts[2].equals("AGENT")) { requiredParts = 3; retVal = req.getHeader("User-Agent"); } } else if (nameParts[0].equals("PATH")) { if (nameParts[1].equals("INFO")) { retVal = req.getPathInfo(); } else if (nameParts[1].equals("TRANSLATED")) { retVal = req.getPathTranslated(); } } else if (nameParts[0].equals("QUERY")) { if (nameParts[1].equals("STRING")) { String queryString = req.getQueryString(); if (nameParts.length == 2) { //apache displays this as an empty string rather than (none) retVal = nullToEmptyString(queryString); } else if (nameParts[2].equals("UNESCAPED")) { requiredParts = 3; if (queryString != null) { // Use default as a last resort String queryStringEncoding = Constants.DEFAULT_CHARACTER_ENCODING; String uriEncoding = null; boolean useBodyEncodingForURI = false; // Get encoding settings from request / connector if // possible String requestEncoding = req.getCharacterEncoding(); if (req instanceof Request) { uriEncoding = ((Request)req).getConnector().getURIEncoding(); useBodyEncodingForURI = ((Request)req) .getConnector().getUseBodyEncodingForURI(); } // If valid, apply settings from request / connector if (uriEncoding != null) { queryStringEncoding = uriEncoding; } else if(useBodyEncodingForURI) { if (requestEncoding != null) { queryStringEncoding = requestEncoding; } } try { retVal = URLDecoder.decode(queryString, queryStringEncoding); } catch (UnsupportedEncodingException e) { retVal = queryString; } } } } } else if(nameParts[0].equals("REMOTE")) { if (nameParts[1].equals("ADDR")) { retVal = req.getRemoteAddr(); } else if (nameParts[1].equals("HOST")) { retVal = req.getRemoteHost(); } else if (nameParts[1].equals("IDENT")) { // Not implemented } else if (nameParts[1].equals("PORT")) { retVal = Integer.toString( req.getRemotePort()); } else if (nameParts[1].equals("USER")) { retVal = req.getRemoteUser(); } } else if(nameParts[0].equals("REQUEST")) { if (nameParts[1].equals("METHOD")) { retVal = req.getMethod(); } else if (nameParts[1].equals("URI")) { // If this is an error page, get the original URI retVal = (String) req.getAttribute( RequestDispatcher.FORWARD_REQUEST_URI); if (retVal == null) retVal=req.getRequestURI(); } } else if (nameParts[0].equals("SCRIPT")) { String scriptName = req.getServletPath(); if (nameParts[1].equals("FILENAME")) { retVal = context.getRealPath(scriptName); } else if (nameParts[1].equals("NAME")) { retVal = scriptName; } } else if (nameParts[0].equals("SERVER")) { if (nameParts[1].equals("ADDR")) { retVal = req.getLocalAddr(); } if (nameParts[1].equals("NAME")) { retVal = req.getServerName(); } else if (nameParts[1].equals("PORT")) { retVal = Integer.toString(req.getServerPort()); } else if (nameParts[1].equals("PROTOCOL")) { retVal = req.getProtocol(); } else if (nameParts[1].equals("SOFTWARE")) { StringBuilder rv = new StringBuilder(context.getServerInfo()); rv.append(" "); rv.append(System.getProperty("java.vm.name")); rv.append("/"); rv.append(System.getProperty("java.vm.version")); rv.append(" "); rv.append(System.getProperty("os.name")); retVal = rv.toString(); } } else if (name.equalsIgnoreCase("UNIQUE_ID")) { retVal = req.getRequestedSessionId(); } if (requiredParts != nameParts.length) return null; return retVal; } @Override public Date getCurrentDate() { return new Date(); } protected String nullToEmptyString(String string) { String retVal = string; if (retVal == null) { retVal = ""; } return retVal; } protected String getPathWithoutFileName(String servletPath) { String retVal = null; int lastSlash = servletPath.lastIndexOf('/'); if (lastSlash >= 0) { //cut off file name retVal = servletPath.substring(0, lastSlash + 1); } return retVal; } protected String getPathWithoutContext(final String contextPath, final String servletPath) { if (servletPath.startsWith(contextPath)) { return servletPath.substring(contextPath.length()); } return servletPath; } protected String getAbsolutePath(String path) throws IOException { String pathWithoutContext = SSIServletRequestUtil.getRelativePath(req); String prefix = getPathWithoutFileName(pathWithoutContext); if (prefix == null) { throw new IOException("Couldn't remove filename from path: " + pathWithoutContext); } String fullPath = prefix + path; String retVal = RequestUtil.normalize(fullPath); if (retVal == null) { throw new IOException("Normalization yielded null on path: " + fullPath); } return retVal; } protected ServletContextAndPath getServletContextAndPathFromNonVirtualPath( String nonVirtualPath) throws IOException { if (nonVirtualPath.startsWith("/") || nonVirtualPath.startsWith("\\")) { throw new IOException("A non-virtual path can't be absolute: " + nonVirtualPath); } if (nonVirtualPath.indexOf("../") >= 0) { throw new IOException("A non-virtual path can't contain '../' : " + nonVirtualPath); } String path = getAbsolutePath(nonVirtualPath); ServletContextAndPath csAndP = new ServletContextAndPath( context, path); return csAndP; } protected ServletContextAndPath getServletContextAndPathFromVirtualPath( String virtualPath) throws IOException { if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) { return new ServletContextAndPath(context, getAbsolutePath(virtualPath)); } String normalized = RequestUtil.normalize(virtualPath); if (isVirtualWebappRelative) { return new ServletContextAndPath(context, normalized); } ServletContext normContext = context.getContext(normalized); if (normContext == null) { throw new IOException("Couldn't get context for path: " + normalized); } //If it's the root context, then there is no context element // to remove, // ie: // '/file1.shtml' vs '/appName1/file1.shtml' if (!isRootContext(normContext)) { String noContext = getPathWithoutContext( normContext.getContextPath(), normalized); if (noContext == null) { throw new IOException( "Couldn't remove context from path: " + normalized); } return new ServletContextAndPath(normContext, noContext); } return new ServletContextAndPath(normContext, normalized); } //Assumes servletContext is not-null //Assumes that identity comparison will be true for the same context //Assuming the above, getContext("/") will be non-null as long as the root // context is // accessible. //If it isn't, then servletContext can't be the root context anyway, hence // they will // not match. protected boolean isRootContext(ServletContext servletContext) { return servletContext == servletContext.getContext("/"); } protected ServletContextAndPath getServletContextAndPath( String originalPath, boolean virtual) throws IOException { ServletContextAndPath csAndP = null; if (debug > 0) { log("SSIServletExternalResolver.getServletContextAndPath( " + originalPath + ", " + virtual + ")", null); } if (virtual) { csAndP = getServletContextAndPathFromVirtualPath(originalPath); } else { csAndP = getServletContextAndPathFromNonVirtualPath(originalPath); } return csAndP; } protected URLConnection getURLConnection(String originalPath, boolean virtual) throws IOException { ServletContextAndPath csAndP = getServletContextAndPath(originalPath, virtual); ServletContext context = csAndP.getServletContext(); String path = csAndP.getPath(); URL url = context.getResource(path); if (url == null) { throw new IOException("Context did not contain resource: " + path); } URLConnection urlConnection = url.openConnection(); return urlConnection; } @Override public long getFileLastModified(String path, boolean virtual) throws IOException { long lastModified = 0; try { URLConnection urlConnection = getURLConnection(path, virtual); lastModified = urlConnection.getLastModified(); } catch (IOException e) { // Ignore this. It will always fail for non-file based includes } return lastModified; } @Override public long getFileSize(String path, boolean virtual) throws IOException { long fileSize = -1; try { URLConnection urlConnection = getURLConnection(path, virtual); fileSize = urlConnection.getContentLength(); } catch (IOException e) { // Ignore this. It will always fail for non-file based includes } return fileSize; } //We are making lots of unnecessary copies of the included data here. If //someone ever complains that this is slow, we should connect the included // stream to the print writer that SSICommand uses. @Override public String getFileText(String originalPath, boolean virtual) throws IOException { try { ServletContextAndPath csAndP = getServletContextAndPath( originalPath, virtual); ServletContext context = csAndP.getServletContext(); String path = csAndP.getPath(); RequestDispatcher rd = context.getRequestDispatcher(path); if (rd == null) { throw new IOException( "Couldn't get request dispatcher for path: " + path); } ByteArrayServletOutputStream basos = new ByteArrayServletOutputStream(); ResponseIncludeWrapper responseIncludeWrapper = new ResponseIncludeWrapper(context, req, res, basos); rd.include(req, responseIncludeWrapper); //We can't assume the included servlet flushed its output responseIncludeWrapper.flushOutputStreamOrWriter(); byte[] bytes = basos.toByteArray(); //Assume platform default encoding unless otherwise specified String retVal; if (inputEncoding == null) { retVal = new String( bytes ); } else { retVal = new String (bytes, B2CConverter.getCharset(inputEncoding)); } //make an assumption that an empty response is a failure. This is // a problem // if a truly empty file //were included, but not sure how else to tell. if (retVal.equals("") && !req.getMethod().equalsIgnoreCase( org.apache.coyote.http11.Constants.HEAD)) { throw new IOException("Couldn't find file: " + path); } return retVal; } catch (ServletException e) { throw new IOException("Couldn't include file: " + originalPath + " because of ServletException: " + e.getMessage()); } } protected static class ServletContextAndPath { protected ServletContext servletContext; protected String path; public ServletContextAndPath(ServletContext servletContext, String path) { this.servletContext = servletContext; this.path = path; } public ServletContext getServletContext() { return servletContext; } public String getPath() { return path; } } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIStopProcessingException.java0000644000175100017510000000231012271471332026527 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; /** * Exception used to tell SSIProcessor that it should stop processing SSI * commands. This is used to mimic the Apache behavior in #set with invalid * attributes. * * @author Paul Speed * @author Dan Sandberg */ public class SSIStopProcessingException extends Exception { private static final long serialVersionUID = 1L; // No specific functionality for this class }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIFlastmod.java0000644000175100017510000000562412271471332023452 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import java.util.Locale; import org.apache.catalina.util.Strftime; /** * Implements the Server-side #flastmod command * * @author Bip Thelin * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public final class SSIFlastmod implements SSICommand { /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) { long lastModified = 0; String configErrMsg = ssiMediator.getConfigErrMsg(); for (int i = 0; i < paramNames.length; i++) { String paramName = paramNames[i]; String paramValue = paramValues[i]; String substitutedValue = ssiMediator .substituteVariables(paramValue); try { if (paramName.equalsIgnoreCase("file") || paramName.equalsIgnoreCase("virtual")) { boolean virtual = paramName.equalsIgnoreCase("virtual"); lastModified = ssiMediator.getFileLastModified( substitutedValue, virtual); Date date = new Date(lastModified); String configTimeFmt = ssiMediator.getConfigTimeFmt(); writer.write(formatDate(date, configTimeFmt)); } else { ssiMediator.log("#flastmod--Invalid attribute: " + paramName); writer.write(configErrMsg); } } catch (IOException e) { ssiMediator.log( "#flastmod--Couldn't get last modified for file: " + substitutedValue, e); writer.write(configErrMsg); } } return lastModified; } protected String formatDate(Date date, String configTimeFmt) { Strftime strftime = new Strftime(configTimeFmt, Locale.US); return strftime.format(date); } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIExec.java0000644000175100017510000000637512271471332022571 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import org.apache.catalina.util.IOTools; /** * Implements the Server-side #exec command * * @author Bip Thelin * @author Amy Roh * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public class SSIExec implements SSICommand { protected SSIInclude ssiInclude = new SSIInclude(); protected static final int BUFFER_SIZE = 1024; /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) { long lastModified = 0; String configErrMsg = ssiMediator.getConfigErrMsg(); String paramName = paramNames[0]; String paramValue = paramValues[0]; String substitutedValue = ssiMediator.substituteVariables(paramValue); if (paramName.equalsIgnoreCase("cgi")) { lastModified = ssiInclude.process(ssiMediator, "include", new String[]{"virtual"}, new String[]{substitutedValue}, writer); } else if (paramName.equalsIgnoreCase("cmd")) { boolean foundProgram = false; try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec(substitutedValue); foundProgram = true; BufferedReader stdOutReader = new BufferedReader( new InputStreamReader(proc.getInputStream())); BufferedReader stdErrReader = new BufferedReader( new InputStreamReader(proc.getErrorStream())); char[] buf = new char[BUFFER_SIZE]; IOTools.flow(stdErrReader, writer, buf); IOTools.flow(stdOutReader, writer, buf); proc.waitFor(); lastModified = System.currentTimeMillis(); } catch (InterruptedException e) { ssiMediator.log("Couldn't exec file: " + substitutedValue, e); writer.write(configErrMsg); } catch (IOException e) { if (!foundProgram) { //apache doesn't output an error message if it can't find // a program } ssiMediator.log("Couldn't exec file: " + substitutedValue, e); } } return lastModified; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIConditionalState.java0000644000175100017510000000276112271471332025144 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; /** * This class is used by SSIMediator and SSIConditional to keep track of state * information necessary to process the nested conditional commands ( if, elif, * else, endif ). * * @author Dan Sandberg * @author Paul Speed */ class SSIConditionalState { /** * Set to true if the current conditional has already been completed, i.e.: * a branch was taken. */ boolean branchTaken = false; /** * Counts the number of nested false branches. */ int nestingCount = 0; /** * Set to true if only conditional commands ( if, elif, else, endif ) * should be processed. */ boolean processConditionalCommandsOnly = false; }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIFsize.java0000644000175100017510000001076012271471332022756 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.io.PrintWriter; import java.text.DecimalFormat; /** * Implements the Server-side #fsize command * * @author Bip Thelin * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public final class SSIFsize implements SSICommand { protected static final int ONE_KILOBYTE = 1024; protected static final int ONE_MEGABYTE = 1024 * 1024; /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) { long lastModified = 0; String configErrMsg = ssiMediator.getConfigErrMsg(); for (int i = 0; i < paramNames.length; i++) { String paramName = paramNames[i]; String paramValue = paramValues[i]; String substitutedValue = ssiMediator .substituteVariables(paramValue); try { if (paramName.equalsIgnoreCase("file") || paramName.equalsIgnoreCase("virtual")) { boolean virtual = paramName.equalsIgnoreCase("virtual"); lastModified = ssiMediator.getFileLastModified( substitutedValue, virtual); long size = ssiMediator.getFileSize(substitutedValue, virtual); String configSizeFmt = ssiMediator.getConfigSizeFmt(); writer.write(formatSize(size, configSizeFmt)); } else { ssiMediator.log("#fsize--Invalid attribute: " + paramName); writer.write(configErrMsg); } } catch (IOException e) { ssiMediator.log("#fsize--Couldn't get size for file: " + substitutedValue, e); writer.write(configErrMsg); } } return lastModified; } public String repeat(char aChar, int numChars) { if (numChars < 0) { throw new IllegalArgumentException("Num chars can't be negative"); } StringBuilder buf = new StringBuilder(); for (int i = 0; i < numChars; i++) { buf.append(aChar); } return buf.toString(); } public String padLeft(String str, int maxChars) { String result = str; int charsToAdd = maxChars - str.length(); if (charsToAdd > 0) { result = repeat(' ', charsToAdd) + str; } return result; } //We try to mimic Apache here, as we do everywhere //All the 'magic' numbers are from the util_script.c Apache source file. protected String formatSize(long size, String format) { String retString = ""; if (format.equalsIgnoreCase("bytes")) { DecimalFormat decimalFormat = new DecimalFormat("#,##0"); retString = decimalFormat.format(size); } else { if (size == 0) { retString = "0k"; } else if (size < ONE_KILOBYTE) { retString = "1k"; } else if (size < ONE_MEGABYTE) { retString = Long.toString((size + 512) / ONE_KILOBYTE); retString += "k"; } else if (size < 99 * ONE_MEGABYTE) { DecimalFormat decimalFormat = new DecimalFormat("0.0M"); retString = decimalFormat.format(size / (double)ONE_MEGABYTE); } else { retString = Long.toString((size + (529 * ONE_KILOBYTE)) / ONE_MEGABYTE); retString += "M"; } retString = padLeft(retString, 5); } return retString; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/ByteArrayServletOutputStream.java0000644000175100017510000000330012271471332027153 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.ByteArrayOutputStream; import javax.servlet.ServletOutputStream; /** * Class that extends ServletOuputStream, used as a wrapper from within * SsiInclude * * @author Bip Thelin * @see ServletOutputStream and ByteArrayOutputStream */ public class ByteArrayServletOutputStream extends ServletOutputStream { /** * Our buffer to hold the stream. */ protected ByteArrayOutputStream buf = null; /** * Construct a new ServletOutputStream. */ public ByteArrayServletOutputStream() { buf = new ByteArrayOutputStream(); } /** * @return the byte array. */ public byte[] toByteArray() { return buf.toByteArray(); } /** * Write to our buffer. * * @param b The parameter to write */ @Override public void write(int b) { buf.write(b); } } tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIEcho.java0000644000175100017510000000536612271471332022562 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.PrintWriter; /** * Return the result associated with the supplied Server Variable. * * @author Bip Thelin * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public class SSIEcho implements SSICommand { protected static final String DEFAULT_ENCODING = "entity"; protected static final String MISSING_VARIABLE_VALUE = "(none)"; /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) { String encoding = DEFAULT_ENCODING; String originalValue = null; String errorMessage = ssiMediator.getConfigErrMsg(); for (int i = 0; i < paramNames.length; i++) { String paramName = paramNames[i]; String paramValue = paramValues[i]; if (paramName.equalsIgnoreCase("var")) { originalValue = paramValue; } else if (paramName.equalsIgnoreCase("encoding")) { if (isValidEncoding(paramValue)) { encoding = paramValue; } else { ssiMediator.log("#echo--Invalid encoding: " + paramValue); writer.write(errorMessage); } } else { ssiMediator.log("#echo--Invalid attribute: " + paramName); writer.write(errorMessage); } } String variableValue = ssiMediator.getVariableValue( originalValue, encoding); if (variableValue == null) { variableValue = MISSING_VARIABLE_VALUE; } writer.write(variableValue); return System.currentTimeMillis(); } protected boolean isValidEncoding(String encoding) { return encoding.equalsIgnoreCase("url") || encoding.equalsIgnoreCase("entity") || encoding.equalsIgnoreCase("none"); } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIFilter.java0000644000175100017510000001554512271471332023131 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; /** * Filter to process SSI requests within a webpage. Mapped to a content types * from within web.xml. * * @author David Becker * @see org.apache.catalina.ssi.SSIServlet */ public class SSIFilter implements Filter { protected FilterConfig config = null; /** Debug level for this servlet. */ protected int debug = 0; /** Expiration time in seconds for the doc. */ protected Long expires = null; /** virtual path can be webapp-relative */ protected boolean isVirtualWebappRelative = false; /** regex pattern to match when evaluating content types */ protected Pattern contentTypeRegEx = null; /** default pattern for ssi filter content type matching */ protected Pattern shtmlRegEx = Pattern.compile("text/x-server-parsed-html(;.*)?"); /** Allow exec (normally blocked for security) */ protected boolean allowExec = false; //----------------- Public methods. /** * Initialize this servlet. * * @exception ServletException * if an error occurs */ @Override public void init(FilterConfig config) throws ServletException { this.config = config; if (config.getInitParameter("debug") != null) { debug = Integer.parseInt(config.getInitParameter("debug")); } if (config.getInitParameter("contentType") != null) { contentTypeRegEx = Pattern.compile(config.getInitParameter("contentType")); } else { contentTypeRegEx = shtmlRegEx; } isVirtualWebappRelative = Boolean.parseBoolean(config.getInitParameter("isVirtualWebappRelative")); if (config.getInitParameter("expires") != null) expires = Long.valueOf(config.getInitParameter("expires")); allowExec = Boolean.parseBoolean(config.getInitParameter("allowExec")); if (debug > 0) config.getServletContext().log( "SSIFilter.init() SSI invoker started with 'debug'=" + debug); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // cast once HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse res = (HttpServletResponse)response; // indicate that we're in SSI processing req.setAttribute(Globals.SSI_FLAG_ATTR, "true"); // setup to capture output ByteArrayServletOutputStream basos = new ByteArrayServletOutputStream(); ResponseIncludeWrapper responseIncludeWrapper = new ResponseIncludeWrapper(config.getServletContext(),req, res, basos); // process remainder of filter chain chain.doFilter(req, responseIncludeWrapper); // we can't assume the chain flushed its output responseIncludeWrapper.flushOutputStreamOrWriter(); byte[] bytes = basos.toByteArray(); // get content type String contentType = responseIncludeWrapper.getContentType(); // is this an allowed type for SSI processing? if (contentTypeRegEx.matcher(contentType).matches()) { String encoding = res.getCharacterEncoding(); // set up SSI processing SSIExternalResolver ssiExternalResolver = new SSIServletExternalResolver(config.getServletContext(), req, res, isVirtualWebappRelative, debug, encoding); SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver, debug, allowExec); // prepare readers/writers Reader reader = new InputStreamReader(new ByteArrayInputStream(bytes), encoding); ByteArrayOutputStream ssiout = new ByteArrayOutputStream(); PrintWriter writer = new PrintWriter(new OutputStreamWriter(ssiout, encoding)); // do SSI processing long lastModified = ssiProcessor.process(reader, responseIncludeWrapper.getLastModified(), writer); // set output bytes writer.flush(); bytes = ssiout.toByteArray(); // override headers if (expires != null) { res.setDateHeader("expires", (new java.util.Date()).getTime() + expires.longValue() * 1000); } if (lastModified > 0) { res.setDateHeader("last-modified", lastModified); } res.setContentLength(bytes.length); Matcher shtmlMatcher = shtmlRegEx.matcher(responseIncludeWrapper.getContentType()); if (shtmlMatcher.matches()) { // Convert shtml mime type to ordinary html mime type but preserve // encoding, if any. String enc = shtmlMatcher.group(1); res.setContentType("text/html" + ((enc != null) ? enc : "")); } } // write output OutputStream out = null; try { out = res.getOutputStream(); } catch (IllegalStateException e) { // Ignore, will try to use a writer } if (out == null) { res.getWriter().write(new String(bytes)); } else { out.write(bytes); } } @Override public void destroy() { // NOOP } } tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIPrintenv.java0000644000175100017510000000445412271471332023506 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.PrintWriter; import java.util.Collection; import java.util.Iterator; /** * Implements the Server-side #printenv command * * @author Dan Sandberg * @author David Becker */ public class SSIPrintenv implements SSICommand { /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) { long lastModified = 0; //any arguments should produce an error if (paramNames.length > 0) { String errorMessage = ssiMediator.getConfigErrMsg(); writer.write(errorMessage); } else { Collection variableNames = ssiMediator.getVariableNames(); Iterator iter = variableNames.iterator(); while (iter.hasNext()) { String variableName = iter.next(); String variableValue = ssiMediator .getVariableValue(variableName); //This shouldn't happen, since all the variable names must // have values if (variableValue == null) { variableValue = "(none)"; } writer.write(variableName); writer.write('='); writer.write(variableValue); writer.write('\n'); lastModified = System.currentTimeMillis(); } } return lastModified; } } tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIExternalResolver.java0000644000175100017510000000445612271471332025207 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.util.Collection; import java.util.Date; /** * Interface used by SSIMediator to talk to the 'outside world' ( usually a * servlet ) * * @author Dan Sandberg */ public interface SSIExternalResolver { /** * Adds any external variables to the variableNames collection. * * @param variableNames * the collection to add to */ public void addVariableNames(Collection variableNames); public String getVariableValue(String name); /** * Set the named variable to the specified value. If value is null, then * the variable will be removed ( ie. a call to getVariableValue will * return null ) * * @param name * of the variable * @param value * of the variable */ public void setVariableValue(String name, String value); /** * Returns the current date. This is useful for putting the SSI stuff in a * regression test. Since you can make the current date a constant, it * makes testing easier since the output won't change. * * @return the data */ public Date getCurrentDate(); public long getFileSize(String path, boolean virtual) throws IOException; public long getFileLastModified(String path, boolean virtual) throws IOException; public String getFileText(String path, boolean virtual) throws IOException; public void log(String message, Throwable throwable); }tomcat7-7.0.52/java/org/apache/catalina/ssi/package.html0000644000175100017510000000333712271471332022737 0ustar locutuslocutus

    This package contains code that is used by the SsiInvoker.

    This class consists of SsiMediator.java which works as a mediator between the different SsiCommands. To add a command you have to implement the SsiCommand interface and extend the SsiMediator. Commands currently implemented are

    • SsiConfig - Implementation of the NCSA command Config i.e. <!--#config errmsg="error?"-->
    • SsiEcho - Implementation of the NCSA command Echo i.e. <!--#echo var="SERVER_NAME"-->
    • SsiExec - Not implemented
    • SsiFlastMod - Implementation of the NCSA command flastmod i.e. <!--#flastmod virtual="file"-->
    • SsiFsize - Implementation of the NCSA command fsize i.e. <!--#fsize file="file"-->
    • SsiInclude - Implementation of the NCSA command Include i.e. <!--#config virtual="includefile"-->
    tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIInclude.java0000644000175100017510000000504512271471332023261 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.io.PrintWriter; /** * Implements the Server-side #include command * * @author Bip Thelin * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public final class SSIInclude implements SSICommand { /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) { long lastModified = 0; String configErrMsg = ssiMediator.getConfigErrMsg(); for (int i = 0; i < paramNames.length; i++) { String paramName = paramNames[i]; String paramValue = paramValues[i]; String substitutedValue = ssiMediator .substituteVariables(paramValue); try { if (paramName.equalsIgnoreCase("file") || paramName.equalsIgnoreCase("virtual")) { boolean virtual = paramName.equalsIgnoreCase("virtual"); lastModified = ssiMediator.getFileLastModified( substitutedValue, virtual); String text = ssiMediator.getFileText(substitutedValue, virtual); writer.write(text); } else { ssiMediator.log("#include--Invalid attribute: " + paramName); writer.write(configErrMsg); } } catch (IOException e) { ssiMediator.log("#include--Couldn't include file: " + substitutedValue, e); writer.write(configErrMsg); } } return lastModified; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIServlet.java0000644000175100017510000002037112271471332023321 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URL; import java.net.URLConnection; import java.util.Locale; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; /** * Servlet to process SSI requests within a webpage. Mapped to a path from * within web.xml. * * @author Bip Thelin * @author Amy Roh * @author Dan Sandberg * @author David Becker */ public class SSIServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** Debug level for this servlet. */ protected int debug = 0; /** Should the output be buffered. */ protected boolean buffered = false; /** Expiration time in seconds for the doc. */ protected Long expires = null; /** virtual path can be webapp-relative */ protected boolean isVirtualWebappRelative = false; /** Input encoding. If not specified, uses platform default */ protected String inputEncoding = null; /** Output encoding. If not specified, uses platform default */ protected String outputEncoding = "UTF-8"; /** Allow exec (normally blocked for security) */ protected boolean allowExec = false; //----------------- Public methods. /** * Initialize this servlet. * * @exception ServletException * if an error occurs */ @Override public void init() throws ServletException { if (getServletConfig().getInitParameter("debug") != null) debug = Integer.parseInt(getServletConfig().getInitParameter("debug")); isVirtualWebappRelative = Boolean.parseBoolean(getServletConfig().getInitParameter("isVirtualWebappRelative")); if (getServletConfig().getInitParameter("expires") != null) expires = Long.valueOf(getServletConfig().getInitParameter("expires")); buffered = Boolean.parseBoolean(getServletConfig().getInitParameter("buffered")); inputEncoding = getServletConfig().getInitParameter("inputEncoding"); if (getServletConfig().getInitParameter("outputEncoding") != null) outputEncoding = getServletConfig().getInitParameter("outputEncoding"); allowExec = Boolean.parseBoolean( getServletConfig().getInitParameter("allowExec")); if (debug > 0) log("SSIServlet.init() SSI invoker started with 'debug'=" + debug); } /** * Process and forward the GET request to our requestHandler()* * * @param req * a value of type 'HttpServletRequest' * @param res * a value of type 'HttpServletResponse' * @exception IOException * if an error occurs * @exception ServletException * if an error occurs */ @Override public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { if (debug > 0) log("SSIServlet.doGet()"); requestHandler(req, res); } /** * Process and forward the POST request to our * requestHandler(). * * @param req * a value of type 'HttpServletRequest' * @param res * a value of type 'HttpServletResponse' * @exception IOException * if an error occurs * @exception ServletException * if an error occurs */ @Override public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { if (debug > 0) log("SSIServlet.doPost()"); requestHandler(req, res); } /** * Process our request and locate right SSI command. * * @param req * a value of type 'HttpServletRequest' * @param res * a value of type 'HttpServletResponse' */ protected void requestHandler(HttpServletRequest req, HttpServletResponse res) throws IOException { ServletContext servletContext = getServletContext(); String path = SSIServletRequestUtil.getRelativePath(req); if (debug > 0) log("SSIServlet.requestHandler()\n" + "Serving " + (buffered?"buffered ":"unbuffered ") + "resource '" + path + "'"); // Exclude any resource in the /WEB-INF and /META-INF subdirectories // (the "toUpperCase()" avoids problems on Windows systems) if (path == null || path.toUpperCase(Locale.ENGLISH).startsWith("/WEB-INF") || path.toUpperCase(Locale.ENGLISH).startsWith("/META-INF")) { res.sendError(HttpServletResponse.SC_NOT_FOUND, path); log("Can't serve file: " + path); return; } URL resource = servletContext.getResource(path); if (resource == null) { res.sendError(HttpServletResponse.SC_NOT_FOUND, path); log("Can't find file: " + path); return; } String resourceMimeType = servletContext.getMimeType(path); if (resourceMimeType == null) { resourceMimeType = "text/html"; } res.setContentType(resourceMimeType + ";charset=" + outputEncoding); if (expires != null) { res.setDateHeader("Expires", (new java.util.Date()).getTime() + expires.longValue() * 1000); } req.setAttribute(Globals.SSI_FLAG_ATTR, "true"); processSSI(req, res, resource); } protected void processSSI(HttpServletRequest req, HttpServletResponse res, URL resource) throws IOException { SSIExternalResolver ssiExternalResolver = new SSIServletExternalResolver(getServletContext(), req, res, isVirtualWebappRelative, debug, inputEncoding); SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver, debug, allowExec); PrintWriter printWriter = null; StringWriter stringWriter = null; if (buffered) { stringWriter = new StringWriter(); printWriter = new PrintWriter(stringWriter); } else { printWriter = res.getWriter(); } URLConnection resourceInfo = resource.openConnection(); InputStream resourceInputStream = resourceInfo.getInputStream(); String encoding = resourceInfo.getContentEncoding(); if (encoding == null) { encoding = inputEncoding; } InputStreamReader isr; if (encoding == null) { isr = new InputStreamReader(resourceInputStream); } else { isr = new InputStreamReader(resourceInputStream, encoding); } BufferedReader bufferedReader = new BufferedReader(isr); long lastModified = ssiProcessor.process(bufferedReader, resourceInfo.getLastModified(), printWriter); if (lastModified > 0) { res.setDateHeader("last-modified", lastModified); } if (buffered) { printWriter.flush(); @SuppressWarnings("null") String text = stringWriter.toString(); res.getWriter().write(text); } bufferedReader.close(); } }tomcat7-7.0.52/java/org/apache/catalina/ssi/ExpressionParseTree.java0000644000175100017510000003126512271471332025274 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.text.ParseException; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; /** * Represents a parsed expression. * * @author Paul Speed */ public class ExpressionParseTree { /** * Contains the current set of completed nodes. This is a workspace for the * parser. */ private LinkedList nodeStack = new LinkedList(); /** * Contains operator nodes that don't yet have values. This is a workspace * for the parser. */ private LinkedList oppStack = new LinkedList(); /** * The root node after the expression has been parsed. */ private Node root; /** * The SSIMediator to use when evaluating the expressions. */ private SSIMediator ssiMediator; /** * Creates a new parse tree for the specified expression. */ public ExpressionParseTree(String expr, SSIMediator ssiMediator) throws ParseException { this.ssiMediator = ssiMediator; parseExpression(expr); } /** * Evaluates the tree and returns true or false. The specified SSIMediator * is used to resolve variable references. */ public boolean evaluateTree() { return root.evaluate(); } /** * Pushes a new operator onto the opp stack, resolving existing opps as * needed. */ private void pushOpp(OppNode node) { // If node is null then it's just a group marker if (node == null) { oppStack.add(0, node); return; } while (true) { if (oppStack.size() == 0) break; OppNode top = oppStack.get(0); // If the top is a spacer then don't pop // anything if (top == null) break; // If the top node has a lower precedence then // let it stay if (top.getPrecedence() < node.getPrecedence()) break; // Remove the top node oppStack.remove(0); // Let it fill its branches top.popValues(nodeStack); // Stick it on the resolved node stack nodeStack.add(0, top); } // Add the new node to the opp stack oppStack.add(0, node); } /** * Resolves all pending opp nodes on the stack until the next group marker * is reached. */ private void resolveGroup() { OppNode top = null; while ((top = oppStack.remove(0)) != null) { // Let it fill its branches top.popValues(nodeStack); // Stick it on the resolved node stack nodeStack.add(0, top); } } /** * Parses the specified expression into a tree of parse nodes. */ private void parseExpression(String expr) throws ParseException { StringNode currStringNode = null; // We cheat a little and start an artificial // group right away. It makes finishing easier. pushOpp(null); ExpressionTokenizer et = new ExpressionTokenizer(expr); while (et.hasMoreTokens()) { int token = et.nextToken(); if (token != ExpressionTokenizer.TOKEN_STRING) currStringNode = null; switch (token) { case ExpressionTokenizer.TOKEN_STRING : if (currStringNode == null) { currStringNode = new StringNode(et.getTokenValue()); nodeStack.add(0, currStringNode); } else { // Add to the existing currStringNode.value.append(" "); currStringNode.value.append(et.getTokenValue()); } break; case ExpressionTokenizer.TOKEN_AND : pushOpp(new AndNode()); break; case ExpressionTokenizer.TOKEN_OR : pushOpp(new OrNode()); break; case ExpressionTokenizer.TOKEN_NOT : pushOpp(new NotNode()); break; case ExpressionTokenizer.TOKEN_EQ : pushOpp(new EqualNode()); break; case ExpressionTokenizer.TOKEN_NOT_EQ : pushOpp(new NotNode()); // Sneak the regular node in. The NOT will // be resolved when the next opp comes along. oppStack.add(0, new EqualNode()); break; case ExpressionTokenizer.TOKEN_RBRACE : // Closeout the current group resolveGroup(); break; case ExpressionTokenizer.TOKEN_LBRACE : // Push a group marker pushOpp(null); break; case ExpressionTokenizer.TOKEN_GE : pushOpp(new NotNode()); // Similar strategy to NOT_EQ above, except this // is NOT less than oppStack.add(0, new LessThanNode()); break; case ExpressionTokenizer.TOKEN_LE : pushOpp(new NotNode()); // Similar strategy to NOT_EQ above, except this // is NOT greater than oppStack.add(0, new GreaterThanNode()); break; case ExpressionTokenizer.TOKEN_GT : pushOpp(new GreaterThanNode()); break; case ExpressionTokenizer.TOKEN_LT : pushOpp(new LessThanNode()); break; case ExpressionTokenizer.TOKEN_END : break; } } // Finish off the rest of the opps resolveGroup(); if (nodeStack.size() == 0) { throw new ParseException("No nodes created.", et.getIndex()); } if (nodeStack.size() > 1) { throw new ParseException("Extra nodes created.", et.getIndex()); } if (oppStack.size() != 0) { throw new ParseException("Unused opp nodes exist.", et.getIndex()); } root = nodeStack.get(0); } /** * A node in the expression parse tree. */ private abstract class Node { /** * Return true if the node evaluates to true. */ public abstract boolean evaluate(); } /** * A node the represents a String value */ private class StringNode extends Node { StringBuilder value; String resolved = null; public StringNode(String value) { this.value = new StringBuilder(value); } /** * Resolves any variable references and returns the value string. */ public String getValue() { if (resolved == null) resolved = ssiMediator.substituteVariables(value.toString()); return resolved; } /** * Returns true if the string is not empty. */ @Override public boolean evaluate() { return !(getValue().length() == 0); } @Override public String toString() { return value.toString(); } } private static final int PRECEDENCE_NOT = 5; private static final int PRECEDENCE_COMPARE = 4; private static final int PRECEDENCE_LOGICAL = 1; /** * A node implementation that represents an operation. */ private abstract class OppNode extends Node { /** * The left branch. */ Node left; /** * The right branch. */ Node right; /** * Returns a preference level suitable for comparison to other OppNode * preference levels. */ public abstract int getPrecedence(); /** * Lets the node pop its own branch nodes off the front of the * specified list. The default pulls two. */ public void popValues(List values) { right = values.remove(0); left = values.remove(0); } } private final class NotNode extends OppNode { @Override public boolean evaluate() { return !left.evaluate(); } @Override public int getPrecedence() { return PRECEDENCE_NOT; } /** * Overridden to pop only one value. */ @Override public void popValues(List values) { left = values.remove(0); } @Override public String toString() { return left + " NOT"; } } private final class AndNode extends OppNode { @Override public boolean evaluate() { if (!left.evaluate()) // Short circuit return false; return right.evaluate(); } @Override public int getPrecedence() { return PRECEDENCE_LOGICAL; } @Override public String toString() { return left + " " + right + " AND"; } } private final class OrNode extends OppNode { @Override public boolean evaluate() { if (left.evaluate()) // Short circuit return true; return right.evaluate(); } @Override public int getPrecedence() { return PRECEDENCE_LOGICAL; } @Override public String toString() { return left + " " + right + " OR"; } } private abstract class CompareNode extends OppNode { protected int compareBranches() { String val1 = ((StringNode)left).getValue(); String val2 = ((StringNode)right).getValue(); int val2Len = val2.length(); if (val2Len > 1 && val2.charAt(0) == '/' && val2.charAt(val2Len - 1) == '/') { // Treat as a regular expression String expr = val2.substring(1, val2Len - 1); try { Pattern pattern = Pattern.compile(expr); // Regular expressions will only ever be used with EqualNode // so return zero for equal and non-zero for not equal if (pattern.matcher(val1).find()) { return 0; } else { return -1; } } catch (PatternSyntaxException pse) { ssiMediator.log("Invalid expression: " + expr, pse); return 0; } } return val1.compareTo(val2); } } private final class EqualNode extends CompareNode { @Override public boolean evaluate() { return (compareBranches() == 0); } @Override public int getPrecedence() { return PRECEDENCE_COMPARE; } @Override public String toString() { return left + " " + right + " EQ"; } } private final class GreaterThanNode extends CompareNode { @Override public boolean evaluate() { return (compareBranches() > 0); } @Override public int getPrecedence() { return PRECEDENCE_COMPARE; } @Override public String toString() { return left + " " + right + " GT"; } } private final class LessThanNode extends CompareNode { @Override public boolean evaluate() { return (compareBranches() < 0); } @Override public int getPrecedence() { return PRECEDENCE_COMPARE; } @Override public String toString() { return left + " " + right + " LT"; } } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIConfig.java0000644000175100017510000000445512271471332023107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.PrintWriter; /** * Implements the Server-side #exec command * * @author Bip Thelin * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public final class SSIConfig implements SSICommand { /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) { for (int i = 0; i < paramNames.length; i++) { String paramName = paramNames[i]; String paramValue = paramValues[i]; String substitutedValue = ssiMediator .substituteVariables(paramValue); if (paramName.equalsIgnoreCase("errmsg")) { ssiMediator.setConfigErrMsg(substitutedValue); } else if (paramName.equalsIgnoreCase("sizefmt")) { ssiMediator.setConfigSizeFmt(substitutedValue); } else if (paramName.equalsIgnoreCase("timefmt")) { ssiMediator.setConfigTimeFmt(substitutedValue); } else { ssiMediator.log("#config--Invalid attribute: " + paramName); //We need to fetch this value each time, since it may change // during the // loop String configErrMsg = ssiMediator.getConfigErrMsg(); writer.write(configErrMsg); } } // Setting config options doesn't really change the page return 0; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIConditional.java0000644000175100017510000001303312271471332024135 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.PrintWriter; import java.text.ParseException; /** * SSI command that handles all conditional directives. * * @author Paul Speed * @author David Becker */ public class SSIConditional implements SSICommand { /** * @see SSICommand */ @Override public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) throws SSIStopProcessingException { // Assume anything using conditionals was modified by it long lastModified = System.currentTimeMillis(); // Retrieve the current state information SSIConditionalState state = ssiMediator.getConditionalState(); if ("if".equalsIgnoreCase(commandName)) { // Do nothing if we are nested in a false branch // except count it if (state.processConditionalCommandsOnly) { state.nestingCount++; return lastModified; } state.nestingCount = 0; // Evaluate the expression if (evaluateArguments(paramNames, paramValues, ssiMediator)) { // No more branches can be taken for this if block state.branchTaken = true; } else { // Do not process this branch state.processConditionalCommandsOnly = true; state.branchTaken = false; } } else if ("elif".equalsIgnoreCase(commandName)) { // No need to even execute if we are nested in // a false branch if (state.nestingCount > 0) return lastModified; // If a branch was already taken in this if block // then disable output and return if (state.branchTaken) { state.processConditionalCommandsOnly = true; return lastModified; } // Evaluate the expression if (evaluateArguments(paramNames, paramValues, ssiMediator)) { // Turn back on output and mark the branch state.processConditionalCommandsOnly = false; state.branchTaken = true; } else { // Do not process this branch state.processConditionalCommandsOnly = true; state.branchTaken = false; } } else if ("else".equalsIgnoreCase(commandName)) { // No need to even execute if we are nested in // a false branch if (state.nestingCount > 0) return lastModified; // If we've already taken another branch then // disable output otherwise enable it. state.processConditionalCommandsOnly = state.branchTaken; // And in any case, it's safe to say a branch // has been taken. state.branchTaken = true; } else if ("endif".equalsIgnoreCase(commandName)) { // If we are nested inside a false branch then pop out // one level on the nesting count if (state.nestingCount > 0) { state.nestingCount--; return lastModified; } // Turn output back on state.processConditionalCommandsOnly = false; // Reset the branch status for any outer if blocks, // since clearly we took a branch to have gotten here // in the first place. state.branchTaken = true; } else { throw new SSIStopProcessingException(); //throw new SsiCommandException( "Not a conditional command:" + // cmdName ); } return lastModified; } /** * Retrieves the expression from the specified arguments and peforms the * necessary evaluation steps. */ private boolean evaluateArguments(String[] names, String[] values, SSIMediator ssiMediator) throws SSIStopProcessingException { String expr = getExpression(names, values); if (expr == null) { throw new SSIStopProcessingException(); //throw new SsiCommandException( "No expression specified." ); } try { ExpressionParseTree tree = new ExpressionParseTree(expr, ssiMediator); return tree.evaluateTree(); } catch (ParseException e) { //throw new SsiCommandException( "Error parsing expression." ); throw new SSIStopProcessingException(); } } /** * Returns the "expr" if the arg name is appropriate, otherwise returns * null. */ private String getExpression(String[] paramNames, String[] paramValues) { if ("expr".equalsIgnoreCase(paramNames[0])) return paramValues[0]; return null; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSICommand.java0000644000175100017510000000347112271471332023255 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.PrintWriter; /** * The interface that all SSI commands ( SSIEcho, SSIInclude, ...) must * implement. * * @author Bip Thelin * @author Dan Sandberg * @author David Becker */ public interface SSICommand { /** * Write the output of the command to the writer. * * @param ssiMediator * the ssi mediator * @param commandName * the name of the actual command ( ie. echo ) * @param paramNames * The parameter names * @param paramValues * The parameter values * @param writer * the writer to output to * @return the most current modified date resulting from any SSI commands * @throws SSIStopProcessingException * if SSI processing should be aborted */ public long process(SSIMediator ssiMediator, String commandName, String[] paramNames, String[] paramValues, PrintWriter writer) throws SSIStopProcessingException; }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIMediator.java0000644000175100017510000002750612271471332023450 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Set; import java.util.TimeZone; import org.apache.catalina.util.Strftime; import org.apache.catalina.util.URLEncoder; import org.apache.tomcat.util.http.HttpMessages; /** * Allows the different SSICommand implementations to share data/talk to each * other * * @author Bip Thelin * @author Amy Roh * @author Paul Speed * @author Dan Sandberg * @author David Becker */ public class SSIMediator { protected static final String DEFAULT_CONFIG_ERR_MSG = "[an error occurred while processing this directive]"; protected static final String DEFAULT_CONFIG_TIME_FMT = "%A, %d-%b-%Y %T %Z"; protected static final String DEFAULT_CONFIG_SIZE_FMT = "abbrev"; protected static URLEncoder urlEncoder; protected String configErrMsg = DEFAULT_CONFIG_ERR_MSG; protected String configTimeFmt = DEFAULT_CONFIG_TIME_FMT; protected String configSizeFmt = DEFAULT_CONFIG_SIZE_FMT; protected String className = getClass().getName(); protected SSIExternalResolver ssiExternalResolver; protected long lastModifiedDate; protected int debug; protected Strftime strftime; protected SSIConditionalState conditionalState = new SSIConditionalState(); static { //We try to encode only the same characters that apache does urlEncoder = new URLEncoder(); urlEncoder.addSafeCharacter(','); urlEncoder.addSafeCharacter(':'); urlEncoder.addSafeCharacter('-'); urlEncoder.addSafeCharacter('_'); urlEncoder.addSafeCharacter('.'); urlEncoder.addSafeCharacter('*'); urlEncoder.addSafeCharacter('/'); urlEncoder.addSafeCharacter('!'); urlEncoder.addSafeCharacter('~'); urlEncoder.addSafeCharacter('\''); urlEncoder.addSafeCharacter('('); urlEncoder.addSafeCharacter(')'); } public SSIMediator(SSIExternalResolver ssiExternalResolver, long lastModifiedDate, int debug) { this.ssiExternalResolver = ssiExternalResolver; this.lastModifiedDate = lastModifiedDate; this.debug = debug; setConfigTimeFmt(DEFAULT_CONFIG_TIME_FMT, true); } public void setConfigErrMsg(String configErrMsg) { this.configErrMsg = configErrMsg; } public void setConfigTimeFmt(String configTimeFmt) { setConfigTimeFmt(configTimeFmt, false); } public void setConfigTimeFmt(String configTimeFmt, boolean fromConstructor) { this.configTimeFmt = configTimeFmt; this.strftime = new Strftime(configTimeFmt, Locale.US); //Variables like DATE_LOCAL, DATE_GMT, and LAST_MODIFIED need to be // updated when //the timefmt changes. This is what Apache SSI does. setDateVariables(fromConstructor); } public void setConfigSizeFmt(String configSizeFmt) { this.configSizeFmt = configSizeFmt; } public String getConfigErrMsg() { return configErrMsg; } public String getConfigTimeFmt() { return configTimeFmt; } public String getConfigSizeFmt() { return configSizeFmt; } public SSIConditionalState getConditionalState() { return conditionalState; } public Collection getVariableNames() { Set variableNames = new HashSet(); //These built-in variables are supplied by the mediator ( if not // over-written by // the user ) and always exist variableNames.add("DATE_GMT"); variableNames.add("DATE_LOCAL"); variableNames.add("LAST_MODIFIED"); ssiExternalResolver.addVariableNames(variableNames); //Remove any variables that are reserved by this class Iterator iter = variableNames.iterator(); while (iter.hasNext()) { String name = iter.next(); if (isNameReserved(name)) { iter.remove(); } } return variableNames; } public long getFileSize(String path, boolean virtual) throws IOException { return ssiExternalResolver.getFileSize(path, virtual); } public long getFileLastModified(String path, boolean virtual) throws IOException { return ssiExternalResolver.getFileLastModified(path, virtual); } public String getFileText(String path, boolean virtual) throws IOException { return ssiExternalResolver.getFileText(path, virtual); } protected boolean isNameReserved(String name) { return name.startsWith(className + "."); } public String getVariableValue(String variableName) { return getVariableValue(variableName, "none"); } public void setVariableValue(String variableName, String variableValue) { if (!isNameReserved(variableName)) { ssiExternalResolver.setVariableValue(variableName, variableValue); } } public String getVariableValue(String variableName, String encoding) { String lowerCaseVariableName = variableName.toLowerCase(Locale.ENGLISH); String variableValue = null; if (!isNameReserved(lowerCaseVariableName)) { //Try getting it externally first, if it fails, try getting the // 'built-in' // value variableValue = ssiExternalResolver.getVariableValue(variableName); if (variableValue == null) { variableName = variableName.toUpperCase(Locale.ENGLISH); variableValue = ssiExternalResolver .getVariableValue(className + "." + variableName); } if (variableValue != null) { variableValue = encode(variableValue, encoding); } } return variableValue; } /** * Applies variable substitution to the specified String and returns the * new resolved string. */ public String substituteVariables(String val) { // If it has no references or HTML entities then no work // need to be done if (val.indexOf('$') < 0 && val.indexOf('&') < 0) return val; // HTML decoding val = val.replace("<", "<"); val = val.replace(">", ">"); val = val.replace(""", "\""); val = val.replace("&", "&"); StringBuilder sb = new StringBuilder(val); int charStart = sb.indexOf("&#"); while (charStart > -1) { int charEnd = sb.indexOf(";", charStart); if (charEnd > -1) { char c = (char) Integer.parseInt( sb.substring(charStart + 2, charEnd)); sb.delete(charStart, charEnd + 1); sb.insert(charStart, c); charStart = sb.indexOf("&#"); } else { break; } } for (int i = 0; i < sb.length();) { // Find the next $ for (; i < sb.length(); i++) { if (sb.charAt(i) == '$') { i++; break; } } if (i == sb.length()) break; // Check to see if the $ is escaped if (i > 1 && sb.charAt(i - 2) == '\\') { sb.deleteCharAt(i - 2); i--; continue; } int nameStart = i; int start = i - 1; int end = -1; int nameEnd = -1; char endChar = ' '; // Check for {} wrapped var if (sb.charAt(i) == '{') { nameStart++; endChar = '}'; } // Find the end of the var reference for (; i < sb.length(); i++) { if (sb.charAt(i) == endChar) break; } end = i; nameEnd = end; if (endChar == '}') end++; // We should now have enough to extract the var name String varName = sb.substring(nameStart, nameEnd); String value = getVariableValue(varName); if (value == null) value = ""; // Replace the var name with its value sb.replace(start, end, value); // Start searching for the next $ after the value // that was just substituted. i = start + value.length(); } return sb.toString(); } protected String formatDate(Date date, TimeZone timeZone) { String retVal; if (timeZone != null) { //we temporarily change strftime. Since SSIMediator is inherently // single-threaded, this //isn't a problem TimeZone oldTimeZone = strftime.getTimeZone(); strftime.setTimeZone(timeZone); retVal = strftime.format(date); strftime.setTimeZone(oldTimeZone); } else { retVal = strftime.format(date); } return retVal; } protected String encode(String value, String encoding) { String retVal = null; if (encoding.equalsIgnoreCase("url")) { retVal = urlEncoder.encode(value); } else if (encoding.equalsIgnoreCase("none")) { retVal = value; } else if (encoding.equalsIgnoreCase("entity")) { retVal = HttpMessages.filter(value); } else { //This shouldn't be possible throw new IllegalArgumentException("Unknown encoding: " + encoding); } return retVal; } public void log(String message) { ssiExternalResolver.log(message, null); } public void log(String message, Throwable throwable) { ssiExternalResolver.log(message, throwable); } protected void setDateVariables(boolean fromConstructor) { boolean alreadySet = ssiExternalResolver.getVariableValue(className + ".alreadyset") != null; //skip this if we are being called from the constructor, and this has // already // been set if (!(fromConstructor && alreadySet)) { ssiExternalResolver.setVariableValue(className + ".alreadyset", "true"); Date date = new Date(); TimeZone timeZone = TimeZone.getTimeZone("GMT"); String retVal = formatDate(date, timeZone); //If we are setting on of the date variables, we want to remove // them from the // user //defined list of variables, because this is what Apache does setVariableValue("DATE_GMT", null); ssiExternalResolver.setVariableValue(className + ".DATE_GMT", retVal); retVal = formatDate(date, null); setVariableValue("DATE_LOCAL", null); ssiExternalResolver.setVariableValue(className + ".DATE_LOCAL", retVal); retVal = formatDate(new Date(lastModifiedDate), null); setVariableValue("LAST_MODIFIED", null); ssiExternalResolver.setVariableValue(className + ".LAST_MODIFIED", retVal); } } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIServletRequestUtil.java0000644000175100017510000000435412271471332025533 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import org.apache.tomcat.util.http.RequestUtil; public class SSIServletRequestUtil { /** * Return the relative path associated with this servlet. Taken from * DefaultServlet.java. Perhaps this should be put in * org.apache.catalina.util somewhere? Seems like it would be widely used. * * @param request * The servlet request we are processing */ public static String getRelativePath(HttpServletRequest request) { // Are we being processed by a RequestDispatcher.include()? if (request.getAttribute( RequestDispatcher.INCLUDE_REQUEST_URI) != null) { String result = (String)request.getAttribute( RequestDispatcher.INCLUDE_PATH_INFO); if (result == null) result = (String)request.getAttribute( RequestDispatcher.INCLUDE_SERVLET_PATH); if ((result == null) || (result.equals(""))) result = "/"; return (result); } // No, extract the desired path directly from the request String result = request.getPathInfo(); if (result == null) { result = request.getServletPath(); } if ((result == null) || (result.equals(""))) { result = "/"; } return RequestUtil.normalize(result); } }tomcat7-7.0.52/java/org/apache/catalina/ssi/ExpressionTokenizer.java0000644000175100017510000001257412271471332025356 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; /** * Parses an expression string to return the individual tokens. This is * patterned similar to the StreamTokenizer in the JDK but customized for SSI * conditional expression parsing. * * @author Paul Speed */ public class ExpressionTokenizer { public static final int TOKEN_STRING = 0; public static final int TOKEN_AND = 1; public static final int TOKEN_OR = 2; public static final int TOKEN_NOT = 3; public static final int TOKEN_EQ = 4; public static final int TOKEN_NOT_EQ = 5; public static final int TOKEN_RBRACE = 6; public static final int TOKEN_LBRACE = 7; public static final int TOKEN_GE = 8; public static final int TOKEN_LE = 9; public static final int TOKEN_GT = 10; public static final int TOKEN_LT = 11; public static final int TOKEN_END = 12; private char[] expr; private String tokenVal = null; private int index; private int length; /** * Creates a new parser for the specified expression. */ public ExpressionTokenizer(String expr) { this.expr = expr.trim().toCharArray(); this.length = this.expr.length; } /** * Returns true if there are more tokens. */ public boolean hasMoreTokens() { return index < length; } /** * Returns the current index for error reporting purposes. */ public int getIndex() { return index; } protected boolean isMetaChar(char c) { return Character.isWhitespace(c) || c == '(' || c == ')' || c == '!' || c == '<' || c == '>' || c == '|' || c == '&' || c == '='; } /** * Returns the next token type and initializes any state variables * accordingly. */ public int nextToken() { // Skip any leading white space while (index < length && Character.isWhitespace(expr[index])) index++; // Clear the current token val tokenVal = null; if (index == length) return TOKEN_END; // End of string int start = index; char currentChar = expr[index]; char nextChar = (char)0; index++; if (index < length) nextChar = expr[index]; // Check for a known token start switch (currentChar) { case '(' : return TOKEN_LBRACE; case ')' : return TOKEN_RBRACE; case '=' : return TOKEN_EQ; case '!' : if (nextChar == '=') { index++; return TOKEN_NOT_EQ; } return TOKEN_NOT; case '|' : if (nextChar == '|') { index++; return TOKEN_OR; } break; case '&' : if (nextChar == '&') { index++; return TOKEN_AND; } break; case '>' : if (nextChar == '=') { index++; return TOKEN_GE; // Greater than or equal } return TOKEN_GT; // Greater than case '<' : if (nextChar == '=') { index++; return TOKEN_LE; // Less than or equal } return TOKEN_LT; // Less than default : // Otherwise it's a string break; } int end = index; // If it's a quoted string then end is the next unescaped quote if (currentChar == '"' || currentChar == '\'') { char endChar = currentChar; boolean escaped = false; start++; for (; index < length; index++) { if (expr[index] == '\\' && !escaped) { escaped = true; continue; } if (expr[index] == endChar && !escaped) break; escaped = false; } end = index; index++; // Skip the end quote } else { // End is the next whitespace character for (; index < length; index++) { if (isMetaChar(expr[index])) break; } end = index; } // Extract the string from the array this.tokenVal = new String(expr, start, end - start); return TOKEN_STRING; } /** * Returns the String value of the token if it was type TOKEN_STRING. * Otherwise null is returned. */ public String getTokenValue() { return tokenVal; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/SSIProcessor.java0000644000175100017510000003126612271471332023661 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; import java.util.HashMap; import java.util.Locale; import java.util.StringTokenizer; import org.apache.catalina.util.IOTools; /** * The entry point to SSI processing. This class does the actual parsing, * delegating to the SSIMediator, SSICommand, and SSIExternalResolver as * necessary[ * * @author Dan Sandberg * @author David Becker */ public class SSIProcessor { /** The start pattern */ protected static final String COMMAND_START = ""; protected static final int BUFFER_SIZE = 4096; protected SSIExternalResolver ssiExternalResolver; protected HashMap commands = new HashMap(); protected int debug; protected final boolean allowExec; public SSIProcessor(SSIExternalResolver ssiExternalResolver, int debug, boolean allowExec) { this.ssiExternalResolver = ssiExternalResolver; this.debug = debug; this.allowExec = allowExec; addBuiltinCommands(); } protected void addBuiltinCommands() { addCommand("config", new SSIConfig()); addCommand("echo", new SSIEcho()); if (allowExec) { addCommand("exec", new SSIExec()); } addCommand("include", new SSIInclude()); addCommand("flastmod", new SSIFlastmod()); addCommand("fsize", new SSIFsize()); addCommand("printenv", new SSIPrintenv()); addCommand("set", new SSISet()); SSIConditional ssiConditional = new SSIConditional(); addCommand("if", ssiConditional); addCommand("elif", ssiConditional); addCommand("endif", ssiConditional); addCommand("else", ssiConditional); } public void addCommand(String name, SSICommand command) { commands.put(name, command); } /** * Process a file with server-side commands, reading from reader and * writing the processed version to writer. NOTE: We really should be doing * this in a streaming way rather than converting it to an array first. * * @param reader * the reader to read the file containing SSIs from * @param writer * the writer to write the file with the SSIs processed. * @return the most current modified date resulting from any SSI commands * @throws IOException * when things go horribly awry. Should be unlikely since the * SSICommand usually catches 'normal' IOExceptions. */ public long process(Reader reader, long lastModifiedDate, PrintWriter writer) throws IOException { SSIMediator ssiMediator = new SSIMediator(ssiExternalResolver, lastModifiedDate, debug); StringWriter stringWriter = new StringWriter(); IOTools.flow(reader, stringWriter); String fileContents = stringWriter.toString(); stringWriter = null; int index = 0; boolean inside = false; StringBuilder command = new StringBuilder(); try { while (index < fileContents.length()) { char c = fileContents.charAt(index); if (!inside) { if (c == COMMAND_START.charAt(0) && charCmp(fileContents, index, COMMAND_START)) { inside = true; index += COMMAND_START.length(); command.setLength(0); //clear the command string } else { if (!ssiMediator.getConditionalState().processConditionalCommandsOnly) { writer.write(c); } index++; } } else { if (c == COMMAND_END.charAt(0) && charCmp(fileContents, index, COMMAND_END)) { inside = false; index += COMMAND_END.length(); String strCmd = parseCmd(command); if (debug > 0) { ssiExternalResolver.log( "SSIProcessor.process -- processing command: " + strCmd, null); } String[] paramNames = parseParamNames(command, strCmd .length()); String[] paramValues = parseParamValues(command, strCmd.length(), paramNames.length); //We need to fetch this value each time, since it may // change // during the loop String configErrMsg = ssiMediator.getConfigErrMsg(); SSICommand ssiCommand = commands.get(strCmd.toLowerCase(Locale.ENGLISH)); String errorMessage = null; if (ssiCommand == null) { errorMessage = "Unknown command: " + strCmd; } else if (paramValues == null) { errorMessage = "Error parsing directive parameters."; } else if (paramNames.length != paramValues.length) { errorMessage = "Parameter names count does not match parameter values count on command: " + strCmd; } else { // don't process the command if we are processing // conditional // commands only and the // command is not conditional if (!ssiMediator.getConditionalState().processConditionalCommandsOnly || ssiCommand instanceof SSIConditional) { long lmd = ssiCommand.process(ssiMediator, strCmd, paramNames, paramValues, writer); if (lmd > lastModifiedDate) { lastModifiedDate = lmd; } } } if (errorMessage != null) { ssiExternalResolver.log(errorMessage, null); writer.write(configErrMsg); } } else { command.append(c); index++; } } } } catch (SSIStopProcessingException e) { //If we are here, then we have already stopped processing, so all // is good } return lastModifiedDate; } /** * Parse a StringBuilder and take out the param type token. Called from * requestHandler * * @param cmd * a value of type 'StringBuilder' * @return a value of type 'String[]' */ protected String[] parseParamNames(StringBuilder cmd, int start) { int bIdx = start; int i = 0; int quotes = 0; boolean inside = false; StringBuilder retBuf = new StringBuilder(); while (bIdx < cmd.length()) { if (!inside) { while (bIdx < cmd.length() && isSpace(cmd.charAt(bIdx))) bIdx++; if (bIdx >= cmd.length()) break; inside = !inside; } else { while (bIdx < cmd.length() && cmd.charAt(bIdx) != '=') { retBuf.append(cmd.charAt(bIdx)); bIdx++; } retBuf.append('='); inside = !inside; quotes = 0; boolean escaped = false; for (; bIdx < cmd.length() && quotes != 2; bIdx++) { char c = cmd.charAt(bIdx); // Need to skip escaped characters if (c == '\\' && !escaped) { escaped = true; continue; } if (c == '"' && !escaped) quotes++; escaped = false; } } } StringTokenizer str = new StringTokenizer(retBuf.toString(), "="); String[] retString = new String[str.countTokens()]; while (str.hasMoreTokens()) { retString[i++] = str.nextToken().trim(); } return retString; } /** * Parse a StringBuilder and take out the param token. Called from * requestHandler * * @param cmd * a value of type 'StringBuilder' * @return a value of type 'String[]' */ protected String[] parseParamValues(StringBuilder cmd, int start, int count) { int valIndex = 0; boolean inside = false; String[] vals = new String[count]; StringBuilder sb = new StringBuilder(); char endQuote = 0; for (int bIdx = start; bIdx < cmd.length(); bIdx++) { if (!inside) { while (bIdx < cmd.length() && !isQuote(cmd.charAt(bIdx))) bIdx++; if (bIdx >= cmd.length()) break; inside = !inside; endQuote = cmd.charAt(bIdx); } else { boolean escaped = false; for (; bIdx < cmd.length(); bIdx++) { char c = cmd.charAt(bIdx); // Check for escapes if (c == '\\' && !escaped) { escaped = true; continue; } // If we reach the other " then stop if (c == endQuote && !escaped) break; // Since parsing of attributes and var // substitution is done in separate places, // we need to leave escape in the string if (c == '$' && escaped) sb.append('\\'); escaped = false; sb.append(c); } // If we hit the end without seeing a quote // the signal an error if (bIdx == cmd.length()) return null; vals[valIndex++] = sb.toString(); sb.delete(0, sb.length()); // clear the buffer inside = !inside; } } return vals; } /** * Parse a StringBuilder and take out the command token. Called from * requestHandler * * @param cmd * a value of type 'StringBuilder' * @return a value of type 'String', or null if there is none */ private String parseCmd(StringBuilder cmd) { int firstLetter = -1; int lastLetter = -1; for (int i = 0; i < cmd.length(); i++) { char c = cmd.charAt(i); if (Character.isLetter(c)) { if (firstLetter == -1) { firstLetter = i; } lastLetter = i; } else if (isSpace(c)) { if (lastLetter > -1) { break; } } else { break; } } if (firstLetter == -1) { return ""; } else { return cmd.substring(firstLetter, lastLetter + 1); } } protected boolean charCmp(String buf, int index, String command) { return buf.regionMatches(index, command, 0, command.length()); } protected boolean isSpace(char c) { return c == ' ' || c == '\n' || c == '\t' || c == '\r'; } protected boolean isQuote(char c) { return c == '\'' || c == '\"' || c == '`'; } }tomcat7-7.0.52/java/org/apache/catalina/ssi/ResponseIncludeWrapper.java0000644000175100017510000002121212271471332025754 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ssi; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.TimeZone; import javax.servlet.ServletContext; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import org.apache.tomcat.util.ExceptionUtils; /** * A HttpServletResponseWrapper, used from * SSIServletExternalResolver * * @author Bip Thelin * @author David Becker */ public class ResponseIncludeWrapper extends HttpServletResponseWrapper { /** * The names of some headers we want to capture. */ private static final String CONTENT_TYPE = "content-type"; private static final String LAST_MODIFIED = "last-modified"; private static final DateFormat RFC1123_FORMAT; private static final String RFC1123_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z"; protected long lastModified = -1; private String contentType = null; /** * Our ServletOutputStream */ protected ServletOutputStream captureServletOutputStream; protected ServletOutputStream servletOutputStream; protected PrintWriter printWriter; private ServletContext context; private HttpServletRequest request; static { RFC1123_FORMAT = new SimpleDateFormat(RFC1123_PATTERN, Locale.US); RFC1123_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); } /** * Initialize our wrapper with the current HttpServletResponse and * ServletOutputStream. * * @param context The servlet context * @param request The HttpServletResponse to use * @param response The response to use * @param captureServletOutputStream The ServletOutputStream to use */ public ResponseIncludeWrapper(ServletContext context, HttpServletRequest request, HttpServletResponse response, ServletOutputStream captureServletOutputStream) { super(response); this.context = context; this.request = request; this.captureServletOutputStream = captureServletOutputStream; } /** * Flush the servletOutputStream or printWriter ( only one will be non-null ) * This must be called after a requestDispatcher.include, since we can't * assume that the included servlet flushed its stream. */ public void flushOutputStreamOrWriter() throws IOException { if (servletOutputStream != null) { servletOutputStream.flush(); } if (printWriter != null) { printWriter.flush(); } } /** * Return a printwriter, throws and exception if a OutputStream already * been returned. * * @return a PrintWriter object * @exception java.io.IOException * if the outputstream already been called */ @Override public PrintWriter getWriter() throws java.io.IOException { if (servletOutputStream == null) { if (printWriter == null) { setCharacterEncoding(getCharacterEncoding()); printWriter = new PrintWriter( new OutputStreamWriter(captureServletOutputStream, getCharacterEncoding())); } return printWriter; } throw new IllegalStateException(); } /** * Return a OutputStream, throws and exception if a printwriter already * been returned. * * @return a OutputStream object * @exception java.io.IOException * if the printwriter already been called */ @Override public ServletOutputStream getOutputStream() throws java.io.IOException { if (printWriter == null) { if (servletOutputStream == null) { servletOutputStream = captureServletOutputStream; } return servletOutputStream; } throw new IllegalStateException(); } /** * Returns the value of the last-modified header field. The * result is the number of milliseconds since January 1, 1970 GMT. * * @return the date the resource referenced by this * ResponseIncludeWrapper was last modified, or -1 if not * known. */ public long getLastModified() { if (lastModified == -1) { // javadocs say to return -1 if date not known, if you want another // default, put it here return -1; } return lastModified; } /** * Sets the value of the last-modified header field. * * @param lastModified The number of milliseconds since January 1, 1970 GMT. */ public void setLastModified(long lastModified) { this.lastModified = lastModified; ((HttpServletResponse) getResponse()).setDateHeader(LAST_MODIFIED, lastModified); } /** * Returns the value of the content-type header field. * * @return the content type of the resource referenced by this * ResponseIncludeWrapper, or null if not known. */ @Override public String getContentType() { if (contentType == null) { String url = request.getRequestURI(); String mime = context.getMimeType(url); if (mime != null) { setContentType(mime); } else { // return a safe value setContentType("application/x-octet-stream"); } } return contentType; } /** * Sets the value of the content-type header field. * * @param mime a mime type */ @Override public void setContentType(String mime) { contentType = mime; if (contentType != null) { getResponse().setContentType(contentType); } } @Override public void addDateHeader(String name, long value) { super.addDateHeader(name, value); String lname = name.toLowerCase(Locale.ENGLISH); if (lname.equals(LAST_MODIFIED)) { lastModified = value; } } @Override public void addHeader(String name, String value) { super.addHeader(name, value); String lname = name.toLowerCase(Locale.ENGLISH); if (lname.equals(LAST_MODIFIED)) { try { synchronized(RFC1123_FORMAT) { lastModified = RFC1123_FORMAT.parse(value).getTime(); } } catch (Throwable ignore) { ExceptionUtils.handleThrowable(ignore); } } else if (lname.equals(CONTENT_TYPE)) { contentType = value; } } @Override public void setDateHeader(String name, long value) { super.setDateHeader(name, value); String lname = name.toLowerCase(Locale.ENGLISH); if (lname.equals(LAST_MODIFIED)) { lastModified = value; } } @Override public void setHeader(String name, String value) { super.setHeader(name, value); String lname = name.toLowerCase(Locale.ENGLISH); if (lname.equals(LAST_MODIFIED)) { try { synchronized(RFC1123_FORMAT) { lastModified = RFC1123_FORMAT.parse(value).getTime(); } } catch (Throwable ignore) { ExceptionUtils.handleThrowable(ignore); } } else if (lname.equals(CONTENT_TYPE)) { contentType = value; } } } tomcat7-7.0.52/java/org/apache/catalina/Authenticator.java0000644000175100017510000000561112271471332023332 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; /** * An Authenticator is a component (usually a Valve or Container) that * provides some sort of authentication service. * * @author Craig R. McClanahan */ public interface Authenticator { /** * Authenticate the user making this request, based on the login * configuration of the {@link Context} with which this Authenticator is * associated. Return true if any specified constraint has * been satisfied, or false if we have created a response * challenge already. * * @param request Request we are processing * @param response Response we are populating * * @exception IOException if an input/output error occurs */ public boolean authenticate(Request request, HttpServletResponse response) throws IOException; /** * Authenticate the user making this request, based on the specified * login configuration. Return true if any specified * constraint has been satisfied, or false if we have * created a response challenge already. * * @param request Request we are processing * @param response Response we are populating * @param config Login configuration describing how authentication * should be performed * * @exception IOException if an input/output error occurs * * @deprecated Use {@link #authenticate(Request, HttpServletResponse)}. * This will be removed / have reduced visibility in Tomcat * 8.0.x */ @Deprecated public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException; public void login(String userName, String password, Request request) throws ServletException; public void logout(Request request) throws ServletException; } tomcat7-7.0.52/java/org/apache/catalina/ContainerEvent.java0000644000175100017510000000444312271471332023446 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.EventObject; /** * General event for notifying listeners of significant changes on a Container. * * @author Craig R. McClanahan */ public final class ContainerEvent extends EventObject { private static final long serialVersionUID = 1L; /** * The event data associated with this event. */ private Object data = null; /** * The event type this instance represents. */ private String type = null; /** * Construct a new ContainerEvent with the specified parameters. * * @param container Container on which this event occurred * @param type Event type * @param data Event data */ public ContainerEvent(Container container, String type, Object data) { super(container); this.type = type; this.data = data; } /** * Return the event data of this event. */ public Object getData() { return (this.data); } /** * Return the Container on which this event occurred. */ public Container getContainer() { return (Container) getSource(); } /** * Return the event type of this event. */ public String getType() { return (this.type); } /** * Return a string representation of this event. */ @Override public String toString() { return ("ContainerEvent['" + getContainer() + "','" + getType() + "','" + getData() + "']"); } } tomcat7-7.0.52/java/org/apache/catalina/filters/0000755000175100017510000000000012301126371021314 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/filters/LocalStrings_es.properties0000644000175100017510000000557612271471332026550 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. addDefaultCharset.unsupportedCharset = El conjunto especificado de caracteres [{0}] no se encuentra soportado csrfPrevention.invalidRandomClass = No pude crear fuente al azar usando la clase [{0}] filterbase.noSuchProperty = La propiedad "{0}" no est\u00E1 definida para los filtros del tipo "{1}" http.403 = El acceso al recurso especificado ({0}) ha sido prohibido. expiresFilter.noExpirationConfigured = No se ha configurado expiraci\u00F3n para el requerimiento "{0}" con status de respuesta "{1}" y content-type "{2}" expiresFilter.setExpirationDate = El requerimiento "{0}" con status de respuesta "{1}" y content-type "{2}", pone fecha de expiraci\u00F3n a {3} expiresFilter.startingPointNotFound = Punto de Arranque (access|now|modification|a|m) no hallado en la directiva "{0}" expiresFilter.startingPointInvalid = Punto de arranque inv\u00E1lido (access|now|modification|a|m) "{0}" en la directiva "{1}" expiresFilter.responseAlreadyCommited = El requerimiento "{0}", no puede aplicar ExpiresFilter en respuesta ya acometida. expiresFilter.noExpirationConfiguredForContentType = No se ha hallado configuraci\u00F3n de Expiraci\u00F3n para content-type "{0}" expiresFilter.useMatchingConfiguration = El Uso de {0} coincidente con "{1}" para content-type "{2}" devuelve {3} expiresFilter.useDefaultConfiguration = El uso de {0} por defecto para content-type "{1}" devuelve {2} expiresFilter.unsupportedStartingPoint = No soportado startingPoint "{0}" expiresFilter.unknownParameterIgnored = \u00A1Se ignora el par\u00E1metro desconocido "{0}" con valor "{1}" especificado\! expiresFilter.exceptionProcessingParameter = Excepci\u00F3n al procesar par\u00E1metro de configuraci\u00F3n "{0}"\:"{1}" expiresFilter.filterInitialized = Filtro inicializado con configuraci\u00F3n {0} expiresFilter.expirationHeaderAlreadyDefined = Ya se ha definido cabecera de expiraci\u00F3n para el requerimiento "{0}" con status de respuesta "{1}" y content-type "{2}" expiresFilter.skippedStatusCode = Generaci\u00F3n de cabecera de expiraci\u00F3n saltada para el requerimiento "{0}" con status de respuesta "{1}" y content-type "{2}" tomcat7-7.0.52/java/org/apache/catalina/filters/WebdavFixFilter.java0000644000175100017510000001344612271471332025222 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Filter that attempts to force MS WebDAV clients connecting on port 80 to use * a WebDAV client that actually works. Other workarounds that might help * include: *
      *
    • Specifying the port, even if it is port 80, when trying to * connect.
    • *
    • Cancelling the first authentication dialog box and then trying to * reconnect.
    • *
    * * Generally each different version of the MS client has a different set of * problems. *

    * TODO: Update this filter to recognise specific MS clients and apply the * appropriate workarounds for that particular client *

    * As a filter, this is configured in web.xml like any other Filter. You usually * want to map this filter to whatever your WebDAV servlet is mapped to. *

    * In addition to the issues fixed by this Filter, the following issues have * also been observed that cannot be fixed by this filter. Where possible the * filter will add an message to the logs. *

    * XP x64 SP2 (MiniRedir Version 3790) *

      *
    • Only connects to port 80
    • *
    • Unknown issue means it doesn't work
    • *
    */ public class WebdavFixFilter implements Filter { private static final String LOG_MESSAGE_PREAMBLE = "WebdavFixFilter: Detected client problem: "; /* Start string for all versions */ private static final String UA_MINIDIR_START = "Microsoft-WebDAV-MiniRedir"; /* XP 32-bit SP3 */ private static final String UA_MINIDIR_5_1_2600 = "Microsoft-WebDAV-MiniRedir/5.1.2600"; /* XP 64-bit SP2 */ private static final String UA_MINIDIR_5_2_3790 = "Microsoft-WebDAV-MiniRedir/5.2.3790"; @Override public void init(FilterConfig filterConfig) throws ServletException { // NOOP } @Override public void destroy() { // NOOP } /** * Check for the broken MS WebDAV client and if detected issue a re-direct * that hopefully will cause the non-broken client to be used. */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { chain.doFilter(request, response); return; } HttpServletRequest httpRequest = ((HttpServletRequest) request); HttpServletResponse httpResponse = ((HttpServletResponse) response); String ua = httpRequest.getHeader("User-Agent"); if (ua == null || ua.length() == 0 || !ua.startsWith(UA_MINIDIR_START)) { // No UA or starts with non MS value // Hope everything just works... chain.doFilter(request, response); } else if (ua.startsWith(UA_MINIDIR_5_1_2600)) { // XP 32-bit SP3 - needs redirect with explicit port httpResponse.sendRedirect(buildRedirect(httpRequest)); } else if (ua.startsWith(UA_MINIDIR_5_2_3790)) { // XP 64-bit SP2 if (!"".equals(httpRequest.getContextPath())) { log(request, "XP-x64-SP2 clients only work with the root context"); } // Namespace issue maybe // see http://greenbytes.de/tech/webdav/webdav-redirector-list.html log(request, "XP-x64-SP2 is known not to work with WebDAV Servlet"); chain.doFilter(request, response); } else { // Don't know which MS client it is - try the redirect with an // explicit port in the hope that it moves the client to a different // WebDAV implementation that works httpResponse.sendRedirect(buildRedirect(httpRequest)); } } private String buildRedirect(HttpServletRequest request) { StringBuilder location = new StringBuilder(request.getRequestURL().length()); location.append(request.getScheme()); location.append("://"); location.append(request.getServerName()); location.append(':'); // If we include the port, even if it is 80, then MS clients will use // a WebDAV client that works rather than the MiniRedir that has // problems with BASIC authentication location.append(request.getServerPort()); location.append(request.getRequestURI()); return location.toString(); } private void log(ServletRequest request, String msg) { StringBuilder builder = new StringBuilder(LOG_MESSAGE_PREAMBLE); builder.append(msg); request.getServletContext().log(builder.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/filters/FailedRequestFilter.java0000644000175100017510000000653311656707323026107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometFilter; import org.apache.catalina.comet.CometFilterChain; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Filter that will reject requests if there was a failure during parameter * parsing. This filter can be used to ensure that none parameter values * submitted by client are lost. * *

    * Note that it has side effect that it triggers parameter parsing and thus * consumes the body for POST requests. Parameter parsing does check content * type of the request, so there should not be problems with addresses that use * request.getInputStream() and request.getReader(), * if requests parsed by them do not use standard value for content mime-type. */ public class FailedRequestFilter extends FilterBase implements CometFilter { private static final Log log = LogFactory.getLog(FailedRequestFilter.class); @Override protected Log getLogger() { return log; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!isGoodRequest(request)) { ((HttpServletResponse) response) .sendError(HttpServletResponse.SC_BAD_REQUEST); return; } chain.doFilter(request, response); } @Override public void doFilterEvent(CometEvent event, CometFilterChain chain) throws IOException, ServletException { if (event.getEventType() == CometEvent.EventType.BEGIN && !isGoodRequest(event.getHttpServletRequest())) { event.getHttpServletResponse().sendError( HttpServletResponse.SC_BAD_REQUEST); event.close(); return; } chain.doFilterEvent(event); } private boolean isGoodRequest(ServletRequest request) { // Trigger parsing of parameters request.getParameter("none"); // Detect failure if (request.getAttribute(Globals.PARAMETER_PARSE_FAILED_ATTR) != null) { return false; } return true; } @Override protected boolean isConfigProblemFatal() { return true; } } tomcat7-7.0.52/java/org/apache/catalina/filters/RequestDumperFilter.java0000644000175100017510000002415312271471332026145 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    Implementation of a Filter that logs interesting contents from the * specified Request (before processing) and the corresponding Response * (after processing). It is especially useful in debugging problems * related to headers and cookies.

    * *

    When using this Filter, it is strongly recommended that the * org.apache.catalina.filter.RequestDumperFilter logger is * directed to a dedicated file and that the * org.apache.juli.VerbatimFormmater is used.

    * * @author Craig R. McClanahan */ public class RequestDumperFilter implements Filter { private static final String NON_HTTP_REQ_MSG = "Not available. Non-http request."; private static final String NON_HTTP_RES_MSG = "Not available. Non-http response."; private static final ThreadLocal timestamp = new ThreadLocal() { @Override protected Timestamp initialValue() { return new Timestamp(); } }; /** * The logger for this class. */ private static final Log log = LogFactory.getLog(RequestDumperFilter.class); /** * Log the interesting request parameters, invoke the next Filter in the * sequence, and log the interesting response parameters. * * @param request The servlet request to be processed * @param response The servlet response to be created * @param chain The filter chain being processed * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest hRequest = null; HttpServletResponse hResponse = null; if (request instanceof HttpServletRequest) { hRequest = (HttpServletRequest) request; } if (response instanceof HttpServletResponse) { hResponse = (HttpServletResponse) response; } // Log pre-service information doLog("START TIME ", getTimestamp()); if (hRequest == null) { doLog(" requestURI", NON_HTTP_REQ_MSG); doLog(" authType", NON_HTTP_REQ_MSG); } else { doLog(" requestURI", hRequest.getRequestURI()); doLog(" authType", hRequest.getAuthType()); } doLog(" characterEncoding", request.getCharacterEncoding()); doLog(" contentLength", Integer.valueOf(request.getContentLength()).toString()); doLog(" contentType", request.getContentType()); if (hRequest == null) { doLog(" contextPath", NON_HTTP_REQ_MSG); doLog(" cookie", NON_HTTP_REQ_MSG); doLog(" header", NON_HTTP_REQ_MSG); } else { doLog(" contextPath", hRequest.getContextPath()); Cookie cookies[] = hRequest.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) { doLog(" cookie", cookies[i].getName() + "=" + cookies[i].getValue()); } } Enumeration hnames = hRequest.getHeaderNames(); while (hnames.hasMoreElements()) { String hname = hnames.nextElement(); Enumeration hvalues = hRequest.getHeaders(hname); while (hvalues.hasMoreElements()) { String hvalue = hvalues.nextElement(); doLog(" header", hname + "=" + hvalue); } } } doLog(" locale", request.getLocale().toString()); if (hRequest == null) { doLog(" method", NON_HTTP_REQ_MSG); } else { doLog(" method", hRequest.getMethod()); } Enumeration pnames = request.getParameterNames(); while (pnames.hasMoreElements()) { String pname = pnames.nextElement(); String pvalues[] = request.getParameterValues(pname); StringBuilder result = new StringBuilder(pname); result.append('='); for (int i = 0; i < pvalues.length; i++) { if (i > 0) { result.append(", "); } result.append(pvalues[i]); } doLog(" parameter", result.toString()); } if (hRequest == null) { doLog(" pathInfo", NON_HTTP_REQ_MSG); } else { doLog(" pathInfo", hRequest.getPathInfo()); } doLog(" protocol", request.getProtocol()); if (hRequest == null) { doLog(" queryString", NON_HTTP_REQ_MSG); } else { doLog(" queryString", hRequest.getQueryString()); } doLog(" remoteAddr", request.getRemoteAddr()); doLog(" remoteHost", request.getRemoteHost()); if (hRequest == null) { doLog(" remoteUser", NON_HTTP_REQ_MSG); doLog("requestedSessionId", NON_HTTP_REQ_MSG); } else { doLog(" remoteUser", hRequest.getRemoteUser()); doLog("requestedSessionId", hRequest.getRequestedSessionId()); } doLog(" scheme", request.getScheme()); doLog(" serverName", request.getServerName()); doLog(" serverPort", Integer.valueOf(request.getServerPort()).toString()); if (hRequest == null) { doLog(" servletPath", NON_HTTP_REQ_MSG); } else { doLog(" servletPath", hRequest.getServletPath()); } doLog(" isSecure", Boolean.valueOf(request.isSecure()).toString()); doLog("------------------", "--------------------------------------------"); // Perform the request chain.doFilter(request, response); // Log post-service information doLog("------------------", "--------------------------------------------"); if (hRequest == null) { doLog(" authType", NON_HTTP_REQ_MSG); } else { doLog(" authType", hRequest.getAuthType()); } doLog(" contentType", response.getContentType()); if (hResponse == null) { doLog(" header", NON_HTTP_RES_MSG); } else { Iterable rhnames = hResponse.getHeaderNames(); for (String rhname : rhnames) { Iterable rhvalues = hResponse.getHeaders(rhname); for (String rhvalue : rhvalues) { doLog(" header", rhname + "=" + rhvalue); } } } if (hRequest == null) { doLog(" remoteUser", NON_HTTP_REQ_MSG); } else { doLog(" remoteUser", hRequest.getRemoteUser()); } if (hResponse == null) { doLog(" remoteUser", NON_HTTP_RES_MSG); } else { doLog(" status", Integer.valueOf(hResponse.getStatus()).toString()); } doLog("END TIME ", getTimestamp()); doLog("==================", "============================================"); } private void doLog(String attribute, String value) { StringBuilder sb = new StringBuilder(80); sb.append(Thread.currentThread().getName()); sb.append(' '); sb.append(attribute); sb.append('='); sb.append(value); log.info(sb.toString()); } private String getTimestamp() { Timestamp ts = timestamp.get(); long currentTime = System.currentTimeMillis(); if ((ts.date.getTime() + 999) < currentTime) { ts.date.setTime(currentTime - (currentTime % 1000)); ts.update(); } return ts.dateString; } @Override public void init(FilterConfig filterConfig) throws ServletException { // NOOP } @Override public void destroy() { // NOOP } private static final class Timestamp { private final Date date = new Date(0); private final SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"); private String dateString = format.format(date); private void update() { dateString = format.format(date); } } } tomcat7-7.0.52/java/org/apache/catalina/filters/RemoteAddrFilter.java0000644000175100017510000000645412271471332025372 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometFilterChain; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Concrete implementation of RequestFilter that filters * based on the string representation of the remote client's IP address. * * @author Craig R. McClanahan * */ public final class RemoteAddrFilter extends RequestFilter { // ----------------------------------------------------- Instance Variables private static final Log log = LogFactory.getLog(RemoteAddrFilter.class); // ------------------------------------------------------------- Properties // --------------------------------------------------------- Public Methods /** * Extract the desired request property, and pass it (along with the * specified request and response objects and associated filter chain) to * the protected process() method to perform the actual * filtering. * * @param request The servlet request to be processed * @param response The servlet response to be created * @param chain The filter chain for this request * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { process(request.getRemoteAddr(), request, response, chain); } /** * Extract the desired request property, and pass it (along with the comet * event and filter chain) to the protected process() method * to perform the actual filtering. * * @param event The comet event to be processed * @param chain The filter chain for this event * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doFilterEvent(CometEvent event, CometFilterChain chain) throws IOException, ServletException { processCometEvent(event.getHttpServletRequest().getRemoteAddr(), event, chain); } @Override protected Log getLogger() { return log; } } tomcat7-7.0.52/java/org/apache/catalina/filters/RemoteIpFilter.java0000644000175100017510000012162412267226511025067 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Pattern; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.AccessLog; import org.apache.catalina.Globals; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    * Servlet filter to integrate "X-Forwarded-For" and "X-Forwarded-Proto" HTTP headers. *

    *

    * Most of the design of this Servlet Filter is a port of mod_remoteip, this servlet filter replaces the apparent client remote * IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. * "X-Forwarded-For"). *

    *

    * Another feature of this servlet filter is to replace the apparent scheme (http/https) and server port with the scheme presented by a * proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto"). *

    *

    * This servlet filter proceeds as follows: *

    *

    * If the incoming request.getRemoteAddr() matches the servlet filter's list of internal proxies : *

      *
    • Loop on the comma delimited list of IPs and hostnames passed by the preceding load balancer or proxy in the given request's Http * header named $remoteIpHeader (default value x-forwarded-for). Values are processed in right-to-left order.
    • *
    • For each ip/host of the list: *
        *
      • if it matches the internal proxies list, the ip/host is swallowed
      • *
      • if it matches the trusted proxies list, the ip/host is added to the created proxies header
      • *
      • otherwise, the ip/host is declared to be the remote ip and looping is stopped.
      • *
      *
    • *
    • If the request http header named $protocolHeader (e.g. x-forwarded-for) equals to the value of * protocolHeaderHttpsValue configuration parameter (default https) then request.isSecure = true, * request.scheme = https and request.serverPort = 443. Note that 443 can be overwritten with the * $httpsServerPort configuration parameter.
    • *
    *

    *

    * Configuration parameters: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    XForwardedFilter propertyDescriptionEquivalent mod_remoteip directiveFormatDefault Value
    remoteIpHeaderName of the Http Header read by this servlet filter that holds the list of traversed IP addresses starting from the requesting client * RemoteIPHeaderCompliant http header namex-forwarded-for
    internalProxiesRegular expression that matches the IP addresses of internal proxies. * If they appear in the remoteIpHeader value, they will be * trusted and will not appear * in the proxiesHeader valueRemoteIPInternalProxyRegular expression (in the syntax supported by * {@link java.util.regex.Pattern java.util.regex})10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3}
    * By default, 10/8, 192.168/16, 169.254/16 and 127/8 are allowed ; 172.16/12 has not been enabled by default because it is complex to * describe with regular expressions
    proxiesHeaderName of the http header created by this servlet filter to hold the list of proxies that have been processed in the incoming * remoteIpHeaderRemoteIPProxiesHeaderCompliant http header namex-forwarded-by
    trustedProxiesRegular expression that matches the IP addresses of trusted proxies. * If they appear in the remoteIpHeader value, they will be * trusted and will appear in the proxiesHeader valueRemoteIPTrustedProxyRegular expression (in the syntax supported by * {@link java.util.regex.Pattern java.util.regex}) 
    protocolHeaderName of the http header read by this servlet filter that holds the flag that this requestN/ACompliant http header name like X-Forwarded-Proto, X-Forwarded-Ssl or Front-End-Httpsnull
    protocolHeaderHttpsValueValue of the protocolHeader to indicate that it is an Https requestN/AString like https or ONhttps
    httpServerPortValue returned by {@link ServletRequest#getServerPort()} when the protocolHeader indicates http protocolN/Ainteger80
    httpsServerPortValue returned by {@link ServletRequest#getServerPort()} when the protocolHeader indicates https protocolN/Ainteger443
    *

    *

    *

    * Regular expression vs. IP address blocks: mod_remoteip allows to use address blocks (e.g. * 192.168/16) to configure RemoteIPInternalProxy and RemoteIPTrustedProxy ; as the JVM doesn't have a * library similar to apr_ipsubnet_test, we rely on * regular expressions. *

    *
    *

    * Sample with internal proxies *

    *

    * XForwardedFilter configuration: *

    *
     * <filter>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class>
     *    <init-param>
     *       <param-name>internalProxies</param-name>
     *       <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpHeader</param-name>
     *       <param-value>x-forwarded-for</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpProxiesHeader</param-name>
     *       <param-value>x-forwarded-by</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>protocolHeader</param-name>
     *       <param-value>x-forwarded-proto</param-value>
     *    </init-param>
     * </filter>
     * 
     * <filter-mapping>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <url-pattern>/*</url-pattern>
     *    <dispatcher>REQUEST</dispatcher>
     * </filter-mapping>
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpFilterValue After RemoteIpFilter
    request.remoteAddr192.168.0.10140.211.11.130
    request.header['x-forwarded-for']140.211.11.130, 192.168.0.10null
    request.header['x-forwarded-by']nullnull
    request.header['x-forwarded-proto']httpshttps
    request.schemehttphttps
    request.securefalsetrue
    request.serverPort80443
    * Note : x-forwarded-by header is null because only internal proxies as been traversed by the request. * x-forwarded-by is null because all the proxies are trusted or internal. *

    *
    *

    * Sample with trusted proxies *

    *

    * RemoteIpFilter configuration: *

    *
     * <filter>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class>
     *    <init-param>
     *       <param-name>internalProxies</param-name>
     *       <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpHeader</param-name>
     *       <param-value>x-forwarded-for</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpProxiesHeader</param-name>
     *       <param-value>x-forwarded-by</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>trustedProxies</param-name>
     *       <param-value>proxy1|proxy2</param-value>
     *    </init-param>
     * </filter>
     * 
     * <filter-mapping>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <url-pattern>/*</url-pattern>
     *    <dispatcher>REQUEST</dispatcher>
     * </filter-mapping>
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpFilterValue After RemoteIpFilter
    request.remoteAddr192.168.0.10140.211.11.130
    request.header['x-forwarded-for']140.211.11.130, proxy1, proxy2null
    request.header['x-forwarded-by']nullproxy1, proxy2
    * Note : proxy1 and proxy2 are both trusted proxies that come in x-forwarded-for header, they both * are migrated in x-forwarded-by header. x-forwarded-by is null because all the proxies are trusted or internal. *

    *
    *

    * Sample with internal and trusted proxies *

    *

    * RemoteIpFilter configuration: *

    *
     * <filter>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class>
     *    <init-param>
     *       <param-name>internalProxies</param-name>
     *       <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpHeader</param-name>
     *       <param-value>x-forwarded-for</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpProxiesHeader</param-name>
     *       <param-value>x-forwarded-by</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>trustedProxies</param-name>
     *       <param-value>proxy1|proxy2</param-value>
     *    </init-param>
     * </filter>
     * 
     * <filter-mapping>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <url-pattern>/*</url-pattern>
     *    <dispatcher>REQUEST</dispatcher>
     * </filter-mapping>
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpFilterValue After RemoteIpFilter
    request.remoteAddr192.168.0.10140.211.11.130
    request.header['x-forwarded-for']140.211.11.130, proxy1, proxy2, 192.168.0.10null
    request.header['x-forwarded-by']nullproxy1, proxy2
    * Note : proxy1 and proxy2 are both trusted proxies that come in x-forwarded-for header, they both * are migrated in x-forwarded-by header. As 192.168.0.10 is an internal proxy, it does not appear in * x-forwarded-by. x-forwarded-by is null because all the proxies are trusted or internal. *

    *
    *

    * Sample with an untrusted proxy *

    *

    * RemoteIpFilter configuration: *

    *
     * <filter>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <filter-class>org.apache.catalina.filters.RemoteIpFilter</filter-class>
     *    <init-param>
     *       <param-name>internalProxies</param-name>
     *       <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpHeader</param-name>
     *       <param-value>x-forwarded-for</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>remoteIpProxiesHeader</param-name>
     *       <param-value>x-forwarded-by</param-value>
     *    </init-param>
     *    <init-param>
     *       <param-name>trustedProxies</param-name>
     *       <param-value>proxy1|proxy2</param-value>
     *    </init-param>
     * </filter>
     * 
     * <filter-mapping>
     *    <filter-name>RemoteIpFilter</filter-name>
     *    <url-pattern>/*</url-pattern>
     *    <dispatcher>REQUEST</dispatcher>
     * </filter-mapping>
    *

    * Request values: * * * * * * * * * * * * * * * * * * * * * *
    propertyValue Before RemoteIpFilterValue After RemoteIpFilter
    request.remoteAddr192.168.0.10untrusted-proxy
    request.header['x-forwarded-for']140.211.11.130, untrusted-proxy, proxy1140.211.11.130
    request.header['x-forwarded-by']nullproxy1
    * Note : x-forwarded-by holds the trusted proxy proxy1. x-forwarded-by holds * 140.211.11.130 because untrusted-proxy is not trusted and thus, we can not trust that * untrusted-proxy is the actual remote ip. request.remoteAddr is untrusted-proxy that is an IP * verified by proxy1. *

    *
    */ public class RemoteIpFilter implements Filter { public static class XForwardedRequest extends HttpServletRequestWrapper { static final ThreadLocal threadLocalDateFormats = new ThreadLocal() { @Override protected SimpleDateFormat[] initialValue() { return new SimpleDateFormat[] { new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) }; } }; protected Map> headers; protected int localPort; protected String remoteAddr; protected String remoteHost; protected String scheme; protected boolean secure; protected int serverPort; public XForwardedRequest(HttpServletRequest request) { super(request); this.localPort = request.getLocalPort(); this.remoteAddr = request.getRemoteAddr(); this.remoteHost = request.getRemoteHost(); this.scheme = request.getScheme(); this.secure = request.isSecure(); this.serverPort = request.getServerPort(); headers = new HashMap>(); for (Enumeration headerNames = request.getHeaderNames(); headerNames.hasMoreElements();) { String header = headerNames.nextElement(); headers.put(header, Collections.list(request.getHeaders(header))); } } @Override public long getDateHeader(String name) { String value = getHeader(name); if (value == null) { return -1; } DateFormat[] dateFormats = threadLocalDateFormats.get(); Date date = null; for (int i = 0; ((i < dateFormats.length) && (date == null)); i++) { DateFormat dateFormat = dateFormats[i]; try { date = dateFormat.parse(value); } catch (Exception ParseException) { // Ignore } } if (date == null) { throw new IllegalArgumentException(value); } return date.getTime(); } @Override public String getHeader(String name) { Map.Entry> header = getHeaderEntry(name); if (header == null || header.getValue() == null || header.getValue().isEmpty()) { return null; } return header.getValue().get(0); } protected Map.Entry> getHeaderEntry(String name) { for (Map.Entry> entry : headers.entrySet()) { if (entry.getKey().equalsIgnoreCase(name)) { return entry; } } return null; } @Override public Enumeration getHeaderNames() { return Collections.enumeration(headers.keySet()); } @Override public Enumeration getHeaders(String name) { Map.Entry> header = getHeaderEntry(name); if (header == null || header.getValue() == null) { return Collections.enumeration(Collections.emptyList()); } return Collections.enumeration(header.getValue()); } @Override public int getIntHeader(String name) { String value = getHeader(name); if (value == null) { return -1; } return Integer.parseInt(value); } @Override public int getLocalPort() { return localPort; } @Override public String getRemoteAddr() { return this.remoteAddr; } @Override public String getRemoteHost() { return this.remoteHost; } @Override public String getScheme() { return scheme; } @Override public int getServerPort() { return serverPort; } @Override public boolean isSecure() { return secure; } public void removeHeader(String name) { Map.Entry> header = getHeaderEntry(name); if (header != null) { headers.remove(header.getKey()); } } public void setHeader(String name, String value) { List values = Arrays.asList(value); Map.Entry> header = getHeaderEntry(name); if (header == null) { headers.put(name, values); } else { header.setValue(values); } } public void setLocalPort(int localPort) { this.localPort = localPort; } public void setRemoteAddr(String remoteAddr) { this.remoteAddr = remoteAddr; } public void setRemoteHost(String remoteHost) { this.remoteHost = remoteHost; } public void setScheme(String scheme) { this.scheme = scheme; } public void setSecure(boolean secure) { this.secure = secure; } public void setServerPort(int serverPort) { this.serverPort = serverPort; } } /** * {@link Pattern} for a comma delimited string that support whitespace characters */ private static final Pattern commaSeparatedValuesPattern = Pattern.compile("\\s*,\\s*"); protected static final String HTTP_SERVER_PORT_PARAMETER = "httpServerPort"; protected static final String HTTPS_SERVER_PORT_PARAMETER = "httpsServerPort"; protected static final String INTERNAL_PROXIES_PARAMETER = "internalProxies"; /** * Logger */ private static final Log log = LogFactory.getLog(RemoteIpFilter.class); protected static final String PROTOCOL_HEADER_PARAMETER = "protocolHeader"; protected static final String PROTOCOL_HEADER_HTTPS_VALUE_PARAMETER = "protocolHeaderHttpsValue"; protected static final String PORT_HEADER_PARAMETER = "portHeader"; protected static final String CHANGE_LOCAL_PORT_PARAMETER = "changeLocalPort"; protected static final String PROXIES_HEADER_PARAMETER = "proxiesHeader"; protected static final String REMOTE_IP_HEADER_PARAMETER = "remoteIpHeader"; protected static final String TRUSTED_PROXIES_PARAMETER = "trustedProxies"; /** * Convert a given comma delimited list of regular expressions into an array of String * * @return array of patterns (non null) */ protected static String[] commaDelimitedListToStringArray(String commaDelimitedStrings) { return (commaDelimitedStrings == null || commaDelimitedStrings.length() == 0) ? new String[0] : commaSeparatedValuesPattern .split(commaDelimitedStrings); } /** * Convert an array of strings in a comma delimited string */ protected static String listToCommaDelimitedString(List stringList) { if (stringList == null) { return ""; } StringBuilder result = new StringBuilder(); for (Iterator it = stringList.iterator(); it.hasNext();) { Object element = it.next(); if (element != null) { result.append(element); if (it.hasNext()) { result.append(", "); } } } return result.toString(); } /** * @see #setHttpServerPort(int) */ private int httpServerPort = 80; /** * @see #setHttpsServerPort(int) */ private int httpsServerPort = 443; /** * @see #setInternalProxies(String) */ private Pattern internalProxies = Pattern.compile( "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" + "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" + "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" + "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); /** * @see #setProtocolHeader(String) */ private String protocolHeader = null; private String protocolHeaderHttpsValue = "https"; private String portHeader = null; private boolean changeLocalPort = false; /** * @see #setProxiesHeader(String) */ private String proxiesHeader = "X-Forwarded-By"; /** * @see #setRemoteIpHeader(String) */ private String remoteIpHeader = "X-Forwarded-For"; /** * @see #setRequestAttributesEnabled(boolean) */ private boolean requestAttributesEnabled = true; /** * @see #setTrustedProxies(String) */ private Pattern trustedProxies = null; @Override public void destroy() { // NOOP } public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { if (internalProxies != null && internalProxies.matcher(request.getRemoteAddr()).matches()) { String remoteIp = null; // In java 6, proxiesHeaderValue should be declared as a java.util.Deque LinkedList proxiesHeaderValue = new LinkedList(); StringBuilder concatRemoteIpHeaderValue = new StringBuilder(); for (Enumeration e = request.getHeaders(remoteIpHeader); e.hasMoreElements();) { if (concatRemoteIpHeaderValue.length() > 0) { concatRemoteIpHeaderValue.append(", "); } concatRemoteIpHeaderValue.append(e.nextElement()); } String[] remoteIpHeaderValue = commaDelimitedListToStringArray(concatRemoteIpHeaderValue.toString()); int idx; // loop on remoteIpHeaderValue to find the first trusted remote ip and to build the proxies chain for (idx = remoteIpHeaderValue.length - 1; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; remoteIp = currentRemoteIp; if (internalProxies.matcher(currentRemoteIp).matches()) { // do nothing, internalProxies IPs are not appended to the } else if (trustedProxies != null && trustedProxies.matcher(currentRemoteIp).matches()) { proxiesHeaderValue.addFirst(currentRemoteIp); } else { idx--; // decrement idx because break statement doesn't do it break; } } // continue to loop on remoteIpHeaderValue to build the new value of the remoteIpHeader LinkedList newRemoteIpHeaderValue = new LinkedList(); for (; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; newRemoteIpHeaderValue.addFirst(currentRemoteIp); } XForwardedRequest xRequest = new XForwardedRequest(request); if (remoteIp != null) { xRequest.setRemoteAddr(remoteIp); xRequest.setRemoteHost(remoteIp); if (proxiesHeaderValue.size() == 0) { xRequest.removeHeader(proxiesHeader); } else { String commaDelimitedListOfProxies = listToCommaDelimitedString(proxiesHeaderValue); xRequest.setHeader(proxiesHeader, commaDelimitedListOfProxies); } if (newRemoteIpHeaderValue.size() == 0) { xRequest.removeHeader(remoteIpHeader); } else { String commaDelimitedRemoteIpHeaderValue = listToCommaDelimitedString(newRemoteIpHeaderValue); xRequest.setHeader(remoteIpHeader, commaDelimitedRemoteIpHeaderValue); } } if (protocolHeader != null) { String protocolHeaderValue = request.getHeader(protocolHeader); if (protocolHeaderValue == null) { // don't modify the secure,scheme and serverPort attributes of the request } else if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) { xRequest.setSecure(true); xRequest.setScheme("https"); setPorts(xRequest, httpsServerPort); } else { xRequest.setSecure(false); xRequest.setScheme("http"); setPorts(xRequest, httpServerPort); } } if (log.isDebugEnabled()) { log.debug("Incoming request " + request.getRequestURI() + " with originalRemoteAddr '" + request.getRemoteAddr() + "', originalRemoteHost='" + request.getRemoteHost() + "', originalSecure='" + request.isSecure() + "', originalScheme='" + request.getScheme() + "', original[" + remoteIpHeader + "]='" + concatRemoteIpHeaderValue + "', original[" + protocolHeader + "]='" + (protocolHeader == null ? null : request.getHeader(protocolHeader)) + "' will be seen as newRemoteAddr='" + xRequest.getRemoteAddr() + "', newRemoteHost='" + xRequest.getRemoteHost() + "', newScheme='" + xRequest.getScheme() + "', newSecure='" + xRequest.isSecure() + "', new[" + remoteIpHeader + "]='" + xRequest.getHeader(remoteIpHeader) + "', new[" + proxiesHeader + "]='" + xRequest.getHeader(proxiesHeader) + "'"); } if (requestAttributesEnabled) { request.setAttribute(AccessLog.REMOTE_ADDR_ATTRIBUTE, xRequest.getRemoteAddr()); request.setAttribute(Globals.REMOTE_ADDR_ATTRIBUTE, xRequest.getRemoteAddr()); request.setAttribute(AccessLog.REMOTE_HOST_ATTRIBUTE, xRequest.getRemoteHost()); request.setAttribute(AccessLog.PROTOCOL_ATTRIBUTE, xRequest.getProtocol()); request.setAttribute(AccessLog.SERVER_PORT_ATTRIBUTE, Integer.valueOf(xRequest.getServerPort())); } chain.doFilter(xRequest, response); } else { if (log.isDebugEnabled()) { log.debug("Skip RemoteIpFilter for request " + request.getRequestURI() + " with originalRemoteAddr '" + request.getRemoteAddr() + "'"); } chain.doFilter(request, response); } } private void setPorts(XForwardedRequest xrequest, int defaultPort) { int port = defaultPort; if (getPortHeader() != null) { String portHeaderValue = xrequest.getHeader(getPortHeader()); if (portHeaderValue != null) { try { port = Integer.parseInt(portHeaderValue); } catch (NumberFormatException nfe) { log.debug("Invalid port value [" + portHeaderValue + "] provided in header [" + getPortHeader() + "]"); } } } xrequest.setServerPort(port); if (isChangeLocalPort()) { xrequest.setLocalPort(port); } } /** * Wrap the incoming request in a {@link XForwardedRequest} if the http header x-forwareded-for is not empty. */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain); } else { chain.doFilter(request, response); } } public boolean isChangeLocalPort() { return changeLocalPort; } public int getHttpsServerPort() { return httpsServerPort; } public Pattern getInternalProxies() { return internalProxies; } public String getProtocolHeader() { return protocolHeader; } public String getPortHeader() { return portHeader; } public String getProtocolHeaderHttpsValue() { return protocolHeaderHttpsValue; } public String getProxiesHeader() { return proxiesHeader; } public String getRemoteIpHeader() { return remoteIpHeader; } /** * @see #setRequestAttributesEnabled(boolean) * @return true if the attributes will be logged, otherwise * false */ public boolean getRequestAttributesEnabled() { return requestAttributesEnabled; } public Pattern getTrustedProxies() { return trustedProxies; } @Override public void init(FilterConfig filterConfig) throws ServletException { if (filterConfig.getInitParameter(INTERNAL_PROXIES_PARAMETER) != null) { setInternalProxies(filterConfig.getInitParameter(INTERNAL_PROXIES_PARAMETER)); } if (filterConfig.getInitParameter(PROTOCOL_HEADER_PARAMETER) != null) { setProtocolHeader(filterConfig.getInitParameter(PROTOCOL_HEADER_PARAMETER)); } if (filterConfig.getInitParameter(PROTOCOL_HEADER_HTTPS_VALUE_PARAMETER) != null) { setProtocolHeaderHttpsValue(filterConfig.getInitParameter(PROTOCOL_HEADER_HTTPS_VALUE_PARAMETER)); } if (filterConfig.getInitParameter(PORT_HEADER_PARAMETER) != null) { setPortHeader(filterConfig.getInitParameter(PORT_HEADER_PARAMETER)); } if (filterConfig.getInitParameter(CHANGE_LOCAL_PORT_PARAMETER) != null) { setChangeLocalPort(Boolean.parseBoolean(filterConfig.getInitParameter(CHANGE_LOCAL_PORT_PARAMETER))); } if (filterConfig.getInitParameter(PROXIES_HEADER_PARAMETER) != null) { setProxiesHeader(filterConfig.getInitParameter(PROXIES_HEADER_PARAMETER)); } if (filterConfig.getInitParameter(REMOTE_IP_HEADER_PARAMETER) != null) { setRemoteIpHeader(filterConfig.getInitParameter(REMOTE_IP_HEADER_PARAMETER)); } if (filterConfig.getInitParameter(TRUSTED_PROXIES_PARAMETER) != null) { setTrustedProxies(filterConfig.getInitParameter(TRUSTED_PROXIES_PARAMETER)); } if (filterConfig.getInitParameter(HTTP_SERVER_PORT_PARAMETER) != null) { try { setHttpServerPort(Integer.parseInt(filterConfig.getInitParameter(HTTP_SERVER_PORT_PARAMETER))); } catch (NumberFormatException e) { throw new NumberFormatException("Illegal " + HTTP_SERVER_PORT_PARAMETER + " : " + e.getMessage()); } } if (filterConfig.getInitParameter(HTTPS_SERVER_PORT_PARAMETER) != null) { try { setHttpsServerPort(Integer.parseInt(filterConfig.getInitParameter(HTTPS_SERVER_PORT_PARAMETER))); } catch (NumberFormatException e) { throw new NumberFormatException("Illegal " + HTTPS_SERVER_PORT_PARAMETER + " : " + e.getMessage()); } } } /** *

    * If true, the return values for both {@link * ServletRequest#getLocalPort()} and {@link ServletRequest#getServerPort()} * wil be modified by this Filter rather than just * {@link ServletRequest#getServerPort()}. *

    *

    * Default value : false *

    */ public void setChangeLocalPort(boolean changeLocalPort) { this.changeLocalPort = changeLocalPort; } /** *

    * Server Port value if the {@link #protocolHeader} indicates HTTP (i.e. {@link #protocolHeader} is not null and * has a value different of {@link #protocolHeaderHttpsValue}). *

    *

    * Default value : 80 *

    */ public void setHttpServerPort(int httpServerPort) { this.httpServerPort = httpServerPort; } /** *

    * Server Port value if the {@link #protocolHeader} indicates HTTPS *

    *

    * Default value : 443 *

    */ public void setHttpsServerPort(int httpsServerPort) { this.httpsServerPort = httpsServerPort; } /** *

    * Regular expression that defines the internal proxies. *

    *

    * Default value : 10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|169\.254.\d{1,3}.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3} *

    */ public void setInternalProxies(String internalProxies) { if (internalProxies == null || internalProxies.length() == 0) { this.internalProxies = null; } else { this.internalProxies = Pattern.compile(internalProxies); } } /** *

    * Header that holds the incoming port, usally named * X-Forwarded-Port. If null, * {@link #httpServerPort} or {@link #httpsServerPort} will be used. *

    *

    * Default value : null *

    */ public void setPortHeader(String portHeader) { this.portHeader = portHeader; } /** *

    * Header that holds the incoming protocol, usally named X-Forwarded-Proto. If null, request.scheme and * request.secure will not be modified. *

    *

    * Default value : null *

    */ public void setProtocolHeader(String protocolHeader) { this.protocolHeader = protocolHeader; } /** *

    * Case insensitive value of the protocol header to indicate that the incoming http request uses HTTPS. *

    *

    * Default value : https *

    */ public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) { this.protocolHeaderHttpsValue = protocolHeaderHttpsValue; } /** *

    * The proxiesHeader directive specifies a header into which mod_remoteip will collect a list of all of the intermediate client IP * addresses trusted to resolve the actual remote IP. Note that intermediate RemoteIPTrustedProxy addresses are recorded in this header, * while any intermediate RemoteIPInternalProxy addresses are discarded. *

    *

    * Name of the http header that holds the list of trusted proxies that has been traversed by the http request. *

    *

    * The value of this header can be comma delimited. *

    *

    * Default value : X-Forwarded-By *

    */ public void setProxiesHeader(String proxiesHeader) { this.proxiesHeader = proxiesHeader; } /** *

    * Name of the http header from which the remote ip is extracted. *

    *

    * The value of this header can be comma delimited. *

    *

    * Default value : X-Forwarded-For *

    */ public void setRemoteIpHeader(String remoteIpHeader) { this.remoteIpHeader = remoteIpHeader; } /** * Should this filter set request attributes for IP address, Hostname, * protocol and port used for the request? This are typically used in * conjunction with an {@link AccessLog} which will otherwise log the * original values. Default is true. * * The attributes set are: *
      *
    • org.apache.catalina.AccessLog.RemoteAddr
    • *
    • org.apache.catalina.AccessLog.RemoteHost
    • *
    • org.apache.catalina.AccessLog.Protocol
    • *
    • org.apache.catalina.AccessLog.ServerPort
    • *
    • org.apache.tomcat.remoteAddr
    • *
    * * @param requestAttributesEnabled true causes the attributes * to be set, false disables * the setting of the attributes. */ public void setRequestAttributesEnabled(boolean requestAttributesEnabled) { this.requestAttributesEnabled = requestAttributesEnabled; } /** *

    * Regular expression defining proxies that are trusted when they appear in * the {@link #remoteIpHeader} header. *

    *

    * Default value : empty list, no external proxy is trusted. *

    */ public void setTrustedProxies(String trustedProxies) { if (trustedProxies == null || trustedProxies.length() == 0) { this.trustedProxies = null; } else { this.trustedProxies = Pattern.compile(trustedProxies); } } } tomcat7-7.0.52/java/org/apache/catalina/filters/FilterBase.java0000644000175100017510000000522012271471332024204 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import org.apache.juli.logging.Log; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.res.StringManager; /** * Base class for filters that provides generic initialisation and a simple * no-op destruction. * * @author xxd * */ public abstract class FilterBase implements Filter { protected static final StringManager sm = StringManager.getManager(Constants.Package); protected abstract Log getLogger(); @Override public void init(FilterConfig filterConfig) throws ServletException { Enumeration paramNames = filterConfig.getInitParameterNames(); while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); if (!IntrospectionUtils.setProperty(this, paramName, filterConfig.getInitParameter(paramName))) { String msg = sm.getString("filterbase.noSuchProperty", paramName, this.getClass().getName()); if (isConfigProblemFatal()) { throw new ServletException(msg); } else { getLogger().warn(msg); } } } } @Override public void destroy() { // NOOP } /** * Determines if an exception when calling a setter or an unknown * configuration attribute triggers the failure of the this filter which in * turn will prevent the web application from starting. * * @return true if a problem should trigger the failure of this * filter, else false */ protected boolean isConfigProblemFatal() { return false; } } tomcat7-7.0.52/java/org/apache/catalina/filters/CorsFilter.java0000644000175100017510000012316012153605676024255 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** *

    * A {@link Filter} that enable client-side cross-origin requests by * implementing W3C's CORS (Cross-Origin Resource * Sharing) specification for resources. Each {@link HttpServletRequest} * request is inspected as per specification, and appropriate response headers * are added to {@link HttpServletResponse}. *

    * *

    * By default, it also sets following request attributes, that help to * determine the nature of the request downstream. *

      *
    • cors.isCorsRequest: Flag to determine if the request is a CORS * request. Set to true if a CORS request; false * otherwise.
    • *
    • cors.request.origin: The Origin URL, i.e. the URL of the page from * where the request is originated.
    • *
    • * cors.request.type: Type of request. Possible values: *
        *
      • SIMPLE: A request which is not preceded by a pre-flight request.
      • *
      • ACTUAL: A request which is preceded by a pre-flight request.
      • *
      • PRE_FLIGHT: A pre-flight request.
      • *
      • NOT_CORS: A normal same-origin request.
      • *
      • INVALID_CORS: A cross-origin request which is invalid.
      • *
      *
    • *
    • cors.request.headers: Request headers sent as * 'Access-Control-Request-Headers' header, for pre-flight request.
    • *
    *

    * * @see CORS specification * */ public final class CorsFilter implements Filter { private static final Log log = LogFactory.getLog(CorsFilter.class); private static final StringManager sm = StringManager.getManager(Constants.Package); /** * A {@link Collection} of origins consisting of zero or more origins that * are allowed access to the resource. */ private final Collection allowedOrigins; /** * Determines if any origin is allowed to make request. */ private boolean anyOriginAllowed; /** * A {@link Collection} of methods consisting of zero or more methods that * are supported by the resource. */ private final Collection allowedHttpMethods; /** * A {@link Collection} of headers consisting of zero or more header field * names that are supported by the resource. */ private final Collection allowedHttpHeaders; /** * A {@link Collection} of exposed headers consisting of zero or more header * field names of headers other than the simple response headers that the * resource might use and can be exposed. */ private final Collection exposedHeaders; /** * A supports credentials flag that indicates whether the resource supports * user credentials in the request. It is true when the resource does and * false otherwise. */ private boolean supportsCredentials; /** * Indicates (in seconds) how long the results of a pre-flight request can * be cached in a pre-flight result cache. */ private long preflightMaxAge; /** * Determines if the request should be decorated or not. */ private boolean decorateRequest; public CorsFilter() { this.allowedOrigins = new HashSet(); this.allowedHttpMethods = new HashSet(); this.allowedHttpHeaders = new HashSet(); this.exposedHeaders = new HashSet(); } @Override public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { if (!(servletRequest instanceof HttpServletRequest) || !(servletResponse instanceof HttpServletResponse)) { throw new ServletException(sm.getString("corsFilter.onlyHttp")); } // Safe to downcast at this point. HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // Determines the CORS request type. CorsFilter.CORSRequestType requestType = checkRequestType(request); // Adds CORS specific attributes to request. if (decorateRequest) { CorsFilter.decorateCORSProperties(request, requestType); } switch (requestType) { case SIMPLE: // Handles a Simple CORS request. this.handleSimpleCORS(request, response, filterChain); break; case ACTUAL: // Handles an Actual CORS request. this.handleSimpleCORS(request, response, filterChain); break; case PRE_FLIGHT: // Handles a Pre-flight CORS request. this.handlePreflightCORS(request, response, filterChain); break; case NOT_CORS: // Handles a Normal request that is not a cross-origin request. this.handleNonCORS(request, response, filterChain); break; default: // Handles a CORS request that violates specification. this.handleInvalidCORS(request, response, filterChain); break; } } @Override public void init(final FilterConfig filterConfig) throws ServletException { // Initialize defaults parseAndStore(DEFAULT_ALLOWED_ORIGINS, DEFAULT_ALLOWED_HTTP_METHODS, DEFAULT_ALLOWED_HTTP_HEADERS, DEFAULT_EXPOSED_HEADERS, DEFAULT_SUPPORTS_CREDENTIALS, DEFAULT_PREFLIGHT_MAXAGE, DEFAULT_DECORATE_REQUEST); if (filterConfig != null) { String configAllowedOrigins = filterConfig .getInitParameter(PARAM_CORS_ALLOWED_ORIGINS); String configAllowedHttpMethods = filterConfig .getInitParameter(PARAM_CORS_ALLOWED_METHODS); String configAllowedHttpHeaders = filterConfig .getInitParameter(PARAM_CORS_ALLOWED_HEADERS); String configExposedHeaders = filterConfig .getInitParameter(PARAM_CORS_EXPOSED_HEADERS); String configSupportsCredentials = filterConfig .getInitParameter(PARAM_CORS_SUPPORT_CREDENTIALS); String configPreflightMaxAge = filterConfig .getInitParameter(PARAM_CORS_PREFLIGHT_MAXAGE); String configDecorateRequest = filterConfig .getInitParameter(PARAM_CORS_REQUEST_DECORATE); parseAndStore(configAllowedOrigins, configAllowedHttpMethods, configAllowedHttpHeaders, configExposedHeaders, configSupportsCredentials, configPreflightMaxAge, configDecorateRequest); } } /** * Handles a CORS request of type {@link CORSRequestType}.SIMPLE. * * @param request * The {@link HttpServletRequest} object. * @param response * The {@link HttpServletResponse} object. * @param filterChain * The {@link FilterChain} object. * @throws IOException * @throws ServletException * @see Simple * Cross-Origin Request, Actual Request, and Redirects */ protected void handleSimpleCORS(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws IOException, ServletException { CorsFilter.CORSRequestType requestType = checkRequestType(request); if (!(requestType == CorsFilter.CORSRequestType.SIMPLE || requestType == CorsFilter.CORSRequestType.ACTUAL)) { throw new IllegalArgumentException( sm.getString("corsFilter.wrongType2", CorsFilter.CORSRequestType.SIMPLE, CorsFilter.CORSRequestType.ACTUAL)); } final String origin = request .getHeader(CorsFilter.REQUEST_HEADER_ORIGIN); final String method = request.getMethod(); // Section 6.1.2 if (!isOriginAllowed(origin)) { handleInvalidCORS(request, response, filterChain); return; } if (!allowedHttpMethods.contains(method)) { handleInvalidCORS(request, response, filterChain); return; } // Section 6.1.3 // Add a single Access-Control-Allow-Origin header. if (anyOriginAllowed && !supportsCredentials) { // If resource doesn't support credentials and if any origin is // allowed // to make CORS request, return header with '*'. response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); } else { // If the resource supports credentials add a single // Access-Control-Allow-Origin header, with the value of the Origin // header as value. response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin); } // Section 6.1.3 // If the resource supports credentials, add a single // Access-Control-Allow-Credentials header with the case-sensitive // string "true" as value. if (supportsCredentials) { response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } // Section 6.1.4 // If the list of exposed headers is not empty add one or more // Access-Control-Expose-Headers headers, with as values the header // field names given in the list of exposed headers. if ((exposedHeaders != null) && (exposedHeaders.size() > 0)) { String exposedHeadersString = join(exposedHeaders, ","); response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS, exposedHeadersString); } // Forward the request down the filter chain. filterChain.doFilter(request, response); } /** * Handles CORS pre-flight request. * * @param request * The {@link HttpServletRequest} object. * @param response * The {@link HttpServletResponse} object. * @param filterChain * The {@link FilterChain} object. * @throws IOException * @throws ServletException */ protected void handlePreflightCORS(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws IOException, ServletException { CORSRequestType requestType = checkRequestType(request); if (requestType != CORSRequestType.PRE_FLIGHT) { throw new IllegalArgumentException( sm.getString("corsFilter.wrongType1", CORSRequestType.PRE_FLIGHT.name().toLowerCase())); } final String origin = request .getHeader(CorsFilter.REQUEST_HEADER_ORIGIN); // Section 6.2.2 if (!isOriginAllowed(origin)) { handleInvalidCORS(request, response, filterChain); return; } // Section 6.2.3 String accessControlRequestMethod = request.getHeader( CorsFilter.REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD); if (accessControlRequestMethod == null || !HTTP_METHODS.contains(accessControlRequestMethod.trim())) { handleInvalidCORS(request, response, filterChain); return; } else { accessControlRequestMethod = accessControlRequestMethod.trim(); } // Section 6.2.4 String accessControlRequestHeadersHeader = request.getHeader( CorsFilter.REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS); List accessControlRequestHeaders = new LinkedList(); if (accessControlRequestHeadersHeader != null && !accessControlRequestHeadersHeader.trim().isEmpty()) { String[] headers = accessControlRequestHeadersHeader.trim().split( ","); for (String header : headers) { accessControlRequestHeaders.add(header.trim().toLowerCase()); } } // Section 6.2.5 if (!allowedHttpMethods.contains(accessControlRequestMethod)) { handleInvalidCORS(request, response, filterChain); return; } // Section 6.2.6 if (!accessControlRequestHeaders.isEmpty()) { for (String header : accessControlRequestHeaders) { if (!allowedHttpHeaders.contains(header)) { handleInvalidCORS(request, response, filterChain); return; } } } // Section 6.2.7 if (supportsCredentials) { response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin); response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } else { if (anyOriginAllowed) { response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); } else { response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin); } } // Section 6.2.8 if (preflightMaxAge > 0) { response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_MAX_AGE, String.valueOf(preflightMaxAge)); } // Section 6.2.9 response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_METHODS, accessControlRequestMethod); // Section 6.2.10 if ((allowedHttpHeaders != null) && (!allowedHttpHeaders.isEmpty())) { response.addHeader( CorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, join(allowedHttpHeaders, ",")); } // Do not forward the request down the filter chain. } /** * Handles a request, that's not a CORS request, but is a valid request i.e. * it is not a cross-origin request. This implementation, just forwards the * request down the filter chain. * * @param request * The {@link HttpServletRequest} object. * @param response * The {@link HttpServletResponse} object. * @param filterChain * The {@link FilterChain} object. * @throws IOException * @throws ServletException */ private void handleNonCORS(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws IOException, ServletException { // Let request pass. filterChain.doFilter(request, response); } /** * Handles a CORS request that violates specification. * * @param request * The {@link HttpServletRequest} object. * @param response * The {@link HttpServletResponse} object. * @param filterChain * The {@link FilterChain} object. */ private void handleInvalidCORS(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) { String origin = request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN); String method = request.getMethod(); String accessControlRequestHeaders = request.getHeader( REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS); response.setContentType("text/plain"); response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.resetBuffer(); if (log.isDebugEnabled()) { // Debug so no need for i18n StringBuilder message = new StringBuilder("Invalid CORS request; Origin="); message.append(origin); message.append(";Method="); message.append(method); if (accessControlRequestHeaders != null) { message.append(";Access-Control-Request-Headers="); message.append(accessControlRequestHeaders); } log.debug(message.toString()); } } @Override public void destroy() { // NOOP } /** * Decorates the {@link HttpServletRequest}, with CORS attributes. *
      *
    • cors.isCorsRequest: Flag to determine if request is a CORS * request. Set to true if CORS request; false * otherwise.
    • *
    • cors.request.origin: The Origin URL.
    • *
    • cors.request.type: Type of request. Values: * simple or preflight or not_cors or * invalid_cors
    • *
    • cors.request.headers: Request headers sent as * 'Access-Control-Request-Headers' header, for pre-flight request.
    • *
    * * @param request * The {@link HttpServletRequest} object. * @param corsRequestType * The {@link CORSRequestType} object. */ protected static void decorateCORSProperties( final HttpServletRequest request, final CORSRequestType corsRequestType) { if (request == null) { throw new IllegalArgumentException( sm.getString("corsFilter.nullRequest")); } if (corsRequestType == null) { throw new IllegalArgumentException( sm.getString("corsFilter.nullRequestType")); } switch (corsRequestType) { case SIMPLE: request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, Boolean.TRUE); request.setAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN, request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN)); request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE, corsRequestType.name().toLowerCase()); break; case ACTUAL: request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, Boolean.TRUE); request.setAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN, request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN)); request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE, corsRequestType.name().toLowerCase()); break; case PRE_FLIGHT: request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, Boolean.TRUE); request.setAttribute(CorsFilter.HTTP_REQUEST_ATTRIBUTE_ORIGIN, request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN)); request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE, corsRequestType.name().toLowerCase()); String headers = request.getHeader( REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS); if (headers == null) { headers = ""; } request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_REQUEST_HEADERS, headers); break; case NOT_CORS: request.setAttribute( CorsFilter.HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST, Boolean.FALSE); break; default: // Don't set any attributes break; } } /** * Joins elements of {@link Set} into a string, where each element is * separated by the provided separator. * * @param elements * The {@link Set} containing elements to join together. * @param joinSeparator * The character to be used for separating elements. * @return The joined {@link String}; null if elements * {@link Set} is null. */ protected static String join(final Collection elements, final String joinSeparator) { String separator = ","; if (elements == null) { return null; } if (joinSeparator != null) { separator = joinSeparator; } StringBuilder buffer = new StringBuilder(); boolean isFirst = true; for (String element : elements) { if (!isFirst) { buffer.append(separator); } else { isFirst = false; } if (element != null) { buffer.append(element); } } return buffer.toString(); } /** * Determines the request type. * * @param request */ protected CORSRequestType checkRequestType(final HttpServletRequest request) { CORSRequestType requestType = CORSRequestType.INVALID_CORS; if (request == null) { throw new IllegalArgumentException( sm.getString("corsFilter.nullRequest")); } String originHeader = request.getHeader(REQUEST_HEADER_ORIGIN); // Section 6.1.1 and Section 6.2.1 if (originHeader != null) { if (originHeader.isEmpty()) { requestType = CORSRequestType.INVALID_CORS; } else if (!isValidOrigin(originHeader)) { requestType = CORSRequestType.INVALID_CORS; } else { String method = request.getMethod(); if (method != null && HTTP_METHODS.contains(method)) { if ("OPTIONS".equals(method)) { String accessControlRequestMethodHeader = request.getHeader( REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD); if (accessControlRequestMethodHeader != null && !accessControlRequestMethodHeader.isEmpty()) { requestType = CORSRequestType.PRE_FLIGHT; } else if (accessControlRequestMethodHeader != null && accessControlRequestMethodHeader.isEmpty()) { requestType = CORSRequestType.INVALID_CORS; } else { requestType = CORSRequestType.ACTUAL; } } else if ("GET".equals(method) || "HEAD".equals(method)) { requestType = CORSRequestType.SIMPLE; } else if ("POST".equals(method)) { String contentType = request.getContentType(); if (contentType != null) { contentType = contentType.toLowerCase().trim(); if (SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES .contains(contentType)) { requestType = CORSRequestType.SIMPLE; } else { requestType = CORSRequestType.ACTUAL; } } } else if (COMPLEX_HTTP_METHODS.contains(method)) { requestType = CORSRequestType.ACTUAL; } } } } else { requestType = CORSRequestType.NOT_CORS; } return requestType; } /** * Checks if the Origin is allowed to make a CORS request. * * @param origin * The Origin. * @return true if origin is allowed; false * otherwise. */ private boolean isOriginAllowed(final String origin) { if (anyOriginAllowed) { return true; } // If 'Origin' header is a case-sensitive match of any of allowed // origins, then return true, else return false. return allowedOrigins.contains(origin); } /** * Parses each param-value and populates configuration variables. If a param * is provided, it overrides the default. * * @param allowedOrigins * A {@link String} of comma separated origins. * @param allowedHttpMethods * A {@link String} of comma separated HTTP methods. * @param allowedHttpHeaders * A {@link String} of comma separated HTTP headers. * @param exposedHeaders * A {@link String} of comma separated headers that needs to be * exposed. * @param supportsCredentials * "true" if support credentials needs to be enabled. * @param preflightMaxAge * The amount of seconds the user agent is allowed to cache the * result of the pre-flight request. * @throws ServletException */ private void parseAndStore(final String allowedOrigins, final String allowedHttpMethods, final String allowedHttpHeaders, final String exposedHeaders, final String supportsCredentials, final String preflightMaxAge, final String decorateRequest) throws ServletException { if (allowedOrigins != null) { if (allowedOrigins.trim().equals("*")) { this.anyOriginAllowed = true; } else { this.anyOriginAllowed = false; Set setAllowedOrigins = parseStringToSet(allowedOrigins); this.allowedOrigins.clear(); this.allowedOrigins.addAll(setAllowedOrigins); } } if (allowedHttpMethods != null) { Set setAllowedHttpMethods = parseStringToSet(allowedHttpMethods); this.allowedHttpMethods.clear(); this.allowedHttpMethods.addAll(setAllowedHttpMethods); } if (allowedHttpHeaders != null) { Set setAllowedHttpHeaders = parseStringToSet(allowedHttpHeaders); Set lowerCaseHeaders = new HashSet(); for (String header : setAllowedHttpHeaders) { String lowerCase = header.toLowerCase(); lowerCaseHeaders.add(lowerCase); } this.allowedHttpHeaders.clear(); this.allowedHttpHeaders.addAll(lowerCaseHeaders); } if (exposedHeaders != null) { Set setExposedHeaders = parseStringToSet(exposedHeaders); this.exposedHeaders.clear(); this.exposedHeaders.addAll(setExposedHeaders); } if (supportsCredentials != null) { // For any value other then 'true' this will be false. this.supportsCredentials = Boolean .parseBoolean(supportsCredentials); } if (preflightMaxAge != null) { try { if (!preflightMaxAge.isEmpty()) { this.preflightMaxAge = Long.parseLong(preflightMaxAge); } else { this.preflightMaxAge = 0L; } } catch (NumberFormatException e) { throw new ServletException( sm.getString("corsFilter.invalidPreflightMaxAge"), e); } } if (decorateRequest != null) { // For any value other then 'true' this will be false. this.decorateRequest = Boolean.parseBoolean(decorateRequest); } } /** * Takes a comma separated list and returns a Set. * * @param data * A comma separated list of strings. * @return Set */ private Set parseStringToSet(final String data) { String[] splits; if (data != null && data.length() > 0) { splits = data.split(","); } else { splits = new String[] {}; } Set set = new HashSet(); if (splits.length > 0) { for (String split : splits) { set.add(split.trim()); } } return set; } /** * Checks if a given origin is valid or not. Criteria: *
      *
    • If an encoded character is present in origin, it's not valid.
    • *
    • Origin should be a valid {@link URI}
    • *
    * * @param origin * @see RFC952 */ protected static boolean isValidOrigin(String origin) { // Checks for encoded characters. Helps prevent CRLF injection. if (origin.contains("%")) { return false; } URI originURI; try { originURI = new URI(origin); } catch (URISyntaxException e) { return false; } // If scheme for URI is null, return false. Return true otherwise. return originURI.getScheme() != null; } /** * Determines if any origin is allowed to make CORS request. * * @return true if it's enabled; false otherwise. */ public boolean isAnyOriginAllowed() { return anyOriginAllowed; } /** * Returns a {@link Set} of headers that should be exposed by browser. */ public Collection getExposedHeaders() { return exposedHeaders; } /** * Determines is supports credentials is enabled. */ public boolean isSupportsCredentials() { return supportsCredentials; } /** * Returns the preflight response cache time in seconds. * * @return Time to cache in seconds. */ public long getPreflightMaxAge() { return preflightMaxAge; } /** * Returns the {@link Set} of allowed origins that are allowed to make * requests. * * @return {@link Set} */ public Collection getAllowedOrigins() { return allowedOrigins; } /** * Returns a {@link Set} of HTTP methods that are allowed to make requests. * * @return {@link Set} */ public Collection getAllowedHttpMethods() { return allowedHttpMethods; } /** * Returns a {@link Set} of headers support by resource. * * @return {@link Set} */ public Collection getAllowedHttpHeaders() { return allowedHttpHeaders; } // -------------------------------------------------- CORS Response Headers /** * The Access-Control-Allow-Origin header indicates whether a resource can * be shared based by returning the value of the Origin request header in * the response. */ public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; /** * The Access-Control-Allow-Credentials header indicates whether the * response to request can be exposed when the omit credentials flag is * unset. When part of the response to a preflight request it indicates that * the actual request can include user credentials. */ public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials"; /** * The Access-Control-Expose-Headers header indicates which headers are safe * to expose to the API of a CORS API specification */ public static final String RESPONSE_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers"; /** * The Access-Control-Max-Age header indicates how long the results of a * preflight request can be cached in a preflight result cache. */ public static final String RESPONSE_HEADER_ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age"; /** * The Access-Control-Allow-Methods header indicates, as part of the * response to a preflight request, which methods can be used during the * actual request. */ public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods"; /** * The Access-Control-Allow-Headers header indicates, as part of the * response to a preflight request, which header field names can be used * during the actual request. */ public static final String RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; // -------------------------------------------------- CORS Request Headers /** * The Origin header indicates where the cross-origin request or preflight * request originates from. */ public static final String REQUEST_HEADER_ORIGIN = "Origin"; /** * The Access-Control-Request-Method header indicates which method will be * used in the actual request as part of the preflight request. */ public static final String REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method"; /** * The Access-Control-Request-Headers header indicates which headers will be * used in the actual request as part of the preflight request. */ public static final String REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers"; // ----------------------------------------------------- Request attributes /** * The prefix to a CORS request attribute. */ public static final String HTTP_REQUEST_ATTRIBUTE_PREFIX = "cors."; /** * Attribute that contains the origin of the request. */ public static final String HTTP_REQUEST_ATTRIBUTE_ORIGIN = HTTP_REQUEST_ATTRIBUTE_PREFIX + "request.origin"; /** * Boolean value, suggesting if the request is a CORS request or not. */ public static final String HTTP_REQUEST_ATTRIBUTE_IS_CORS_REQUEST = HTTP_REQUEST_ATTRIBUTE_PREFIX + "isCorsRequest"; /** * Type of CORS request, of type {@link CORSRequestType}. */ public static final String HTTP_REQUEST_ATTRIBUTE_REQUEST_TYPE = HTTP_REQUEST_ATTRIBUTE_PREFIX + "request.type"; /** * Request headers sent as 'Access-Control-Request-Headers' header, for * pre-flight request. */ public static final String HTTP_REQUEST_ATTRIBUTE_REQUEST_HEADERS = HTTP_REQUEST_ATTRIBUTE_PREFIX + "request.headers"; // -------------------------------------------------------------- Constants /** * Enumerates varies types of CORS requests. Also, provides utility methods * to determine the request type. */ protected static enum CORSRequestType { /** * A simple HTTP request, i.e. it shouldn't be pre-flighted. */ SIMPLE, /** * A HTTP request that needs to be pre-flighted. */ ACTUAL, /** * A pre-flight CORS request, to get meta information, before a * non-simple HTTP request is sent. */ PRE_FLIGHT, /** * Not a CORS request, but a normal request. */ NOT_CORS, /** * An invalid CORS request, i.e. it qualifies to be a CORS request, but * fails to be a valid one. */ INVALID_CORS } /** * {@link Collection} of HTTP methods. Case sensitive. * * @see http://tools.ietf.org/html/rfc2616#section-5.1.1 * */ public static final Collection HTTP_METHODS = new HashSet(Arrays.asList("OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT")); /** * {@link Collection} of non-simple HTTP methods. Case sensitive. */ public static final Collection COMPLEX_HTTP_METHODS = new HashSet(Arrays.asList("PUT", "DELETE", "TRACE", "CONNECT")); /** * {@link Collection} of Simple HTTP methods. Case sensitive. * * @see http://www.w3.org/TR/cors/#terminology */ public static final Collection SIMPLE_HTTP_METHODS = new HashSet(Arrays.asList("GET", "POST", "HEAD")); /** * {@link Collection} of Simple HTTP request headers. Case in-sensitive. * * @see http://www.w3.org/TR/cors/#terminology */ public static final Collection SIMPLE_HTTP_REQUEST_HEADERS = new HashSet(Arrays.asList("Accept", "Accept-Language", "Content-Language")); /** * {@link Collection} of Simple HTTP request headers. Case in-sensitive. * * @see http://www.w3.org/TR/cors/#terminology */ public static final Collection SIMPLE_HTTP_RESPONSE_HEADERS = new HashSet(Arrays.asList("Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma")); /** * {@link Collection} of Simple HTTP request headers. Case in-sensitive. * * @see http://www.w3.org/TR/cors/#terminology */ public static final Collection SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES = new HashSet(Arrays.asList( "application/x-www-form-urlencoded", "multipart/form-data", "text/plain")); // ------------------------------------------------ Configuration Defaults /** * By default, all origins are allowed to make requests. */ public static final String DEFAULT_ALLOWED_ORIGINS = "*"; /** * By default, following methods are supported: GET, POST, HEAD and OPTIONS. */ public static final String DEFAULT_ALLOWED_HTTP_METHODS = "GET,POST,HEAD,OPTIONS"; /** * By default, time duration to cache pre-flight response is 30 mins. */ public static final String DEFAULT_PREFLIGHT_MAXAGE = "1800"; /** * By default, support credentials is turned on. */ public static final String DEFAULT_SUPPORTS_CREDENTIALS = "true"; /** * By default, following headers are supported: * Origin,Accept,X-Requested-With, Content-Type, * Access-Control-Request-Method, and Access-Control-Request-Headers. */ public static final String DEFAULT_ALLOWED_HTTP_HEADERS = "Origin,Accept,X-Requested-With,Content-Type," + "Access-Control-Request-Method,Access-Control-Request-Headers"; /** * By default, none of the headers are exposed in response. */ public static final String DEFAULT_EXPOSED_HEADERS = ""; /** * By default, request is decorated with CORS attributes. */ public static final String DEFAULT_DECORATE_REQUEST = "true"; // ----------------------------------------Filter Config Init param-name(s) /** * Key to retrieve allowed origins from {@link FilterConfig}. */ public static final String PARAM_CORS_ALLOWED_ORIGINS = "cors.allowed.origins"; /** * Key to retrieve support credentials from {@link FilterConfig}. */ public static final String PARAM_CORS_SUPPORT_CREDENTIALS = "cors.support.credentials"; /** * Key to retrieve exposed headers from {@link FilterConfig}. */ public static final String PARAM_CORS_EXPOSED_HEADERS = "cors.exposed.headers"; /** * Key to retrieve allowed headers from {@link FilterConfig}. */ public static final String PARAM_CORS_ALLOWED_HEADERS = "cors.allowed.headers"; /** * Key to retrieve allowed methods from {@link FilterConfig}. */ public static final String PARAM_CORS_ALLOWED_METHODS = "cors.allowed.methods"; /** * Key to retrieve preflight max age from {@link FilterConfig}. */ public static final String PARAM_CORS_PREFLIGHT_MAXAGE = "cors.preflight.maxage"; /** * Key to determine if request should be decorated. */ public static final String PARAM_CORS_REQUEST_DECORATE = "cors.request.decorate"; } tomcat7-7.0.52/java/org/apache/catalina/filters/RemoteHostFilter.java0000644000175100017510000000612712271471332025432 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometFilterChain; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Concrete implementation of RequestFilter that filters * based on the remote client's host name. * * @author Craig R. McClanahan * */ public final class RemoteHostFilter extends RequestFilter { private static final Log log = LogFactory.getLog(RemoteHostFilter.class); // --------------------------------------------------------- Public Methods /** * Extract the desired request property, and pass it (along with the * specified request and response objects and associated filter chain) to * the protected process() method to perform the actual * filtering. * * @param request The servlet request to be processed * @param response The servlet response to be created * @param chain The filter chain for this request * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { process(request.getRemoteHost(), request, response, chain); } /** * Extract the desired request property, and pass it (along with the comet * event and filter chain) to the protected process() method * to perform the actual filtering. * * @param event The comet event to be processed * @param chain The filter chain for this event * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doFilterEvent(CometEvent event, CometFilterChain chain) throws IOException, ServletException { processCometEvent(event.getHttpServletRequest().getRemoteHost(), event, chain); } @Override protected Log getLogger() { return log; } } tomcat7-7.0.52/java/org/apache/catalina/filters/ExpiresFilter.java0000644000175100017510000015665411730342573024776 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.StringTokenizer; import java.util.regex.Pattern; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    * ExpiresFilter is a Java Servlet API port of Apache * mod_expires to add ' Expires' and ' * Cache-Control: max-age=' headers to HTTP response according to its ' * Content-Type'. *

    * *

    * Following documentation is inspired by mod_expires . *

    *

    Summary

    *

    * This filter controls the setting of the Expires HTTP header and the * max-age directive of the Cache-Control HTTP header in * server responses. The expiration date can set to be relative to either the * time the source file was last modified, or to the time of the client access. *

    *

    * These HTTP headers are an instruction to the client about the document's * validity and persistence. If cached, the document may be fetched from the * cache rather than from the source until this time has passed. After that, the * cache copy is considered "expired" and invalid, and a new copy must * be obtained from the source. *

    *

    * To modify Cache-Control directives other than max-age (see * RFC * 2616 section 14.9), you can use other servlet filters or Apache Httpd * mod_headers module. *

    *

    Filter Configuration

    Basic configuration to add ' * Expires' and ' Cache-Control: max-age=' * headers to images, css and javascript

    * *
     * <web-app ...>
     *    ...
     *    <filter>
     *       <filter-name>ExpiresFilter</filter-name>
     *       <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
     *       <init-param>
     *          <param-name>ExpiresByType image</param-name>
     *          <param-value>access plus 10 minutes</param-value>
     *       </init-param>
     *       <init-param>
     *          <param-name>ExpiresByType text/css</param-name>
     *          <param-value>access plus 10 minutes</param-value>
     *       </init-param>
     *       <init-param>
     *          <param-name>ExpiresByType application/javascript</param-name>
     *          <param-value>access plus 10 minutes</param-value>
     *       </init-param>
     *    </filter>
     *    ...
     *    <filter-mapping>
     *       <filter-name>ExpiresFilter</filter-name>
     *       <url-pattern>/*</url-pattern>
     *       <dispatcher>REQUEST</dispatcher>
     *    </filter-mapping>
     *    ...
     * </web-app>
     * 
    * *

    Configuration Parameters

    * *

    * ExpiresByType <content-type>

    *

    * This directive defines the value of the Expires header and the * max-age directive of the Cache-Control header generated for * documents of the specified type (e.g., text/html). The second * argument sets the number of seconds that will be added to a base time to * construct the expiration date. The Cache-Control: max-age is * calculated by subtracting the request time from the expiration date and * expressing the result in seconds. *

    *

    * The base time is either the last modification time of the file, or the time * of the client's access to the document. Which should be used is * specified by the <code> field; M means that the * file's last modification time should be used as the base time, and * A means the client's access time should be used. The duration * is expressed in seconds. A2592000 stands for * access plus 30 days in alternate syntax. *

    *

    * The difference in effect is subtle. If M (modification in * alternate syntax) is used, all current copies of the document in all caches * will expire at the same time, which can be good for something like a weekly * notice that's always found at the same URL. If A ( * access or now in alternate syntax) is used, the date of * expiration is different for each client; this can be good for image files * that don't change very often, particularly for a set of related * documents that all refer to the same images (i.e., the images will be * accessed repeatedly within a relatively short timespan). *

    *

    * Example: *

    * *
     * <init-param>
     *    <param-name>ExpiresByType text/html</param-name><param-value>access plus 1 month 15   days 2 hours</param-value>
     * </init-param>
     *  
     * <init-param>
     *    <!-- 2592000 seconds = 30 days -->
     *    <param-name>ExpiresByType image/gif</param-name><param-value>A2592000</param-value>
     * </init-param>
     * 
    *

    * Note that this directive only has effect if ExpiresActive On has * been specified. It overrides, for the specified MIME type only, any * expiration date set by the ExpiresDefault directive. *

    *

    * You can also specify the expiration time calculation using an alternate * syntax, described earlier in this document. *

    *

    * ExpiresExcludedResponseStatusCodes

    *

    * This directive defines the http response status codes for which the * ExpiresFilter will not generate expiration headers. By default, the * 304 status code ("Not modified") is skipped. The * value is a comma separated list of http status codes. *

    *

    * This directive is useful to ease usage of ExpiresDefault directive. * Indeed, the behavior of 304 Not modified (which does specify a * Content-Type header) combined with Expires and * Cache-Control:max-age= headers can be unnecessarily tricky to * understand. *

    *

    * Configuration sample : *

    * *
     * <init-param>
     *    <param-name>ExpiresExcludedResponseStatusCodes</param-name><param-value>302, 500, 503</param-value>
     * </init-param>
     * 
    * *

    ExpiresDefault

    *

    * This directive sets the default algorithm for calculating the expiration time * for all documents in the affected realm. It can be overridden on a * type-by-type basis by the ExpiresByType directive. See the * description of that directive for details about the syntax of the argument, * and the "alternate syntax" description as well. *

    *

    Alternate Syntax

    *

    * The ExpiresDefault and ExpiresByType directives can also be * defined in a more readable syntax of the form: *

    * *
     * <init-param>
     *    <param-name>ExpiresDefault</param-name><param-value><base> [plus] {<num>   <type>}*</param-value>
     * </init-param>
     *  
     * <init-param>
     *    <param-name>ExpiresByType type/encoding</param-name><param-value><base> [plus]   {<num> <type>}*</param-value>
     * </init-param>
     * 
    *

    * where <base> is one of: *

      *
    • access
    • *
    • now (equivalent to 'access')
    • *
    • modification
    • *
    *

    *

    * The plus keyword is optional. <num> should be an * integer value (acceptable to Integer.parseInt()), and * <type> is one of: *

      *
    • years
    • *
    • months
    • *
    • weeks
    • *
    • days
    • *
    • hours
    • *
    • minutes
    • *
    • seconds
    • *
    * For example, any of the following directives can be used to make documents * expire 1 month after being accessed, by default: *

    * *
     * <init-param>
     *    <param-name>ExpiresDefault</param-name><param-value>access plus 1 month</param-value>
     * </init-param>
     *  
     * <init-param>
     *    <param-name>ExpiresDefault</param-name><param-value>access plus 4 weeks</param-value>
     * </init-param>
     *  
     * <init-param>
     *    <param-name>ExpiresDefault</param-name><param-value>access plus 30 days</param-value>
     * </init-param>
     * 
    *

    * The expiry time can be fine-tuned by adding several ' * <num> <type>' clauses: *

    * *
     * <init-param>
     *    <param-name>ExpiresByType text/html</param-name><param-value>access plus 1 month 15   days 2 hours</param-value>
     * </init-param>
     *  
     * <init-param>
     *    <param-name>ExpiresByType image/gif</param-name><param-value>modification plus 5 hours 3   minutes</param-value>
     * </init-param>
     * 
    *

    * Note that if you use a modification date based setting, the Expires * header will not be added to content that does not come from * a file on disk. This is due to the fact that there is no modification time * for such content. *

    *

    Expiration headers generation eligibility

    *

    * A response is eligible to be enriched by ExpiresFilter if : *

      *
    1. no expiration header is defined (Expires header or the * max-age directive of the Cache-Control header),
    2. *
    3. the response status code is not excluded by the directive * ExpiresExcludedResponseStatusCodes,
    4. *
    5. the Content-Type of the response matches one of the types * defined the in ExpiresByType directives or the * ExpiresDefault directive is defined.
    6. *
    *

    *

    * Note : *

      *
    • If Cache-Control header contains other directives than * max-age, they are concatenated with the max-age directive * that is added by the ExpiresFilter.
    • *
    *

    *

    Expiration configuration selection

    *

    * The expiration configuration if elected according to the following algorithm: *

      *
    1. ExpiresByType matching the exact content-type returned by * HttpServletResponse.getContentType() possibly including the charset * (e.g. 'text/xml;charset=UTF-8'),
    2. *
    3. ExpiresByType matching the content-type without the charset if * HttpServletResponse.getContentType() contains a charset (e.g. ' * text/xml;charset=UTF-8' -> 'text/xml'),
    4. *
    5. ExpiresByType matching the major type (e.g. substring before * '/') of HttpServletResponse.getContentType() * (e.g. 'text/xml;charset=UTF-8' -> 'text * '),
    6. *
    7. ExpiresDefault
    8. *
    *

    *

    Implementation Details

    When to write the expiration headers ?

    *

    * The ExpiresFilter traps the 'on before write response * body' event to decide whether it should generate expiration headers or * not. *

    *

    * To trap the 'before write response body' event, the * ExpiresFilter wraps the http servlet response's writer and * outputStream to intercept calls to the methods write(), * print(), close() and flush(). For empty response * body (e.g. empty files), the write(), print(), * close() and flush() methods are not called; to handle this * case, the ExpiresFilter, at the end of its doFilter() * method, manually triggers the onBeforeWriteResponseBody() method. *

    *

    Configuration syntax

    *

    * The ExpiresFilter supports the same configuration syntax as Apache * Httpd mod_expires. *

    *

    * A challenge has been to choose the name of the <param-name> * associated with ExpiresByType in the <filter> * declaration. Indeed, Several ExpiresByType directives can be * declared when web.xml syntax does not allow to declare several * <init-param> with the same name. *

    *

    * The workaround has been to declare the content type in the * <param-name> rather than in the <param-value>. *

    *

    Designed for extension : the open/close principle

    *

    * The ExpiresFilter has been designed for extension following the * open/close principle. *

    *

    * Key methods to override for extension are : *

      *
    • * {@link #isEligibleToExpirationHeaderGeneration(HttpServletRequest, XHttpServletResponse)} *
    • *
    • * {@link #getExpirationDate(XHttpServletResponse)}
    • *
    *

    *

    Troubleshooting

    *

    * To troubleshoot, enable logging on the * org.apache.catalina.filters.ExpiresFilter. *

    *

    * Extract of logging.properties *

    * *
     * org.apache.catalina.filters.ExpiresFilter.level = FINE
     * 
    *

    * Sample of initialization log message : *

    * *
     * Mar 26, 2010 2:01:41 PM org.apache.catalina.filters.ExpiresFilter init
     * FINE: Filter initialized with configuration ExpiresFilter[
     *    excludedResponseStatusCode=[304], 
     *    default=null, 
     *    byType={
     *       image=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]], 
     *       text/css=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]], 
     *       application/javascript=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]]}]
     * 
    *

    * Sample of per-request log message where ExpiresFilter adds an * expiration date *

    * *
     * Mar 26, 2010 2:09:47 PM org.apache.catalina.filters.ExpiresFilter onBeforeWriteResponseBody
     * FINE: Request "/tomcat.gif" with response status "200" content-type "image/gif", set expiration date 3/26/10 2:19 PM
     * 
    *

    * Sample of per-request log message where ExpiresFilter does not add * an expiration date *

    * *
     * Mar 26, 2010 2:10:27 PM org.apache.catalina.filters.ExpiresFilter onBeforeWriteResponseBody
     * FINE: Request "/docs/config/manager.html" with response status "200" content-type "text/html", no expiration configured
     * 
    * */ public class ExpiresFilter extends FilterBase { /** * Duration composed of an {@link #amount} and a {@link #unit} */ protected static class Duration { protected final int amount; protected final DurationUnit unit; public Duration(int amount, DurationUnit unit) { super(); this.amount = amount; this.unit = unit; } public int getAmount() { return amount; } public DurationUnit getUnit() { return unit; } @Override public String toString() { return amount + " " + unit; } } /** * Duration unit */ protected enum DurationUnit { DAY(Calendar.DAY_OF_YEAR), HOUR(Calendar.HOUR), MINUTE(Calendar.MINUTE), MONTH( Calendar.MONTH), SECOND(Calendar.SECOND), WEEK( Calendar.WEEK_OF_YEAR), YEAR(Calendar.YEAR); private final int calendardField; private DurationUnit(int calendardField) { this.calendardField = calendardField; } public int getCalendardField() { return calendardField; } } /** *

    * Main piece of configuration of the filter. *

    *

    * Can be expressed like 'access plus 1 month 15 days 2 hours'. *

    */ protected static class ExpiresConfiguration { /** * List of duration elements. */ private final List durations; /** * Starting point of the elaspse to set in the response. */ private final StartingPoint startingPoint; public ExpiresConfiguration(StartingPoint startingPoint, List durations) { super(); this.startingPoint = startingPoint; this.durations = durations; } public List getDurations() { return durations; } public StartingPoint getStartingPoint() { return startingPoint; } @Override public String toString() { return "ExpiresConfiguration[startingPoint=" + startingPoint + ", duration=" + durations + "]"; } } /** * Expiration configuration starting point. Either the time the * html-page/servlet-response was served ({@link StartingPoint#ACCESS_TIME}) * or the last time the html-page/servlet-response was modified ( * {@link StartingPoint#LAST_MODIFICATION_TIME}). */ protected enum StartingPoint { ACCESS_TIME, LAST_MODIFICATION_TIME } /** *

    * Wrapping extension of the {@link HttpServletResponse} to yrap the * "Start Write Response Body" event. *

    *

    * For performance optimization : this extended response holds the * {@link #lastModifiedHeader} and {@link #cacheControlHeader} values access * to the slow {@link #getHeader(String)} and to spare the string * to date to long conversion. *

    */ public class XHttpServletResponse extends HttpServletResponseWrapper { /** * Value of the Cache-Control/tt> http response header if it has * been set. */ private String cacheControlHeader; /** * Value of the Last-Modified http response header if it has * been set. */ private long lastModifiedHeader; private boolean lastModifiedHeaderSet; private PrintWriter printWriter; private final HttpServletRequest request; private ServletOutputStream servletOutputStream; /** * Indicates whether calls to write methods (write(...), * print(...), etc) of the response body have been called or * not. */ private boolean writeResponseBodyStarted; public XHttpServletResponse(HttpServletRequest request, HttpServletResponse response) { super(response); this.request = request; } @Override public void addDateHeader(String name, long date) { super.addDateHeader(name, date); if (!lastModifiedHeaderSet) { this.lastModifiedHeader = date; this.lastModifiedHeaderSet = true; } } @Override public void addHeader(String name, String value) { super.addHeader(name, value); if (HEADER_CACHE_CONTROL.equalsIgnoreCase(name) && cacheControlHeader == null) { cacheControlHeader = value; } } public String getCacheControlHeader() { return cacheControlHeader; } public long getLastModifiedHeader() { return lastModifiedHeader; } @Override public ServletOutputStream getOutputStream() throws IOException { if (servletOutputStream == null) { servletOutputStream = new XServletOutputStream( super.getOutputStream(), request, this); } return servletOutputStream; } @Override public PrintWriter getWriter() throws IOException { if (printWriter == null) { printWriter = new XPrintWriter(super.getWriter(), request, this); } return printWriter; } public boolean isLastModifiedHeaderSet() { return lastModifiedHeaderSet; } public boolean isWriteResponseBodyStarted() { return writeResponseBodyStarted; } @Override public void reset() { super.reset(); this.lastModifiedHeader = 0; this.lastModifiedHeaderSet = false; this.cacheControlHeader = null; } @Override public void setDateHeader(String name, long date) { super.setDateHeader(name, date); if (HEADER_LAST_MODIFIED.equalsIgnoreCase(name)) { this.lastModifiedHeader = date; this.lastModifiedHeaderSet = true; } } @Override public void setHeader(String name, String value) { super.setHeader(name, value); if (HEADER_CACHE_CONTROL.equalsIgnoreCase(name)) { this.cacheControlHeader = value; } } public void setWriteResponseBodyStarted(boolean writeResponseBodyStarted) { this.writeResponseBodyStarted = writeResponseBodyStarted; } } /** * Wrapping extension of {@link PrintWriter} to trap the * "Start Write Response Body" event. */ public class XPrintWriter extends PrintWriter { private final PrintWriter out; private final HttpServletRequest request; private final XHttpServletResponse response; public XPrintWriter(PrintWriter out, HttpServletRequest request, XHttpServletResponse response) { super(out); this.out = out; this.request = request; this.response = response; } @Override public PrintWriter append(char c) { fireBeforeWriteResponseBodyEvent(); return out.append(c); } @Override public PrintWriter append(CharSequence csq) { fireBeforeWriteResponseBodyEvent(); return out.append(csq); } @Override public PrintWriter append(CharSequence csq, int start, int end) { fireBeforeWriteResponseBodyEvent(); return out.append(csq, start, end); } @Override public void close() { fireBeforeWriteResponseBodyEvent(); out.close(); } private void fireBeforeWriteResponseBodyEvent() { if (!this.response.isWriteResponseBodyStarted()) { this.response.setWriteResponseBodyStarted(true); onBeforeWriteResponseBody(request, response); } } @Override public void flush() { fireBeforeWriteResponseBodyEvent(); out.flush(); } @Override public void print(boolean b) { fireBeforeWriteResponseBodyEvent(); out.print(b); } @Override public void print(char c) { fireBeforeWriteResponseBodyEvent(); out.print(c); } @Override public void print(char[] s) { fireBeforeWriteResponseBodyEvent(); out.print(s); } @Override public void print(double d) { fireBeforeWriteResponseBodyEvent(); out.print(d); } @Override public void print(float f) { fireBeforeWriteResponseBodyEvent(); out.print(f); } @Override public void print(int i) { fireBeforeWriteResponseBodyEvent(); out.print(i); } @Override public void print(long l) { fireBeforeWriteResponseBodyEvent(); out.print(l); } @Override public void print(Object obj) { fireBeforeWriteResponseBodyEvent(); out.print(obj); } @Override public void print(String s) { fireBeforeWriteResponseBodyEvent(); out.print(s); } @Override public PrintWriter printf(Locale l, String format, Object... args) { fireBeforeWriteResponseBodyEvent(); return out.printf(l, format, args); } @Override public PrintWriter printf(String format, Object... args) { fireBeforeWriteResponseBodyEvent(); return out.printf(format, args); } @Override public void println() { fireBeforeWriteResponseBodyEvent(); out.println(); } @Override public void println(boolean x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(char x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(char[] x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(double x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(float x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(int x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(long x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(Object x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void println(String x) { fireBeforeWriteResponseBodyEvent(); out.println(x); } @Override public void write(char[] buf) { fireBeforeWriteResponseBodyEvent(); out.write(buf); } @Override public void write(char[] buf, int off, int len) { fireBeforeWriteResponseBodyEvent(); out.write(buf, off, len); } @Override public void write(int c) { fireBeforeWriteResponseBodyEvent(); out.write(c); } @Override public void write(String s) { fireBeforeWriteResponseBodyEvent(); out.write(s); } @Override public void write(String s, int off, int len) { fireBeforeWriteResponseBodyEvent(); out.write(s, off, len); } } /** * Wrapping extension of {@link ServletOutputStream} to trap the * "Start Write Response Body" event. */ public class XServletOutputStream extends ServletOutputStream { private final HttpServletRequest request; private final XHttpServletResponse response; private final ServletOutputStream servletOutputStream; public XServletOutputStream(ServletOutputStream servletOutputStream, HttpServletRequest request, XHttpServletResponse response) { super(); this.servletOutputStream = servletOutputStream; this.response = response; this.request = request; } @Override public void close() throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.close(); } private void fireOnBeforeWriteResponseBodyEvent() { if (!this.response.isWriteResponseBodyStarted()) { this.response.setWriteResponseBodyStarted(true); onBeforeWriteResponseBody(request, response); } } @Override public void flush() throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.flush(); } @Override public void print(boolean b) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.print(b); } @Override public void print(char c) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.print(c); } @Override public void print(double d) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.print(d); } @Override public void print(float f) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.print(f); } @Override public void print(int i) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.print(i); } @Override public void print(long l) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.print(l); } @Override public void print(String s) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.print(s); } @Override public void println() throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(); } @Override public void println(boolean b) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(b); } @Override public void println(char c) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(c); } @Override public void println(double d) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(d); } @Override public void println(float f) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(f); } @Override public void println(int i) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(i); } @Override public void println(long l) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(l); } @Override public void println(String s) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.println(s); } @Override public void write(byte[] b) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.write(b, off, len); } @Override public void write(int b) throws IOException { fireOnBeforeWriteResponseBodyEvent(); servletOutputStream.write(b); } } /** * {@link Pattern} for a comma delimited string that support whitespace * characters */ private static final Pattern commaSeparatedValuesPattern = Pattern.compile("\\s*,\\s*"); private static final String HEADER_CACHE_CONTROL = "Cache-Control"; private static final String HEADER_EXPIRES = "Expires"; private static final String HEADER_LAST_MODIFIED = "Last-Modified"; private static final Log log = LogFactory.getLog(ExpiresFilter.class); private static final String PARAMETER_EXPIRES_BY_TYPE = "ExpiresByType"; private static final String PARAMETER_EXPIRES_DEFAULT = "ExpiresDefault"; private static final String PARAMETER_EXPIRES_EXCLUDED_RESPONSE_STATUS_CODES = "ExpiresExcludedResponseStatusCodes"; /** * Convert a comma delimited list of numbers into an int[]. * * @param commaDelimitedInts * can be null * @return never null array */ protected static int[] commaDelimitedListToIntArray( String commaDelimitedInts) { String[] intsAsStrings = commaDelimitedListToStringArray(commaDelimitedInts); int[] ints = new int[intsAsStrings.length]; for (int i = 0; i < intsAsStrings.length; i++) { String intAsString = intsAsStrings[i]; try { ints[i] = Integer.parseInt(intAsString); } catch (NumberFormatException e) { throw new RuntimeException("Exception parsing number '" + i + "' (zero based) of comma delimited list '" + commaDelimitedInts + "'"); } } return ints; } /** * Convert a given comma delimited list of strings into an array of String * * @return array of patterns (non null) */ protected static String[] commaDelimitedListToStringArray( String commaDelimitedStrings) { return (commaDelimitedStrings == null || commaDelimitedStrings.length() == 0) ? new String[0] : commaSeparatedValuesPattern.split(commaDelimitedStrings); } /** * Return true if the given str contains the given * searchStr. */ protected static boolean contains(String str, String searchStr) { if (str == null || searchStr == null) { return false; } return str.indexOf(searchStr) >= 0; } /** * Convert an array of ints into a comma delimited string */ protected static String intsToCommaDelimitedString(int[] ints) { if (ints == null) { return ""; } StringBuilder result = new StringBuilder(); for (int i = 0; i < ints.length; i++) { result.append(ints[i]); if (i < (ints.length - 1)) { result.append(", "); } } return result.toString(); } /** * Return true if the given str is * null or has a zero characters length. */ protected static boolean isEmpty(String str) { return str == null || str.length() == 0; } /** * Return true if the given str has at least one * character (can be a withespace). */ protected static boolean isNotEmpty(String str) { return !isEmpty(str); } /** * Return true if the given string starts with the * given prefix ignoring case. * * @param string * can be null * @param prefix * can be null */ protected static boolean startsWithIgnoreCase(String string, String prefix) { if (string == null || prefix == null) { return string == null && prefix == null; } if (prefix.length() > string.length()) { return false; } return string.regionMatches(true, 0, prefix, 0, prefix.length()); } /** * Return the subset of the given str that is before the first * occurence of the given separator. Return null * if the given str or the given separator is * null. Return and empty string if the separator is empty. * * @param str * can be null * @param separator * can be null */ protected static String substringBefore(String str, String separator) { if (str == null || str.isEmpty() || separator == null) { return null; } if (separator.isEmpty()) { return ""; } int separatorIndex = str.indexOf(separator); if (separatorIndex == -1) { return str; } return str.substring(0, separatorIndex); } /** * Default Expires configuration. */ private ExpiresConfiguration defaultExpiresConfiguration; /** * list of response status code for which the {@link ExpiresFilter} will not * generate expiration headers. */ private int[] excludedResponseStatusCodes = new int[] { HttpServletResponse.SC_NOT_MODIFIED }; /** * Expires configuration by content type. Visible for test. */ private Map expiresConfigurationByContentType = new LinkedHashMap(); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; if (response.isCommitted()) { if (log.isDebugEnabled()) { log.debug(sm.getString( "expiresFilter.responseAlreadyCommited", httpRequest.getRequestURL())); } chain.doFilter(request, response); } else { XHttpServletResponse xResponse = new XHttpServletResponse( httpRequest, httpResponse); chain.doFilter(request, xResponse); if (!xResponse.isWriteResponseBodyStarted()) { // Empty response, manually trigger // onBeforeWriteResponseBody() onBeforeWriteResponseBody(httpRequest, xResponse); } } } else { chain.doFilter(request, response); } } public ExpiresConfiguration getDefaultExpiresConfiguration() { return defaultExpiresConfiguration; } public String getExcludedResponseStatusCodes() { return intsToCommaDelimitedString(excludedResponseStatusCodes); } public int[] getExcludedResponseStatusCodesAsInts() { return excludedResponseStatusCodes; } /** *

    * Returns the expiration date of the given {@link XHttpServletResponse} or * null if no expiration date has been configured for the * declared content type. *

    *

    * protected for extension. *

    * * @see HttpServletResponse#getContentType() */ protected Date getExpirationDate(XHttpServletResponse response) { String contentType = response.getContentType(); // lookup exact content-type match (e.g. // "text/html; charset=iso-8859-1") ExpiresConfiguration configuration = expiresConfigurationByContentType.get(contentType); if (configuration != null) { Date result = getExpirationDate(configuration, response); if (log.isDebugEnabled()) { log.debug(sm.getString( "expiresFilter.useMatchingConfiguration", configuration, contentType, contentType, result)); } return result; } if (contains(contentType, ";")) { // lookup content-type without charset match (e.g. "text/html") String contentTypeWithoutCharset = substringBefore(contentType, ";").trim(); configuration = expiresConfigurationByContentType.get(contentTypeWithoutCharset); if (configuration != null) { Date result = getExpirationDate(configuration, response); if (log.isDebugEnabled()) { log.debug(sm.getString( "expiresFilter.useMatchingConfiguration", configuration, contentTypeWithoutCharset, contentType, result)); } return result; } } if (contains(contentType, "/")) { // lookup major type match (e.g. "text") String majorType = substringBefore(contentType, "/"); configuration = expiresConfigurationByContentType.get(majorType); if (configuration != null) { Date result = getExpirationDate(configuration, response); if (log.isDebugEnabled()) { log.debug(sm.getString( "expiresFilter.useMatchingConfiguration", configuration, majorType, contentType, result)); } return result; } } if (defaultExpiresConfiguration != null) { Date result = getExpirationDate(defaultExpiresConfiguration, response); if (log.isDebugEnabled()) { log.debug(sm.getString("expiresFilter.useDefaultConfiguration", defaultExpiresConfiguration, contentType, result)); } return result; } if (log.isDebugEnabled()) { log.debug(sm.getString( "expiresFilter.noExpirationConfiguredForContentType", contentType)); } return null; } /** *

    * Returns the expiration date of the given {@link ExpiresConfiguration}, * {@link HttpServletRequest} and {@link XHttpServletResponse}. *

    *

    * protected for extension. *

    */ protected Date getExpirationDate(ExpiresConfiguration configuration, XHttpServletResponse response) { Calendar calendar; switch (configuration.getStartingPoint()) { case ACCESS_TIME: calendar = Calendar.getInstance(); break; case LAST_MODIFICATION_TIME: if (response.isLastModifiedHeaderSet()) { try { long lastModified = response.getLastModifiedHeader(); calendar = Calendar.getInstance(); calendar.setTimeInMillis(lastModified); } catch (NumberFormatException e) { // default to now calendar = Calendar.getInstance(); } } else { // Last-Modified header not found, use now calendar = Calendar.getInstance(); } break; default: throw new IllegalStateException(sm.getString( "expiresFilter.unsupportedStartingPoint", configuration.getStartingPoint())); } for (Duration duration : configuration.getDurations()) { calendar.add(duration.getUnit().getCalendardField(), duration.getAmount()); } return calendar.getTime(); } public Map getExpiresConfigurationByContentType() { return expiresConfigurationByContentType; } @Override protected Log getLogger() { return log; } @Override public void init(FilterConfig filterConfig) throws ServletException { for (Enumeration names = filterConfig.getInitParameterNames(); names.hasMoreElements();) { String name = names.nextElement(); String value = filterConfig.getInitParameter(name); try { if (name.startsWith(PARAMETER_EXPIRES_BY_TYPE)) { String contentType = name.substring( PARAMETER_EXPIRES_BY_TYPE.length()).trim(); ExpiresConfiguration expiresConfiguration = parseExpiresConfiguration(value); this.expiresConfigurationByContentType.put(contentType, expiresConfiguration); } else if (name.equalsIgnoreCase(PARAMETER_EXPIRES_DEFAULT)) { ExpiresConfiguration expiresConfiguration = parseExpiresConfiguration(value); this.defaultExpiresConfiguration = expiresConfiguration; } else if (name.equalsIgnoreCase(PARAMETER_EXPIRES_EXCLUDED_RESPONSE_STATUS_CODES)) { this.excludedResponseStatusCodes = commaDelimitedListToIntArray(value); } else { log.warn(sm.getString( "expiresFilter.unknownParameterIgnored", name, value)); } } catch (RuntimeException e) { throw new ServletException(sm.getString( "expiresFilter.exceptionProcessingParameter", name, value), e); } } log.debug(sm.getString("expiresFilter.filterInitialized", this.toString())); } /** * *

    * protected for extension. *

    */ protected boolean isEligibleToExpirationHeaderGeneration( HttpServletRequest request, XHttpServletResponse response) { boolean expirationHeaderHasBeenSet = response.containsHeader(HEADER_EXPIRES) || contains(response.getCacheControlHeader(), "max-age"); if (expirationHeaderHasBeenSet) { if (log.isDebugEnabled()) { log.debug(sm.getString( "expiresFilter.expirationHeaderAlreadyDefined", request.getRequestURI(), Integer.valueOf(response.getStatus()), response.getContentType())); } return false; } for (int skippedStatusCode : this.excludedResponseStatusCodes) { if (response.getStatus() == skippedStatusCode) { if (log.isDebugEnabled()) { log.debug(sm.getString("expiresFilter.skippedStatusCode", request.getRequestURI(), Integer.valueOf(response.getStatus()), response.getContentType())); } return false; } } return true; } /** *

    * If no expiration header has been set by the servlet and an expiration has * been defined in the {@link ExpiresFilter} configuration, sets the ' * Expires' header and the attribute 'max-age' of the ' * Cache-Control' header. *

    *

    * Must be called on the "Start Write Response Body" event. *

    *

    * Invocations to Logger.debug(...) are guarded by * {@link Log#isDebugEnabled()} because * {@link HttpServletRequest#getRequestURI()} and * {@link HttpServletResponse#getContentType()} costs String * objects instantiations (as of Tomcat 7). *

    */ public void onBeforeWriteResponseBody(HttpServletRequest request, XHttpServletResponse response) { if (!isEligibleToExpirationHeaderGeneration(request, response)) { return; } Date expirationDate = getExpirationDate(response); if (expirationDate == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("expiresFilter.noExpirationConfigured", request.getRequestURI(), Integer.valueOf(response.getStatus()), response.getContentType())); } } else { if (log.isDebugEnabled()) { log.debug(sm.getString("expiresFilter.setExpirationDate", request.getRequestURI(), Integer.valueOf(response.getStatus()), response.getContentType(), expirationDate)); } String maxAgeDirective = "max-age=" + ((expirationDate.getTime() - System.currentTimeMillis()) / 1000); String cacheControlHeader = response.getCacheControlHeader(); String newCacheControlHeader = (cacheControlHeader == null) ? maxAgeDirective : cacheControlHeader + ", " + maxAgeDirective; response.setHeader(HEADER_CACHE_CONTROL, newCacheControlHeader); response.setDateHeader(HEADER_EXPIRES, expirationDate.getTime()); } } /** * Parse configuration lines like ' * access plus 1 month 15 days 2 hours' or ' * modification 1 day 2 hours 5 seconds' * * @param inputLine */ protected ExpiresConfiguration parseExpiresConfiguration(String inputLine) { String line = inputLine.trim(); StringTokenizer tokenizer = new StringTokenizer(line, " "); String currentToken; try { currentToken = tokenizer.nextToken(); } catch (NoSuchElementException e) { throw new IllegalStateException(sm.getString( "expiresFilter.startingPointNotFound", line)); } StartingPoint startingPoint; if ("access".equalsIgnoreCase(currentToken) || "now".equalsIgnoreCase(currentToken)) { startingPoint = StartingPoint.ACCESS_TIME; } else if ("modification".equalsIgnoreCase(currentToken)) { startingPoint = StartingPoint.LAST_MODIFICATION_TIME; } else if (!tokenizer.hasMoreTokens() && startsWithIgnoreCase(currentToken, "a")) { startingPoint = StartingPoint.ACCESS_TIME; // trick : convert duration configuration from old to new style tokenizer = new StringTokenizer(currentToken.substring(1) + " seconds", " "); } else if (!tokenizer.hasMoreTokens() && startsWithIgnoreCase(currentToken, "m")) { startingPoint = StartingPoint.LAST_MODIFICATION_TIME; // trick : convert duration configuration from old to new style tokenizer = new StringTokenizer(currentToken.substring(1) + " seconds", " "); } else { throw new IllegalStateException(sm.getString( "expiresFilter.startingPointInvalid", currentToken, line)); } try { currentToken = tokenizer.nextToken(); } catch (NoSuchElementException e) { throw new IllegalStateException(sm.getString( "Duration not found in directive '{}'", line)); } if ("plus".equalsIgnoreCase(currentToken)) { // skip try { currentToken = tokenizer.nextToken(); } catch (NoSuchElementException e) { throw new IllegalStateException(sm.getString( "Duration not found in directive '{}'", line)); } } List durations = new ArrayList(); while (currentToken != null) { int amount; try { amount = Integer.parseInt(currentToken); } catch (NumberFormatException e) { throw new IllegalStateException(sm.getString( "Invalid duration (number) '{}' in directive '{}'", currentToken, line)); } try { currentToken = tokenizer.nextToken(); } catch (NoSuchElementException e) { throw new IllegalStateException( sm.getString( "Duration unit not found after amount {} in directive '{}'", Integer.valueOf(amount), line)); } DurationUnit durationUnit; if ("years".equalsIgnoreCase(currentToken)) { durationUnit = DurationUnit.YEAR; } else if ("month".equalsIgnoreCase(currentToken) || "months".equalsIgnoreCase(currentToken)) { durationUnit = DurationUnit.MONTH; } else if ("week".equalsIgnoreCase(currentToken) || "weeks".equalsIgnoreCase(currentToken)) { durationUnit = DurationUnit.WEEK; } else if ("day".equalsIgnoreCase(currentToken) || "days".equalsIgnoreCase(currentToken)) { durationUnit = DurationUnit.DAY; } else if ("hour".equalsIgnoreCase(currentToken) || "hours".equalsIgnoreCase(currentToken)) { durationUnit = DurationUnit.HOUR; } else if ("minute".equalsIgnoreCase(currentToken) || "minutes".equalsIgnoreCase(currentToken)) { durationUnit = DurationUnit.MINUTE; } else if ("second".equalsIgnoreCase(currentToken) || "seconds".equalsIgnoreCase(currentToken)) { durationUnit = DurationUnit.SECOND; } else { throw new IllegalStateException( sm.getString( "Invalid duration unit (years|months|weeks|days|hours|minutes|seconds) '{}' in directive '{}'", currentToken, line)); } Duration duration = new Duration(amount, durationUnit); durations.add(duration); if (tokenizer.hasMoreTokens()) { currentToken = tokenizer.nextToken(); } else { currentToken = null; } } return new ExpiresConfiguration(startingPoint, durations); } public void setDefaultExpiresConfiguration( ExpiresConfiguration defaultExpiresConfiguration) { this.defaultExpiresConfiguration = defaultExpiresConfiguration; } public void setExcludedResponseStatusCodes(int[] excludedResponseStatusCodes) { this.excludedResponseStatusCodes = excludedResponseStatusCodes; } public void setExpiresConfigurationByContentType( Map expiresConfigurationByContentType) { this.expiresConfigurationByContentType = expiresConfigurationByContentType; } @Override public String toString() { return getClass().getSimpleName() + "[excludedResponseStatusCode=[" + intsToCommaDelimitedString(this.excludedResponseStatusCodes) + "], default=" + this.defaultExpiresConfiguration + ", byType=" + this.expiresConfigurationByContentType + "]"; } } tomcat7-7.0.52/java/org/apache/catalina/filters/Constants.java0000644000175100017510000000245212271471332024144 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; /** * Manifest constants for this Java package. * * * @author Craig R. McClanahan */ public final class Constants { public static final String Package = "org.apache.catalina.filters"; public static final String CSRF_NONCE_SESSION_ATTR_NAME = "org.apache.catalina.filters.CSRF_NONCE"; public static final String CSRF_NONCE_REQUEST_PARAM = "org.apache.catalina.filters.CSRF_NONCE"; public static final String METHOD_GET = "GET"; } tomcat7-7.0.52/java/org/apache/catalina/filters/LocalStrings.properties0000644000175100017510000000573112271471332026052 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. addDefaultCharset.unsupportedCharset=Specified character set [{0}] is not supported corsFilter.invalidPreflightMaxAge=Unable to parse preflightMaxAge corsFilter.nullRequest=HttpServletRequest object is null corsFilter.nullRequestType=CORSRequestType object is null corsFilter.onlyHttp=CORS doesn't support non-HTTP request or response corsFilter.wrongType1=Expects a HttpServletRequest object of type [{0}] corsFilter.wrongType2=Expects a HttpServletRequest object of type [{0}] or [{1}] csrfPrevention.invalidRandomClass=Unable to create Random source using class [{0}] filterbase.noSuchProperty=The property "{0}" is not defined for filters of type "{1}" http.403=Access to the specified resource ({0}) has been forbidden. expiresFilter.noExpirationConfigured=Request "{0}" with response status "{1}" content-type "{2}", no expiration configured expiresFilter.setExpirationDate=Request "{0}" with response status "{1}" content-type "{2}", set expiration date {3} expiresFilter.startingPointNotFound=Starting point (access|now|modification|a|m) not found in directive "{0}" expiresFilter.startingPointInvalid=Invalid starting point (access|now|modification|a|m) "{0}" in directive "{1}" expiresFilter.responseAlreadyCommited=Request "{0}", can not apply ExpiresFilter on already committed response. expiresFilter.noExpirationConfiguredForContentType=No Expires configuration found for content-type "{0}" expiresFilter.useMatchingConfiguration=Use {0} matching "{1}" for content-type "{2}" returns {3} expiresFilter.useDefaultConfiguration=Use default {0} for content-type "{1}" returns {2} expiresFilter.unsupportedStartingPoint=Unsupported startingPoint "{0}" expiresFilter.unknownParameterIgnored=Unknown parameter "{0}" with value "{1}" is ignored ! expiresFilter.exceptionProcessingParameter=Exception processing configuration parameter "{0}":"{1}" expiresFilter.filterInitialized=Filter initialized with configuration {0} expiresFilter.expirationHeaderAlreadyDefined=Request "{0}" with response status "{1}" content-type "{2}", expiration header already defined expiresFilter.skippedStatusCode=Request "{0}" with response status "{1}" content-type "{1}", skip expiration header generation for given status tomcat7-7.0.52/java/org/apache/catalina/filters/CsrfPreventionFilter.java0000644000175100017510000002647112200762652026314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import java.io.Serializable; import java.security.SecureRandom; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Random; import java.util.Set; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.http.HttpSession; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Provides basic CSRF protection for a web application. The filter assumes * that: *
      *
    • The filter is mapped to /*
    • *
    • {@link HttpServletResponse#encodeRedirectURL(String)} and * {@link HttpServletResponse#encodeURL(String)} are used to encode all URLs * returned to the client *
    */ public class CsrfPreventionFilter extends FilterBase { private static final Log log = LogFactory.getLog(CsrfPreventionFilter.class); private String randomClass = SecureRandom.class.getName(); private Random randomSource; private int denyStatus = HttpServletResponse.SC_FORBIDDEN; private final Set entryPoints = new HashSet(); private int nonceCacheSize = 5; @Override protected Log getLogger() { return log; } /** * Return response status code that is used to reject denied request. */ public int getDenyStatus() { return denyStatus; } /** * Set response status code that is used to reject denied request. If none * set, the default value of 403 will be used. * * @param denyStatus * HTTP status code */ public void setDenyStatus(int denyStatus) { this.denyStatus = denyStatus; } /** * Entry points are URLs that will not be tested for the presence of a valid * nonce. They are used to provide a way to navigate back to a protected * application after navigating away from it. Entry points will be limited * to HTTP GET requests and should not trigger any security sensitive * actions. * * @param entryPoints Comma separated list of URLs to be configured as * entry points. */ public void setEntryPoints(String entryPoints) { String values[] = entryPoints.split(","); for (String value : values) { this.entryPoints.add(value.trim()); } } /** * Sets the number of previously issued nonces that will be cached on a LRU * basis to support parallel requests, limited use of the refresh and back * in the browser and similar behaviors that may result in the submission * of a previous nonce rather than the current one. If not set, the default * value of 5 will be used. * * @param nonceCacheSize The number of nonces to cache */ public void setNonceCacheSize(int nonceCacheSize) { this.nonceCacheSize = nonceCacheSize; } /** * Specify the class to use to generate the nonces. Must be in instance of * {@link Random}. * * @param randomClass The name of the class to use */ public void setRandomClass(String randomClass) { this.randomClass = randomClass; } @Override public void init(FilterConfig filterConfig) throws ServletException { // Set the parameters super.init(filterConfig); try { Class clazz = Class.forName(randomClass); randomSource = (Random) clazz.newInstance(); } catch (ClassNotFoundException e) { ServletException se = new ServletException(sm.getString( "csrfPrevention.invalidRandomClass", randomClass), e); throw se; } catch (InstantiationException e) { ServletException se = new ServletException(sm.getString( "csrfPrevention.invalidRandomClass", randomClass), e); throw se; } catch (IllegalAccessException e) { ServletException se = new ServletException(sm.getString( "csrfPrevention.invalidRandomClass", randomClass), e); throw se; } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletResponse wResponse = null; if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; boolean skipNonceCheck = false; if (Constants.METHOD_GET.equals(req.getMethod())) { String path = req.getServletPath(); if (req.getPathInfo() != null) { path = path + req.getPathInfo(); } if (entryPoints.contains(path)) { skipNonceCheck = true; } } HttpSession session = req.getSession(false); @SuppressWarnings("unchecked") LruCache nonceCache = (session == null) ? null : (LruCache) session.getAttribute( Constants.CSRF_NONCE_SESSION_ATTR_NAME); if (!skipNonceCheck) { String previousNonce = req.getParameter(Constants.CSRF_NONCE_REQUEST_PARAM); if (nonceCache == null || previousNonce == null || !nonceCache.contains(previousNonce)) { res.sendError(denyStatus); return; } } if (nonceCache == null) { nonceCache = new LruCache(nonceCacheSize); if (session == null) { session = req.getSession(true); } session.setAttribute( Constants.CSRF_NONCE_SESSION_ATTR_NAME, nonceCache); } String newNonce = generateNonce(); nonceCache.add(newNonce); wResponse = new CsrfResponseWrapper(res, newNonce); } else { wResponse = response; } chain.doFilter(request, wResponse); } @Override protected boolean isConfigProblemFatal() { return true; } /** * Generate a once time token (nonce) for authenticating subsequent * requests. This will also add the token to the session. The nonce * generation is a simplified version of ManagerBase.generateSessionId(). * */ protected String generateNonce() { byte random[] = new byte[16]; // Render the result as a String of hexadecimal digits StringBuilder buffer = new StringBuilder(); randomSource.nextBytes(random); for (int j = 0; j < random.length; j++) { byte b1 = (byte) ((random[j] & 0xf0) >> 4); byte b2 = (byte) (random[j] & 0x0f); if (b1 < 10) { buffer.append((char) ('0' + b1)); } else { buffer.append((char) ('A' + (b1 - 10))); } if (b2 < 10) { buffer.append((char) ('0' + b2)); } else { buffer.append((char) ('A' + (b2 - 10))); } } return buffer.toString(); } protected static class CsrfResponseWrapper extends HttpServletResponseWrapper { private final String nonce; public CsrfResponseWrapper(HttpServletResponse response, String nonce) { super(response); this.nonce = nonce; } @Override @Deprecated public String encodeRedirectUrl(String url) { return encodeRedirectURL(url); } @Override public String encodeRedirectURL(String url) { return addNonce(super.encodeRedirectURL(url)); } @Override @Deprecated public String encodeUrl(String url) { return encodeURL(url); } @Override public String encodeURL(String url) { return addNonce(super.encodeURL(url)); } /** * Return the specified URL with the nonce added to the query string. * * @param url URL to be modified * @param nonce The nonce to add */ private String addNonce(String url) { if ((url == null) || (nonce == null)) { return (url); } String path = url; String query = ""; String anchor = ""; int pound = path.indexOf('#'); if (pound >= 0) { anchor = path.substring(pound); path = path.substring(0, pound); } int question = path.indexOf('?'); if (question >= 0) { query = path.substring(question); path = path.substring(0, question); } StringBuilder sb = new StringBuilder(path); if (query.length() >0) { sb.append(query); sb.append('&'); } else { sb.append('?'); } sb.append(Constants.CSRF_NONCE_REQUEST_PARAM); sb.append('='); sb.append(nonce); sb.append(anchor); return (sb.toString()); } } protected static class LruCache implements Serializable { private static final long serialVersionUID = 1L; // Although the internal implementation uses a Map, this cache // implementation is only concerned with the keys. private final Map cache; public LruCache(final int cacheSize) { cache = new LinkedHashMap() { private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry eldest) { if (size() > cacheSize) { return true; } return false; } }; } public void add(T key) { synchronized (cache) { cache.put(key, null); } } public boolean contains(T key) { synchronized (cache) { return cache.containsKey(key); } } } } tomcat7-7.0.52/java/org/apache/catalina/filters/LocalStrings_fr.properties0000644000175100017510000000154712271471332026542 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. http.403=L''acc\u00e8s \u00e0 la ressource demand\u00e9e ({0}) a \u00e9t\u00e9 interdit. tomcat7-7.0.52/java/org/apache/catalina/filters/AddDefaultCharsetFilter.java0000644000175100017510000001106312271471332026643 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import java.nio.charset.Charset; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Filter that explicitly sets the default character set for media subtypes of * the "text" type to ISO-8859-1, or another user defined character set. RFC2616 * explicitly states that browsers must use ISO-8859-1 if no character set is * defined for media with subtype "text". However, browsers may attempt to * auto-detect the character set. This may be exploited by an attacker to * perform an XSS attack. Internet Explorer has this behaviour by default. Other * browsers have an option to enable it.
    * * This filter prevents the attack by explicitly setting a character set. Unless * the provided character set is explicitly overridden by the user - in which * case they deserve everything they get - the browser will adhere to an * explicitly set character set, thus preventing the XSS attack. */ public class AddDefaultCharsetFilter extends FilterBase { private static final Log log = LogFactory.getLog(AddDefaultCharsetFilter.class); private static final String DEFAULT_ENCODING = "ISO-8859-1"; private String encoding; public void setEncoding(String encoding) { this.encoding = encoding; } @Override protected Log getLogger() { return log; } @Override public void init(FilterConfig filterConfig) throws ServletException { super.init(filterConfig); if (encoding == null || encoding.length() == 0 || encoding.equalsIgnoreCase("default")) { encoding = DEFAULT_ENCODING; } else if (encoding.equalsIgnoreCase("system")) { encoding = Charset.defaultCharset().name(); } else if (!Charset.isSupported(encoding)) { throw new IllegalArgumentException(sm.getString( "addDefaultCharset.unsupportedCharset", encoding)); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Wrap the response if (response instanceof HttpServletResponse) { ResponseWrapper wrapped = new ResponseWrapper((HttpServletResponse)response, encoding); chain.doFilter(request, wrapped); } else { chain.doFilter(request, response); } } /** * Wrapper that adds a character set for text media types if no character * set is specified. */ public static class ResponseWrapper extends HttpServletResponseWrapper { private String encoding; public ResponseWrapper(HttpServletResponse response, String encoding) { super(response); this.encoding = encoding; } @Override public void setContentType(String ct) { if (ct != null && ct.startsWith("text/")) { if (ct.indexOf("charset=") < 0) { super.setContentType(ct + ";charset=" + encoding); } else { super.setContentType(ct); encoding = getCharacterEncoding(); } } else { super.setContentType(ct); } } @Override public void setCharacterEncoding(String charset) { super.setCharacterEncoding(charset); encoding = charset; } } } tomcat7-7.0.52/java/org/apache/catalina/filters/RequestFilter.java0000644000175100017510000002143612271471332024771 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import java.util.regex.Pattern; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometFilter; import org.apache.catalina.comet.CometFilterChain; /** * Implementation of a Filter that performs filtering based on comparing the * appropriate request property (selected based on which subclass you choose * to configure into your Container's pipeline) against the regular expressions * configured for this Filter. *

    * This filter is configured by setting the allow and/or * deny properties to a regular expressions (in the syntax * supported by {@link Pattern}) to which the appropriate request property will * be compared. Evaluation proceeds as follows: *

      *
    • The subclass extracts the request property to be filtered, and * calls the common process() method. *
    • If there is a deny expression configured, the property will be compared * to the expression. If a match is found, this request will be rejected * with a "Forbidden" HTTP response.
    • *
    • If there is a allow expression configured, the property will be compared * to the expression. If a match is found, this request will be allowed to * pass through to the next filter in the current pipeline.
    • *
    • If a deny expression was specified but no allow expression, allow this * request to pass through (because none of the deny expressions matched * it). *
    • The request will be rejected with a "Forbidden" HTTP response.
    • *
    */ public abstract class RequestFilter extends FilterBase implements CometFilter { // ----------------------------------------------------- Instance Variables /** * The regular expression used to test for allowed requests. */ protected Pattern allow = null; /** * The regular expression used to test for denied requests. */ protected Pattern deny = null; /** * The HTTP response status code that is used when rejecting denied * request. It is 403 by default, but may be changed to be 404. */ protected int denyStatus = HttpServletResponse.SC_FORBIDDEN; /** * mime type -- "text/plain" */ private static final String PLAIN_TEXT_MIME_TYPE = "text/plain"; // ------------------------------------------------------------- Properties /** * Return the regular expression used to test for allowed requests for this * Filter, if any; otherwise, return null. */ public String getAllow() { if (allow == null) { return null; } return allow.toString(); } /** * Set the regular expression used to test for allowed requests for this * Filter, if any. * * @param allow The new allow expression */ public void setAllow(String allow) { if (allow == null || allow.length() == 0) { this.allow = null; } else { this.allow = Pattern.compile(allow); } } /** * Return the regular expression used to test for denied requests for this * Filter, if any; otherwise, return null. */ public String getDeny() { if (deny == null) { return null; } return deny.toString(); } /** * Set the regular expression used to test for denied requests for this * Filter, if any. * * @param deny The new deny expression */ public void setDeny(String deny) { if (deny == null || deny.length() == 0) { this.deny = null; } else { this.deny = Pattern.compile(deny); } } /** * Return response status code that is used to reject denied request. */ public int getDenyStatus() { return denyStatus; } /** * Set response status code that is used to reject denied request. */ public void setDenyStatus(int denyStatus) { this.denyStatus = denyStatus; } // --------------------------------------------------------- Public Methods /** * Extract the desired request property, and pass it (along with the * specified request and response objects) to the protected * process() method to perform the actual filtering. * This method must be implemented by a concrete subclass. * * @param request The servlet request to be processed * @param response The servlet response to be created * @param chain The filter chain * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public abstract void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; // ------------------------------------------------------ Protected Methods @Override protected boolean isConfigProblemFatal() { return true; } /** * Perform the filtering that has been configured for this Filter, matching * against the specified request property. * * @param property The request property on which to filter * @param request The servlet request to be processed * @param response The servlet response to be processed * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ protected void process(String property, ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (isAllowed(property)) { chain.doFilter(request, response); } else { if (response instanceof HttpServletResponse) { ((HttpServletResponse) response).sendError(denyStatus); } else { sendErrorWhenNotHttp(response); } } } /** * Perform the filtering that has been configured for this Filter, matching * against the specified request property. * * @param property The property to check against the allow/deny rules * @param event The comet event to be filtered * @param chain The comet filter chain * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ protected void processCometEvent(String property, CometEvent event, CometFilterChain chain) throws IOException, ServletException { HttpServletResponse response = event.getHttpServletResponse(); if (isAllowed(property)) { chain.doFilterEvent(event); } else { response.sendError(denyStatus); event.close(); } } /** * Process the allow and deny rules for the provided property. * * @param property The property to test against the allow and deny lists * @return true if this request should be allowed, * false otherwise */ private boolean isAllowed(String property) { if (deny != null && deny.matcher(property).matches()) { return false; } // Check the allow patterns, if any if (allow != null && allow.matcher(property).matches()) { return true; } // Allow if denies specified but not allows if (deny != null && allow == null) { return true; } // Deny this request return false; } private void sendErrorWhenNotHttp(ServletResponse response) throws IOException { response.setContentType(PLAIN_TEXT_MIME_TYPE); response.getWriter().write(sm.getString("http.403")); response.getWriter().flush(); } } tomcat7-7.0.52/java/org/apache/catalina/filters/SetCharacterEncodingFilter.java0000644000175100017510000001201212271471332027346 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.filters; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    Example filter that sets the character encoding to be used in parsing the * incoming request, either unconditionally or only if the client did not * specify a character encoding. Configuration of this filter is based on * the following initialization parameters:

    *
      *
    • encoding - The character encoding to be configured * for this request, either conditionally or unconditionally based on * the ignore initialization parameter. This parameter * is required, so there is no default.
    • *
    • ignore - If set to "true", any character encoding * specified by the client is ignored, and the value returned by the * selectEncoding() method is set. If set to "false, * selectEncoding() is called only if the * client has not already specified an encoding. By default, this * parameter is set to "false".
    • *
    * *

    Although this filter can be used unchanged, it is also easy to * subclass it and make the selectEncoding() method more * intelligent about what encoding to choose, based on characteristics of * the incoming request (such as the values of the Accept-Language * and User-Agent headers, or a value stashed in the current * user's session.

    */ public class SetCharacterEncodingFilter extends FilterBase { private static final Log log = LogFactory.getLog(SetCharacterEncodingFilter.class); // ----------------------------------------------------- Instance Variables /** * The default character encoding to set for requests that pass through * this filter. */ private String encoding = null; public void setEncoding(String encoding) { this.encoding = encoding; } public String getEncoding() { return encoding; } /** * Should a character encoding specified by the client be ignored? */ private boolean ignore = false; public void setIgnore(boolean ignore) { this.ignore = ignore; } public boolean isIgnore() { return ignore; } // --------------------------------------------------------- Public Methods /** * Select and set (if specified) the character encoding to be used to * interpret request parameters for this request. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param chain The filter chain we are processing * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Conditionally select and set the character encoding to be used if (ignore || (request.getCharacterEncoding() == null)) { String characterEncoding = selectEncoding(request); if (characterEncoding != null) { request.setCharacterEncoding(characterEncoding); } } // Pass control on to the next filter chain.doFilter(request, response); } // ------------------------------------------------------ Protected Methods @Override protected Log getLogger() { return log; } /** * Select an appropriate character encoding to be used, based on the * characteristics of the current request and/or filter initialization * parameters. If no character encoding should be set, return * null. *

    * The default implementation unconditionally returns the value configured * by the encoding initialization parameter for this * filter. * * @param request The servlet request we are processing */ protected String selectEncoding(ServletRequest request) { return this.encoding; } } tomcat7-7.0.52/java/org/apache/catalina/Manager.java0000644000175100017510000002477712271471332022110 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.beans.PropertyChangeListener; import java.io.IOException; /** * A Manager manages the pool of Sessions that are associated with a * particular Container. Different Manager implementations may support * value-added features such as the persistent storage of session data, * as well as migrating sessions for distributable web applications. *

    * In order for a Manager implementation to successfully operate * with a Context implementation that implements reloading, it * must obey the following constraints: *

      *
    • Must implement Lifecycle so that the Context can indicate * that a restart is required. *
    • Must allow a call to stop() to be followed by a call to * start() on the same Manager instance. *
    * * @author Craig R. McClanahan */ public interface Manager { // ------------------------------------------------------------- Properties /** * Return the Container with which this Manager is associated. */ public Container getContainer(); /** * Set the Container with which this Manager is associated. * * @param container The newly associated Container */ public void setContainer(Container container); /** * Return the distributable flag for the sessions supported by * this Manager. */ public boolean getDistributable(); /** * Set the distributable flag for the sessions supported by this * Manager. If this flag is set, all user data objects added to * sessions associated with this manager must implement Serializable. * * @param distributable The new distributable flag */ public void setDistributable(boolean distributable); /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo(); /** * Return the default maximum inactive interval (in seconds) * for Sessions created by this Manager. */ public int getMaxInactiveInterval(); /** * Set the default maximum inactive interval (in seconds) * for Sessions created by this Manager. * * @param interval The new default value */ public void setMaxInactiveInterval(int interval); /** * Gets the session id length (in bytes) of Sessions created by * this Manager. * * @return The session id length */ public int getSessionIdLength(); /** * Sets the session id length (in bytes) for Sessions created by this * Manager. * * @param idLength The session id length */ public void setSessionIdLength(int idLength); /** * Returns the total number of sessions created by this manager. * * @return Total number of sessions created by this manager. */ public long getSessionCounter(); /** * Sets the total number of sessions created by this manager. * * @param sessionCounter Total number of sessions created by this manager. */ public void setSessionCounter(long sessionCounter); /** * Gets the maximum number of sessions that have been active at the same * time. * * @return Maximum number of sessions that have been active at the same * time */ public int getMaxActive(); /** * (Re)sets the maximum number of sessions that have been active at the * same time. * * @param maxActive Maximum number of sessions that have been active at * the same time. */ public void setMaxActive(int maxActive); /** * Gets the number of currently active sessions. * * @return Number of currently active sessions */ public int getActiveSessions(); /** * Gets the number of sessions that have expired. * * @return Number of sessions that have expired */ public long getExpiredSessions(); /** * Sets the number of sessions that have expired. * * @param expiredSessions Number of sessions that have expired */ public void setExpiredSessions(long expiredSessions); /** * Gets the number of sessions that were not created because the maximum * number of active sessions was reached. * * @return Number of rejected sessions */ public int getRejectedSessions(); /** * Gets the longest time (in seconds) that an expired session had been * alive. * * @return Longest time (in seconds) that an expired session had been * alive. */ public int getSessionMaxAliveTime(); /** * Sets the longest time (in seconds) that an expired session had been * alive. * * @param sessionMaxAliveTime Longest time (in seconds) that an expired * session had been alive. */ public void setSessionMaxAliveTime(int sessionMaxAliveTime); /** * Gets the average time (in seconds) that expired sessions had been * alive. This may be based on sample data. * * @return Average time (in seconds) that expired sessions had been * alive. */ public int getSessionAverageAliveTime(); /** * Gets the current rate of session creation (in session per minute). This * may be based on sample data. * * @return The current rate (in sessions per minute) of session creation */ public int getSessionCreateRate(); /** * Gets the current rate of session expiration (in session per minute). This * may be based on sample data * * @return The current rate (in sessions per minute) of session expiration */ public int getSessionExpireRate(); // --------------------------------------------------------- Public Methods /** * Add this Session to the set of active Sessions for this Manager. * * @param session Session to be added */ public void add(Session session); /** * Add a property change listener to this component. * * @param listener The listener to add */ public void addPropertyChangeListener(PropertyChangeListener listener); /** * Change the session ID of the current session to a new randomly generated * session ID. * * @param session The session to change the session ID for */ public void changeSessionId(Session session); /** * Get a session from the recycled ones or create a new empty one. * The PersistentManager manager does not need to create session data * because it reads it from the Store. */ public Session createEmptySession(); /** * Construct and return a new session object, based on the default * settings specified by this Manager's properties. The session * id specified will be used as the session id. * If a new session cannot be created for any reason, return * null. * * @param sessionId The session id which should be used to create the * new session; if null, the session * id will be assigned by this method, and available via the getId() * method of the returned session. * @exception IllegalStateException if a new session cannot be * instantiated for any reason */ public Session createSession(String sessionId); /** * Return the active Session, associated with this Manager, with the * specified session id (if any); otherwise return null. * * @param id The session id for the session to be returned * * @exception IllegalStateException if a new session cannot be * instantiated for any reason * @exception IOException if an input/output error occurs while * processing this request */ public Session findSession(String id) throws IOException; /** * Return the set of active Sessions associated with this Manager. * If this Manager has no active Sessions, a zero-length array is returned. */ public Session[] findSessions(); /** * Load any currently active sessions that were previously unloaded * to the appropriate persistence mechanism, if any. If persistence is not * supported, this method returns without doing anything. * * @exception ClassNotFoundException if a serialized class cannot be * found during the reload * @exception IOException if an input/output error occurs */ public void load() throws ClassNotFoundException, IOException; /** * Remove this Session from the active Sessions for this Manager. * * @param session Session to be removed */ public void remove(Session session); /** * Remove this Session from the active Sessions for this Manager. * * @param session Session to be removed * @param update Should the expiration statistics be updated */ public void remove(Session session, boolean update); /** * Remove a property change listener from this component. * * @param listener The listener to remove */ public void removePropertyChangeListener(PropertyChangeListener listener); /** * Save any currently active sessions in the appropriate persistence * mechanism, if any. If persistence is not supported, this method * returns without doing anything. * * @exception IOException if an input/output error occurs */ public void unload() throws IOException; /** * This method will be invoked by the context/container on a periodic * basis and allows the manager to implement * a method that executes periodic tasks, such as expiring sessions etc. */ public void backgroundProcess(); } tomcat7-7.0.52/java/org/apache/catalina/Group.java0000644000175100017510000000572112271471332021616 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.security.Principal; import java.util.Iterator; /** *

    Abstract representation of a group of {@link User}s in a * {@link UserDatabase}. Each user that is a member of this group * inherits the {@link Role}s assigned to the group.

    * * @author Craig R. McClanahan * @since 4.1 */ public interface Group extends Principal { // ------------------------------------------------------------- Properties /** * Return the description of this group. */ public String getDescription(); /** * Set the description of this group. * * @param description The new description */ public void setDescription(String description); /** * Return the group name of this group, which must be unique * within the scope of a {@link UserDatabase}. */ public String getGroupname(); /** * Set the group name of this group, which must be unique * within the scope of a {@link UserDatabase}. * * @param groupname The new group name */ public void setGroupname(String groupname); /** * Return the set of {@link Role}s assigned specifically to this group. */ public Iterator getRoles(); /** * Return the {@link UserDatabase} within which this Group is defined. */ public UserDatabase getUserDatabase(); /** * Return the set of {@link User}s that are members of this group. */ public Iterator getUsers(); // --------------------------------------------------------- Public Methods /** * Add a new {@link Role} to those assigned specifically to this group. * * @param role The new role */ public void addRole(Role role); /** * Is this group specifically assigned the specified {@link Role}? * * @param role The role to check */ public boolean isInRole(Role role); /** * Remove a {@link Role} from those assigned to this group. * * @param role The old role */ public void removeRole(Role role); /** * Remove all {@link Role}s from those assigned to this group. */ public void removeRoles(); } tomcat7-7.0.52/java/org/apache/catalina/LifecycleListener.java0000644000175100017510000000253012271471332024122 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * Interface defining a listener for significant events (including "component * start" and "component stop" generated by a component that implements the * Lifecycle interface. The listener will be fired after the associated state * change has taken place. * * @author Craig R. McClanahan */ public interface LifecycleListener { /** * Acknowledge the occurrence of the specified event. * * @param event LifecycleEvent that has occurred */ public void lifecycleEvent(LifecycleEvent event); } tomcat7-7.0.52/java/org/apache/catalina/Session.java0000644000175100017510000002256712271471332022154 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.security.Principal; import java.util.Iterator; import javax.servlet.http.HttpSession; /** * A Session is the Catalina-internal facade for an * HttpSession that is used to maintain state information * between requests for a particular user of a web application. * * @author Craig R. McClanahan */ public interface Session { // ----------------------------------------------------- Manifest Constants /** * The SessionEvent event type when a session is created. */ public static final String SESSION_CREATED_EVENT = "createSession"; /** * The SessionEvent event type when a session is destroyed. */ public static final String SESSION_DESTROYED_EVENT = "destroySession"; /** * The SessionEvent event type when a session is activated. */ public static final String SESSION_ACTIVATED_EVENT = "activateSession"; /** * The SessionEvent event type when a session is passivated. */ public static final String SESSION_PASSIVATED_EVENT = "passivateSession"; // ------------------------------------------------------------- Properties /** * Return the authentication type used to authenticate our cached * Principal, if any. */ public String getAuthType(); /** * Set the authentication type used to authenticate our cached * Principal, if any. * * @param authType The new cached authentication type */ public void setAuthType(String authType); /** * Return the creation time for this session. */ public long getCreationTime(); /** * Return the creation time for this session, bypassing the session validity * checks. */ public long getCreationTimeInternal(); /** * Set the creation time for this session. This method is called by the * Manager when an existing Session instance is reused. * * @param time The new creation time */ public void setCreationTime(long time); /** * Return the session identifier for this session. */ public String getId(); /** * Return the session identifier for this session. */ public String getIdInternal(); /** * Set the session identifier for this session and notifies any associated * listeners that a new session has been created. * * @param id The new session identifier */ public void setId(String id); /** * Set the session identifier for this session and optionally notifies any * associated listeners that a new session has been created. * * @param id The new session identifier * @param notify Should any associated listeners be notified that a new * session has been created? */ public void setId(String id, boolean notify); /** * Return descriptive information about this Session implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo(); /** * Return the last time the client sent a request associated with this * session, as the number of milliseconds since midnight, January 1, 1970 * GMT. Actions that your application takes, such as getting or setting * a value associated with the session, do not affect the access time. * This one gets updated whenever a request starts. */ public long getThisAccessedTime(); /** * Return the last client access time without invalidation check * @see #getThisAccessedTime() */ public long getThisAccessedTimeInternal(); /** * Return the last time the client sent a request associated with this * session, as the number of milliseconds since midnight, January 1, 1970 * GMT. Actions that your application takes, such as getting or setting * a value associated with the session, do not affect the access time. * This one gets updated whenever a request finishes. */ public long getLastAccessedTime(); /** * Return the last client access time without invalidation check * @see #getLastAccessedTime() */ public long getLastAccessedTimeInternal(); /** * Return the Manager within which this Session is valid. */ public Manager getManager(); /** * Set the Manager within which this Session is valid. * * @param manager The new Manager */ public void setManager(Manager manager); /** * Return the maximum time interval, in seconds, between client requests * before the servlet container will invalidate the session. A negative * time indicates that the session should never time out. */ public int getMaxInactiveInterval(); /** * Set the maximum time interval, in seconds, between client requests * before the servlet container will invalidate the session. A negative * time indicates that the session should never time out. * * @param interval The new maximum interval */ public void setMaxInactiveInterval(int interval); /** * Set the isNew flag for this session. * * @param isNew The new value for the isNew flag */ public void setNew(boolean isNew); /** * Return the authenticated Principal that is associated with this Session. * This provides an Authenticator with a means to cache a * previously authenticated Principal, and avoid potentially expensive * Realm.authenticate() calls on every request. If there * is no current associated Principal, return null. */ public Principal getPrincipal(); /** * Set the authenticated Principal that is associated with this Session. * This provides an Authenticator with a means to cache a * previously authenticated Principal, and avoid potentially expensive * Realm.authenticate() calls on every request. * * @param principal The new Principal, or null if none */ public void setPrincipal(Principal principal); /** * Return the HttpSession for which this object * is the facade. */ public HttpSession getSession(); /** * Set the isValid flag for this session. * * @param isValid The new value for the isValid flag */ public void setValid(boolean isValid); /** * Return the isValid flag for this session. */ public boolean isValid(); // --------------------------------------------------------- Public Methods /** * Update the accessed time information for this session. This method * should be called by the context when a request comes in for a particular * session, even if the application does not reference it. */ public void access(); /** * Add a session event listener to this component. */ public void addSessionListener(SessionListener listener); /** * End access to the session. */ public void endAccess(); /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. */ public void expire(); /** * Return the object bound with the specified name to the internal notes * for this session, or null if no such binding exists. * * @param name Name of the note to be returned */ public Object getNote(String name); /** * Return an Iterator containing the String names of all notes bindings * that exist for this session. */ public Iterator getNoteNames(); /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle(); /** * Remove any object bound to the specified name in the internal notes * for this session. * * @param name Name of the note to be removed */ public void removeNote(String name); /** * Remove a session event listener from this component. */ public void removeSessionListener(SessionListener listener); /** * Bind an object to a specified name in the internal notes associated * with this session, replacing any existing binding for this name. * * @param name Name to which the object should be bound * @param value Object to be bound to the specified name */ public void setNote(String name, Object value); } tomcat7-7.0.52/java/org/apache/catalina/connector/0000755000175100017510000000000012301126370021635 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/connector/LocalStrings_es.properties0000644000175100017510000001472712271471332027070 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # CoyoteConnector coyoteConnector.cannotRegisterProtocol = No puedo registrar MBean para el Protocolo coyoteConnector.protocolHandlerDestroyFailed = Fall\u00F3 la destrucci\u00F3n del manejador de protocolo coyoteConnector.protocolHandlerInitializationFailed = Fall\u00F3 la inicializaci\u00F3n del manejador de protocolo coyoteConnector.protocolHandlerInstantiationFailed = Fall\u00F3 la instanciaci\u00F3n del manejador de protocolo coyoteConnector.protocolHandlerStartFailed = Fall\u00F3 el arranque del manejador de protocolo coyoteConnector.protocolRegistrationFailed = Fall\u00F3 el registro de JMX coyoteConnector.protocolHandlerPauseFailed = Ha fallado la pausa del manejador de protocolo coyoteConnector.protocolHandlerResumeFailed = Ha fallado el rearranque del manejador de protocolo coyoteConnector.MapperRegistration = Mapeador de registro\: {0} coyoteConnector.protocolUnregistrationFailed = Ha fallado la parada del manejador de protocolo coyoteConnector.parseBodyMethodNoTrace = El m\u00E9todo TRACE NO DEBE DE incluir una entidad (vea RFC 2616 Secci\u00F3n 9.6) # # CoyoteAdapter coyoteAdapter.read = El servlet no ley\u00F3 todos los bytes disponibles durante el procesamiento del evento de lectura coyoteAdapter.parsePathParam = No puedo analizar los par\u00E1metros de ruta mediante la codificaci\u00F3n [{0}]. Se ignoran los par\u00E1metros de la URL. coyoteAdapter.debug = La variable [{0}] tiene el valor [{1}] coyoteAdapter.accesslogFail = Excepci\u00F3n al intentar a\u00F1adir una entrada al historial de acceso # # CoyoteResponse coyoteResponse.getOutputStream.ise = getWriter() ya ha sido llamado para esta respuesta coyoteResponse.getWriter.ise = getOutputStream() ya ha sido llamado para esta respuesta coyoteResponse.resetBuffer.ise = No puedo limpiar el b\u00FAfer despu\u00E9s de que la repuesta ha sido llevada a cabo coyoteResponse.sendError.ise = No puedo llamar a sendError() tras llevar a cabo la respuesta coyoteResponse.sendRedirect.ise = No puedo llamar a sendRedirect() tras llevar a cabo la respuesta coyoteResponse.setBufferSize.ise = No puedo cambiar la medida del b\u00FAfer tras escribir los datos # # CoyoteRequest coyoteRequest.getInputStream.ise = getReader() ya ha sido llamado para este requerimiento coyoteRequest.getReader.ise = getInputStream() ya ha sido llamado para este requerimiento coyoteRequest.sessionCreateCommitted = No puedo crear una sesi\u00F3n despu\u00E9s de llevar a cabo la respueta coyoteRequest.setAttribute.namenull = No pudeo llamar a setAttribute con un nombre nulo coyoteRequest.listenerStart = Excepci\u00F3n enviando evento inicializado de contexto a instancia de escuchador de clase {0} coyoteRequest.listenerStop = Excepci\u00F3n enviando evento destru\u00EDdo de contexto a instancia de escuchador de clase {0} coyoteRequest.attributeEvent = Excepci\u00F3n lanzada mediante el escuchador de eventos de atributos coyoteRequest.parseParameters = Excepci\u00F3n lanzada al procesar par\u00E1metros POST coyoteRequest.postTooLarge = No se analizaron los par\u00E1metros porque la medida de los datos enviados era demasiado grande. Usa el atributo maxPostSize del conector para resolver esto en caso de que la aplicaci\u00F3n debiera de aceptar POSTs m\u00E1s grandes. coyoteRequest.chunkedPostTooLarge = No se han analizado los par\u00E1metros porque la medida de los datos enviados meiante "post" era demasiado grande. Debido a que este requerimiento es una parte del original, no puede ser procesado. Utiliza el atributo "maxPostSize" del conector para resolver esta situaci\u00F3n, en caso de que la aplicaci\u00F3n deba de aceptar POSTs mayores. coyoteRequest.alreadyAuthenticated = Este requerimiento ya ha sido autenticado coyoteRequest.noLoginConfig = No se ha configurado mecanismo de autenticaci\u00F3n para este contexto coyoteRequest.authenticate.ise = No puedo llamar a authenticate() tras haberse acometido la respuesta coyoteRequest.uploadLocationInvalid = No es v\u00E1lida la localizaci\u00F3n [{0}] de carga temporal coyoteRequest.sessionEndAccessFail = Excepci\u00F3n disparada acabando acceso a sesi\u00F3n mientras se reciclaba el requerimiento requestFacade.nullRequest = El objeto de requerimiento ha sido reciclado y ya no est\u00E1 asociado con esta fachada responseFacade.nullResponse = El objeto de respuesta ha sido reciclado y ya no est\u00E1 asociado con esta fachada cometEvent.nullRequest = El objeto de evento ha sido reciclado y ya no est\u00E1 asociado con este requerimiento mapperListener.unknownDefaultHost = M\u00E1quina por defecto desconocida\: {0} para el conector [{1}] mapperListener.registerHost = Registrar m\u00E1quina {0} en dominio {1} para el conector [{2}] mapperListener.unregisterHost = Desregistrar m\u00E1quina {0} en dominio {1} para el conector [{2}] # # MapperListener mapperListener.registerContext = Registrar Contexto {0} para el conector [{1}] mapperListener.unregisterContext = Desregistrar Contexto {0} para el conector [{1}] mapperListener.registerWrapper = Registrar Arropador (Wrapper) {0} en Contexto {1} mapperListener.unregisterWrapper = Desregistrar Arropador (Wrapper) {0} en Contexto {1} mapperListener.addMBeanListenerFail = No pude a\u00F1adir escuchador de notificaci\u00F3n MBean para el conector [{0}] en dominio [{1}]. La adici\u00F3n de M\u00E1quinas, Contextos y Arropadores no ser\u00E1n visibles al conector. mapperListener.removeMBeanListenerFail = No pude quitar escuchador de notificaci\u00F3n MBean para el conector [{0}] en dominio [{1}]. Esto puede dar lugar a p\u00E9rdida de memoria. mapperListener.lifecycleListenerFail = No pude a\u00F1adir escuchador de Ciclo de Vida al objeto [{0}]. Los cambios en el estado del objeto pueden no ser reflejados correctamente en el mapeador para el conector [{1}] en el dominio [{2}]. inputBuffer.streamClosed = Flujo cerrado tomcat7-7.0.52/java/org/apache/catalina/connector/Connector.java0000644000175100017510000006655312271471332024460 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.net.InetAddress; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import javax.management.ObjectName; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Service; import org.apache.catalina.core.AprLifecycleListener; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.coyote.Adapter; import org.apache.coyote.ProtocolHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.http.mapper.Mapper; import org.apache.tomcat.util.res.StringManager; /** * Implementation of a Coyote connector. * * @author Craig R. McClanahan * @author Remy Maucherat */ public class Connector extends LifecycleMBeanBase { private static final Log log = LogFactory.getLog(Connector.class); /** * Alternate flag to enable recycling of facades. */ public static final boolean RECYCLE_FACADES = Boolean.valueOf(System.getProperty("org.apache.catalina.connector.RECYCLE_FACADES", "false")).booleanValue(); // ------------------------------------------------------------ Constructor public Connector() { this(null); } public Connector(String protocol) { setProtocol(protocol); // Instantiate protocol handler try { Class clazz = Class.forName(protocolHandlerClassName); this.protocolHandler = (ProtocolHandler) clazz.newInstance(); } catch (Exception e) { log.error(sm.getString( "coyoteConnector.protocolHandlerInstantiationFailed"), e); } } // ----------------------------------------------------- Instance Variables /** * The Service we are associated with (if any). */ protected Service service = null; /** * Do we allow TRACE ? */ protected boolean allowTrace = false; /** * Default timeout for asynchronous requests (ms). */ protected long asyncTimeout = 10000; /** * The "enable DNS lookups" flag for this Connector. */ protected boolean enableLookups = false; /* * Is generation of X-Powered-By response header enabled/disabled? */ protected boolean xpoweredBy = false; /** * Descriptive information about this Connector implementation. */ protected static final String info = "org.apache.catalina.connector.Connector/2.1"; /** * The port number on which we listen for requests. */ protected int port = -1; /** * The server name to which we should pretend requests to this Connector * were directed. This is useful when operating Tomcat behind a proxy * server, so that redirects get constructed accurately. If not specified, * the server name included in the Host header is used. */ protected String proxyName = null; /** * The server port to which we should pretend requests to this Connector * were directed. This is useful when operating Tomcat behind a proxy * server, so that redirects get constructed accurately. If not specified, * the port number specified by the port property is used. */ protected int proxyPort = 0; /** * The redirect port for non-SSL to SSL redirects. */ protected int redirectPort = 443; /** * The request scheme that will be set on all requests received * through this connector. */ protected String scheme = "http"; /** * The secure connection flag that will be set on all requests received * through this connector. */ protected boolean secure = false; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The maximum number of parameters (GET plus POST) which will be * automatically parsed by the container. 10000 by default. A value of less * than 0 means no limit. */ protected int maxParameterCount = 10000; /** * Maximum size of a POST which will be automatically parsed by the * container. 2MB by default. */ protected int maxPostSize = 2 * 1024 * 1024; /** * Maximum size of a POST which will be saved by the container * during authentication. 4kB by default */ protected int maxSavePostSize = 4 * 1024; /** * Comma-separated list of HTTP methods that will be parsed according * to POST-style rules for application/x-www-form-urlencoded request bodies. */ protected String parseBodyMethods = "POST"; /** * A Set of methods determined by {@link #parseBodyMethods}. */ protected HashSet parseBodyMethodsSet; /** * Flag to use IP-based virtual hosting. */ protected boolean useIPVHosts = false; /** * Coyote Protocol handler class name. * Defaults to the Coyote HTTP/1.1 protocolHandler. */ protected String protocolHandlerClassName = "org.apache.coyote.http11.Http11Protocol"; /** * Coyote protocol handler. */ protected ProtocolHandler protocolHandler = null; /** * Coyote adapter. */ protected Adapter adapter = null; /** * Mapper. */ protected Mapper mapper = new Mapper(); /** * Mapper listener. */ protected MapperListener mapperListener = new MapperListener(mapper, this); /** * URI encoding. */ protected String URIEncoding = null; /** * URI encoding as body. */ protected boolean useBodyEncodingForURI = false; protected static HashMap replacements = new HashMap(); static { replacements.put("acceptCount", "backlog"); replacements.put("connectionLinger", "soLinger"); replacements.put("connectionTimeout", "soTimeout"); replacements.put("rootFile", "rootfile"); } // ------------------------------------------------------------- Properties /** * Return a configured property. */ public Object getProperty(String name) { String repl = name; if (replacements.get(name) != null) { repl = replacements.get(name); } return IntrospectionUtils.getProperty(protocolHandler, repl); } /** * Set a configured property. */ public boolean setProperty(String name, String value) { String repl = name; if (replacements.get(name) != null) { repl = replacements.get(name); } return IntrospectionUtils.setProperty(protocolHandler, repl, value); } /** * Return a configured property. */ public Object getAttribute(String name) { return getProperty(name); } /** * Set a configured property. */ public void setAttribute(String name, Object value) { setProperty(name, String.valueOf(value)); } /** * Return the Service with which we are associated (if any). */ public Service getService() { return (this.service); } /** * Set the Service with which we are associated (if any). * * @param service The service that owns this Engine */ public void setService(Service service) { this.service = service; } /** * True if the TRACE method is allowed. Default value is "false". */ public boolean getAllowTrace() { return (this.allowTrace); } /** * Set the allowTrace flag, to disable or enable the TRACE HTTP method. * * @param allowTrace The new allowTrace flag */ public void setAllowTrace(boolean allowTrace) { this.allowTrace = allowTrace; setProperty("allowTrace", String.valueOf(allowTrace)); } /** * Return the default timeout for async requests in ms. */ public long getAsyncTimeout() { return asyncTimeout; } /** * Set the default timeout for async requests. * * @param asyncTimeout The new timeout in ms. */ public void setAsyncTimeout(long asyncTimeout) { this.asyncTimeout= asyncTimeout; setProperty("asyncTimeout", String.valueOf(asyncTimeout)); } /** * Return the "enable DNS lookups" flag. */ public boolean getEnableLookups() { return (this.enableLookups); } /** * Set the "enable DNS lookups" flag. * * @param enableLookups The new "enable DNS lookups" flag value */ public void setEnableLookups(boolean enableLookups) { this.enableLookups = enableLookups; setProperty("enableLookups", String.valueOf(enableLookups)); } /** * Return descriptive information about this Connector implementation. */ public String getInfo() { return (info); } /** * Return the mapper. */ public Mapper getMapper() { return (mapper); } /** * Return the maximum number of headers that are allowed by the container. A * value of less than 0 means no limit. */ public int getMaxHeaderCount() { return ((Integer) getProperty("maxHeaderCount")).intValue(); } /** * Set the maximum number of headers in a request that are allowed by the * container. A value of less than 0 means no limit. * * @param maxHeaderCount The new setting */ public void setMaxHeaderCount(int maxHeaderCount) { setProperty("maxHeaderCount", String.valueOf(maxHeaderCount)); } /** * Return the maximum number of parameters (GET plus POST) that will be * automatically parsed by the container. A value of less than 0 means no * limit. */ public int getMaxParameterCount() { return maxParameterCount; } /** * Set the maximum number of parameters (GET plus POST) that will be * automatically parsed by the container. A value of less than 0 means no * limit. * * @param maxParameterCount The new setting */ public void setMaxParameterCount(int maxParameterCount) { this.maxParameterCount = maxParameterCount; } /** * Return the maximum size of a POST which will be automatically * parsed by the container. */ public int getMaxPostSize() { return (maxPostSize); } /** * Set the maximum size of a POST which will be automatically * parsed by the container. * * @param maxPostSize The new maximum size in bytes of a POST which will * be automatically parsed by the container */ public void setMaxPostSize(int maxPostSize) { this.maxPostSize = maxPostSize; } /** * Return the maximum size of a POST which will be saved by the container * during authentication. */ public int getMaxSavePostSize() { return (maxSavePostSize); } /** * Set the maximum size of a POST which will be saved by the container * during authentication. * * @param maxSavePostSize The new maximum size in bytes of a POST which will * be saved by the container during authentication. */ public void setMaxSavePostSize(int maxSavePostSize) { this.maxSavePostSize = maxSavePostSize; setProperty("maxSavePostSize", String.valueOf(maxSavePostSize)); } public String getParseBodyMethods() { return this.parseBodyMethods; } public void setParseBodyMethods(String methods) { HashSet methodSet = new HashSet(); if( null != methods ) { methodSet.addAll(Arrays.asList(methods.split("\\s*,\\s*"))); } if( methodSet.contains("TRACE") ) { throw new IllegalArgumentException(sm.getString("coyoteConnector.parseBodyMethodNoTrace")); } this.parseBodyMethods = methods; this.parseBodyMethodsSet = methodSet; } protected boolean isParseBodyMethod(String method) { return parseBodyMethodsSet.contains(method); } /** * Return the port number on which this connector is configured to listen * for requests. The special value of 0 means select a random free port * when the socket is bound. */ public int getPort() { return (this.port); } /** * Set the port number on which we listen for requests. * * @param port The new port number */ public void setPort(int port) { this.port = port; setProperty("port", String.valueOf(port)); } /** * Return the port number on which this connector is listening to requests. * If the special value for {@link #port} of zero is used then this method * will report the actual port bound. */ public int getLocalPort() { return ((Integer) getProperty("localPort")).intValue(); } /** * Return the Coyote protocol handler in use. */ public String getProtocol() { if ("org.apache.coyote.http11.Http11Protocol".equals (getProtocolHandlerClassName()) || "org.apache.coyote.http11.Http11AprProtocol".equals (getProtocolHandlerClassName())) { return "HTTP/1.1"; } else if ("org.apache.coyote.ajp.AjpProtocol".equals (getProtocolHandlerClassName()) || "org.apache.coyote.ajp.AjpAprProtocol".equals (getProtocolHandlerClassName())) { return "AJP/1.3"; } return getProtocolHandlerClassName(); } /** * Set the Coyote protocol which will be used by the connector. * * @param protocol The Coyote protocol name */ public void setProtocol(String protocol) { if (AprLifecycleListener.isAprAvailable()) { if ("HTTP/1.1".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.http11.Http11AprProtocol"); } else if ("AJP/1.3".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.ajp.AjpAprProtocol"); } else if (protocol != null) { setProtocolHandlerClassName(protocol); } else { setProtocolHandlerClassName ("org.apache.coyote.http11.Http11AprProtocol"); } } else { if ("HTTP/1.1".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.http11.Http11Protocol"); } else if ("AJP/1.3".equals(protocol)) { setProtocolHandlerClassName ("org.apache.coyote.ajp.AjpProtocol"); } else if (protocol != null) { setProtocolHandlerClassName(protocol); } } } /** * Return the class name of the Coyote protocol handler in use. */ public String getProtocolHandlerClassName() { return (this.protocolHandlerClassName); } /** * Set the class name of the Coyote protocol handler which will be used * by the connector. * * @param protocolHandlerClassName The new class name */ public void setProtocolHandlerClassName(String protocolHandlerClassName) { this.protocolHandlerClassName = protocolHandlerClassName; } /** * Return the protocol handler associated with the connector. */ public ProtocolHandler getProtocolHandler() { return (this.protocolHandler); } /** * Return the proxy server name for this Connector. */ public String getProxyName() { return (this.proxyName); } /** * Set the proxy server name for this Connector. * * @param proxyName The new proxy server name */ public void setProxyName(String proxyName) { if(proxyName != null && proxyName.length() > 0) { this.proxyName = proxyName; setProperty("proxyName", proxyName); } else { this.proxyName = null; } } /** * Return the proxy server port for this Connector. */ public int getProxyPort() { return (this.proxyPort); } /** * Set the proxy server port for this Connector. * * @param proxyPort The new proxy server port */ public void setProxyPort(int proxyPort) { this.proxyPort = proxyPort; setProperty("proxyPort", String.valueOf(proxyPort)); } /** * Return the port number to which a request should be redirected if * it comes in on a non-SSL port and is subject to a security constraint * with a transport guarantee that requires SSL. */ public int getRedirectPort() { return (this.redirectPort); } /** * Set the redirect port number. * * @param redirectPort The redirect port number (non-SSL to SSL) */ public void setRedirectPort(int redirectPort) { this.redirectPort = redirectPort; setProperty("redirectPort", String.valueOf(redirectPort)); } /** * Return the scheme that will be assigned to requests received * through this connector. Default value is "http". */ public String getScheme() { return (this.scheme); } /** * Set the scheme that will be assigned to requests received through * this connector. * * @param scheme The new scheme */ public void setScheme(String scheme) { this.scheme = scheme; } /** * Return the secure connection flag that will be assigned to requests * received through this connector. Default value is "false". */ public boolean getSecure() { return (this.secure); } /** * Set the secure connection flag that will be assigned to requests * received through this connector. * * @param secure The new secure connection flag */ public void setSecure(boolean secure) { this.secure = secure; setProperty("secure", Boolean.toString(secure)); } /** * Return the character encoding to be used for the URI. */ public String getURIEncoding() { return (this.URIEncoding); } /** * Set the URI encoding to be used for the URI. * * @param URIEncoding The new URI character encoding. */ public void setURIEncoding(String URIEncoding) { this.URIEncoding = URIEncoding; setProperty("uRIEncoding", URIEncoding); } /** * Return the true if the entity body encoding should be used for the URI. */ public boolean getUseBodyEncodingForURI() { return (this.useBodyEncodingForURI); } /** * Set if the entity body encoding should be used for the URI. * * @param useBodyEncodingForURI The new value for the flag. */ public void setUseBodyEncodingForURI(boolean useBodyEncodingForURI) { this.useBodyEncodingForURI = useBodyEncodingForURI; setProperty ("useBodyEncodingForURI", String.valueOf(useBodyEncodingForURI)); } /** * Indicates whether the generation of an X-Powered-By response header for * servlet-generated responses is enabled or disabled for this Connector. * * @return true if generation of X-Powered-By response header is enabled, * false otherwise */ public boolean getXpoweredBy() { return xpoweredBy; } /** * Enables or disables the generation of an X-Powered-By header (with value * Servlet/2.5) for all servlet-generated responses returned by this * Connector. * * @param xpoweredBy true if generation of X-Powered-By response header is * to be enabled, false otherwise */ public void setXpoweredBy(boolean xpoweredBy) { this.xpoweredBy = xpoweredBy; setProperty("xpoweredBy", String.valueOf(xpoweredBy)); } /** * Enable the use of IP-based virtual hosting. * * @param useIPVHosts true if Hosts are identified by IP, * false/code> if Hosts are identified by name. */ public void setUseIPVHosts(boolean useIPVHosts) { this.useIPVHosts = useIPVHosts; setProperty("useIPVHosts", String.valueOf(useIPVHosts)); } /** * Test if IP-based virtual hosting is enabled. */ public boolean getUseIPVHosts() { return useIPVHosts; } public String getExecutorName() { Object obj = protocolHandler.getExecutor(); if (obj instanceof org.apache.catalina.Executor) { return ((org.apache.catalina.Executor) obj).getName(); } return "Internal"; } // --------------------------------------------------------- Public Methods /** * Create (or allocate) and return a Request object suitable for * specifying the contents of a Request to the responsible Container. */ public Request createRequest() { Request request = new Request(); request.setConnector(this); return (request); } /** * Create (or allocate) and return a Response object suitable for * receiving the contents of a Response from the responsible Container. */ public Response createResponse() { Response response = new Response(); response.setConnector(this); return (response); } protected String createObjectNameKeyProperties(String type) { Object addressObj = getProperty("address"); StringBuilder sb = new StringBuilder("type="); sb.append(type); sb.append(",port="); int port = getPort(); if (port > 0) { sb.append(getPort()); } else { sb.append("auto-"); sb.append(getProperty("nameIndex")); } String address = ""; if (addressObj instanceof InetAddress) { address = ((InetAddress) addressObj).getHostAddress(); } else if (addressObj != null) { address = addressObj.toString(); } if (address.length() > 0) { sb.append(",address="); sb.append(ObjectName.quote(address)); } return sb.toString(); } /** * Pause the connector. */ public void pause() { try { protocolHandler.pause(); } catch (Exception e) { log.error(sm.getString ("coyoteConnector.protocolHandlerPauseFailed"), e); } } /** * Pause the connector. */ public void resume() { try { protocolHandler.resume(); } catch (Exception e) { log.error(sm.getString ("coyoteConnector.protocolHandlerResumeFailed"), e); } } @Override protected void initInternal() throws LifecycleException { super.initInternal(); // Initialize adapter adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); // Make sure parseBodyMethodsSet has a default if( null == parseBodyMethodsSet ) { setParseBodyMethods(getParseBodyMethods()); } if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerNoApr", getProtocolHandlerClassName())); } try { protocolHandler.init(); } catch (Exception e) { throw new LifecycleException (sm.getString ("coyoteConnector.protocolHandlerInitializationFailed"), e); } // Initialize mapper listener mapperListener.init(); } /** * Begin processing requests via this Connector. * * @exception LifecycleException if a fatal startup error occurs */ @Override protected void startInternal() throws LifecycleException { // Validate settings before starting if (getPort() < 0) { throw new LifecycleException(sm.getString( "coyoteConnector.invalidPort", Integer.valueOf(getPort()))); } setState(LifecycleState.STARTING); try { protocolHandler.start(); } catch (Exception e) { String errPrefix = ""; if(this.service != null) { errPrefix += "service.getName(): \"" + this.service.getName() + "\"; "; } throw new LifecycleException (errPrefix + " " + sm.getString ("coyoteConnector.protocolHandlerStartFailed"), e); } mapperListener.start(); } /** * Terminate processing requests via this Connector. * * @exception LifecycleException if a fatal shutdown error occurs */ @Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); try { protocolHandler.stop(); } catch (Exception e) { throw new LifecycleException (sm.getString ("coyoteConnector.protocolHandlerStopFailed"), e); } mapperListener.stop(); } @Override protected void destroyInternal() throws LifecycleException { mapperListener.destroy(); try { protocolHandler.destroy(); } catch (Exception e) { throw new LifecycleException (sm.getString ("coyoteConnector.protocolHandlerDestroyFailed"), e); } if (getService() != null) { getService().removeConnector(this); } super.destroyInternal(); } /** * Provide a useful toString() implementation as it may be used when logging * Lifecycle errors to identify the component. */ @Override public String toString() { // Not worth caching this right now StringBuilder sb = new StringBuilder("Connector["); sb.append(getProtocol()); sb.append('-'); int port = getPort(); if (port > 0) { sb.append(getPort()); } else { sb.append("auto-"); sb.append(getProperty("nameIndex")); } sb.append(']'); return sb.toString(); } // -------------------- JMX registration -------------------- @Override protected String getDomainInternal() { return MBeanUtils.getDomain(getService()); } @Override protected String getObjectNameKeyProperties() { return createObjectNameKeyProperties("Connector"); } } tomcat7-7.0.52/java/org/apache/catalina/connector/InputBuffer.java0000644000175100017510000003237212271471332024747 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import java.io.Reader; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.HashMap; import org.apache.catalina.security.SecurityUtil; import org.apache.coyote.ActionCode; import org.apache.coyote.Request; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.res.StringManager; /** * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3 * OutputBuffer, adapted to handle input instead of output. This allows * complete recycling of the facade objects (the ServletInputStream and the * BufferedReader). * * @author Remy Maucherat */ public class InputBuffer extends Reader implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel, CharChunk.CharOutputChannel { /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // -------------------------------------------------------------- Constants public static final String DEFAULT_ENCODING = org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING; public static final int DEFAULT_BUFFER_SIZE = 8*1024; // The buffer can be used for byte[] and char[] reading // ( this is needed to support ServletInputStream and BufferedReader ) public final int INITIAL_STATE = 0; public final int CHAR_STATE = 1; public final int BYTE_STATE = 2; // ----------------------------------------------------- Instance Variables /** * The byte buffer. */ private final ByteChunk bb; /** * The chunk buffer. */ private CharChunk cb; /** * State of the output buffer. */ private int state = 0; /** * Flag which indicates if the input buffer is closed. */ private boolean closed = false; /** * Encoding to use. */ private String enc; /** * Encoder is set. */ private boolean gotEnc = false; /** * List of encoders. */ protected HashMap encoders = new HashMap(); /** * Current byte to char converter. */ protected B2CConverter conv; /** * Associated Coyote request. */ private Request coyoteRequest; /** * Buffer position. */ private int markPos = -1; /** * Buffer size. */ private int size = -1; // ----------------------------------------------------------- Constructors /** * Default constructor. Allocate the buffer with the default buffer size. */ public InputBuffer() { this(DEFAULT_BUFFER_SIZE); } /** * Alternate constructor which allows specifying the initial buffer size. * * @param size Buffer size to use */ public InputBuffer(int size) { this.size = size; bb = new ByteChunk(size); bb.setLimit(size); bb.setByteInputChannel(this); cb = new CharChunk(size); cb.setLimit(size); cb.setOptimizedWrite(false); cb.setCharInputChannel(this); cb.setCharOutputChannel(this); } // ------------------------------------------------------------- Properties /** * Associated Coyote request. * * @param coyoteRequest Associated Coyote request */ public void setRequest(Request coyoteRequest) { this.coyoteRequest = coyoteRequest; } /** * Get associated Coyote request. * * @return the associated Coyote request */ @Deprecated public Request getRequest() { return this.coyoteRequest; } // --------------------------------------------------------- Public Methods /** * Recycle the output buffer. */ public void recycle() { state = INITIAL_STATE; // If usage of mark made the buffer too big, reallocate it if (cb.getChars().length > size) { cb = new CharChunk(size); cb.setLimit(size); cb.setOptimizedWrite(false); cb.setCharInputChannel(this); cb.setCharOutputChannel(this); } else { cb.recycle(); } markPos = -1; bb.recycle(); closed = false; if (conv != null) { conv.recycle(); } gotEnc = false; enc = null; } /** * Clear cached encoders (to save memory for Comet requests). */ public void clearEncoders() { encoders.clear(); } /** * Close the input buffer. * * @throws IOException An underlying IOException occurred */ @Override public void close() throws IOException { closed = true; } public int available() { int available = 0; if (state == BYTE_STATE) { available = bb.getLength(); } else if (state == CHAR_STATE) { available = cb.getLength(); } if (available == 0) { coyoteRequest.action(ActionCode.AVAILABLE, null); available = (coyoteRequest.getAvailable() > 0) ? 1 : 0; } return available; } // ------------------------------------------------- Bytes Handling Methods /** * Reads new bytes in the byte chunk. * * @param cbuf Byte buffer to be written to the response * @param off Offset * @param len Length * * @throws IOException An underlying IOException occurred */ @Override public int realReadBytes(byte cbuf[], int off, int len) throws IOException { if (closed) { return -1; } if (coyoteRequest == null) { return -1; } if(state == INITIAL_STATE) { state = BYTE_STATE; } int result = coyoteRequest.doRead(bb); return result; } public int readByte() throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } return bb.substract(); } public int read(byte[] b, int off, int len) throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } return bb.substract(b, off, len); } // ------------------------------------------------- Chars Handling Methods /** * Since the converter will use append, it is possible to get chars to * be removed from the buffer for "writing". Since the chars have already * been read before, they are ignored. If a mark was set, then the * mark is lost. */ @Override public void realWriteChars(char c[], int off, int len) throws IOException { markPos = -1; cb.setOffset(0); cb.setEnd(0); } public void setEncoding(String s) { enc = s; } @Override public int realReadChars(char cbuf[], int off, int len) throws IOException { if (!gotEnc) { setConverter(); } boolean eof = false; if (bb.getLength() <= 0) { int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length); if (nRead < 0) { eof = true; } } if (markPos == -1) { cb.setOffset(0); cb.setEnd(0); } else { // Make sure there's enough space in the worst case cb.makeSpace(bb.getLength()); if ((cb.getBuffer().length - cb.getEnd()) == 0) { // We went over the limit cb.setOffset(0); cb.setEnd(0); markPos = -1; } } state = CHAR_STATE; conv.convert(bb, cb, eof); if (cb.getLength() == 0 && eof) { return -1; } else { return cb.getLength(); } } @Override public int read() throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } return cb.substract(); } @Override public int read(char[] cbuf) throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } return read(cbuf, 0, cbuf.length); } @Override public int read(char[] cbuf, int off, int len) throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } return cb.substract(cbuf, off, len); } @Override public long skip(long n) throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } if (n < 0) { throw new IllegalArgumentException(); } long nRead = 0; while (nRead < n) { if (cb.getLength() >= n) { cb.setOffset(cb.getStart() + (int) n); nRead = n; } else { nRead += cb.getLength(); cb.setOffset(cb.getEnd()); int toRead = 0; if (cb.getChars().length < (n - nRead)) { toRead = cb.getChars().length; } else { toRead = (int) (n - nRead); } int nb = realReadChars(cb.getChars(), 0, toRead); if (nb < 0) { break; } } } return nRead; } @Override public boolean ready() throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } return (available() > 0); } @Override public boolean markSupported() { return true; } @Override public void mark(int readAheadLimit) throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } if (cb.getLength() <= 0) { cb.setOffset(0); cb.setEnd(0); } else { if ((cb.getBuffer().length > (2 * size)) && (cb.getLength()) < (cb.getStart())) { System.arraycopy(cb.getBuffer(), cb.getStart(), cb.getBuffer(), 0, cb.getLength()); cb.setEnd(cb.getLength()); cb.setOffset(0); } } cb.setLimit(cb.getStart() + readAheadLimit + size); markPos = cb.getStart(); } @Override public void reset() throws IOException { if (closed) { throw new IOException(sm.getString("inputBuffer.streamClosed")); } if (state == CHAR_STATE) { if (markPos < 0) { cb.recycle(); markPos = -1; throw new IOException(); } else { cb.setOffset(markPos); } } else { bb.recycle(); } } public void checkConverter() throws IOException { if (!gotEnc) { setConverter(); } } protected void setConverter() throws IOException { if (coyoteRequest != null) { enc = coyoteRequest.getCharacterEncoding(); } gotEnc = true; if (enc == null) { enc = DEFAULT_ENCODING; } conv = encoders.get(enc); if (conv == null) { if (SecurityUtil.isPackageProtectionEnabled()){ try{ conv = AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public B2CConverter run() throws IOException { return new B2CConverter(enc); } } ); }catch(PrivilegedActionException ex){ Exception e = ex.getException(); if (e instanceof IOException) { throw (IOException)e; } } } else { conv = new B2CConverter(enc); } encoders.put(enc, conv); } } } tomcat7-7.0.52/java/org/apache/catalina/connector/CoyoteAdapter.java0000644000175100017510000013366612271471332025271 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.EnumSet; import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.RequestDispatcher; import javax.servlet.SessionTrackingMode; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.Host; import org.apache.catalina.Wrapper; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometEvent.EventType; import org.apache.catalina.core.AsyncContextImpl; import org.apache.catalina.util.ServerInfo; import org.apache.catalina.util.SessionConfig; import org.apache.catalina.util.URLEncoder; import org.apache.coyote.ActionCode; import org.apache.coyote.Adapter; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.Cookies; import org.apache.tomcat.util.http.ServerCookie; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.res.StringManager; /** * Implementation of a request processor which delegates the processing to a * Coyote processor. * * @author Craig R. McClanahan * @author Remy Maucherat */ public class CoyoteAdapter implements Adapter { private static final Log log = LogFactory.getLog(CoyoteAdapter.class); // -------------------------------------------------------------- Constants private static final String POWERED_BY = "Servlet/3.0 JSP/2.2 " + "(" + ServerInfo.getServerInfo() + " Java/" + System.getProperty("java.vm.vendor") + "/" + System.getProperty("java.runtime.version") + ")"; private static final EnumSet SSL_ONLY = EnumSet.of(SessionTrackingMode.SSL); public static final int ADAPTER_NOTES = 1; protected static final boolean ALLOW_BACKSLASH = Boolean.valueOf(System.getProperty("org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH", "false")).booleanValue(); // ----------------------------------------------------------- Constructors /** * Construct a new CoyoteProcessor associated with the specified connector. * * @param connector CoyoteConnector that owns this processor */ public CoyoteAdapter(Connector connector) { super(); this.connector = connector; } // ----------------------------------------------------- Instance Variables /** * The CoyoteConnector with which this processor is associated. */ private Connector connector = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Encoder for the Location URL in HTTP redirects. */ protected static URLEncoder urlEncoder; // ----------------------------------------------------- Static Initializer /** * The safe character set. */ static { urlEncoder = new URLEncoder(); urlEncoder.addSafeCharacter('-'); urlEncoder.addSafeCharacter('_'); urlEncoder.addSafeCharacter('.'); urlEncoder.addSafeCharacter('*'); urlEncoder.addSafeCharacter('/'); } // -------------------------------------------------------- Adapter Methods /** * Event method. * * @return false to indicate an error, expected or not */ @Override public boolean event(org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status) { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request.getWrapper() == null) { return false; } boolean error = false; boolean read = false; try { if (status == SocketStatus.OPEN_READ) { if (response.isClosed()) { // The event has been closed asynchronously, so call end instead of // read to cleanup the pipeline request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } else { try { // Fill the read buffer of the servlet layer if (request.read()) { read = true; } } catch (IOException e) { error = true; } if (read) { request.getEvent().setEventType(CometEvent.EventType.READ); request.getEvent().setEventSubType(null); } else if (error) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT); } else { request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } } } else if (status == SocketStatus.DISCONNECT) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT); error = true; } else if (status == SocketStatus.ERROR) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION); error = true; } else if (status == SocketStatus.STOP) { request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(CometEvent.EventSubType.SERVER_SHUTDOWN); } else if (status == SocketStatus.TIMEOUT) { if (response.isClosed()) { // The event has been closed asynchronously, so call end instead of // read to cleanup the pipeline request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } else { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.TIMEOUT); } } req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); // Calling the container connector.getService().getContainer().getPipeline().getFirst().event(request, response, request.getEvent()); if (!error && !response.isClosed() && (request.getAttribute( RequestDispatcher.ERROR_EXCEPTION) != null)) { // An unexpected exception occurred while processing the event, so // error should be called request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(null); error = true; connector.getService().getContainer().getPipeline().getFirst().event(request, response, request.getEvent()); } if (response.isClosed() || !request.isComet()) { if (status==SocketStatus.OPEN_READ && request.getEvent().getEventType() != EventType.END) { //CometEvent.close was called during an event other than END request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); error = true; connector.getService().getContainer().getPipeline().getFirst().event(request, response, request.getEvent()); } res.action(ActionCode.COMET_END, null); } else if (!error && read && request.getAvailable()) { // If this was a read and not all bytes have been read, or if no data // was read from the connector, then it is an error request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION); error = true; connector.getService().getContainer().getPipeline().getFirst().event(request, response, request.getEvent()); } return (!error); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (!(t instanceof IOException)) { log.error(sm.getString("coyoteAdapter.service"), t); } error = true; return false; } finally { req.getRequestProcessor().setWorkerThreadName(null); // Recycle the wrapper request and response if (error || response.isClosed() || !request.isComet()) { ((Context) request.getMappingData().context).logAccess( request, response, System.currentTimeMillis() - req.getStartTime(), false); request.recycle(); request.setFilterChain(null); response.recycle(); } } } @Override public boolean asyncDispatch(org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { throw new IllegalStateException( "Dispatch may only happen on an existing request."); } boolean comet = false; boolean success = true; AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext(); req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); try { if (!request.isAsync() && !comet) { // Error or timeout - need to tell listeners the request is over // Have to test this first since state may change while in this // method and this is only required if entering this method in // this state Context ctxt = (Context) request.getMappingData().context; if (ctxt != null) { ctxt.fireRequestDestroyEvent(request); } // Lift any suspension (e.g. if sendError() was used by an async // request) to allow the response to be written to the client response.setSuspended(false); } if (status==SocketStatus.TIMEOUT) { success = true; if (!asyncConImpl.timeout()) { asyncConImpl.setErrorState(null, false); } } if (request.isAsyncDispatching()) { success = true; connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); Throwable t = (Throwable) request.getAttribute( RequestDispatcher.ERROR_EXCEPTION); if (t != null) { asyncConImpl.setErrorState(t, true); } } if (request.isComet()) { if (!response.isClosed() && !response.isError()) { if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) { // Invoke a read event right away if there are available bytes if (event(req, res, SocketStatus.OPEN_READ)) { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { // Clear the filter chain, as otherwise it will not be reset elsewhere // since this is a Comet request request.setFilterChain(null); } } if (!request.isAsync() && !comet) { request.finishRequest(); response.finishResponse(); req.action(ActionCode.POST_REQUEST , null); ((Context) request.getMappingData().context).logAccess( request, response, System.currentTimeMillis() - req.getStartTime(), false); } } catch (IOException e) { success = false; // Ignore } catch (Throwable t) { ExceptionUtils.handleThrowable(t); success = false; log.error(sm.getString("coyoteAdapter.service"), t); } finally { req.getRequestProcessor().setWorkerThreadName(null); // Recycle the wrapper request and response if (!success || (!comet && !request.isAsync())) { request.recycle(); response.recycle(); } else { // Clear converters so that the minimum amount of memory // is used by this processor request.clearEncoders(); response.clearEncoders(); } } return success; } /** * Service method. */ @Override public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { // Create objects request = connector.createRequest(); request.setCoyoteRequest(req); response = connector.createResponse(); response.setCoyoteResponse(res); // Link objects request.setResponse(response); response.setRequest(request); // Set as notes req.setNote(ADAPTER_NOTES, request); res.setNote(ADAPTER_NOTES, response); // Set query string encoding req.getParameters().setQueryStringEncoding (connector.getURIEncoding()); } if (connector.getXpoweredBy()) { response.addHeader("X-Powered-By", POWERED_BY); } boolean comet = false; boolean async = false; try { // Parse and set Catalina and configuration specific // request parameters req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); boolean postParseSuccess = postParseRequest(req, request, res, response); if (postParseSuccess) { //check valves if we support async request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported()); // Calling the container connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); if (request.isComet()) { if (!response.isClosed() && !response.isError()) { if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) { // Invoke a read event right away if there are available bytes if (event(req, res, SocketStatus.OPEN_READ)) { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { // Clear the filter chain, as otherwise it will not be reset elsewhere // since this is a Comet request request.setFilterChain(null); } } } AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext(); if (asyncConImpl != null) { async = true; } else if (!comet) { request.finishRequest(); response.finishResponse(); if (postParseSuccess && request.getMappingData().context != null) { // Log only if processing was invoked. // If postParseRequest() failed, it has already logged it. // If context is null this was the start of a comet request // that failed and has already been logged. ((Context) request.getMappingData().context).logAccess( request, response, System.currentTimeMillis() - req.getStartTime(), false); } req.action(ActionCode.POST_REQUEST , null); } } catch (IOException e) { // Ignore } finally { req.getRequestProcessor().setWorkerThreadName(null); AtomicBoolean error = new AtomicBoolean(false); res.action(ActionCode.IS_ERROR, error); // Recycle the wrapper request and response if (!comet && !async || error.get()) { request.recycle(); response.recycle(); } else { // Clear converters so that the minimum amount of memory // is used by this processor request.clearEncoders(); response.clearEncoders(); } } } @Override public void log(org.apache.coyote.Request req, org.apache.coyote.Response res, long time) { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { // Create objects request = connector.createRequest(); request.setCoyoteRequest(req); response = connector.createResponse(); response.setCoyoteResponse(res); // Link objects request.setResponse(response); response.setRequest(request); // Set as notes req.setNote(ADAPTER_NOTES, request); res.setNote(ADAPTER_NOTES, response); // Set query string encoding req.getParameters().setQueryStringEncoding (connector.getURIEncoding()); } try { // Log at the lowest level available. logAccess() will be // automatically called on parent containers. boolean logged = false; if (request.mappingData != null) { if (request.mappingData.context != null) { logged = true; ((Context) request.mappingData.context).logAccess( request, response, time, true); } else if (request.mappingData.host != null) { logged = true; ((Host) request.mappingData.host).logAccess( request, response, time, true); } } if (!logged) { connector.getService().getContainer().logAccess( request, response, time, true); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn(sm.getString("coyoteAdapter.accesslogFail"), t); } finally { request.recycle(); response.recycle(); } } @Override public String getDomain() { return connector.getDomain(); } // ------------------------------------------------------ Protected Methods /** * Parse additional request parameters. */ protected boolean postParseRequest(org.apache.coyote.Request req, Request request, org.apache.coyote.Response res, Response response) throws Exception { // XXX the processor may have set a correct scheme and port prior to this point, // in ajp13 protocols dont make sense to get the port from the connector... // otherwise, use connector configuration if (! req.scheme().isNull()) { // use processor specified scheme to determine secure state request.setSecure(req.scheme().equals("https")); } else { // use connector scheme and secure configuration, (defaults to // "http" and false respectively) req.scheme().setString(connector.getScheme()); request.setSecure(connector.getSecure()); } // FIXME: the code below doesnt belongs to here, // this is only have sense // in Http11, not in ajp13.. // At this point the Host header has been processed. // Override if the proxyPort/proxyHost are set String proxyName = connector.getProxyName(); int proxyPort = connector.getProxyPort(); if (proxyPort != 0) { req.setServerPort(proxyPort); } if (proxyName != null) { req.serverName().setString(proxyName); } // Copy the raw URI to the decodedURI MessageBytes decodedURI = req.decodedURI(); decodedURI.duplicate(req.requestURI()); // Parse the path parameters. This will: // - strip out the path parameters // - convert the decodedURI to bytes parsePathParameters(req, request); // URI decoding // %xx decoding of the URL try { req.getURLDecoder().convert(decodedURI, false); } catch (IOException ioe) { res.setStatus(400); res.setMessage("Invalid URI: " + ioe.getMessage()); connector.getService().getContainer().logAccess( request, response, 0, true); return false; } // Normalization if (!normalize(req.decodedURI())) { res.setStatus(400); res.setMessage("Invalid URI"); connector.getService().getContainer().logAccess( request, response, 0, true); return false; } // Character decoding convertURI(decodedURI, request); // Check that the URI is still normalized if (!checkNormalize(req.decodedURI())) { res.setStatus(400); res.setMessage("Invalid URI character encoding"); connector.getService().getContainer().logAccess( request, response, 0, true); return false; } // Set the remote principal String principal = req.getRemoteUser().toString(); if (principal != null) { request.setUserPrincipal(new CoyotePrincipal(principal)); } // Set the authorization type String authtype = req.getAuthType().toString(); if (authtype != null) { request.setAuthType(authtype); } // Request mapping. MessageBytes serverName; if (connector.getUseIPVHosts()) { serverName = req.localName(); if (serverName.isNull()) { // well, they did ask for it res.action(ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, null); } } else { serverName = req.serverName(); } if (request.isAsyncStarted()) { //TODO SERVLET3 - async //reset mapping data, should prolly be done elsewhere request.getMappingData().recycle(); } boolean mapRequired = true; String version = null; while (mapRequired) { if (version != null) { // Once we have a version - that is it mapRequired = false; } // This will map the the latest version by default connector.getMapper().map(serverName, decodedURI, version, request.getMappingData()); request.setContext((Context) request.getMappingData().context); request.setWrapper((Wrapper) request.getMappingData().wrapper); // Single contextVersion therefore no possibility of remap if (request.getMappingData().contexts == null) { mapRequired = false; } // If there is no context at this point, it is likely no ROOT context // has been deployed if (request.getContext() == null) { res.setStatus(404); res.setMessage("Not found"); // No context, so use host Host host = request.getHost(); // Make sure there is a host (might not be during shutdown) if (host != null) { host.logAccess(request, response, 0, true); } return false; } // Now we have the context, we can parse the session ID from the URL // (if any). Need to do this before we redirect in case we need to // include the session id in the redirect String sessionID = null; if (request.getServletContext().getEffectiveSessionTrackingModes() .contains(SessionTrackingMode.URL)) { // Get the session ID if there was one sessionID = request.getPathParameter( SessionConfig.getSessionUriParamName( request.getContext())); if (sessionID != null) { request.setRequestedSessionId(sessionID); request.setRequestedSessionURL(true); } } // Look for session ID in cookies and SSL session parseSessionCookiesId(req, request); parseSessionSslId(request); sessionID = request.getRequestedSessionId(); if (mapRequired) { if (sessionID == null) { // No session means no possibility of needing to remap mapRequired = false; } else { // Find the context associated with the session Object[] objs = request.getMappingData().contexts; for (int i = (objs.length); i > 0; i--) { Context ctxt = (Context) objs[i - 1]; if (ctxt.getManager().findSession(sessionID) != null) { // Was the correct context already mapped? if (ctxt.equals(request.getMappingData().context)) { mapRequired = false; } else { // Set version so second time through mapping the // correct context is found version = ctxt.getWebappVersion(); // Reset mapping request.getMappingData().recycle(); break; } } } if (version == null) { // No matching context found. No need to re-map mapRequired = false; } } } if (!mapRequired && request.getContext().getPaused()) { // Found a matching context but it is paused. Mapping data will // be wrong since some Wrappers may not be registered at this // point. try { Thread.sleep(1000); } catch (InterruptedException e) { // Should never happen } // Reset mapping request.getMappingData().recycle(); mapRequired = true; } } // Possible redirect MessageBytes redirectPathMB = request.getMappingData().redirectPath; if (!redirectPathMB.isNull()) { String redirectPath = urlEncoder.encode(redirectPathMB.toString()); String query = request.getQueryString(); if (request.isRequestedSessionIdFromURL()) { // This is not optimal, but as this is not very common, it // shouldn't matter redirectPath = redirectPath + ";" + SessionConfig.getSessionUriParamName( request.getContext()) + "=" + request.getRequestedSessionId(); } if (query != null) { // This is not optimal, but as this is not very common, it // shouldn't matter redirectPath = redirectPath + "?" + query; } response.sendRedirect(redirectPath); request.getContext().logAccess(request, response, 0, true); return false; } // Filter trace method if (!connector.getAllowTrace() && req.method().equalsIgnoreCase("TRACE")) { Wrapper wrapper = request.getWrapper(); String header = null; if (wrapper != null) { String[] methods = wrapper.getServletMethods(); if (methods != null) { for (int i=0; i -1) { // Parse path param, and extract it from the decoded request URI int start = uriBC.getStart(); int end = uriBC.getEnd(); int pathParamStart = semicolon + 1; int pathParamEnd = ByteChunk.findBytes(uriBC.getBuffer(), start + pathParamStart, end, new byte[] {';', '/'}); String pv = null; if (pathParamEnd >= 0) { if (charset != null) { pv = new String(uriBC.getBuffer(), start + pathParamStart, pathParamEnd - pathParamStart, charset); } // Extract path param from decoded request URI byte[] buf = uriBC.getBuffer(); for (int i = 0; i < end - start - pathParamEnd; i++) { buf[start + semicolon + i] = buf[start + i + pathParamEnd]; } uriBC.setBytes(buf, start, end - start - pathParamEnd + semicolon); } else { if (charset != null) { pv = new String(uriBC.getBuffer(), start + pathParamStart, (end - start) - pathParamStart, charset); } uriBC.setEnd(start + semicolon); } if (log.isDebugEnabled()) { log.debug(sm.getString("coyoteAdapter.debug", "pathParamStart", String.valueOf(pathParamStart))); log.debug(sm.getString("coyoteAdapter.debug", "pathParamEnd", String.valueOf(pathParamEnd))); log.debug(sm.getString("coyoteAdapter.debug", "pv", pv)); } if (pv != null) { int equals = pv.indexOf('='); if (equals > -1) { String name = pv.substring(0, equals); String value = pv.substring(equals + 1); request.addPathParameter(name, value); if (log.isDebugEnabled()) { log.debug(sm.getString("coyoteAdapter.debug", "equals", String.valueOf(equals))); log.debug(sm.getString("coyoteAdapter.debug", "name", name)); log.debug(sm.getString("coyoteAdapter.debug", "value", value)); } } } semicolon = uriBC.indexOf(';', semicolon); } } /** * Look for SSL session ID if required. Only look for SSL Session ID if it * is the only tracking method enabled. */ protected void parseSessionSslId(Request request) { if (request.getRequestedSessionId() == null && SSL_ONLY.equals(request.getServletContext() .getEffectiveSessionTrackingModes()) && request.connector.secure) { // TODO Is there a better way to map SSL sessions to our sesison ID? // TODO The request.getAttribute() will cause a number of other SSL // attribute to be populated. Is this a performance concern? request.setRequestedSessionId( request.getAttribute(SSLSupport.SESSION_ID_KEY).toString()); request.setRequestedSessionSSL(true); } } /** * Parse session id in URL. */ protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { // If session tracking via cookies has been disabled for the current // context, don't go looking for a session ID in a cookie as a cookie // from a parent context with a session ID may be present which would // overwrite the valid session ID encoded in the URL Context context = (Context) request.getMappingData().context; if (context != null && !context.getServletContext() .getEffectiveSessionTrackingModes().contains( SessionTrackingMode.COOKIE)) { return; } // Parse session id from cookies Cookies serverCookies = req.getCookies(); int count = serverCookies.getCookieCount(); if (count <= 0) { return; } String sessionCookieName = SessionConfig.getSessionCookieName(context); for (int i = 0; i < count; i++) { ServerCookie scookie = serverCookies.getCookie(i); if (scookie.getName().equals(sessionCookieName)) { // Override anything requested in the URL if (!request.isRequestedSessionIdFromCookie()) { // Accept only the first session id cookie convertMB(scookie.getValue()); request.setRequestedSessionId (scookie.getValue().toString()); request.setRequestedSessionCookie(true); request.setRequestedSessionURL(false); if (log.isDebugEnabled()) { log.debug(" Requested cookie session id is " + request.getRequestedSessionId()); } } else { if (!request.isRequestedSessionIdValid()) { // Replace the session id until one is valid convertMB(scookie.getValue()); request.setRequestedSessionId (scookie.getValue().toString()); } } } } } /** * Character conversion of the URI. */ protected void convertURI(MessageBytes uri, Request request) throws Exception { ByteChunk bc = uri.getByteChunk(); int length = bc.getLength(); CharChunk cc = uri.getCharChunk(); cc.allocate(length, -1); String enc = connector.getURIEncoding(); if (enc != null) { B2CConverter conv = request.getURIConverter(); try { if (conv == null) { conv = new B2CConverter(enc, true); request.setURIConverter(conv); } else { conv.recycle(); } } catch (IOException e) { log.error("Invalid URI encoding; using HTTP default"); connector.setURIEncoding(null); } if (conv != null) { try { conv.convert(bc, cc, true); uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength()); return; } catch (IOException ioe) { // Should never happen as B2CConverter should replace // problematic characters request.getResponse().sendError( HttpServletResponse.SC_BAD_REQUEST); } } } // Default encoding: fast conversion for ISO-8859-1 byte[] bbuf = bc.getBuffer(); char[] cbuf = cc.getBuffer(); int start = bc.getStart(); for (int i = 0; i < length; i++) { cbuf[i] = (char) (bbuf[i + start] & 0xff); } uri.setChars(cbuf, 0, length); } /** * Character conversion of the a US-ASCII MessageBytes. */ protected void convertMB(MessageBytes mb) { // This is of course only meaningful for bytes if (mb.getType() != MessageBytes.T_BYTES) { return; } ByteChunk bc = mb.getByteChunk(); CharChunk cc = mb.getCharChunk(); int length = bc.getLength(); cc.allocate(length, -1); // Default encoding: fast conversion byte[] bbuf = bc.getBuffer(); char[] cbuf = cc.getBuffer(); int start = bc.getStart(); for (int i = 0; i < length; i++) { cbuf[i] = (char) (bbuf[i + start] & 0xff); } mb.setChars(cbuf, 0, length); } /** * Normalize URI. *

    * This method normalizes "\", "//", "/./" and "/../". This method will * return false when trying to go above the root, or if the URI contains * a null byte. * * @param uriMB URI to be normalized */ public static boolean normalize(MessageBytes uriMB) { ByteChunk uriBC = uriMB.getByteChunk(); final byte[] b = uriBC.getBytes(); final int start = uriBC.getStart(); int end = uriBC.getEnd(); // An empty URL is not acceptable if (start == end) { return false; } // URL * is acceptable if ((end - start == 1) && b[start] == (byte) '*') { return true; } int pos = 0; int index = 0; // Replace '\' with '/' // Check for null byte for (pos = start; pos < end; pos++) { if (b[pos] == (byte) '\\') { if (ALLOW_BACKSLASH) { b[pos] = (byte) '/'; } else { return false; } } if (b[pos] == (byte) 0) { return false; } } // The URL must start with '/' if (b[start] != (byte) '/') { return false; } // Replace "//" with "/" for (pos = start; pos < (end - 1); pos++) { if (b[pos] == (byte) '/') { while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) { copyBytes(b, pos, pos + 1, end - pos - 1); end--; } } } // If the URI ends with "/." or "/..", then we append an extra "/" // Note: It is possible to extend the URI by 1 without any side effect // as the next character is a non-significant WS. if (((end - start) >= 2) && (b[end - 1] == (byte) '.')) { if ((b[end - 2] == (byte) '/') || ((b[end - 2] == (byte) '.') && (b[end - 3] == (byte) '/'))) { b[end] = (byte) '/'; end++; } } uriBC.setEnd(end); index = 0; // Resolve occurrences of "/./" in the normalized path while (true) { index = uriBC.indexOf("/./", 0, 3, index); if (index < 0) { break; } copyBytes(b, start + index, start + index + 2, end - start - index - 2); end = end - 2; uriBC.setEnd(end); } index = 0; // Resolve occurrences of "/../" in the normalized path while (true) { index = uriBC.indexOf("/../", 0, 4, index); if (index < 0) { break; } // Prevent from going outside our context if (index == 0) { return false; } int index2 = -1; for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) { if (b[pos] == (byte) '/') { index2 = pos; } } copyBytes(b, start + index2, start + index + 3, end - start - index - 3); end = end + index2 - index - 3; uriBC.setEnd(end); index = index2; } return true; } /** * Check that the URI is normalized following character decoding. *

    * This method checks for "\", 0, "//", "/./" and "/../". This method will * return false if sequences that are supposed to be normalized are still * present in the URI. * * @param uriMB URI to be checked (should be chars) */ public static boolean checkNormalize(MessageBytes uriMB) { CharChunk uriCC = uriMB.getCharChunk(); char[] c = uriCC.getChars(); int start = uriCC.getStart(); int end = uriCC.getEnd(); int pos = 0; // Check for '\' and 0 for (pos = start; pos < end; pos++) { if (c[pos] == '\\') { return false; } if (c[pos] == 0) { return false; } } // Check for "//" for (pos = start; pos < (end - 1); pos++) { if (c[pos] == '/') { if (c[pos + 1] == '/') { return false; } } } // Check for ending with "/." or "/.." if (((end - start) >= 2) && (c[end - 1] == '.')) { if ((c[end - 2] == '/') || ((c[end - 2] == '.') && (c[end - 3] == '/'))) { return false; } } // Check for "/./" if (uriCC.indexOf("/./", 0, 3, 0) >= 0) { return false; } // Check for "/../" if (uriCC.indexOf("/../", 0, 4, 0) >= 0) { return false; } return true; } // ------------------------------------------------------ Protected Methods /** * Copy an array of bytes to a different position. Used during * normalization. */ protected static void copyBytes(byte[] b, int dest, int src, int len) { for (int pos = 0; pos < len; pos++) { b[pos + dest] = b[pos + src]; } } } tomcat7-7.0.52/java/org/apache/catalina/connector/Request.java0000644000175100017510000030257112271471332024147 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.nio.charset.Charset; import java.security.Principal; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; import javax.naming.NamingException; import javax.security.auth.Subject; import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.FilterChain; import javax.servlet.MultipartConfigElement; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletResponse; import javax.servlet.SessionTrackingMode; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Part; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.Wrapper; import org.apache.catalina.core.ApplicationPart; import org.apache.catalina.core.ApplicationSessionCookieConfig; import org.apache.catalina.core.AsyncContextImpl; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.util.ParameterMap; import org.apache.catalina.util.StringParser; import org.apache.coyote.ActionCode; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.Cookies; import org.apache.tomcat.util.http.FastHttpDateFormat; import org.apache.tomcat.util.http.Parameters; import org.apache.tomcat.util.http.ServerCookie; import org.apache.tomcat.util.http.fileupload.FileItem; import org.apache.tomcat.util.http.fileupload.FileUploadBase; import org.apache.tomcat.util.http.fileupload.FileUploadBase.InvalidContentTypeException; import org.apache.tomcat.util.http.fileupload.FileUploadException; import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory; import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload; import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext; import org.apache.tomcat.util.http.mapper.MappingData; import org.apache.tomcat.util.res.StringManager; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; /** * Wrapper object for the Coyote request. * * @author Remy Maucherat * @author Craig R. McClanahan */ public class Request implements HttpServletRequest { private static final Log log = LogFactory.getLog(Request.class); // ----------------------------------------------------------- Constructors public Request() { formats[0].setTimeZone(GMT_ZONE); formats[1].setTimeZone(GMT_ZONE); formats[2].setTimeZone(GMT_ZONE); } // ------------------------------------------------------------- Properties /** * Coyote request. */ protected org.apache.coyote.Request coyoteRequest; /** * Set the Coyote request. * * @param coyoteRequest The Coyote request */ public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) { this.coyoteRequest = coyoteRequest; inputBuffer.setRequest(coyoteRequest); } /** * Get the Coyote request. */ public org.apache.coyote.Request getCoyoteRequest() { return (this.coyoteRequest); } // ----------------------------------------------------- Variables protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The set of cookies associated with this Request. */ protected Cookie[] cookies = null; /** * The set of SimpleDateFormat formats to use in getDateHeader(). * * Notice that because SimpleDateFormat is not thread-safe, we can't * declare formats[] as a static variable. */ protected SimpleDateFormat formats[] = { new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) }; /** * The default Locale if none are specified. */ protected static Locale defaultLocale = Locale.getDefault(); /** * The attributes associated with this Request, keyed by attribute name. */ protected HashMap attributes = new HashMap(); /** * Flag that indicates if SSL attributes have been parsed to improve * performance for applications (usually frameworks) that make multiple * calls to {@link Request#getAttributeNames()}. */ protected boolean sslAttributesParsed = false; /** * The preferred Locales associated with this Request. */ protected ArrayList locales = new ArrayList(); /** * Internal notes associated with this request by Catalina components * and event listeners. */ private transient HashMap notes = new HashMap(); /** * Authentication type. */ protected String authType = null; /** * Associated event. */ protected CometEventImpl event = null; /** * Comet state */ protected boolean comet = false; /** * The current dispatcher type. */ protected DispatcherType internalDispatcherType = null; /** * The associated input buffer. */ protected InputBuffer inputBuffer = new InputBuffer(); /** * ServletInputStream. */ protected CoyoteInputStream inputStream = new CoyoteInputStream(inputBuffer); /** * Reader. */ protected CoyoteReader reader = new CoyoteReader(inputBuffer); /** * Using stream flag. */ protected boolean usingInputStream = false; /** * Using writer flag. */ protected boolean usingReader = false; /** * User principal. */ protected Principal userPrincipal = null; /** * Session parsed flag. */ @Deprecated protected boolean sessionParsed = false; /** * Request parameters parsed flag. */ protected boolean parametersParsed = false; /** * Cookies parsed flag. */ protected boolean cookiesParsed = false; /** * Secure flag. */ protected boolean secure = false; /** * The Subject associated with the current AccessControllerContext */ protected transient Subject subject = null; /** * Post data buffer. */ protected static int CACHED_POST_LEN = 8192; protected byte[] postData = null; /** * Hash map used in the getParametersMap method. */ protected ParameterMap parameterMap = new ParameterMap(); /** * The parts, if any, uploaded with this request. */ protected Collection parts = null; /** * The exception thrown, if any when parsing the parts. */ protected Exception partsParseException = null; /** * The currently active session for this request. */ protected Session session = null; /** * The current request dispatcher path. */ protected Object requestDispatcherPath = null; /** * Was the requested session ID received in a cookie? */ protected boolean requestedSessionCookie = false; /** * The requested session ID (if any) for this request. */ protected String requestedSessionId = null; /** * Was the requested session ID received in a URL? */ protected boolean requestedSessionURL = false; /** * Was the requested session ID obtained from the SSL session? */ protected boolean requestedSessionSSL = false; /** * Parse locales. */ protected boolean localesParsed = false; /** * The string parser we will use for parsing request lines. */ private final StringParser parser = new StringParser(); /** * Local port */ protected int localPort = -1; /** * Remote address. */ protected String remoteAddr = null; /** * Remote host. */ protected String remoteHost = null; /** * Remote port */ protected int remotePort = -1; /** * Local address */ protected String localAddr = null; /** * Local address */ protected String localName = null; /** * AsyncContext */ protected volatile AsyncContextImpl asyncContext = null; protected Boolean asyncSupported = null; /** * Path parameters */ protected Map pathParameters = new HashMap(); // --------------------------------------------------------- Public Methods protected void addPathParameter(String name, String value) { pathParameters.put(name, value); } protected String getPathParameter(String name) { return pathParameters.get(name); } public void setAsyncSupported(boolean asyncSupported) { this.asyncSupported = Boolean.valueOf(asyncSupported); } /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { context = null; wrapper = null; internalDispatcherType = null; requestDispatcherPath = null; comet = false; if (event != null) { event.clear(); event = null; } authType = null; inputBuffer.recycle(); usingInputStream = false; usingReader = false; userPrincipal = null; subject = null; sessionParsed = false; parametersParsed = false; if (parts != null) { for (Part part: parts) { try { part.delete(); } catch (IOException ignored) { // ApplicationPart.delete() never throws an IOEx } } parts = null; } partsParseException = null; cookiesParsed = false; locales.clear(); localesParsed = false; secure = false; remoteAddr = null; remoteHost = null; remotePort = -1; localPort = -1; localAddr = null; localName = null; attributes.clear(); sslAttributesParsed = false; notes.clear(); cookies = null; if (session != null) { try { session.endAccess(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn(sm.getString("coyoteRequest.sessionEndAccessFail"), t); } } session = null; requestedSessionCookie = false; requestedSessionId = null; requestedSessionURL = false; if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) { parameterMap = new ParameterMap(); } else { parameterMap.setLocked(false); parameterMap.clear(); } mappingData.recycle(); if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) { if (facade != null) { facade.clear(); facade = null; } if (inputStream != null) { inputStream.clear(); inputStream = null; } if (reader != null) { reader.clear(); reader = null; } } asyncSupported = null; if (asyncContext!=null) { asyncContext.recycle(); } asyncContext = null; pathParameters.clear(); } @Deprecated protected boolean isProcessing() { return coyoteRequest.isProcessing(); } /** * Clear cached encoders (to save memory for Comet requests). */ public void clearEncoders() { inputBuffer.clearEncoders(); } /** * Clear cached encoders (to save memory for Comet requests). */ public boolean read() throws IOException { return (inputBuffer.realReadBytes(null, 0, 0) > 0); } // -------------------------------------------------------- Request Methods /** * Associated Catalina connector. */ protected Connector connector; /** * Return the Connector through which this Request was received. */ public Connector getConnector() { return this.connector; } /** * Set the Connector through which this Request was received. * * @param connector The new connector */ public void setConnector(Connector connector) { this.connector = connector; } /** * Associated context. */ protected Context context = null; /** * Return the Context within which this Request is being processed. */ public Context getContext() { return this.context; } /** * Set the Context within which this Request is being processed. This * must be called as soon as the appropriate Context is identified, because * it identifies the value to be returned by getContextPath(), * and thus enables parsing of the request URI. * * @param context The newly associated Context */ public void setContext(Context context) { this.context = context; } /** * Filter chain associated with the request. */ protected FilterChain filterChain = null; /** * Get filter chain associated with the request. */ public FilterChain getFilterChain() { return this.filterChain; } /** * Set filter chain associated with the request. * * @param filterChain new filter chain */ public void setFilterChain(FilterChain filterChain) { this.filterChain = filterChain; } /** * Return the Host within which this Request is being processed. */ public Host getHost() { return ((Host) mappingData.host); } /** * Set the Host within which this Request is being processed. This * must be called as soon as the appropriate Host is identified, and * before the Request is passed to a context. * * @param host The newly associated Host */ @Deprecated public void setHost(Host host) { mappingData.host = host; } /** * Descriptive information about this Request implementation. */ protected static final String info = "org.apache.coyote.catalina.CoyoteRequest/1.0"; /** * Return descriptive information about this Request implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return info; } /** * Mapping data. */ protected MappingData mappingData = new MappingData(); /** * Return mapping data. */ public MappingData getMappingData() { return mappingData; } /** * The facade associated with this request. */ protected RequestFacade facade = null; /** * Return the ServletRequest for which this object * is the facade. This method must be implemented by a subclass. */ public HttpServletRequest getRequest() { if (facade == null) { facade = new RequestFacade(this); } return facade; } /** * The response with which this request is associated. */ protected org.apache.catalina.connector.Response response = null; /** * Return the Response with which this Request is associated. */ public org.apache.catalina.connector.Response getResponse() { return this.response; } /** * Set the Response with which this Request is associated. * * @param response The new associated response */ public void setResponse(org.apache.catalina.connector.Response response) { this.response = response; } /** * Return the input stream associated with this Request. */ public InputStream getStream() { if (inputStream == null) { inputStream = new CoyoteInputStream(inputBuffer); } return inputStream; } /** * URI byte to char converter. */ protected B2CConverter URIConverter = null; /** * Return the URI converter. */ protected B2CConverter getURIConverter() { return URIConverter; } /** * Set the URI converter. * * @param URIConverter the new URI converter */ protected void setURIConverter(B2CConverter URIConverter) { this.URIConverter = URIConverter; } /** * Associated wrapper. */ protected Wrapper wrapper = null; /** * Return the Wrapper within which this Request is being processed. */ public Wrapper getWrapper() { return this.wrapper; } /** * Set the Wrapper within which this Request is being processed. This * must be called as soon as the appropriate Wrapper is identified, and * before the Request is ultimately passed to an application servlet. * @param wrapper The newly associated Wrapper */ public void setWrapper(Wrapper wrapper) { this.wrapper = wrapper; } // ------------------------------------------------- Request Public Methods /** * Create and return a ServletInputStream to read the content * associated with this Request. * * @exception IOException if an input/output error occurs */ public ServletInputStream createInputStream() throws IOException { if (inputStream == null) { inputStream = new CoyoteInputStream(inputBuffer); } return inputStream; } /** * Perform whatever actions are required to flush and close the input * stream or reader, in a single operation. * * @exception IOException if an input/output error occurs */ public void finishRequest() throws IOException { // Optionally disable swallowing of additional request data. Context context = getContext(); if (context != null && response.getStatus() == HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE && !context.getSwallowAbortedUploads()) { coyoteRequest.action(ActionCode.DISABLE_SWALLOW_INPUT, null); } } /** * Return the object bound with the specified name to the internal notes * for this request, or null if no such binding exists. * * @param name Name of the note to be returned */ public Object getNote(String name) { return notes.get(name); } /** * Return an Iterator containing the String names of all notes bindings * that exist for this request. */ @Deprecated public Iterator getNoteNames() { return notes.keySet().iterator(); } /** * Remove any object bound to the specified name in the internal notes * for this request. * * @param name Name of the note to be removed */ public void removeNote(String name) { notes.remove(name); } /** * Set the port number of the server to process this request. * * @param port The server port */ public void setLocalPort(int port) { localPort = port; } /** * Bind an object to a specified name in the internal notes associated * with this request, replacing any existing binding for this name. * * @param name Name to which the object should be bound * @param value Object to be bound to the specified name */ public void setNote(String name, Object value) { notes.put(name, value); } /** * Set the IP address of the remote client associated with this Request. * * @param remoteAddr The remote IP address */ public void setRemoteAddr(String remoteAddr) { this.remoteAddr = remoteAddr; } /** * Set the fully qualified name of the remote client associated with this * Request. * * @param remoteHost The remote host name */ public void setRemoteHost(String remoteHost) { this.remoteHost = remoteHost; } /** * Set the value to be returned by isSecure() * for this Request. * * @param secure The new isSecure value */ public void setSecure(boolean secure) { this.secure = secure; } /** * Set the name of the server (virtual host) to process this request. * * @param name The server name */ @Deprecated public void setServerName(String name) { coyoteRequest.serverName().setString(name); } /** * Set the port number of the server to process this request. * * @param port The server port */ public void setServerPort(int port) { coyoteRequest.setServerPort(port); } // ------------------------------------------------- ServletRequest Methods /** * Return the specified request attribute if it exists; otherwise, return * null. * * @param name Name of the request attribute to return */ @Override public Object getAttribute(String name) { // Special attributes SpecialAttributeAdapter adapter = specialAttributes.get(name); if (adapter != null) { return adapter.get(this, name); } Object attr=attributes.get(name); if(attr!=null) { return(attr); } attr = coyoteRequest.getAttribute(name); if(attr != null) { return attr; } if( isSSLAttribute(name) ) { coyoteRequest.action(ActionCode.REQ_SSL_ATTRIBUTE, coyoteRequest); attr = coyoteRequest.getAttribute(Globals.CERTIFICATES_ATTR); if( attr != null) { attributes.put(Globals.CERTIFICATES_ATTR, attr); } attr = coyoteRequest.getAttribute(Globals.CIPHER_SUITE_ATTR); if(attr != null) { attributes.put(Globals.CIPHER_SUITE_ATTR, attr); } attr = coyoteRequest.getAttribute(Globals.KEY_SIZE_ATTR); if(attr != null) { attributes.put(Globals.KEY_SIZE_ATTR, attr); } attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR); if(attr != null) { attributes.put(Globals.SSL_SESSION_ID_ATTR, attr); attributes.put(Globals.SSL_SESSION_ID_TOMCAT_ATTR, attr); } attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_MGR_ATTR); if(attr != null) { attributes.put(Globals.SSL_SESSION_MGR_ATTR, attr); } attr = attributes.get(name); sslAttributesParsed = true; } return attr; } /** * Test if a given name is one of the special Servlet-spec SSL attributes. */ static boolean isSSLAttribute(String name) { return Globals.CERTIFICATES_ATTR.equals(name) || Globals.CIPHER_SUITE_ATTR.equals(name) || Globals.KEY_SIZE_ATTR.equals(name) || Globals.SSL_SESSION_ID_ATTR.equals(name) || Globals.SSL_SESSION_ID_TOMCAT_ATTR.equals(name) || Globals.SSL_SESSION_MGR_ATTR.equals(name); } /** * Return the names of all request attributes for this Request, or an * empty Enumeration if there are none. Note that the attribute * names returned will only be those for the attributes set via * {@link #setAttribute(String, Object)}. Tomcat internal attributes will * not be included although they are accessible via * {@link #getAttribute(String)}. The Tomcat internal attributes include: *

      *
    • {@link Globals#DISPATCHER_TYPE_ATTR}
    • *
    • {@link Globals#DISPATCHER_REQUEST_PATH_ATTR}
    • *
    • {@link Globals#ASYNC_SUPPORTED_ATTR}
    • *
    • {@link Globals#CERTIFICATES_ATTR} (SSL connections only)
    • *
    • {@link Globals#CIPHER_SUITE_ATTR} (SSL connections only)
    • *
    • {@link Globals#KEY_SIZE_ATTR} (SSL connections only)
    • *
    • {@link Globals#SSL_SESSION_ID_ATTR} (SSL connections only)
    • *
    • {@link Globals#SSL_SESSION_ID_TOMCAT_ATTR} (SSL connections only) *
    • *
    • {@link Globals#SSL_SESSION_MGR_ATTR} (SSL connections only)
    • *
    • {@link Globals#PARAMETER_PARSE_FAILED_ATTR}
    • *
    * The underlying connector may also expose request attributes. These all * have names starting with "org.apache.tomcat" and include: *
      *
    • {@link Globals#SENDFILE_SUPPORTED_ATTR}
    • *
    • {@link Globals#COMET_SUPPORTED_ATTR}
    • *
    • {@link Globals#COMET_TIMEOUT_SUPPORTED_ATTR}
    • *
    * Connector implementations may return some, all or none of these * attributes and may also support additional attributes. */ @Override public Enumeration getAttributeNames() { if (isSecure() && !sslAttributesParsed) { getAttribute(Globals.CERTIFICATES_ATTR); } // Take a copy to prevent ConncurrentModificationExceptions if used to // remove attributes Set names = new HashSet(); names.addAll(attributes.keySet()); return Collections.enumeration(names); } /** * Return the character encoding for this Request. */ @Override public String getCharacterEncoding() { return coyoteRequest.getCharacterEncoding(); } /** * Return the content length for this Request. */ @Override public int getContentLength() { return coyoteRequest.getContentLength(); } /** * Return the content type for this Request. */ @Override public String getContentType() { return coyoteRequest.getContentType(); } /** * Return the servlet input stream for this Request. The default * implementation returns a servlet input stream created by * createInputStream(). * * @exception IllegalStateException if getReader() has * already been called for this request * @exception IOException if an input/output error occurs */ @Override public ServletInputStream getInputStream() throws IOException { if (usingReader) { throw new IllegalStateException (sm.getString("coyoteRequest.getInputStream.ise")); } usingInputStream = true; if (inputStream == null) { inputStream = new CoyoteInputStream(inputBuffer); } return inputStream; } /** * Return the preferred Locale that the client will accept content in, * based on the value for the first Accept-Language header * that was encountered. If the request did not specify a preferred * language, the server's default Locale is returned. */ @Override public Locale getLocale() { if (!localesParsed) { parseLocales(); } if (locales.size() > 0) { return locales.get(0); } return defaultLocale; } /** * Return the set of preferred Locales that the client will accept * content in, based on the values for any Accept-Language * headers that were encountered. If the request did not specify a * preferred language, the server's default Locale is returned. */ @Override public Enumeration getLocales() { if (!localesParsed) { parseLocales(); } if (locales.size() > 0) { return Collections.enumeration(locales); } ArrayList results = new ArrayList(); results.add(defaultLocale); return Collections.enumeration(results); } /** * Return the value of the specified request parameter, if any; otherwise, * return null. If there is more than one value defined, * return only the first one. * * @param name Name of the desired request parameter */ @Override public String getParameter(String name) { if (!parametersParsed) { parseParameters(); } return coyoteRequest.getParameters().getParameter(name); } /** * Returns a Map of the parameters of this request. * Request parameters are extra information sent with the request. * For HTTP servlets, parameters are contained in the query string * or posted form data. * * @return A Map containing parameter names as keys * and parameter values as map values. */ @Override public Map getParameterMap() { if (parameterMap.isLocked()) { return parameterMap; } Enumeration enumeration = getParameterNames(); while (enumeration.hasMoreElements()) { String name = enumeration.nextElement(); String[] values = getParameterValues(name); parameterMap.put(name, values); } parameterMap.setLocked(true); return parameterMap; } /** * Return the names of all defined request parameters for this request. */ @Override public Enumeration getParameterNames() { if (!parametersParsed) { parseParameters(); } return coyoteRequest.getParameters().getParameterNames(); } /** * Return the defined values for the specified request parameter, if any; * otherwise, return null. * * @param name Name of the desired request parameter */ @Override public String[] getParameterValues(String name) { if (!parametersParsed) { parseParameters(); } return coyoteRequest.getParameters().getParameterValues(name); } /** * Return the protocol and version used to make this Request. */ @Override public String getProtocol() { return coyoteRequest.protocol().toString(); } /** * Read the Reader wrapping the input stream for this Request. The * default implementation wraps a BufferedReader around the * servlet input stream returned by createInputStream(). * * @exception IllegalStateException if getInputStream() * has already been called for this request * @exception IOException if an input/output error occurs */ @Override public BufferedReader getReader() throws IOException { if (usingInputStream) { throw new IllegalStateException (sm.getString("coyoteRequest.getReader.ise")); } usingReader = true; inputBuffer.checkConverter(); if (reader == null) { reader = new CoyoteReader(inputBuffer); } return reader; } /** * Return the real path of the specified virtual path. * * @param path Path to be translated * * @deprecated As of version 2.1 of the Java Servlet API, use * ServletContext.getRealPath(). */ @Override @Deprecated public String getRealPath(String path) { if (context == null) { return null; } ServletContext servletContext = context.getServletContext(); if (servletContext == null) { return null; } try { return (servletContext.getRealPath(path)); } catch (IllegalArgumentException e) { return null; } } /** * Return the remote IP address making this Request. */ @Override public String getRemoteAddr() { if (remoteAddr == null) { coyoteRequest.action (ActionCode.REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest); remoteAddr = coyoteRequest.remoteAddr().toString(); } return remoteAddr; } /** * Return the remote host name making this Request. */ @Override public String getRemoteHost() { if (remoteHost == null) { if (!connector.getEnableLookups()) { remoteHost = getRemoteAddr(); } else { coyoteRequest.action (ActionCode.REQ_HOST_ATTRIBUTE, coyoteRequest); remoteHost = coyoteRequest.remoteHost().toString(); } } return remoteHost; } /** * Returns the Internet Protocol (IP) source port of the client * or last proxy that sent the request. */ @Override public int getRemotePort(){ if (remotePort == -1) { coyoteRequest.action (ActionCode.REQ_REMOTEPORT_ATTRIBUTE, coyoteRequest); remotePort = coyoteRequest.getRemotePort(); } return remotePort; } /** * Returns the host name of the Internet Protocol (IP) interface on * which the request was received. */ @Override public String getLocalName(){ if (localName == null) { coyoteRequest.action (ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, coyoteRequest); localName = coyoteRequest.localName().toString(); } return localName; } /** * Returns the Internet Protocol (IP) address of the interface on * which the request was received. */ @Override public String getLocalAddr(){ if (localAddr == null) { coyoteRequest.action (ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE, coyoteRequest); localAddr = coyoteRequest.localAddr().toString(); } return localAddr; } /** * Returns the Internet Protocol (IP) port number of the interface * on which the request was received. */ @Override public int getLocalPort(){ if (localPort == -1){ coyoteRequest.action (ActionCode.REQ_LOCALPORT_ATTRIBUTE, coyoteRequest); localPort = coyoteRequest.getLocalPort(); } return localPort; } /** * Return a RequestDispatcher that wraps the resource at the specified * path, which may be interpreted as relative to the current request path. * * @param path Path of the resource to be wrapped */ @Override public RequestDispatcher getRequestDispatcher(String path) { if (context == null) { return null; } // If the path is already context-relative, just pass it through if (path == null) { return null; } else if (path.startsWith("/")) { return (context.getServletContext().getRequestDispatcher(path)); } // Convert a request-relative path to a context-relative one String servletPath = (String) getAttribute( RequestDispatcher.INCLUDE_SERVLET_PATH); if (servletPath == null) { servletPath = getServletPath(); } // Add the path info, if there is any String pathInfo = getPathInfo(); String requestPath = null; if (pathInfo == null) { requestPath = servletPath; } else { requestPath = servletPath + pathInfo; } int pos = requestPath.lastIndexOf('/'); String relative = null; if (pos >= 0) { relative = requestPath.substring(0, pos + 1) + path; } else { relative = requestPath + path; } return context.getServletContext().getRequestDispatcher(relative); } /** * Return the scheme used to make this Request. */ @Override public String getScheme() { return coyoteRequest.scheme().toString(); } /** * Return the server name responding to this Request. */ @Override public String getServerName() { return coyoteRequest.serverName().toString(); } /** * Return the server port responding to this Request. */ @Override public int getServerPort() { return coyoteRequest.getServerPort(); } /** * Was this request received on a secure connection? */ @Override public boolean isSecure() { return secure; } /** * Remove the specified request attribute if it exists. * * @param name Name of the request attribute to remove */ @Override public void removeAttribute(String name) { // Remove the specified attribute // Pass special attributes to the native layer if (name.startsWith("org.apache.tomcat.")) { coyoteRequest.getAttributes().remove(name); } boolean found = attributes.containsKey(name); if (found) { Object value = attributes.get(name); attributes.remove(name); // Notify interested application event listeners notifyAttributeRemoved(name, value); } else { return; } } /** * Set the specified request attribute to the specified value. * * @param name Name of the request attribute to set * @param value The associated value */ @Override public void setAttribute(String name, Object value) { // Name cannot be null if (name == null) { throw new IllegalArgumentException (sm.getString("coyoteRequest.setAttribute.namenull")); } // Null value is the same as removeAttribute() if (value == null) { removeAttribute(name); return; } // Special attributes SpecialAttributeAdapter adapter = specialAttributes.get(name); if (adapter != null) { adapter.set(this, name, value); return; } // Add or replace the specified attribute // Do the security check before any updates are made if (Globals.IS_SECURITY_ENABLED && name.equals(Globals.SENDFILE_FILENAME_ATTR)) { // Use the canonical file name to avoid any possible symlink and // relative path issues String canonicalPath; try { canonicalPath = new File(value.toString()).getCanonicalPath(); } catch (IOException e) { throw new SecurityException(sm.getString( "coyoteRequest.sendfileNotCanonical", value), e); } // Sendfile is performed in Tomcat's security context so need to // check if the web app is permitted to access the file while still // in the web app's security context System.getSecurityManager().checkRead(canonicalPath); // Update the value so the canonical path is used value = canonicalPath; } Object oldValue = attributes.put(name, value); // Pass special attributes to the native layer if (name.startsWith("org.apache.tomcat.")) { coyoteRequest.setAttribute(name, value); } // Notify interested application event listeners notifyAttributeAssigned(name, value, oldValue); } /** * Notify interested listeners that attribute has been assigned a value. */ private void notifyAttributeAssigned(String name, Object value, Object oldValue) { Object listeners[] = context.getApplicationEventListeners(); if ((listeners == null) || (listeners.length == 0)) { return; } boolean replaced = (oldValue != null); ServletRequestAttributeEvent event = null; if (replaced) { event = new ServletRequestAttributeEvent( context.getServletContext(), getRequest(), name, oldValue); } else { event = new ServletRequestAttributeEvent( context.getServletContext(), getRequest(), name, value); } for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof ServletRequestAttributeListener)) { continue; } ServletRequestAttributeListener listener = (ServletRequestAttributeListener) listeners[i]; try { if (replaced) { listener.attributeReplaced(event); } else { listener.attributeAdded(event); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t); // Error valve will pick this exception up and display it to user attributes.put(RequestDispatcher.ERROR_EXCEPTION, t); } } } /** * Notify interested listeners that attribute has been removed. */ private void notifyAttributeRemoved(String name, Object value) { Object listeners[] = context.getApplicationEventListeners(); if ((listeners == null) || (listeners.length == 0)) { return; } ServletRequestAttributeEvent event = new ServletRequestAttributeEvent(context.getServletContext(), getRequest(), name, value); for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof ServletRequestAttributeListener)) { continue; } ServletRequestAttributeListener listener = (ServletRequestAttributeListener) listeners[i]; try { listener.attributeRemoved(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t); // Error valve will pick this exception up and display it to user attributes.put(RequestDispatcher.ERROR_EXCEPTION, t); } } } /** * Overrides the name of the character encoding used in the body of * this request. This method must be called prior to reading request * parameters or reading input using getReader(). * * @param enc The character encoding to be used * * @exception UnsupportedEncodingException if the specified encoding * is not supported * * @since Servlet 2.3 */ @Override public void setCharacterEncoding(String enc) throws UnsupportedEncodingException { if (usingReader) { return; } // Ensure that the specified encoding is valid byte buffer[] = new byte[1]; buffer[0] = (byte) 'a'; // Confirm that the encoding name is valid B2CConverter.getCharset(enc); // Save the validated encoding coyoteRequest.setCharacterEncoding(enc); } @Override public ServletContext getServletContext() { return context.getServletContext(); } @Override public AsyncContext startAsync() { return startAsync(getRequest(),response.getResponse()); } @Override public AsyncContext startAsync(ServletRequest request, ServletResponse response) { if (!isAsyncSupported()) { throw new IllegalStateException("Not supported."); } if (asyncContext == null) { asyncContext = new AsyncContextImpl(this); } asyncContext.setStarted(getContext(), request, response, request==getRequest() && response==getResponse().getResponse()); asyncContext.setTimeout(getConnector().getAsyncTimeout()); return asyncContext; } @Override public boolean isAsyncStarted() { if (asyncContext == null) { return false; } return asyncContext.isStarted(); } public boolean isAsyncDispatching() { if (asyncContext == null) { return false; } AtomicBoolean result = new AtomicBoolean(false); coyoteRequest.action(ActionCode.ASYNC_IS_DISPATCHING, result); return result.get(); } public boolean isAsync() { if (asyncContext == null) { return false; } AtomicBoolean result = new AtomicBoolean(false); coyoteRequest.action(ActionCode.ASYNC_IS_ASYNC, result); return result.get(); } @Override public boolean isAsyncSupported() { if (this.asyncSupported == null) { return true; } return asyncSupported.booleanValue(); } @Override public AsyncContext getAsyncContext() { return this.asyncContext; } @Override public DispatcherType getDispatcherType() { if (internalDispatcherType == null) { return DispatcherType.REQUEST; } return this.internalDispatcherType; } // ---------------------------------------------------- HttpRequest Methods /** * Add a Cookie to the set of Cookies associated with this Request. * * @param cookie The new cookie */ public void addCookie(Cookie cookie) { if (!cookiesParsed) { parseCookies(); } int size = 0; if (cookies != null) { size = cookies.length; } Cookie[] newCookies = new Cookie[size + 1]; for (int i = 0; i < size; i++) { newCookies[i] = cookies[i]; } newCookies[size] = cookie; cookies = newCookies; } /** * Add a Locale to the set of preferred Locales for this Request. The * first added Locale will be the first one returned by getLocales(). * * @param locale The new preferred Locale */ public void addLocale(Locale locale) { locales.add(locale); } /** * Add a parameter name and corresponding set of values to this Request. * (This is used when restoring the original request on a form based * login). * * @param name Name of this request parameter * @param values Corresponding values for this request parameter */ @Deprecated public void addParameter(String name, String values[]) { coyoteRequest.getParameters().addParameterValues(name, values); } /** * Clear the collection of Cookies associated with this Request. */ public void clearCookies() { cookiesParsed = true; cookies = null; } /** * Clear the collection of Headers associated with this Request. */ @Deprecated public void clearHeaders() { // Not used } /** * Clear the collection of Locales associated with this Request. */ public void clearLocales() { locales.clear(); } /** * Clear the collection of parameters associated with this Request. */ @Deprecated public void clearParameters() { // Not used } /** * Set the authentication type used for this request, if any; otherwise * set the type to null. Typical values are "BASIC", * "DIGEST", or "SSL". * * @param type The authentication type used */ public void setAuthType(String type) { this.authType = type; } /** * Set the context path for this Request. This will normally be called * when the associated Context is mapping the Request to a particular * Wrapper. * * @param path The context path */ @Deprecated public void setContextPath(String path) { if (path == null) { mappingData.contextPath.setString(""); } else { mappingData.contextPath.setString(path); } } /** * Set the path information for this Request. This will normally be called * when the associated Context is mapping the Request to a particular * Wrapper. * * @param path The path information */ public void setPathInfo(String path) { mappingData.pathInfo.setString(path); } /** * Set a flag indicating whether or not the requested session ID for this * request came in through a cookie. This is normally called by the * HTTP Connector, when it parses the request headers. * * @param flag The new flag */ public void setRequestedSessionCookie(boolean flag) { this.requestedSessionCookie = flag; } /** * Set the requested session ID for this request. This is normally called * by the HTTP Connector, when it parses the request headers. * * @param id The new session id */ public void setRequestedSessionId(String id) { this.requestedSessionId = id; } /** * Set a flag indicating whether or not the requested session ID for this * request came in through a URL. This is normally called by the * HTTP Connector, when it parses the request headers. * * @param flag The new flag */ public void setRequestedSessionURL(boolean flag) { this.requestedSessionURL = flag; } /** * Set a flag indicating whether or not the requested session ID for this * request came in through SSL. This is normally called by the * HTTP Connector, when it parses the request headers. * * @param flag The new flag */ public void setRequestedSessionSSL(boolean flag) { this.requestedSessionSSL = flag; } /** * Get the decoded request URI. * * @return the URL decoded request URI */ public String getDecodedRequestURI() { return coyoteRequest.decodedURI().toString(); } /** * Get the decoded request URI. * * @return the URL decoded request URI */ public MessageBytes getDecodedRequestURIMB() { return coyoteRequest.decodedURI(); } /** * Set the servlet path for this Request. This will normally be called * when the associated Context is mapping the Request to a particular * Wrapper. * * @param path The servlet path */ @Deprecated public void setServletPath(String path) { if (path != null) { mappingData.wrapperPath.setString(path); } } /** * Set the Principal who has been authenticated for this Request. This * value is also used to calculate the value to be returned by the * getRemoteUser() method. * * @param principal The user Principal */ public void setUserPrincipal(Principal principal) { if (Globals.IS_SECURITY_ENABLED){ HttpSession session = getSession(false); if ( (subject != null) && (!subject.getPrincipals().contains(principal)) ){ subject.getPrincipals().add(principal); } else if (session != null && session.getAttribute(Globals.SUBJECT_ATTR) == null) { subject = new Subject(); subject.getPrincipals().add(principal); } if (session != null){ session.setAttribute(Globals.SUBJECT_ATTR, subject); } } this.userPrincipal = principal; } // --------------------------------------------- HttpServletRequest Methods /** * Return the authentication type used for this Request. */ @Override public String getAuthType() { return authType; } /** * Return the portion of the request URI used to select the Context * of the Request. */ @Override public String getContextPath() { return mappingData.contextPath.toString(); } /** * Get the context path. * * @return the context path */ @Deprecated public MessageBytes getContextPathMB() { return mappingData.contextPath; } /** * Return the set of Cookies received with this Request. */ @Override public Cookie[] getCookies() { if (!cookiesParsed) { parseCookies(); } return cookies; } /** * Set the set of cookies received with this Request. */ @Deprecated public void setCookies(Cookie[] cookies) { this.cookies = cookies; } /** * Return the value of the specified date header, if any; otherwise * return -1. * * @param name Name of the requested date header * * @exception IllegalArgumentException if the specified header value * cannot be converted to a date */ @Override public long getDateHeader(String name) { String value = getHeader(name); if (value == null) { return (-1L); } // Attempt to convert the date header in a variety of formats long result = FastHttpDateFormat.parseDate(value, formats); if (result != (-1L)) { return result; } throw new IllegalArgumentException(value); } /** * Return the first value of the specified header, if any; otherwise, * return null * * @param name Name of the requested header */ @Override public String getHeader(String name) { return coyoteRequest.getHeader(name); } /** * Return all of the values of the specified header, if any; otherwise, * return an empty enumeration. * * @param name Name of the requested header */ @Override public Enumeration getHeaders(String name) { return coyoteRequest.getMimeHeaders().values(name); } /** * Return the names of all headers received with this request. */ @Override public Enumeration getHeaderNames() { return coyoteRequest.getMimeHeaders().names(); } /** * Return the value of the specified header as an integer, or -1 if there * is no such header for this request. * * @param name Name of the requested header * * @exception IllegalArgumentException if the specified header value * cannot be converted to an integer */ @Override public int getIntHeader(String name) { String value = getHeader(name); if (value == null) { return (-1); } return Integer.parseInt(value); } /** * Return the HTTP request method used in this Request. */ @Override public String getMethod() { return coyoteRequest.method().toString(); } /** * Return the path information associated with this Request. */ @Override public String getPathInfo() { return mappingData.pathInfo.toString(); } /** * Get the path info. * * @return the path info */ @Deprecated public MessageBytes getPathInfoMB() { return mappingData.pathInfo; } /** * Return the extra path information for this request, translated * to a real path. */ @Override public String getPathTranslated() { if (context == null) { return null; } if (getPathInfo() == null) { return null; } return context.getServletContext().getRealPath(getPathInfo()); } /** * Return the query string associated with this request. */ @Override public String getQueryString() { return coyoteRequest.queryString().toString(); } /** * Return the name of the remote user that has been authenticated * for this Request. */ @Override public String getRemoteUser() { if (userPrincipal == null) { return null; } return userPrincipal.getName(); } /** * Get the request path. * * @return the request path */ public MessageBytes getRequestPathMB() { return mappingData.requestPath; } /** * Return the session identifier included in this request, if any. */ @Override public String getRequestedSessionId() { return requestedSessionId; } /** * Return the request URI for this request. */ @Override public String getRequestURI() { return coyoteRequest.requestURI().toString(); } /** * Reconstructs the URL the client used to make the request. * The returned URL contains a protocol, server name, port * number, and server path, but it does not include query * string parameters. *

    * Because this method returns a StringBuffer, * not a String, you can modify the URL easily, * for example, to append query parameters. *

    * This method is useful for creating redirect messages and * for reporting errors. * * @return A StringBuffer object containing the * reconstructed URL */ @Override public StringBuffer getRequestURL() { StringBuffer url = new StringBuffer(); String scheme = getScheme(); int port = getServerPort(); if (port < 0) { port = 80; // Work around java.net.URL bug } url.append(scheme); url.append("://"); url.append(getServerName()); if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) { url.append(':'); url.append(port); } url.append(getRequestURI()); return url; } /** * Return the portion of the request URI used to select the servlet * that will process this request. */ @Override public String getServletPath() { return (mappingData.wrapperPath.toString()); } /** * Get the servlet path. * * @return the servlet path */ @Deprecated public MessageBytes getServletPathMB() { return mappingData.wrapperPath; } /** * Return the session associated with this Request, creating one * if necessary. */ @Override public HttpSession getSession() { Session session = doGetSession(true); if (session == null) { return null; } return session.getSession(); } /** * Return the session associated with this Request, creating one * if necessary and requested. * * @param create Create a new session if one does not exist */ @Override public HttpSession getSession(boolean create) { Session session = doGetSession(create); if (session == null) { return null; } return session.getSession(); } /** * Return true if the session identifier included in this * request came from a cookie. */ @Override public boolean isRequestedSessionIdFromCookie() { if (requestedSessionId == null) { return false; } return requestedSessionCookie; } /** * Return true if the session identifier included in this * request came from the request URI. */ @Override public boolean isRequestedSessionIdFromURL() { if (requestedSessionId == null) { return false; } return requestedSessionURL; } /** * Return true if the session identifier included in this * request came from the request URI. * * @deprecated As of Version 2.1 of the Java Servlet API, use * isRequestedSessionIdFromURL() instead. */ @Override @Deprecated public boolean isRequestedSessionIdFromUrl() { return (isRequestedSessionIdFromURL()); } /** * Return true if the session identifier included in this * request identifies a valid session. */ @Override public boolean isRequestedSessionIdValid() { if (requestedSessionId == null) { return false; } if (context == null) { return false; } Manager manager = context.getManager(); if (manager == null) { return false; } Session session = null; try { session = manager.findSession(requestedSessionId); } catch (IOException e) { // Can't find the session } if ((session == null) || !session.isValid()) { // Check for parallel deployment contexts if (getMappingData().contexts == null) { return false; } else { for (int i = (getMappingData().contexts.length); i > 0; i--) { Context ctxt = (Context) getMappingData().contexts[i - 1]; try { if (ctxt.getManager().findSession(requestedSessionId) != null) { return true; } } catch (IOException e) { // Ignore } } return false; } } return true; } /** * Return true if the authenticated user principal * possesses the specified role name. * * @param role Role name to be validated */ @Override public boolean isUserInRole(String role) { // Have we got an authenticated principal at all? if (userPrincipal == null) { return false; } // Identify the Realm we will use for checking role assignments if (context == null) { return false; } Realm realm = context.getRealm(); if (realm == null) { return false; } // Check for a role defined directly as a return (realm.hasRole(wrapper, userPrincipal, role)); } /** * Return the principal that has been authenticated for this Request. */ public Principal getPrincipal() { return userPrincipal; } /** * Return the principal that has been authenticated for this Request. */ @Override public Principal getUserPrincipal() { if (userPrincipal instanceof GenericPrincipal) { GSSCredential gssCredential = ((GenericPrincipal) userPrincipal).getGssCredential(); if (gssCredential != null) { int left = -1; try { left = gssCredential.getRemainingLifetime(); } catch (GSSException e) { log.warn(sm.getString("coyoteRequest.gssLifetimeFail", userPrincipal.getName()), e); } if (left == 0) { // GSS credential has expired. Need to re-authenticate. try { logout(); } catch (ServletException e) { // Should never happen (no code called by logout() // throws a ServletException } return null; } } return ((GenericPrincipal) userPrincipal).getUserPrincipal(); } return userPrincipal; } /** * Return the session associated with this Request, creating one * if necessary. */ public Session getSessionInternal() { return doGetSession(true); } /** * Change the ID of the session that this request is associated with. There * are several things that may trigger an ID change. These include moving * between nodes in a cluster and session fixation prevention during the * authentication process. * * @param newSessionId The session to change the session ID for */ public void changeSessionId(String newSessionId) { // This should only ever be called if there was an old session ID but // double check to be sure if (requestedSessionId != null && requestedSessionId.length() > 0) { requestedSessionId = newSessionId; } if (context != null && !context.getServletContext() .getEffectiveSessionTrackingModes().contains( SessionTrackingMode.COOKIE)) { return; } if (response != null) { Cookie newCookie = ApplicationSessionCookieConfig.createSessionCookie(context, newSessionId, secure); response.addSessionCookieInternal(newCookie); } } /** * Return the session associated with this Request, creating one * if necessary and requested. * * @param create Create a new session if one does not exist */ public Session getSessionInternal(boolean create) { return doGetSession(create); } /** * Get the event associated with the request. * @return the event */ public CometEventImpl getEvent() { if (event == null) { event = new CometEventImpl(this, response); } return event; } /** * Return true if the current request is handling Comet traffic. */ public boolean isComet() { return comet; } /** * Set comet state. */ public void setComet(boolean comet) { this.comet = comet; } /** * return true if we have parsed parameters */ public boolean isParametersParsed() { return parametersParsed; } /** * Return true if bytes are available. */ public boolean getAvailable() { return (inputBuffer.available() > 0); } /** * Disable swallowing of remaining input if configured */ protected void checkSwallowInput() { Context context = getContext(); if (context != null && !context.getSwallowAbortedUploads()) { coyoteRequest.action(ActionCode.DISABLE_SWALLOW_INPUT, null); } } public void cometClose() { coyoteRequest.action(ActionCode.COMET_CLOSE,getEvent()); setComet(false); } public void setCometTimeout(long timeout) { coyoteRequest.action(ActionCode.COMET_SETTIMEOUT, Long.valueOf(timeout)); } /** * Not part of Servlet 3 spec but probably should be. * @return true if the requested session ID was obtained from the SSL session */ @Deprecated public boolean isRequestedSessionIdFromSSL() { return requestedSessionSSL; } /** * @throws IOException If an I/O error occurs * @throws IllegalStateException If the response has been committed * @throws ServletException If the caller is responsible for handling the * error and the container has NOT set the HTTP response code etc. */ @Override public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { if (response.isCommitted()) { throw new IllegalStateException( sm.getString("coyoteRequest.authenticate.ise")); } return context.getAuthenticator().authenticate(this, response); } /** * {@inheritDoc} */ @Override public void login(String username, String password) throws ServletException { if (getAuthType() != null || getRemoteUser() != null || getUserPrincipal() != null) { throw new ServletException( sm.getString("coyoteRequest.alreadyAuthenticated")); } if (context.getAuthenticator() == null) { throw new ServletException("no authenticator"); } context.getAuthenticator().login(username, password, this); } /** * {@inheritDoc} */ @Override public void logout() throws ServletException { context.getAuthenticator().logout(this); } /** * {@inheritDoc} */ @Override public Collection getParts() throws IOException, IllegalStateException, ServletException { parseParts(); if (partsParseException != null) { if (partsParseException instanceof IOException) { throw (IOException) partsParseException; } else if (partsParseException instanceof IllegalStateException) { throw (IllegalStateException) partsParseException; } else if (partsParseException instanceof ServletException) { throw (ServletException) partsParseException; } } return parts; } private void parseParts() { // Return immediately if the parts have already been parsed if (parts != null || partsParseException != null) { return; } MultipartConfigElement mce = getWrapper().getMultipartConfigElement(); if (mce == null) { if(getContext().getAllowCasualMultipartParsing()) { mce = new MultipartConfigElement(null, connector.getMaxPostSize(), connector.getMaxPostSize(), connector.getMaxPostSize()); } else { parts = Collections.emptyList(); return; } } Parameters parameters = coyoteRequest.getParameters(); parameters.setLimit(getConnector().getMaxParameterCount()); boolean success = false; try { File location; String locationStr = mce.getLocation(); if (locationStr == null || locationStr.length() == 0) { location = ((File) context.getServletContext().getAttribute( ServletContext.TEMPDIR)); } else { // If relative, it is relative to TEMPDIR location = new File(locationStr); if (!location.isAbsolute()) { location = new File( (File) context.getServletContext().getAttribute( ServletContext.TEMPDIR), locationStr).getAbsoluteFile(); } } if (!location.isDirectory()) { partsParseException = new IOException( sm.getString("coyoteRequest.uploadLocationInvalid", location)); return; } // Create a new file upload handler DiskFileItemFactory factory = new DiskFileItemFactory(); try { factory.setRepository(location.getCanonicalFile()); } catch (IOException ioe) { partsParseException = ioe; return; } factory.setSizeThreshold(mce.getFileSizeThreshold()); ServletFileUpload upload = new ServletFileUpload(); upload.setFileItemFactory(factory); upload.setFileSizeMax(mce.getMaxFileSize()); upload.setSizeMax(mce.getMaxRequestSize()); parts = new ArrayList(); try { List items = upload.parseRequest(new ServletRequestContext(this)); int maxPostSize = getConnector().getMaxPostSize(); int postSize = 0; String enc = getCharacterEncoding(); Charset charset = null; if (enc != null) { try { charset = B2CConverter.getCharset(enc); } catch (UnsupportedEncodingException e) { // Ignore } } for (FileItem item : items) { ApplicationPart part = new ApplicationPart(item, location); parts.add(part); if (part.getSubmittedFileName() == null) { String name = part.getName(); String value = null; try { String encoding = parameters.getEncoding(); if (encoding == null) { if (enc == null) { encoding = Parameters.DEFAULT_ENCODING; } else { encoding = enc; } } value = part.getString(encoding); } catch (UnsupportedEncodingException uee) { try { value = part.getString(Parameters.DEFAULT_ENCODING); } catch (UnsupportedEncodingException e) { // Should not be possible } } if (maxPostSize > 0) { // Have to calculate equivalent size. Not completely // accurate but close enough. if (charset == null) { // Name length postSize += name.getBytes().length; } else { postSize += name.getBytes(charset).length; } if (value != null) { // Equals sign postSize++; // Value length postSize += part.getSize(); } // Value separator postSize++; if (postSize > maxPostSize) { throw new IllegalStateException(sm.getString( "coyoteRequest.maxPostSizeExceeded")); } } parameters.addParameter(name, value); } } success = true; } catch (InvalidContentTypeException e) { partsParseException = new ServletException(e); } catch (FileUploadBase.SizeException e) { checkSwallowInput(); partsParseException = new IllegalStateException(e); } catch (FileUploadException e) { partsParseException = new IOException(e); } catch (IllegalStateException e) { checkSwallowInput(); partsParseException = e; } } finally { if (partsParseException != null || !success) { parameters.setParseFailed(true); } } } /** * {@inheritDoc} */ @Override public Part getPart(String name) throws IOException, IllegalStateException, ServletException { Collection c = getParts(); Iterator iterator = c.iterator(); while (iterator.hasNext()) { Part part = iterator.next(); if (name.equals(part.getName())) { return part; } } return null; } // --------------------------------- Tomcat proprietary HTTP upgrade methods /** * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public void doUpgrade(org.apache.coyote.http11.upgrade.UpgradeInbound inbound) throws IOException { coyoteRequest.action(ActionCode.UPGRADE_TOMCAT, inbound); // Output required by RFC2616. Protocol specific headers should have // already been set. response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS); response.flushBuffer(); } // ---------------------------------- Servlet 3.1 based HTTP upgrade methods @SuppressWarnings("unchecked") public T upgrade( Class httpUpgradeHandlerClass) throws ServletException { T handler; try { handler = (T) context.getInstanceManager().newInstance(httpUpgradeHandlerClass); } catch (InstantiationException e) { throw new ServletException(e); } catch (IllegalAccessException e) { throw new ServletException(e); } catch (InvocationTargetException e) { throw new ServletException(e); } catch (NamingException e) { throw new ServletException(e); } coyoteRequest.action(ActionCode.UPGRADE, handler); // Output required by RFC2616. Protocol specific headers should have // already been set. response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS); return handler; } // ------------------------------------------------------ Protected Methods protected Session doGetSession(boolean create) { // There cannot be a session if no context has been assigned yet if (context == null) { return (null); } // Return the current session if it exists and is valid if ((session != null) && !session.isValid()) { session = null; } if (session != null) { return (session); } // Return the requested session if it exists and is valid Manager manager = null; if (context != null) { manager = context.getManager(); } if (manager == null) { return (null); // Sessions are not supported } if (requestedSessionId != null) { try { session = manager.findSession(requestedSessionId); } catch (IOException e) { session = null; } if ((session != null) && !session.isValid()) { session = null; } if (session != null) { session.access(); return (session); } } // Create a new session if requested and the response is not committed if (!create) { return (null); } if ((context != null) && (response != null) && context.getServletContext().getEffectiveSessionTrackingModes(). contains(SessionTrackingMode.COOKIE) && response.getResponse().isCommitted()) { throw new IllegalStateException (sm.getString("coyoteRequest.sessionCreateCommitted")); } // Attempt to reuse session id if one was submitted in a cookie // Do not reuse the session id if it is from a URL, to prevent possible // phishing attacks // Use the SSL session ID if one is present. if (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie()) || requestedSessionSSL ) { session = manager.createSession(getRequestedSessionId()); } else { session = manager.createSession(null); } // Creating a new session cookie based on that session if ((session != null) && (getContext() != null) && getContext().getServletContext(). getEffectiveSessionTrackingModes().contains( SessionTrackingMode.COOKIE)) { Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie( context, session.getIdInternal(), isSecure()); response.addSessionCookieInternal(cookie); } if (session == null) { return null; } session.access(); return session; } protected String unescape(String s) { if (s==null) { return null; } if (s.indexOf('\\') == -1) { return s; } StringBuilder buf = new StringBuilder(); for (int i=0; i= s.length()) { throw new IllegalArgumentException();//invalid escape, hence invalid cookie } c = s.charAt(i); buf.append(c); } } return buf.toString(); } /** * Parse cookies. */ protected void parseCookies() { cookiesParsed = true; Cookies serverCookies = coyoteRequest.getCookies(); int count = serverCookies.getCookieCount(); if (count <= 0) { return; } cookies = new Cookie[count]; int idx=0; for (int i = 0; i < count; i++) { ServerCookie scookie = serverCookies.getCookie(i); try { /* we must unescape the '\\' escape character */ Cookie cookie = new Cookie(scookie.getName().toString(),null); int version = scookie.getVersion(); cookie.setVersion(version); cookie.setValue(unescape(scookie.getValue().toString())); cookie.setPath(unescape(scookie.getPath().toString())); String domain = scookie.getDomain().toString(); if (domain!=null) { cookie.setDomain(unescape(domain));//avoid NPE } String comment = scookie.getComment().toString(); cookie.setComment(version==1?unescape(comment):null); cookies[idx++] = cookie; } catch(IllegalArgumentException e) { // Ignore bad cookie } } if( idx < count ) { Cookie [] ncookies = new Cookie[idx]; System.arraycopy(cookies, 0, ncookies, 0, idx); cookies = ncookies; } } /** * Parse request parameters. */ protected void parseParameters() { parametersParsed = true; Parameters parameters = coyoteRequest.getParameters(); boolean success = false; try { // Set this every time in case limit has been changed via JMX parameters.setLimit(getConnector().getMaxParameterCount()); // getCharacterEncoding() may have been overridden to search for // hidden form field containing request encoding String enc = getCharacterEncoding(); boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI(); if (enc != null) { parameters.setEncoding(enc); if (useBodyEncodingForURI) { parameters.setQueryStringEncoding(enc); } } else { parameters.setEncoding (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); if (useBodyEncodingForURI) { parameters.setQueryStringEncoding (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); } } parameters.handleQueryParameters(); if (usingInputStream || usingReader) { success = true; return; } if( !getConnector().isParseBodyMethod(getMethod()) ) { success = true; return; } String contentType = getContentType(); if (contentType == null) { contentType = ""; } int semicolon = contentType.indexOf(';'); if (semicolon >= 0) { contentType = contentType.substring(0, semicolon).trim(); } else { contentType = contentType.trim(); } if ("multipart/form-data".equals(contentType)) { parseParts(); success = true; return; } if (!("application/x-www-form-urlencoded".equals(contentType))) { success = true; return; } int len = getContentLength(); if (len > 0) { int maxPostSize = connector.getMaxPostSize(); if ((maxPostSize > 0) && (len > maxPostSize)) { if (context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.postTooLarge")); } checkSwallowInput(); return; } byte[] formData = null; if (len < CACHED_POST_LEN) { if (postData == null) { postData = new byte[CACHED_POST_LEN]; } formData = postData; } else { formData = new byte[len]; } try { if (readPostBody(formData, len) != len) { return; } } catch (IOException e) { // Client disconnect if (context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.parseParameters"), e); } return; } parameters.processParameters(formData, 0, len); } else if ("chunked".equalsIgnoreCase( coyoteRequest.getHeader("transfer-encoding"))) { byte[] formData = null; try { formData = readChunkedPostBody(); } catch (IOException e) { // Client disconnect or chunkedPostTooLarge error if (context.getLogger().isDebugEnabled()) { context.getLogger().debug( sm.getString("coyoteRequest.parseParameters"), e); } return; } if (formData != null) { parameters.processParameters(formData, 0, formData.length); } } success = true; } finally { if (!success) { parameters.setParseFailed(true); } } } /** * Read post body in an array. */ protected int readPostBody(byte body[], int len) throws IOException { int offset = 0; do { int inputLen = getStream().read(body, offset, len - offset); if (inputLen <= 0) { return offset; } offset += inputLen; } while ((len - offset) > 0); return len; } /** * Read chunked post body. */ protected byte[] readChunkedPostBody() throws IOException { ByteChunk body = new ByteChunk(); byte[] buffer = new byte[CACHED_POST_LEN]; int len = 0; while (len > -1) { len = getStream().read(buffer, 0, CACHED_POST_LEN); if (connector.getMaxPostSize() > 0 && (body.getLength() + len) > connector.getMaxPostSize()) { // Too much data checkSwallowInput(); throw new IOException( sm.getString("coyoteRequest.chunkedPostTooLarge")); } if (len > 0) { body.append(buffer, 0, len); } } if (body.getLength() == 0) { return null; } if (body.getLength() < body.getBuffer().length) { int length = body.getLength(); byte[] result = new byte[length]; System.arraycopy(body.getBuffer(), 0, result, 0, length); return result; } return body.getBuffer(); } /** * Parse request locales. */ protected void parseLocales() { localesParsed = true; Enumeration values = getHeaders("accept-language"); while (values.hasMoreElements()) { String value = values.nextElement(); parseLocalesHeader(value); } } /** * Parse accept-language header value. */ protected void parseLocalesHeader(String value) { // Store the accumulated languages that have been requested in // a local collection, sorted by the quality value (so we can // add Locales in descending order). The values will be ArrayLists // containing the corresponding Locales to be added TreeMap> locales = new TreeMap>(); // Preprocess the value to remove all whitespace int white = value.indexOf(' '); if (white < 0) { white = value.indexOf('\t'); } if (white >= 0) { StringBuilder sb = new StringBuilder(); int len = value.length(); for (int i = 0; i < len; i++) { char ch = value.charAt(i); if ((ch != ' ') && (ch != '\t')) { sb.append(ch); } } parser.setString(sb.toString()); } else { parser.setString(value); } // Process each comma-delimited language specification int length = parser.getLength(); while (true) { // Extract the next comma-delimited entry int start = parser.getIndex(); if (start >= length) { break; } int end = parser.findChar(','); String entry = parser.extract(start, end).trim(); parser.advance(); // For the following entry // Extract the quality factor for this entry double quality = 1.0; int semi = entry.indexOf(";q="); if (semi >= 0) { try { String strQuality = entry.substring(semi + 3); if (strQuality.length() <= 5) { quality = Double.parseDouble(strQuality); } else { quality = 0.0; } } catch (NumberFormatException e) { quality = 0.0; } entry = entry.substring(0, semi); } // Skip entries we are not going to keep track of if (quality < 0.00005) { continue; // Zero (or effectively zero) quality factors } if ("*".equals(entry)) { continue; // FIXME - "*" entries are not handled } // Extract the language and country for this entry String language = null; String country = null; String variant = null; int dash = entry.indexOf('-'); if (dash < 0) { language = entry; country = ""; variant = ""; } else { language = entry.substring(0, dash); country = entry.substring(dash + 1); int vDash = country.indexOf('-'); if (vDash > 0) { String cTemp = country.substring(0, vDash); variant = country.substring(vDash + 1); country = cTemp; } else { variant = ""; } } if (!isAlpha(language) || !isAlpha(country) || !isAlpha(variant)) { continue; } // Add a new Locale to the list of Locales for this quality level Locale locale = new Locale(language, country, variant); Double key = new Double(-quality); // Reverse the order ArrayList values = locales.get(key); if (values == null) { values = new ArrayList(); locales.put(key, values); } values.add(locale); } // Process the quality values in highest->lowest order (due to // negating the Double value when creating the key) for (ArrayList list : locales.values()) { for (Locale locale : list) { addLocale(locale); } } } protected static final boolean isAlpha(String value) { for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) { return false; } } return true; } // ----------------------------------------------------- Special attributes handling private static interface SpecialAttributeAdapter { Object get(Request request, String name); void set(Request request, String name, Object value); // None of special attributes support removal // void remove(Request request, String name); } private static final Map specialAttributes = new HashMap(); static { specialAttributes.put(Globals.DISPATCHER_TYPE_ATTR, new SpecialAttributeAdapter() { @Override public Object get(Request request, String name) { return (request.internalDispatcherType == null) ? DispatcherType.REQUEST : request.internalDispatcherType; } @Override public void set(Request request, String name, Object value) { request.internalDispatcherType = (DispatcherType) value; } }); specialAttributes.put(Globals.DISPATCHER_REQUEST_PATH_ATTR, new SpecialAttributeAdapter() { @Override public Object get(Request request, String name) { return (request.requestDispatcherPath == null) ? request .getRequestPathMB().toString() : request.requestDispatcherPath.toString(); } @Override public void set(Request request, String name, Object value) { request.requestDispatcherPath = value; } }); specialAttributes.put(Globals.ASYNC_SUPPORTED_ATTR, new SpecialAttributeAdapter() { @Override public Object get(Request request, String name) { return request.asyncSupported; } @Override public void set(Request request, String name, Object value) { Boolean oldValue = request.asyncSupported; request.asyncSupported = (Boolean)value; request.notifyAttributeAssigned(name, value, oldValue); } }); specialAttributes.put(Globals.GSS_CREDENTIAL_ATTR, new SpecialAttributeAdapter() { @Override public Object get(Request request, String name) { if (request.userPrincipal instanceof GenericPrincipal) { return ((GenericPrincipal) request.userPrincipal) .getGssCredential(); } return null; } @Override public void set(Request request, String name, Object value) { // NO-OP } }); specialAttributes.put(Globals.PARAMETER_PARSE_FAILED_ATTR, new SpecialAttributeAdapter() { @Override public Object get(Request request, String name) { if (request.getCoyoteRequest().getParameters() .isParseFailed()) { return Boolean.TRUE; } return null; } @Override public void set(Request request, String name, Object value) { // NO-OP } }); } } tomcat7-7.0.52/java/org/apache/catalina/connector/OutputBuffer.java0000644000175100017510000003627112271471332025152 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import java.io.Writer; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.HashMap; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.coyote.ActionCode; import org.apache.coyote.Response; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.C2BConverter; import org.apache.tomcat.util.buf.CharChunk; /** * The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3 * OutputBuffer, with the removal of some of the state handling (which in * Coyote is mostly the Processor's responsibility). * * @author Costin Manolache * @author Remy Maucherat */ public class OutputBuffer extends Writer implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel { // -------------------------------------------------------------- Constants public static final String DEFAULT_ENCODING = org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING; public static final int DEFAULT_BUFFER_SIZE = 8*1024; // ----------------------------------------------------- Instance Variables /** * The byte buffer. */ private final ByteChunk bb; /** * The chunk buffer. */ private final CharChunk cb; /** * State of the output buffer. */ private boolean initial = true; /** * Number of bytes written. */ private long bytesWritten = 0; /** * Number of chars written. */ private long charsWritten = 0; /** * Flag which indicates if the output buffer is closed. */ private boolean closed = false; /** * Do a flush on the next operation. */ private boolean doFlush = false; /** * Byte chunk used to output bytes. */ private final ByteChunk outputChunk = new ByteChunk(); /** * Char chunk used to output chars. */ private CharChunk outputCharChunk = new CharChunk(); /** * Encoding to use. */ private String enc; /** * Encoder is set. */ private boolean gotEnc = false; /** * List of encoders. */ protected HashMap encoders = new HashMap(); /** * Current char to byte converter. */ protected C2BConverter conv; /** * Associated Coyote response. */ private Response coyoteResponse; /** * Suspended flag. All output bytes will be swallowed if this is true. */ private boolean suspended = false; // ----------------------------------------------------------- Constructors /** * Default constructor. Allocate the buffer with the default buffer size. */ public OutputBuffer() { this(DEFAULT_BUFFER_SIZE); } /** * Alternate constructor which allows specifying the initial buffer size. * * @param size Buffer size to use */ public OutputBuffer(int size) { bb = new ByteChunk(size); bb.setLimit(size); bb.setByteOutputChannel(this); cb = new CharChunk(size); cb.setLimit(size); cb.setOptimizedWrite(false); cb.setCharOutputChannel(this); } // ------------------------------------------------------------- Properties /** * Associated Coyote response. * * @param coyoteResponse Associated Coyote response */ public void setResponse(Response coyoteResponse) { this.coyoteResponse = coyoteResponse; } /** * Get associated Coyote response. * * @return the associated Coyote response */ @Deprecated public Response getResponse() { return this.coyoteResponse; } /** * Is the response output suspended ? * * @return suspended flag value */ public boolean isSuspended() { return this.suspended; } /** * Set the suspended flag. * * @param suspended New suspended flag value */ public void setSuspended(boolean suspended) { this.suspended = suspended; } /** * Is the response output closed ? * * @return closed flag value */ public boolean isClosed() { return this.closed; } // --------------------------------------------------------- Public Methods /** * Recycle the output buffer. */ public void recycle() { initial = true; bytesWritten = 0; charsWritten = 0; bb.recycle(); cb.recycle(); outputCharChunk.setChars(null, 0, 0); closed = false; suspended = false; doFlush = false; if (conv!= null) { conv.recycle(); } gotEnc = false; enc = null; } /** * Clear cached encoders (to save memory for Comet requests). */ public void clearEncoders() { encoders.clear(); } /** * Close the output buffer. This tries to calculate the response size if * the response has not been committed yet. * * @throws IOException An underlying IOException occurred */ @Override public void close() throws IOException { if (closed) { return; } if (suspended) { return; } // If there are chars, flush all of them to the byte buffer now as bytes are used to // calculate the content-length (if everything fits into the byte buffer, of course). if (cb.getLength() > 0) { cb.flushBuffer(); } if ((!coyoteResponse.isCommitted()) && (coyoteResponse.getContentLengthLong() == -1)) { // If this didn't cause a commit of the response, the final content // length can be calculated if (!coyoteResponse.isCommitted()) { coyoteResponse.setContentLength(bb.getLength()); } } if (coyoteResponse.getStatus() == HttpServletResponse.SC_SWITCHING_PROTOCOLS) { doFlush(true); } else { doFlush(false); } closed = true; // The request should have been completely read by the time the response // is closed. Further reads of the input a) are pointless and b) really // confuse AJP (bug 50189) so close the input buffer to prevent them. Request req = (Request) coyoteResponse.getRequest().getNote( CoyoteAdapter.ADAPTER_NOTES); req.inputBuffer.close(); coyoteResponse.finish(); } /** * Flush bytes or chars contained in the buffer. * * @throws IOException An underlying IOException occurred */ @Override public void flush() throws IOException { doFlush(true); } /** * Flush bytes or chars contained in the buffer. * * @throws IOException An underlying IOException occurred */ protected void doFlush(boolean realFlush) throws IOException { if (suspended) { return; } try { doFlush = true; if (initial) { coyoteResponse.sendHeaders(); initial = false; } if (cb.getLength() > 0) { cb.flushBuffer(); } if (bb.getLength() > 0) { bb.flushBuffer(); } } finally { doFlush = false; } if (realFlush) { coyoteResponse.action(ActionCode.CLIENT_FLUSH, coyoteResponse); // If some exception occurred earlier, or if some IOE occurred // here, notify the servlet with an IOE if (coyoteResponse.isExceptionPresent()) { throw new ClientAbortException (coyoteResponse.getErrorException()); } } } // ------------------------------------------------- Bytes Handling Methods /** * Sends the buffer data to the client output, checking the * state of Response and calling the right interceptors. * * @param buf Byte buffer to be written to the response * @param off Offset * @param cnt Length * * @throws IOException An underlying IOException occurred */ @Override public void realWriteBytes(byte buf[], int off, int cnt) throws IOException { if (closed) { return; } if (coyoteResponse == null) { return; } // If we really have something to write if (cnt > 0) { // real write to the adapter outputChunk.setBytes(buf, off, cnt); try { coyoteResponse.doWrite(outputChunk); } catch (IOException e) { // An IOException on a write is almost always due to // the remote client aborting the request. Wrap this // so that it can be handled better by the error dispatcher. throw new ClientAbortException(e); } } } public void write(byte b[], int off, int len) throws IOException { if (suspended) { return; } writeBytes(b, off, len); } private void writeBytes(byte b[], int off, int len) throws IOException { if (closed) { return; } bb.append(b, off, len); bytesWritten += len; // if called from within flush(), then immediately flush // remaining bytes if (doFlush) { bb.flushBuffer(); } } public void writeByte(int b) throws IOException { if (suspended) { return; } bb.append((byte) b); bytesWritten++; } // ------------------------------------------------- Chars Handling Methods /** * Convert the chars to bytes, then send the data to the client. * * @param buf Char buffer to be written to the response * @param off Offset * @param len Length * * @throws IOException An underlying IOException occurred */ @Override public void realWriteChars(char buf[], int off, int len) throws IOException { outputCharChunk.setChars(buf, off, len); while (outputCharChunk.getLength() > 0) { conv.convert(outputCharChunk, bb); if (bb.getLength() == 0) { // Break out of the loop if more chars are needed to produce any output break; } if (outputCharChunk.getLength() > 0) { if (bb.getBuffer().length == bb.getEnd() && bb.getLength() < bb.getLimit()) { // Need to expand output buffer bb.makeSpace(outputCharChunk.getLength()); } else { bb.flushBuffer(); } } } } @Override public void write(int c) throws IOException { if (suspended) { return; } cb.append((char) c); charsWritten++; } @Override public void write(char c[]) throws IOException { if (suspended) { return; } write(c, 0, c.length); } @Override public void write(char c[], int off, int len) throws IOException { if (suspended) { return; } cb.append(c, off, len); charsWritten += len; } /** * Append a string to the buffer */ @Override public void write(String s, int off, int len) throws IOException { if (suspended) { return; } charsWritten += len; if (s == null) { s = "null"; } cb.append(s, off, len); charsWritten += len; } @Override public void write(String s) throws IOException { if (suspended) { return; } if (s == null) { s = "null"; } cb.append(s); charsWritten += s.length(); } public void setEncoding(String s) { enc = s; } public void checkConverter() throws IOException { if (!gotEnc) { setConverter(); } } protected void setConverter() throws IOException { if (coyoteResponse != null) { enc = coyoteResponse.getCharacterEncoding(); } gotEnc = true; if (enc == null) { enc = DEFAULT_ENCODING; } conv = encoders.get(enc); if (conv == null) { if (Globals.IS_SECURITY_ENABLED){ try{ conv = AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public C2BConverter run() throws IOException{ return new C2BConverter(enc); } } ); }catch(PrivilegedActionException ex){ Exception e = ex.getException(); if (e instanceof IOException) { throw (IOException)e; } } } else { conv = new C2BConverter(enc); } encoders.put(enc, conv); } } // -------------------- BufferedOutputStream compatibility public long getContentWritten() { return bytesWritten + charsWritten; } /** * True if this buffer hasn't been used ( since recycle() ) - * i.e. no chars or bytes have been added to the buffer. */ public boolean isNew() { return (bytesWritten == 0) && (charsWritten == 0); } public void setBufferSize(int size) { if (size > bb.getLimit()) {// ?????? bb.setLimit(size); } } public void reset() { reset(false); } public void reset(boolean resetWriterStreamFlags) { bb.recycle(); cb.recycle(); bytesWritten = 0; charsWritten = 0; if (resetWriterStreamFlags) { gotEnc = false; enc = null; } initial = true; } public int getBufferSize() { return bb.getLimit(); } } tomcat7-7.0.52/java/org/apache/catalina/connector/Response.java0000644000175100017510000014567712271471332024331 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.net.MalformedURLException; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.Locale; import java.util.TimeZone; import java.util.Vector; import javax.servlet.ServletOutputStream; import javax.servlet.SessionTrackingMode; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Session; import org.apache.catalina.Wrapper; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.util.DateTool; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.SessionConfig; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.UEncoder; import org.apache.tomcat.util.http.FastHttpDateFormat; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.ServerCookie; import org.apache.tomcat.util.http.parser.MediaTypeCache; import org.apache.tomcat.util.net.URL; import org.apache.tomcat.util.res.StringManager; /** * Wrapper object for the Coyote response. * * @author Remy Maucherat * @author Craig R. McClanahan */ public class Response implements HttpServletResponse { // ----------------------------------------------------------- Constructors private static final MediaTypeCache MEDIA_TYPE_CACHE = new MediaTypeCache(100); /** * Compliance with SRV.15.2.22.1. A call to Response.getWriter() if no * character encoding has been specified will result in subsequent calls to * Response.getCharacterEncoding() returning ISO-8859-1 and the Content-Type * response header will include a charset=ISO-8859-1 component. */ private static final boolean ENFORCE_ENCODING_IN_GET_WRITER; static { // Ensure that URL is loaded for SM URL.isSchemeChar('c'); ENFORCE_ENCODING_IN_GET_WRITER = Boolean.valueOf( System.getProperty("org.apache.catalina.connector.Response.ENFORCE_ENCODING_IN_GET_WRITER", "true")).booleanValue(); } public Response() { urlEncoder.addSafeCharacter('/'); } // ----------------------------------------------------- Class Variables /** * Descriptive information about this Response implementation. */ protected static final String info = "org.apache.coyote.catalina.CoyoteResponse/1.0"; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ----------------------------------------------------- Instance Variables /** * The date format we will use for creating date headers. */ protected SimpleDateFormat format = null; // ------------------------------------------------------------- Properties /** * Associated Catalina connector. * @deprecated Unused */ @Deprecated protected Connector connector; /** * Return the Connector through which this Request was received. */ @Deprecated public Connector getConnector() { return (this.connector); } /** * Set the Connector through which this Request was received. * * @param connector The new connector */ public void setConnector(Connector connector) { this.connector = connector; if("AJP/1.3".equals(connector.getProtocol())) { // default size to size of one ajp-packet outputBuffer = new OutputBuffer(8184); } else { outputBuffer = new OutputBuffer(); } outputStream = new CoyoteOutputStream(outputBuffer); writer = new CoyoteWriter(outputBuffer); } /** * Coyote response. */ protected org.apache.coyote.Response coyoteResponse; /** * Set the Coyote response. * * @param coyoteResponse The Coyote response */ public void setCoyoteResponse(org.apache.coyote.Response coyoteResponse) { this.coyoteResponse = coyoteResponse; outputBuffer.setResponse(coyoteResponse); } /** * Get the Coyote response. */ public org.apache.coyote.Response getCoyoteResponse() { return (coyoteResponse); } /** * Return the Context within which this Request is being processed. */ public Context getContext() { return (request.getContext()); } /** * Set the Context within which this Request is being processed. This * must be called as soon as the appropriate Context is identified, because * it identifies the value to be returned by getContextPath(), * and thus enables parsing of the request URI. * * @param context The newly associated Context */ @Deprecated public void setContext(Context context) { request.setContext(context); } /** * The associated output buffer. */ protected OutputBuffer outputBuffer; /** * The associated output stream. */ protected CoyoteOutputStream outputStream; /** * The associated writer. */ protected CoyoteWriter writer; /** * The application commit flag. */ protected boolean appCommitted = false; /** * The included flag. */ protected boolean included = false; /** * The characterEncoding flag */ private boolean isCharacterEncodingSet = false; /** * The error flag. */ protected boolean error = false; /** * Using output stream flag. */ protected boolean usingOutputStream = false; /** * Using writer flag. */ protected boolean usingWriter = false; /** * URL encoder. */ protected UEncoder urlEncoder = new UEncoder(); /** * Recyclable buffer to hold the redirect URL. */ protected CharChunk redirectURLCC = new CharChunk(); // --------------------------------------------------------- Public Methods /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { outputBuffer.recycle(); usingOutputStream = false; usingWriter = false; appCommitted = false; included = false; error = false; isCharacterEncodingSet = false; if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) { if (facade != null) { facade.clear(); facade = null; } if (outputStream != null) { outputStream.clear(); outputStream = null; } if (writer != null) { writer.clear(); writer = null; } } else { writer.recycle(); } } /** * Clear cached encoders (to save memory for Comet requests). */ public void clearEncoders() { outputBuffer.clearEncoders(); } // ------------------------------------------------------- Response Methods /** * Return the number of bytes the application has actually written to the * output stream. This excludes chunking, compression, etc. as well as * headers. */ public long getContentWritten() { return outputBuffer.getContentWritten(); } /** * Return the number of bytes the actually written to the socket. This * includes chunking, compression, etc. but excludes headers. */ public long getBytesWritten(boolean flush) { if (flush) { try { outputBuffer.flush(); } catch (IOException ioe) { // Ignore - the client has probably closed the connection } } return coyoteResponse.getBytesWritten(flush); } /** * Set the application commit flag. * * @param appCommitted The new application committed flag value */ public void setAppCommitted(boolean appCommitted) { this.appCommitted = appCommitted; } /** * Application commit flag accessor. */ public boolean isAppCommitted() { return (this.appCommitted || isCommitted() || isSuspended() || ((getContentLength() > 0) && (getContentWritten() >= getContentLength()))); } /** * Return the "processing inside an include" flag. */ @Deprecated public boolean getIncluded() { return included; } /** * Set the "processing inside an include" flag. * * @param included true if we are currently inside a * RequestDispatcher.include(), else false */ @Deprecated public void setIncluded(boolean included) { this.included = included; } /** * Return descriptive information about this Response implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /** * The request with which this response is associated. */ protected Request request = null; /** * Return the Request with which this Response is associated. */ public org.apache.catalina.connector.Request getRequest() { return (this.request); } /** * Set the Request with which this Response is associated. * * @param request The new associated request */ public void setRequest(org.apache.catalina.connector.Request request) { this.request = request; } /** * The facade associated with this response. */ protected ResponseFacade facade = null; /** * Return the ServletResponse for which this object * is the facade. */ public HttpServletResponse getResponse() { if (facade == null) { facade = new ResponseFacade(this); } return (facade); } /** * Return the output stream associated with this Response. */ @Deprecated public OutputStream getStream() { if (outputStream == null) { outputStream = new CoyoteOutputStream(outputBuffer); } return outputStream; } /** * Set the suspended flag. * * @param suspended The new suspended flag value */ public void setSuspended(boolean suspended) { outputBuffer.setSuspended(suspended); } /** * Suspended flag accessor. */ public boolean isSuspended() { return outputBuffer.isSuspended(); } /** * Closed flag accessor. */ public boolean isClosed() { return outputBuffer.isClosed(); } /** * Set the error flag. */ public void setError() { error = true; } /** * Error flag accessor. */ public boolean isError() { return error; } /** * Create and return a ServletOutputStream to write the content * associated with this Response. * * @exception IOException if an input/output error occurs */ @Deprecated public ServletOutputStream createOutputStream() throws IOException { // Probably useless if (outputStream == null) { outputStream = new CoyoteOutputStream(outputBuffer); } return outputStream; } /** * Perform whatever actions are required to flush and close the output * stream or writer, in a single operation. * * @exception IOException if an input/output error occurs */ public void finishResponse() throws IOException { // Writing leftover bytes outputBuffer.close(); } /** * Return the content length that was set or calculated for this Response. */ public int getContentLength() { return (coyoteResponse.getContentLength()); } /** * Return the content type that was set or calculated for this response, * or null if no content type was set. */ @Override public String getContentType() { return (coyoteResponse.getContentType()); } /** * Return a PrintWriter that can be used to render error messages, * regardless of whether a stream or writer has already been acquired. * * @return Writer which can be used for error reports. If the response is * not an error report returned using sendError or triggered by an * unexpected exception thrown during the servlet processing * (and only in that case), null will be returned if the response stream * has already been used. * * @exception IOException if an input/output error occurs */ public PrintWriter getReporter() throws IOException { if (outputBuffer.isNew()) { outputBuffer.checkConverter(); if (writer == null) { writer = new CoyoteWriter(outputBuffer); } return writer; } else { return null; } } // ------------------------------------------------ ServletResponse Methods /** * Flush the buffer and commit this response. * * @exception IOException if an input/output error occurs */ @Override public void flushBuffer() throws IOException { outputBuffer.flush(); } /** * Return the actual buffer size used for this Response. */ @Override public int getBufferSize() { return outputBuffer.getBufferSize(); } /** * Return the character encoding used for this Response. */ @Override public String getCharacterEncoding() { return (coyoteResponse.getCharacterEncoding()); } /** * Return the servlet output stream associated with this Response. * * @exception IllegalStateException if getWriter has * already been called for this response * @exception IOException if an input/output error occurs */ @Override public ServletOutputStream getOutputStream() throws IOException { if (usingWriter) { throw new IllegalStateException (sm.getString("coyoteResponse.getOutputStream.ise")); } usingOutputStream = true; if (outputStream == null) { outputStream = new CoyoteOutputStream(outputBuffer); } return outputStream; } /** * Return the Locale assigned to this response. */ @Override public Locale getLocale() { return (coyoteResponse.getLocale()); } /** * Return the writer associated with this Response. * * @exception IllegalStateException if getOutputStream has * already been called for this response * @exception IOException if an input/output error occurs */ @Override public PrintWriter getWriter() throws IOException { if (usingOutputStream) { throw new IllegalStateException (sm.getString("coyoteResponse.getWriter.ise")); } if (ENFORCE_ENCODING_IN_GET_WRITER) { /* * If the response's character encoding has not been specified as * described in getCharacterEncoding (i.e., the method * just returns the default value ISO-8859-1), * getWriter updates it to ISO-8859-1 * (with the effect that a subsequent call to getContentType() will * include a charset=ISO-8859-1 component which will also be * reflected in the Content-Type response header, thereby satisfying * the Servlet spec requirement that containers must communicate the * character encoding used for the servlet response's writer to the * client). */ setCharacterEncoding(getCharacterEncoding()); } usingWriter = true; outputBuffer.checkConverter(); if (writer == null) { writer = new CoyoteWriter(outputBuffer); } return writer; } /** * Has the output of this response already been committed? */ @Override public boolean isCommitted() { return (coyoteResponse.isCommitted()); } /** * Clear any content written to the buffer. * * @exception IllegalStateException if this response has already * been committed */ @Override public void reset() { if (included) { return; // Ignore any call from an included servlet } coyoteResponse.reset(); outputBuffer.reset(); usingOutputStream = false; usingWriter = false; isCharacterEncodingSet = false; } /** * Reset the data buffer but not any status or header information. * * @exception IllegalStateException if the response has already * been committed */ @Override public void resetBuffer() { resetBuffer(false); } /** * Reset the data buffer and the using Writer/Stream flags but not any * status or header information. * * @param resetWriterStreamFlags true if the internal * usingWriter, usingOutputStream, * isCharacterEncodingSet flags should also be reset * * @exception IllegalStateException if the response has already * been committed */ public void resetBuffer(boolean resetWriterStreamFlags) { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.resetBuffer.ise")); } outputBuffer.reset(resetWriterStreamFlags); if(resetWriterStreamFlags) { usingOutputStream = false; usingWriter = false; isCharacterEncodingSet = false; } } /** * Set the buffer size to be used for this Response. * * @param size The new buffer size * * @exception IllegalStateException if this method is called after * output has been committed for this response */ @Override public void setBufferSize(int size) { if (isCommitted() || !outputBuffer.isNew()) { throw new IllegalStateException (sm.getString("coyoteResponse.setBufferSize.ise")); } outputBuffer.setBufferSize(size); } /** * Set the content length (in bytes) for this Response. * * @param length The new content length */ @Override public void setContentLength(int length) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } coyoteResponse.setContentLength(length); } /** * Set the content type for this Response. * * @param type The new content type */ @Override public void setContentType(String type) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } if (type == null) { coyoteResponse.setContentType(null); return; } String[] m = MEDIA_TYPE_CACHE.parse(type); if (m == null) { // Invalid - Assume no charset and just pass through whatever // the user provided. coyoteResponse.setContentTypeNoCharset(type); return; } coyoteResponse.setContentTypeNoCharset(m[0]); if (m[1] != null) { // Ignore charset if getWriter() has already been called if (!usingWriter) { coyoteResponse.setCharacterEncoding(m[1]); isCharacterEncodingSet = true; } } } /* * Overrides the name of the character encoding used in the body * of the request. This method must be called prior to reading * request parameters or reading input using getReader(). * * @param charset String containing the name of the character encoding. */ @Override public void setCharacterEncoding(String charset) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } // Ignore any call made after the getWriter has been invoked // The default should be used if (usingWriter) { return; } coyoteResponse.setCharacterEncoding(charset); isCharacterEncodingSet = true; } /** * Set the Locale that is appropriate for this response, including * setting the appropriate character encoding. * * @param locale The new locale */ @Override public void setLocale(Locale locale) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } coyoteResponse.setLocale(locale); // Ignore any call made after the getWriter has been invoked. // The default should be used if (usingWriter) { return; } if (isCharacterEncodingSet) { return; } String charset = getContext().getCharset(locale); if (charset != null) { coyoteResponse.setCharacterEncoding(charset); } } // --------------------------------------------------- HttpResponse Methods @Override public String getHeader(String name) { return coyoteResponse.getMimeHeaders().getHeader(name); } @Override public Collection getHeaderNames() { MimeHeaders headers = coyoteResponse.getMimeHeaders(); int n = headers.size(); List result = new ArrayList(n); for (int i = 0; i < n; i++) { result.add(headers.getName(i).toString()); } return result; } @Override public Collection getHeaders(String name) { Enumeration enumeration = coyoteResponse.getMimeHeaders().values(name); Vector result = new Vector(); while (enumeration.hasMoreElements()) { result.addElement(enumeration.nextElement()); } return result; } /** * Return the error message that was set with sendError() * for this Response. */ public String getMessage() { return coyoteResponse.getMessage(); } @Override public int getStatus() { return coyoteResponse.getStatus(); } /** * Reset this response, and specify the values for the HTTP status code * and corresponding message. * * @exception IllegalStateException if this response has already been * committed */ @Deprecated public void reset(int status, String message) { reset(); setStatus(status, message); } // -------------------------------------------- HttpServletResponse Methods /** * Add the specified Cookie to those that will be included with * this Response. * * @param cookie Cookie to be added */ @Override public void addCookie(final Cookie cookie) { // Ignore any call from an included servlet if (included || isCommitted()) { return; } final StringBuffer sb = generateCookieString(cookie); //if we reached here, no exception, cookie is valid // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 ) // RFC2965 is not supported by browsers and the Servlet spec // asks for 2109. addHeader("Set-Cookie", sb.toString()); } /** * Special method for adding a session cookie as we should be overriding * any previous * @param cookie */ public void addSessionCookieInternal(final Cookie cookie) { if (isCommitted()) { return; } String name = cookie.getName(); final String headername = "Set-Cookie"; final String startsWith = name + "="; final StringBuffer sb = generateCookieString(cookie); boolean set = false; MimeHeaders headers = coyoteResponse.getMimeHeaders(); int n = headers.size(); for (int i = 0; i < n; i++) { if (headers.getName(i).toString().equals(headername)) { if (headers.getValue(i).toString().startsWith(startsWith)) { headers.getValue(i).setString(sb.toString()); set = true; } } } if (!set) { addHeader(headername, sb.toString()); } } public StringBuffer generateCookieString(final Cookie cookie) { final StringBuffer sb = new StringBuffer(); //web application code can receive a IllegalArgumentException //from the appendCookieValue invocation if (SecurityUtil.isPackageProtectionEnabled()) { AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run(){ ServerCookie.appendCookieValue (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getDomain(), cookie.getComment(), cookie.getMaxAge(), cookie.getSecure(), cookie.isHttpOnly()); return null; } }); } else { ServerCookie.appendCookieValue (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getDomain(), cookie.getComment(), cookie.getMaxAge(), cookie.getSecure(), cookie.isHttpOnly()); } return sb; } /** * Add the specified date header to the specified value. * * @param name Name of the header to set * @param value Date value to be set */ @Override public void addDateHeader(String name, long value) { if (name == null || name.length() == 0) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } if (format == null) { format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, Locale.US); format.setTimeZone(TimeZone.getTimeZone("GMT")); } addHeader(name, FastHttpDateFormat.formatDate(value, format)); } /** * Add the specified header to the specified value. * * @param name Name of the header to set * @param value Value to be set */ @Override public void addHeader(String name, String value) { if (name == null || name.length() == 0 || value == null) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } char cc=name.charAt(0); if (cc=='C' || cc=='c') { if (checkSpecialHeader(name, value)) return; } coyoteResponse.addHeader(name, value); } /** * An extended version of this exists in {@link org.apache.coyote.Response}. * This check is required here to ensure that the usingWriter checks in * {@link #setContentType(String)} are applied since usingWriter is not * visible to {@link org.apache.coyote.Response} * * Called from set/addHeader. * Return true if the header is special, no need to set the header. */ private boolean checkSpecialHeader(String name, String value) { if (name.equalsIgnoreCase("Content-Type")) { setContentType(value); return true; } return false; } /** * Add the specified integer header to the specified value. * * @param name Name of the header to set * @param value Integer value to be set */ @Override public void addIntHeader(String name, int value) { if (name == null || name.length() == 0) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } addHeader(name, "" + value); } /** * Has the specified header been set already in this response? * * @param name Name of the header to check */ @Override public boolean containsHeader(String name) { // Need special handling for Content-Type and Content-Length due to // special handling of these in coyoteResponse char cc=name.charAt(0); if(cc=='C' || cc=='c') { if(name.equalsIgnoreCase("Content-Type")) { // Will return null if this has not been set return (coyoteResponse.getContentType() != null); } if(name.equalsIgnoreCase("Content-Length")) { // -1 means not known and is not sent to client return (coyoteResponse.getContentLengthLong() != -1); } } return coyoteResponse.containsHeader(name); } /** * Encode the session identifier associated with this response * into the specified redirect URL, if necessary. * * @param url URL to be encoded */ @Override public String encodeRedirectURL(String url) { if (isEncodeable(toAbsolute(url))) { return (toEncoded(url, request.getSessionInternal().getIdInternal())); } else { return (url); } } /** * Encode the session identifier associated with this response * into the specified redirect URL, if necessary. * * @param url URL to be encoded * * @deprecated As of Version 2.1 of the Java Servlet API, use * encodeRedirectURL() instead. */ @Override @Deprecated public String encodeRedirectUrl(String url) { return (encodeRedirectURL(url)); } /** * Encode the session identifier associated with this response * into the specified URL, if necessary. * * @param url URL to be encoded */ @Override public String encodeURL(String url) { String absolute; try { absolute = toAbsolute(url); } catch (IllegalArgumentException iae) { // Relative URL return url; } if (isEncodeable(absolute)) { // W3c spec clearly said if (url.equalsIgnoreCase("")) { url = absolute; } else if (url.equals(absolute) && !hasPath(url)) { url += '/'; } return (toEncoded(url, request.getSessionInternal().getIdInternal())); } else { return (url); } } /** * Encode the session identifier associated with this response * into the specified URL, if necessary. * * @param url URL to be encoded * * @deprecated As of Version 2.1 of the Java Servlet API, use * encodeURL() instead. */ @Override @Deprecated public String encodeUrl(String url) { return (encodeURL(url)); } /** * Send an acknowledgment of a request. * * @exception IOException if an input/output error occurs */ public void sendAcknowledgement() throws IOException { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } coyoteResponse.acknowledge(); } /** * Send an error response with the specified status and a * default message. * * @param status HTTP status code to send * * @exception IllegalStateException if this response has * already been committed * @exception IOException if an input/output error occurs */ @Override public void sendError(int status) throws IOException { sendError(status, null); } /** * Send an error response with the specified status and message. * * @param status HTTP status code to send * @param message Corresponding message to send * * @exception IllegalStateException if this response has * already been committed * @exception IOException if an input/output error occurs */ @Override public void sendError(int status, String message) throws IOException { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.sendError.ise")); } // Ignore any call from an included servlet if (included) { return; } Wrapper wrapper = getRequest().getWrapper(); if (wrapper != null) { wrapper.incrementErrorCount(); } setError(); coyoteResponse.setStatus(status); coyoteResponse.setMessage(message); // Clear any data content that has been buffered resetBuffer(); // Cause the response to be finished (from the application perspective) setSuspended(true); } /** * Send a temporary redirect to the specified redirect location URL. * * @param location Location URL to redirect to * * @exception IllegalStateException if this response has * already been committed * @exception IOException if an input/output error occurs */ @Override public void sendRedirect(String location) throws IOException { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.sendRedirect.ise")); } // Ignore any call from an included servlet if (included) { return; } // Clear any data content that has been buffered resetBuffer(true); // Generate a temporary redirect to the specified location try { String absolute = toAbsolute(location); setStatus(SC_FOUND); setHeader("Location", absolute); if (getContext().getSendRedirectBody()) { PrintWriter writer = getWriter(); writer.print(sm.getString("coyoteResponse.sendRedirect.note", RequestUtil.filter(absolute))); flushBuffer(); } } catch (IllegalArgumentException e) { setStatus(SC_NOT_FOUND); } // Cause the response to be finished (from the application perspective) setSuspended(true); } /** * Set the specified date header to the specified value. * * @param name Name of the header to set * @param value Date value to be set */ @Override public void setDateHeader(String name, long value) { if (name == null || name.length() == 0) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } if (format == null) { format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, Locale.US); format.setTimeZone(TimeZone.getTimeZone("GMT")); } setHeader(name, FastHttpDateFormat.formatDate(value, format)); } /** * Set the specified header to the specified value. * * @param name Name of the header to set * @param value Value to be set */ @Override public void setHeader(String name, String value) { if (name == null || name.length() == 0 || value == null) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } char cc=name.charAt(0); if (cc=='C' || cc=='c') { if (checkSpecialHeader(name, value)) return; } coyoteResponse.setHeader(name, value); } /** * Set the specified integer header to the specified value. * * @param name Name of the header to set * @param value Integer value to be set */ @Override public void setIntHeader(String name, int value) { if (name == null || name.length() == 0) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } setHeader(name, "" + value); } /** * Set the HTTP status to be returned with this response. * * @param status The new HTTP status */ @Override public void setStatus(int status) { setStatus(status, null); } /** * Set the HTTP status and message to be returned with this response. * * @param status The new HTTP status * @param message The associated text message * * @deprecated As of Version 2.1 of the Java Servlet API, this method * has been deprecated due to the ambiguous meaning of the message * parameter. */ @Override @Deprecated public void setStatus(int status, String message) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } coyoteResponse.setStatus(status); coyoteResponse.setMessage(message); } // ------------------------------------------------------ Protected Methods /** * Return true if the specified URL should be encoded with * a session identifier. This will be true if all of the following * conditions are met: *

      *
    • The request we are responding to asked for a valid session *
    • The requested session ID was not received via a cookie *
    • The specified URL points back to somewhere within the web * application that is responding to this request *
    * * @param location Absolute URL to be validated */ protected boolean isEncodeable(final String location) { if (location == null) { return (false); } // Is this an intra-document reference? if (location.startsWith("#")) { return (false); } // Are we in a valid session that is not using cookies? final Request hreq = request; final Session session = hreq.getSessionInternal(false); if (session == null) { return (false); } if (hreq.isRequestedSessionIdFromCookie()) { return (false); } // Is URL encoding permitted if (!hreq.getServletContext().getEffectiveSessionTrackingModes(). contains(SessionTrackingMode.URL)) { return false; } if (SecurityUtil.isPackageProtectionEnabled()) { return ( AccessController.doPrivileged(new PrivilegedAction() { @Override public Boolean run(){ return Boolean.valueOf(doIsEncodeable(hreq, session, location)); } })).booleanValue(); } else { return doIsEncodeable(hreq, session, location); } } private boolean doIsEncodeable(Request hreq, Session session, String location) { // Is this a valid absolute URL? URL url = null; try { url = new URL(location); } catch (MalformedURLException e) { return (false); } // Does this URL match down to (and including) the context path? if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) { return (false); } if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) { return (false); } int serverPort = hreq.getServerPort(); if (serverPort == -1) { if ("https".equals(hreq.getScheme())) { serverPort = 443; } else { serverPort = 80; } } int urlPort = url.getPort(); if (urlPort == -1) { if ("https".equals(url.getProtocol())) { urlPort = 443; } else { urlPort = 80; } } if (serverPort != urlPort) { return (false); } String contextPath = getContext().getPath(); if (contextPath != null) { String file = url.getFile(); if ((file == null) || !file.startsWith(contextPath)) { return (false); } String tok = ";" + SessionConfig.getSessionUriParamName(request.getContext()) + "=" + session.getIdInternal(); if( file.indexOf(tok, contextPath.length()) >= 0 ) { return (false); } } // This URL belongs to our web application, so it is encodeable return (true); } /** * Convert (if necessary) and return the absolute URL that represents the * resource referenced by this possibly relative URL. If this URL is * already absolute, return it unchanged. * * @param location URL to be (possibly) converted and then returned * * @exception IllegalArgumentException if a MalformedURLException is * thrown when converting the relative URL to an absolute one */ protected String toAbsolute(String location) { if (location == null) { return (location); } boolean leadingSlash = location.startsWith("/"); if (location.startsWith("//")) { // Scheme relative redirectURLCC.recycle(); // Add the scheme String scheme = request.getScheme(); try { redirectURLCC.append(scheme, 0, scheme.length()); redirectURLCC.append(':'); redirectURLCC.append(location, 0, location.length()); return redirectURLCC.toString(); } catch (IOException e) { IllegalArgumentException iae = new IllegalArgumentException(location); iae.initCause(e); throw iae; } } else if (leadingSlash || !hasScheme(location)) { redirectURLCC.recycle(); String scheme = request.getScheme(); String name = request.getServerName(); int port = request.getServerPort(); try { redirectURLCC.append(scheme, 0, scheme.length()); redirectURLCC.append("://", 0, 3); redirectURLCC.append(name, 0, name.length()); if ((scheme.equals("http") && port != 80) || (scheme.equals("https") && port != 443)) { redirectURLCC.append(':'); String portS = port + ""; redirectURLCC.append(portS, 0, portS.length()); } if (!leadingSlash) { String relativePath = request.getDecodedRequestURI(); int pos = relativePath.lastIndexOf('/'); CharChunk encodedURI = null; final String frelativePath = relativePath; final int fend = pos; if (SecurityUtil.isPackageProtectionEnabled() ){ try{ encodedURI = AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public CharChunk run() throws IOException{ return urlEncoder.encodeURL(frelativePath, 0, fend); } }); } catch (PrivilegedActionException pae){ IllegalArgumentException iae = new IllegalArgumentException(location); iae.initCause(pae.getException()); throw iae; } } else { encodedURI = urlEncoder.encodeURL(relativePath, 0, pos); } redirectURLCC.append(encodedURI); encodedURI.recycle(); redirectURLCC.append('/'); } redirectURLCC.append(location, 0, location.length()); normalize(redirectURLCC); } catch (IOException e) { IllegalArgumentException iae = new IllegalArgumentException(location); iae.initCause(e); throw iae; } return redirectURLCC.toString(); } else { return (location); } } /* * Removes /./ and /../ sequences from absolute URLs. * Code borrowed heavily from CoyoteAdapter.normalize() */ private void normalize(CharChunk cc) { // Strip query string and/or fragment first as doing it this way makes // the normalization logic a lot simpler int truncate = cc.indexOf('?'); if (truncate == -1) { truncate = cc.indexOf('#'); } char[] truncateCC = null; if (truncate > -1) { truncateCC = Arrays.copyOfRange(cc.getBuffer(), cc.getStart() + truncate, cc.getEnd()); cc.setEnd(cc.getStart() + truncate); } if (cc.endsWith("/.") || cc.endsWith("/..")) { try { cc.append('/'); } catch (IOException e) { throw new IllegalArgumentException(cc.toString(), e); } } char[] c = cc.getChars(); int start = cc.getStart(); int end = cc.getEnd(); int index = 0; int startIndex = 0; // Advance past the first three / characters (should place index just // scheme://host[:port] for (int i = 0; i < 3; i++) { startIndex = cc.indexOf('/', startIndex + 1); } // Remove /./ index = startIndex; while (true) { index = cc.indexOf("/./", 0, 3, index); if (index < 0) { break; } copyChars(c, start + index, start + index + 2, end - start - index - 2); end = end - 2; cc.setEnd(end); } // Remove /../ index = startIndex; int pos; while (true) { index = cc.indexOf("/../", 0, 4, index); if (index < 0) { break; } // Can't go above the server root if (index == startIndex) { throw new IllegalArgumentException(); } int index2 = -1; for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) { if (c[pos] == (byte) '/') { index2 = pos; } } copyChars(c, start + index2, start + index + 3, end - start - index - 3); end = end + index2 - index - 3; cc.setEnd(end); index = index2; } // Add the query string and/or fragment (if present) back in if (truncateCC != null) { try { cc.append(truncateCC, 0, truncateCC.length); } catch (IOException ioe) { throw new IllegalArgumentException(ioe); } } } private void copyChars(char[] c, int dest, int src, int len) { for (int pos = 0; pos < len; pos++) { c[pos + dest] = c[pos + src]; } } /** * Determine if an absolute URL has a path component */ private boolean hasPath(String uri) { int pos = uri.indexOf("://"); if (pos < 0) { return false; } pos = uri.indexOf('/', pos + 3); if (pos < 0) { return false; } return true; } /** * Determine if a URI string has a scheme component. */ private boolean hasScheme(String uri) { int len = uri.length(); for(int i=0; i < len ; i++) { char c = uri.charAt(i); if(c == ':') { return i > 0; } else if(!URL.isSchemeChar(c)) { return false; } } return false; } /** * Return the specified URL with the specified session identifier * suitably encoded. * * @param url URL to be encoded with the session id * @param sessionId Session id to be included in the encoded URL */ protected String toEncoded(String url, String sessionId) { if ((url == null) || (sessionId == null)) { return (url); } String path = url; String query = ""; String anchor = ""; int question = url.indexOf('?'); if (question >= 0) { path = url.substring(0, question); query = url.substring(question); } int pound = path.indexOf('#'); if (pound >= 0) { anchor = path.substring(pound); path = path.substring(0, pound); } StringBuilder sb = new StringBuilder(path); if( sb.length() > 0 ) { // jsessionid can't be first. sb.append(";"); sb.append(SessionConfig.getSessionUriParamName( request.getContext())); sb.append("="); sb.append(sessionId); } sb.append(anchor); sb.append(query); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/connector/CoyoteOutputStream.java0000644000175100017510000000471412271471332026354 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import javax.servlet.ServletOutputStream; /** * Coyote implementation of the servlet output stream. * * @author Costin Manolache * @author Remy Maucherat */ public class CoyoteOutputStream extends ServletOutputStream { // ----------------------------------------------------- Instance Variables protected OutputBuffer ob; // ----------------------------------------------------------- Constructors protected CoyoteOutputStream(OutputBuffer ob) { this.ob = ob; } // --------------------------------------------------------- Public Methods /** * Prevent cloning the facade. */ @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // -------------------------------------------------------- Package Methods /** * Clear facade. */ void clear() { ob = null; } // --------------------------------------------------- OutputStream Methods @Override public void write(int i) throws IOException { ob.writeByte(i); } @Override public void write(byte[] b) throws IOException { write(b, 0, b.length); } @Override public void write(byte[] b, int off, int len) throws IOException { ob.write(b, off, len); } /** * Will send the buffer to the client. */ @Override public void flush() throws IOException { ob.flush(); } @Override public void close() throws IOException { ob.close(); } } tomcat7-7.0.52/java/org/apache/catalina/connector/ClientAbortException.java0000644000175100017510000000664612271471332026610 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; /** * Wrap an IOException identifying it as being caused by an abort * of a request by a remote client. * * @author Glenn L. Nielsen */ public final class ClientAbortException extends IOException { private static final long serialVersionUID = 1L; //------------------------------------------------------------ Constructors /** * Construct a new ClientAbortException with no other information. */ public ClientAbortException() { this(null, null); } /** * Construct a new ClientAbortException for the specified message. * * @param message Message describing this exception */ public ClientAbortException(String message) { this(message, null); } /** * Construct a new ClientAbortException for the specified throwable. * * @param throwable Throwable that caused this exception */ public ClientAbortException(Throwable throwable) { this(null, throwable); } /** * Construct a new ClientAbortException for the specified message * and throwable. * * @param message Message describing this exception * @param throwable Throwable that caused this exception */ public ClientAbortException(String message, Throwable throwable) { super(); this.message = message; this.throwable = throwable; } //------------------------------------------------------ Instance Variables /** * The error message passed to our constructor (if any) */ protected String message = null; /** * The underlying exception or error passed to our constructor (if any) */ protected Throwable throwable = null; //---------------------------------------------------------- Public Methods /** * Returns the message associated with this exception, if any. */ @Override public String getMessage() { return (message); } /** * Returns the cause that caused this exception, if any. */ @Override public Throwable getCause() { return (throwable); } /** * Return a formatted string that describes this exception. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ClientAbortException: "); if (message != null) { sb.append(message); if (throwable != null) { sb.append(": "); } } if (throwable != null) { sb.append(throwable.toString()); } return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/connector/CoyoteWriter.java0000644000175100017510000001302312271471332025145 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import java.io.PrintWriter; /** * Coyote implementation of the servlet writer. * * @author Remy Maucherat */ public class CoyoteWriter extends PrintWriter { // -------------------------------------------------------------- Constants // No need for a do privileged block - every web app has permission to read // this by default private static final char[] LINE_SEP = System.getProperty("line.separator").toCharArray(); // ----------------------------------------------------- Instance Variables protected OutputBuffer ob; protected boolean error = false; // ----------------------------------------------------------- Constructors public CoyoteWriter(OutputBuffer ob) { super(ob); this.ob = ob; } // --------------------------------------------------------- Public Methods /** * Prevent cloning the facade. */ @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // -------------------------------------------------------- Package Methods /** * Clear facade. */ void clear() { ob = null; } /** * Recycle. */ void recycle() { error = false; } // --------------------------------------------------------- Writer Methods @Override public void flush() { if (error) { return; } try { ob.flush(); } catch (IOException e) { error = true; } } @Override public void close() { // We don't close the PrintWriter - super() is not called, // so the stream can be reused. We close ob. try { ob.close(); } catch (IOException ex ) { // Ignore } error = false; } @Override public boolean checkError() { flush(); return error; } @Override public void write(int c) { if (error) { return; } try { ob.write(c); } catch (IOException e) { error = true; } } @Override public void write(char buf[], int off, int len) { if (error) { return; } try { ob.write(buf, off, len); } catch (IOException e) { error = true; } } @Override public void write(char buf[]) { write(buf, 0, buf.length); } @Override public void write(String s, int off, int len) { if (error) { return; } try { ob.write(s, off, len); } catch (IOException e) { error = true; } } @Override public void write(String s) { write(s, 0, s.length()); } // ---------------------------------------------------- PrintWriter Methods @Override public void print(boolean b) { if (b) { write("true"); } else { write("false"); } } @Override public void print(char c) { write(c); } @Override public void print(int i) { write(String.valueOf(i)); } @Override public void print(long l) { write(String.valueOf(l)); } @Override public void print(float f) { write(String.valueOf(f)); } @Override public void print(double d) { write(String.valueOf(d)); } @Override public void print(char s[]) { write(s); } @Override public void print(String s) { if (s == null) { s = "null"; } write(s); } @Override public void print(Object obj) { write(String.valueOf(obj)); } @Override public void println() { write(LINE_SEP); } @Override public void println(boolean b) { print(b); println(); } @Override public void println(char c) { print(c); println(); } @Override public void println(int i) { print(i); println(); } @Override public void println(long l) { print(l); println(); } @Override public void println(float f) { print(f); println(); } @Override public void println(double d) { print(d); println(); } @Override public void println(char c[]) { print(c); println(); } @Override public void println(String s) { print(s); println(); } @Override public void println(Object o) { print(o); println(); } } tomcat7-7.0.52/java/org/apache/catalina/connector/CometEventImpl.java0000644000175100017510000000755712271471332025420 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.comet.CometEvent; import org.apache.tomcat.util.res.StringManager; public class CometEventImpl implements CometEvent { /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); public CometEventImpl(Request request, Response response) { this.request = request; this.response = response; } // ----------------------------------------------------- Instance Variables /** * Associated request. */ protected Request request = null; /** * Associated response. */ protected Response response = null; /** * Event type. */ protected EventType eventType = EventType.BEGIN; /** * Event sub type. */ protected EventSubType eventSubType = null; // --------------------------------------------------------- Public Methods /** * Clear the event. */ public void clear() { request = null; response = null; } public void setEventType(EventType eventType) { this.eventType = eventType; } public void setEventSubType(EventSubType eventSubType) { this.eventSubType = eventSubType; } @Override public void close() throws IOException { if (request == null) { throw new IllegalStateException(sm.getString("cometEvent.nullRequest")); } request.finishRequest(); response.finishResponse(); if (request.isComet()) { request.cometClose(); } } @Override public EventSubType getEventSubType() { return eventSubType; } @Override public EventType getEventType() { return eventType; } @Override public HttpServletRequest getHttpServletRequest() { return request.getRequest(); } @Override public HttpServletResponse getHttpServletResponse() { return response.getResponse(); } @Override public void setTimeout(int timeout) throws IOException, ServletException, UnsupportedOperationException { if (request.getAttribute(Globals.COMET_TIMEOUT_SUPPORTED_ATTR) == Boolean.TRUE) { request.setAttribute(Globals.COMET_TIMEOUT_ATTR, Integer.valueOf(timeout)); if (request.isComet()) { request.setCometTimeout(timeout); } } else { throw new UnsupportedOperationException(); } } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append(super.toString()); buf.append("[EventType:"); buf.append(eventType); buf.append(", EventSubType:"); buf.append(eventSubType); buf.append("]"); return buf.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/connector/MapperListener.java0000644000175100017510000004063612271471332025452 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import org.apache.catalina.Container; import org.apache.catalina.ContainerEvent; import org.apache.catalina.ContainerListener; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.LifecycleState; import org.apache.catalina.Wrapper; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.http.mapper.Mapper; import org.apache.tomcat.util.res.StringManager; /** * Mapper listener. * * @author Remy Maucherat * @author Costin Manolache */ public class MapperListener extends LifecycleMBeanBase implements ContainerListener, LifecycleListener { private static final Log log = LogFactory.getLog(MapperListener.class); // ----------------------------------------------------- Instance Variables /** * Associated mapper. */ private Mapper mapper = null; /** * Associated connector */ private Connector connector = null; /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The domain (effectively the engine) this mapper is associated with */ private final String domain = null; // ----------------------------------------------------------- Constructors /** * Create mapper listener. */ public MapperListener(Mapper mapper, Connector connector) { this.mapper = mapper; this.connector = connector; } // --------------------------------------------------------- Public Methods @Deprecated public String getConnectorName() { return this.connector.toString(); } // ------------------------------------------------------- Lifecycle Methods @Override public void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); // Find any components that have already been initialized since the // MBean listener won't be notified as those components will have // already registered their MBeans findDefaultHost(); Engine engine = (Engine) connector.getService().getContainer(); addListeners(engine); Container[] conHosts = engine.findChildren(); for (Container conHost : conHosts) { Host host = (Host) conHost; if (!LifecycleState.NEW.equals(host.getState())) { // Registering the host will register the context and wrappers registerHost(host); } } } @Override public void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); } @Override protected String getDomainInternal() { // Should be the same as the connector return connector.getDomainInternal(); } @Override protected String getObjectNameKeyProperties() { // Same as connector but Mapper rather than Connector return connector.createObjectNameKeyProperties("Mapper"); } // --------------------------------------------- Container Listener methods @Override public void containerEvent(ContainerEvent event) { if (Container.ADD_CHILD_EVENT.equals(event.getType())) { Container child = (Container) event.getData(); addListeners(child); // If child is started then it is too late for life-cycle listener // to register the child so register it here if (child.getState().isAvailable()) { if (child instanceof Host) { registerHost((Host) child); } else if (child instanceof Context) { registerContext((Context) child); } else if (child instanceof Wrapper) { registerWrapper((Wrapper) child); } } } else if (Container.REMOVE_CHILD_EVENT.equals(event.getType())) { Container child = (Container) event.getData(); removeListeners(child); // No need to unregister - life-cycle listener will handle this when // the child stops } else if (Host.ADD_ALIAS_EVENT.equals(event.getType())) { // Handle dynamically adding host aliases mapper.addHostAlias(((Host) event.getSource()).getName(), event.getData().toString()); } else if (Host.REMOVE_ALIAS_EVENT.equals(event.getType())) { // Handle dynamically removing host aliases mapper.removeHostAlias(event.getData().toString()); } else if (Wrapper.ADD_MAPPING_EVENT.equals(event.getType())) { // Handle dynamically adding wrappers Wrapper wrapper = (Wrapper) event.getSource(); Context context = (Context) wrapper.getParent(); String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } String version = ((Context) wrapper.getParent()).getWebappVersion(); String hostName = context.getParent().getName(); String wrapperName = wrapper.getName(); String mapping = (String) event.getData(); boolean jspWildCard = ("jsp".equals(wrapperName) && mapping.endsWith("/*")); mapper.addWrapper(hostName, contextPath, version, mapping, wrapper, jspWildCard, context.isResourceOnlyServlet(wrapperName)); } else if (Wrapper.REMOVE_MAPPING_EVENT.equals(event.getType())) { // Handle dynamically removing wrappers Wrapper wrapper = (Wrapper) event.getSource(); String contextPath = ((Context) wrapper.getParent()).getPath(); if ("/".equals(contextPath)) { contextPath = ""; } String version = ((Context) wrapper.getParent()).getWebappVersion(); String hostName = wrapper.getParent().getParent().getName(); String mapping = (String) event.getData(); mapper.removeWrapper(hostName, contextPath, version, mapping); } else if (Context.ADD_WELCOME_FILE_EVENT.equals(event.getType())) { // Handle dynamically adding welcome files Context context = (Context) event.getSource(); String hostName = context.getParent().getName(); String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } String welcomeFile = (String) event.getData(); mapper.addWelcomeFile(hostName, contextPath, context.getWebappVersion(), welcomeFile); } else if (Context.REMOVE_WELCOME_FILE_EVENT.equals(event.getType())) { // Handle dynamically removing welcome files Context context = (Context) event.getSource(); String hostName = context.getParent().getName(); String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } String welcomeFile = (String) event.getData(); mapper.removeWelcomeFile(hostName, contextPath, context.getWebappVersion(), welcomeFile); } else if (Context.CLEAR_WELCOME_FILES_EVENT.equals(event.getType())) { // Handle dynamically clearing welcome files Context context = (Context) event.getSource(); String hostName = context.getParent().getName(); String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } mapper.clearWelcomeFiles(hostName, contextPath, context.getWebappVersion()); } } // ------------------------------------------------------ Protected Methods private void findDefaultHost() { Engine engine = (Engine) connector.getService().getContainer(); String defaultHost = engine.getDefaultHost(); boolean found = false; if (defaultHost != null && defaultHost.length() >0) { Container[] containers = engine.findChildren(); for (Container container : containers) { Host host = (Host) container; if (defaultHost.equalsIgnoreCase(host.getName())) { found = true; break; } String[] aliases = host.findAliases(); for (String alias : aliases) { if (defaultHost.equalsIgnoreCase(alias)) { found = true; break; } } } } if(found) { mapper.setDefaultHostName(defaultHost); } else { log.warn(sm.getString("mapperListener.unknownDefaultHost", defaultHost, connector)); } } /** * Register host. */ private void registerHost(Host host) { String[] aliases = host.findAliases(); mapper.addHost(host.getName(), aliases, host); for (Container container : host.findChildren()) { if (container.getState().isAvailable()) { registerContext((Context) container); } } if(log.isDebugEnabled()) { log.debug(sm.getString("mapperListener.registerHost", host.getName(), domain, connector)); } } /** * Unregister host. */ private void unregisterHost(Host host) { String hostname = host.getName(); mapper.removeHost(hostname); if(log.isDebugEnabled()) { log.debug(sm.getString("mapperListener.unregisterHost", hostname, domain, connector)); } } /** * Unregister wrapper. */ private void unregisterWrapper(Wrapper wrapper) { String contextPath = ((Context) wrapper.getParent()).getPath(); String wrapperName = wrapper.getName(); if ("/".equals(contextPath)) { contextPath = ""; } String version = ((Context) wrapper.getParent()).getWebappVersion(); String hostName = wrapper.getParent().getParent().getName(); String[] mappings = wrapper.findMappings(); for (String mapping : mappings) { mapper.removeWrapper(hostName, contextPath, version, mapping); } if(log.isDebugEnabled()) { log.debug(sm.getString("mapperListener.unregisterWrapper", wrapperName, contextPath, connector)); } } /** * Register context. */ private void registerContext(Context context) { String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } Container host = context.getParent(); javax.naming.Context resources = context.getResources(); String[] welcomeFiles = context.findWelcomeFiles(); mapper.addContextVersion(host.getName(), host, contextPath, context.getWebappVersion(), context, welcomeFiles, resources); for (Container container : context.findChildren()) { registerWrapper((Wrapper) container); } if(log.isDebugEnabled()) { log.debug(sm.getString("mapperListener.registerContext", contextPath, connector)); } } /** * Unregister context. */ private void unregisterContext(Context context) { // Don't un-map a context that is paused if (context.getPaused()){ return; } String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } String hostName = context.getParent().getName(); if(log.isDebugEnabled()) { log.debug(sm.getString("mapperListener.unregisterContext", contextPath, connector)); } mapper.removeContextVersion(hostName, contextPath, context.getWebappVersion()); } /** * Register wrapper. */ private void registerWrapper(Wrapper wrapper) { String wrapperName = wrapper.getName(); Context context = (Context) wrapper.getParent(); String contextPath = context.getPath(); if ("/".equals(contextPath)) { contextPath = ""; } String version = ((Context) wrapper.getParent()).getWebappVersion(); String hostName = context.getParent().getName(); String[] mappings = wrapper.findMappings(); for (String mapping : mappings) { boolean jspWildCard = (wrapperName.equals("jsp") && mapping.endsWith("/*")); mapper.addWrapper(hostName, contextPath, version, mapping, wrapper, jspWildCard, context.isResourceOnlyServlet(wrapperName)); } if(log.isDebugEnabled()) { log.debug(sm.getString("mapperListener.registerWrapper", wrapperName, contextPath, connector)); } } @Override public void lifecycleEvent(LifecycleEvent event) { if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) { Object obj = event.getSource(); if (obj instanceof Wrapper) { Wrapper w = (Wrapper) obj; // Only if the Context has started. If it has not, then it will // have its own "after_start" event later. if (w.getParent().getState().isAvailable()) { registerWrapper(w); } } else if (obj instanceof Context) { Context c = (Context) obj; // Only if the Host has started. If it has not, then it will // have its own "after_start" event later. if (c.getParent().getState().isAvailable()) { registerContext(c); } } else if (obj instanceof Host) { registerHost((Host) obj); } } else if (event.getType().equals(Lifecycle.BEFORE_STOP_EVENT)) { Object obj = event.getSource(); if (obj instanceof Wrapper) { unregisterWrapper((Wrapper) obj); } else if (obj instanceof Context) { Context c = (Context) obj; // Only unregister if not paused. If paused, need to keep // registration in place to prevent 404's during reload if (!c.getPaused()) { unregisterContext(c); } } else if (obj instanceof Host) { unregisterHost((Host) obj); } } } /** * Add this mapper to the container and all child containers * * @param container */ private void addListeners(Container container) { container.addContainerListener(this); container.addLifecycleListener(this); for (Container child : container.findChildren()) { addListeners(child); } } /** * Remove this mapper from the container and all child containers * * @param container */ private void removeListeners(Container container) { container.removeContainerListener(this); container.removeLifecycleListener(this); for (Container child : container.findChildren()) { removeListeners(child); } } } tomcat7-7.0.52/java/org/apache/catalina/connector/CoyoteInputStream.java0000644000175100017510000001631112271471332026147 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import javax.servlet.ServletInputStream; import org.apache.catalina.security.SecurityUtil; /** * This class handles reading bytes. * * @author Remy Maucherat * @author Jean-Francois Arcand */ public class CoyoteInputStream extends ServletInputStream { // ----------------------------------------------------- Instance Variables protected InputBuffer ib; // ----------------------------------------------------------- Constructors protected CoyoteInputStream(InputBuffer ib) { this.ib = ib; } // -------------------------------------------------------- Package Methods /** * Clear facade. */ void clear() { ib = null; } // --------------------------------------------------------- Public Methods /** * Prevent cloning the facade. */ @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // --------------------------------------------- ServletInputStream Methods @Override public int read() throws IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ Integer result = AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public Integer run() throws IOException{ Integer integer = Integer.valueOf(ib.readByte()); return integer; } }); return result.intValue(); } catch(PrivilegedActionException pae){ Exception e = pae.getException(); if (e instanceof IOException){ throw (IOException)e; } else { throw new RuntimeException(e.getMessage(), e); } } } else { return ib.readByte(); } } @Override public int available() throws IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ Integer result = AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public Integer run() throws IOException{ Integer integer = Integer.valueOf(ib.available()); return integer; } }); return result.intValue(); } catch(PrivilegedActionException pae){ Exception e = pae.getException(); if (e instanceof IOException){ throw (IOException)e; } else { throw new RuntimeException(e.getMessage(), e); } } } else { return ib.available(); } } @Override public int read(final byte[] b) throws IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ Integer result = AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public Integer run() throws IOException{ Integer integer = Integer.valueOf(ib.read(b, 0, b.length)); return integer; } }); return result.intValue(); } catch(PrivilegedActionException pae){ Exception e = pae.getException(); if (e instanceof IOException){ throw (IOException)e; } else { throw new RuntimeException(e.getMessage() ,e); } } } else { return ib.read(b, 0, b.length); } } @Override public int read(final byte[] b, final int off, final int len) throws IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ Integer result = AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public Integer run() throws IOException{ Integer integer = Integer.valueOf(ib.read(b, off, len)); return integer; } }); return result.intValue(); } catch(PrivilegedActionException pae){ Exception e = pae.getException(); if (e instanceof IOException){ throw (IOException)e; } else { throw new RuntimeException(e.getMessage(), e); } } } else { return ib.read(b, off, len); } } @Override public int readLine(byte[] b, int off, int len) throws IOException { return super.readLine(b, off, len); } /** * Close the stream * Since we re-cycle, we can't allow the call to super.close() * which would permanently disable us. */ @Override public void close() throws IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public Void run() throws IOException{ ib.close(); return null; } }); } catch(PrivilegedActionException pae){ Exception e = pae.getException(); if (e instanceof IOException){ throw (IOException)e; } else { throw new RuntimeException(e.getMessage(), e); } } } else { ib.close(); } } } tomcat7-7.0.52/java/org/apache/catalina/connector/CoyoteReader.java0000644000175100017510000001214212271471332025074 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.BufferedReader; import java.io.IOException; /** * Coyote implementation of the buffered reader. * * @author Remy Maucherat */ public class CoyoteReader extends BufferedReader { // -------------------------------------------------------------- Constants private static final char[] LINE_SEP = { '\r', '\n' }; private static final int MAX_LINE_LENGTH = 4096; // ----------------------------------------------------- Instance Variables protected InputBuffer ib; protected char[] lineBuffer = null; // ----------------------------------------------------------- Constructors public CoyoteReader(InputBuffer ib) { super(ib, 1); this.ib = ib; } // --------------------------------------------------------- Public Methods /** * Prevent cloning the facade. */ @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // -------------------------------------------------------- Package Methods /** * Clear facade. */ void clear() { ib = null; } // --------------------------------------------------------- Reader Methods @Override public void close() throws IOException { ib.close(); } @Override public int read() throws IOException { return ib.read(); } @Override public int read(char[] cbuf) throws IOException { return ib.read(cbuf, 0, cbuf.length); } @Override public int read(char[] cbuf, int off, int len) throws IOException { return ib.read(cbuf, off, len); } @Override public long skip(long n) throws IOException { return ib.skip(n); } @Override public boolean ready() throws IOException { return ib.ready(); } @Override public boolean markSupported() { return true; } @Override public void mark(int readAheadLimit) throws IOException { ib.mark(readAheadLimit); } @Override public void reset() throws IOException { ib.reset(); } @Override public String readLine() throws IOException { if (lineBuffer == null) { lineBuffer = new char[MAX_LINE_LENGTH]; } String result = null; int pos = 0; int end = -1; int skip = -1; StringBuilder aggregator = null; while (end < 0) { mark(MAX_LINE_LENGTH); while ((pos < MAX_LINE_LENGTH) && (end < 0)) { int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos); if (nRead < 0) { if (pos == 0 && aggregator == null) { return null; } end = pos; skip = pos; } for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) { if (lineBuffer[i] == LINE_SEP[0]) { end = i; skip = i + 1; char nextchar; if (i == (pos + nRead - 1)) { nextchar = (char) read(); } else { nextchar = lineBuffer[i+1]; } if (nextchar == LINE_SEP[1]) { skip++; } } else if (lineBuffer[i] == LINE_SEP[1]) { end = i; skip = i + 1; } } if (nRead > 0) { pos += nRead; } } if (end < 0) { if (aggregator == null) { aggregator = new StringBuilder(); } aggregator.append(lineBuffer); pos = 0; } else { reset(); skip(skip); } } if (aggregator == null) { result = new String(lineBuffer, 0, end); } else { aggregator.append(lineBuffer, 0, end); result = aggregator.toString(); } return result; } } tomcat7-7.0.52/java/org/apache/catalina/connector/ResponseFacade.java0000644000175100017510000003364512271471332025404 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.IOException; import java.io.PrintWriter; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Collection; import java.util.Locale; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.security.SecurityUtil; import org.apache.tomcat.util.res.StringManager; /** * Facade class that wraps a Coyote response object. * All methods are delegated to the wrapped response. * * @author Remy Maucherat * @author Jean-Francois Arcand */ @SuppressWarnings("deprecation") public class ResponseFacade implements HttpServletResponse { // ----------------------------------------------------------- DoPrivileged private final class SetContentTypePrivilegedAction implements PrivilegedAction { private final String contentType; public SetContentTypePrivilegedAction(String contentType){ this.contentType = contentType; } @Override public Void run() { response.setContentType(contentType); return null; } } private final class DateHeaderPrivilegedAction implements PrivilegedAction { private final String name; private final long value; private final boolean add; DateHeaderPrivilegedAction(String name, long value, boolean add) { this.name = name; this.value = value; this.add = add; } @Override public Void run() { if(add) { response.addDateHeader(name, value); } else { response.setDateHeader(name, value); } return null; } } // ----------------------------------------------------------- Constructors /** * Construct a wrapper for the specified response. * * @param response The response to be wrapped */ public ResponseFacade(Response response) { this.response = response; } // ----------------------------------------------- Class/Instance Variables /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The wrapped response. */ protected Response response = null; // --------------------------------------------------------- Public Methods /** * Clear facade. */ public void clear() { response = null; } /** * Prevent cloning the facade. */ @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } public void finish() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } response.setSuspended(true); } public boolean isFinished() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.isSuspended(); } public long getContentWritten() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.getContentWritten(); } // ------------------------------------------------ ServletResponse Methods @Override public String getCharacterEncoding() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.getCharacterEncoding(); } @Override public ServletOutputStream getOutputStream() throws IOException { // if (isFinished()) // throw new IllegalStateException // (/*sm.getString("responseFacade.finished")*/); ServletOutputStream sos = response.getOutputStream(); if (isFinished()) { response.setSuspended(true); } return (sos); } @Override public PrintWriter getWriter() throws IOException { // if (isFinished()) // throw new IllegalStateException // (/*sm.getString("responseFacade.finished")*/); PrintWriter writer = response.getWriter(); if (isFinished()) { response.setSuspended(true); } return (writer); } @Override public void setContentLength(int len) { if (isCommitted()) { return; } response.setContentLength(len); } @Override public void setContentType(String type) { if (isCommitted()) { return; } if (SecurityUtil.isPackageProtectionEnabled()){ AccessController.doPrivileged(new SetContentTypePrivilegedAction(type)); } else { response.setContentType(type); } } @Override public void setBufferSize(int size) { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.setBufferSize.ise")); } response.setBufferSize(size); } @Override public int getBufferSize() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.getBufferSize(); } @Override public void flushBuffer() throws IOException { if (isFinished()) { // throw new IllegalStateException // (/*sm.getString("responseFacade.finished")*/); return; } if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged( new PrivilegedExceptionAction(){ @Override public Void run() throws IOException{ response.setAppCommitted(true); response.flushBuffer(); return null; } }); } catch(PrivilegedActionException e){ Exception ex = e.getException(); if (ex instanceof IOException){ throw (IOException)ex; } } } else { response.setAppCommitted(true); response.flushBuffer(); } } @Override public void resetBuffer() { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.resetBuffer.ise")); } response.resetBuffer(); } @Override public boolean isCommitted() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return (response.isAppCommitted()); } @Override public void reset() { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.reset.ise")); } response.reset(); } @Override public void setLocale(Locale loc) { if (isCommitted()) { return; } response.setLocale(loc); } @Override public Locale getLocale() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.getLocale(); } @Override public void addCookie(Cookie cookie) { if (isCommitted()) { return; } response.addCookie(cookie); } @Override public boolean containsHeader(String name) { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.containsHeader(name); } @Override public String encodeURL(String url) { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.encodeURL(url); } @Override public String encodeRedirectURL(String url) { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.encodeRedirectURL(url); } @Override public String encodeUrl(String url) { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.encodeURL(url); } @Override public String encodeRedirectUrl(String url) { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.encodeRedirectURL(url); } @Override public void sendError(int sc, String msg) throws IOException { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.sendError.ise")); } response.setAppCommitted(true); response.sendError(sc, msg); } @Override public void sendError(int sc) throws IOException { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.sendError.ise")); } response.setAppCommitted(true); response.sendError(sc); } @Override public void sendRedirect(String location) throws IOException { if (isCommitted()) { throw new IllegalStateException (sm.getString("coyoteResponse.sendRedirect.ise")); } response.setAppCommitted(true); response.sendRedirect(location); } @Override public void setDateHeader(String name, long date) { if (isCommitted()) { return; } if(Globals.IS_SECURITY_ENABLED) { AccessController.doPrivileged(new DateHeaderPrivilegedAction (name, date, false)); } else { response.setDateHeader(name, date); } } @Override public void addDateHeader(String name, long date) { if (isCommitted()) { return; } if(Globals.IS_SECURITY_ENABLED) { AccessController.doPrivileged(new DateHeaderPrivilegedAction (name, date, true)); } else { response.addDateHeader(name, date); } } @Override public void setHeader(String name, String value) { if (isCommitted()) { return; } response.setHeader(name, value); } @Override public void addHeader(String name, String value) { if (isCommitted()) { return; } response.addHeader(name, value); } @Override public void setIntHeader(String name, int value) { if (isCommitted()) { return; } response.setIntHeader(name, value); } @Override public void addIntHeader(String name, int value) { if (isCommitted()) { return; } response.addIntHeader(name, value); } @Override public void setStatus(int sc) { if (isCommitted()) { return; } response.setStatus(sc); } @Override public void setStatus(int sc, String sm) { if (isCommitted()) { return; } response.setStatus(sc, sm); } @Override public String getContentType() { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } return response.getContentType(); } @Override public void setCharacterEncoding(String arg0) { if (response == null) { throw new IllegalStateException( sm.getString("responseFacade.nullResponse")); } response.setCharacterEncoding(arg0); } @Override public int getStatus() { return response.getStatus(); } @Override public String getHeader(String name) { return response.getHeader(name); } @Override public Collection getHeaderNames() { return response.getHeaderNames(); } @Override public Collection getHeaders(String name) { return response.getHeaders(name); } } tomcat7-7.0.52/java/org/apache/catalina/connector/mbeans-descriptors.xml0000644000175100017510000002056112271471332026176 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/connector/Constants.java0000644000175100017510000000174612271471332024473 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; /** * Static constants for this package. */ public final class Constants { public static final String Package = "org.apache.catalina.connector"; } tomcat7-7.0.52/java/org/apache/catalina/connector/LocalStrings.properties0000644000175100017510000001464512271471332026400 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # CoyoteConnector # coyoteConnector.cannotRegisterProtocol=Cannot register MBean for the Protocol coyoteConnector.invalidPort=The connector cannot start since the specified port value of [{0}] is invalid coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed coyoteConnector.protocolHandlerNoApr=The configured protocol [{0}] requires the APR/native library which is not available coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed coyoteConnector.protocolRegistrationFailed=Protocol JMX registration failed coyoteConnector.protocolHandlerPauseFailed=Protocol handler pause failed coyoteConnector.protocolHandlerResumeFailed=Protocol handler resume failed coyoteConnector.MapperRegistration=register Mapper: {0} coyoteConnector.protocolUnregistrationFailed=Protocol handler stop failed coyoteConnector.parseBodyMethodNoTrace=TRACE method MUST NOT include an entity (see RFC 2616 Section 9.6) # # CoyoteAdapter # coyoteAdapter.read=The servlet did not read all available bytes during the processing of the read event coyoteAdapter.parsePathParam=Unable to parse the path parameters using encoding [{0}]. The path parameters in the URL will be ignored. coyoteAdapter.debug=The variable [{0}] has value [{1}] coyoteAdapter.accesslogFail=Exception while attempting to add an entry to the access log # # CoyoteResponse # coyoteResponse.getOutputStream.ise=getWriter() has already been called for this response coyoteResponse.getWriter.ise=getOutputStream() has already been called for this response coyoteResponse.reset.ise=Cannot call reset() after response has been committed coyoteResponse.resetBuffer.ise=Cannot reset buffer after response has been committed coyoteResponse.sendError.ise=Cannot call sendError() after the response has been committed coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been committed coyoteResponse.sendRedirect.note=

    Redirecting to {0}

    coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written # # CoyoteRequest # coyoteRequest.getInputStream.ise=getReader() has already been called for this request coyoteRequest.getReader.ise=getInputStream() has already been called for this request coyoteRequest.gssLifetimeFail=Failed to obtain remaining lifetime for user principal [{0}] coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name coyoteRequest.listenerStart=Exception sending context initialized event to listener instance of class {0} coyoteRequest.listenerStop=Exception sending context destroyed event to listener instance of class {0} coyoteRequest.attributeEvent=Exception thrown by attributes event listener coyoteRequest.parseParameters=Exception thrown whilst processing POSTed parameters coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data was too big. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs. coyoteRequest.chunkedPostTooLarge=Parameters were not parsed because the size of the posted data was too big. Because this request was a chunked request, it could not be processed further. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs. coyoteRequest.alreadyAuthenticated=This is request has already been authenticated coyoteRequest.authenticate.ise=Cannot call authenticate() after the reponse has been committed coyoteRequest.uploadLocationInvalid=The temporary upload location [{0}] is not valid coyoteRequest.sessionEndAccessFail=Exception triggered ending access to session while recycling request coyoteRequest.sendfileNotCanonical=Unable to determine canonical name of file [{0}] specified for use with sendfile coyoteRequest.maxPostSizeExceeded=The multi-part request contained parameter data (excluding uploaded files) that exceeded the limit for maxPostSize set on the associated connector requestFacade.nullRequest=The request object has been recycled and is no longer associated with this facade responseFacade.nullResponse=The response object has been recycled and is no longer associated with this facade cometEvent.nullRequest=The event object has been recycled and is no longer associated with a request # # MapperListener # mapperListener.unknownDefaultHost=Unknown default host [{0}] for connector [{1}] mapperListener.registerHost=Register host [{0}] at domain [{1}] for connector [{2}] mapperListener.unregisterHost=Unregister host [{0}] at domain [{1}] for connector [{2}] mapperListener.registerContext=Register Context [{0}] for connector [{1}] mapperListener.unregisterContext=Unregister Context [{0}] for connector [{1}] mapperListener.registerWrapper=Register Wrapper [{0}] in Context [{1}] for connector [{2}] mapperListener.unregisterWrapper=Unregister Wrapper [{0}] in Context [{1}] for connector [{2}] mapperListener.addMBeanListenerFail=Failed to add MBean notification listener for connector [{0}] in domain [{1}]. Adding Hosts, Contexts and Wrappers will not be visible to the connector. mapperListener.removeMBeanListenerFail=Failed to remove MBean notification listener for connector [{0}] in domain [{1}]. This may result in a memory leak. mapperListener.lifecycleListenerFail=Failed to add Lifecycle listener to object [{0}]. Changes in the object state may not be correctly reflected in the mapper for connector [{1}] in domain [{2}]. inputBuffer.streamClosed=Stream closed tomcat7-7.0.52/java/org/apache/catalina/connector/LocalStrings_ja.properties0000644000175100017510000001327012271471332027043 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # CoyoteConnector # coyoteConnector.cannotRegisterProtocol=\u305d\u306e\u30d7\u30ed\u30c8\u30b3\u30eb\u306bMBean\u3092\u767b\u9332\u3067\u304d\u307e\u305b\u3093 coyoteConnector.protocolHandlerDestroyFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u5ec3\u68c4\u306b\u5931\u6557\u3057\u307e\u3057\u305f coyoteConnector.protocolHandlerInitializationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f coyoteConnector.protocolHandlerInstantiationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f coyoteConnector.protocolHandlerStartFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f coyoteConnector.protocolRegistrationFailed=\u30d7\u30ed\u30c8\u30b3\u30ebJMX\u306e\u767b\u9332\u306b\u5931\u6557\u3057\u307e\u3057\u305f coyoteConnector.protocolHandlerPauseFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u4e00\u6642\u505c\u6b62\u306b\u5931\u6557\u3057\u307e\u3057\u305f coyoteConnector.protocolHandlerResumeFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u518d\u958b\u306b\u5931\u6557\u3057\u307e\u3057\u305f # # CoyoteResponse # coyoteResponse.getOutputStream.ise=getWriter()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 coyoteResponse.getWriter.ise=getOutputStream()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 coyoteResponse.resetBuffer.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u3092\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 coyoteResponse.sendError.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendError()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 coyoteResponse.sendRedirect.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendRedirect()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 coyoteResponse.setBufferSize.ise=\u30c7\u30fc\u30bf\u304c\u65e2\u306b\u66f8\u304d\u8fbc\u307e\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3092\u5909\u66f4\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 # # CoyoteRequest # coyoteRequest.getInputStream.ise=getReader()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 coyoteRequest.getReader.ise=getInputStream()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 coyoteRequest.sessionCreateCommitted=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 coyoteRequest.setAttribute.namenull=setAttribute\u3092\u540d\u524d\u3092\u6307\u5b9a\u305b\u305a\u306b\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 coyoteRequest.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f coyoteRequest.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f coyoteRequest.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f coyoteRequest.postTooLarge=POST\u3055\u308c\u305f\u30c7\u30fc\u30bf\u304c\u5927\u304d\u3059\u304e\u305f\u306e\u3067\u3001\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u69cb\u6587\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u305d\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c\u5de8\u5927\u306aPOST\u3092\u53d7\u3051\u4ed8\u3051\u306d\u3070\u306a\u3089\u306a\u3044\u5834\u5408\u306b\u306f\u3001\u3053\u308c\u3092\u89e3\u6c7a\u3059\u308b\u305f\u3081\u306b\u30b3\u30cd\u30af\u30bf\u306emaxPostSize\u5c5e\u6027\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002 # # MapperListener # mapperListener.registerContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0}\u3000\u3092\u767b\u9332\u3057\u307e\u3059 mapperListener.unregisterContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u767b\u9332\u3092\u62b9\u6d88\u3057\u307e\u3059 mapperListener.registerWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {1} \u306b\u30e9\u30c3\u30d1 {0} \u3092\u767b\u9332\u3057\u307e\u3059 tomcat7-7.0.52/java/org/apache/catalina/connector/LocalStrings_fr.properties0000644000175100017510000000761212271471332027063 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # # CoyoteConnector # coyoteConnector.cannotRegisterProtocol=Impossible d''enregistrer le MBean pour le Protocol coyoteConnector.protocolHandlerDestroyFailed=La destruction du gestionnaire de protocole a \u00e9chou\u00e9 coyoteConnector.protocolHandlerInitializationFailed=L''initialisation du gestionnaire de protocole a \u00e9chou\u00e9 coyoteConnector.protocolHandlerInstantiationFailed=L''instantiation du gestionnaire de protocole a \u00e9chou\u00e9 coyoteConnector.protocolHandlerStartFailed=Le d\u00e9marrage du gestionnaire de protocole a \u00e9chou\u00e9 coyoteConnector.protocolRegistrationFailed=L''enregistrement du protocol JMX a \u00e9chou\u00e9 coyoteConnector.protocolHandlerPauseFailed=La suspension du gestionnaire de protocole a \u00e9chou\u00e9e coyoteConnector.protocolHandlerResumeFailed=Le red\u00e9marrage du gestionnaire de protocole a \u00e9chou\u00e9 # # CoyoteResponse # coyoteResponse.getOutputStream.ise="getWriter()" a d\u00e9j\u00e0 \u00e9t\u00e9 appel\u00e9 pour cette r\u00e9ponse coyoteResponse.getWriter.ise="getOutputStream()" a d\u00e9j\u00e0 \u00e9t\u00e9 appel\u00e9 pour cette r\u00e9ponse coyoteResponse.resetBuffer.ise=Impossible de remettre \u00e0 z\u00e9ro le tampon apr\u00e8s que la r\u00e9ponse ait \u00e9t\u00e9 envoy\u00e9e coyoteResponse.sendError.ise=Impossible d''appeler "sendError()" apr\u00e8s que la r\u00e9ponse ait \u00e9t\u00e9 envoy\u00e9e coyoteResponse.sendRedirect.ise=Impossible d''appeler "sendRedirect()" apr\u00e8s que la r\u00e9ponse ait \u00e9t\u00e9 envoy\u00e9e coyoteResponse.setBufferSize.ise=Impossible de changer la taille du tampon apr\u00e8s que les donn\u00e9es aient \u00e9t\u00e9 \u00e9crites # # CoyoteRequest # coyoteRequest.getInputStream.ise="getReader()" a d\u00e9j\u00e0 \u00e9t\u00e9 appel\u00e9 pour cette requ\u00eate coyoteRequest.getReader.ise="getInputStream()" a d\u00e9j\u00e0 \u00e9t\u00e9 appel\u00e9 pour cette requ\u00eate coyoteRequest.sessionCreateCommitted=Impossible de cr\u00e9er une session apr\u00e8s que la r\u00e9ponse ait \u00e9t\u00e9 envoy\u00e9e coyoteRequest.setAttribute.namenull=Impossible d''appeler "setAttribute" avec un nom nul coyoteRequest.listenerStart=Une exception s''est produite lors de l''envoi de l''\u00e9v\u00e8nement contexte initialis\u00e9 \u00e0 l''instance de classe d''\u00e9coute {0} coyoteRequest.listenerStop=Une exception s''est produite lors de l''envoi de l''\u00e9v\u00e8nement contexte d\u00e9truit \u00e0 l''instance de classe d''\u00e9coute {0} coyoteRequest.attributeEvent=Une exception a \u00e9t\u00e9 lanc\u00e9e par l''instance d''\u00e9coute pour l''\u00e9v\u00e8nement attributs (attributes) coyoteRequest.postTooLarge=Les param\u00e8tres n''ont pas \u00e9t\u00e9 \u00e9valu\u00e9s car la taille des donn\u00e9es post\u00e9es est trop important. Utilisez l''attribut maxPostSize du connecteur pour corriger ce probl\u00e8me si votre application doit accepter des POSTs importants. # # MapperListener # mapperListener.registerContext=Enregistrement du contexte {0} mapperListener.unregisterContext=D\u00e9senregistrement du contexte {0} mapperListener.registerWrapper=Enregistrement de l''enrobeur (wrapper) {0} dans le contexte {1} tomcat7-7.0.52/java/org/apache/catalina/connector/RequestFacade.java0000644000175100017510000006504112271471332025231 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.BufferedReader; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; import java.util.Enumeration; import java.util.Locale; import java.util.Map; import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Part; import org.apache.catalina.Globals; import org.apache.catalina.security.SecurityUtil; import org.apache.coyote.http11.upgrade.UpgradeInbound; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; import org.apache.tomcat.util.res.StringManager; /** * Facade class that wraps a Coyote request object. * All methods are delegated to the wrapped request. * * @author Craig R. McClanahan * @author Remy Maucherat * @author Jean-Francois Arcand */ @SuppressWarnings("deprecation") public class RequestFacade implements HttpServletRequest { // ----------------------------------------------------------- DoPrivileged private final class GetAttributePrivilegedAction implements PrivilegedAction> { @Override public Enumeration run() { return request.getAttributeNames(); } } private final class GetParameterMapPrivilegedAction implements PrivilegedAction> { @Override public Map run() { return request.getParameterMap(); } } private final class GetRequestDispatcherPrivilegedAction implements PrivilegedAction { private final String path; public GetRequestDispatcherPrivilegedAction(String path){ this.path = path; } @Override public RequestDispatcher run() { return request.getRequestDispatcher(path); } } private final class GetParameterPrivilegedAction implements PrivilegedAction { public String name; public GetParameterPrivilegedAction(String name){ this.name = name; } @Override public String run() { return request.getParameter(name); } } private final class GetParameterNamesPrivilegedAction implements PrivilegedAction> { @Override public Enumeration run() { return request.getParameterNames(); } } private final class GetParameterValuePrivilegedAction implements PrivilegedAction { public String name; public GetParameterValuePrivilegedAction(String name){ this.name = name; } @Override public String[] run() { return request.getParameterValues(name); } } private final class GetCookiesPrivilegedAction implements PrivilegedAction { @Override public Cookie[] run() { return request.getCookies(); } } private final class GetCharacterEncodingPrivilegedAction implements PrivilegedAction { @Override public String run() { return request.getCharacterEncoding(); } } private final class GetHeadersPrivilegedAction implements PrivilegedAction> { private final String name; public GetHeadersPrivilegedAction(String name){ this.name = name; } @Override public Enumeration run() { return request.getHeaders(name); } } private final class GetHeaderNamesPrivilegedAction implements PrivilegedAction> { @Override public Enumeration run() { return request.getHeaderNames(); } } private final class GetLocalePrivilegedAction implements PrivilegedAction { @Override public Locale run() { return request.getLocale(); } } private final class GetLocalesPrivilegedAction implements PrivilegedAction> { @Override public Enumeration run() { return request.getLocales(); } } private final class GetSessionPrivilegedAction implements PrivilegedAction { private final boolean create; public GetSessionPrivilegedAction(boolean create){ this.create = create; } @Override public HttpSession run() { return request.getSession(create); } } // ----------------------------------------------------------- Constructors /** * Construct a wrapper for the specified request. * * @param request The request to be wrapped */ public RequestFacade(Request request) { this.request = request; } // ----------------------------------------------------- Instance Variables /** * The wrapped request. */ protected Request request = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // --------------------------------------------------------- Public Methods /** * Clear facade. */ public void clear() { request = null; } /** * Prevent cloning the facade. */ @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // ------------------------------------------------- ServletRequest Methods @Override public Object getAttribute(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getAttribute(name); } @Override public Enumeration getAttributeNames() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetAttributePrivilegedAction()); } else { return request.getAttributeNames(); } } @Override public String getCharacterEncoding() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetCharacterEncodingPrivilegedAction()); } else { return request.getCharacterEncoding(); } } @Override public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } request.setCharacterEncoding(env); } @Override public int getContentLength() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getContentLength(); } @Override public String getContentType() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getContentType(); } @Override public ServletInputStream getInputStream() throws IOException { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getInputStream(); } @Override public String getParameter(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetParameterPrivilegedAction(name)); } else { return request.getParameter(name); } } @Override public Enumeration getParameterNames() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetParameterNamesPrivilegedAction()); } else { return request.getParameterNames(); } } @Override public String[] getParameterValues(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } String[] ret = null; /* * Clone the returned array only if there is a security manager * in place, so that performance won't suffer in the non-secure case */ if (SecurityUtil.isPackageProtectionEnabled()){ ret = AccessController.doPrivileged( new GetParameterValuePrivilegedAction(name)); if (ret != null) { ret = ret.clone(); } } else { ret = request.getParameterValues(name); } return ret; } @Override public Map getParameterMap() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetParameterMapPrivilegedAction()); } else { return request.getParameterMap(); } } @Override public String getProtocol() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getProtocol(); } @Override public String getScheme() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getScheme(); } @Override public String getServerName() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getServerName(); } @Override public int getServerPort() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getServerPort(); } @Override public BufferedReader getReader() throws IOException { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getReader(); } @Override public String getRemoteAddr() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRemoteAddr(); } @Override public String getRemoteHost() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRemoteHost(); } @Override public void setAttribute(String name, Object o) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } request.setAttribute(name, o); } @Override public void removeAttribute(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } request.removeAttribute(name); } @Override public Locale getLocale() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetLocalePrivilegedAction()); } else { return request.getLocale(); } } @Override public Enumeration getLocales() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetLocalesPrivilegedAction()); } else { return request.getLocales(); } } @Override public boolean isSecure() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.isSecure(); } @Override public RequestDispatcher getRequestDispatcher(String path) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetRequestDispatcherPrivilegedAction(path)); } else { return request.getRequestDispatcher(path); } } @Override public String getRealPath(String path) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRealPath(path); } @Override public String getAuthType() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getAuthType(); } @Override public Cookie[] getCookies() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } Cookie[] ret = null; /* * Clone the returned array only if there is a security manager * in place, so that performance won't suffer in the non-secure case */ if (SecurityUtil.isPackageProtectionEnabled()){ ret = AccessController.doPrivileged( new GetCookiesPrivilegedAction()); if (ret != null) { ret = ret.clone(); } } else { ret = request.getCookies(); } return ret; } @Override public long getDateHeader(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getDateHeader(name); } @Override public String getHeader(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getHeader(name); } @Override public Enumeration getHeaders(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetHeadersPrivilegedAction(name)); } else { return request.getHeaders(name); } } @Override public Enumeration getHeaderNames() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetHeaderNamesPrivilegedAction()); } else { return request.getHeaderNames(); } } @Override public int getIntHeader(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getIntHeader(name); } @Override public String getMethod() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getMethod(); } @Override public String getPathInfo() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getPathInfo(); } @Override public String getPathTranslated() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getPathTranslated(); } @Override public String getContextPath() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getContextPath(); } @Override public String getQueryString() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getQueryString(); } @Override public String getRemoteUser() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRemoteUser(); } @Override public boolean isUserInRole(String role) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.isUserInRole(role); } @Override public java.security.Principal getUserPrincipal() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getUserPrincipal(); } @Override public String getRequestedSessionId() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRequestedSessionId(); } @Override public String getRequestURI() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRequestURI(); } @Override public StringBuffer getRequestURL() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRequestURL(); } @Override public String getServletPath() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getServletPath(); } @Override public HttpSession getSession(boolean create) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (SecurityUtil.isPackageProtectionEnabled()){ return AccessController. doPrivileged(new GetSessionPrivilegedAction(create)); } else { return request.getSession(create); } } @Override public HttpSession getSession() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return getSession(true); } @Override public boolean isRequestedSessionIdValid() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.isRequestedSessionIdValid(); } @Override public boolean isRequestedSessionIdFromCookie() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.isRequestedSessionIdFromCookie(); } @Override public boolean isRequestedSessionIdFromURL() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.isRequestedSessionIdFromURL(); } @Override public boolean isRequestedSessionIdFromUrl() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.isRequestedSessionIdFromURL(); } @Override public String getLocalAddr() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getLocalAddr(); } @Override public String getLocalName() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getLocalName(); } @Override public int getLocalPort() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getLocalPort(); } @Override public int getRemotePort() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getRemotePort(); } @Override public ServletContext getServletContext() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getServletContext(); } @Override public AsyncContext startAsync() throws IllegalStateException { return request.startAsync(); } @Override public AsyncContext startAsync(ServletRequest request, ServletResponse response) throws IllegalStateException { return this.request.startAsync(request, response); } @Override public boolean isAsyncStarted() { return request.isAsyncStarted(); } @Override public boolean isAsyncSupported() { return request.isAsyncSupported(); } @Override public AsyncContext getAsyncContext() { return request.getAsyncContext(); } @Override public DispatcherType getDispatcherType() { return request.getDispatcherType(); } @Override public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { return request.authenticate(response); } @Override public void login(String username, String password) throws ServletException { request.login(username, password); } @Override public void logout() throws ServletException { request.logout(); } @Override public Collection getParts() throws IllegalStateException, IOException, ServletException { return request.getParts(); } @Override public Part getPart(String name) throws IllegalStateException, IOException, ServletException { return request.getPart(name); } public boolean getAllowTrace() { return request.getConnector().getAllowTrace(); } /** * Sets the response status to {@link * HttpServletResponse#SC_SWITCHING_PROTOCOLS} and flushes the response. * Protocol specific headers must have already been set before this method * is called. * * @param inbound The handler for all further incoming data on the current * connection. * * @throws IOException If the upgrade fails (e.g. if the response has * already been committed. */ public void doUpgrade(UpgradeInbound inbound) throws IOException { request.doUpgrade(inbound); } public T upgrade( Class httpUpgradeHandlerClass) throws ServletException { return request.upgrade(httpUpgradeHandlerClass); } } tomcat7-7.0.52/java/org/apache/catalina/connector/CoyotePrincipal.java0000644000175100017510000000403412271471332025614 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.connector; import java.io.Serializable; import java.security.Principal; /** * Generic implementation of java.security.Principal that * is used to represent principals authenticated at the protocol handler level. * * @author Remy Maucherat */ public class CoyotePrincipal implements Principal, Serializable { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors public CoyotePrincipal(String name) { this.name = name; } // ------------------------------------------------------------- Properties /** * The username of the user represented by this Principal. */ protected String name = null; @Override public String getName() { return (this.name); } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object, which exposes only * information that should be public. */ @Override public String toString() { StringBuilder sb = new StringBuilder("CoyotePrincipal["); sb.append(this.name); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/Host.java0000644000175100017510000001630712271471332021441 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; /** * A Host is a Container that represents a virtual host in the * Catalina servlet engine. It is useful in the following types of scenarios: *
      *
    • You wish to use Interceptors that see every single request processed * by this particular virtual host. *
    • You wish to run Catalina in with a standalone HTTP connector, but still * want support for multiple virtual hosts. *
    * In general, you would not use a Host when deploying Catalina connected * to a web server (such as Apache), because the Connector will have * utilized the web server's facilities to determine which Context (or * perhaps even which Wrapper) should be utilized to process this request. *

    * The parent Container attached to a Host is generally an Engine, but may * be some other implementation, or may be omitted if it is not necessary. *

    * The child containers attached to a Host are generally implementations * of Context (representing an individual servlet context). * * @author Craig R. McClanahan */ public interface Host extends Container { // ----------------------------------------------------- Manifest Constants /** * The ContainerEvent event type sent when a new alias is added * by addAlias(). */ public static final String ADD_ALIAS_EVENT = "addAlias"; /** * The ContainerEvent event type sent when an old alias is removed * by removeAlias(). */ public static final String REMOVE_ALIAS_EVENT = "removeAlias"; // ------------------------------------------------------------- Properties /** * Return the XML root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. * If null, defaults to * ${catalina.base}/conf/<engine name>/<host name> directory */ public String getXmlBase(); /** * Set the Xml root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. * If null, defaults to * ${catalina.base}/conf/<engine name>/<host name> directory * @param xmlBase The new XML root */ public void setXmlBase(String xmlBase); /** * Return the application root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. */ public String getAppBase(); /** * Set the application root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. * * @param appBase The new application root */ public void setAppBase(String appBase); /** * Return the value of the auto deploy flag. If true, it indicates that * this host's child webapps should be discovered and automatically * deployed dynamically. */ public boolean getAutoDeploy(); /** * Set the auto deploy flag value for this host. * * @param autoDeploy The new auto deploy flag */ public void setAutoDeploy(boolean autoDeploy); /** * Return the Java class name of the context configuration class * for new web applications. */ public String getConfigClass(); /** * Set the Java class name of the context configuration class * for new web applications. * * @param configClass The new context configuration class */ public void setConfigClass(String configClass); /** * Return the value of the deploy on startup flag. If true, it indicates * that this host's child webapps should be discovered and automatically * deployed. */ public boolean getDeployOnStartup(); /** * Set the deploy on startup flag value for this host. * * @param deployOnStartup The new deploy on startup flag */ public void setDeployOnStartup(boolean deployOnStartup); /** * Return the regular expression that defines the files and directories in * the host's appBase that will be ignored by the automatic deployment * process. */ public String getDeployIgnore(); /** * Return the compiled regular expression that defines the files and * directories in the host's appBase that will be ignored by the automatic * deployment process. */ public Pattern getDeployIgnorePattern(); /** * Set the regular expression that defines the files and directories in * the host's appBase that will be ignored by the automatic deployment * process. */ public void setDeployIgnore(String deployIgnore); /** * Return the executor that is used for starting and stopping contexts. This * is primarily for use by components deploying contexts that want to do * this in a multi-threaded manner. */ public ExecutorService getStartStopExecutor(); /** * Returns true of the Host is configured to automatically undeploy old * versions of applications deployed using parallel deployment. This only * takes effect is {@link #getAutoDeploy()} also returns true. */ public boolean getUndeployOldVersions(); /** * Set to true if the Host should automatically undeploy old versions of * applications deployed using parallel deployment. This only takes effect * if {@link #getAutoDeploy()} returns true. */ public void setUndeployOldVersions(boolean undeployOldVersions); // --------------------------------------------------------- Public Methods /** * Add an alias name that should be mapped to this same Host. * * @param alias The alias to be added */ public void addAlias(String alias); /** * Return the set of alias names for this Host. If none are defined, * a zero length array is returned. */ public String[] findAliases(); /** * Remove the specified alias name from the aliases for this Host. * * @param alias Alias name to be removed */ public void removeAlias(String alias); /** * Returns true if the Host will attempt to create directories for appBase and xmlBase * unless they already exist. * @return true if the Host will attempt to create directories */ public boolean getCreateDirs(); /** * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup * @param createDirs */ public void setCreateDirs(boolean createDirs); } tomcat7-7.0.52/java/org/apache/catalina/CatalinaFactory.java0000644000175100017510000000371011774372603023572 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import org.apache.catalina.core.StandardPipeline; /** * Factory class used whenever a default implementation of a component is * required. It provides both class names (for the digester) and objects for * other components. The current implementation is as simple as possible. If * there is demand it can be extended to support alternative factories and/or * alternative defaults. * * @deprecated There was no demand for this capability and it will be removed in * Tomcat 8.0.x */ @Deprecated public class CatalinaFactory { private static CatalinaFactory factory = new CatalinaFactory(); public static CatalinaFactory getFactory() { return factory; } private CatalinaFactory() { // Hide the default constructor } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x. */ @Deprecated public String getDefaultPipelineClassName() { return StandardPipeline.class.getName(); } public Pipeline createPipeline(Container container) { Pipeline pipeline = new StandardPipeline(); pipeline.setContainer(container); return pipeline; } } tomcat7-7.0.52/java/org/apache/catalina/users/0000755000175100017510000000000012301126371021005 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/users/LocalStrings_es.properties0000644000175100017510000000343512271471332026231 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. memoryUserDatabase.notPersistable = La base de datos de usuario no es persistible - no hay permisos de grabaci\u00F3n sobre el directorio memoryUserDatabase.nullGroup = Se ha especificado un nombre de grupo nulo o de tama\u00F1o cero. Se ignora el grupo. memoryUserDatabase.nullRole = Se ha especificado un nombre rol nulo o de tama\u00F1o cero. Se ignora el rol. memoryUserDatabase.nullUser = Se ha especificado un nombre de usuario nulo o de tama\u00F1o cero. Se ignora el usuario. memoryUserDatabase.readOnly = User database has been configured to be read only. Changes cannot be saved memoryUserDatabase.renameOld = Imposible de renombrar el archivo original a {0} memoryUserDatabase.renameNew = Imposible de renombrar el archivo nuevo a {0} memoryUserDatabase.writeException = IOException durante la escritura hacia {0} memoryUserDatabase.xmlFeatureEncoding = Excepci\u00F3n al configurar el resumidor para permitir nombres codificados en java en los ficheros XML. S\u00F3lo se soportar\u00E1n los nombres con codificaci\u00F3n IANA. tomcat7-7.0.52/java/org/apache/catalina/users/AbstractGroup.java0000644000175100017510000000763312271471332024447 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import java.util.Iterator; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; /** *

    Convenience base class for {@link Group} implementations.

    * * @author Craig R. McClanahan * @since 4.1 */ public abstract class AbstractGroup implements Group { // ----------------------------------------------------- Instance Variables /** * The description of this group. */ protected String description = null; /** * The group name of this group. */ protected String groupname = null; // ------------------------------------------------------------- Properties /** * Return the description of this group. */ @Override public String getDescription() { return (this.description); } /** * Set the description of this group. * * @param description The new description */ @Override public void setDescription(String description) { this.description = description; } /** * Return the group name of this group, which must be unique * within the scope of a {@link UserDatabase}. */ @Override public String getGroupname() { return (this.groupname); } /** * Set the group name of this group, which must be unique * within the scope of a {@link UserDatabase}. * * @param groupname The new group name */ @Override public void setGroupname(String groupname) { this.groupname = groupname; } /** * Return the set of {@link Role}s assigned specifically to this group. */ @Override public abstract Iterator getRoles(); /** * Return the {@link UserDatabase} within which this Group is defined. */ @Override public abstract UserDatabase getUserDatabase(); /** * Return an Iterator over the set of {@link org.apache.catalina.User}s that * are members of this group. */ @Override public abstract Iterator getUsers(); // --------------------------------------------------------- Public Methods /** * Add a new {@link Role} to those assigned specifically to this group. * * @param role The new role */ @Override public abstract void addRole(Role role); /** * Is this group specifically assigned the specified {@link Role}? * * @param role The role to check */ @Override public abstract boolean isInRole(Role role); /** * Remove a {@link Role} from those assigned to this group. * * @param role The old role */ @Override public abstract void removeRole(Role role); /** * Remove all {@link Role}s from those assigned to this group. */ @Override public abstract void removeRoles(); // ------------------------------------------------------ Principal Methods /** * Make the principal name the same as the group name. */ @Override public String getName() { return (getGroupname()); } } tomcat7-7.0.52/java/org/apache/catalina/users/MemoryUserDatabase.java0000644000175100017510000005455412271471332025427 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.HashMap; import java.util.Iterator; import org.apache.catalina.Globals; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.digester.AbstractObjectCreationFactory; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.Attributes; /** *

    Concrete implementation of {@link UserDatabase} that loads all * defined users, groups, and roles into an in-memory data structure, * and uses a specified XML file for its persistent storage.

    * * @author Craig R. McClanahan * @since 4.1 */ public class MemoryUserDatabase implements UserDatabase { private static final Log log = LogFactory.getLog(MemoryUserDatabase.class); // ----------------------------------------------------------- Constructors /** * Create a new instance with default values. */ public MemoryUserDatabase() { this(null); } /** * Create a new instance with the specified values. * * @param id Unique global identifier of this user database */ public MemoryUserDatabase(String id) { this.id = id; } // ----------------------------------------------------- Instance Variables /** * The set of {@link Group}s defined in this database, keyed by * group name. */ protected final HashMap groups = new HashMap(); /** * The unique global identifier of this user database. */ protected final String id; /** * The relative (to catalina.base) or absolute pathname to * the XML file in which we will save our persistent information. */ protected String pathname = "conf/tomcat-users.xml"; /** * The relative or absolute pathname to the file in which our old * information is stored while renaming is in progress. */ protected String pathnameOld = pathname + ".old"; /** * The relative or absolute pathname of the file in which we write * our new information prior to renaming. */ protected String pathnameNew = pathname + ".new"; /** * A flag, indicating if the user database is read only. */ protected boolean readonly = true; /** * The set of {@link Role}s defined in this database, keyed by * role name. */ protected final HashMap roles = new HashMap(); /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The set of {@link User}s defined in this database, keyed by * user name. */ protected final HashMap users = new HashMap(); // ------------------------------------------------------------- Properties /** * Return the set of {@link Group}s defined in this user database. */ @Override public Iterator getGroups() { synchronized (groups) { return (groups.values().iterator()); } } /** * Return the unique global identifier of this user database. */ @Override public String getId() { return (this.id); } /** * Return the relative or absolute pathname to the persistent storage file. */ public String getPathname() { return (this.pathname); } /** * Set the relative or absolute pathname to the persistent storage file. * * @param pathname The new pathname */ public void setPathname(String pathname) { this.pathname = pathname; this.pathnameOld = pathname + ".old"; this.pathnameNew = pathname + ".new"; } /** * Returning the readonly status of the user database */ public boolean getReadonly() { return (this.readonly); } /** * Setting the readonly status of the user database * * @param readonly the new status */ public void setReadonly(boolean readonly) { this.readonly = readonly; } /** * Return the set of {@link Role}s defined in this user database. */ @Override public Iterator getRoles() { synchronized (roles) { return (roles.values().iterator()); } } /** * Return the set of {@link User}s defined in this user database. */ @Override public Iterator getUsers() { synchronized (users) { return (users.values().iterator()); } } // --------------------------------------------------------- Public Methods /** * Finalize access to this user database. * * @exception Exception if any exception is thrown during closing */ @Override public void close() throws Exception { save(); synchronized (groups) { synchronized (users) { users.clear(); groups.clear(); } } } /** * Create and return a new {@link Group} defined in this user database. * * @param groupname The group name of the new group (must be unique) * @param description The description of this group */ @Override public Group createGroup(String groupname, String description) { if (groupname == null || groupname.length() == 0) { String msg = sm.getString("memoryUserDatabase.nullGroup"); log.warn(msg); throw new IllegalArgumentException(msg); } MemoryGroup group = new MemoryGroup(this, groupname, description); synchronized (groups) { groups.put(group.getGroupname(), group); } return (group); } /** * Create and return a new {@link Role} defined in this user database. * * @param rolename The role name of the new group (must be unique) * @param description The description of this group */ @Override public Role createRole(String rolename, String description) { if (rolename == null || rolename.length() == 0) { String msg = sm.getString("memoryUserDatabase.nullRole"); log.warn(msg); throw new IllegalArgumentException(msg); } MemoryRole role = new MemoryRole(this, rolename, description); synchronized (roles) { roles.put(role.getRolename(), role); } return (role); } /** * Create and return a new {@link User} defined in this user database. * * @param username The logon username of the new user (must be unique) * @param password The logon password of the new user * @param fullName The full name of the new user */ @Override public User createUser(String username, String password, String fullName) { if (username == null || username.length() == 0) { String msg = sm.getString("memoryUserDatabase.nullUser"); log.warn(msg); throw new IllegalArgumentException(msg); } MemoryUser user = new MemoryUser(this, username, password, fullName); synchronized (users) { users.put(user.getUsername(), user); } return (user); } /** * Return the {@link Group} with the specified group name, if any; * otherwise return null. * * @param groupname Name of the group to return */ @Override public Group findGroup(String groupname) { synchronized (groups) { return groups.get(groupname); } } /** * Return the {@link Role} with the specified role name, if any; * otherwise return null. * * @param rolename Name of the role to return */ @Override public Role findRole(String rolename) { synchronized (roles) { return roles.get(rolename); } } /** * Return the {@link User} with the specified user name, if any; * otherwise return null. * * @param username Name of the user to return */ @Override public User findUser(String username) { synchronized (users) { return users.get(username); } } /** * Initialize access to this user database. * * @exception Exception if any exception is thrown during opening */ @Override public void open() throws Exception { synchronized (groups) { synchronized (users) { // Erase any previous groups and users users.clear(); groups.clear(); roles.clear(); // Construct a reader for the XML input file (if it exists) File file = new File(pathname); if (!file.isAbsolute()) { file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname); } if (!file.exists()) { log.error(sm.getString("memoryUserDatabase.fileNotFound", file.getAbsolutePath())); return; } // Construct a digester to read the XML input file Digester digester = new Digester(); try { digester.setFeature( "http://apache.org/xml/features/allow-java-encodings", true); } catch (Exception e) { log.warn(sm.getString("memoryUserDatabase.xmlFeatureEncoding"), e); } digester.addFactoryCreate ("tomcat-users/group", new MemoryGroupCreationFactory(this), true); digester.addFactoryCreate ("tomcat-users/role", new MemoryRoleCreationFactory(this), true); digester.addFactoryCreate ("tomcat-users/user", new MemoryUserCreationFactory(this), true); // Parse the XML input file to load this database FileInputStream fis = null; try { fis = new FileInputStream(file); digester.parse(fis); } finally { if (fis != null) { try { fis.close(); } catch (IOException ioe) { // Ignore } } } } } } /** * Remove the specified {@link Group} from this user database. * * @param group The group to be removed */ @Override public void removeGroup(Group group) { synchronized (groups) { Iterator users = getUsers(); while (users.hasNext()) { User user = users.next(); user.removeGroup(group); } groups.remove(group.getGroupname()); } } /** * Remove the specified {@link Role} from this user database. * * @param role The role to be removed */ @Override public void removeRole(Role role) { synchronized (roles) { Iterator groups = getGroups(); while (groups.hasNext()) { Group group = groups.next(); group.removeRole(role); } Iterator users = getUsers(); while (users.hasNext()) { User user = users.next(); user.removeRole(role); } roles.remove(role.getRolename()); } } /** * Remove the specified {@link User} from this user database. * * @param user The user to be removed */ @Override public void removeUser(User user) { synchronized (users) { users.remove(user.getUsername()); } } /** * Check for permissions to save this user database * to persistent storage location * */ public boolean isWriteable() { File file = new File(pathname); if (!file.isAbsolute()) { file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname); } File dir = file.getParentFile(); return dir.exists() && dir.isDirectory() && dir.canWrite(); } /** * Save any updated information to the persistent storage location for * this user database. * * @exception Exception if any exception is thrown during saving */ @Override public void save() throws Exception { if (getReadonly()) { log.error(sm.getString("memoryUserDatabase.readOnly")); return; } if (!isWriteable()) { log.warn(sm.getString("memoryUserDatabase.notPersistable")); return; } // Write out contents to a temporary file File fileNew = new File(pathnameNew); if (!fileNew.isAbsolute()) { fileNew = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathnameNew); } PrintWriter writer = null; try { // Configure our PrintWriter FileOutputStream fos = new FileOutputStream(fileNew); OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8"); writer = new PrintWriter(osw); // Print the file prolog writer.println(""); writer.println(""); // Print entries for each defined role, group, and user Iterator values = null; values = getRoles(); while (values.hasNext()) { writer.print(" "); writer.println(values.next()); } values = getGroups(); while (values.hasNext()) { writer.print(" "); writer.println(values.next()); } values = getUsers(); while (values.hasNext()) { writer.print(" "); writer.println(((MemoryUser) values.next()).toXml()); } // Print the file epilog writer.println(""); // Check for errors that occurred while printing if (writer.checkError()) { writer.close(); fileNew.delete(); throw new IOException (sm.getString("memoryUserDatabase.writeException", fileNew.getAbsolutePath())); } writer.close(); } catch (IOException e) { if (writer != null) { writer.close(); } fileNew.delete(); throw e; } // Perform the required renames to permanently save this file File fileOld = new File(pathnameOld); if (!fileOld.isAbsolute()) { fileOld = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathnameOld); } fileOld.delete(); File fileOrig = new File(pathname); if (!fileOrig.isAbsolute()) { fileOrig = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname); } if (fileOrig.exists()) { fileOld.delete(); if (!fileOrig.renameTo(fileOld)) { throw new IOException (sm.getString("memoryUserDatabase.renameOld", fileOld.getAbsolutePath())); } } if (!fileNew.renameTo(fileOrig)) { if (fileOld.exists()) { fileOld.renameTo(fileOrig); } throw new IOException (sm.getString("memoryUserDatabase.renameNew", fileOrig.getAbsolutePath())); } fileOld.delete(); } /** * Return a String representation of this UserDatabase. */ @Override public String toString() { StringBuilder sb = new StringBuilder("MemoryUserDatabase[id="); sb.append(this.id); sb.append(",pathname="); sb.append(pathname); sb.append(",groupCount="); sb.append(this.groups.size()); sb.append(",roleCount="); sb.append(this.roles.size()); sb.append(",userCount="); sb.append(this.users.size()); sb.append("]"); return (sb.toString()); } // -------------------------------------------------------- Package Methods /** * Return the StringManager for use in looking up messages. */ StringManager getStringManager() { return (sm); } } /** * Digester object creation factory for group instances. */ class MemoryGroupCreationFactory extends AbstractObjectCreationFactory { public MemoryGroupCreationFactory(MemoryUserDatabase database) { this.database = database; } @Override public Object createObject(Attributes attributes) { String groupname = attributes.getValue("groupname"); if (groupname == null) { groupname = attributes.getValue("name"); } String description = attributes.getValue("description"); String roles = attributes.getValue("roles"); Group group = database.createGroup(groupname, description); if (roles != null) { while (roles.length() > 0) { String rolename = null; int comma = roles.indexOf(','); if (comma >= 0) { rolename = roles.substring(0, comma).trim(); roles = roles.substring(comma + 1); } else { rolename = roles.trim(); roles = ""; } if (rolename.length() > 0) { Role role = database.findRole(rolename); if (role == null) { role = database.createRole(rolename, null); } group.addRole(role); } } } return (group); } private MemoryUserDatabase database = null; } /** * Digester object creation factory for role instances. */ class MemoryRoleCreationFactory extends AbstractObjectCreationFactory { public MemoryRoleCreationFactory(MemoryUserDatabase database) { this.database = database; } @Override public Object createObject(Attributes attributes) { String rolename = attributes.getValue("rolename"); if (rolename == null) { rolename = attributes.getValue("name"); } String description = attributes.getValue("description"); Role role = database.createRole(rolename, description); return (role); } private MemoryUserDatabase database = null; } /** * Digester object creation factory for user instances. */ class MemoryUserCreationFactory extends AbstractObjectCreationFactory { public MemoryUserCreationFactory(MemoryUserDatabase database) { this.database = database; } @Override public Object createObject(Attributes attributes) { String username = attributes.getValue("username"); if (username == null) { username = attributes.getValue("name"); } String password = attributes.getValue("password"); String fullName = attributes.getValue("fullName"); if (fullName == null) { fullName = attributes.getValue("fullname"); } String groups = attributes.getValue("groups"); String roles = attributes.getValue("roles"); User user = database.createUser(username, password, fullName); if (groups != null) { while (groups.length() > 0) { String groupname = null; int comma = groups.indexOf(','); if (comma >= 0) { groupname = groups.substring(0, comma).trim(); groups = groups.substring(comma + 1); } else { groupname = groups.trim(); groups = ""; } if (groupname.length() > 0) { Group group = database.findGroup(groupname); if (group == null) { group = database.createGroup(groupname, null); } user.addGroup(group); } } } if (roles != null) { while (roles.length() > 0) { String rolename = null; int comma = roles.indexOf(','); if (comma >= 0) { rolename = roles.substring(0, comma).trim(); roles = roles.substring(comma + 1); } else { rolename = roles.trim(); roles = ""; } if (rolename.length() > 0) { Role role = database.findRole(rolename); if (role == null) { role = database.createRole(rolename, null); } user.addRole(role); } } } return (user); } private MemoryUserDatabase database = null; } tomcat7-7.0.52/java/org/apache/catalina/users/AbstractUser.java0000644000175100017510000001226012271471332024261 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import java.util.Iterator; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.User; /** *

    Convenience base class for {@link User} implementations.

    * * @author Craig R. McClanahan * @since 4.1 */ public abstract class AbstractUser implements User { // ----------------------------------------------------- Instance Variables /** * The full name of this user. */ protected String fullName = null; /** * The logon password of this user. */ protected String password = null; /** * The logon username of this user. */ protected String username = null; // ------------------------------------------------------------- Properties /** * Return the full name of this user. */ @Override public String getFullName() { return (this.fullName); } /** * Set the full name of this user. * * @param fullName The new full name */ @Override public void setFullName(String fullName) { this.fullName = fullName; } /** * Return the set of {@link Group}s to which this user belongs. */ @Override public abstract Iterator getGroups(); /** * Return the logon password of this user, optionally prefixed with the * identifier of an encoding scheme surrounded by curly braces, such as * {md5}xxxxx. */ @Override public String getPassword() { return (this.password); } /** * Set the logon password of this user, optionally prefixed with the * identifier of an encoding scheme surrounded by curly braces, such as * {md5}xxxxx. * * @param password The new logon password */ @Override public void setPassword(String password) { this.password = password; } /** * Return the set of {@link Role}s assigned specifically to this user. */ @Override public abstract Iterator getRoles(); /** * Return the logon username of this user, which must be unique * within the scope of a {@link org.apache.catalina.UserDatabase}. */ @Override public String getUsername() { return (this.username); } /** * Set the logon username of this user, which must be unique within * the scope of a {@link org.apache.catalina.UserDatabase}. * * @param username The new logon username */ @Override public void setUsername(String username) { this.username = username; } // --------------------------------------------------------- Public Methods /** * Add a new {@link Group} to those this user belongs to. * * @param group The new group */ @Override public abstract void addGroup(Group group); /** * Add a new {@link Role} to those assigned specifically to this user. * * @param role The new role */ @Override public abstract void addRole(Role role); /** * Is this user in the specified {@link Group}? * * @param group The group to check */ @Override public abstract boolean isInGroup(Group group); /** * Is this user specifically assigned the specified {@link Role}? This * method does NOT check for roles inherited based on * {@link Group} membership. * * @param role The role to check */ @Override public abstract boolean isInRole(Role role); /** * Remove a {@link Group} from those this user belongs to. * * @param group The old group */ @Override public abstract void removeGroup(Group group); /** * Remove all {@link Group}s from those this user belongs to. */ @Override public abstract void removeGroups(); /** * Remove a {@link Role} from those assigned to this user. * * @param role The old role */ @Override public abstract void removeRole(Role role); /** * Remove all {@link Role}s from those assigned to this user. */ @Override public abstract void removeRoles(); // ------------------------------------------------------ Principal Methods /** * Make the principal name the same as the group name. */ @Override public String getName() { return (getUsername()); } } tomcat7-7.0.52/java/org/apache/catalina/users/MemoryUser.java0000644000175100017510000002125412271471332023771 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import java.util.ArrayList; import java.util.Iterator; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.UserDatabase; import org.apache.catalina.util.RequestUtil; /** *

    Concrete implementation of {@link org.apache.catalina.User} for the * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

    * * @author Craig R. McClanahan * @since 4.1 */ public class MemoryUser extends AbstractUser { // ----------------------------------------------------------- Constructors /** * Package-private constructor used by the factory method in * {@link MemoryUserDatabase}. * * @param database The {@link MemoryUserDatabase} that owns this user * @param username Logon username of the new user * @param password Logon password of the new user * @param fullName Full name of the new user */ MemoryUser(MemoryUserDatabase database, String username, String password, String fullName) { super(); this.database = database; setUsername(username); setPassword(password); setFullName(fullName); } // ----------------------------------------------------- Instance Variables /** * The {@link MemoryUserDatabase} that owns this user. */ protected MemoryUserDatabase database = null; /** * The set of {@link Group}s that this user is a member of. */ protected ArrayList groups = new ArrayList(); /** * The set of {@link Role}s associated with this user. */ protected ArrayList roles = new ArrayList(); // ------------------------------------------------------------- Properties /** * Return the set of {@link Group}s to which this user belongs. */ @Override public Iterator getGroups() { synchronized (groups) { return (groups.iterator()); } } /** * Return the set of {@link Role}s assigned specifically to this user. */ @Override public Iterator getRoles() { synchronized (roles) { return (roles.iterator()); } } /** * Return the {@link UserDatabase} within which this User is defined. */ @Override public UserDatabase getUserDatabase() { return (this.database); } // --------------------------------------------------------- Public Methods /** * Add a new {@link Group} to those this user belongs to. * * @param group The new group */ @Override public void addGroup(Group group) { synchronized (groups) { if (!groups.contains(group)) { groups.add(group); } } } /** * Add a new {@link Role} to those assigned specifically to this user. * * @param role The new role */ @Override public void addRole(Role role) { synchronized (roles) { if (!roles.contains(role)) { roles.add(role); } } } /** * Is this user in the specified group? * * @param group The group to check */ @Override public boolean isInGroup(Group group) { synchronized (groups) { return (groups.contains(group)); } } /** * Is this user specifically assigned the specified {@link Role}? This * method does NOT check for roles inherited based on * {@link Group} membership. * * @param role The role to check */ @Override public boolean isInRole(Role role) { synchronized (roles) { return (roles.contains(role)); } } /** * Remove a {@link Group} from those this user belongs to. * * @param group The old group */ @Override public void removeGroup(Group group) { synchronized (groups) { groups.remove(group); } } /** * Remove all {@link Group}s from those this user belongs to. */ @Override public void removeGroups() { synchronized (groups) { groups.clear(); } } /** * Remove a {@link Role} from those assigned to this user. * * @param role The old role */ @Override public void removeRole(Role role) { synchronized (roles) { roles.remove(role); } } /** * Remove all {@link Role}s from those assigned to this user. */ @Override public void removeRoles() { synchronized (roles) { roles.clear(); } } /** *

    Return a String representation of this user in XML format.

    * *

    IMPLEMENTATION NOTE - For backwards compatibility, * the reader that processes this entry will accept either * username or name for the username * property.

    */ public String toXml() { StringBuilder sb = new StringBuilder(" 0) { sb.append(" groups=\""); int n = 0; Iterator values = groups.iterator(); while (values.hasNext()) { if (n > 0) { sb.append(','); } n++; sb.append(RequestUtil.filter(values.next().getGroupname())); } sb.append("\""); } } synchronized (roles) { if (roles.size() > 0) { sb.append(" roles=\""); int n = 0; Iterator values = roles.iterator(); while (values.hasNext()) { if (n > 0) { sb.append(','); } n++; sb.append(RequestUtil.filter(values.next().getRolename())); } sb.append("\""); } } sb.append("/>"); return (sb.toString()); } /** *

    Return a String representation of this user.

    */ @Override public String toString() { StringBuilder sb = new StringBuilder("User username=\""); sb.append(RequestUtil.filter(username)); sb.append("\""); if (fullName != null) { sb.append(", fullName=\""); sb.append(RequestUtil.filter(fullName)); sb.append("\""); } synchronized (groups) { if (groups.size() > 0) { sb.append(", groups=\""); int n = 0; Iterator values = groups.iterator(); while (values.hasNext()) { if (n > 0) { sb.append(','); } n++; sb.append(RequestUtil.filter(values.next().getGroupname())); } sb.append("\""); } } synchronized (roles) { if (roles.size() > 0) { sb.append(", roles=\""); int n = 0; Iterator values = roles.iterator(); while (values.hasNext()) { if (n > 0) { sb.append(','); } n++; sb.append(RequestUtil.filter(values.next().getRolename())); } sb.append("\""); } } return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/users/MemoryGroup.java0000644000175100017510000001233412271471332024146 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import java.util.ArrayList; import java.util.Iterator; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; /** *

    Concrete implementation of {@link org.apache.catalina.Group} for the * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

    * * @author Craig R. McClanahan * @since 4.1 */ public class MemoryGroup extends AbstractGroup { // ----------------------------------------------------------- Constructors /** * Package-private constructor used by the factory method in * {@link MemoryUserDatabase}. * * @param database The {@link MemoryUserDatabase} that owns this group * @param groupname Group name of this group * @param description Description of this group */ MemoryGroup(MemoryUserDatabase database, String groupname, String description) { super(); this.database = database; setGroupname(groupname); setDescription(description); } // ----------------------------------------------------- Instance Variables /** * The {@link MemoryUserDatabase} that owns this group. */ protected MemoryUserDatabase database = null; /** * The set of {@link Role}s associated with this group. */ protected ArrayList roles = new ArrayList(); // ------------------------------------------------------------- Properties /** * Return the set of {@link Role}s assigned specifically to this group. */ @Override public Iterator getRoles() { synchronized (roles) { return (roles.iterator()); } } /** * Return the {@link UserDatabase} within which this Group is defined. */ @Override public UserDatabase getUserDatabase() { return (this.database); } /** * Return the set of {@link org.apache.catalina.User}s that are members of this group. */ @Override public Iterator getUsers() { ArrayList results = new ArrayList(); Iterator users = database.getUsers(); while (users.hasNext()) { User user = users.next(); if (user.isInGroup(this)) { results.add(user); } } return (results.iterator()); } // --------------------------------------------------------- Public Methods /** * Add a new {@link Role} to those assigned specifically to this group. * * @param role The new role */ @Override public void addRole(Role role) { synchronized (roles) { if (!roles.contains(role)) { roles.add(role); } } } /** * Is this group specifically assigned the specified {@link Role}? * * @param role The role to check */ @Override public boolean isInRole(Role role) { synchronized (roles) { return (roles.contains(role)); } } /** * Remove a {@link Role} from those assigned to this group. * * @param role The old role */ @Override public void removeRole(Role role) { synchronized (roles) { roles.remove(role); } } /** * Remove all {@link Role}s from those assigned to this group. */ @Override public void removeRoles() { synchronized (roles) { roles.clear(); } } /** *

    Return a String representation of this group in XML format.

    */ @Override public String toString() { StringBuilder sb = new StringBuilder(" 0) { sb.append(" roles=\""); int n = 0; Iterator values = roles.iterator(); while (values.hasNext()) { if (n > 0) { sb.append(','); } n++; sb.append((values.next()).getRolename()); } sb.append("\""); } } sb.append("/>"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java0000644000175100017510000001004212271471332026737 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; /** *

    JNDI object creation factory for MemoryUserDatabase * instances. This makes it convenient to configure a user database * in the global JNDI resources associated with this Catalina instance, * and then link to that resource for web applications that administer * the contents of the user database.

    * *

    The MemoryUserDatabase instance is configured based * on the following parameter values:

    *
      *
    • pathname - Absolute or relative (to the directory * path specified by the catalina.base system property) * pathname to the XML file from which our user information is loaded, * and to which it is stored. [conf/tomcat-users.xml]
    • *
    * * @author Craig R. McClanahan * @since 4.1 */ public class MemoryUserDatabaseFactory implements ObjectFactory { // --------------------------------------------------------- Public Methods /** *

    Create and return a new MemoryUserDatabase instance * that has been configured according to the properties of the * specified Reference. If you instance can be created, * return null instead.

    * * @param obj The possibly null object containing location or * reference information that can be used in creating an object * @param name The name of this object relative to nameCtx * @param nameCtx The context relative to which the name * parameter is specified, or null if name * is relative to the default initial context * @param environment The possibly null environment that is used in * creating this object */ @Override public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception { // We only know how to deal with javax.naming.References // that specify a class name of "org.apache.catalina.UserDatabase" if ((obj == null) || !(obj instanceof Reference)) { return (null); } Reference ref = (Reference) obj; if (!"org.apache.catalina.UserDatabase".equals(ref.getClassName())) { return (null); } // Create and configure a MemoryUserDatabase instance based on the // RefAddr values associated with this Reference MemoryUserDatabase database = new MemoryUserDatabase(name.toString()); RefAddr ra = null; ra = ref.get("pathname"); if (ra != null) { database.setPathname(ra.getContent().toString()); } ra = ref.get("readonly"); if (ra != null) { database.setReadonly(Boolean.valueOf(ra.getContent().toString()).booleanValue()); } // Return the configured database instance database.open(); // Don't try something we know won't work if (!database.getReadonly()) database.save(); return (database); } } tomcat7-7.0.52/java/org/apache/catalina/users/mbeans-descriptors.xml0000644000175100017510000001314112271471332025341 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/users/Constants.java0000644000175100017510000000203512271471332023632 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; /** * Manifest constants for this Java package. * * * @author Craig R. McClanahan * @since 4.1 */ public final class Constants { public static final String Package = "org.apache.catalina.users"; } tomcat7-7.0.52/java/org/apache/catalina/users/LocalStrings.properties0000644000175100017510000000324612271471332025542 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. memoryUserDatabase.fileNotFound=The specified user database [{0}] could not be found memoryUserDatabase.notPersistable=User database is not persistable - no write permissions on directory memoryUserDatabase.nullGroup=Null or zero length group name specified. The group will be ignored. memoryUserDatabase.nullRole=Null or zero length role name specified. The role will be ignored. memoryUserDatabase.nullUser=Null or zero length user name specified. The user will be ignored. memoryUserDatabase.readOnly=User database has been configured to be read only. Changes cannot be saved memoryUserDatabase.renameOld=Cannot rename original file to {0} memoryUserDatabase.renameNew=Cannot rename new file to {0} memoryUserDatabase.writeException=IOException writing to {0} memoryUserDatabase.xmlFeatureEncoding=Exception configuring digester to permit java encoding names in XML files. Only IANA encoding names will be supported. tomcat7-7.0.52/java/org/apache/catalina/users/LocalStrings_ja.properties0000644000175100017510000000220212271471332026203 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. memoryUserDatabase.renameOld=\u5143\u306e\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 memoryUserDatabase.renameNew=\u65b0\u3057\u3044\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 memoryUserDatabase.writeException={0} \u306b\u66f8\u304d\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059 tomcat7-7.0.52/java/org/apache/catalina/users/AbstractRole.java0000644000175100017510000000540012271471332024242 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import org.apache.catalina.Role; import org.apache.catalina.UserDatabase; /** *

    Convenience base class for {@link Role} implementations.

    * * @author Craig R. McClanahan * @since 4.1 */ public abstract class AbstractRole implements Role { // ----------------------------------------------------- Instance Variables /** * The description of this Role. */ protected String description = null; /** * The role name of this Role. */ protected String rolename = null; // ------------------------------------------------------------- Properties /** * Return the description of this role. */ @Override public String getDescription() { return (this.description); } /** * Set the description of this role. * * @param description The new description */ @Override public void setDescription(String description) { this.description = description; } /** * Return the role name of this role, which must be unique * within the scope of a {@link UserDatabase}. */ @Override public String getRolename() { return (this.rolename); } /** * Set the role name of this role, which must be unique * within the scope of a {@link UserDatabase}. * * @param rolename The new role name */ @Override public void setRolename(String rolename) { this.rolename = rolename; } /** * Return the {@link UserDatabase} within which this Role is defined. */ @Override public abstract UserDatabase getUserDatabase(); // --------------------------------------------------------- Public Methods // ------------------------------------------------------ Principal Methods /** * Make the principal name the same as the role name. */ @Override public String getName() { return (getRolename()); } } tomcat7-7.0.52/java/org/apache/catalina/users/LocalStrings_fr.properties0000644000175100017510000000177312271471332026234 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. memoryUserDatabase.renameOld=Impossible de renommer le fichier original en {0} memoryUserDatabase.renameNew=Impossible de renommer le nouveau fichier en {0} memoryUserDatabase.writeException=IOException lors de l''\u00e9criture vers {0} tomcat7-7.0.52/java/org/apache/catalina/users/MemoryRole.java0000644000175100017510000000533612271471332023757 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.users; import org.apache.catalina.UserDatabase; /** *

    Concrete implementation of {@link org.apache.catalina.Role} for the * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

    * * @author Craig R. McClanahan * @since 4.1 */ public class MemoryRole extends AbstractRole { // ----------------------------------------------------------- Constructors /** * Package-private constructor used by the factory method in * {@link MemoryUserDatabase}. * * @param database The {@link MemoryUserDatabase} that owns this role * @param rolename Role name of this role * @param description Description of this role */ MemoryRole(MemoryUserDatabase database, String rolename, String description) { super(); this.database = database; setRolename(rolename); setDescription(description); } // ----------------------------------------------------- Instance Variables /** * The {@link MemoryUserDatabase} that owns this role. */ protected MemoryUserDatabase database = null; // ------------------------------------------------------------- Properties /** * Return the {@link UserDatabase} within which this role is defined. */ @Override public UserDatabase getUserDatabase() { return (this.database); } // --------------------------------------------------------- Public Methods /** *

    Return a String representation of this role in XML format.

    */ @Override public String toString() { StringBuilder sb = new StringBuilder(""); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/Valve.java0000644000175100017510000001314512271471332021576 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.io.IOException; import javax.servlet.ServletException; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** *

    A Valve is a request processing component associated with a * particular Container. A series of Valves are generally associated with * each other into a Pipeline. The detailed contract for a Valve is included * in the description of the invoke() method below.

    * * HISTORICAL NOTE: The "Valve" name was assigned to this concept * because a valve is what you use in a real world pipeline to control and/or * modify flows through it. * * @author Craig R. McClanahan * @author Gunnar Rjnning * @author Peter Donald */ public interface Valve { //-------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ public String getInfo(); /** * Return the next Valve in the pipeline containing this Valve, if any. */ public Valve getNext(); /** * Set the next Valve in the pipeline containing this Valve. * * @param valve The new next valve, or null if none */ public void setNext(Valve valve); //---------------------------------------------------------- Public Methods /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ public void backgroundProcess(); /** *

    Perform request processing as required by this Valve.

    * *

    An individual Valve MAY perform the following actions, in * the specified order:

    *
      *
    • Examine and/or modify the properties of the specified Request and * Response. *
    • Examine the properties of the specified Request, completely generate * the corresponding Response, and return control to the caller. *
    • Examine the properties of the specified Request and Response, wrap * either or both of these objects to supplement their functionality, * and pass them on. *
    • If the corresponding Response was not generated (and control was not * returned, call the next Valve in the pipeline (if there is one) by * executing getNext().invoke(). *
    • Examine, but not modify, the properties of the resulting Response * (which was created by a subsequently invoked Valve or Container). *
    * *

    A Valve MUST NOT do any of the following things:

    *
      *
    • Change request properties that have already been used to direct * the flow of processing control for this request (for instance, * trying to change the virtual host to which a Request should be * sent from a pipeline attached to a Host or Context in the * standard implementation). *
    • Create a completed Response AND pass this * Request and Response on to the next Valve in the pipeline. *
    • Consume bytes from the input stream associated with the Request, * unless it is completely generating the response, or wrapping the * request before passing it on. *
    • Modify the HTTP headers included with the Response after the * getNext().invoke() method has returned. *
    • Perform any actions on the output stream associated with the * specified Response after the getNext().invoke() method has * returned. *
    * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet * @exception ServletException if a servlet error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet */ public void invoke(Request request, Response response) throws IOException, ServletException; /** * Process a Comet event. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet * @exception ServletException if a servlet error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet */ public void event(Request request, Response response, CometEvent event) throws IOException, ServletException; public boolean isAsyncSupported(); } tomcat7-7.0.52/java/org/apache/catalina/ContainerServlet.java0000644000175100017510000000311712271471332024006 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * A ContainerServlet is a servlet that has access to Catalina * internal functionality, and is loaded from the Catalina class loader * instead of the web application class loader. The property setter * methods must be called by the container whenever a new instance of * this servlet is put into service. * * @author Craig R. McClanahan */ public interface ContainerServlet { // ------------------------------------------------------------- Properties /** * Return the Wrapper with which this Servlet is associated. */ public Wrapper getWrapper(); /** * Set the Wrapper with which this Servlet is associated. * * @param wrapper The new associated Wrapper */ public void setWrapper(Wrapper wrapper); } tomcat7-7.0.52/java/org/apache/catalina/Globals.java0000644000175100017510000003052612271471332022106 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.Locale; /** * Global constants that are applicable to multiple packages within Catalina. * * @author Craig R. McClanahan */ public final class Globals { /** * The servlet context attribute under which we store the alternate * deployment descriptor for this web application */ public static final String ALT_DD_ATTR = "org.apache.catalina.deploy.alt_dd"; /** * The request attribute under which we store the array of X509Certificate * objects representing the certificate chain presented by our client, * if any. */ public static final String CERTIFICATES_ATTR = "javax.servlet.request.X509Certificate"; /** * The request attribute under which we store the name of the cipher suite * being used on an SSL connection (as an object of type * java.lang.String). */ public static final String CIPHER_SUITE_ATTR = "javax.servlet.request.cipher_suite"; /** * Request dispatcher state. */ public static final String DISPATCHER_TYPE_ATTR = "org.apache.catalina.core.DISPATCHER_TYPE"; /** * Request dispatcher path. */ public static final String DISPATCHER_REQUEST_PATH_ATTR = "org.apache.catalina.core.DISPATCHER_REQUEST_PATH"; /** * The JNDI directory context which is associated with the context. This * context can be used to manipulate static files. */ public static final String RESOURCES_ATTR = "org.apache.catalina.resources"; /** * The servlet context attribute under which we store the class path * for our application class loader (as an object of type String), * delimited with the appropriate path delimiter for this platform. */ public static final String CLASS_PATH_ATTR = "org.apache.catalina.jsp_classpath"; /** * The request attribute under which we store the key size being used for * this SSL connection (as an object of type java.lang.Integer). */ public static final String KEY_SIZE_ATTR = "javax.servlet.request.key_size"; /** * The request attribute under which we store the session id being used * for this SSL connection (as an object of type java.lang.String). */ public static final String SSL_SESSION_ID_ATTR = "javax.servlet.request.ssl_session_id"; /** * Tomcat specific attribute as used in Tomcat 6. * @deprecated */ @Deprecated public static final String SSL_SESSION_ID_TOMCAT_ATTR = "javax.servlet.request.ssl_session"; /** * The request attribute key for the session manager. * This one is a Tomcat extension to the Servlet spec. */ public static final String SSL_SESSION_MGR_ATTR = "javax.servlet.request.ssl_session_mgr"; /** * The servlet context attribute under which the managed bean Registry * will be stored for privileged contexts (if enabled). * @deprecated Unused. Will be removed in Tomcat 8.0.x. */ @Deprecated public static final String MBEAN_REGISTRY_ATTR = "org.apache.catalina.Registry"; /** * The servlet context attribute under which the MBeanServer will be stored * for privileged contexts (if enabled). * @deprecated Unused. Will be removed in Tomcat 8.0.x. */ @Deprecated public static final String MBEAN_SERVER_ATTR = "org.apache.catalina.MBeanServer"; /** * The request attribute under which we store the servlet name on a * named dispatcher request. */ public static final String NAMED_DISPATCHER_ATTR = "org.apache.catalina.NAMED"; /** * The servlet context attribute under which we store a flag used * to mark this request as having been processed by the SSIServlet. * We do this because of the pathInfo mangling happening when using * the CGIServlet in conjunction with the SSI servlet. (value stored * as an object of type String) */ public static final String SSI_FLAG_ATTR = "org.apache.catalina.ssi.SSIServlet"; /** * The subject under which the AccessControlContext is running. */ public static final String SUBJECT_ATTR = "javax.security.auth.subject"; public static final String GSS_CREDENTIAL_ATTR = "org.apache.catalina.realm.GSS_CREDENTIAL"; /** * All request attributes which names start with this prefix are used by * connector implementations. They are passed down to coyoteRequest and back * up. See Request.setAttribute(String, Object). * @deprecated Unused. Will be removed in Tomcat 8.0.x. */ @Deprecated public static final String TOMCAT_CONNECTOR_ATTR_PREFIX = "org.apache.tomcat."; /** * The request attribute that is set to the value of {@code Boolean.TRUE} * if connector processing this request supports Comet API. * Duplicated here for neater code in the catalina packages. */ public static final String COMET_SUPPORTED_ATTR = org.apache.coyote.Constants.COMET_SUPPORTED_ATTR; /** * The request attribute that is set to the value of {@code Boolean.TRUE} * if connector processing this request supports setting * per-connection request timeout through Comet API. * * @see org.apache.catalina.comet.CometEvent#setTimeout(int) * * Duplicated here for neater code in the catalina packages. */ public static final String COMET_TIMEOUT_SUPPORTED_ATTR = org.apache.coyote.Constants.COMET_TIMEOUT_SUPPORTED_ATTR; /** * The request attribute that can be set to a value of type * {@code java.lang.Integer} to specify per-connection request * timeout for Comet API. The value is in milliseconds. * * @see org.apache.catalina.comet.CometEvent#setTimeout(int) * * Duplicated here for neater code in the catalina packages. */ public static final String COMET_TIMEOUT_ATTR = org.apache.coyote.Constants.COMET_TIMEOUT_ATTR; /** * The request attribute that is set to the value of {@code Boolean.TRUE} * if connector processing this request supports use of sendfile. * * Duplicated here for neater code in the catalina packages. */ public static final String SENDFILE_SUPPORTED_ATTR = org.apache.coyote.Constants.SENDFILE_SUPPORTED_ATTR; /** * The request attribute that can be used by a servlet to pass * to the connector the name of the file that is to be served * by sendfile. The value should be {@code java.lang.String} * that is {@code File.getCanonicalPath()} of the file to be served. * * Duplicated here for neater code in the catalina packages. */ public static final String SENDFILE_FILENAME_ATTR = org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR; /** * The request attribute that can be used by a servlet to pass * to the connector the start offset of the part of a file * that is to be served by sendfile. The value should be * {@code java.lang.Long}. To serve complete file * the value should be {@code Long.valueOf(0)}. * * Duplicated here for neater code in the catalina packages. */ public static final String SENDFILE_FILE_START_ATTR = org.apache.coyote.Constants.SENDFILE_FILE_START_ATTR; /** * The request attribute that can be used by a servlet to pass * to the connector the end offset (not including) of the part * of a file that is to be served by sendfile. The value should be * {@code java.lang.Long}. To serve complete file * the value should be equal to the length of the file. * * Duplicated here for neater code in the catalina packages. */ public static final String SENDFILE_FILE_END_ATTR = org.apache.coyote.Constants.SENDFILE_FILE_END_ATTR; /** * The request attribute set by the RemoteIpFilter, RemoteIpValve (and may * be set by other similar components) that identifies for the connector the * remote IP address claimed to be associated with this request when a * request is received via one or more proxies. It is typically provided via * the X-Forwarded-For HTTP header. * * Duplicated here for neater code in the catalina packages. */ public static final String REMOTE_ADDR_ATTRIBUTE = org.apache.coyote.Constants.REMOTE_ADDR_ATTRIBUTE; /** * */ public static final String ASYNC_SUPPORTED_ATTR = "org.apache.catalina.ASYNC_SUPPORTED"; /** * The request attribute that is set to {@code Boolean.TRUE} if some request * parameters have been ignored during request parameters parsing. It can * happen, for example, if there is a limit on the total count of parseable * parameters, or if parameter cannot be decoded, or any other error * happened during parameter parsing. */ public static final String PARAMETER_PARSE_FAILED_ATTR = "org.apache.catalina.parameter_parse_failed"; /** * The master flag which controls strict servlet specification * compliance. */ public static final boolean STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false")).booleanValue(); /** * Has security been turned on? */ public static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); /** * Default domain for MBeans if none can be determined */ public static final String DEFAULT_MBEAN_DOMAIN = "Catalina"; /** * Name of the system property containing * the tomcat product installation path */ public static final String CATALINA_HOME_PROP = "catalina.home"; /** * Name of the system property containing * the tomcat instance installation path */ public static final String CATALINA_BASE_PROP = "catalina.base"; /** * Name of the ServletContext init-param that determines if the JSP engine * should validate *.tld files when parsing them. *

    * This must be kept in sync with org.apache.jasper.Constants */ public static final String JASPER_XML_VALIDATION_TLD_INIT_PARAM = "org.apache.jasper.XML_VALIDATE_TLD"; /** * Name of the ServletContext init-param that determines if the JSP engine * will block external entities from being used in *.tld, *.jspx, *.tagx and * tagplugin.xml files. *

    * This must be kept in sync with org.apache.jasper.Constants */ public static final String JASPER_XML_BLOCK_EXTERNAL_INIT_PARAM = "org.apache.jasper.XML_BLOCK_EXTERNAL"; static { /** * There are a few places where Tomcat either accesses JVM internals * (e.g. the memory leak protection) or where feature support varies * between JVMs (e.g. SPNEGO). These flags exist to enable Tomcat to * adjust its behaviour based on the vendor of the JVM. In an ideal * world this code would not exist. */ String vendor = System.getProperty("java.vendor", ""); vendor = vendor.toLowerCase(Locale.ENGLISH); if (vendor.startsWith("oracle") || vendor.startsWith("sun")) { IS_ORACLE_JVM = true; IS_IBM_JVM = false; } else if (vendor.contains("ibm")) { IS_ORACLE_JVM = false; IS_IBM_JVM = true; } else { IS_ORACLE_JVM = false; IS_IBM_JVM = false; } } public static final boolean IS_ORACLE_JVM; public static final boolean IS_IBM_JVM; } tomcat7-7.0.52/java/org/apache/catalina/InstanceListener.java0000644000175100017510000000237412271471332023775 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * Interface defining a listener for significant events related to a * specific servlet instance, rather than to the Wrapper component that * is managing that instance. * * @author Craig R. McClanahan */ public interface InstanceListener { /** * Acknowledge the occurrence of the specified event. * * @param event InstanceEvent that has occurred */ public void instanceEvent(InstanceEvent event); } tomcat7-7.0.52/java/org/apache/catalina/ha/0000755000175100017510000000000012301126370020233 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/ClusterMessageBase.java0000644000175100017510000000406112271463015024626 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import org.apache.catalina.tribes.Member; /** *

    Title:

    * *

    Description:

    * * *

    Company:

    * * @author not attributable * @version 1.0 */ public class ClusterMessageBase implements ClusterMessage { private static final long serialVersionUID = 1L; protected transient Member address; private String uniqueId; private long timestamp; public ClusterMessageBase() { // NO-OP } /** * getAddress * * @return Member * TODO Implement this org.apache.catalina.ha.ClusterMessage method */ @Override public Member getAddress() { return address; } @Override public String getUniqueId() { return uniqueId; } @Override public long getTimestamp() { return timestamp; } /** * setAddress * * @param member Member * TODO Implement this org.apache.catalina.ha.ClusterMessage method */ @Override public void setAddress(Member member) { this.address = member; } @Override public void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } @Override public void setTimestamp(long timestamp) { this.timestamp = timestamp; } } tomcat7-7.0.52/java/org/apache/catalina/ha/context/0000755000175100017510000000000012301126370021717 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/context/ReplicatedContext.java0000644000175100017510000001674412271463015026225 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.context; import java.util.AbstractMap; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletContext; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.Loader; import org.apache.catalina.core.ApplicationContext; import org.apache.catalina.core.StandardContext; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.tipis.AbstractReplicatedMap.MapOwner; import org.apache.catalina.tribes.tipis.ReplicatedMap; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * @author Filip Hanik * @version 1.0 */ public class ReplicatedContext extends StandardContext implements MapOwner { private int mapSendOptions = Channel.SEND_OPTIONS_DEFAULT; private static final Log log = LogFactory.getLog( ReplicatedContext.class ); protected static long DEFAULT_REPL_TIMEOUT = 15000;//15 seconds /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @SuppressWarnings("unchecked") @Override protected synchronized void startInternal() throws LifecycleException { try { CatalinaCluster catclust = (CatalinaCluster)this.getCluster(); if (this.context == null) this.context = new ReplApplContext(this); if ( catclust != null ) { ReplicatedMap map = new ReplicatedMap(this,catclust.getChannel(),DEFAULT_REPL_TIMEOUT, getName(),getClassLoaders()); map.setChannelSendOptions(mapSendOptions); ((ReplApplContext)this.context).setAttributeMap(map); if (getAltDDName() != null) context.setAttribute(Globals.ALT_DD_ATTR, getAltDDName()); } super.startInternal(); } catch ( Exception x ) { log.error("Unable to start ReplicatedContext",x); throw new LifecycleException("Failed to start ReplicatedContext",x); } } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { super.stopInternal(); AbstractMap map = ((ReplApplContext)this.context).getAttributeMap(); if ( map!=null && map instanceof ReplicatedMap) { ((ReplicatedMap)map).breakdown(); } } public void setMapSendOptions(int mapSendOptions) { this.mapSendOptions = mapSendOptions; } public int getMapSendOptions() { return mapSendOptions; } public ClassLoader[] getClassLoaders() { Loader loader = null; ClassLoader classLoader = null; loader = this.getLoader(); if (loader != null) classLoader = loader.getClassLoader(); if ( classLoader == null ) classLoader = Thread.currentThread().getContextClassLoader(); if ( classLoader == Thread.currentThread().getContextClassLoader() ) { return new ClassLoader[] {classLoader}; } else { return new ClassLoader[] {classLoader,Thread.currentThread().getContextClassLoader()}; } } @Override public ServletContext getServletContext() { if (context == null) { context = new ReplApplContext(this); if (getAltDDName() != null) context.setAttribute(Globals.ALT_DD_ATTR,getAltDDName()); } return ((ReplApplContext)context).getFacade(); } protected static class ReplApplContext extends ApplicationContext { protected ConcurrentHashMap tomcatAttributes = new ConcurrentHashMap(); public ReplApplContext(ReplicatedContext context) { super(context); } protected ReplicatedContext getParent() { return (ReplicatedContext)getContext(); } @Override protected ServletContext getFacade() { return super.getFacade(); } public AbstractMap getAttributeMap() { return (AbstractMap)this.attributes; } public void setAttributeMap(AbstractMap map) { this.attributes = map; } @Override public void removeAttribute(String name) { tomcatAttributes.remove(name); //do nothing super.removeAttribute(name); } @Override public void setAttribute(String name, Object value) { if ( (!getParent().getState().isAvailable()) || "org.apache.jasper.runtime.JspApplicationContextImpl".equals(name) ){ tomcatAttributes.put(name,value); } else super.setAttribute(name,value); } @Override public Object getAttribute(String name) { Object obj = tomcatAttributes.get(name); if (obj == null) { return super.getAttribute(name); } else { return obj; } } @SuppressWarnings("unchecked") @Override public Enumeration getAttributeNames() { Set names = new HashSet(); names.addAll(attributes.keySet()); return new MultiEnumeration(new Enumeration[] { super.getAttributeNames(), Collections.enumeration(names) }); } } protected static class MultiEnumeration implements Enumeration { Enumeration[] e=null; public MultiEnumeration(Enumeration[] lists) { e = lists; } @Override public boolean hasMoreElements() { for ( int i=0; iImplementation of a Valve that logs interesting contents from the * specified Request (before processing) and the corresponding Response * (after processing). It is especially useful in debugging problems * related to headers and cookies.

    * *

    This Valve may be attached to any Container, depending on the granularity * of the logging you wish to perform.

    * *

    primaryIndicator=true, then the request attribute org.apache.catalina.ha.tcp.isPrimarySession. * is set true, when request processing is at sessions primary node. *

    * * @author Craig R. McClanahan * @author Filip Hanik * @author Peter Rossbach */ public class ReplicationValve extends ValveBase implements ClusterValve { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( ReplicationValve.class ); // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.ha.tcp.ReplicationValve/2.0"; /** * The StringManager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); private CatalinaCluster cluster = null ; /** * Filter expression */ protected Pattern filter = null; /** * crossContext session container */ protected ThreadLocal> crossContextSessions = new ThreadLocal>() ; /** * doProcessingStats (default = off) */ protected boolean doProcessingStats = false; protected long totalRequestTime = 0; protected long totalSendTime = 0; protected long nrOfRequests = 0; protected long lastSendTime = 0; protected long nrOfFilterRequests = 0; protected long nrOfSendRequests = 0; protected long nrOfCrossContextSendRequests = 0; /** * must primary change indicator set */ protected boolean primaryIndicator = false ; /** * Name of primary change indicator as request attribute */ protected String primaryIndicatorName = "org.apache.catalina.ha.tcp.isPrimarySession"; // ------------------------------------------------------------- Properties public ReplicationValve() { super(true); } /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * @return Returns the cluster. */ @Override public CatalinaCluster getCluster() { return cluster; } /** * @param cluster The cluster to set. */ @Override public void setCluster(CatalinaCluster cluster) { this.cluster = cluster; } /** * @return Returns the filter */ public String getFilter() { if (filter == null) { return null; } return filter.toString(); } /** * compile filter string to regular expression * @see Pattern#compile(java.lang.String) * @param filter * The filter to set. */ public void setFilter(String filter) { if (log.isDebugEnabled()) log.debug(sm.getString("ReplicationValve.filter.loading", filter)); if (filter == null || filter.length() == 0) { this.filter = null; } else { try { this.filter = Pattern.compile(filter); } catch (PatternSyntaxException pse) { log.error(sm.getString("ReplicationValve.filter.failure", filter), pse); } } } /** * @return Returns the primaryIndicator. */ public boolean isPrimaryIndicator() { return primaryIndicator; } /** * @param primaryIndicator The primaryIndicator to set. */ public void setPrimaryIndicator(boolean primaryIndicator) { this.primaryIndicator = primaryIndicator; } /** * @return Returns the primaryIndicatorName. */ public String getPrimaryIndicatorName() { return primaryIndicatorName; } /** * @param primaryIndicatorName The primaryIndicatorName to set. */ public void setPrimaryIndicatorName(String primaryIndicatorName) { this.primaryIndicatorName = primaryIndicatorName; } /** * Calc processing stats */ public boolean doStatistics() { return doProcessingStats; } /** * Set Calc processing stats * @see #resetStatistics() */ public void setStatistics(boolean doProcessingStats) { this.doProcessingStats = doProcessingStats; } /** * @return Returns the lastSendTime. */ public long getLastSendTime() { return lastSendTime; } /** * @return Returns the nrOfRequests. */ public long getNrOfRequests() { return nrOfRequests; } /** * @return Returns the nrOfFilterRequests. */ public long getNrOfFilterRequests() { return nrOfFilterRequests; } /** * @return Returns the nrOfCrossContextSendRequests. */ public long getNrOfCrossContextSendRequests() { return nrOfCrossContextSendRequests; } /** * @return Returns the nrOfSendRequests. */ public long getNrOfSendRequests() { return nrOfSendRequests; } /** * @return Returns the totalRequestTime. */ public long getTotalRequestTime() { return totalRequestTime; } /** * @return Returns the totalSendTime. */ public long getTotalSendTime() { return totalSendTime; } // --------------------------------------------------------- Public Methods /** * Register all cross context sessions inside endAccess. * Use a list with contains check, that the Portlet API can include a lot of fragments from same or * different applications with session changes. * * @param session cross context session */ public void registerReplicationSession(DeltaSession session) { List sessions = crossContextSessions.get(); if(sessions != null) { if(!sessions.contains(session)) { if(log.isDebugEnabled()) log.debug(sm.getString("ReplicationValve.crossContext.registerSession", session.getIdInternal(), session.getManager().getContainer().getName())); sessions.add(session); } } } /** * Log the interesting request parameters, invoke the next Valve in the * sequence, and log the interesting response parameters. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { long totalstart = 0; //this happens before the request if(doStatistics()) { totalstart = System.currentTimeMillis(); } if (primaryIndicator) { createPrimaryIndicator(request) ; } Context context = request.getContext(); boolean isCrossContext = context != null && context instanceof StandardContext && ((StandardContext) context).getCrossContext(); try { if(isCrossContext) { if(log.isDebugEnabled()) log.debug(sm.getString("ReplicationValve.crossContext.add")); //FIXME add Pool of Arraylists crossContextSessions.set(new ArrayList()); } getNext().invoke(request, response); if(context != null && cluster != null && context.getManager() instanceof ClusterManager) { ClusterManager clusterManager = (ClusterManager) context.getManager(); // valve cluster can access manager - other cluster handle replication // at host level - hopefully! if(cluster.getManager(clusterManager.getName()) == null) return ; if(cluster.hasMembers()) { sendReplicationMessage(request, totalstart, isCrossContext, clusterManager, cluster); } else { resetReplicationRequest(request,isCrossContext); } } } finally { // Array must be remove: Current master request send endAccess at recycle. // Don't register this request session again! if(isCrossContext) { if(log.isDebugEnabled()) log.debug(sm.getString("ReplicationValve.crossContext.remove")); // crossContextSessions.remove() only exist at Java 5 // register ArrayList at a pool crossContextSessions.set(null); } } } /** * reset the active statistics */ public void resetStatistics() { totalRequestTime = 0 ; totalSendTime = 0 ; lastSendTime = 0 ; nrOfFilterRequests = 0 ; nrOfRequests = 0 ; nrOfSendRequests = 0; nrOfCrossContextSendRequests = 0; } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { if (cluster == null) { Cluster containerCluster = getContainer().getCluster(); if (containerCluster instanceof CatalinaCluster) { setCluster((CatalinaCluster)containerCluster); } else { if (log.isWarnEnabled()) { log.warn(sm.getString("ReplicationValve.nocluster")); } } } super.startInternal(); } // --------------------------------------------------------- Protected Methods /** * @param request * @param totalstart * @param isCrossContext * @param clusterManager * @param containerCluster */ protected void sendReplicationMessage(Request request, long totalstart, boolean isCrossContext, ClusterManager clusterManager, CatalinaCluster containerCluster) { //this happens after the request long start = 0; if(doStatistics()) { start = System.currentTimeMillis(); } try { // send invalid sessions // DeltaManager returns String[0] if (!(clusterManager instanceof DeltaManager)) sendInvalidSessions(clusterManager, containerCluster); // send replication sendSessionReplicationMessage(request, clusterManager, containerCluster); if(isCrossContext) sendCrossContextSession(containerCluster); } catch (Exception x) { // FIXME we have a lot of sends, but the trouble with one node stops the correct replication to other nodes! log.error(sm.getString("ReplicationValve.send.failure"), x); } finally { // FIXME this stats update are not cheap!! if(doStatistics()) { updateStats(totalstart,start); } } } /** * Send all changed cross context sessions to backups * @param containerCluster */ protected void sendCrossContextSession(CatalinaCluster containerCluster) { List sessions = crossContextSessions.get(); if(sessions != null && sessions.size() >0) { for(Iterator iter = sessions.iterator(); iter.hasNext() ;) { Session session = iter.next(); if(log.isDebugEnabled()) log.debug(sm.getString("ReplicationValve.crossContext.sendDelta", session.getManager().getContainer().getName() )); sendMessage(session,(ClusterManager)session.getManager(),containerCluster); if(doStatistics()) { nrOfCrossContextSendRequests++; } } } } /** * Fix memory leak for long sessions with many changes, when no backup member exists! * @param request current request after response is generated * @param isCrossContext check crosscontext threadlocal */ protected void resetReplicationRequest(Request request, boolean isCrossContext) { Session contextSession = request.getSessionInternal(false); if(contextSession instanceof DeltaSession){ resetDeltaRequest(contextSession); ((DeltaSession)contextSession).setPrimarySession(true); } if(isCrossContext) { List sessions = crossContextSessions.get(); if(sessions != null && sessions.size() >0) { Iterator iter = sessions.iterator(); for(; iter.hasNext() ;) { Session session = iter.next(); resetDeltaRequest(session); if(session instanceof DeltaSession) ((DeltaSession)contextSession).setPrimarySession(true); } } } } /** * Reset DeltaRequest from session * @param session HttpSession from current request or cross context session */ protected void resetDeltaRequest(Session session) { if(log.isDebugEnabled()) { log.debug(sm.getString("ReplicationValve.resetDeltaRequest" , session.getManager().getContainer().getName() )); } ((DeltaSession)session).resetDeltaRequest(); } /** * Send Cluster Replication Request * @param request current request * @param manager session manager * @param cluster replication cluster */ protected void sendSessionReplicationMessage(Request request, ClusterManager manager, CatalinaCluster cluster) { Session session = request.getSessionInternal(false); if (session != null) { String uri = request.getDecodedRequestURI(); // request without session change if (!isRequestWithoutSessionChange(uri)) { if (log.isDebugEnabled()) log.debug(sm.getString("ReplicationValve.invoke.uri", uri)); sendMessage(session,manager,cluster); } else if(doStatistics()) nrOfFilterRequests++; } } /** * Send message delta message from request session * @param session current session * @param manager session manager * @param cluster replication cluster */ protected void sendMessage(Session session, ClusterManager manager, CatalinaCluster cluster) { String id = session.getIdInternal(); if (id != null) { send(manager, cluster, id); } } /** * send manager requestCompleted message to cluster * @param manager SessionManager * @param cluster replication cluster * @param sessionId sessionid from the manager * @see DeltaManager#requestCompleted(String) * @see SimpleTcpCluster#send(ClusterMessage) */ protected void send(ClusterManager manager, CatalinaCluster cluster, String sessionId) { ClusterMessage msg = manager.requestCompleted(sessionId); if (msg != null) { cluster.send(msg); if(doStatistics()) nrOfSendRequests++; } } /** * check for session invalidations * @param manager * @param cluster */ protected void sendInvalidSessions(ClusterManager manager, CatalinaCluster cluster) { String[] invalidIds=manager.getInvalidatedSessions(); if ( invalidIds.length > 0 ) { for ( int i=0;i 0)) { Manager manager = request.getContext().getManager(); Session session = manager.findSession(id); if (session instanceof ClusterSession) { ClusterSession cses = (ClusterSession) session; if (log.isDebugEnabled()) log.debug(sm.getString( "ReplicationValve.session.indicator", request.getContext().getName(),id, primaryIndicatorName, Boolean.valueOf(cses.isPrimarySession()))); request.setAttribute(primaryIndicatorName, cses.isPrimarySession()?Boolean.TRUE:Boolean.FALSE); } else { if (log.isDebugEnabled()) { if (session != null) { log.debug(sm.getString( "ReplicationValve.session.found", request.getContext().getName(),id)); } else { log.debug(sm.getString( "ReplicationValve.session.invalid", request.getContext().getName(),id)); } } } } } } tomcat7-7.0.52/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java0000644000175100017510000010333412272411157025141 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.tcp; import java.beans.PropertyChangeSupport; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.management.ObjectName; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.LifecycleState; import org.apache.catalina.Manager; import org.apache.catalina.Valve; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterListener; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.ha.ClusterValve; import org.apache.catalina.ha.session.ClusterSessionListener; import org.apache.catalina.ha.session.DeltaManager; import org.apache.catalina.ha.session.JvmRouteBinderValve; import org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener; import org.apache.catalina.ha.session.SessionMessage; import org.apache.catalina.ha.util.IDynamicProperty; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelListener; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; import org.apache.catalina.tribes.group.GroupChannel; import org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor; import org.apache.catalina.tribes.group.interceptors.TcpFailureDetector; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.res.StringManager; /** * A Cluster implementation using simple multicast. Responsible for * setting up a cluster and provides callers with a valid multicast * receiver/sender. * * FIXME wrote testcases * * @author Filip Hanik * @author Remy Maucherat * @author Peter Rossbach */ public class SimpleTcpCluster extends LifecycleMBeanBase implements CatalinaCluster, LifecycleListener, IDynamicProperty, MembershipListener, ChannelListener{ public static final Log log = LogFactory.getLog(SimpleTcpCluster.class); // ----------------------------------------------------- Instance Variables /** * Descriptive information about this component implementation. */ protected static final String info = "SimpleTcpCluster/2.2"; public static final String BEFORE_MEMBERREGISTER_EVENT = "before_member_register"; public static final String AFTER_MEMBERREGISTER_EVENT = "after_member_register"; public static final String BEFORE_MANAGERREGISTER_EVENT = "before_manager_register"; public static final String AFTER_MANAGERREGISTER_EVENT = "after_manager_register"; public static final String BEFORE_MANAGERUNREGISTER_EVENT = "before_manager_unregister"; public static final String AFTER_MANAGERUNREGISTER_EVENT = "after_manager_unregister"; public static final String BEFORE_MEMBERUNREGISTER_EVENT = "before_member_unregister"; public static final String AFTER_MEMBERUNREGISTER_EVENT = "after_member_unregister"; public static final String SEND_MESSAGE_FAILURE_EVENT = "send_message_failure"; public static final String RECEIVE_MESSAGE_FAILURE_EVENT = "receive_message_failure"; /** * Group channel. */ protected Channel channel = new GroupChannel(); /** * Name for logging purpose */ protected String clusterImpName = "SimpleTcpCluster"; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The cluster name to join */ protected String clusterName ; /** * call Channel.heartbeat() at container background thread * @see org.apache.catalina.tribes.group.GroupChannel#heartbeat() */ protected boolean heartbeatBackgroundEnabled =false ; /** * The Container associated with this Cluster. */ protected Container container = null; /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); /** * The context name <->manager association for distributed contexts. */ protected Map managers = new HashMap(); protected ClusterManager managerTemplate = new DeltaManager(); private List valves = new ArrayList(); private org.apache.catalina.ha.ClusterDeployer clusterDeployer; private ObjectName onameClusterDeployer; /** * Listeners of messages */ protected List clusterListeners = new ArrayList(); /** * Comment for notifyLifecycleListenerOnFailure */ private boolean notifyLifecycleListenerOnFailure = false; /** * dynamic sender properties * * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated private Map properties = new HashMap(); private int channelSendOptions = Channel.SEND_OPTIONS_ASYNCHRONOUS; private int channelStartOptions = Channel.DEFAULT; private Map memberOnameMap = new ConcurrentHashMap(); // ------------------------------------------------------------- Properties public SimpleTcpCluster() { // NO-OP } /** * Return descriptive information about this Cluster implementation and the * corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return heartbeat enable flag (default false) * @return the heartbeatBackgroundEnabled */ public boolean isHeartbeatBackgroundEnabled() { return heartbeatBackgroundEnabled; } /** * enabled that container backgroundThread call heartbeat at channel * @param heartbeatBackgroundEnabled the heartbeatBackgroundEnabled to set */ public void setHeartbeatBackgroundEnabled(boolean heartbeatBackgroundEnabled) { this.heartbeatBackgroundEnabled = heartbeatBackgroundEnabled; } /** * Set the name of the cluster to join, if no cluster with this name is * present create one. * * @param clusterName * The clustername to join */ @Override public void setClusterName(String clusterName) { this.clusterName = clusterName; } /** * Return the name of the cluster that this Server is currently configured * to operate within. * * @return The name of the cluster associated with this server */ @Override public String getClusterName() { if(clusterName == null && container != null) return container.getName() ; return clusterName; } /** * Set the Container associated with our Cluster * * @param container * The Container to use */ @Override public void setContainer(Container container) { Container oldContainer = this.container; this.container = container; support.firePropertyChange("container", oldContainer, this.container); } /** * Get the Container associated with our Cluster * * @return The Container associated with our Cluster */ @Override public Container getContainer() { return (this.container); } /** * @return Returns the notifyLifecycleListenerOnFailure. */ public boolean isNotifyLifecycleListenerOnFailure() { return notifyLifecycleListenerOnFailure; } /** * @param notifyListenerOnFailure * The notifyLifecycleListenerOnFailure to set. */ public void setNotifyLifecycleListenerOnFailure( boolean notifyListenerOnFailure) { boolean oldNotifyListenerOnFailure = this.notifyLifecycleListenerOnFailure; this.notifyLifecycleListenerOnFailure = notifyListenerOnFailure; support.firePropertyChange("notifyLifecycleListenerOnFailure", oldNotifyListenerOnFailure, this.notifyLifecycleListenerOnFailure); } /** * Add cluster valve * Cluster Valves are only add to container when cluster is started! * @param valve The new cluster Valve. */ @Override public void addValve(Valve valve) { if (valve instanceof ClusterValve && (!valves.contains(valve))) valves.add(valve); } /** * get all cluster valves * @return current cluster valves */ @Override public Valve[] getValves() { return valves.toArray(new Valve[valves.size()]); } /** * Get the cluster listeners associated with this cluster. If this Array has * no listeners registered, a zero-length array is returned. */ public ClusterListener[] findClusterListeners() { if (clusterListeners.size() > 0) { ClusterListener[] listener = new ClusterListener[clusterListeners.size()]; clusterListeners.toArray(listener); return listener; } else return new ClusterListener[0]; } /** * Add cluster message listener and register cluster to this listener. * * @see org.apache.catalina.ha.CatalinaCluster#addClusterListener(org.apache.catalina.ha.ClusterListener) */ @Override public void addClusterListener(ClusterListener listener) { if (listener != null && !clusterListeners.contains(listener)) { clusterListeners.add(listener); listener.setCluster(this); } } /** * Remove message listener and deregister Cluster from listener. * * @see org.apache.catalina.ha.CatalinaCluster#removeClusterListener(org.apache.catalina.ha.ClusterListener) */ @Override public void removeClusterListener(ClusterListener listener) { if (listener != null) { clusterListeners.remove(listener); listener.setCluster(null); } } /** * get current Deployer */ @Override public org.apache.catalina.ha.ClusterDeployer getClusterDeployer() { return clusterDeployer; } /** * set a new Deployer, must be set before cluster started! */ @Override public void setClusterDeployer( org.apache.catalina.ha.ClusterDeployer clusterDeployer) { this.clusterDeployer = clusterDeployer; } @Override public void setChannel(Channel channel) { this.channel = channel; } public void setManagerTemplate(ClusterManager managerTemplate) { this.managerTemplate = managerTemplate; } public void setChannelSendOptions(int channelSendOptions) { this.channelSendOptions = channelSendOptions; } /** * has members */ protected boolean hasMembers = false; @Override public boolean hasMembers() { return hasMembers; } /** * Get all current cluster members * @return all members or empty array */ @Override public Member[] getMembers() { return channel.getMembers(); } /** * Return the member that represents this node. * * @return Member */ @Override public Member getLocalMember() { return channel.getLocalMember(true); } // ------------------------------------------------------------- dynamic // manager property handling /** * JMX hack to direct use at jconsole * * @param name * @param value * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public boolean setProperty(String name, String value) { return setProperty(name, (Object) value); } /** * set config attributes with reflect and propagate to all managers * * @param name * @param value * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Override @Deprecated public boolean setProperty(String name, Object value) { if (log.isTraceEnabled()) log.trace(sm.getString("SimpleTcpCluster.setProperty", name, value,properties.get(name))); properties.put(name, value); //using a dynamic way of setting properties is nice, but a security risk //if exposed through JMX. This way you can sit and try to guess property names, //we will only allow explicit property names log.warn("Dynamic setProperty("+name+",value) has been disabled, please use explicit properties for the element you are trying to identify"); return false; } /** * get current config * * @param key * @return The property * * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Override @Deprecated public Object getProperty(String key) { if (log.isTraceEnabled()) log.trace(sm.getString("SimpleTcpCluster.getProperty", key)); return properties.get(key); } /** * Get all properties keys * * @return An iterator over the property names. * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Override @Deprecated public Iterator getPropertyNames() { return properties.keySet().iterator(); } /** * remove a configured property. * * @param key * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Override @Deprecated public void removeProperty(String key) { properties.remove(key); } /** * transfer properties from cluster configuration to subelement bean. * @param prefix * @param bean * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected void transferProperty(String prefix, Object bean) { if (prefix != null) { for (Iterator iter = getPropertyNames(); iter.hasNext();) { String pkey = iter.next(); if (pkey.startsWith(prefix)) { String key = pkey.substring(prefix.length() + 1); Object value = getProperty(pkey); IntrospectionUtils.setProperty(bean, key, value.toString()); } } } } // --------------------------------------------------------- Public Methods /** * @return Returns the managers. */ @Override public Map getManagers() { return managers; } @Override public Channel getChannel() { return channel; } public ClusterManager getManagerTemplate() { return managerTemplate; } public int getChannelSendOptions() { return channelSendOptions; } /** * Create new Manager without add to cluster (comes with start the manager) * * @param name * Context Name of this manager * @see org.apache.catalina.Cluster#createManager(java.lang.String) * @see DeltaManager#start() */ @Override public synchronized Manager createManager(String name) { if (log.isDebugEnabled()) { log.debug("Creating ClusterManager for context " + name + " using class " + getManagerTemplate().getClass().getName()); } ClusterManager manager = null; try { manager = managerTemplate.cloneFromTemplate(); manager.setName(name); } catch (Exception x) { log.error("Unable to clone cluster manager, defaulting to org.apache.catalina.ha.session.DeltaManager", x); manager = new org.apache.catalina.ha.session.DeltaManager(); } finally { if ( manager != null) manager.setCluster(this); } return manager; } @Override public void registerManager(Manager manager) { if (! (manager instanceof ClusterManager)) { log.warn("Manager [ " + manager + "] does not implement ClusterManager, addition to cluster has been aborted."); return; } ClusterManager cmanager = (ClusterManager) manager ; cmanager.setDistributable(true); // Notify our interested LifecycleListeners fireLifecycleEvent(BEFORE_MANAGERREGISTER_EVENT, manager); String clusterName = getManagerName(cmanager.getName(), manager); cmanager.setName(clusterName); cmanager.setCluster(this); managers.put(clusterName, cmanager); // Notify our interested LifecycleListeners fireLifecycleEvent(AFTER_MANAGERREGISTER_EVENT, manager); } /** * Remove an application from cluster replication bus. * * @see org.apache.catalina.Cluster#removeManager(Manager) */ @Override public void removeManager(Manager manager) { if (manager != null && manager instanceof ClusterManager ) { ClusterManager cmgr = (ClusterManager) manager; // Notify our interested LifecycleListeners fireLifecycleEvent(BEFORE_MANAGERUNREGISTER_EVENT,manager); managers.remove(getManagerName(cmgr.getName(),manager)); cmgr.setCluster(null); // Notify our interested LifecycleListeners fireLifecycleEvent(AFTER_MANAGERUNREGISTER_EVENT, manager); } } /** * @param name * @param manager * @return TODO */ @Override public String getManagerName(String name, Manager manager) { String clusterName = name ; if ( clusterName == null ) clusterName = manager.getContainer().getName(); if(getContainer() instanceof Engine) { Container context = manager.getContainer() ; if(context != null && context instanceof Context) { Container host = ((Context)context).getParent(); if(host != null && host instanceof Host && clusterName!=null && !(clusterName.startsWith(host.getName() +"#"))) { clusterName = host.getName() +"#" + clusterName ; } } } return clusterName; } /* * Get Manager * * @see org.apache.catalina.ha.CatalinaCluster#getManager(java.lang.String) */ @Override public Manager getManager(String name) { return managers.get(name); } // ------------------------------------------------------ Lifecycle Methods /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. * @see org.apache.catalina.ha.deploy.FarmWarDeployer#backgroundProcess() * @see org.apache.catalina.tribes.group.GroupChannel#heartbeat() * @see org.apache.catalina.tribes.group.GroupChannel.HeartbeatThread#run() * */ @Override public void backgroundProcess() { if (clusterDeployer != null) clusterDeployer.backgroundProcess(); //send a heartbeat through the channel if ( isHeartbeatBackgroundEnabled() && channel !=null ) channel.heartbeat(); // periodic event fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); } /** * Use as base to handle start/stop/periodic Events from host. Currently * only log the messages as trace level. * * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent) */ @Override public void lifecycleEvent(LifecycleEvent lifecycleEvent) { if (log.isTraceEnabled()) log.trace(sm.getString("SimpleTcpCluster.event.log", lifecycleEvent.getType(), lifecycleEvent.getData())); } // ------------------------------------------------------ public @SuppressWarnings("deprecation") @Override protected void initInternal() throws LifecycleException { super.initInternal(); if (clusterDeployer != null) { StringBuilder name = new StringBuilder("type=Cluster"); Container container = getContainer(); name.append(MBeanUtils.getContainerKeyProperties(container)); name.append(",component=Deployer"); onameClusterDeployer = register(clusterDeployer, name.toString()); } } /** * Start Cluster and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { if (log.isInfoEnabled()) log.info("Cluster is about to start"); try { checkDefaults(); registerClusterValve(); channel.addMembershipListener(this); channel.addChannelListener(this); channel.start(channelStartOptions); if (clusterDeployer != null) clusterDeployer.start(); registerMember(channel.getLocalMember(false)); } catch (Exception x) { log.error("Unable to start cluster.", x); throw new LifecycleException(x); } setState(LifecycleState.STARTING); } protected void checkDefaults() { if ( clusterListeners.size() == 0 ) { addClusterListener(new JvmRouteSessionIDBinderListener()); addClusterListener(new ClusterSessionListener()); } if ( valves.size() == 0 ) { addValve(new JvmRouteBinderValve()); addValve(new ReplicationValve()); } if ( clusterDeployer != null ) clusterDeployer.setCluster(this); if ( channel == null ) channel = new GroupChannel(); if ( channel instanceof GroupChannel && !((GroupChannel)channel).getInterceptors().hasNext()) { channel.addInterceptor(new MessageDispatch15Interceptor()); channel.addInterceptor(new TcpFailureDetector()); } } /** * register all cluster valve to host or engine * @throws Exception * @throws ClassNotFoundException */ protected void registerClusterValve() throws Exception { if(container != null ) { for (Iterator iter = valves.iterator(); iter.hasNext();) { ClusterValve valve = (ClusterValve) iter.next(); if (log.isDebugEnabled()) log.debug("Invoking addValve on " + getContainer() + " with class=" + valve.getClass().getName()); if (valve != null) { IntrospectionUtils.callMethodN(getContainer(), "addValve", new Object[] { valve }, new Class[] { org.apache.catalina.Valve.class }); valve.setCluster(this); } } } } /** * unregister all cluster valve to host or engine * @throws Exception * @throws ClassNotFoundException */ protected void unregisterClusterValve() throws Exception { for (Iterator iter = valves.iterator(); iter.hasNext();) { ClusterValve valve = (ClusterValve) iter.next(); if (log.isDebugEnabled()) log.debug("Invoking removeValve on " + getContainer() + " with class=" + valve.getClass().getName()); if (valve != null) { IntrospectionUtils.callMethodN(getContainer(), "removeValve", new Object[] { valve }, new Class[] { org.apache.catalina.Valve.class }); valve.setCluster(this); } } } /** * Stop Cluster and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); unregisterMember(channel.getLocalMember(false)); if (clusterDeployer != null) clusterDeployer.stop(); this.managers.clear(); try { if ( clusterDeployer != null ) clusterDeployer.setCluster(null); channel.stop(channelStartOptions); channel.removeChannelListener(this); channel.removeMembershipListener(this); this.unregisterClusterValve(); } catch (Exception x) { log.error("Unable to stop cluster.", x); } } @Override protected void destroyInternal() throws LifecycleException { if (onameClusterDeployer != null) { unregister(onameClusterDeployer); onameClusterDeployer = null; } super.destroyInternal(); } /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append('['); if (container == null) { sb.append("Container is null"); } else { sb.append(container.getName()); } sb.append(']'); return sb.toString(); } /** * send message to all cluster members * @param msg message to transfer * * @see org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage) */ @Override public void send(ClusterMessage msg) { send(msg, null); } /** * send a cluster message to one member * * @param msg message to transfer * @param dest Receiver member * @see org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage, * org.apache.catalina.tribes.Member) */ @Override public void send(ClusterMessage msg, Member dest) { try { msg.setAddress(getLocalMember()); int sendOptions = channelSendOptions; if (msg instanceof SessionMessage && ((SessionMessage)msg).getEventType() == SessionMessage.EVT_ALL_SESSION_DATA) { sendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK|Channel.SEND_OPTIONS_USE_ACK; } if (dest != null) { if (!getLocalMember().equals(dest)) { channel.send(new Member[] {dest}, msg, sendOptions); } else log.error("Unable to send message to local member " + msg); } else { Member[] destmembers = channel.getMembers(); if (destmembers.length>0) channel.send(destmembers,msg, sendOptions); else if (log.isDebugEnabled()) log.debug("No members in cluster, ignoring message:"+msg); } } catch (Exception x) { log.error("Unable to send message through cluster sender.", x); } } /** * New cluster member is registered * * @see org.apache.catalina.tribes.MembershipListener#memberAdded(org.apache.catalina.tribes.Member) */ @Override public void memberAdded(Member member) { try { hasMembers = channel.hasMembers(); if (log.isInfoEnabled()) log.info("Replication member added:" + member); // Notify our interested LifecycleListeners fireLifecycleEvent(BEFORE_MEMBERREGISTER_EVENT, member); registerMember(member); // Notify our interested LifecycleListeners fireLifecycleEvent(AFTER_MEMBERREGISTER_EVENT, member); } catch (Exception x) { log.error("Unable to connect to replication system.", x); } } /** * Cluster member is gone * * @see org.apache.catalina.tribes.MembershipListener#memberDisappeared(org.apache.catalina.tribes.Member) */ @Override public void memberDisappeared(Member member) { try { hasMembers = channel.hasMembers(); if (log.isInfoEnabled()) log.info("Received member disappeared:" + member); // Notify our interested LifecycleListeners fireLifecycleEvent(BEFORE_MEMBERUNREGISTER_EVENT, member); unregisterMember(member); // Notify our interested LifecycleListeners fireLifecycleEvent(AFTER_MEMBERUNREGISTER_EVENT, member); } catch (Exception x) { log.error("Unable remove cluster node from replication system.", x); } } // --------------------------------------------------------- receiver // messages /** * notify all listeners from receiving a new message is not ClusterMessage * emit Failure Event to LifecylceListener * * @param msg * received Message */ @Override public boolean accept(Serializable msg, Member sender) { return (msg instanceof ClusterMessage); } @Override public void messageReceived(Serializable message, Member sender) { ClusterMessage fwd = (ClusterMessage)message; fwd.setAddress(sender); messageReceived(fwd); } public void messageReceived(ClusterMessage message) { if (log.isDebugEnabled() && message != null) log.debug("Assuming clocks are synched: Replication for " + message.getUniqueId() + " took=" + (System.currentTimeMillis() - (message).getTimestamp()) + " ms."); //invoke all the listeners boolean accepted = false; if (message != null) { for (Iterator iter = clusterListeners.iterator(); iter.hasNext();) { ClusterListener listener = iter.next(); if (listener.accept(message)) { accepted = true; listener.messageReceived(message); } } if (!accepted && notifyLifecycleListenerOnFailure) { Member dest = message.getAddress(); // Notify our interested LifecycleListeners fireLifecycleEvent(RECEIVE_MESSAGE_FAILURE_EVENT, new SendMessageData(message, dest, null)); if (log.isDebugEnabled()) { log.debug("Message " + message.toString() + " from type " + message.getClass().getName() + " transfered but no listener registered"); } } } return; } // --------------------------------------------------------- Logger @Override public Log getLogger() { return log; } // ------------------------------------------------------------- deprecated /** * * @see org.apache.catalina.Cluster#setProtocol(java.lang.String) */ @Override public void setProtocol(String protocol) { // NO-OP } /** * @see org.apache.catalina.Cluster#getProtocol() */ @Override public String getProtocol() { return null; } public int getChannelStartOptions() { return channelStartOptions; } public void setChannelStartOptions(int channelStartOptions) { this.channelStartOptions = channelStartOptions; } // --------------------------------------------------------------------- JMX @SuppressWarnings("deprecation") @Override protected String getDomainInternal() { Container container = getContainer(); if (container == null) { return null; } return MBeanUtils.getDomain(container); } @SuppressWarnings("deprecation") @Override protected String getObjectNameKeyProperties() { StringBuilder name = new StringBuilder("type=Cluster"); Container container = getContainer(); if (container != null) { name.append(MBeanUtils.getContainerKeyProperties(container)); } return name.toString(); } @SuppressWarnings("deprecation") private void registerMember(Member member) { // JMX registration StringBuilder name = new StringBuilder("type=Cluster"); Container container = getContainer(); if (container != null) { name.append(MBeanUtils.getContainerKeyProperties(container)); } name.append(",component=Member,name="); name.append(ObjectName.quote(member.getName())); ObjectName oname = register(member, name.toString()); memberOnameMap.put(member, oname); } private void unregisterMember(Member member) { if (member == null) return; ObjectName oname = memberOnameMap.remove(member); if (oname != null) { unregister(oname); } } } tomcat7-7.0.52/java/org/apache/catalina/ha/tcp/mbeans-descriptors.xml0000644000175100017510000001307212271463015025360 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/ha/tcp/Constants.java0000644000175100017510000000204712271463015023651 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.tcp; /** * Manifest constants for the org.apache.catalina.ha.tcp * package. * * @author Peter Rossbach */ public class Constants { public static final String Package = "org.apache.catalina.ha.tcp"; } tomcat7-7.0.52/java/org/apache/catalina/ha/tcp/LocalStrings.properties0000644000175100017510000000606312271463015025556 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. ReplicationValve.crossContext.add=add Cross Context session replication container to replicationValve threadlocal ReplicationValve.crossContext.registerSession=register Cross context session id={0} from context {1} ReplicationValve.crossContext.remove=remove Cross Context session replication container from replicationValve threadlocal ReplicationValve.crossContext.sendDelta=send Cross Context session delta from context {0}. ReplicationValve.filter.loading=Loading request filter={0} ReplicationValve.filter.failure=Unable to compile filter={0} ReplicationValve.invoke.uri=Invoking replication request on {0} ReplicationValve.nocluster=No cluster configured for this request. ReplicationValve.resetDeltaRequest=Cluster is standalone: reset Session Request Delta at context {0} ReplicationValve.send.failure=Unable to perform replication request. ReplicationValve.send.invalid.failure=Unable to send session [id={0}] invalid message over cluster. ReplicationValve.session.found=Context {0}: Found session {1} but it isn't a ClusterSession. ReplicationValve.session.indicator=Context {0}: Primarity of session {0} in request attribute {1} is {2}. ReplicationValve.session.invalid=Context {0}: Requested session {1} is invalid, removed or not replicated at this node. ReplicationValve.stats=Average request time= {0} ms for Cluster overhead time={1} ms for {2} requests {3} filter requests {4} send requests {5} cross context requests (Request={6} ms Cluster={7} ms). SimpleTcpCluster.event.log=Cluster receive listener event {0} with data {1} SimpleTcpCluster.getProperty=get property {0} SimpleTcpCluster.setProperty=set property {0}: {1} old value {2} SimpleTcpCluster.default.addClusterListener=Add Default ClusterListener at cluster {0} SimpleTcpCluster.default.addClusterValves=Add Default ClusterValves at cluster {0} SimpleTcpCluster.default.addClusterReceiver=Add Default ClusterReceiver at cluster {0} SimpleTcpCluster.default.addClusterSender=Add Default ClusterSender at cluster {0} SimpleTcpCluster.default.addMembershipService=Add Default Membership Service at cluster {0} SimpleTcpCluster.log.receive=RECEIVE {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} {5} SimpleTcpCluster.log.send=SEND {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} SimpleTcpCluster.log.send.all=SEND {0,date}:{0,time} {1,number} - {2} tomcat7-7.0.52/java/org/apache/catalina/ha/tcp/SendMessageData.java0000644000175100017510000000424012271463015024662 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.tcp; import org.apache.catalina.tribes.Member; /** * @author Peter Rossbach */ public class SendMessageData { private Object message ; private Member destination ; private Exception exception ; /** * @param message * @param destination * @param exception */ public SendMessageData(Object message, Member destination, Exception exception) { super(); this.message = message; this.destination = destination; this.exception = exception; } /** * @return Returns the destination. */ public Member getDestination() { return destination; } /** * @param destination The destination to set. */ public void setDestination(Member destination) { this.destination = destination; } /** * @return Returns the exception. */ public Exception getException() { return exception; } /** * @param exception The exception to set. */ public void setException(Exception exception) { this.exception = exception; } /** * @return Returns the message. */ public Object getMessage() { return message; } /** * @param message The message to set. */ public void setMessage(Object message) { this.message = message; } } tomcat7-7.0.52/java/org/apache/catalina/ha/ClusterValve.java0000644000175100017510000000267712271463015023537 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import org.apache.catalina.Valve; /** * Cluster valves are a simple extension to the Tomcat valve architecture * with a small addition of being able to reference the cluster component in the container it sits in. * @author Filip Hanik * @author Peter Rossbach */ public interface ClusterValve extends Valve{ /** * Returns the cluster the cluster deployer is associated with * @return CatalinaCluster */ public CatalinaCluster getCluster(); /** * Associates the cluster deployer with a cluster * @param cluster CatalinaCluster */ public void setCluster(CatalinaCluster cluster); } tomcat7-7.0.52/java/org/apache/catalina/ha/ClusterManager.java0000644000175100017510000000601412271463015024021 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import java.io.IOException; import org.apache.catalina.Manager; import org.apache.catalina.tribes.io.ReplicationStream; /** * The common interface used by all cluster manager. * This is so that we can have a more pluggable way * of swapping session managers for different algorithms. * * @author Filip Hanik * @author Peter Rossbach */ public interface ClusterManager extends Manager { /** * A message was received from another node, this * is the callback method to implement if you are interested in * receiving replication messages. * @param msg - the message received. */ public void messageDataReceived(ClusterMessage msg); /** * When the request has been completed, the replication valve * will notify the manager, and the manager will decide whether * any replication is needed or not. * If there is a need for replication, the manager will * create a session message and that will be replicated. * The cluster determines where it gets sent. * @param sessionId - the sessionId that just completed. * @return a SessionMessage to be sent. */ public ClusterMessage requestCompleted(String sessionId); /** * When the manager expires session not tied to a request. * The cluster will periodically ask for a list of sessions * that should expire and that should be sent across the wire. * @return String[] The invalidated sessions */ public String[] getInvalidatedSessions(); /** * Return the name of the manager, at host /context name and at engine hostname+/context. * @return String * @since 5.5.10 */ public String getName(); /** * Set the name of the manager, at host /context name and at engine hostname+/context * @param name * @since 5.5.10 */ public void setName(String name); public CatalinaCluster getCluster(); public void setCluster(CatalinaCluster cluster); public ReplicationStream getReplicationStream(byte[] data) throws IOException; public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException; public boolean isNotifyListenersOnReplication(); public ClusterManager cloneFromTemplate(); } tomcat7-7.0.52/java/org/apache/catalina/ha/ClusterDeployer.java0000644000175100017510000001017012274222760024233 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import java.io.File; import java.io.IOException; import org.apache.catalina.LifecycleException; import org.apache.catalina.tribes.ChannelListener; /** * A ClusterDeployer interface allows to plug in and out the * different deployment implementations * * @author Filip Hanik */ public interface ClusterDeployer extends ChannelListener { /** * Descriptive information about this component implementation. */ public String info = "ClusterDeployer/1.0"; /** * Start the cluster deployer, the owning container will invoke this * @throws Exception - if failure to start cluster */ public void start() throws Exception; /** * Stops the cluster deployer, the owning container will invoke this * @throws LifecycleException */ public void stop() throws LifecycleException; /** * Install a new web application, whose web application archive is at the * specified URL, into this container and all the other * members of the cluster with the specified context name. *

    * If this application is successfully installed locally, * a ContainerEvent of type * INSTALL_EVENT will be sent to all registered listeners, * with the newly created Context as an argument. * * @param contextName The context name to which this application should * be installed (must be unique) * @param webapp A WAR file or unpacked directory structure containing * the web application to be installed * * @exception IllegalArgumentException if the specified context name * is malformed * @exception IllegalStateException if the specified context name * is already attached to an existing web application * @exception IOException if an input/output error was encountered * during installation */ public void install(String contextName, File webapp) throws IOException; /** * Remove an existing web application, attached to the specified context * name. If this application is successfully removed, a * ContainerEvent of type REMOVE_EVENT will be sent to all * registered listeners, with the removed Context as * an argument. Deletes the web application war file and/or directory * if they exist in the Host's appBase. * * @param contextName The context name of the application to be removed * @param undeploy boolean flag to remove web application from server * * @exception IllegalArgumentException if the specified context name * is malformed * @exception IllegalArgumentException if the specified context name does * not identify a currently installed web application * @exception IOException if an input/output error occurs during * removal */ public void remove(String contextName, boolean undeploy) throws IOException; /** * call from container Background Process */ public void backgroundProcess(); /** * Returns the cluster the cluster deployer is associated with * @return CatalinaCluster */ public CatalinaCluster getCluster(); /** * Associates the cluster deployer with a cluster * @param cluster CatalinaCluster */ public void setCluster(CatalinaCluster cluster); } tomcat7-7.0.52/java/org/apache/catalina/ha/package.html0000644000175100017510000000175612271463015022533 0ustar locutuslocutus

    This package contains code for Clustering, the base class of a Cluster is org.apache.catalina.Cluster implementations of this class is done when implementing a new Cluster protocol

    tomcat7-7.0.52/java/org/apache/catalina/ha/backend/0000755000175100017510000000000012301126370021622 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/backend/MultiCastSender.java0000644000175100017510000000540212271463015025542 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.backend; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.nio.charset.Charset; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /* * Sender to proxies using multicast socket. */ public class MultiCastSender implements Sender { private static final Log log = LogFactory.getLog(HeartbeatListener.class); private static final Charset US_ASCII = Charset.forName("US-ASCII"); HeartbeatListener config = null; /* for multicasting stuff */ MulticastSocket s = null; InetAddress group = null; @Override public void init(HeartbeatListener config) throws Exception { this.config = config; } @Override public int send(String mess) throws Exception { if (s == null) { try { group = InetAddress.getByName(config.getGroup()); if (config.host != null) { InetAddress addr = InetAddress.getByName(config.host); InetSocketAddress addrs = new InetSocketAddress(addr, config.getMultiport()); s = new MulticastSocket(addrs); } else s = new MulticastSocket(config.getMultiport()); s.setTimeToLive(config.getTtl()); s.joinGroup(group); } catch (Exception ex) { log.error("Unable to use multicast: " + ex); s = null; return -1; } } byte[] buf; buf = mess.getBytes(US_ASCII); DatagramPacket data = new DatagramPacket(buf, buf.length, group, config.getMultiport()); try { s.send(data); } catch (Exception ex) { log.error("Unable to send colllected load information: " + ex); s.close(); s = null; return -1; } return 0; } } tomcat7-7.0.52/java/org/apache/catalina/ha/backend/TcpSender.java0000644000175100017510000001701312271463015024364 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.backend; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.util.StringTokenizer; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /* * Sender to proxies using multicast socket. */ public class TcpSender implements Sender { private static final Log log = LogFactory.getLog(HeartbeatListener.class); HeartbeatListener config = null; /** * Proxies. */ protected Proxy[] proxies = null; /** * Active connections. */ protected Socket[] connections = null; protected BufferedReader[] connectionReaders = null; protected BufferedWriter[] connectionWriters = null; @Override public void init(HeartbeatListener config) throws Exception { this.config = config; StringTokenizer tok = new StringTokenizer(config.getProxyList(), ","); proxies = new Proxy[tok.countTokens()]; int i = 0; while (tok.hasMoreTokens()) { String token = tok.nextToken().trim(); int pos = token.indexOf(':'); if (pos <=0) throw new Exception("bad ProxyList"); proxies[i] = new Proxy(); proxies[i].port = Integer.parseInt(token.substring(pos + 1)); try { proxies[i].address = InetAddress.getByName(token.substring(0, pos)); } catch (Exception e) { throw new Exception("bad ProxyList"); } i++; } connections = new Socket[proxies.length]; connectionReaders = new BufferedReader[proxies.length]; connectionWriters = new BufferedWriter[proxies.length]; } @Override public int send(String mess) throws Exception { if (connections == null) { log.error("Not initialized"); return -1; } String requestLine = "POST " + config.getProxyURL() + " HTTP/1.0"; for (int i = 0; i < connections.length; i++) { if (connections[i] == null) { try { if (config.host != null) { connections[i] = new Socket(); InetAddress addr = InetAddress.getByName(config.host); InetSocketAddress addrs = new InetSocketAddress(addr, 0); connections[i].setReuseAddress(true); connections[i].bind(addrs); addrs = new InetSocketAddress(proxies[i].address, proxies[i].port); connections[i].connect(addrs); } else connections[i] = new Socket(proxies[i].address, proxies[i].port); connectionReaders[i] = new BufferedReader(new InputStreamReader(connections[i].getInputStream())); connectionWriters[i] = new BufferedWriter(new OutputStreamWriter(connections[i].getOutputStream())); } catch (Exception ex) { log.error("Unable to connect to proxy: " + ex); close(i); } } if (connections[i] == null) continue; // try next proxy in the list BufferedWriter writer = connectionWriters[i]; try { writer.write(requestLine); writer.write("\r\n"); writer.write("Content-Length: " + mess.length() + "\r\n"); writer.write("User-Agent: HeartbeatListener/1.0\r\n"); writer.write("Connection: Keep-Alive\r\n"); writer.write("\r\n"); writer.write(mess); writer.write("\r\n"); writer.flush(); } catch (Exception ex) { log.error("Unable to send collected load information to proxy: " + ex); close(i); } if (connections[i] == null) continue; // try next proxy in the list /* Read httpd answer */ String responseStatus = connectionReaders[i].readLine(); if (responseStatus == null) { log.error("Unable to read response from proxy"); close(i); continue; } else { responseStatus = responseStatus.substring(responseStatus.indexOf(' ') + 1, responseStatus.indexOf(' ', responseStatus.indexOf(' ') + 1)); int status = Integer.parseInt(responseStatus); if (status != 200) { log.error("Status is " + status); close(i); continue; } // read all the headers. String header = connectionReaders[i].readLine(); int contentLength = 0; while (!"".equals(header)) { int colon = header.indexOf(':'); String headerName = header.substring(0, colon).trim(); String headerValue = header.substring(colon + 1).trim(); if ("content-length".equalsIgnoreCase(headerName)) { contentLength = Integer.parseInt(headerValue); } header = connectionReaders[i].readLine(); } if (contentLength > 0) { char[] buf = new char[512]; while (contentLength > 0) { int thisTime = (contentLength > buf.length) ? buf.length : contentLength; int n = connectionReaders[i].read(buf, 0, thisTime); if (n <= 0) { log.error("Read content failed"); close(i); break; } else { contentLength -= n; } } } } } return 0; } /** * Close connection. */ protected void close(int i) { try { if (connectionReaders[i] != null) { connectionReaders[i].close(); } } catch (IOException e) { } connectionReaders[i] = null; try { if (connectionWriters[i] != null) { connectionWriters[i].close(); } } catch (IOException e) { } connectionWriters[i] = null; try { if (connections[i] != null) { connections[i].close(); } } catch (IOException e) { } connections[i] = null; } } tomcat7-7.0.52/java/org/apache/catalina/ha/backend/CollectedInfo.java0000644000175100017510000000732012271463015025207 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.backend; /* for MBean to read ready and busy */ import java.util.Iterator; import java.util.Set; import javax.management.MBeanServer; import javax.management.ObjectInstance; import javax.management.ObjectName; import org.apache.tomcat.util.modeler.Registry; /* * Listener to provider informations to mod_heartbeat.c * *msg_format = "v=%u&ready=%u&busy=%u"; (message to send). * send the muticast message using the format... * what about the bind(IP. port) only IP makes sense (for the moment). * BTW:v = version :-) */ public class CollectedInfo { /* Collect info via JMX */ protected MBeanServer mBeanServer = null; protected ObjectName objName = null; int ready; int busy; int port = 0; String host = null; public CollectedInfo(String host, int port) throws Exception { init(host, port); } public void init(String host, int port) throws Exception { int iport = 0; String shost = null; mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); String onStr = "*:type=ThreadPool,*"; ObjectName objectName = new ObjectName(onStr); Set set = mBeanServer.queryMBeans(objectName, null); Iterator iterator = set.iterator(); while (iterator.hasNext()) { ObjectInstance oi = iterator.next(); objName = oi.getObjectName(); String name = objName.getKeyProperty("name"); /* Name are: * http-8080 * jk-10.33.144.3-8009 * jk-jfcpc%2F10.33.144.3-8009 */ String [] elenames = name.split("-"); String sport = elenames[elenames.length-1]; iport = Integer.parseInt(sport); String [] shosts = elenames[1].split("%2F"); shost = shosts[0]; if (port==0 && host==null) break; /* Take the first one */ if (host==null && iport==port) break; /* Only port done */ if (shost.compareTo(host) == 0) break; /* Done port and host are the expected ones */ } if (objName == null) throw(new Exception("Can't find connector for " + host + ":" + port)); this.port = iport; this.host = shost; } public void refresh() throws Exception { if (mBeanServer == null || objName == null) { throw(new Exception("Not initialized!!!")); } Integer imax = (Integer) mBeanServer.getAttribute(objName, "maxThreads"); // the currentThreadCount could be 0 before the threads are created... // Integer iready = (Integer) mBeanServer.getAttribute(objName, "currentThreadCount"); Integer ibusy = (Integer) mBeanServer.getAttribute(objName, "currentThreadsBusy"); busy = ibusy.intValue(); ready = imax.intValue() - ibusy.intValue(); } } tomcat7-7.0.52/java/org/apache/catalina/ha/backend/HeartbeatListener.java0000644000175100017510000001066712271463015026112 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.backend; import org.apache.catalina.ContainerEvent; import org.apache.catalina.ContainerListener; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /* * Listener to provider informations to mod_heartbeat.c * *msg_format = "v=%u&ready=%u&busy=%u"; (message to send). * send the muticast message using the format... * what about the bind(IP. port) only IP makes sense (for the moment). * BTW:v = version :-) */ public class HeartbeatListener implements LifecycleListener, ContainerListener { private static final Log log = LogFactory.getLog(HeartbeatListener.class); /* To allow to select the connector */ int port = 0; String host = null; public void setHost(String host) { this.host = host; } public void setPort(int port) { this.port = port; } /* for multicasting stuff */ String ip = "224.0.1.105"; /* Multicast IP */ int multiport = 23364; /* Multicast Port */ int ttl = 16; public void setGroup(String ip) { this.ip = ip; } public String getGroup() { return ip; } public void setMultiport(int multiport) { this.multiport = multiport; } public int getMultiport() { return multiport; } public void setTtl(int ttl) { this.ttl = ttl; } public int getTtl() { return ttl; } /** * Proxy list, format "address:port,address:port". */ protected String proxyList = null; public String getProxyList() { return proxyList; } public void setProxyList(String proxyList) { this.proxyList = proxyList; } /** * URL prefix. */ protected String proxyURL = "/HeartbeatListener"; public String getProxyURL() { return proxyURL; } public void setProxyURL(String proxyURL) { this.proxyURL = proxyURL; } private CollectedInfo coll = null; private Sender sender = null; @Override public void containerEvent(ContainerEvent event) { } @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.PERIODIC_EVENT.equals(event.getType())) { if (sender == null) { if (proxyList == null) sender = new MultiCastSender(); else sender = new TcpSender(); } /* Read busy and ready */ if (coll == null) { try { coll = new CollectedInfo(host, port); this.port = coll.port; this.host = coll.host; } catch (Exception ex) { log.error("Unable to initialize info collection: " + ex); coll = null; return; } } /* Start or restart sender */ try { sender.init(this); } catch (Exception ex) { log.error("Unable to initialize Sender: " + ex); sender = null; return; } /* refresh the connector information and send it */ try { coll.refresh(); } catch (Exception ex) { log.error("Unable to collect load information: " + ex); coll = null; return; } String output = "v=1&ready=" + coll.ready + "&busy=" + coll.busy + "&port=" + port; try { sender.send(output); } catch (Exception ex) { log.error("Unable to send colllected load information: " + ex); } } } } tomcat7-7.0.52/java/org/apache/catalina/ha/backend/Proxy.java0000644000175100017510000000211512271463015023613 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.backend; import java.net.InetAddress; /* * This class represents a front-end httpd server. * */ public class Proxy { protected enum State { OK, ERROR, DOWN } public InetAddress address = null; public int port = 80; public State state = State.OK; } tomcat7-7.0.52/java/org/apache/catalina/ha/backend/Sender.java0000644000175100017510000000216012271463015023712 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.backend; /* * Interface to send data to proxies * */ public interface Sender { /** * Set the configuration parameters */ public void init(HeartbeatListener config) throws Exception; /** * Send the message to the proxies */ public int send(String mess) throws Exception; } tomcat7-7.0.52/java/org/apache/catalina/ha/ClusterRuleSet.java0000644000175100017510000001724112271463015024036 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSetBase; /** *

    RuleSet for processing the contents of a * Cluster definition element.

    * * @author Filip Hanik * @author Peter Rossbach */ public class ClusterRuleSet extends RuleSetBase { // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public ClusterRuleSet() { this(""); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public ClusterRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { //Cluster configuration start digester.addObjectCreate(prefix + "Manager", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Manager"); digester.addSetNext(prefix + "Manager", "setManagerTemplate", "org.apache.catalina.ha.ClusterManager"); digester.addObjectCreate(prefix + "Channel", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Channel"); digester.addSetNext(prefix + "Channel", "setChannel", "org.apache.catalina.tribes.Channel"); String channelPrefix = prefix + "Channel/"; { //channel properties digester.addObjectCreate(channelPrefix + "Membership", null, // MUST be specified in the element "className"); digester.addSetProperties(channelPrefix + "Membership"); digester.addSetNext(channelPrefix + "Membership", "setMembershipService", "org.apache.catalina.tribes.MembershipService"); digester.addObjectCreate(channelPrefix + "Sender", null, // MUST be specified in the element "className"); digester.addSetProperties(channelPrefix + "Sender"); digester.addSetNext(channelPrefix + "Sender", "setChannelSender", "org.apache.catalina.tribes.ChannelSender"); digester.addObjectCreate(channelPrefix + "Sender/Transport", null, // MUST be specified in the element "className"); digester.addSetProperties(channelPrefix + "Sender/Transport"); digester.addSetNext(channelPrefix + "Sender/Transport", "setTransport", "org.apache.catalina.tribes.transport.MultiPointSender"); digester.addObjectCreate(channelPrefix + "Receiver", null, // MUST be specified in the element "className"); digester.addSetProperties(channelPrefix + "Receiver"); digester.addSetNext(channelPrefix + "Receiver", "setChannelReceiver", "org.apache.catalina.tribes.ChannelReceiver"); digester.addObjectCreate(channelPrefix + "Interceptor", null, // MUST be specified in the element "className"); digester.addSetProperties(channelPrefix + "Interceptor"); digester.addSetNext(channelPrefix + "Interceptor", "addInterceptor", "org.apache.catalina.tribes.ChannelInterceptor"); digester.addObjectCreate(channelPrefix + "Interceptor/Member", null, // MUST be specified in the element "className"); digester.addSetProperties(channelPrefix + "Interceptor/Member"); digester.addSetNext(channelPrefix + "Interceptor/Member", "addStaticMember", "org.apache.catalina.tribes.Member"); } digester.addObjectCreate(prefix + "Valve", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Valve"); digester.addSetNext(prefix + "Valve", "addValve", "org.apache.catalina.Valve"); digester.addObjectCreate(prefix + "Deployer", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Deployer"); digester.addSetNext(prefix + "Deployer", "setClusterDeployer", "org.apache.catalina.ha.ClusterDeployer"); digester.addObjectCreate(prefix + "Listener", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Listener"); digester.addSetNext(prefix + "Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener"); digester.addObjectCreate(prefix + "ClusterListener", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "ClusterListener"); digester.addSetNext(prefix + "ClusterListener", "addClusterListener", "org.apache.catalina.ha.ClusterListener"); //Cluster configuration end } } tomcat7-7.0.52/java/org/apache/catalina/ha/authenticator/0000755000175100017510000000000012301126370023105 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java0000644000175100017510000003674112271463015027672 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.authenticator; import java.security.Principal; import org.apache.catalina.Cluster; import org.apache.catalina.Container; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.LifecycleException; import org.apache.catalina.Manager; import org.apache.catalina.Session; import org.apache.catalina.authenticator.SingleSignOn; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.ha.session.SerializablePrincipal; import org.apache.catalina.realm.GenericPrincipal; import org.apache.tomcat.util.ExceptionUtils; /** * A Valve that supports a "single sign on" user experience on * each nodes of a cluster, where the security identity of a user who successfully * authenticates to one web application is propagated to other web applications and * to other nodes cluster in the same security domain. For successful use, the following * requirements must be met: *
      *
    • This Valve must be configured on the Container that represents a * virtual host (typically an implementation of Host).
    • *
    • The Realm that contains the shared user and role * information must be configured on the same Container (or a higher * one), and not overridden at the web application level.
    • *
    • The web applications themselves must use one of the standard * Authenticators found in the * org.apache.catalina.authenticator package.
    • *
    * * @author Fabien Carrion */ public class ClusterSingleSignOn extends SingleSignOn { // ----------------------------------------------------- Instance Variables /** * Descriptive information about this Valve implementation. */ protected static final String info = "org.apache.catalina.ha.authenticator.ClusterSingleSignOn"; protected int messageNumber = 0; private ClusterSingleSignOnListener clusterSSOListener = null; // ------------------------------------------------------------- Properties private CatalinaCluster cluster = null; /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } public CatalinaCluster getCluster() { return cluster; } public void setCluster(CatalinaCluster cluster) { this.cluster = cluster; } // ------------------------------------------------------ Lifecycle Methods /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { clusterSSOListener = new ClusterSingleSignOnListener(); clusterSSOListener.setClusterSSO(this); // Load the cluster component, if any try { //the channel is already running Cluster cluster = getCluster(); // stop remove cluster binding if(cluster == null) { Container host = getContainer(); if(host != null && host instanceof Host) { cluster = host.getCluster(); if(cluster != null && cluster instanceof CatalinaCluster) { setCluster((CatalinaCluster) cluster); getCluster().addClusterListener(clusterSSOListener); } else { Container engine = host.getParent(); if(engine != null && engine instanceof Engine) { cluster = engine.getCluster(); if(cluster != null && cluster instanceof CatalinaCluster) { setCluster((CatalinaCluster) cluster); getCluster().addClusterListener(clusterSSOListener); } } else { cluster = null; } } } } if (cluster == null) { throw new LifecycleException( "There is no Cluster for ClusterSingleSignOn"); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); throw new LifecycleException( "ClusterSingleSignOn exception during clusterLoad " + t); } super.startInternal(); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { super.stopInternal(); if (getCluster() != null) { getCluster().removeClusterListener(clusterSSOListener); } } // ------------------------------------------------------ Protected Methods /** * Notify the cluster of the addition of a Session to * an SSO session and associate the specified single * sign on identifier with the specified Session on the * local node. * * @param ssoId Single sign on identifier * @param session Session to be associated */ @Override protected void associate(String ssoId, Session session) { if (cluster != null && cluster.getMembers().length > 0) { messageNumber++; SingleSignOnMessage msg = new SingleSignOnMessage(cluster.getLocalMember(), ssoId, session.getId()); Manager mgr = session.getManager(); if ((mgr != null) && (mgr instanceof ClusterManager)) msg.setContextName(((ClusterManager) mgr).getName()); msg.setAction(SingleSignOnMessage.ADD_SESSION); cluster.send(msg); if (containerLog.isDebugEnabled()) containerLog.debug("SingleSignOnMessage Send with action " + msg.getAction()); } associateLocal(ssoId, session); } protected void associateLocal(String ssoId, Session session) { super.associate(ssoId, session); } /** * Notify the cluster of the removal of a Session from an * SSO session and deregister the specified session. If it is the last * session, then also get rid of the single sign on identifier on the * local node. * * @param ssoId Single sign on identifier * @param session Session to be deregistered */ @Override protected void deregister(String ssoId, Session session) { if (cluster != null && cluster.getMembers().length > 0) { messageNumber++; SingleSignOnMessage msg = new SingleSignOnMessage(cluster.getLocalMember(), ssoId, session.getId()); Manager mgr = session.getManager(); if ((mgr != null) && (mgr instanceof ClusterManager)) msg.setContextName(((ClusterManager) mgr).getName()); msg.setAction(SingleSignOnMessage.DEREGISTER_SESSION); cluster.send(msg); if (containerLog.isDebugEnabled()) containerLog.debug("SingleSignOnMessage Send with action " + msg.getAction()); } deregisterLocal(ssoId, session); } protected void deregisterLocal(String ssoId, Session session) { super.deregister(ssoId, session); } /** * Notifies the cluster that a single sign on session * has been terminated due to a user logout, deregister * the specified single sign on identifier, and invalidate * any associated sessions on the local node. * * @param ssoId Single sign on identifier to deregister */ @Override protected void deregister(String ssoId) { if (cluster != null && cluster.getMembers().length > 0) { messageNumber++; SingleSignOnMessage msg = new SingleSignOnMessage(cluster.getLocalMember(), ssoId, null); msg.setAction(SingleSignOnMessage.LOGOUT_SESSION); cluster.send(msg); if (containerLog.isDebugEnabled()) containerLog.debug("SingleSignOnMessage Send with action " + msg.getAction()); } deregisterLocal(ssoId); } protected void deregisterLocal(String ssoId) { super.deregister(ssoId); } /** * Notifies the cluster of the creation of a new SSO entry * and register the specified Principal as being associated * with the specified value for the single sign on identifier. * * @param ssoId Single sign on identifier to register * @param principal Associated user principal that is identified * @param authType Authentication type used to authenticate this * user principal * @param username Username used to authenticate this user * @param password Password used to authenticate this user */ @Override protected void register(String ssoId, Principal principal, String authType, String username, String password) { if (cluster != null && cluster.getMembers().length > 0) { messageNumber++; SingleSignOnMessage msg = new SingleSignOnMessage(cluster.getLocalMember(), ssoId, null); msg.setAction(SingleSignOnMessage.REGISTER_SESSION); msg.setAuthType(authType); msg.setUsername(username); msg.setPassword(password); SerializablePrincipal sp = null; if (principal instanceof GenericPrincipal) { sp = SerializablePrincipal.createPrincipal((GenericPrincipal) principal); msg.setPrincipal(sp); } cluster.send(msg); if (containerLog.isDebugEnabled()) containerLog.debug("SingleSignOnMessage Send with action " + msg.getAction()); } registerLocal(ssoId, principal, authType, username, password); } protected void registerLocal(String ssoId, Principal principal, String authType, String username, String password) { super.register(ssoId, principal, authType, username, password); } /** * Notifies the cluster of an update of the security credentials * associated with an SSO session. Updates any SingleSignOnEntry * found under key ssoId with the given authentication data. *

    * The purpose of this method is to allow an SSO entry that was * established without a username/password combination (i.e. established * following DIGEST or CLIENT-CERT authentication) to be updated with * a username and password if one becomes available through a subsequent * BASIC or FORM authentication. The SSO entry will then be usable for * reauthentication. *

    * NOTE: Only updates the SSO entry if a call to * SingleSignOnEntry.getCanReauthenticate() returns * false; otherwise, it is assumed that the SSO entry already * has sufficient information to allow reauthentication and that no update * is needed. * * @param ssoId identifier of Single sign to be updated * @param principal the Principal returned by the latest * call to Realm.authenticate. * @param authType the type of authenticator used (BASIC, CLIENT-CERT, * DIGEST or FORM) * @param username the username (if any) used for the authentication * @param password the password (if any) used for the authentication */ @Override protected void update(String ssoId, Principal principal, String authType, String username, String password) { if (cluster != null && cluster.getMembers().length > 0) { messageNumber++; SingleSignOnMessage msg = new SingleSignOnMessage(cluster.getLocalMember(), ssoId, null); msg.setAction(SingleSignOnMessage.UPDATE_SESSION); msg.setAuthType(authType); msg.setUsername(username); msg.setPassword(password); SerializablePrincipal sp = null; if (principal instanceof GenericPrincipal) { sp = SerializablePrincipal.createPrincipal((GenericPrincipal) principal); msg.setPrincipal(sp); } cluster.send(msg); if (containerLog.isDebugEnabled()) containerLog.debug("SingleSignOnMessage Send with action " + msg.getAction()); } updateLocal(ssoId, principal, authType, username, password); } protected void updateLocal(String ssoId, Principal principal, String authType, String username, String password) { super.update(ssoId, principal, authType, username, password); } /** * Remove a single Session from a SingleSignOn and notify the cluster * of the removal. Called when a session is timed out and no longer active. * * @param ssoId Single sign on identifier from which to remove the session. * @param session the session to be removed. */ @Override protected void removeSession(String ssoId, Session session) { if (cluster != null && cluster.getMembers().length > 0) { messageNumber++; SingleSignOnMessage msg = new SingleSignOnMessage(cluster.getLocalMember(), ssoId, session.getId()); Manager mgr = session.getManager(); if ((mgr != null) && (mgr instanceof ClusterManager)) msg.setContextName(((ClusterManager) mgr).getName()); msg.setAction(SingleSignOnMessage.REMOVE_SESSION); cluster.send(msg); if (containerLog.isDebugEnabled()) containerLog.debug("SingleSignOnMessage Send with action " + msg.getAction()); } removeSessionLocal(ssoId, session); } protected void removeSessionLocal(String ssoId, Session session) { super.removeSession(ssoId, session); } } tomcat7-7.0.52/java/org/apache/catalina/ha/authenticator/SingleSignOnMessage.java0000644000175100017510000001242512271463015027626 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.authenticator; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.ha.session.SerializablePrincipal; import org.apache.catalina.tribes.Member; /** * Contains the SingleSignOn data, read and written by the ClusterSingleSignOn * @author Fabien Carrion */ public class SingleSignOnMessage implements ClusterMessage { private static final long serialVersionUID = 1L; public static final int ADD_SESSION = 1; public static final int DEREGISTER_SESSION = 2; public static final int LOGOUT_SESSION = 3; public static final int REGISTER_SESSION = 4; public static final int UPDATE_SESSION = 5; public static final int REMOVE_SESSION = 6; private int action = -1; private String ssoId = null; private String ctxname = null; private String sessionId = null; private String authType = null; private String password = null; private String username = null; private SerializablePrincipal principal = null; private Member address = null; private long timestamp = 0; private String uniqueId = null; public SingleSignOnMessage(Member source, String ssoId, String sessionId) { this.address = source; this.ssoId = ssoId; this.sessionId = sessionId; } /** * Get the address that this message originated from. This would be set * if the message was being relayed from a host other than the one * that originally sent it. */ @Override public Member getAddress() { return address; } /** * Called by the cluster before sending it to the other * nodes. * * @param member Member */ @Override public void setAddress(Member member) { this.address = member; } /** * Timestamp message. * * @return long */ @Override public long getTimestamp() { return timestamp; } /** * Called by the cluster before sending out * the message. * * @param timestamp The timestamp */ @Override public void setTimestamp(long timestamp) { this.timestamp = timestamp; } /** * Each message must have a unique ID, in case of using async replication, * and a smart queue, this id is used to replace messages not yet sent. * * @return String */ @Override public String getUniqueId() { if (this.uniqueId != null) return this.uniqueId; StringBuilder result = new StringBuilder(getSsoId()); result.append("#-#"); result.append(System.currentTimeMillis()); return result.toString(); } @Override public void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } public int getAction() { return action; } public void setAction(int action) { this.action = action; } public String getSsoId() { return ssoId; } public void setSsoId(String ssoId) { this.ssoId = ssoId; } public String getContextName() { return ctxname; } public void setContextName(String ctxname) { this.ctxname = ctxname; } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; } public String getAuthType() { return authType; } public void setAuthType(String authType) { this.authType = authType; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public SerializablePrincipal getPrincipal() { return principal; } public void setPrincipal(SerializablePrincipal principal) { this.principal = principal; } // --------------------------------------------------------- Public Methods /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SingleSignOnMessage[action="); sb.append(getAction()).append(", ssoId=").append(getSsoId()); sb.append(", sessionId=").append(getSessionId()).append(", username="); sb.append(getUsername()).append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/ha/authenticator/mbeans-descriptors.xml0000644000175100017510000000305611513073447027451 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOnListener.java0000644000175100017510000001514312271463015031371 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.authenticator; import java.io.IOException; import java.security.Principal; import java.util.Map; import org.apache.catalina.Session; import org.apache.catalina.ha.ClusterListener; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.ha.ClusterMessage; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Receive replicated SingleSignOnMessage form other cluster node. * * @author Fabien Carrion */ public class ClusterSingleSignOnListener extends ClusterListener { private static final Log log = LogFactory.getLog(ClusterSingleSignOnListener.class); /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.ha.authenticator.ClusterSingleSignOnListener/1.0"; // ------------------------------------------------------------- Properties private ClusterSingleSignOn clusterSSO = null; //--Constructor--------------------------------------------- public ClusterSingleSignOnListener() { // NO-OP } //--Logic--------------------------------------------------- /** * Return descriptive information about this implementation. */ public String getInfo() { return (info); } public ClusterSingleSignOn getClusterSSO() { return clusterSSO; } public void setClusterSSO(ClusterSingleSignOn clusterSSO) { this.clusterSSO = clusterSSO; } /** * Callback from the cluster, when a message is received, The cluster will * broadcast it invoking the messageReceived on the receiver. * * @param myobj * ClusterMessage - the message received from the cluster */ @Override public void messageReceived(ClusterMessage myobj) { if (myobj != null && myobj instanceof SingleSignOnMessage) { SingleSignOnMessage msg = (SingleSignOnMessage) myobj; int action = msg.getAction(); Session session = null; Principal principal = null; if (log.isDebugEnabled()) log.debug("SingleSignOnMessage Received with action " + msg.getAction()); switch(action) { case SingleSignOnMessage.ADD_SESSION: session = getSession(msg.getSessionId(), msg.getContextName()); if (session != null) clusterSSO.associateLocal(msg.getSsoId(), session); break; case SingleSignOnMessage.DEREGISTER_SESSION: session = getSession(msg.getSessionId(), msg.getContextName()); if (session != null) clusterSSO.deregisterLocal(msg.getSsoId(), session); break; case SingleSignOnMessage.LOGOUT_SESSION: clusterSSO.deregisterLocal(msg.getSsoId()); break; case SingleSignOnMessage.REGISTER_SESSION: if (msg.getPrincipal() != null) { principal = msg.getPrincipal().getPrincipal(); } clusterSSO.registerLocal(msg.getSsoId(), principal, msg.getAuthType(), msg.getUsername(), msg.getPassword()); break; case SingleSignOnMessage.UPDATE_SESSION: if (msg.getPrincipal() != null) { principal = msg.getPrincipal().getPrincipal(); } clusterSSO.updateLocal(msg.getSsoId(), principal, msg.getAuthType(), msg.getUsername(), msg.getPassword()); break; case SingleSignOnMessage.REMOVE_SESSION: session = getSession(msg.getSessionId(), msg.getContextName()); if (session != null) clusterSSO.removeSessionLocal(msg.getSsoId(), session); break; } } } /** * Accept only SingleSignOnMessage * * @param msg * ClusterMessage * @return boolean - returns true to indicate that messageReceived should be * invoked. If false is returned, the messageReceived method will * not be invoked. */ @Override public boolean accept(ClusterMessage msg) { return (msg instanceof SingleSignOnMessage); } private Session getSession(String sessionId, String ctxname) { Map managers = clusterSSO.getCluster().getManagers(); Session session = null; if (ctxname == null) { for (Map.Entry entry : managers.entrySet()) { if (entry.getValue() != null) { try { session = entry.getValue().findSession(sessionId); } catch (IOException io) { log.error("Session doesn't exist:" + io); } return session; } //this happens a lot before the system has started // up if (log.isDebugEnabled()) log.debug("Context manager doesn't exist:" + entry.getKey()); } } else { ClusterManager mgr = managers.get(ctxname); if (mgr != null) { try { session = mgr.findSession(sessionId); } catch (IOException io) { log.error("Session doesn't exist:" + io); } return session; } else if (log.isErrorEnabled()) log.error("Context manager doesn't exist:" + ctxname); } return null; } } tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/0000755000175100017510000000000012301126370021527 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/deploy/FileMessageFactory.java0000644000175100017510000003425312271463015026123 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.HexUtils; import org.apache.tomcat.util.res.StringManager; /** * This factory is used to read files and write files by splitting them up into * smaller messages. So that entire files don't have to be read into memory. *
    * The factory can be used as a reader or writer but not both at the same time. * When done reading or writing the factory will close the input or output * streams and mark the factory as closed. It is not possible to use it after * that.
    * To force a cleanup, call cleanup() from the calling object.
    * This class is not thread safe. * * @author Filip Hanik * @version 1.0 */ public class FileMessageFactory { /*--Static Variables----------------------------------------*/ private static final Log log = LogFactory.getLog(FileMessageFactory.class); private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The number of bytes that we read from file */ public static final int READ_SIZE = 1024 * 10; //10kb /** * The file that we are reading/writing */ protected File file = null; /** * True means that we are writing with this factory. False means that we are * reading with this factory */ protected boolean openForWrite; /** * Once the factory is used, it can not be reused. */ protected boolean closed = false; /** * When openForWrite=false, the input stream is held by this variable */ protected FileInputStream in; /** * When openForWrite=true, the output stream is held by this variable */ protected FileOutputStream out; /** * The number of messages we have written */ protected int nrOfMessagesProcessed = 0; /** * The total size of the file */ protected long size = 0; /** * The total number of packets that we split this file into */ protected long totalNrOfMessages = 0; /** * The number of the last message processed. Message IDs are 1 based. */ protected AtomicLong lastMessageProcessed = new AtomicLong(0); /** * Messages received out of order are held in the buffer until required. If * everything is worked as expected, messages will spend very little time in * the buffer. */ protected Map msgBuffer = new ConcurrentHashMap(); /** * The bytes that we hold the data in, not thread safe. */ protected byte[] data = new byte[READ_SIZE]; /** * Flag that indicates if a thread is writing messages to disk. Access to * this flag must be synchronised. */ protected boolean isWriting = false; /** * The time this instance was created. (in milliseconds) */ protected long creationTime = 0; /** * The maximum valid time(in seconds) from creationTime. */ protected int maxValidTime = -1; /** * Private constructor, either instantiates a factory to read or write.
    * When openForWrite==true, then a the file, f, will be created and an * output stream is opened to write to it.
    * When openForWrite==false, an input stream is opened, the file has to * exist. * * @param f * File - the file to be read/written * @param openForWrite * boolean - true means we are writing to the file, false means * we are reading from the file * @throws FileNotFoundException - * if the file to be read doesn't exist * @throws IOException - * if the system fails to open input/output streams to the file * or if it fails to create the file to be written to. */ private FileMessageFactory(File f, boolean openForWrite) throws FileNotFoundException, IOException { this.file = f; this.openForWrite = openForWrite; if (log.isDebugEnabled()) log.debug("open file " + f + " write " + openForWrite); if (openForWrite) { if (!file.exists()) if (!file.createNewFile()) { throw new IOException(sm.getString("fileNewFail", file)); } out = new FileOutputStream(f); } else { size = file.length(); totalNrOfMessages = (size / READ_SIZE) + 1; in = new FileInputStream(f); }//end if creationTime = System.currentTimeMillis(); } /** * Creates a factory to read or write from a file. When opening for read, * the readMessage can be invoked, and when opening for write the * writeMessage can be invoked. * * @param f * File - the file to be read or written * @param openForWrite * boolean - true, means we are writing to the file, false means * we are reading from it * @throws FileNotFoundException - * if the file to be read doesn't exist * @throws IOException - * if it fails to create the file that is to be written * @return FileMessageFactory */ public static FileMessageFactory getInstance(File f, boolean openForWrite) throws FileNotFoundException, IOException { return new FileMessageFactory(f, openForWrite); } /** * Reads file data into the file message and sets the size, totalLength, * totalNrOfMsgs and the message number
    * If EOF is reached, the factory returns null, and closes itself, otherwise * the same message is returned as was passed in. This makes sure that not * more memory is ever used. To remember, neither the file message or the * factory are thread safe. dont hand off the message to one thread and read * the same with another. * * @param f * FileMessage - the message to be populated with file data * @throws IllegalArgumentException - * if the factory is for writing or is closed * @throws IOException - * if a file read exception occurs * @return FileMessage - returns the same message passed in as a parameter, * or null if EOF */ public FileMessage readMessage(FileMessage f) throws IllegalArgumentException, IOException { checkState(false); int length = in.read(data); if (length == -1) { cleanup(); return null; } else { f.setData(data, length); f.setTotalLength(size); f.setTotalNrOfMsgs(totalNrOfMessages); f.setMessageNumber(++nrOfMessagesProcessed); return f; }//end if } /** * Writes a message to file. If (msg.getMessageNumber() == * msg.getTotalNrOfMsgs()) the output stream will be closed after writing. * * @param msg * FileMessage - message containing data to be written * @throws IllegalArgumentException - * if the factory is opened for read or closed * @throws IOException - * if a file write error occurs * @return returns true if the file is complete and outputstream is closed, * false otherwise. */ public boolean writeMessage(FileMessage msg) throws IllegalArgumentException, IOException { if (!openForWrite) throw new IllegalArgumentException( "Can't write message, this factory is reading."); if (log.isDebugEnabled()) log.debug("Message " + msg + " data " + HexUtils.toHexString(msg.getData()) + " data length " + msg.getDataLength() + " out " + out); if (msg.getMessageNumber() <= lastMessageProcessed.get()) { // Duplicate of message already processed log.warn("Receive Message again -- Sender ActTimeout too short [ name: " + msg.getContextName() + " war: " + msg.getFileName() + " data: " + HexUtils.toHexString(msg.getData()) + " data length: " + msg.getDataLength() + " ]"); return false; } FileMessage previous = msgBuffer.put(Long.valueOf(msg.getMessageNumber()), msg); if (previous !=null) { // Duplicate of message not yet processed log.warn("Receive Message again -- Sender ActTimeout too short [ name: " + msg.getContextName() + " war: " + msg.getFileName() + " data: " + HexUtils.toHexString(msg.getData()) + " data length: " + msg.getDataLength() + " ]"); return false; } FileMessage next = null; synchronized (this) { if (!isWriting) { next = msgBuffer.get(Long.valueOf(lastMessageProcessed.get() + 1)); if (next != null) { isWriting = true; } else { return false; } } else { return false; } } while (next != null) { out.write(next.getData(), 0, next.getDataLength()); lastMessageProcessed.incrementAndGet(); out.flush(); if (next.getMessageNumber() == next.getTotalNrOfMsgs()) { out.close(); cleanup(); return true; } synchronized(this) { next = msgBuffer.get(Long.valueOf(lastMessageProcessed.get() + 1)); if (next == null) { isWriting = false; } } } return false; }//writeMessage /** * Closes the factory, its streams and sets all its references to null */ public void cleanup() { if (in != null) try { in.close(); } catch (Exception ignore) { } if (out != null) try { out.close(); } catch (Exception ignore) { } in = null; out = null; size = 0; closed = true; data = null; nrOfMessagesProcessed = 0; totalNrOfMessages = 0; msgBuffer.clear(); lastMessageProcessed = null; } /** * Check to make sure the factory is able to perform the function it is * asked to do. Invoked by readMessage/writeMessage before those methods * proceed. * * @param openForWrite * boolean * @throws IllegalArgumentException */ protected void checkState(boolean openForWrite) throws IllegalArgumentException { if (this.openForWrite != openForWrite) { cleanup(); if (openForWrite) throw new IllegalArgumentException( "Can't write message, this factory is reading."); else throw new IllegalArgumentException( "Can't read message, this factory is writing."); } if (this.closed) { cleanup(); throw new IllegalArgumentException("Factory has been closed."); } } /** * Example usage. * * @param args * String[], args[0] - read from filename, args[1] write to * filename * @throws Exception */ public static void main(String[] args) throws Exception { System.out .println("Usage: FileMessageFactory fileToBeRead fileToBeWritten"); System.out .println("Usage: This will make a copy of the file on the local file system"); FileMessageFactory read = getInstance(new File(args[0]), false); FileMessageFactory write = getInstance(new File(args[1]), true); FileMessage msg = new FileMessage(null, args[0], args[0]); msg = read.readMessage(msg); if (msg == null) { System.out.println("Empty input file : " + args[0]); return; } System.out.println("Expecting to write " + msg.getTotalNrOfMsgs() + " messages."); int cnt = 0; while (msg != null) { write.writeMessage(msg); cnt++; msg = read.readMessage(msg); }//while System.out.println("Actually wrote " + cnt + " messages."); }///main public File getFile() { return file; } public boolean isValid() { if (maxValidTime > 0) { long timeNow = System.currentTimeMillis(); int timeIdle = (int) ((timeNow - creationTime) / 1000L); if (timeIdle > maxValidTime) { cleanup(); if (file.exists()) file.delete(); return false; } } return true; } public int getMaxValidTime() { return maxValidTime; } public void setMaxValidTime(int maxValidTime) { this.maxValidTime = maxValidTime; } } tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/WarWatcher.java0000644000175100017510000001530212271463015024450 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy; import java.io.File; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    * The WarWatcher watches the deployDir for changes made to the * directory (adding new WAR files->deploy or remove WAR files->undeploy) And * notifies a listener of the changes made *

    * * @author Filip Hanik * @author Peter Rossbach * @version 1.1 */ public class WarWatcher { /*--Static Variables----------------------------------------*/ private static final Log log = LogFactory.getLog(WarWatcher.class); /*--Instance Variables--------------------------------------*/ /** * Directory to watch for war files */ protected File watchDir = null; /** * Parent to be notified of changes */ protected FileChangeListener listener = null; /** * Currently deployed files */ protected Map currentStatus = new HashMap(); /*--Constructor---------------------------------------------*/ public WarWatcher() { } public WarWatcher(FileChangeListener listener, File watchDir) { this.listener = listener; this.watchDir = watchDir; } /*--Logic---------------------------------------------------*/ /** * check for modification and send notification to listener */ public void check() { if (log.isDebugEnabled()) log.debug("check cluster wars at " + watchDir); File[] list = watchDir.listFiles(new WarFilter()); if (list == null) list = new File[0]; //first make sure all the files are listed in our current status for (int i = 0; i < list.length; i++) { addWarInfo(list[i]); } //check all the status codes and update the FarmDeployer for (Iterator> i = currentStatus.entrySet().iterator(); i.hasNext();) { Map.Entry entry = i.next(); WarInfo info = entry.getValue(); int check = info.check(); if (check == 1) { listener.fileModified(info.getWar()); } else if (check == -1) { listener.fileRemoved(info.getWar()); //no need to keep in memory i.remove(); } } } /** * add cluster war to the watcher state * @param warfile */ protected void addWarInfo(File warfile) { WarInfo info = currentStatus.get(warfile.getAbsolutePath()); if (info == null) { info = new WarInfo(warfile); info.setLastState(-1); //assume file is non existent currentStatus.put(warfile.getAbsolutePath(), info); } } /** * clear watcher state */ public void clear() { currentStatus.clear(); } /** * @return Returns the watchDir. */ public File getWatchDir() { return watchDir; } /** * @param watchDir * The watchDir to set. */ public void setWatchDir(File watchDir) { this.watchDir = watchDir; } /** * @return Returns the listener. */ public FileChangeListener getListener() { return listener; } /** * @param listener * The listener to set. */ public void setListener(FileChangeListener listener) { this.listener = listener; } /*--Inner classes-------------------------------------------*/ /** * File name filter for war files */ protected static class WarFilter implements java.io.FilenameFilter { @Override public boolean accept(File path, String name) { if (name == null) return false; return name.endsWith(".war"); } } /** * File information on existing WAR files */ protected static class WarInfo { protected File war = null; protected long lastChecked = 0; protected long lastState = 0; public WarInfo(File war) { this.war = war; this.lastChecked = war.lastModified(); if (!war.exists()) lastState = -1; } public boolean modified() { return war.exists() && war.lastModified() > lastChecked; } public boolean exists() { return war.exists(); } /** * Returns 1 if the file has been added/modified, 0 if the file is * unchanged and -1 if the file has been removed * * @return int 1=file added; 0=unchanged; -1=file removed */ public int check() { //file unchanged by default int result = 0; if (modified()) { //file has changed - timestamp result = 1; lastState = result; } else if ((!exists()) && (!(lastState == -1))) { //file was removed result = -1; lastState = result; } else if ((lastState == -1) && exists()) { //file was added result = 1; lastState = result; } this.lastChecked = System.currentTimeMillis(); return result; } public File getWar() { return war; } @Override public int hashCode() { return war.getAbsolutePath().hashCode(); } @Override public boolean equals(Object other) { if (other instanceof WarInfo) { WarInfo wo = (WarInfo) other; return wo.getWar().equals(getWar()); } else { return false; } } protected void setLastState(int lastState) { this.lastState = lastState; } } }tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml0000644000175100017510000000350712142136427026071 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/Constants.java0000644000175100017510000000202111514053460024345 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy; /** * Manifest constants for the org.apache.catalina.ha.deploy * package. */ public class Constants { public static final String Package = "org.apache.catalina.ha.deploy"; } tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/LocalStrings.properties0000644000175100017510000000570712135671654026301 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. fileNewFail=Unable to create [{0}] farmWarDeployer.deleteFail=Failed to delete [{0}] farmWarDeployer.deployEnd=Deployment from [{0}] finished. farmWarDeployer.fileCopyFail=Unable to copy from [{0}] to [{1}] farmWarDeployer.hostOnly=FarmWarDeployer can only work as host cluster subelement! farmWarDeployer.hostParentEngine=FarmWarDeployer can only work if parent of [{0}] is an engine! farmWarDeployer.mbeanNameFail=Can't construct MBean object name for engine [{0}] and host [{1}] farmWarDeployer.alreadyDeployed=webapp [{0}] are already deployed. farmWarDeployer.modInstall=Installing webapp [{0}] from [{1}] farmWarDeployer.modRemoveFail=No removal farmWarDeployer.modInstallFail=Unable to install WAR file farmWarDeployer.msgIoe=Unable to read farm deploy file message. farmWarDeployer.msgRxDeploy=Receive cluster deployment path [{0}], war [{1}] farmWarDeployer.msgRxUndeploy=Receive cluster undeployment from path [{0}] farmWarDeployer.notImplemented=Method [{0}] not yet implemented. farmWarDeployer.removeStart=Cluster wide remove of web app [{0}] farmWarDeployer.removeTxMsg=Send cluster wide undeployment from [{0}] farmWarDeployer.removeFailRemote=Local remove from [{0}] failed, other manager has app in service! farmWarDeployer.removeFailLocal=Local remove from [{0}] failed farmWarDeployer.removeLocal=Removing webapp [{0}] farmWarDeployer.removeLocalFail=Unable to remove WAR file farmWarDeployer.renameFail=Failed to rename [{0}] to [{1}] farmWarDeployer.sendEnd=Send cluster war deployment path [{0}], war [{1}] finished. farmWarDeployer.sendFragment=Send cluster war fragment path [{0}], war [{1}] to [{2}] farmWarDeployer.sendStart=Send cluster war deployment path [{0}], war [{1}] started. farmWarDeployer.servicingDeploy=Application [{0}] is being serviced. Touch war file [{1}] again! farmWarDeployer.servicingUneploy=Application [{0}] is being serviced and can't be removed from backup cluster node farmWarDeployer.started=Cluster FarmWarDeployer started. farmWarDeployer.stopped=Cluster FarmWarDeployer stopped. farmWarDeployer.undeployEnd=Undeployment from [{0}] finished. farmWarDeployer.undeployLocal=Undeploy local context [{0}] farmWarDeployer.watchDir=Cluster deployment is watching [{0}] for changes. tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/FileMessage.java0000644000175100017510000000637312271463015024575 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy; import org.apache.catalina.ha.ClusterMessageBase; import org.apache.catalina.tribes.Member; /** * Contains the data for a file being transferred over TCP, this is * essentially a fragment of a file, read and written by the FileMessageFactory * @author Filip Hanik * @version 1.0 */ public class FileMessage extends ClusterMessageBase { private static final long serialVersionUID = 1L; private int messageNumber; private byte[] data; private int dataLength; private long totalLength; private long totalNrOfMsgs; private String fileName; private String contextName; public FileMessage(Member source, String fileName, String contextName) { this.address=source; this.fileName=fileName; this.contextName=contextName; } /* public void writeExternal(ObjectOutput out) throws IOException { } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { } */ public int getMessageNumber() { return messageNumber; } public void setMessageNumber(int messageNumber) { this.messageNumber = messageNumber; } public long getTotalNrOfMsgs() { return totalNrOfMsgs; } public void setTotalNrOfMsgs(long totalNrOfMsgs) { this.totalNrOfMsgs = totalNrOfMsgs; } public byte[] getData() { return data; } public void setData(byte[] data, int length) { this.data = data; this.dataLength = length; } public int getDataLength() { return dataLength; } public void setDataLength(int dataLength) { this.dataLength = dataLength; } public long getTotalLength() { return totalLength; } public void setTotalLength(long totalLength) { this.totalLength = totalLength; } @Override public String getUniqueId() { StringBuilder result = new StringBuilder(getFileName()); result.append("#-#"); result.append(getMessageNumber()); result.append("#-#"); result.append(System.currentTimeMillis()); return result.toString(); } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getContextName() { return contextName; } } tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/FileChangeListener.java0000644000175100017510000000172612271463015026101 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy; import java.io.File; public interface FileChangeListener { public void fileModified(File f); public void fileRemoved(File f); } tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java0000644000175100017510000006721212271463015025453 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy; import java.io.File; import java.io.IOException; import java.util.HashMap; import javax.management.MBeanServer; import javax.management.ObjectName; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.LifecycleException; import org.apache.catalina.ha.ClusterDeployer; import org.apache.catalina.ha.ClusterListener; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.util.ContextName; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; /** *

    * A farm war deployer is a class that is able to deploy/undeploy web * applications in WAR from within the cluster. *

    * Any host can act as the admin, and will have three directories *
      *
    • watchDir - the directory where we watch for changes
    • *
    • deployDir - the directory where we install applications
    • *
    • tempDir - a temporaryDirectory to store binary data when downloading a * war from the cluster
    • *
    * Currently we only support deployment of WAR files since they are easier to * send across the wire. * * @author Filip Hanik * @author Peter Rossbach */ public class FarmWarDeployer extends ClusterListener implements ClusterDeployer, FileChangeListener { /*--Static Variables----------------------------------------*/ private static final Log log = LogFactory.getLog(FarmWarDeployer.class); private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The descriptive information about this implementation. */ private static final String info = "FarmWarDeployer/1.2"; /*--Instance Variables--------------------------------------*/ protected boolean started = false; protected HashMap fileFactories = new HashMap(); /** * Deployment directory. */ protected String deployDir; private File deployDirFile = null; /** * Temporary directory. */ protected String tempDir; private File tempDirFile = null; /** * Watch directory. */ protected String watchDir; private File watchDirFile = null; protected boolean watchEnabled = false; protected WarWatcher watcher = null; /** * Iteration count for background processing. */ private int count = 0; /** * Frequency of the Farm watchDir check. Cluster wide deployment will be * done once for the specified amount of backgrondProcess calls (ie, the * lower the amount, the most often the checks will occur). */ protected int processDeployFrequency = 2; /** * Path where context descriptors should be deployed. */ protected File configBase = null; /** * The associated host. */ protected Host host = null; /** * The host appBase. */ protected File appBase = null; /** * MBean server. */ protected MBeanServer mBeanServer = null; /** * The associated deployer ObjectName. */ protected ObjectName oname = null; /** * The maximum valid time(in seconds) for FileMessageFactory. */ protected int maxValidTime = 5 * 60; /*--Constructor---------------------------------------------*/ public FarmWarDeployer() { } /** * Return descriptive information about this deployer implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /*--Logic---------------------------------------------------*/ @Override public void start() throws Exception { if (started) return; Container hcontainer = getCluster().getContainer(); if(!(hcontainer instanceof Host)) { log.error(sm.getString("farmWarDeployer.hostOnly")); return ; } host = (Host) hcontainer; // Check to correct engine and host setup Container econtainer = host.getParent(); if(!(econtainer instanceof Engine)) { log.error(sm.getString("farmWarDeployer.hostParentEngine", host.getName())); return ; } Engine engine = (Engine) econtainer; String hostname = null; hostname = host.getName(); try { oname = new ObjectName(engine.getName() + ":type=Deployer,host=" + hostname); } catch (Exception e) { log.error(sm.getString("farmWarDeployer.mbeanNameFail", engine.getName(), hostname),e); return; } if (watchEnabled) { watcher = new WarWatcher(this, getWatchDirFile()); if (log.isInfoEnabled()) { log.info(sm.getString( "farmWarDeployer.watchDir", getWatchDir())); } } if (host.getXmlBase()!=null) { configBase = getAbsolutePath(host.getXmlBase()); } else { StringBuilder xmlDir = new StringBuilder("conf"); xmlDir.append('/'); xmlDir.append(engine.getName()); xmlDir.append('/'); xmlDir.append(host.getName()); configBase = getAbsolutePath(xmlDir.toString()); } // Retrieve the MBean server mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); started = true; count = 0; getCluster().addClusterListener(this); if (log.isInfoEnabled()) log.info(sm.getString("farmWarDeployer.started")); } /* * stop cluster wide deployments * * @see org.apache.catalina.ha.ClusterDeployer#stop() */ @Override public void stop() throws LifecycleException { started = false; getCluster().removeClusterListener(this); count = 0; if (watcher != null) { watcher.clear(); watcher = null; } if (log.isInfoEnabled()) log.info(sm.getString("farmWarDeployer.stopped")); } public void cleanDeployDir() { throw new java.lang.UnsupportedOperationException(sm.getString( "farmWarDeployer.notImplemented", "cleanDeployDir()")); } /** * Callback from the cluster, when a message is received, The cluster will * broadcast it invoking the messageReceived on the receiver. * * @param msg * ClusterMessage - the message received from the cluster */ @Override public void messageReceived(ClusterMessage msg) { try { if (msg instanceof FileMessage) { FileMessage fmsg = (FileMessage) msg; if (log.isDebugEnabled()) log.debug(sm.getString("farmWarDeployer.msgRxDeploy", fmsg.getContextName(), fmsg.getFileName())); FileMessageFactory factory = getFactory(fmsg); // TODO correct second try after app is in service! if (factory.writeMessage(fmsg)) { //last message received war file is completed String name = factory.getFile().getName(); if (!name.endsWith(".war")) name = name + ".war"; File deployable = new File(getDeployDirFile(), name); try { String contextName = fmsg.getContextName(); if (!isServiced(contextName)) { addServiced(contextName); try { remove(contextName); if (!factory.getFile().renameTo(deployable)) { log.error(sm.getString( "farmWarDeployer.renameFail", factory.getFile(), deployable)); } check(contextName); } finally { removeServiced(contextName); } if (log.isDebugEnabled()) log.debug(sm.getString( "farmWarDeployer.deployEnd", contextName)); } else log.error(sm.getString( "farmWarDeployer.servicingDeploy", contextName, name)); } catch (Exception ex) { log.error(ex); } finally { removeFactory(fmsg); } } } else if (msg instanceof UndeployMessage) { try { UndeployMessage umsg = (UndeployMessage) msg; String contextName = umsg.getContextName(); if (log.isDebugEnabled()) log.debug(sm.getString("farmWarDeployer.msgRxUndeploy", contextName)); if (!isServiced(contextName)) { addServiced(contextName); try { remove(contextName); } finally { removeServiced(contextName); } if (log.isDebugEnabled()) log.debug(sm.getString( "farmWarDeployer.undeployEnd", contextName)); } else log.error(sm.getString( "farmWarDeployer.servicingUneploy", contextName)); } catch (Exception ex) { log.error(ex); } } } catch (java.io.IOException x) { log.error(sm.getString("farmWarDeployer.msgIoe"), x); } } /** * create factory for all transported war files * * @param msg * @return Factory for all app message (war files) * @throws java.io.FileNotFoundException * @throws java.io.IOException */ public synchronized FileMessageFactory getFactory(FileMessage msg) throws java.io.FileNotFoundException, java.io.IOException { File writeToFile = new File(getTempDirFile(), msg.getFileName()); FileMessageFactory factory = fileFactories.get(msg.getFileName()); if (factory == null) { factory = FileMessageFactory.getInstance(writeToFile, true); factory.setMaxValidTime(maxValidTime); fileFactories.put(msg.getFileName(), factory); } return factory; } /** * Remove file (war) from messages) * * @param msg */ public void removeFactory(FileMessage msg) { fileFactories.remove(msg.getFileName()); } /** * Before the cluster invokes messageReceived the cluster will ask the * receiver to accept or decline the message, In the future, when messages * get big, the accept method will only take a message header * * @param msg * ClusterMessage * @return boolean - returns true to indicate that messageReceived should be * invoked. If false is returned, the messageReceived method will * not be invoked. */ @Override public boolean accept(ClusterMessage msg) { return (msg instanceof FileMessage) || (msg instanceof UndeployMessage); } /** * Install a new web application, whose web application archive is at the * specified URL, into this container and all the other members of the * cluster with the specified context name. *

    * If this application is successfully installed locally, a ContainerEvent * of type INSTALL_EVENT will be sent to all registered * listeners, with the newly created Context as an argument. * * @param contextName * The context name to which this application should be installed * (must be unique) * @param webapp * A WAR file or unpacked directory structure containing the web * application to be installed * * @exception IllegalArgumentException * if the specified context name is malformed * @exception IllegalStateException * if the specified context name is already deployed * @exception IOException * if an input/output error was encountered during * installation */ @Override public void install(String contextName, File webapp) throws IOException { Member[] members = getCluster().getMembers(); if (members.length == 0) return; Member localMember = getCluster().getLocalMember(); FileMessageFactory factory = FileMessageFactory.getInstance(webapp, false); FileMessage msg = new FileMessage(localMember, webapp.getName(), contextName); if(log.isDebugEnabled()) log.debug(sm.getString("farmWarDeployer.sendStart", contextName, webapp)); msg = factory.readMessage(msg); while (msg != null) { for (int i = 0; i < members.length; i++) { if (log.isDebugEnabled()) log.debug(sm.getString("farmWarDeployer.sendFragment", contextName, webapp, members[i])); getCluster().send(msg, members[i]); } msg = factory.readMessage(msg); } if(log.isDebugEnabled()) log.debug(sm.getString( "farmWarDeployer.sendEnd", contextName, webapp)); } /** * Remove an existing web application, attached to the specified context * name. If this application is successfully removed, a ContainerEvent of * type REMOVE_EVENT will be sent to all registered * listeners, with the removed Context as an argument. * Deletes the web application war file and/or directory if they exist in * the Host's appBase. * * @param contextName * The context name of the application to be removed * @param undeploy * boolean flag to remove web application from server * * @exception IllegalArgumentException * if the specified context name is malformed * @exception IllegalArgumentException * if the specified context name does not identify a * currently installed web application * @exception IOException * if an input/output error occurs during removal */ @Override public void remove(String contextName, boolean undeploy) throws IOException { if (getCluster().getMembers().length > 0) { if (log.isInfoEnabled()) log.info(sm.getString("farmWarDeployer.removeStart", contextName)); Member localMember = getCluster().getLocalMember(); UndeployMessage msg = new UndeployMessage(localMember, System .currentTimeMillis(), "Undeploy:" + contextName + ":" + System.currentTimeMillis(), contextName, undeploy); if (log.isDebugEnabled()) log.debug(sm.getString("farmWarDeployer.removeTxMsg", contextName)); cluster.send(msg); } // remove locally if (undeploy) { try { if (!isServiced(contextName)) { addServiced(contextName); try { remove(contextName); } finally { removeServiced(contextName); } } else log.error(sm.getString("farmWarDeployer.removeFailRemote", contextName)); } catch (Exception ex) { log.error(sm.getString("farmWarDeployer.removeFailLocal", contextName), ex); } } } /* * Modification from watchDir war detected! * * @see org.apache.catalina.ha.deploy.FileChangeListener#fileModified(File) */ @Override public void fileModified(File newWar) { try { File deployWar = new File(getDeployDirFile(), newWar.getName()); ContextName cn = new ContextName(deployWar.getName(), true); if (deployWar.exists() && deployWar.lastModified() > newWar.lastModified()) { if (log.isInfoEnabled()) log.info(sm.getString("farmWarDeployer.alreadyDeployed", cn.getName())); return; } if (log.isInfoEnabled()) log.info(sm.getString("farmWarDeployer.modInstall", cn.getName(), deployWar.getAbsolutePath())); // install local if (!isServiced(cn.getName())) { addServiced(cn.getName()); try { copy(newWar, deployWar); check(cn.getName()); } finally { removeServiced(cn.getName()); } } else { log.error(sm.getString("farmWarDeployer.servicingDeploy", cn.getName(), deployWar.getName())); } install(cn.getName(), deployWar); } catch (Exception x) { log.error(sm.getString("farmWarDeployer.modInstallFail"), x); } } /* * War remove from watchDir * * @see org.apache.catalina.ha.deploy.FileChangeListener#fileRemoved(File) */ @Override public void fileRemoved(File removeWar) { try { ContextName cn = new ContextName(removeWar.getName(), true); if (log.isInfoEnabled()) log.info(sm.getString("farmWarDeployer.removeLocal", cn.getName())); remove(cn.getName(), true); } catch (Exception x) { log.error(sm.getString("farmWarDeployer.removeLocalFail"), x); } } /** * Return a File object representing the "application root" directory for * our associated Host. */ protected File getAppBase() { if (appBase != null) { return appBase; } File file = new File(host.getAppBase()); if (!file.isAbsolute()) file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), host .getAppBase()); try { appBase = file.getCanonicalFile(); } catch (IOException e) { appBase = file; } return (appBase); } /** * Invoke the remove method on the deployer. */ protected void remove(String contextName) throws Exception { // TODO Handle remove also work dir content ! // Stop the context first to be nicer Context context = (Context) host.findChild(contextName); if (context != null) { if(log.isDebugEnabled()) log.debug(sm.getString("farmWarDeployer.undeployLocal", contextName)); context.stop(); String baseName = context.getBaseName(); File war = new File(getAppBase(), baseName + ".war"); File dir = new File(getAppBase(), baseName); File xml = new File(configBase, baseName + ".xml"); if (war.exists()) { if (!war.delete()) { log.error(sm.getString("farmWarDeployer.deleteFail", war)); } } else if (dir.exists()) { undeployDir(dir); } else { if (!xml.delete()) { log.error(sm.getString("farmWarDeployer.deleteFail", xml)); } } // Perform new deployment and remove internal HostConfig state check(contextName); } } /** * Delete the specified directory, including all of its contents and * subdirectories recursively. * * @param dir * File object representing the directory to be deleted */ protected void undeployDir(File dir) { String files[] = dir.list(); if (files == null) { files = new String[0]; } for (int i = 0; i < files.length; i++) { File file = new File(dir, files[i]); if (file.isDirectory()) { undeployDir(file); } else { if (!file.delete()) { log.error(sm.getString("farmWarDeployer.deleteFail", file)); } } } if (!dir.delete()) { log.error(sm.getString("farmWarDeployer.deleteFail", dir)); } } /* * Call watcher to check for deploy changes * * @see org.apache.catalina.ha.ClusterDeployer#backgroundProcess() */ @Override public void backgroundProcess() { if (started) { if (watchEnabled) { count = (count + 1) % processDeployFrequency; if (count == 0) { watcher.check(); } } removeInvalidFileFactories(); } } /*--Deployer Operations ------------------------------------*/ /** * Invoke the check method on the deployer. */ protected void check(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; mBeanServer.invoke(oname, "check", params, signature); } /** * Invoke the check method on the deployer. */ protected boolean isServiced(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced", params, signature); return result.booleanValue(); } /** * Invoke the check method on the deployer. */ protected void addServiced(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; mBeanServer.invoke(oname, "addServiced", params, signature); } /** * Invoke the check method on the deployer. */ protected void removeServiced(String name) throws Exception { String[] params = { name }; String[] signature = { "java.lang.String" }; mBeanServer.invoke(oname, "removeServiced", params, signature); } /*--Instance Getters/Setters--------------------------------*/ @Override public boolean equals(Object listener) { return super.equals(listener); } @Override public int hashCode() { return super.hashCode(); } public String getDeployDir() { return deployDir; } public File getDeployDirFile() { if (deployDirFile != null) return deployDirFile; File dir = getAbsolutePath(getDeployDir()); this.deployDirFile = dir; return dir; } public void setDeployDir(String deployDir) { this.deployDir = deployDir; } public String getTempDir() { return tempDir; } public File getTempDirFile() { if (tempDirFile != null) return tempDirFile; File dir = getAbsolutePath(getTempDir()); this.tempDirFile = dir; return dir; } public void setTempDir(String tempDir) { this.tempDir = tempDir; } public String getWatchDir() { return watchDir; } public File getWatchDirFile() { if (watchDirFile != null) return watchDirFile; File dir = getAbsolutePath(getWatchDir()); this.watchDirFile = dir; return dir; } public void setWatchDir(String watchDir) { this.watchDir = watchDir; } public boolean isWatchEnabled() { return watchEnabled; } public boolean getWatchEnabled() { return watchEnabled; } public void setWatchEnabled(boolean watchEnabled) { this.watchEnabled = watchEnabled; } /** * Return the frequency of watcher checks. */ public int getProcessDeployFrequency() { return (this.processDeployFrequency); } /** * Set the watcher checks frequency. * * @param processExpiresFrequency * the new manager checks frequency */ public void setProcessDeployFrequency(int processExpiresFrequency) { if (processExpiresFrequency <= 0) { return; } this.processDeployFrequency = processExpiresFrequency; } public int getMaxValidTime() { return maxValidTime; } public void setMaxValidTime(int maxValidTime) { this.maxValidTime = maxValidTime; } /** * Copy a file to the specified temp directory. * @param from copy from temp * @param to to host appBase directory * @return true, copy successful */ protected boolean copy(File from, File to) { try { if (!to.exists()) { if (!to.createNewFile()) { log.error(sm.getString("fileNewFail", to)); return false; } } java.io.FileInputStream is = new java.io.FileInputStream(from); java.io.FileOutputStream os = new java.io.FileOutputStream(to, false); byte[] buf = new byte[4096]; while (true) { int len = is.read(buf); if (len < 0) break; os.write(buf, 0, len); } is.close(); os.close(); } catch (IOException e) { log.error(sm.getString("farmWarDeployer.fileCopyFail", from, to), e); return false; } return true; } protected void removeInvalidFileFactories() { String[] fileNames = fileFactories.keySet().toArray(new String[0]); for (String fileName : fileNames) { FileMessageFactory factory = fileFactories.get(fileName); if (!factory.isValid()) { fileFactories.remove(fileName); } } } private File getAbsolutePath(String path) { File dir = new File(path); File base = new File(System.getProperty(Globals.CATALINA_BASE_PROP)); if (!dir.isAbsolute()) { dir = new File(base, dir.getPath()); } try { dir = dir.getCanonicalFile(); } catch (IOException e) {// ignore } return dir; } } tomcat7-7.0.52/java/org/apache/catalina/ha/deploy/UndeployMessage.java0000644000175100017510000000620012271463015025502 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.deploy; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.tribes.Member; public class UndeployMessage implements ClusterMessage { private static final long serialVersionUID = 1L; private Member address; private long timestamp; private String uniqueId; private String contextName; private boolean undeploy; private int resend = 0; private int compress = 0; public UndeployMessage() {} //for serialization public UndeployMessage(Member address, long timestamp, String uniqueId, String contextName, boolean undeploy) { this.address = address; this.timestamp= timestamp; this.undeploy = undeploy; this.uniqueId = uniqueId; this.undeploy = undeploy; this.contextName = contextName; } @Override public Member getAddress() { return address; } @Override public void setAddress(Member address) { this.address = address; } @Override public long getTimestamp() { return timestamp; } @Override public void setTimestamp(long timestamp) { this.timestamp = timestamp; } @Override public String getUniqueId() { return uniqueId; } @Override public void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } public String getContextName() { return contextName; } public void setContextPath(String contextName) { this.contextName = contextName; } public boolean getUndeploy() { return undeploy; } public void setUndeploy(boolean undeploy) { this.undeploy = undeploy; } /** * @return Returns the compress. * @since 5.5.10 */ public int getCompress() { return compress; } /** * @param compress The compress to set. * @since 5.5.10 */ public void setCompress(int compress) { this.compress = compress; } /** * @return Returns the resend. * @since 5.5.10 */ public int getResend() { return resend; } /** * @param resend The resend to set. * @since 5.5.10 */ public void setResend(int resend) { this.resend = resend; } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/0000755000175100017510000000000012301126370021716 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/session/LocalStrings_es.properties0000644000175100017510000002030112271463015027131 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. deltaManager.createSession.newSession = Creada una DeltaSession con Id [{0}] Total contador\={1} deltaManager.createMessage.access = Gestor [{0}]\: creado mensaje de sesi\u00F3n [{1}] acceso. deltaManager.createMessage.accessChangePrimary = Gestor [{0}]\: creado mensaje de sesi\u00F3n [{1}] acceso para cambiar el primario. deltaManager.createMessage.allSessionData = Gestor [{0}] env\u00EDa todos los datos de sesi\u00F3n. deltaManager.createMessage.allSessionTransfered = Gestor [{0}] env\u00EDa todos los datos de sesi\u00F3n transferidos deltaManager.createMessage.delta = Gestor [{0}]\: crea mensaje de sesi\u00F3n [{1}] de requerimiento delta. deltaManager.createMessage.expire = Gestor [{0}]\: crea mensaje de sesi\u00F3n [{1}] de expiraci\u00F3n. deltaManager.createMessage.unableCreateDeltaRequest = No puedo serializar requerimiento delta para la id de sesi\u00F3n [{0}] deltaManager.dropMessage = Gestor [{0}]\: Quita mensaje {1} dentro de fase sincronizada GET_ALL_SESSIONS fecha inicio {2} fecha mensaje {3} deltaManager.foundMasterMember = Hallado para contexto [{0}] el miembro maestro de r\u00E9plica [{1}] deltaManager.loading.cnfe = ClassNotFoundException al cargar sesiones persistentes\: {0} deltaManager.loading.existing.session = sobrecarga en sesi\u00F3n existente {0} deltaManager.loading.ioe = IOException al cargar sesiones persistentes\: {0} deltaManager.loading.withContextClassLoader = Gestor [{0}]\: Cargando los datos de objeto con un cargador de clase de contexto. deltaManager.loading.withoutClassLoader = Gestor [{0}]\: Cargando los datos de objeto sin un cargador de clase de contexto. deltaManager.managerLoad = Excepci\u00F3n cargando sesiones desde almacenaje persistente deltaManager.noCluster = Arrancando... no hay cl\u00FAster asociado con este contexto\: [{0}] deltaManager.noMasterMember = Arrancando... sin otro miembro para el contexto [{0}] en dominio [{1}] deltaManager.noMembers = Gestor [{0}]\: saltando estado de transferencia. No hay miembros activos en grupo de cl\u00FAster. deltaManager.noSessionState = Gestor [{0}]\: No se ha recibido estado de sesi\u00F3n a las {1}, agotando tiempo tras {2} ms. deltaManager.sendMessage.newSession = El gestor [{0}] env\u00EDa nueva sesi\u00F3n ({1}) deltaManager.expireSessions = Gestor [{0}] expirando sesiones al apagar deltaManager.receiveMessage.accessed = Gestor [{0}]\: accedida sesi\u00F3n [{1}] recibida. deltaManager.receiveMessage.createNewSession = Gestor [{0}]\: creada sesi\u00F3n [{1}] recibida. deltaManager.receiveMessage.delta = Gestor [{0}]\: delta sesi\u00F3n [{1}] recibida. deltaManager.receiveMessage.error = Gestor [{0}]\: No puedo recibir mensaje a trav\u00E9s del canal TCP deltaManager.receiveMessage.eventType = Gestor [{0}]\: recibido SessionMessage de tipo\=({1}) desde [{2}] deltaManager.receiveMessage.expired = Gestor [{0}]\: expirada sesi\u00F3n [{1}] recibida. deltaManager.receiveMessage.transfercomplete = Gestor [{0}] recibido desde nodo [{1}\:{2}] estado de sesi\u00F3n transferido. deltaManager.receiveMessage.unloadingAfter = Gestor [{0}]\: completada la descarga de sesiones deltaManager.receiveMessage.unloadingBegin = Gestor [{0}]\: iniciada descarga de sesiones deltaManager.receiveMessage.allSessionDataAfter = Gestor [{0}]\: estado de sesi\u00F3n deserializado deltaManager.receiveMessage.allSessionDataBegin = Gestor [{0}]\: recibidos datos de estado de sesi\u00F3n deltaManager.receiveMessage.fromWrongDomain = Gestor [{0}]\: Recibido SessionMessage equivocado de tipo\=({1}) desde [{2}] con dominio [{3}] (dominio local [{4}] deltaManager.registerCluster = Registrar gestor {0} a elemento de cl\u00FAster {1} con nombre {2} deltaManager.sessionReceived = Gestor [{0}]; estado de sesi\u00F3n enviado a las {1} recibido en {2} ms. deltaManager.startClustering = Iniciando gestor de cl\u00FAster a las {0} deltaManager.stopped = El gestor [{0}] se est\u00E1 parando deltaManager.unloading.ioe = IOException al grabar sesiones persistentes\: {0} deltaManager.waitForSessionState = Gestor [{0}], requiriendo estado de sesi\u00F3n desde {1}. Esta operaci\u00F3n se agotar\u00E1 si no se recibe estado de sesi\u00F3n dentro de {2} segundos. deltaManager.unableSerializeSessionID = No puedo seriallizar la ID de sesi\u00F3n [{0}] deltaRequest.showPrincipal = El Principal [{0}] est\u00E1 puesto a sesi\u00F3n {1} deltaRequest.wrongPrincipalClass = DeltaManager s\u00F3lo soporta GenericPrincipal. Tu reino utiliz\u00F3 clase principal {0}. deltaSession.notifying = Notificando cl\u00FAster de expiraci\u00F3n primaria\={0} sessionId [{1}] deltaSession.valueBound.ex = Oyente ligado a sesi\u00F3n lanz\u00F3 una excepci\u00F3n deltaSession.valueBinding.ex = Oyente lig\u00E1ndose a sesi\u00F3n lanz\u00F3 una excepci\u00F3n deltaSession.valueUnbound.ex = Oyente desligado de sesi\u00F3n lanz\u00F3 una excepci\u00F3n deltaSession.readSession = readObject() cargando sesi\u00F3n [{0}] deltaSession.readAttribute = sesi\u00F3n [{0}] cargando atributo '{1}' con valor '{2}' deltaSession.writeSession = writeObject() guardando sesi\u00F3n [{0}] jvmRoute.cannotFindSession = No puedo hallar sesi\u00F3n [{0}] jvmRoute.changeSession = Cambiada sesi\u00F3n desde [{0}] a [{1}] jvmRoute.clusterListener.started = Cl\u00FAster JvmRouteSessionIDBinderListener arrancado jvmRoute.clusterListener.stopped = Cl\u00FAster JvmRouteSessionIDBinderListener parado jvmRoute.configure.warn = Por favor, \u00A1configura tu JvmRouteBinderValve en la v\u00E1lvula de m\u00E1quina, no en la v\u00E1lvula del contexto\! jvmRoute.contextNotFound = \u00A1Contexto [{0}] no hallado en el nodo [{1}]\! jvmRoute.failover = Detectada una ca\u00EDda con diferente jvmRoute - ruta original\: [{0}] nueva\: [{1}] en id de sesi\u00F3n [{2}] jvmRoute.foundManager = Hallado Cl\u00FAster DeltaManager {0} en {1} jvmRoute.hostNotFound = No hallada m\u00E1quina [{0}] jvmRoute.listener.started = Arrancado Oyente Ligador de SessionID jvmRoute.listener.stopped = Parado Oyente Ligador de SessionID jvmRoute.lostSession = Perdida Sesi\u00F3n [{0}] en ruta [{1}] jvmRoute.missingJvmRouteAttribute = \u00A1No se ha configurado atributo de motor jvmRoute\! jvmRoute.newSessionCookie = Poniendo cookie con id de sesi\u00F3n [{0}] nombre\: [{1}] ruta\: [{2}] seguro\: [{3}] httpOnly\: [{4}] jvmRoute.noCluster = La v\u00E1lvula JvmRouterBinderValve se encuentra configurada, pero no se usa el cl\u00FAster. A\u00FAn funcionar\u00E1 la tolerancia a fallos, siempre que se est\u00E9 usando PersistentManager. jvmRoute.notFoundManager = No hallado Cl\u00FAster DeltaManager {0} en {1} jvmRoute.receiveMessage.sessionIDChanged = Cl\u00FAster JvmRouteSessionIDBinderListener recibi\u00F3 ID original de sesi\u00F3n [{0}] puesto a nuevo id [{1}] para la ruta de contexto [{2}] jvmRoute.run.already = receptor jvmRoute SessionID ya ejecutado jvmRoute.skipURLSessionIDs = \u00A1Saltado chequeo de reasignaci\u00F3n de ruta jvm, la sessionid viene desde URL\! jvmRoute.turnoverInfo = Ajustado tiempo de Chequeo a {0} mseg jvmRoute.valve.started = JvmRouteBinderValve arrancada jvmRoute.valve.stopped = JvmRouteBinderValve parada jvmRoute.set.orignalsessionid = Puesta id Orginal de Sesi\u00F3n en atributo de requerimiento {0} valor\: {1} standardSession.notSerializable = No puedo serializar atributo de sesi\u00F3n {0} para sesi\u00F3n {1} standardSession.removeAttribute.ise = removeAttribute\: Sesi\u00F3n ya invalidada standardSession.setAttribute.namenull = setAttribute\: par\u00E1metro de nombre no puede ser nulo serializablePrincipal.readPrincipal.cnfe = readPrincipal\: No pude volver a crea el usuario Principal tomcat7-7.0.52/java/org/apache/catalina/ha/session/BackupManager.java0000644000175100017510000002227112271463015025273 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.catalina.Cluster; import org.apache.catalina.DistributedManager; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.tipis.AbstractReplicatedMap.MapOwner; import org.apache.catalina.tribes.tipis.LazyReplicatedMap; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** *@author Filip Hanik *@version 1.0 */ public class BackupManager extends ClusterManagerBase implements MapOwner, DistributedManager { private final Log log = LogFactory.getLog(BackupManager.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); protected static long DEFAULT_REPL_TIMEOUT = 15000;//15 seconds /** * Set to true if we don't want the sessions to expire on shutdown * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected boolean mExpireSessionsOnShutdown = true; /** * The name of this manager */ protected String name; /** * */ private int mapSendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK|Channel.SEND_OPTIONS_USE_ACK; /** * Timeout for RPC messages. */ private long rpcTimeout = DEFAULT_REPL_TIMEOUT; /** * Flag for whether to terminate this map that failed to start. */ private boolean terminateOnStartFailure = false; /** * Constructor, just calls super() * */ public BackupManager() { super(); } //******************************************************************************/ // ClusterManager Interface //******************************************************************************/ @Override public void messageDataReceived(ClusterMessage msg) { } /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public void setExpireSessionsOnShutdown(boolean expireSessionsOnShutdown) { mExpireSessionsOnShutdown = expireSessionsOnShutdown; } /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public boolean getExpireSessionsOnShutdown() { return mExpireSessionsOnShutdown; } @Override public ClusterMessage requestCompleted(String sessionId) { if (!getState().isAvailable()) return null; LazyReplicatedMap map = (LazyReplicatedMap)sessions; map.replicate(sessionId,false); return null; } //========================================================================= // OVERRIDE THESE METHODS TO IMPLEMENT THE REPLICATION //========================================================================= @Override public void objectMadePrimay(Object key, Object value) { if (value!=null && value instanceof DeltaSession) { DeltaSession session = (DeltaSession)value; synchronized (session) { session.access(); session.setPrimarySession(true); session.endAccess(); } } } @Override public Session createEmptySession() { return new DeltaSession(this); } @Override public String getName() { return this.name; } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * Starts the cluster communication channel, this will connect with the * other nodes in the cluster, and request the current session state to be * transferred to this node. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @SuppressWarnings("unchecked") @Override protected synchronized void startInternal() throws LifecycleException { super.startInternal(); try { if (getCluster() == null) { Cluster cluster = getContainer().getCluster(); if (cluster instanceof CatalinaCluster) { setCluster((CatalinaCluster)cluster); } else { throw new LifecycleException( sm.getString("backupManager.noCluster", getName())); } } cluster.registerManager(this); LazyReplicatedMap map = new LazyReplicatedMap(this, cluster.getChannel(), rpcTimeout, getMapName(), getClassLoaders(), terminateOnStartFailure); map.setChannelSendOptions(mapSendOptions); this.sessions = map; } catch ( Exception x ) { log.error(sm.getString("backupManager.startUnable", getName()),x); throw new LifecycleException(sm.getString("backupManager.startFailed", getName()),x); } setState(LifecycleState.STARTING); } public String getMapName() { String name = cluster.getManagerName(getName(),this)+"-"+"map"; if ( log.isDebugEnabled() ) log.debug("Backup manager, Setting map name to:"+name); return name; } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * This will disconnect the cluster communication channel and stop the * listener thread. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { if (log.isDebugEnabled()) log.debug(sm.getString("backupManager.stopped", getName())); setState(LifecycleState.STOPPING); if (sessions instanceof LazyReplicatedMap) { LazyReplicatedMap map = (LazyReplicatedMap)sessions; map.breakdown(); } cluster.removeManager(this); super.stopInternal(); } @Override public void setDistributable(boolean dist) { this.distributable = dist; } @Override public void setName(String name) { this.name = name; } public void setMapSendOptions(int mapSendOptions) { this.mapSendOptions = mapSendOptions; } public int getMapSendOptions() { return mapSendOptions; } public void setRpcTimeout(long rpcTimeout) { this.rpcTimeout = rpcTimeout; } public long getRpcTimeout() { return rpcTimeout; } public void setTerminateOnStartFailure(boolean terminateOnStartFailure) { this.terminateOnStartFailure = terminateOnStartFailure; } public boolean isTerminateOnStartFailure() { return terminateOnStartFailure; } @Override public String[] getInvalidatedSessions() { return new String[0]; } @Override public ClusterManager cloneFromTemplate() { BackupManager result = new BackupManager(); clone(result); result.mExpireSessionsOnShutdown = mExpireSessionsOnShutdown; result.mapSendOptions = mapSendOptions; result.rpcTimeout = rpcTimeout; result.terminateOnStartFailure = terminateOnStartFailure; return result; } @Override public int getActiveSessionsFull() { LazyReplicatedMap map = (LazyReplicatedMap)sessions; return map.sizeFull(); } @Override public Set getSessionIdsFull() { Set sessionIds = new HashSet(); LazyReplicatedMap map = (LazyReplicatedMap)sessions; @SuppressWarnings("unchecked") // sessions is of type Map Iterator keys = map.keySetFull().iterator(); while (keys.hasNext()) { sessionIds.add(keys.next()); } return sessionIds; } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/DeltaSession.java0000644000175100017510000007201212271463015025166 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import java.io.Externalizable; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.Principal; import java.util.ArrayList; import java.util.Hashtable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.catalina.Manager; import org.apache.catalina.SessionListener; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.ha.ClusterSession; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.session.ManagerBase; import org.apache.catalina.session.StandardManager; import org.apache.catalina.session.StandardSession; import org.apache.catalina.tribes.io.ReplicationStream; import org.apache.catalina.tribes.tipis.ReplicatedMapEntry; import org.apache.tomcat.util.res.StringManager; /** * * Similar to the StandardSession except that this session will keep * track of deltas during a request. * * @author Filip Hanik */ public class DeltaSession extends StandardSession implements Externalizable,ClusterSession,ReplicatedMapEntry { public static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(DeltaSession.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ----------------------------------------------------- Instance Variables /** * only the primary session will expire, or be able to expire due to * inactivity. This is set to false as soon as I receive this session over * the wire in a session message. That means that someone else has made a * request on another server. */ private transient boolean isPrimarySession = true; /** * The delta request contains all the action info * */ private transient DeltaRequest deltaRequest = null; /** * Last time the session was replicated, used for distributed expiring of * session */ private transient long lastTimeReplicated = System.currentTimeMillis(); protected final Lock diffLock = new ReentrantReadWriteLock().writeLock(); private long version; // ----------------------------------------------------------- Constructors public DeltaSession() { this(null); } /** * Construct a new Session associated with the specified Manager. * * @param manager * The manager with which this Session is associated */ public DeltaSession(Manager manager) { super(manager); this.resetDeltaRequest(); } // ----------------------------------------------------- ReplicatedMapEntry /** * Has the object changed since last replication * and is not in a locked state * @return boolean */ @Override public boolean isDirty() { return getDeltaRequest().getSize()>0; } /** * If this returns true, the map will extract the diff using getDiff() * Otherwise it will serialize the entire object. * @return boolean */ @Override public boolean isDiffable() { return true; } /** * Returns a diff and sets the dirty map to false * @return byte[] * @throws IOException */ @Override public byte[] getDiff() throws IOException { try{ lock(); return getDeltaRequest().serialize(); }finally{ unlock(); } } public ClassLoader[] getClassLoaders() { if ( manager instanceof BackupManager ) return ((BackupManager)manager).getClassLoaders(); else if ( manager instanceof ClusterManagerBase ) return ((ClusterManagerBase)manager).getClassLoaders(); else if ( manager instanceof StandardManager ) { StandardManager sm = (StandardManager)manager; return ClusterManagerBase.getClassLoaders(sm.getContainer()); } else if ( manager instanceof ManagerBase ) { ManagerBase mb = (ManagerBase)manager; return ClusterManagerBase.getClassLoaders(mb.getContainer()); }//end if return null; } /** * Applies a diff to an existing object. * @param diff byte[] * @param offset int * @param length int * @throws IOException */ @Override public void applyDiff(byte[] diff, int offset, int length) throws IOException, ClassNotFoundException { try { lock(); ReplicationStream stream = ( (ClusterManager) getManager()).getReplicationStream(diff, offset, length); ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); try { ClassLoader[] loaders = getClassLoaders(); if (loaders != null && loaders.length > 0) Thread.currentThread().setContextClassLoader(loaders[0]); getDeltaRequest().readExternal(stream); getDeltaRequest().execute(this, ((ClusterManager)getManager()).isNotifyListenersOnReplication()); } finally { Thread.currentThread().setContextClassLoader(contextLoader); } }finally { unlock(); } } /** * Resets the current diff state and resets the dirty flag */ @Override public void resetDiff() { resetDeltaRequest(); } /** * Lock during serialization */ @Override public void lock() { diffLock.lock(); } /** * Unlock after serialization */ @Override public void unlock() { diffLock.unlock(); } @Override public void setOwner(Object owner) { if ( owner instanceof ClusterManager && getManager()==null) { ClusterManager cm = (ClusterManager)owner; this.setManager(cm); this.setValid(true); this.setPrimarySession(false); this.access(); this.resetDeltaRequest(); this.endAccess(); } } /** * If this returns true, to replicate that an object has been accessed * @return boolean */ @Override public boolean isAccessReplicate() { long replDelta = System.currentTimeMillis() - getLastTimeReplicated(); if (maxInactiveInterval >=0 && replDelta > (maxInactiveInterval * 1000)) { return true; } return false; } /** * Access to an existing object. */ @Override public void accessEntry() { this.access(); this.setPrimarySession(false); this.endAccess(); } // ----------------------------------------------------- Session Properties /** * returns true if this session is the primary session, if that is the case, * the manager can expire it upon timeout. */ @Override public boolean isPrimarySession() { return isPrimarySession; } /** * Sets whether this is the primary session or not. * * @param primarySession * Flag value */ @Override public void setPrimarySession(boolean primarySession) { this.isPrimarySession = primarySession; } /** * {@inheritDoc} */ @Override public void setId(String id, boolean notify) { super.setId(id, notify); resetDeltaRequest(); } /** * Set the session identifier for this session. * * @param id * The new session identifier */ @Override public void setId(String id) { super.setId(id, true); resetDeltaRequest(); } @Override public void setMaxInactiveInterval(int interval) { this.setMaxInactiveInterval(interval,true); } public void setMaxInactiveInterval(int interval, boolean addDeltaRequest) { super.maxInactiveInterval = interval; if (addDeltaRequest && (deltaRequest != null)) { try { lock(); deltaRequest.setMaxInactiveInterval(interval); }finally{ unlock(); } } } /** * Set the isNew flag for this session. * * @param isNew * The new value for the isNew flag */ @Override public void setNew(boolean isNew) { setNew(isNew, true); } public void setNew(boolean isNew, boolean addDeltaRequest) { super.setNew(isNew); if (addDeltaRequest && (deltaRequest != null)){ try { lock(); deltaRequest.setNew(isNew); }finally{ unlock(); } } } /** * Set the authenticated Principal that is associated with this Session. * This provides an Authenticator with a means to cache a * previously authenticated Principal, and avoid potentially expensive * Realm.authenticate() calls on every request. * * @param principal * The new Principal, or null if none */ @Override public void setPrincipal(Principal principal) { setPrincipal(principal, true); } public void setPrincipal(Principal principal, boolean addDeltaRequest) { try { lock(); super.setPrincipal(principal); if (addDeltaRequest && (deltaRequest != null)) deltaRequest.setPrincipal(principal); } finally { unlock(); } } /** * Set the authentication type used to authenticate our cached * Principal, if any. * * @param authType The new cached authentication type */ @Override public void setAuthType(String authType) { setAuthType(authType, true); } public void setAuthType(String authType, boolean addDeltaRequest) { try { lock(); super.setAuthType(authType); if (addDeltaRequest && (deltaRequest != null)) deltaRequest.setAuthType(authType); } finally { unlock(); } } /** * Return the isValid flag for this session. */ @Override public boolean isValid() { if (!this.isValid) { return false; } if (this.expiring) { return true; } if (ACTIVITY_CHECK && accessCount.get() > 0) { return true; } if (maxInactiveInterval > 0) { long timeNow = System.currentTimeMillis(); int timeIdle; if (LAST_ACCESS_AT_START) { timeIdle = (int) ((timeNow - lastAccessedTime) / 1000L); } else { timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L); } if (isPrimarySession()) { if (timeIdle >= maxInactiveInterval) { expire(true); } } else { if (timeIdle >= (2 * maxInactiveInterval)) { //if the session has been idle twice as long as allowed, //the primary session has probably crashed, and no other //requests are coming in. that is why we do this. otherwise //we would have a memory leak expire(true, false); } } } return (this.isValid); } /** * End the access and register to ReplicationValve (crossContext support) */ @Override public void endAccess() { super.endAccess() ; if(manager instanceof DeltaManager) { ((DeltaManager)manager).registerSessionAtReplicationValve(this); } } // ------------------------------------------------- Session Public Methods /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. * * @param notify * Should we notify listeners about the demise of this session? */ @Override public void expire(boolean notify) { expire(notify, true); } public void expire(boolean notify, boolean notifyCluster) { // Check to see if session has already been invalidated. // Do not check expiring at this point as expire should not return until // isValid is false if (!isValid) return; synchronized (this) { // Check again, now we are inside the sync so this code only runs once // Double check locking - isValid needs to be volatile if (!isValid) return; if (manager == null) return; // Mark this session as "being expired". The flag will be unset in // the call to super.expire(notify) expiring = true; String expiredId = getIdInternal(); if(notifyCluster && expiredId != null && manager instanceof DeltaManager) { DeltaManager dmanager = (DeltaManager)manager; CatalinaCluster cluster = dmanager.getCluster(); ClusterMessage msg = dmanager.requestCompleted(expiredId, true); if (msg != null) { cluster.send(msg); } } super.expire(notify); if (notifyCluster) { if (log.isDebugEnabled()) log.debug(sm.getString("deltaSession.notifying", ((ClusterManager)manager).getName(), Boolean.valueOf(isPrimarySession()), expiredId)); if ( manager instanceof DeltaManager ) { ( (DeltaManager) manager).sessionExpired(expiredId); } } } } /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ @Override public void recycle() { try { lock(); super.recycle(); deltaRequest.clear(); }finally{ unlock(); } } /** * Return a string representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("DeltaSession["); sb.append(id); sb.append("]"); return (sb.toString()); } // ------------------------------------------------ Session Package Methods @Override public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException { try { lock(); readObjectData(in); }finally{ unlock(); } } /** * Read a serialized version of the contents of this session object from the * specified object input stream, without requiring that the StandardSession * itself have been serialized. * * @param stream * The object input stream to read from * * @exception ClassNotFoundException * if an unknown class is specified * @exception IOException * if an input/output error occurs */ @Override public void readObjectData(ObjectInputStream stream) throws ClassNotFoundException, IOException { readObject((ObjectInput)stream); } public void readObjectData(ObjectInput stream) throws ClassNotFoundException, IOException { readObject(stream); } /** * Write a serialized version of the contents of this session object to the * specified object output stream, without requiring that the * StandardSession itself have been serialized. * * @param stream * The object output stream to write to * * @exception IOException * if an input/output error occurs */ @Override public void writeObjectData(ObjectOutputStream stream) throws IOException { writeObjectData((ObjectOutput)stream); } public void writeObjectData(ObjectOutput stream) throws IOException { writeObject(stream); } public void resetDeltaRequest() { try { lock(); if (deltaRequest == null) { deltaRequest = new DeltaRequest(getIdInternal(), false); } else { deltaRequest.reset(); deltaRequest.setSessionId(getIdInternal()); } }finally{ unlock(); } } public DeltaRequest getDeltaRequest() { if (deltaRequest == null) resetDeltaRequest(); return deltaRequest; } // ------------------------------------------------- HttpSession Properties // ----------------------------------------------HttpSession Public Methods /** * Check whether the Object can be distributed. * The object is always distributable, if the cluster manager * decides to never distribute it. * @param name The name of the attribute to check * @param value The value of the attribute to check * @return true if the attribute is distributable, false otherwise */ @Override protected boolean isAttributeDistributable(String name, Object value) { if (manager instanceof ClusterManagerBase && !((ClusterManagerBase)manager).willAttributeDistribute(name)) return true; return super.isAttributeDistributable(name, value); } /** * Exclude attributes from replication. * @param name the attribute's name * @return true if attribute should not be replicated */ @Override protected boolean exclude(String name) { if (super.exclude(name)) return true; if (manager instanceof ClusterManagerBase) return !((ClusterManagerBase)manager).willAttributeDistribute(name); return false; } /** * Remove the object bound with the specified name from this session. If the * session does not have an object bound with this name, this method does * nothing. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueUnbound() on the object. * * @param name * Name of the object to remove from this session. * @param notify * Should we notify interested listeners that this attribute is * being removed? * * @exception IllegalStateException * if this method is called on an invalidated session */ @Override public void removeAttribute(String name, boolean notify) { removeAttribute(name, notify, true); } public void removeAttribute(String name, boolean notify,boolean addDeltaRequest) { // Validate our current state if (!isValid()) throw new IllegalStateException(sm.getString("standardSession.removeAttribute.ise")); removeAttributeInternal(name, notify, addDeltaRequest); } /** * Bind an object to this session, using the specified name. If an object of * the same name is already bound to this session, the object is replaced. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueBound() on the object. * * @param name * Name to which the object is bound, cannot be null * @param value * Object to be bound, cannot be null * * @exception IllegalArgumentException * if an attempt is made to add a non-serializable object in * an environment marked distributable. * @exception IllegalStateException * if this method is called on an invalidated session */ @Override public void setAttribute(String name, Object value) { setAttribute(name, value, true, true); } public void setAttribute(String name, Object value, boolean notify,boolean addDeltaRequest) { // Name cannot be null if (name == null) throw new IllegalArgumentException(sm.getString("standardSession.setAttribute.namenull")); // Null value is the same as removeAttribute() if (value == null) { removeAttribute(name); return; } try { lock(); super.setAttribute(name,value, notify); if (addDeltaRequest && deltaRequest != null && !exclude(name)) { deltaRequest.setAttribute(name, value); } } finally { unlock(); } } // -------------------------------------------- HttpSession Private Methods /** * Read a serialized version of this session object from the specified * object input stream. *

    * IMPLEMENTATION NOTE : The reference to the owning Manager is not * restored by this method, and must be set explicitly. * * @param stream * The input stream to read from * * @exception ClassNotFoundException * if an unknown class is specified * @exception IOException * if an input/output error occurs */ @Override protected void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { readObject((ObjectInput)stream); } private void readObject(ObjectInput stream) throws ClassNotFoundException, IOException { // Deserialize the scalar instance variables (except Manager) authType = null; // Transient only creationTime = ( (Long) stream.readObject()).longValue(); lastAccessedTime = ( (Long) stream.readObject()).longValue(); maxInactiveInterval = ( (Integer) stream.readObject()).intValue(); isNew = ( (Boolean) stream.readObject()).booleanValue(); isValid = ( (Boolean) stream.readObject()).booleanValue(); thisAccessedTime = ( (Long) stream.readObject()).longValue(); version = ( (Long) stream.readObject()).longValue(); boolean hasPrincipal = stream.readBoolean(); principal = null; if (hasPrincipal) { principal = SerializablePrincipal.readPrincipal(stream); } // setId((String) stream.readObject()); id = (String) stream.readObject(); if (log.isDebugEnabled()) log.debug(sm.getString("deltaSession.readSession", id)); // Deserialize the attribute count and attribute values if (attributes == null) attributes = new ConcurrentHashMap(); int n = ( (Integer) stream.readObject()).intValue(); boolean isValidSave = isValid; isValid = true; for (int i = 0; i < n; i++) { String name = (String) stream.readObject(); Object value = stream.readObject(); if ( (value instanceof String) && (value.equals(NOT_SERIALIZED))) continue; attributes.put(name, value); } isValid = isValidSave; if (listeners == null) { ArrayList arrayList = new ArrayList(); listeners = arrayList; } if (notes == null) { notes = new Hashtable(); } activate(); } @Override public void writeExternal(ObjectOutput out ) throws java.io.IOException { try { lock(); writeObject(out); }finally { unlock(); } } /** * Write a serialized version of this session object to the specified object * output stream. *

    * IMPLEMENTATION NOTE : The owning Manager will not be stored in the * serialized representation of this Session. After calling * readObject(), you must set the associated Manager * explicitly. *

    * IMPLEMENTATION NOTE : Any attribute that is not Serializable will * be unbound from the session, with appropriate actions if it implements * HttpSessionBindingListener. If you do not want any such attributes, be * sure the distributable property of the associated Manager * is set to true. * * @param stream * The output stream to write to * * @exception IOException * if an input/output error occurs */ @Override protected void writeObject(ObjectOutputStream stream) throws IOException { writeObject((ObjectOutput)stream); } private void writeObject(ObjectOutput stream) throws IOException { // Write the scalar instance variables (except Manager) stream.writeObject(Long.valueOf(creationTime)); stream.writeObject(Long.valueOf(lastAccessedTime)); stream.writeObject(Integer.valueOf(maxInactiveInterval)); stream.writeObject(Boolean.valueOf(isNew)); stream.writeObject(Boolean.valueOf(isValid)); stream.writeObject(Long.valueOf(thisAccessedTime)); stream.writeObject(Long.valueOf(version)); stream.writeBoolean(getPrincipal() != null); if (getPrincipal() != null) { SerializablePrincipal.writePrincipal((GenericPrincipal) principal,stream); } stream.writeObject(id); if (log.isDebugEnabled()) log.debug(sm.getString("deltaSession.writeSession", id)); // Accumulate the names of serializable and non-serializable attributes String keys[] = keys(); ArrayList saveNames = new ArrayList(); ArrayList saveValues = new ArrayList(); for (int i = 0; i < keys.length; i++) { Object value = null; value = attributes.get(keys[i]); if (value == null || exclude(keys[i])) continue; else if (value instanceof Serializable) { saveNames.add(keys[i]); saveValues.add(value); } } // Serialize the attribute count and the Serializable attributes int n = saveNames.size(); stream.writeObject(Integer.valueOf(n)); for (int i = 0; i < n; i++) { stream.writeObject( saveNames.get(i)); try { stream.writeObject(saveValues.get(i)); } catch (NotSerializableException e) { log.error(sm.getString("standardSession.notSerializable",saveNames.get(i), id), e); stream.writeObject(NOT_SERIALIZED); log.error(" storing attribute '" + saveNames.get(i)+ "' with value NOT_SERIALIZED"); } } } // -------------------------------------------------------- Private Methods /** * Return the value of an attribute without a check for validity. */ protected Object getAttributeInternal(String name) { return (attributes.get(name)); } protected void removeAttributeInternal(String name, boolean notify, boolean addDeltaRequest) { try { lock(); // Remove this attribute from our collection Object value = attributes.get(name); if (value == null) return; super.removeAttributeInternal(name,notify); if (addDeltaRequest && deltaRequest != null && !exclude(name)) { deltaRequest.removeAttribute(name); } }finally { unlock(); } } @Override public long getLastTimeReplicated() { return lastTimeReplicated; } @Override public long getVersion() { return version; } @Override public void setLastTimeReplicated(long lastTimeReplicated) { this.lastTimeReplicated = lastTimeReplicated; } @Override public void setVersion(long version) { this.version = version; } protected void setAccessCount(int count) { if ( accessCount == null && ACTIVITY_CHECK ) accessCount = new AtomicInteger(); if ( accessCount != null ) super.accessCount.set(count); } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/SessionIDMessage.java0000644000175100017510000000670012271463015025737 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import org.apache.catalina.ha.ClusterMessageBase; /** * Session id change cluster message * * @author Peter Rossbach * * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated public class SessionIDMessage extends ClusterMessageBase { private static final long serialVersionUID = 1L; private int messageNumber; private String orignalSessionID; private String backupSessionID; private String host ; private String contextName; @Override public String getUniqueId() { StringBuilder result = new StringBuilder(getOrignalSessionID()); result.append("#-#"); result.append(getHost()); result.append("#-#"); result.append(getContextName()); result.append("#-#"); result.append(getMessageNumber()); result.append("#-#"); result.append(System.currentTimeMillis()); return result.toString(); } /** * @return Returns the host. */ public String getHost() { return host; } /** * @param host The host to set. */ public void setHost(String host) { this.host = host; } /** * @return Returns the context name. */ public String getContextName() { return contextName; } /** * @param contextName The context name to set. */ public void setContextName(String contextName) { this.contextName = contextName; } /** * @return Returns the messageNumber. */ public int getMessageNumber() { return messageNumber; } /** * @param messageNumber * The messageNumber to set. */ public void setMessageNumber(int messageNumber) { this.messageNumber = messageNumber; } /** * @return Returns the backupSessionID. */ public String getBackupSessionID() { return backupSessionID; } /** * @param backupSessionID * The backupSessionID to set. */ public void setBackupSessionID(String backupSessionID) { this.backupSessionID = backupSessionID; } /** * @return Returns the orignalSessionID. */ public String getOrignalSessionID() { return orignalSessionID; } /** * @param orignalSessionID * The orignalSessionID to set. */ public void setOrignalSessionID(String orignalSessionID) { this.orignalSessionID = orignalSessionID; } @Override public String toString() { return "SESSIONID-UPDATE#" + getHost() + "." + getContextName() + "#" + getOrignalSessionID() + ":" + getBackupSessionID(); } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/DeltaManager.java0000644000175100017510000016314312271463015025123 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import org.apache.catalina.Cluster; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; import org.apache.catalina.Valve; import org.apache.catalina.core.StandardContext; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.ha.ClusterMessage; import org.apache.catalina.ha.tcp.ReplicationValve; import org.apache.catalina.session.ManagerBase; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.io.ReplicationStream; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * The DeltaManager manages replicated sessions by only replicating the deltas * in data. For applications written to handle this, the DeltaManager is the * optimal way of replicating data. * * This code is almost identical to StandardManager with a difference in how it * persists sessions and some modifications to it. * * IMPLEMENTATION NOTE : Correct behavior of session storing and * reloading depends upon external calls to the start() and * stop() methods of this class at the correct times. * * @author Filip Hanik * @author Craig R. McClanahan * @author Jean-Francois Arcand * @author Peter Rossbach */ public class DeltaManager extends ClusterManagerBase{ // ---------------------------------------------------- Security Classes public final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(DeltaManager.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ private static final String info = "DeltaManager/2.1"; /** * The descriptive name of this Manager implementation (for logging). */ protected static String managerName = "DeltaManager"; protected String name = null; /** * cached replication valve cluster container! */ private volatile ReplicationValve replicationValve = null ; private boolean expireSessionsOnShutdown = false; private boolean notifySessionListenersOnReplication = true; private boolean notifyContainerListenersOnReplication = true; private volatile boolean stateTransfered = false ; private volatile boolean noContextManagerReceived = false ; private int stateTransferTimeout = 60; private boolean sendAllSessions = true; private int sendAllSessionsSize = 1000 ; /** * wait time between send session block (default 2 sec) */ private int sendAllSessionsWaitTime = 2 * 1000 ; private ArrayList receivedMessageQueue = new ArrayList() ; private boolean receiverQueue = false ; private boolean stateTimestampDrop = true ; private long stateTransferCreateSendTime; // ------------------------------------------------------------------ stats attributes private long sessionReplaceCounter = 0 ; private long counterReceive_EVT_GET_ALL_SESSIONS = 0 ; private long counterReceive_EVT_ALL_SESSION_DATA = 0 ; private long counterReceive_EVT_SESSION_CREATED = 0 ; private long counterReceive_EVT_SESSION_EXPIRED = 0; private long counterReceive_EVT_SESSION_ACCESSED = 0 ; private long counterReceive_EVT_SESSION_DELTA = 0; private int counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0 ; private long counterReceive_EVT_CHANGE_SESSION_ID = 0 ; private long counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER = 0 ; private long counterSend_EVT_GET_ALL_SESSIONS = 0 ; private long counterSend_EVT_ALL_SESSION_DATA = 0 ; private long counterSend_EVT_SESSION_CREATED = 0; private long counterSend_EVT_SESSION_DELTA = 0 ; private long counterSend_EVT_SESSION_ACCESSED = 0; private long counterSend_EVT_SESSION_EXPIRED = 0; private int counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0 ; private long counterSend_EVT_CHANGE_SESSION_ID = 0; private int counterNoStateTransfered = 0 ; // ------------------------------------------------------------- Constructor public DeltaManager() { super(); } // ------------------------------------------------------------- Properties /** * Return descriptive information about this Manager implementation and the * corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return info; } @Override public void setName(String name) { this.name = name; } /** * Return the descriptive short name of this Manager implementation. */ @Override public String getName() { return name; } /** * @return Returns the counterSend_EVT_GET_ALL_SESSIONS. */ public long getCounterSend_EVT_GET_ALL_SESSIONS() { return counterSend_EVT_GET_ALL_SESSIONS; } /** * @return Returns the counterSend_EVT_SESSION_ACCESSED. */ public long getCounterSend_EVT_SESSION_ACCESSED() { return counterSend_EVT_SESSION_ACCESSED; } /** * @return Returns the counterSend_EVT_SESSION_CREATED. */ public long getCounterSend_EVT_SESSION_CREATED() { return counterSend_EVT_SESSION_CREATED; } /** * @return Returns the counterSend_EVT_SESSION_DELTA. */ public long getCounterSend_EVT_SESSION_DELTA() { return counterSend_EVT_SESSION_DELTA; } /** * @return Returns the counterSend_EVT_SESSION_EXPIRED. */ public long getCounterSend_EVT_SESSION_EXPIRED() { return counterSend_EVT_SESSION_EXPIRED; } /** * @return Returns the counterSend_EVT_ALL_SESSION_DATA. */ public long getCounterSend_EVT_ALL_SESSION_DATA() { return counterSend_EVT_ALL_SESSION_DATA; } /** * @return Returns the counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE. */ public int getCounterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE() { return counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE; } /** * @return Returns the counterSend_EVT_CHANGE_SESSION_ID. */ public long getCounterSend_EVT_CHANGE_SESSION_ID() { return counterSend_EVT_CHANGE_SESSION_ID; } /** * @return Returns the counterReceive_EVT_ALL_SESSION_DATA. */ public long getCounterReceive_EVT_ALL_SESSION_DATA() { return counterReceive_EVT_ALL_SESSION_DATA; } /** * @return Returns the counterReceive_EVT_GET_ALL_SESSIONS. */ public long getCounterReceive_EVT_GET_ALL_SESSIONS() { return counterReceive_EVT_GET_ALL_SESSIONS; } /** * @return Returns the counterReceive_EVT_SESSION_ACCESSED. */ public long getCounterReceive_EVT_SESSION_ACCESSED() { return counterReceive_EVT_SESSION_ACCESSED; } /** * @return Returns the counterReceive_EVT_SESSION_CREATED. */ public long getCounterReceive_EVT_SESSION_CREATED() { return counterReceive_EVT_SESSION_CREATED; } /** * @return Returns the counterReceive_EVT_SESSION_DELTA. */ public long getCounterReceive_EVT_SESSION_DELTA() { return counterReceive_EVT_SESSION_DELTA; } /** * @return Returns the counterReceive_EVT_SESSION_EXPIRED. */ public long getCounterReceive_EVT_SESSION_EXPIRED() { return counterReceive_EVT_SESSION_EXPIRED; } /** * @return Returns the counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE. */ public int getCounterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE() { return counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE; } /** * @return Returns the counterReceive_EVT_CHANGE_SESSION_ID. */ public long getCounterReceive_EVT_CHANGE_SESSION_ID() { return counterReceive_EVT_CHANGE_SESSION_ID; } /** * @return Returns the counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER. */ public long getCounterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER() { return counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER; } /** * @return Returns the processingTime. */ @Override public long getProcessingTime() { return processingTime; } /** * @return Returns the sessionReplaceCounter. */ public long getSessionReplaceCounter() { return sessionReplaceCounter; } /** * @return Returns the counterNoStateTransfered. */ public int getCounterNoStateTransfered() { return counterNoStateTransfered; } public int getReceivedQueueSize() { return receivedMessageQueue.size() ; } /** * @return Returns the stateTransferTimeout. */ public int getStateTransferTimeout() { return stateTransferTimeout; } /** * @param timeoutAllSession The timeout */ public void setStateTransferTimeout(int timeoutAllSession) { this.stateTransferTimeout = timeoutAllSession; } /** * is session state transfered complete? * */ public boolean getStateTransfered() { return stateTransfered; } /** * set that state ist complete transfered * @param stateTransfered */ public void setStateTransfered(boolean stateTransfered) { this.stateTransfered = stateTransfered; } public boolean isNoContextManagerReceived() { return noContextManagerReceived; } public void setNoContextManagerReceived(boolean noContextManagerReceived) { this.noContextManagerReceived = noContextManagerReceived; } /** * @return Returns the sendAllSessionsWaitTime in msec */ public int getSendAllSessionsWaitTime() { return sendAllSessionsWaitTime; } /** * @param sendAllSessionsWaitTime The sendAllSessionsWaitTime to set at msec. */ public void setSendAllSessionsWaitTime(int sendAllSessionsWaitTime) { this.sendAllSessionsWaitTime = sendAllSessionsWaitTime; } /** * @return Returns the stateTimestampDrop. */ public boolean isStateTimestampDrop() { return stateTimestampDrop; } /** * @param isTimestampDrop The new flag value */ public void setStateTimestampDrop(boolean isTimestampDrop) { this.stateTimestampDrop = isTimestampDrop; } /** * * @return Returns the sendAllSessions. */ public boolean isSendAllSessions() { return sendAllSessions; } /** * @param sendAllSessions The sendAllSessions to set. */ public void setSendAllSessions(boolean sendAllSessions) { this.sendAllSessions = sendAllSessions; } /** * @return Returns the sendAllSessionsSize. */ public int getSendAllSessionsSize() { return sendAllSessionsSize; } /** * @param sendAllSessionsSize The sendAllSessionsSize to set. */ public void setSendAllSessionsSize(int sendAllSessionsSize) { this.sendAllSessionsSize = sendAllSessionsSize; } /** * @return Returns the notifySessionListenersOnReplication. */ public boolean isNotifySessionListenersOnReplication() { return notifySessionListenersOnReplication; } /** * @param notifyListenersCreateSessionOnReplication The notifySessionListenersOnReplication to set. */ public void setNotifySessionListenersOnReplication(boolean notifyListenersCreateSessionOnReplication) { this.notifySessionListenersOnReplication = notifyListenersCreateSessionOnReplication; } public boolean isExpireSessionsOnShutdown() { return expireSessionsOnShutdown; } public void setExpireSessionsOnShutdown(boolean expireSessionsOnShutdown) { this.expireSessionsOnShutdown = expireSessionsOnShutdown; } public boolean isNotifyContainerListenersOnReplication() { return notifyContainerListenersOnReplication; } public void setNotifyContainerListenersOnReplication( boolean notifyContainerListenersOnReplication) { this.notifyContainerListenersOnReplication = notifyContainerListenersOnReplication; } // --------------------------------------------------------- Public Methods /** * Construct and return a new session object, based on the default settings * specified by this Manager's properties. The session id will be assigned * by this method, and available via the getId() method of the returned * session. If a new session cannot be created for any reason, return * null. * * @exception IllegalStateException * if a new session cannot be instantiated for any reason * * Construct and return a new session object, based on the default settings * specified by this Manager's properties. The session id will be assigned * by this method, and available via the getId() method of the returned * session. If a new session cannot be created for any reason, return * null. * * @exception IllegalStateException * if a new session cannot be instantiated for any reason */ @Override public Session createSession(String sessionId) { return createSession(sessionId, true); } /** * create new session with check maxActiveSessions and send session creation * to other cluster nodes. * * @param distribute * @return The session */ public Session createSession(String sessionId, boolean distribute) { DeltaSession session = (DeltaSession) super.createSession(sessionId) ; if (distribute) { sendCreateSession(session.getId(), session); } if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createSession.newSession", session.getId(), Integer.valueOf(sessions.size()))); return (session); } /** * Send create session evt to all backup node * @param sessionId * @param session */ protected void sendCreateSession(String sessionId, DeltaSession session) { if(cluster.getMembers().length > 0 ) { SessionMessage msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_CREATED, null, sessionId, sessionId + "-" + System.currentTimeMillis()); if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.sendMessage.newSession",name, sessionId)); msg.setTimestamp(session.getCreationTime()); counterSend_EVT_SESSION_CREATED++; send(msg); } } /** * Send messages to other backup member (domain or all) * @param msg Session message */ protected void send(SessionMessage msg) { if(cluster != null) { cluster.send(msg); } } /** * Create DeltaSession * @see org.apache.catalina.Manager#createEmptySession() */ @Override public Session createEmptySession() { return getNewDeltaSession() ; } /** * Get new session class to be used in the doLoad() method. */ protected DeltaSession getNewDeltaSession() { return new DeltaSession(this); } /** * Change the session ID of the current session to a new randomly generated * session ID. * * @param session The session to change the session ID for */ @Override public void changeSessionId(Session session) { changeSessionId(session, true); } public void changeSessionId(Session session, boolean notify) { // original sessionID String orgSessionID = session.getId(); super.changeSessionId(session); if (notify && cluster.getMembers().length > 0) { // changed sessionID String newSessionID = session.getId(); try { // serialize sessionID byte[] data = serializeSessionId(newSessionID); // notify change sessionID SessionMessage msg = new SessionMessageImpl(getName(), SessionMessage.EVT_CHANGE_SESSION_ID, data, orgSessionID, orgSessionID + "-" + System.currentTimeMillis()); msg.setTimestamp(System.currentTimeMillis()); counterSend_EVT_CHANGE_SESSION_ID++; send(msg); } catch (IOException e) { log.error(sm.getString("deltaManager.unableSerializeSessionID", newSessionID), e); } } } /** * serialize sessionID * @throws IOException if an input/output error occurs */ protected byte[] serializeSessionId(String sessionId) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeUTF(sessionId); oos.flush(); oos.close(); return bos.toByteArray(); } /** * Load sessionID * @throws IOException if an input/output error occurs */ protected String deserializeSessionId(byte[] data) throws IOException { ReplicationStream ois = getReplicationStream(data); String sessionId = ois.readUTF(); ois.close(); return sessionId; } /** * Load Deltarequest from external node * Load the Class at container classloader * @see DeltaRequest#readExternal(java.io.ObjectInput) * @param session * @param data message data * @return The request * @throws ClassNotFoundException * @throws IOException */ protected DeltaRequest deserializeDeltaRequest(DeltaSession session, byte[] data) throws ClassNotFoundException, IOException { try { session.lock(); ReplicationStream ois = getReplicationStream(data); session.getDeltaRequest().readExternal(ois); ois.close(); return session.getDeltaRequest(); }finally { session.unlock(); } } /** * serialize DeltaRequest * @see DeltaRequest#writeExternal(java.io.ObjectOutput) * * @param deltaRequest * @return serialized delta request * @throws IOException */ protected byte[] serializeDeltaRequest(DeltaSession session, DeltaRequest deltaRequest) throws IOException { try { session.lock(); return deltaRequest.serialize(); }finally { session.unlock(); } } /** * Load sessions from other cluster node. * FIXME replace currently sessions with same id without notification. * FIXME SSO handling is not really correct with the session replacement! * @exception ClassNotFoundException * if a serialized class cannot be found during the reload * @exception IOException * if an input/output error occurs */ protected void deserializeSessions(byte[] data) throws ClassNotFoundException,IOException { // Initialize our internal data structures //sessions.clear(); //should not do this // Open an input stream to the specified pathname, if any ClassLoader originalLoader = Thread.currentThread().getContextClassLoader(); ObjectInputStream ois = null; // Load the previously unloaded active sessions try { ois = getReplicationStream(data); Integer count = (Integer) ois.readObject(); int n = count.intValue(); for (int i = 0; i < n; i++) { DeltaSession session = (DeltaSession) createEmptySession(); session.readObjectData(ois); session.setManager(this); session.setValid(true); session.setPrimarySession(false); //in case the nodes in the cluster are out of //time synch, this will make sure that we have the //correct timestamp, isValid returns true, cause // accessCount=1 session.access(); //make sure that the session gets ready to expire if // needed session.setAccessCount(0); session.resetDeltaRequest(); // FIXME How inform other session id cache like SingleSignOn // increment sessionCounter to correct stats report if (findSession(session.getIdInternal()) == null ) { sessionCounter++; } else { sessionReplaceCounter++; // FIXME better is to grap this sessions again ! if (log.isWarnEnabled()) log.warn(sm.getString("deltaManager.loading.existing.session",session.getIdInternal())); } add(session); if (notifySessionListenersOnReplication) { session.tellNew(); } } } catch (ClassNotFoundException e) { log.error(sm.getString("deltaManager.loading.cnfe", e), e); throw e; } catch (IOException e) { log.error(sm.getString("deltaManager.loading.ioe", e), e); throw e; } finally { // Close the input stream try { if (ois != null) ois.close(); } catch (IOException f) { // ignored } ois = null; if (originalLoader != null) Thread.currentThread().setContextClassLoader(originalLoader); } } /** * Save any currently active sessions in the appropriate persistence * mechanism, if any. If persistence is not supported, this method returns * without doing anything. * * @exception IOException * if an input/output error occurs */ protected byte[] serializeSessions(Session[] currentSessions) throws IOException { // Open an output stream to the specified pathname, if any ByteArrayOutputStream fos = null; ObjectOutputStream oos = null; try { fos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(new BufferedOutputStream(fos)); oos.writeObject(Integer.valueOf(currentSessions.length)); for(int i=0 ; i < currentSessions.length;i++) { ((DeltaSession)currentSessions[i]).writeObjectData(oos); } // Flush and close the output stream oos.flush(); } catch (IOException e) { log.error(sm.getString("deltaManager.unloading.ioe", e), e); throw e; } finally { if (oos != null) { try { oos.close(); } catch (IOException f) { // Ignore } oos = null; } } // send object data as byte[] return fos.toByteArray(); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { super.startInternal(); // Load unloaded sessions, if any try { //the channel is already running Cluster cluster = getCluster() ; // stop remove cluster binding if(cluster == null) { Container context = getContainer(); if (context != null) { cluster = context.getCluster(); if(cluster instanceof CatalinaCluster) { setCluster((CatalinaCluster) cluster); } else { cluster = null; } } } if (cluster == null) { log.error(sm.getString("deltaManager.noCluster", getName())); return; } else { if (log.isInfoEnabled()) { String type = "unknown" ; if( cluster.getContainer() instanceof Host){ type = "Host" ; } else if( cluster.getContainer() instanceof Engine){ type = "Engine" ; } log.info(sm.getString("deltaManager.registerCluster", getName(), type, cluster.getClusterName())); } } if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.startClustering", getName())); //to survice context reloads, as only a stop/start is called, not // createManager cluster.registerManager(this); getAllClusterSessions(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("deltaManager.managerLoad"), t); } setState(LifecycleState.STARTING); } /** * get from first session master the backup from all clustered sessions * @see #findSessionMasterMember() */ public synchronized void getAllClusterSessions() { if (cluster != null && cluster.getMembers().length > 0) { long beforeSendTime = System.currentTimeMillis(); Member mbr = findSessionMasterMember(); if(mbr == null) { // No domain member found return; } SessionMessage msg = new SessionMessageImpl(this.getName(),SessionMessage.EVT_GET_ALL_SESSIONS, null, "GET-ALL","GET-ALL-" + getName()); msg.setTimestamp(beforeSendTime); // set reference time stateTransferCreateSendTime = beforeSendTime ; // request session state counterSend_EVT_GET_ALL_SESSIONS++; stateTransfered = false ; // FIXME This send call block the deploy thread, when sender waitForAck is enabled try { synchronized(receivedMessageQueue) { receiverQueue = true ; } cluster.send(msg, mbr); if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.waitForSessionState",getName(), mbr, Integer.valueOf(getStateTransferTimeout()))); // FIXME At sender ack mode this method check only the state transfer and resend is a problem! waitForSendAllSessions(beforeSendTime); } finally { synchronized(receivedMessageQueue) { for (Iterator iter = receivedMessageQueue.iterator(); iter.hasNext();) { SessionMessage smsg = iter.next(); if (!stateTimestampDrop) { messageReceived(smsg, smsg.getAddress() != null ? (Member) smsg.getAddress() : null); } else { if (smsg.getEventType() != SessionMessage.EVT_GET_ALL_SESSIONS && smsg.getTimestamp() >= stateTransferCreateSendTime) { // FIXME handle EVT_GET_ALL_SESSIONS later messageReceived(smsg,smsg.getAddress() != null ? (Member) smsg.getAddress() : null); } else { if (log.isWarnEnabled()) { log.warn(sm.getString("deltaManager.dropMessage",getName(), smsg.getEventTypeString(),new Date(stateTransferCreateSendTime), new Date(smsg.getTimestamp()))); } } } } receivedMessageQueue.clear(); receiverQueue = false ; } } } else { if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.noMembers", getName())); } } /** * Register cross context session at replication valve thread local * @param session cross context session */ protected void registerSessionAtReplicationValve(DeltaSession session) { if(replicationValve == null) { if(container instanceof StandardContext && ((StandardContext)container).getCrossContext()) { CatalinaCluster cluster = getCluster() ; if(cluster != null) { Valve[] valves = cluster.getValves(); if(valves != null && valves.length > 0) { for(int i=0; replicationValve == null && i < valves.length ; i++ ){ if(valves[i] instanceof ReplicationValve) replicationValve = (ReplicationValve)valves[i] ; }//for if(replicationValve == null && log.isDebugEnabled()) { log.debug("no ReplicationValve found for CrossContext Support"); }//endif }//end if }//endif }//end if }//end if if(replicationValve != null) { replicationValve.registerReplicationSession(session); } } /** * Find the master of the session state * @return master member of sessions */ protected Member findSessionMasterMember() { Member mbr = null; Member mbrs[] = cluster.getMembers(); if(mbrs.length != 0 ) mbr = mbrs[0]; if(mbr == null && log.isWarnEnabled()) log.warn(sm.getString("deltaManager.noMasterMember",getName(), "")); if(mbr != null && log.isDebugEnabled()) log.warn(sm.getString("deltaManager.foundMasterMember",getName(), mbr)); return mbr; } /** * Wait that cluster session state is transfer or timeout after 60 Sec * With stateTransferTimeout == -1 wait that backup is transfered (forever mode) */ protected void waitForSendAllSessions(long beforeSendTime) { long reqStart = System.currentTimeMillis(); long reqNow = reqStart ; boolean isTimeout = false; if(getStateTransferTimeout() > 0) { // wait that state is transfered with timeout check do { try { Thread.sleep(100); } catch (Exception sleep) { // } reqNow = System.currentTimeMillis(); isTimeout = ((reqNow - reqStart) > (1000 * getStateTransferTimeout())); } while ((!getStateTransfered()) && (!isTimeout) && (!isNoContextManagerReceived())); } else { if(getStateTransferTimeout() == -1) { // wait that state is transfered do { try { Thread.sleep(100); } catch (Exception sleep) { } } while ((!getStateTransfered())&& (!isNoContextManagerReceived())); reqNow = System.currentTimeMillis(); } } if (isTimeout) { counterNoStateTransfered++ ; log.error(sm.getString("deltaManager.noSessionState",getName(),new Date(beforeSendTime),Long.valueOf(reqNow - beforeSendTime))); }else if (isNoContextManagerReceived()) { if (log.isWarnEnabled()) log.warn(sm.getString("deltaManager.noContextManager",getName(),new Date(beforeSendTime),Long.valueOf(reqNow - beforeSendTime))); } else { if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.sessionReceived",getName(), new Date(beforeSendTime), Long.valueOf(reqNow - beforeSendTime))); } } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.stopped", getName())); setState(LifecycleState.STOPPING); // Expire all active sessions if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.expireSessions", getName())); Session sessions[] = findSessions(); for (int i = 0; i < sessions.length; i++) { DeltaSession session = (DeltaSession) sessions[i]; if (!session.isValid()) continue; try { session.expire(true, isExpireSessionsOnShutdown()); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } // Require a new random number generator if we are restarted getCluster().removeManager(this); super.stopInternal(); replicationValve = null; } // -------------------------------------------------------- Replication // Methods /** * A message was received from another node, this is the callback method to * implement if you are interested in receiving replication messages. * * @param cmsg - * the message received. */ @Override public void messageDataReceived(ClusterMessage cmsg) { if (cmsg != null && cmsg instanceof SessionMessage) { SessionMessage msg = (SessionMessage) cmsg; switch (msg.getEventType()) { case SessionMessage.EVT_GET_ALL_SESSIONS: case SessionMessage.EVT_SESSION_CREATED: case SessionMessage.EVT_SESSION_EXPIRED: case SessionMessage.EVT_SESSION_ACCESSED: case SessionMessage.EVT_SESSION_DELTA: case SessionMessage.EVT_CHANGE_SESSION_ID: { synchronized(receivedMessageQueue) { if(receiverQueue) { receivedMessageQueue.add(msg); return ; } } break; } default: { //we didn't queue, do nothing break; } } //switch messageReceived(msg, msg.getAddress() != null ? (Member) msg.getAddress() : null); } } /** * When the request has been completed, the replication valve will notify * the manager, and the manager will decide whether any replication is * needed or not. If there is a need for replication, the manager will * create a session message and that will be replicated. The cluster * determines where it gets sent. * * @param sessionId - * the sessionId that just completed. * @return a SessionMessage to be sent, */ @Override public ClusterMessage requestCompleted(String sessionId) { return requestCompleted(sessionId, false); } /** * When the request has been completed, the replication valve will notify * the manager, and the manager will decide whether any replication is * needed or not. If there is a need for replication, the manager will * create a session message and that will be replicated. The cluster * determines where it gets sent. * * Session expiration also calls this method, but with expires == true. * * @param sessionId - * the sessionId that just completed. * @param expires - * whether this method has been called during session expiration * @return a SessionMessage to be sent, */ public ClusterMessage requestCompleted(String sessionId, boolean expires) { DeltaSession session = null; try { session = (DeltaSession) findSession(sessionId); if (session == null) { // A parallel request has called session.invalidate() which has // removed the session from the Manager. return null; } DeltaRequest deltaRequest = session.getDeltaRequest(); session.lock(); SessionMessage msg = null; boolean isDeltaRequest = false ; synchronized(deltaRequest) { isDeltaRequest = deltaRequest.getSize() > 0 ; if (isDeltaRequest) { counterSend_EVT_SESSION_DELTA++; byte[] data = serializeDeltaRequest(session,deltaRequest); msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_DELTA, data, sessionId, sessionId + "-" + System.currentTimeMillis()); session.resetDeltaRequest(); } } if(!isDeltaRequest) { if(!expires && !session.isPrimarySession()) { counterSend_EVT_SESSION_ACCESSED++; msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_ACCESSED, null, sessionId, sessionId + "-" + System.currentTimeMillis()); if (log.isDebugEnabled()) { log.debug(sm.getString("deltaManager.createMessage.accessChangePrimary",getName(), sessionId)); } } } else { // log only outside synch block! if (log.isDebugEnabled()) { log.debug(sm.getString("deltaManager.createMessage.delta",getName(), sessionId)); } } if (!expires) session.setPrimarySession(true); //check to see if we need to send out an access message if (!expires && (msg == null)) { long replDelta = System.currentTimeMillis() - session.getLastTimeReplicated(); if (session.getMaxInactiveInterval() >=0 && replDelta > (session.getMaxInactiveInterval() * 1000)) { counterSend_EVT_SESSION_ACCESSED++; msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_ACCESSED, null, sessionId, sessionId + "-" + System.currentTimeMillis()); if (log.isDebugEnabled()) { log.debug(sm.getString("deltaManager.createMessage.access", getName(),sessionId)); } } } //update last replicated time if (msg != null){ session.setLastTimeReplicated(System.currentTimeMillis()); msg.setTimestamp(session.getLastTimeReplicated()); } return msg; } catch (IOException x) { log.error(sm.getString("deltaManager.createMessage.unableCreateDeltaRequest",sessionId), x); return null; }finally { if (session!=null) session.unlock(); } } /** * Reset manager statistics */ public synchronized void resetStatistics() { processingTime = 0 ; expiredSessions.set(0); synchronized (sessionCreationTiming) { sessionCreationTiming.clear(); while (sessionCreationTiming.size() < ManagerBase.TIMING_STATS_CACHE_SIZE) { sessionCreationTiming.add(null); } } synchronized (sessionExpirationTiming) { sessionExpirationTiming.clear(); while (sessionExpirationTiming.size() < ManagerBase.TIMING_STATS_CACHE_SIZE) { sessionExpirationTiming.add(null); } } rejectedSessions = 0 ; sessionReplaceCounter = 0 ; counterNoStateTransfered = 0 ; setMaxActive(getActiveSessions()); sessionCounter = getActiveSessions() ; counterReceive_EVT_ALL_SESSION_DATA = 0; counterReceive_EVT_GET_ALL_SESSIONS = 0; counterReceive_EVT_SESSION_ACCESSED = 0 ; counterReceive_EVT_SESSION_CREATED = 0 ; counterReceive_EVT_SESSION_DELTA = 0 ; counterReceive_EVT_SESSION_EXPIRED = 0 ; counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0; counterReceive_EVT_CHANGE_SESSION_ID = 0; counterSend_EVT_ALL_SESSION_DATA = 0; counterSend_EVT_GET_ALL_SESSIONS = 0; counterSend_EVT_SESSION_ACCESSED = 0 ; counterSend_EVT_SESSION_CREATED = 0 ; counterSend_EVT_SESSION_DELTA = 0 ; counterSend_EVT_SESSION_EXPIRED = 0 ; counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0; counterSend_EVT_CHANGE_SESSION_ID = 0; } // -------------------------------------------------------- expire /** * send session expired to other cluster nodes * * @param id * session id */ protected void sessionExpired(String id) { if(cluster.getMembers().length > 0 ) { counterSend_EVT_SESSION_EXPIRED++ ; SessionMessage msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_EXPIRED, null, id, id+ "-EXPIRED-MSG"); msg.setTimestamp(System.currentTimeMillis()); if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.expire",getName(), id)); send(msg); } } /** * Expire all find sessions. */ public void expireAllLocalSessions() { long timeNow = System.currentTimeMillis(); Session sessions[] = findSessions(); int expireDirect = 0 ; int expireIndirect = 0 ; if(log.isDebugEnabled()) log.debug("Start expire all sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); for (int i = 0; i < sessions.length; i++) { if (sessions[i] instanceof DeltaSession) { DeltaSession session = (DeltaSession) sessions[i]; if (session.isPrimarySession()) { if (session.isValid()) { session.expire(); expireDirect++; } else { expireIndirect++; }//end if }//end if }//end if }//for long timeEnd = System.currentTimeMillis(); if(log.isDebugEnabled()) log.debug("End expire sessions " + getName() + " expire processingTime " + (timeEnd - timeNow) + " expired direct sessions: " + expireDirect + " expired direct sessions: " + expireIndirect); } /** * When the manager expires session not tied to a request. The cluster will * periodically ask for a list of sessions that should expire and that * should be sent across the wire. * * @return The invalidated sessions array */ @Override public String[] getInvalidatedSessions() { return new String[0]; } // -------------------------------------------------------- message receive /** * Test that sender and local domain is the same */ protected boolean checkSenderDomain(SessionMessage msg,Member sender) { boolean sameDomain= true; if (!sameDomain && log.isWarnEnabled()) { log.warn(sm.getString("deltaManager.receiveMessage.fromWrongDomain", new Object[] {getName(), msg.getEventTypeString(), sender, "", "" })); } return sameDomain ; } /** * This method is called by the received thread when a SessionMessage has * been received from one of the other nodes in the cluster. * * @param msg - * the message received * @param sender - * the sender of the message, this is used if we receive a * EVT_GET_ALL_SESSION message, so that we only reply to the * requesting node */ protected void messageReceived(SessionMessage msg, Member sender) { if(!checkSenderDomain(msg,sender)) { return; } ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); try { ClassLoader[] loaders = getClassLoaders(); if ( loaders != null && loaders.length > 0) Thread.currentThread().setContextClassLoader(loaders[0]); if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.eventType",getName(), msg.getEventTypeString(), sender)); switch (msg.getEventType()) { case SessionMessage.EVT_GET_ALL_SESSIONS: { handleGET_ALL_SESSIONS(msg,sender); break; } case SessionMessage.EVT_ALL_SESSION_DATA: { handleALL_SESSION_DATA(msg,sender); break; } case SessionMessage.EVT_ALL_SESSION_TRANSFERCOMPLETE: { handleALL_SESSION_TRANSFERCOMPLETE(msg,sender); break; } case SessionMessage.EVT_SESSION_CREATED: { handleSESSION_CREATED(msg,sender); break; } case SessionMessage.EVT_SESSION_EXPIRED: { handleSESSION_EXPIRED(msg,sender); break; } case SessionMessage.EVT_SESSION_ACCESSED: { handleSESSION_ACCESSED(msg,sender); break; } case SessionMessage.EVT_SESSION_DELTA: { handleSESSION_DELTA(msg,sender); break; } case SessionMessage.EVT_CHANGE_SESSION_ID: { handleCHANGE_SESSION_ID(msg,sender); break; } case SessionMessage.EVT_ALL_SESSION_NOCONTEXTMANAGER: { handleALL_SESSION_NOCONTEXTMANAGER(msg,sender); break; } default: { //we didn't recognize the message type, do nothing break; } } //switch } catch (Exception x) { log.error(sm.getString("deltaManager.receiveMessage.error",getName()), x); } finally { Thread.currentThread().setContextClassLoader(contextLoader); } } // -------------------------------------------------------- message receiver handler /** * handle receive session state is complete transfered * @param msg * @param sender */ protected void handleALL_SESSION_TRANSFERCOMPLETE(SessionMessage msg, Member sender) { counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE++ ; if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.transfercomplete",getName(), sender.getHost(), Integer.valueOf(sender.getPort()))); stateTransferCreateSendTime = msg.getTimestamp() ; stateTransfered = true ; } /** * handle receive session delta * @param msg * @param sender * @throws IOException * @throws ClassNotFoundException */ protected void handleSESSION_DELTA(SessionMessage msg, Member sender) throws IOException, ClassNotFoundException { counterReceive_EVT_SESSION_DELTA++; byte[] delta = msg.getSession(); DeltaSession session = (DeltaSession) findSession(msg.getSessionID()); if (session != null) { if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.delta",getName(), msg.getSessionID())); try { session.lock(); DeltaRequest dreq = deserializeDeltaRequest(session, delta); dreq.execute(session, isNotifyListenersOnReplication()); session.setPrimarySession(false); }finally { session.unlock(); } } } /** * handle receive session is access at other node ( primary session is now false) * @param msg * @param sender * @throws IOException */ protected void handleSESSION_ACCESSED(SessionMessage msg,Member sender) throws IOException { counterReceive_EVT_SESSION_ACCESSED++; DeltaSession session = (DeltaSession) findSession(msg.getSessionID()); if (session != null) { if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.accessed",getName(), msg.getSessionID())); session.access(); session.setPrimarySession(false); session.endAccess(); } } /** * handle receive session is expire at other node ( expire session also here) * @param msg * @param sender * @throws IOException */ protected void handleSESSION_EXPIRED(SessionMessage msg,Member sender) throws IOException { counterReceive_EVT_SESSION_EXPIRED++; DeltaSession session = (DeltaSession) findSession(msg.getSessionID()); if (session != null) { if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.expired",getName(), msg.getSessionID())); session.expire(notifySessionListenersOnReplication, false); } } /** * handle receive new session is created at other node (create backup - primary false) * @param msg * @param sender */ protected void handleSESSION_CREATED(SessionMessage msg,Member sender) { counterReceive_EVT_SESSION_CREATED++; if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.createNewSession",getName(), msg.getSessionID())); DeltaSession session = (DeltaSession) createEmptySession(); session.setManager(this); session.setValid(true); session.setPrimarySession(false); session.setCreationTime(msg.getTimestamp()); // use container maxInactiveInterval so that session will expire correctly in case of primary transfer session.setMaxInactiveInterval(getMaxInactiveInterval(), false); session.access(); session.setId(msg.getSessionID(), notifySessionListenersOnReplication); session.resetDeltaRequest(); session.endAccess(); } /** * handle receive sessions from other not ( restart ) * @param msg * @param sender * @throws ClassNotFoundException * @throws IOException */ protected void handleALL_SESSION_DATA(SessionMessage msg,Member sender) throws ClassNotFoundException, IOException { counterReceive_EVT_ALL_SESSION_DATA++; if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.allSessionDataBegin",getName())); byte[] data = msg.getSession(); deserializeSessions(data); if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.allSessionDataAfter",getName())); //stateTransferred = true; } /** * handle receive that other node want all sessions ( restart ) * a) send all sessions with one message * b) send session at blocks * After sending send state is complete transfered * @param msg * @param sender * @throws IOException */ protected void handleGET_ALL_SESSIONS(SessionMessage msg, Member sender) throws IOException { counterReceive_EVT_GET_ALL_SESSIONS++; //get a list of all the session from this manager if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.unloadingBegin", getName())); // Write the number of active sessions, followed by the details // get all sessions and serialize without sync Session[] currentSessions = findSessions(); long findSessionTimestamp = System.currentTimeMillis() ; if (isSendAllSessions()) { sendSessions(sender, currentSessions, findSessionTimestamp); } else { // send session at blocks int remain = currentSessions.length; for (int i = 0; i < currentSessions.length; i += getSendAllSessionsSize()) { int len = i + getSendAllSessionsSize() > currentSessions.length ? currentSessions.length - i : getSendAllSessionsSize(); Session[] sendSessions = new Session[len]; System.arraycopy(currentSessions, i, sendSessions, 0, len); sendSessions(sender, sendSessions,findSessionTimestamp); remain = remain - len; if (getSendAllSessionsWaitTime() > 0 && remain > 0) { try { Thread.sleep(getSendAllSessionsWaitTime()); } catch (Exception sleep) { } }//end if }//for }//end if SessionMessage newmsg = new SessionMessageImpl(name,SessionMessage.EVT_ALL_SESSION_TRANSFERCOMPLETE, null,"SESSION-STATE-TRANSFERED", "SESSION-STATE-TRANSFERED"+ getName()); newmsg.setTimestamp(findSessionTimestamp); if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.allSessionTransfered",getName())); counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE++; cluster.send(newmsg, sender); } /** * handle receive change sessionID at other node * @param msg * @param sender * @throws IOException */ protected void handleCHANGE_SESSION_ID(SessionMessage msg,Member sender) throws IOException { counterReceive_EVT_CHANGE_SESSION_ID++; DeltaSession session = (DeltaSession) findSession(msg.getSessionID()); if (session != null) { String newSessionID = deserializeSessionId(msg.getSession()); session.setPrimarySession(false); session.setId(newSessionID, false); if (notifyContainerListenersOnReplication) { getContainer().fireContainerEvent(Context.CHANGE_SESSION_ID_EVENT, new String[] {msg.getSessionID(), newSessionID}); } } } /** * handle receive no context manager. * @param msg * @param sender */ protected void handleALL_SESSION_NOCONTEXTMANAGER(SessionMessage msg, Member sender) { counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER++ ; if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.noContextManager",getName(), sender.getHost(), Integer.valueOf(sender.getPort()))); noContextManagerReceived = true ; } /** * send a block of session to sender * @param sender * @param currentSessions * @param sendTimestamp * @throws IOException */ protected void sendSessions(Member sender, Session[] currentSessions,long sendTimestamp) throws IOException { byte[] data = serializeSessions(currentSessions); if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.unloadingAfter",getName())); SessionMessage newmsg = new SessionMessageImpl(name,SessionMessage.EVT_ALL_SESSION_DATA, data,"SESSION-STATE", "SESSION-STATE-" + getName()); newmsg.setTimestamp(sendTimestamp); if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.allSessionData",getName())); counterSend_EVT_ALL_SESSION_DATA++; cluster.send(newmsg, sender); } @Override public ClusterManager cloneFromTemplate() { DeltaManager result = new DeltaManager(); clone(result); result.replicationValve = replicationValve; result.expireSessionsOnShutdown = expireSessionsOnShutdown; result.notifySessionListenersOnReplication = notifySessionListenersOnReplication; result.notifyContainerListenersOnReplication = notifyContainerListenersOnReplication; result.stateTransferTimeout = stateTransferTimeout; result.sendAllSessions = sendAllSessions; result.sendAllSessionsSize = sendAllSessionsSize; result.sendAllSessionsWaitTime = sendAllSessionsWaitTime ; result.stateTimestampDrop = stateTimestampDrop ; return result; } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/ClusterManagerBase.java0000644000175100017510000001460712271463015026306 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.regex.Pattern; import org.apache.catalina.Container; import org.apache.catalina.Loader; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.session.ManagerBase; import org.apache.catalina.tribes.io.ReplicationStream; /** * * @author Filip Hanik */ public abstract class ClusterManagerBase extends ManagerBase implements ClusterManager { /** * A reference to the cluster */ protected CatalinaCluster cluster = null; /** * Should listeners be notified? */ private boolean notifyListenersOnReplication = true; /** * The pattern used for including session attributes to * replication, e.g. ^(userName|sessionHistory)$. * If not set, all session attributes will be eligible for replication. */ private String sessionAttributeFilter = null; /** * The compiled pattern used for including session attributes to * replication, e.g. ^(userName|sessionHistory)$. * If not set, all session attributes will be eligible for replication. */ private Pattern sessionAttributePattern = null; /* * @see org.apache.catalina.ha.ClusterManager#getCluster() */ @Override public CatalinaCluster getCluster() { return cluster; } @Override public void setCluster(CatalinaCluster cluster) { this.cluster = cluster; } @Override public boolean isNotifyListenersOnReplication() { return notifyListenersOnReplication; } public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) { this.notifyListenersOnReplication = notifyListenersOnReplication; } /** * Return the string pattern used for including session attributes * to replication. * * @return the sessionAttributeFilter */ public String getSessionAttributeFilter() { return sessionAttributeFilter; } /** * Set the pattern used for including session attributes to replication. * If not set, all session attributes will be eligible for replication. *

    * E.g. ^(userName|sessionHistory)$ *

    * * @param sessionAttributeFilter * the filter name pattern to set */ public void setSessionAttributeFilter(String sessionAttributeFilter) { if (sessionAttributeFilter == null || sessionAttributeFilter.trim().equals("")) { this.sessionAttributeFilter = null; sessionAttributePattern = null; } else { this.sessionAttributeFilter = sessionAttributeFilter; sessionAttributePattern = Pattern.compile(sessionAttributeFilter); } } /** * Check whether the given session attribute should be distributed * * @return true if the attribute should be distributed */ public boolean willAttributeDistribute(String name) { if (sessionAttributePattern == null) { return true; } return sessionAttributePattern.matcher(name).matches(); } public static ClassLoader[] getClassLoaders(Container container) { Loader loader = null; ClassLoader classLoader = null; if (container != null) loader = container.getLoader(); if (loader != null) classLoader = loader.getClassLoader(); else classLoader = Thread.currentThread().getContextClassLoader(); if ( classLoader == Thread.currentThread().getContextClassLoader() ) { return new ClassLoader[] {classLoader}; } else { return new ClassLoader[] {classLoader,Thread.currentThread().getContextClassLoader()}; } } public ClassLoader[] getClassLoaders() { return getClassLoaders(container); } /** * Open Stream and use correct ClassLoader (Container) Switch * ThreadClassLoader * * @param data * @return The object input stream * @throws IOException */ @Override public ReplicationStream getReplicationStream(byte[] data) throws IOException { return getReplicationStream(data,0,data.length); } @Override public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException { ByteArrayInputStream fis = new ByteArrayInputStream(data, offset, length); return new ReplicationStream(fis, getClassLoaders()); } // ---------------------------------------------------- persistence handler /** * {@link org.apache.catalina.Manager} implementations that also implement * {@link ClusterManager} do not support local session persistence. */ @Override public void load() { // NOOP } @Override public void unload() { // NOOP } protected void clone(ClusterManagerBase copy) { copy.setName("Clone-from-" + getName()); copy.setCluster(getCluster()); copy.setMaxActiveSessions(getMaxActiveSessions()); copy.setMaxInactiveInterval(getMaxInactiveInterval()); copy.setSessionIdLength(getSessionIdLength()); copy.setProcessExpiresFrequency(getProcessExpiresFrequency()); copy.setNotifyListenersOnReplication(isNotifyListenersOnReplication()); copy.setSessionAttributeFilter(getSessionAttributeFilter()); copy.setSecureRandomClass(getSecureRandomClass()); copy.setSecureRandomProvider(getSecureRandomProvider()); copy.setSecureRandomAlgorithm(getSecureRandomAlgorithm()); } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/DeltaRequest.java0000644000175100017510000003337412271463015025203 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; /** * This class is used to track the series of actions that happens when * a request is executed. These actions will then translate into invocations of methods * on the actual session. * This class is NOT thread safe. One DeltaRequest per session * @author Filip Hanik * @version 1.0 */ import java.io.ByteArrayOutputStream; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectOutputStream; import java.security.Principal; import java.util.LinkedList; import org.apache.catalina.realm.GenericPrincipal; import org.apache.tomcat.util.res.StringManager; public class DeltaRequest implements Externalizable { public static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( DeltaRequest.class ); /** * The string manager for this package. */ protected static final StringManager sm = StringManager .getManager(Constants.Package); public static final int TYPE_ATTRIBUTE = 0; public static final int TYPE_PRINCIPAL = 1; public static final int TYPE_ISNEW = 2; public static final int TYPE_MAXINTERVAL = 3; public static final int TYPE_AUTHTYPE = 4; public static final int ACTION_SET = 0; public static final int ACTION_REMOVE = 1; public static final String NAME_PRINCIPAL = "__SET__PRINCIPAL__"; public static final String NAME_MAXINTERVAL = "__SET__MAXINTERVAL__"; public static final String NAME_ISNEW = "__SET__ISNEW__"; public static final String NAME_AUTHTYPE = "__SET__AUTHTYPE__"; private String sessionId; private LinkedList actions = new LinkedList(); private LinkedList actionPool = new LinkedList(); private boolean recordAllActions = false; public DeltaRequest() { } public DeltaRequest(String sessionId, boolean recordAllActions) { this.recordAllActions=recordAllActions; if(sessionId != null) setSessionId(sessionId); } public void setAttribute(String name, Object value) { int action = (value==null)?ACTION_REMOVE:ACTION_SET; addAction(TYPE_ATTRIBUTE,action,name,value); } public void removeAttribute(String name) { int action = ACTION_REMOVE; addAction(TYPE_ATTRIBUTE,action,name,null); } public void setMaxInactiveInterval(int interval) { int action = ACTION_SET; addAction(TYPE_MAXINTERVAL,action,NAME_MAXINTERVAL,Integer.valueOf(interval)); } /** * convert principal at SerializablePrincipal for backup nodes. * Only support principals from type {@link GenericPrincipal GenericPrincipal} * @param p Session principal * @see GenericPrincipal */ public void setPrincipal(Principal p) { int action = (p==null)?ACTION_REMOVE:ACTION_SET; SerializablePrincipal sp = null; if ( p != null ) { if(p instanceof GenericPrincipal) { sp = SerializablePrincipal.createPrincipal((GenericPrincipal)p); if(log.isDebugEnabled()) log.debug(sm.getString("deltaRequest.showPrincipal", p.getName() , getSessionId())); } else log.error(sm.getString("deltaRequest.wrongPrincipalClass",p.getClass().getName())); } addAction(TYPE_PRINCIPAL,action,NAME_PRINCIPAL,sp); } public void setNew(boolean n) { int action = ACTION_SET; addAction(TYPE_ISNEW,action,NAME_ISNEW,Boolean.valueOf(n)); } public void setAuthType(String authType) { int action = (authType==null)?ACTION_REMOVE:ACTION_SET; addAction(TYPE_AUTHTYPE,action,NAME_AUTHTYPE, authType); } protected void addAction(int type, int action, String name, Object value) { AttributeInfo info = null; if ( this.actionPool.size() > 0 ) { try { info = actionPool.removeFirst(); }catch ( Exception x ) { log.error("Unable to remove element:",x); info = new AttributeInfo(type, action, name, value); } info.init(type,action,name,value); } else { info = new AttributeInfo(type, action, name, value); } //if we have already done something to this attribute, make sure //we don't send multiple actions across the wire if ( !recordAllActions) { try { actions.remove(info); } catch (java.util.NoSuchElementException x) { //do nothing, we wanted to remove it anyway } } //add the action actions.addLast(info); } public void execute(DeltaSession session, boolean notifyListeners) { if ( !this.sessionId.equals( session.getId() ) ) throw new java.lang.IllegalArgumentException("Session id mismatch, not executing the delta request"); session.access(); for ( int i=0; i(); else actions.clear(); for (int i = 0; i < cnt; i++) { AttributeInfo info = null; if (this.actionPool.size() > 0) { try { info = actionPool.removeFirst(); } catch ( Exception x ) { log.error("Unable to remove element",x); info = new AttributeInfo(); } } else { info = new AttributeInfo(); } info.readExternal(in); actions.addLast(info); }//for } @Override public void writeExternal(java.io.ObjectOutput out ) throws java.io.IOException { //sessionId - String //recordAll - boolean //size - int //AttributeInfo - in an array out.writeUTF(getSessionId()); out.writeBoolean(recordAllActions); out.writeInt(getSize()); for ( int i=0; ijava.security.Principal that * is available for use by Realm implementations. * The GenericPrincipal does NOT implement serializable and I didn't want to * change that implementation hence I implemented this one instead. * @author Filip Hanik */ public class SerializablePrincipal implements java.io.Serializable { private static final long serialVersionUID = 1L; private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(SerializablePrincipal.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ----------------------------------------------------------- Constructors public SerializablePrincipal() { super(); } /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password. * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user */ public SerializablePrincipal(String name, String password) { this(name, password, null); } /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password, with the specified role names * (as Strings). * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user * @param roles List of roles (must be Strings) possessed by this user */ public SerializablePrincipal(String name, String password, List roles) { this(name, password, roles, null); } /** * Construct a new Principal, associated with the specified Realm, for the * specified username and password, with the specified role names * (as Strings). * * @param name The username of the user represented by this Principal * @param password Credentials used to authenticate this user * @param roles List of roles (must be Strings) possessed by this user * @param userPrincipal The user principal to be exposed to applications */ public SerializablePrincipal(String name, String password, List roles, Principal userPrincipal) { super(); this.name = name; this.password = password; if (roles != null) { this.roles = new String[roles.size()]; this.roles = roles.toArray(this.roles); if (this.roles.length > 1) Arrays.sort(this.roles); } if (userPrincipal instanceof Serializable) { this.userPrincipal = userPrincipal; } } // ------------------------------------------------------------- Properties /** * The username of the user represented by this Principal. */ protected String name = null; public String getName() { return (this.name); } /** * The authentication credentials for the user represented by * this Principal. */ protected String password = null; public String getPassword() { return (this.password); } /** * The Realm with which this Principal is associated. */ protected transient Realm realm = null; public Realm getRealm() { return (this.realm); } public void setRealm(Realm realm) { this.realm = realm; } /** * The set of roles associated with this user. */ protected String roles[] = new String[0]; public String[] getRoles() { return (this.roles); } /** * The user principal, if present. */ protected Principal userPrincipal = null; // --------------------------------------------------------- Public Methods /** * Return a String representation of this object, which exposes only * information that should be public. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SerializablePrincipal["); sb.append(this.name); sb.append("]"); return (sb.toString()); } public static SerializablePrincipal createPrincipal(GenericPrincipal principal) { if ( principal==null) return null; return new SerializablePrincipal(principal.getName(), principal.getPassword(), principal.getRoles()!=null?Arrays.asList(principal.getRoles()):null, principal.getUserPrincipal()!=principal?principal.getUserPrincipal():null); } public GenericPrincipal getPrincipal() { return new GenericPrincipal(name, password, getRoles()!=null?Arrays.asList(getRoles()):null, userPrincipal); } public static GenericPrincipal readPrincipal(ObjectInput in) throws IOException, ClassNotFoundException { String name = in.readUTF(); boolean hasPwd = in.readBoolean(); String pwd = null; if ( hasPwd ) pwd = in.readUTF(); int size = in.readInt(); String[] roles = new String[size]; for ( int i=0; i * For this valve to function correctly, so that all nodes of the cluster * receive the sessionid change notifications that it generates, the following * ClusterListener MUST be configured at all nodes of the cluster: * {@link org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener * JvmRouteSessionIDBinderListener} since Tomcat 5.5.10, and both * JvmRouteSessionIDBinderListener and JvmRouteSessionIDBinderLifecycleListener * for earlier versions of Tomcat. * *

    * Add this Valve to your host definition at conf/server.xml . * * Since 5.5.10 as direct cluster valve:
    * *

     *  <Cluster>
     *  <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" />  
     *  </Cluster>
     * 
    * *
    * Before 5.5.10 as Host element:
    * *
     *  <Host>
     *  <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" />  
     *  </Host>
     * 
    * * A Trick:
    * You can enable this mod_jk turnover mode via JMX before you drop a node to * all backup nodes! Set enable true on all JvmRouteBinderValve backups, disable * worker at mod_jk and then drop node and restart it! Then enable mod_jk worker * and disable JvmRouteBinderValves again. This use case means that only * requested sessions are migrated. * * @author Peter Rossbach */ public class JvmRouteBinderValve extends ValveBase implements ClusterValve { /*--Static Variables----------------------------------------*/ public static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory .getLog(JvmRouteBinderValve.class); /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.ha.session.JvmRouteBinderValve/1.2"; //------------------------------------------------------ Constructor public JvmRouteBinderValve() { super(true); } /*--Instance Variables--------------------------------------*/ /** * the cluster */ protected CatalinaCluster cluster; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * enabled this component */ protected boolean enabled = true; /** * number of session that no at this tomcat instanz hosted */ protected long numberOfSessions = 0; protected String sessionIdAttribute = "org.apache.catalina.ha.session.JvmRouteOrignalSessionID"; /*--Logic---------------------------------------------------*/ /** * Return descriptive information about this implementation. */ @Override public String getInfo() { return (info); } /** * set session id attribute to failed node for request. * * @return Returns the sessionIdAttribute. */ public String getSessionIdAttribute() { return sessionIdAttribute; } /** * get name of failed request session attribute * * @param sessionIdAttribute * The sessionIdAttribute to set. */ public void setSessionIdAttribute(String sessionIdAttribute) { this.sessionIdAttribute = sessionIdAttribute; } /** * @return Returns the number of migrated sessions. */ public long getNumberOfSessions() { return numberOfSessions; } /** * @return Returns the enabled. */ public boolean getEnabled() { return enabled; } /** * @param enabled * The enabled to set. */ public void setEnabled(boolean enabled) { this.enabled = enabled; } /** * Detect possible the JVMRoute change at cluster backup node.. * * @param request * tomcat request being processed * @param response * tomcat response being processed * @exception IOException * if an input/output error has occurred * @exception ServletException * if a servlet error has occurred */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { if (getEnabled() && request.getContext() != null && request.getContext().getDistributable() && !request.isAsyncDispatching()) { // valve cluster can access manager - other cluster handle turnover // at host level - hopefully! Manager manager = request.getContext().getManager(); if (manager != null && ( (manager instanceof ClusterManager && getCluster() != null && getCluster().getManager(((ClusterManager)manager).getName()) != null) || (manager instanceof PersistentManager))) handlePossibleTurnover(request); } // Pass this request on to the next valve in our pipeline getNext().invoke(request, response); } /** * handle possible session turn over. * * @see JvmRouteBinderValve#handleJvmRoute(Request, String, String) * @param request current request */ protected void handlePossibleTurnover(Request request) { String sessionID = request.getRequestedSessionId() ; if (sessionID != null) { long t1 = System.currentTimeMillis(); String jvmRoute = getLocalJvmRoute(request); if (jvmRoute == null) { if (log.isDebugEnabled()) log.debug(sm.getString("jvmRoute.missingJvmRouteAttribute")); return; } handleJvmRoute( request, sessionID, jvmRoute); if (log.isDebugEnabled()) { long t2 = System.currentTimeMillis(); long time = t2 - t1; log.debug(sm.getString("jvmRoute.turnoverInfo", Long.valueOf(time))); } } } /** * get jvmroute from engine * * @param request current request * @return return jvmRoute from ManagerBase or null */ protected String getLocalJvmRoute(Request request) { Manager manager = getManager(request); if(manager instanceof ManagerBase) return ((ManagerBase) manager).getJvmRoute(); return null ; } /** * get Cluster DeltaManager * * @param request current request * @return manager or null */ protected Manager getManager(Request request) { Manager manager = request.getContext().getManager(); if (log.isDebugEnabled()) { if(manager != null) log.debug(sm.getString("jvmRoute.foundManager", manager, request.getContext().getName())); else log.debug(sm.getString("jvmRoute.notFoundManager", request.getContext().getName())); } return manager; } /** * @return Returns the cluster. */ @Override public CatalinaCluster getCluster() { return cluster; } /** * @param cluster The cluster to set. */ @Override public void setCluster(CatalinaCluster cluster) { this.cluster = cluster; } /** * Handle jvmRoute stickiness after tomcat instance failed. After this * correction a new Cookie send to client with new jvmRoute and the * SessionID change propagate to the other cluster nodes. * * @param request current request * @param sessionId * request SessionID from Cookie * @param localJvmRoute * local jvmRoute */ protected void handleJvmRoute( Request request, String sessionId, String localJvmRoute) { // get requested jvmRoute. String requestJvmRoute = null; int index = sessionId.indexOf("."); if (index > 0) { requestJvmRoute = sessionId .substring(index + 1, sessionId.length()); } if (requestJvmRoute != null && !requestJvmRoute.equals(localJvmRoute)) { if (log.isDebugEnabled()) { log.debug(sm.getString("jvmRoute.failover", requestJvmRoute, localJvmRoute, sessionId)); } Session catalinaSession = null; try { catalinaSession = getManager(request).findSession(sessionId); } catch (IOException e) { // Hups! } String id = sessionId.substring(0, index); String newSessionID = id + "." + localJvmRoute; // OK - turnover the session and inform other cluster nodes if (catalinaSession != null) { changeSessionID(request, sessionId, newSessionID, catalinaSession); numberOfSessions++; } else { try { catalinaSession = getManager(request).findSession(newSessionID); } catch (IOException e) { // Hups! } if (catalinaSession != null) { // session is rewrite at other request, rewrite this also changeRequestSessionID(request, sessionId, newSessionID); } else { if (log.isDebugEnabled()) { log.debug(sm.getString("jvmRoute.cannotFindSession",sessionId)); } } } } } /** * change session id and send to all cluster nodes * * @param request current request * @param sessionId * original session id * @param newSessionID * new session id for node migration * @param catalinaSession * current session with original session id */ protected void changeSessionID(Request request, String sessionId, String newSessionID, Session catalinaSession) { fireLifecycleEvent("Before session migration", catalinaSession); catalinaSession.setId(newSessionID, false); // FIXME: Why we remove change data from other running request? // setId also trigger resetDeltaRequest!! if (catalinaSession instanceof DeltaSession) ((DeltaSession) catalinaSession).resetDeltaRequest(); changeRequestSessionID(request, sessionId, newSessionID); // now sending the change to all other clusternodes! sendSessionIDClusterBackup(request,sessionId, newSessionID); fireLifecycleEvent("After session migration", catalinaSession); if (log.isDebugEnabled()) { log.debug(sm.getString("jvmRoute.changeSession", sessionId, newSessionID)); } } /** * Change Request Session id * @param request current request * @param sessionId * original session id * @param newSessionID * new session id for node migration */ protected void changeRequestSessionID(Request request, String sessionId, String newSessionID) { request.changeSessionId(newSessionID); // set original sessionid at request, to allow application detect the // change if (sessionIdAttribute != null && !"".equals(sessionIdAttribute)) { if (log.isDebugEnabled()) { log.debug(sm.getString("jvmRoute.set.orignalsessionid",sessionIdAttribute,sessionId)); } request.setAttribute(sessionIdAttribute, sessionId); } } /** * Send the changed Sessionid to all clusternodes. * * @see JvmRouteSessionIDBinderListener#messageReceived( * org.apache.catalina.ha.ClusterMessage) * @param sessionId * current failed sessionid * @param newSessionID * new session id, bind to the new cluster node */ protected void sendSessionIDClusterBackup(Request request, String sessionId, String newSessionID) { CatalinaCluster c = getCluster(); if (c != null && !(getManager(request) instanceof BackupManager)) { SessionIDMessage msg = new SessionIDMessage(); msg.setOrignalSessionID(sessionId); msg.setBackupSessionID(newSessionID); Context context = request.getContext(); msg.setContextName(context.getName()); msg.setHost(context.getParent().getName()); c.send(msg); } } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { if (cluster == null) { Container hostContainer = getContainer(); // compatibility with JvmRouteBinderValve version 1.1 // ( setup at context.xml or context.xml.default ) if (!(hostContainer instanceof Host)) { if (log.isWarnEnabled()) log.warn(sm.getString("jvmRoute.configure.warn")); hostContainer = hostContainer.getParent(); } if (hostContainer instanceof Host && ((Host) hostContainer).getCluster() != null) { cluster = (CatalinaCluster) ((Host) hostContainer).getCluster(); } else { Container engine = hostContainer.getParent() ; if (engine instanceof Engine && ((Engine) engine).getCluster() != null) { cluster = (CatalinaCluster) ((Engine) engine).getCluster(); } } } if (log.isInfoEnabled()) { log.info(sm.getString("jvmRoute.valve.started")); if (cluster == null) log.info(sm.getString("jvmRoute.noCluster")); } super.startInternal(); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { super.stopInternal(); cluster = null; numberOfSessions = 0; if (log.isInfoEnabled()) log.info(sm.getString("jvmRoute.valve.stopped")); } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/JvmRouteSessionIDBinderListener.java0000644000175100017510000001411112271463015030753 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import java.io.IOException; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.LifecycleException; import org.apache.catalina.Session; import org.apache.catalina.core.StandardEngine; import org.apache.catalina.ha.ClusterListener; import org.apache.catalina.ha.ClusterMessage; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Receive SessionID cluster change from other backup node after primary session * node is failed. * * @author Peter Rossbach * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated public class JvmRouteSessionIDBinderListener extends ClusterListener { private static final Log log = LogFactory.getLog(JvmRouteSessionIDBinderListener.class); private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener/1.1"; //--Instance Variables-------------------------------------- protected boolean started = false; /** * number of session that goes to this cluster node */ private long numberOfSessions = 0; //--Constructor--------------------------------------------- public JvmRouteSessionIDBinderListener() { // NO-OP } //--Logic--------------------------------------------------- /** * Return descriptive information about this implementation. */ public String getInfo() { return (info); } /** * @return Returns the numberOfSessions. */ public long getNumberOfSessions() { return numberOfSessions; } /** * Add this Mover as Cluster Listener ( receiver) * * @throws LifecycleException */ public void start() throws LifecycleException { if (started) return; getCluster().addClusterListener(this); started = true; if (log.isInfoEnabled()) log.info(sm.getString("jvmRoute.clusterListener.started")); } /** * Remove this from Cluster Listener * * @throws LifecycleException */ public void stop() throws LifecycleException { started = false; getCluster().removeClusterListener(this); if (log.isInfoEnabled()) log.info(sm.getString("jvmRoute.clusterListener.stopped")); } /** * Callback from the cluster, when a message is received, The cluster will * broadcast it invoking the messageReceived on the receiver. * * @param msg * ClusterMessage - the message received from the cluster */ @Override public void messageReceived(ClusterMessage msg) { if (msg instanceof SessionIDMessage) { SessionIDMessage sessionmsg = (SessionIDMessage) msg; if (log.isDebugEnabled()) log.debug(sm.getString( "jvmRoute.receiveMessage.sessionIDChanged", sessionmsg .getOrignalSessionID(), sessionmsg .getBackupSessionID(), sessionmsg .getContextName())); Container container = getCluster().getContainer(); Container host = null ; if(container instanceof Engine) { host = container.findChild(sessionmsg.getHost()); } else { host = container ; } if (host != null) { Context context = (Context) host.findChild(sessionmsg .getContextName()); if (context != null) { try { Session session = context.getManager().findSession( sessionmsg.getOrignalSessionID()); if (session != null) { session.setId(sessionmsg.getBackupSessionID()); } else if (log.isInfoEnabled()) log.info(sm.getString("jvmRoute.lostSession", sessionmsg.getOrignalSessionID(), sessionmsg.getContextName())); } catch (IOException e) { log.error(e); } } else if (log.isErrorEnabled()) log.error(sm.getString("jvmRoute.contextNotFound", sessionmsg.getContextName(), ((StandardEngine) host .getParent()).getJvmRoute())); } else if (log.isErrorEnabled()) log.error(sm.getString("jvmRoute.hostNotFound", sessionmsg.getContextName())); } return; } /** * Accept only SessionIDMessages * * @param msg * ClusterMessage * @return boolean - returns true to indicate that messageReceived should be * invoked. If false is returned, the messageReceived method will * not be invoked. */ @Override public boolean accept(ClusterMessage msg) { return (msg instanceof SessionIDMessage); } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/mbeans-descriptors.xml0000644000175100017510000005300112271463015026251 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/ha/session/Constants.java0000644000175100017510000000207112271463015024543 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; /** * Manifest constants for the org.apache.catalina.ha.session * package. * * @author Peter Rossbach Pero */ public class Constants { public static final String Package = "org.apache.catalina.ha.session"; } tomcat7-7.0.52/java/org/apache/catalina/ha/session/LocalStrings.properties0000644000175100017510000001722412271463015026454 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. deltaManager.createSession.newSession=Created a DeltaSession with Id [{0}] Total count={1} deltaManager.createMessage.access=Manager [{0}]: create session message [{1}] access. deltaManager.createMessage.accessChangePrimary=Manager [{0}]: create session message [{1}] access to change primary. deltaManager.createMessage.allSessionData=Manager [{0}] send all session data. deltaManager.createMessage.allSessionTransfered=Manager [{0}] send all session data transfered deltaManager.createMessage.delta=Manager [{0}]: create session message [{1}] delta request. deltaManager.createMessage.expire=Manager [{0}]: create session message [{1}] expire. deltaManager.createMessage.unableCreateDeltaRequest=Unable to serialize delta request for sessionid [{0}] deltaManager.dropMessage=Manager [{0}]: Drop message {1} inside GET_ALL_SESSIONS sync phase start date {2} message date {3} deltaManager.foundMasterMember=Found for context [{0}] the replication master member [{1}] deltaManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0} deltaManager.loading.existing.session=overload existing session {0} deltaManager.loading.ioe=IOException while loading persisted sessions: {0} deltaManager.loading.withContextClassLoader=Manager [{0}]: Loading the object data with a context class loader. deltaManager.loading.withoutClassLoader=Manager [{0}]: Loading the object data without a context class loader. deltaManager.managerLoad=Exception loading sessions from persistent storage deltaManager.noCluster=Starting... no cluster associated with this context: [{0}] deltaManager.noMasterMember=Starting... with no other member for context [{0}] at domain [{1}] deltaManager.noMembers=Manager [{0}]: skipping state transfer. No members active in cluster group. deltaManager.noSessionState=Manager [{0}]: No session state send at {1} received, timing out after {2} ms. deltaManager.noContextManager=Manager [{0}]: No context manager send at {1} received in {2} ms. deltaManager.sendMessage.newSession=Manager [{0}] send new session ({1}) deltaManager.expireSessions=Manager [{0}] expiring sessions upon shutdown deltaManager.receiveMessage.accessed=Manager [{0}]: received session [{1}] accessed. deltaManager.receiveMessage.createNewSession=Manager [{0}]: received session [{1}] created. deltaManager.receiveMessage.delta=Manager [{0}]: received session [{1}] delta. deltaManager.receiveMessage.error=Manager [{0}]: Unable to receive message through TCP channel deltaManager.receiveMessage.eventType=Manager [{0}]: Received SessionMessage of type=({1}) from [{2}] deltaManager.receiveMessage.expired=Manager [{0}]: received session [{1}] expired. deltaManager.receiveMessage.transfercomplete=Manager [{0}] received from node [{1}:{2}] session state transfered. deltaManager.receiveMessage.noContextManager=Manager [{0}] received from node [{1}:{2}] no context manager. deltaManager.receiveMessage.unloadingAfter=Manager [{0}]: unloading sessions complete deltaManager.receiveMessage.unloadingBegin=Manager [{0}]: start unloading sessions deltaManager.receiveMessage.allSessionDataAfter=Manager [{0}]: session state deserialized deltaManager.receiveMessage.allSessionDataBegin=Manager [{0}]: received session state data deltaManager.receiveMessage.fromWrongDomain=Manager [{0}]: Received wrong SessionMessage of type=({1}) from [{2}] with domain [{3}] (localdomain [{4}] deltaManager.registerCluster=Register manager {0} to cluster element {1} with name {2} deltaManager.sessionReceived=Manager [{0}]; session state send at {1} received in {2} ms. deltaManager.startClustering=Starting clustering manager at {0} deltaManager.stopped=Manager [{0}] is stopping deltaManager.unloading.ioe=IOException while saving persisted sessions: {0} deltaManager.waitForSessionState=Manager [{0}], requesting session state from {1}. This operation will timeout if no session state has been received within {2} seconds. deltaManager.unableSerializeSessionID =Unable to serialize sessionID [{0}] deltaRequest.showPrincipal=Principal [{0}] is set to session {1} deltaRequest.wrongPrincipalClass=DeltaManager only support GenericPrincipal. Your realm used principal class {0}. deltaSession.notifying=Notifying cluster of expiration primary={0} sessionId [{1}] deltaSession.valueBound.ex=Session bound listener throw an exception deltaSession.valueBinding.ex=Session binding listener throw an exception deltaSession.valueUnbound.ex=Session unbound listener throw an exception deltaSession.readSession=readObject() loading session [{0}] deltaSession.readAttribute=session [{0}] loading attribute '{1}' with value '{2}' deltaSession.writeSession=writeObject() storing session [{0}] jvmRoute.cannotFindSession=Can't find session [{0}] jvmRoute.changeSession=Changed session from [{0}] to [{1}] jvmRoute.clusterListener.started=Cluster JvmRouteSessionIDBinderListener started jvmRoute.clusterListener.stopped=Cluster JvmRouteSessionIDBinderListener stopped jvmRoute.configure.warn=Please, setup your JvmRouteBinderValve at host valve, not at context valve! jvmRoute.contextNotFound=Context [{0}] not found at node [{1}]! jvmRoute.failover=Detected a failover with different jvmRoute - orginal route: [{0}] new one: [{1}] at session id [{2}] jvmRoute.foundManager=Found Cluster DeltaManager {0} at {1} jvmRoute.hostNotFound=No host found [{0}] jvmRoute.listener.started=SessionID Binder Listener started jvmRoute.listener.stopped=SessionID Binder Listener stopped jvmRoute.lostSession=Lost Session [{0}] at path [{1}] jvmRoute.missingJvmRouteAttribute=No engine jvmRoute attribute configured! jvmRoute.newSessionCookie=Setting cookie with session id [{0}] name: [{1}] path: [{2}] secure: [{3}] httpOnly: [{4}] jvmRoute.noCluster=The JvmRouterBinderValve is configured, but clustering is not being used. Fail over will still work, providing a PersistentManager is used. jvmRoute.notFoundManager=Not found Cluster DeltaManager at {0} jvmRoute.receiveMessage.sessionIDChanged=Cluster JvmRouteSessionIDBinderListener received orginal session ID [{0}] set to new id [{1}] for context path [{2}] jvmRoute.run.already=jvmRoute SessionID receiver run already jvmRoute.skipURLSessionIDs=Skip reassign jvm route check, sessionid comes from URL! jvmRoute.turnoverInfo=Turnover Check time {0} msec jvmRoute.valve.started=JvmRouteBinderValve started jvmRoute.valve.stopped=JvmRouteBinderValve stopped jvmRoute.set.orignalsessionid=Set Orginal Session id at request attriute {0} value: {1} standardSession.notSerializable=Cannot serialize session attribute {0} for session {1} standardSession.removeAttribute.ise=removeAttribute: Session already invalidated standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null serializablePrincipal.readPrincipal.cnfe=readPrincipal: Failed to recreate user Principal backupManager.noCluster=no cluster associated with this context: [{0}] backupManager.startUnable=Unable to start BackupManager: [{0}] backupManager.startFailed=Failed to start BackupManager: [{0}] backupManager.stopped=Manager [{0}] is stopping tomcat7-7.0.52/java/org/apache/catalina/ha/session/SessionMessageImpl.java0000644000175100017510000001356512271463015026353 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import org.apache.catalina.ha.ClusterMessageBase; /** * Session cluster message * * @author Filip Hanik * @author Peter Rossbach */ public class SessionMessageImpl extends ClusterMessageBase implements SessionMessage { private static final long serialVersionUID = 1L; public SessionMessageImpl() { } /* * Private serializable variables to keep the messages state */ private int mEvtType = -1; private byte[] mSession; private String mSessionID; private String mContextName; private long serializationTimestamp; private boolean timestampSet = false ; private String uniqueId; private SessionMessageImpl( String contextName, int eventtype, byte[] session, String sessionID) { mEvtType = eventtype; mSession = session; mSessionID = sessionID; mContextName = contextName; uniqueId = sessionID; } /** * Creates a session message. Depending on what event type you want this * message to represent, you populate the different parameters in the constructor
    * The following rules apply dependent on what event type argument you use:
    * EVT_SESSION_CREATED
    * The parameters: session, sessionID must be set.
    * EVT_SESSION_EXPIRED
    * The parameters: sessionID must be set.
    * EVT_SESSION_ACCESSED
    * The parameters: sessionID must be set.
    * EVT_GET_ALL_SESSIONS
    * get all sessions from from one of the nodes.
    * EVT_SESSION_DELTA
    * Send attribute delta (add,update,remove attribute or principal, ...).
    * EVT_ALL_SESSION_DATA
    * Send complete serializes session list
    * EVT_ALL_SESSION_TRANSFERCOMPLETE
    * send that all session state information are transfered * after GET_ALL_SESSION received from this sender.
    * EVT_CHANGE_SESSION_ID
    * send original sessionID and new sessionID.
    * EVT_ALL_SESSION_NOCONTEXTMANAGER
    * send that context manager does not exist * after GET_ALL_SESSION received from this sender.
    * @param contextName - the name of the context (application * @param eventtype - one of the 8 event type defined in this class * @param session - the serialized byte array of the session itself * @param sessionID - the id that identifies this session * @param uniqueID - the id that identifies this message */ public SessionMessageImpl( String contextName, int eventtype, byte[] session, String sessionID, String uniqueID) { this(contextName,eventtype,session,sessionID); uniqueId = uniqueID; } /** * returns the event type * @return one of the event types EVT_XXXX */ @Override public int getEventType() { return mEvtType; } /** * @return the serialized data for the session */ @Override public byte[] getSession() { return mSession;} /** * @return the session ID for the session */ @Override public String getSessionID(){ return mSessionID; } /** * set message send time but only the first setting works (one shot) */ @Override public void setTimestamp(long time) { synchronized(this) { if(!timestampSet) { serializationTimestamp=time; timestampSet = true ; } } } @Override public long getTimestamp() { return serializationTimestamp;} /** * clear text event type name (for logging purpose only) * @return the event type in a string representation, useful for debugging */ @Override public String getEventTypeString() { switch (mEvtType) { case EVT_SESSION_CREATED : return "SESSION-MODIFIED"; case EVT_SESSION_EXPIRED : return "SESSION-EXPIRED"; case EVT_SESSION_ACCESSED : return "SESSION-ACCESSED"; case EVT_GET_ALL_SESSIONS : return "SESSION-GET-ALL"; case EVT_SESSION_DELTA : return "SESSION-DELTA"; case EVT_ALL_SESSION_DATA : return "ALL-SESSION-DATA"; case EVT_ALL_SESSION_TRANSFERCOMPLETE : return "SESSION-STATE-TRANSFERED"; case EVT_CHANGE_SESSION_ID : return "SESSION-ID-CHANGED"; case EVT_ALL_SESSION_NOCONTEXTMANAGER : return "NO-CONTEXT-MANAGER"; default : return "UNKNOWN-EVENT-TYPE"; } } @Override public String getContextName() { return mContextName; } @Override public String getUniqueId() { return uniqueId; } @Override public void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } @Override public String toString() { return getEventTypeString() + "#" + getContextName() + "#" + getSessionID() ; } } tomcat7-7.0.52/java/org/apache/catalina/ha/session/SessionMessage.java0000644000175100017510000000753712271463015025533 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import org.apache.catalina.ha.ClusterMessage; /** * * Class Description:
    * The SessionMessage class is a class that is used when a session has been * created, modified, expired in a Tomcat cluster node.
    * * The following events are currently available: *
      *
    • public static final int EVT_SESSION_CREATED
    • *
    • public static final int EVT_SESSION_EXPIRED
    • *
    • public static final int EVT_SESSION_ACCESSED
    • *
    • public static final int EVT_GET_ALL_SESSIONS
    • *
    • public static final int EVT_SESSION_DELTA
    • *
    • public static final int EVT_ALL_SESSION_DATA
    • *
    • public static final int EVT_ALL_SESSION_TRANSFERCOMPLETE
    • *
    • public static final int EVT_CHANGE_SESSION_ID
    • *
    • public static final int EVT_ALL_SESSION_NOCONTEXTMANAGER
    • *
    * */ public interface SessionMessage extends ClusterMessage { /** * Event type used when a session has been created on a node */ public static final int EVT_SESSION_CREATED = 1; /** * Event type used when a session has expired */ public static final int EVT_SESSION_EXPIRED = 2; /** * Event type used when a session has been accessed (ie, last access time * has been updated. This is used so that the replicated sessions will not expire * on the network */ public static final int EVT_SESSION_ACCESSED = 3; /** * Event type used when a server comes online for the first time. * The first thing the newly started server wants to do is to grab the * all the sessions from one of the nodes and keep the same state in there */ public static final int EVT_GET_ALL_SESSIONS = 4; /** * Event type used when an attribute has been added to a session, * the attribute will be sent to all the other nodes in the cluster */ public static final int EVT_SESSION_DELTA = 13; /** * When a session state is transferred, this is the event. */ public static final int EVT_ALL_SESSION_DATA = 12; /** * When a session state is complete transferred, this is the event. */ public static final int EVT_ALL_SESSION_TRANSFERCOMPLETE = 14; /** * Event type used when a sessionID has been changed. */ public static final int EVT_CHANGE_SESSION_ID = 15; /** * Event type used when context manager doesn't exist. * This is used when the manager which send a session state does not exist. */ public static final int EVT_ALL_SESSION_NOCONTEXTMANAGER = 16; public String getContextName(); public String getEventTypeString(); /** * returns the event type * @return one of the event types EVT_XXXX */ public int getEventType(); /** * @return the serialized data for the session */ public byte[] getSession(); /** * @return the session ID for the session */ public String getSessionID(); }//SessionMessage tomcat7-7.0.52/java/org/apache/catalina/ha/session/ClusterSessionListener.java0000644000175100017510000001072112271463015027263 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.session; import java.util.Map; import org.apache.catalina.ha.ClusterListener; import org.apache.catalina.ha.ClusterManager; import org.apache.catalina.ha.ClusterMessage; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Receive replicated SessionMessage form other cluster node. * @author Filip Hanik * @author Peter Rossbach */ public class ClusterSessionListener extends ClusterListener { private static final Log log = LogFactory.getLog(ClusterSessionListener.class); /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.ha.session.ClusterSessionListener/1.1"; //--Constructor--------------------------------------------- public ClusterSessionListener() { // NO-OP } //--Logic--------------------------------------------------- /** * Return descriptive information about this implementation. */ public String getInfo() { return (info); } /** * Callback from the cluster, when a message is received, The cluster will * broadcast it invoking the messageReceived on the receiver. * * @param myobj * ClusterMessage - the message received from the cluster */ @Override public void messageReceived(ClusterMessage myobj) { if (myobj != null && myobj instanceof SessionMessage) { SessionMessage msg = (SessionMessage) myobj; String ctxname = msg.getContextName(); //check if the message is a EVT_GET_ALL_SESSIONS, //if so, wait until we are fully started up Map managers = cluster.getManagers() ; if (ctxname == null) { for (Map.Entry entry : managers.entrySet()) { if (entry.getValue() != null) entry.getValue().messageDataReceived(msg); else { //this happens a lot before the system has started // up if (log.isDebugEnabled()) log.debug("Context manager doesn't exist:" + entry.getKey()); } } } else { ClusterManager mgr = managers.get(ctxname); if (mgr != null) { mgr.messageDataReceived(msg); } else { if (log.isWarnEnabled()) log.warn("Context manager doesn't exist:" + ctxname); // A no context manager message is replied in order to avoid // timeout of GET_ALL_SESSIONS sync phase. if (msg.getEventType() == SessionMessage.EVT_GET_ALL_SESSIONS) { SessionMessage replymsg = new SessionMessageImpl(ctxname, SessionMessage.EVT_ALL_SESSION_NOCONTEXTMANAGER, null, "NO-CONTEXT-MANAGER","NO-CONTEXT-MANAGER-" + ctxname); cluster.send(replymsg, msg.getAddress()); } } } } return; } /** * Accept only SessionMessage * * @param msg * ClusterMessage * @return boolean - returns true to indicate that messageReceived should be * invoked. If false is returned, the messageReceived method will * not be invoked. */ @Override public boolean accept(ClusterMessage msg) { return (msg instanceof SessionMessage); } } tomcat7-7.0.52/java/org/apache/catalina/ha/jmx/0000755000175100017510000000000012301126370021031 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/jmx/ClusterJmxHelper.java0000644000175100017510000001162712271463015025151 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.jmx; import javax.management.DynamicMBean; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import org.apache.catalina.core.StandardEngine; import org.apache.catalina.core.StandardHost; import org.apache.catalina.ha.deploy.FarmWarDeployer; import org.apache.catalina.ha.tcp.SimpleTcpCluster; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; /** * * @author Filip Hanik * * @deprecated Unused - registration now happens via * {@link org.apache.catalina.util.LifecycleMBeanBase} */ @Deprecated public class ClusterJmxHelper { protected static Registry registry = Registry.getRegistry(null,null); private static final Log log = LogFactory.getLog(ClusterJmxHelper.class); protected static boolean jmxEnabled = true; protected static MBeanServer mbeanServer = null; public static Registry getRegistry() { return registry; } public static MBeanServer getMBeanServer() throws Exception { if (mbeanServer == null) { if (MBeanServerFactory.findMBeanServer(null).size() > 0) { mbeanServer = MBeanServerFactory.findMBeanServer(null).get(0); } else { mbeanServer = MBeanServerFactory.createMBeanServer(); } } return mbeanServer; } protected static boolean initMetaData(Class clazz) { try { if (clazz==null) return false; getRegistry().loadMetadata(clazz.getResourceAsStream("mbeans-descriptors.xml")); }catch (Exception x) { log.warn("Unable to load meta data for class:"+clazz.getName()); return false; } return true; } public static DynamicMBean getManagedBean(Object object) throws Exception { DynamicMBean mbean = null; if (getRegistry() != null) { ManagedBean managedBean = registry.findManagedBean(object.getClass().getName()); mbean = managedBean.createMBean(object); } return mbean; } protected static void initDefaultCluster() { initMetaData(SimpleTcpCluster.class); initMetaData(FarmWarDeployer.class); //not functional yet } public static boolean registerDefaultCluster(SimpleTcpCluster cluster) { try { initDefaultCluster(); ObjectName clusterName = getDefaultClusterName(cluster); if (!getMBeanServer().isRegistered(clusterName)) { getMBeanServer().registerMBean(getManagedBean(cluster), clusterName); } return true; }catch ( Exception x ) { log.warn("Unable to register default cluster implementation with JMX",x); return false; } } public static boolean unregisterDefaultCluster(SimpleTcpCluster cluster) { try { ObjectName clusterName = getDefaultClusterName(cluster); if (getMBeanServer().isRegistered(clusterName)) { getMBeanServer().unregisterMBean(clusterName); } return true; }catch ( Exception x ) { log.warn("Unable to unregister default cluster implementation with JMX",x); return false; } } private static ObjectName getDefaultClusterName(SimpleTcpCluster cluster) throws Exception { String domain = getMBeanServer().getDefaultDomain(); String type = ":type="; String clusterType= type+"Cluster"; if (cluster.getContainer() instanceof StandardHost) { domain = ((StandardHost) cluster.getContainer()).getDomain(); clusterType += ",host=" + cluster.getContainer().getName(); } else { if (cluster.getContainer() instanceof StandardEngine) { domain = ((StandardEngine) cluster.getContainer()).getDomain(); } } ObjectName clusterName = new ObjectName(domain + clusterType); return clusterName; } }tomcat7-7.0.52/java/org/apache/catalina/ha/util/0000755000175100017510000000000012301126370021210 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/ha/util/IDynamicProperty.java0000644000175100017510000000277412271463015025335 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha.util; import java.util.Iterator; /** * @author Peter Rossbach */ public interface IDynamicProperty { /** * set config attributes with reflect * * @param name * @param value */ public boolean setProperty(String name, Object value) ; /** * get current config * * @param key * @return The property */ public Object getProperty(String key) ; /** * Get all properties keys * * @return An iterator over the property names */ public Iterator getPropertyNames() ; /** * remove a configured property. * * @param key */ public void removeProperty(String key) ; } tomcat7-7.0.52/java/org/apache/catalina/ha/ClusterSession.java0000644000175100017510000000253712271463015024100 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import javax.servlet.http.HttpSession; import org.apache.catalina.Session; public interface ClusterSession extends Session, HttpSession { /** * returns true if this session is the primary session, if that is the * case, the manager can expire it upon timeout. * @return True if this session is primary */ public boolean isPrimarySession(); /** * Sets whether this is the primary session or not. * @param primarySession Flag value */ public void setPrimarySession(boolean primarySession); } tomcat7-7.0.52/java/org/apache/catalina/ha/ClusterListener.java0000644000175100017510000000662712271463015024246 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import java.io.Serializable; import org.apache.catalina.tribes.ChannelListener; import org.apache.catalina.tribes.Member; /** * Receive SessionID cluster change from other backup node after primary session * node is failed. * * @author Peter Rossbach * @author Filip Hanik */ public abstract class ClusterListener implements ChannelListener { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(ClusterListener.class); //--Instance Variables-------------------------------------- /** * The string manager for this package. */ protected CatalinaCluster cluster = null; //--Constructor--------------------------------------------- public ClusterListener() { // NO-OP } //--Instance Getters/Setters-------------------------------- public CatalinaCluster getCluster() { return cluster; } public void setCluster(CatalinaCluster cluster) { if (log.isDebugEnabled()) { if (cluster != null) log.debug("add ClusterListener " + this.toString() + " to cluster" + cluster); else log.debug("remove ClusterListener " + this.toString() + " from cluster"); } this.cluster = cluster; } @Override public boolean equals(Object listener) { return super.equals(listener); } @Override public int hashCode() { return super.hashCode(); } //--Logic--------------------------------------------------- @Override public final void messageReceived(Serializable msg, Member member) { if ( msg instanceof ClusterMessage ) messageReceived((ClusterMessage)msg); } @Override public final boolean accept(Serializable msg, Member member) { if ( msg instanceof ClusterMessage ) return true; return false; } /** * Callback from the cluster, when a message is received, The cluster will * broadcast it invoking the messageReceived on the receiver. * * @param msg * ClusterMessage - the message received from the cluster */ public abstract void messageReceived(ClusterMessage msg) ; /** * Accept only SessionIDMessages * * @param msg * ClusterMessage * @return boolean - returns true to indicate that messageReceived should be * invoked. If false is returned, the messageReceived method will * not be invoked. */ public abstract boolean accept(ClusterMessage msg) ; } tomcat7-7.0.52/java/org/apache/catalina/ha/ClusterMessage.java0000644000175100017510000000231412271463015024032 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import java.io.Serializable; import org.apache.catalina.tribes.Member; /** * @author Filip Hanik * */ public interface ClusterMessage extends Serializable { public Member getAddress(); public void setAddress(Member member); public String getUniqueId(); public void setUniqueId(String id); public long getTimestamp(); public void setTimestamp(long timestamp); } tomcat7-7.0.52/java/org/apache/catalina/ha/CatalinaCluster.java0000644000175100017510000000651512271463015024171 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.ha; import java.util.Map; import org.apache.catalina.Cluster; import org.apache.catalina.LifecycleException; import org.apache.catalina.Manager; import org.apache.catalina.Valve; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.Member; import org.apache.juli.logging.Log; /** * A CatalinaCluster interface allows to plug in and out the * different cluster implementations * * @author Filip Hanik */ public interface CatalinaCluster extends Cluster { // ----------------------------------------------------- Instance Variables /** * Descriptive information about this component implementation. */ public String info = "CatalinaCluster/2.0"; /** * Start the cluster, the owning container will invoke this * @throws Exception - if failure to start cluster */ public void start() throws Exception; /** * Stops the cluster, the owning container will invoke this * @throws LifecycleException */ public void stop() throws LifecycleException; /** * Returns the associates logger with this cluster. * * @return Log */ public Log getLogger(); /** * Sends a message to all the members in the cluster * @param msg ClusterMessage */ public void send(ClusterMessage msg); /** * Sends a message to a specific member in the cluster. * * @param msg ClusterMessage * @param dest Member */ public void send(ClusterMessage msg, Member dest); /** * Returns that cluster has members. */ public boolean hasMembers(); /** * Returns all the members currently participating in the cluster. * * @return Member[] */ public Member[] getMembers(); /** * Return the member that represents this node. * * @return Member */ public Member getLocalMember(); public void addValve(Valve valve); public void addClusterListener(ClusterListener listener); public void removeClusterListener(ClusterListener listener); public void setClusterDeployer(ClusterDeployer deployer); public ClusterDeployer getClusterDeployer(); /** * @return The map of managers */ public Map getManagers(); public Manager getManager(String name); public String getManagerName(String name, Manager manager); public Valve[] getValves(); public void setChannel(Channel channel); public Channel getChannel(); } tomcat7-7.0.52/java/org/apache/catalina/mbeans/0000755000175100017510000000000012301126371021111 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java0000644000175100017510000000672712271471332026552 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.deploy.ContextEnvironment; import org.apache.catalina.deploy.NamingResources; import org.apache.tomcat.util.modeler.BaseModelMBean; /** *

    A ModelMBean implementation for the * org.apache.catalina.deploy.ContextEnvironment component.

    * * @author Amy Roh */ public class ContextEnvironmentMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public ContextEnvironmentMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------------- Attributes /** * Set the value of a specific attribute of this MBean. * * @param attribute The identification of the attribute to be set * and the new value * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { super.setAttribute(attribute); ContextEnvironment ce = null; try { ce = (ContextEnvironment) getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } // cannot use side-effects. It's removed and added back each time // there is a modification in a resource. NamingResources nr = ce.getNamingResources(); nr.removeEnvironment(ce.getName()); nr.addEnvironment(ce); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/ContainerMBean.java0000644000175100017510000002673211475747174024640 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.util.ArrayList; import java.util.List; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.Container; import org.apache.catalina.ContainerListener; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Valve; import org.apache.catalina.core.ContainerBase; import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardHost; import org.apache.catalina.startup.ContextConfig; import org.apache.catalina.startup.HostConfig; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.catalina.valves.ValveBase; import org.apache.tomcat.util.modeler.BaseModelMBean; public class ContainerMBean extends BaseModelMBean { /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public ContainerMBean() throws MBeanException, RuntimeOperationsException { super(); } /** * Add a new child Container to those associated with this Container, * if supported. Won't start the child yet. Has to be started with a call to * Start method after necessary configurations are done. * * @param type ClassName of the child to be added * @param name Name of the child to be added * * @exception MBeanException if the child cannot be added */ public void addChild(String type, String name) throws MBeanException{ Container contained = null; try { contained = (Container)Class.forName(type).newInstance(); contained.setName(name); if(contained instanceof StandardHost){ HostConfig config = new HostConfig(); contained.addLifecycleListener(config); } else if(contained instanceof StandardContext){ ContextConfig config = new ContextConfig(); contained.addLifecycleListener(config); } } catch (InstantiationException e) { throw new MBeanException(e); } catch (IllegalAccessException e) { throw new MBeanException(e); } catch (ClassNotFoundException e) { throw new MBeanException(e); } boolean oldValue= true; ContainerBase container = null; try { container = (ContainerBase)getManagedResource(); oldValue = container.getStartChildren(); container.setStartChildren(false); container.addChild(contained); contained.init(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } catch (LifecycleException e){ throw new MBeanException(e); } finally { if(container != null) { container.setStartChildren(oldValue); } } } /** * Remove an existing child Container from association with this parent * Container. * * @param name Name of the existing child Container to be removed */ public void removeChild(String name) throws MBeanException{ if(name != null){ try { Container container = (Container)getManagedResource(); Container contained = container.findChild(name); container.removeChild(contained); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } } } /** * Adds a valve to this Container instance. * * @param valveType ClassName of the valve to be added * * @exception MBeanException if a component cannot be removed */ public String addValve(String valveType) throws MBeanException{ Valve valve = null; try { valve = (Valve)Class.forName(valveType).newInstance(); } catch (InstantiationException e) { throw new MBeanException(e); } catch (IllegalAccessException e) { throw new MBeanException(e); } catch (ClassNotFoundException e) { throw new MBeanException(e); } if (valve == null) { return null; } try { ContainerBase container = (ContainerBase)getManagedResource(); container.addValve(valve); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } return ((LifecycleMBeanBase)valve).getObjectName().toString(); } /** * Remove an existing Valve. * * @param valveName MBean Name of the Valve to remove * * @exception MBeanException if a component cannot be removed */ public void removeValve(String valveName) throws MBeanException{ ContainerBase container=null; try { container = (ContainerBase)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } ObjectName oname; try { oname = new ObjectName(valveName); } catch (MalformedObjectNameException e) { throw new MBeanException(e); } catch (NullPointerException e) { throw new MBeanException(e); } if(container != null){ Valve[] valves = container.getPipeline().getValves(); for (int i = 0; i < valves.length; i++) { ObjectName voname = ((ValveBase) valves[i]).getObjectName(); if (voname.equals(oname)) { container.getPipeline().removeValve(valves[i]); } } } } /** * Add a LifecycleEvent listener to this component. * * @param type ClassName of the listener to add */ public void addLifeCycleListener(String type) throws MBeanException{ LifecycleListener listener = null; try { listener = (LifecycleListener)Class.forName(type).newInstance(); } catch (InstantiationException e) { throw new MBeanException(e); } catch (IllegalAccessException e) { throw new MBeanException(e); } catch (ClassNotFoundException e) { throw new MBeanException(e); } if(listener != null){ try { ContainerBase container = (ContainerBase)getManagedResource(); container.addLifecycleListener(listener); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } } } /** * Remove a LifecycleEvent listeners from this component. * * @param type The ClassName of the listeners to be removed. * Note that all the listeners having given ClassName will be removed. */ public void removeLifeCycleListeners(String type) throws MBeanException{ ContainerBase container=null; try { container = (ContainerBase)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } LifecycleListener[] listeners = container.findLifecycleListeners(); for(LifecycleListener listener: listeners){ if(listener.getClass().getName().equals(type)){ container.removeLifecycleListener(listener); } } } /** * List the class name of each of the lifecycle listeners added to this * container. */ public String[] findLifecycleListenerNames() throws MBeanException { ContainerBase container = null; List result = new ArrayList(); try { container = (ContainerBase) getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } LifecycleListener[] listeners = container.findLifecycleListeners(); for(LifecycleListener listener: listeners){ result.add(listener.getClass().getName()); } return result.toArray(new String[result.size()]); } /** * List the class name of each of the container listeners added to this * container. */ public String[] findContainerListenerNames() throws MBeanException { ContainerBase container = null; List result = new ArrayList(); try { container = (ContainerBase) getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } ContainerListener[] listeners = container.findContainerListeners(); for(ContainerListener listener: listeners){ result.add(listener.getClass().getName()); } return result.toArray(new String[result.size()]); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/ConnectorMBean.java0000644000175100017510000001135312271471332024622 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.connector.Connector; import org.apache.tomcat.util.IntrospectionUtils; /** *

    A ModelMBean implementation for the * org.apache.coyote.tomcat5.CoyoteConnector component.

    * * @author Amy Roh */ public class ConnectorMBean extends ClassNameMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public ConnectorMBean() throws MBeanException, RuntimeOperationsException { super(); } // ------------------------------------------------------------- Attributes /** * Obtain and return the value of a specific attribute of this MBean. * * @param name Name of the requested attribute * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException { // Validate the input parameters if (name == null) throw new RuntimeOperationsException(new IllegalArgumentException( "Attribute name is null"), "Attribute name is null"); Object result = null; try { Connector connector = (Connector) getManagedResource(); result = IntrospectionUtils.getProperty(connector, name); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } return result; } /** * Set the value of a specific attribute of this MBean. * * @param attribute The identification of the attribute to be set * and the new value * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { // Validate the input parameters if (attribute == null) throw new RuntimeOperationsException(new IllegalArgumentException( "Attribute is null"), "Attribute is null"); String name = attribute.getName(); Object value = attribute.getValue(); if (name == null) throw new RuntimeOperationsException(new IllegalArgumentException( "Attribute name is null"), "Attribute name is null"); try { Connector connector = (Connector) getManagedResource(); IntrospectionUtils.setProperty(connector, name, String.valueOf(value)); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/ContextResourceMBean.java0000644000175100017510000001434212271471332026025 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.deploy.ContextResource; import org.apache.catalina.deploy.NamingResources; import org.apache.tomcat.util.modeler.BaseModelMBean; /** *

    A ModelMBean implementation for the * org.apache.catalina.deploy.ContextResource component.

    * * @author Amy Roh */ public class ContextResourceMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public ContextResourceMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------------- Attributes /** * Obtain and return the value of a specific attribute of this MBean. * * @param name Name of the requested attribute * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException { // Validate the input parameters if (name == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute name is null"), "Attribute name is null"); ContextResource cr = null; try { cr = (ContextResource) getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } String value = null; if ("auth".equals(name)) { return (cr.getAuth()); } else if ("description".equals(name)) { return (cr.getDescription()); } else if ("name".equals(name)) { return (cr.getName()); } else if ("scope".equals(name)) { return (cr.getScope()); } else if ("type".equals(name)) { return (cr.getType()); } else { value = (String) cr.getProperty(name); if (value == null) { throw new AttributeNotFoundException ("Cannot find attribute "+name); } } return value; } /** * Set the value of a specific attribute of this MBean. * * @param attribute The identification of the attribute to be set * and the new value * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { // Validate the input parameters if (attribute == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute is null"), "Attribute is null"); String name = attribute.getName(); Object value = attribute.getValue(); if (name == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute name is null"), "Attribute name is null"); ContextResource cr = null; try { cr = (ContextResource) getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } if ("auth".equals(name)) { cr.setAuth((String)value); } else if ("description".equals(name)) { cr.setDescription((String)value); } else if ("name".equals(name)) { cr.setName((String)value); } else if ("scope".equals(name)) { cr.setScope((String)value); } else if ("type".equals(name)) { cr.setType((String)value); } else { cr.setProperty(name, ""+value); } // cannot use side-effects. It's removed and added back each time // there is a modification in a resource. NamingResources nr = cr.getNamingResources(); nr.removeResource(cr.getName()); nr.addResource(cr); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java0000644000175100017510000001722312271471332030410 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.util.Iterator; import javax.naming.Binding; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.OperationNotSupportedException; import org.apache.catalina.Group; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.modeler.Registry; /** * Implementation of LifecycleListener that instantiates the * set of MBeans associated with global JNDI resources that are subject to * management. * * @author Craig R. McClanahan * @since 4.1 */ public class GlobalResourcesLifecycleListener implements LifecycleListener { private static final Log log = LogFactory.getLog(GlobalResourcesLifecycleListener.class); // ----------------------------------------------------- Instance Variables /** * The owning Catalina component that we are attached to. */ protected Lifecycle component = null; /** * The configuration information registry for our managed beans. */ protected static Registry registry = MBeanUtils.createRegistry(); // ---------------------------------------------- LifecycleListener Methods /** * Primary entry point for startup and shutdown events. * * @param event The event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.START_EVENT.equals(event.getType())) { component = event.getLifecycle(); createMBeans(); } else if (Lifecycle.STOP_EVENT.equals(event.getType())) { destroyMBeans(); component = null; } } // ------------------------------------------------------ Protected Methods /** * Create the MBeans for the interesting global JNDI resources. */ protected void createMBeans() { // Look up our global naming context Context context = null; try { context = (Context) (new InitialContext()).lookup("java:/"); } catch (NamingException e) { log.error("No global naming context defined for server"); return; } // Recurse through the defined global JNDI resources context try { createMBeans("", context); } catch (NamingException e) { log.error("Exception processing Global JNDI Resources", e); } } /** * Create the MBeans for the interesting global JNDI resources in * the specified naming context. * * @param prefix Prefix for complete object name paths * @param context Context to be scanned * * @exception NamingException if a JNDI exception occurs */ protected void createMBeans(String prefix, Context context) throws NamingException { if (log.isDebugEnabled()) { log.debug("Creating MBeans for Global JNDI Resources in Context '" + prefix + "'"); } try { NamingEnumeration bindings = context.listBindings(""); while (bindings.hasMore()) { Binding binding = bindings.next(); String name = prefix + binding.getName(); Object value = context.lookup(binding.getName()); if (log.isDebugEnabled()) { log.debug("Checking resource " + name); } if (value instanceof Context) { createMBeans(name + "/", (Context) value); } else if (value instanceof UserDatabase) { try { createMBeans(name, (UserDatabase) value); } catch (Exception e) { log.error("Exception creating UserDatabase MBeans for " + name, e); } } } } catch( RuntimeException ex) { log.error("RuntimeException " + ex); } catch( OperationNotSupportedException ex) { log.error("Operation not supported " + ex); } } /** * Create the MBeans for the specified UserDatabase and its contents. * * @param name Complete resource name of this UserDatabase * @param database The UserDatabase to be processed * * @exception Exception if an exception occurs while creating MBeans */ protected void createMBeans(String name, UserDatabase database) throws Exception { // Create the MBean for the UserDatabase itself if (log.isDebugEnabled()) { log.debug("Creating UserDatabase MBeans for resource " + name); log.debug("Database=" + database); } if (MBeanUtils.createMBean(database) == null) { throw new IllegalArgumentException ("Cannot create UserDatabase MBean for resource " + name); } // Create the MBeans for each defined Role Iterator roles = database.getRoles(); while (roles.hasNext()) { Role role = roles.next(); if (log.isDebugEnabled()) { log.debug(" Creating Role MBean for role " + role); } if (MBeanUtils.createMBean(role) == null) { throw new IllegalArgumentException ("Cannot create Role MBean for role " + role); } } // Create the MBeans for each defined Group Iterator groups = database.getGroups(); while (groups.hasNext()) { Group group = groups.next(); if (log.isDebugEnabled()) { log.debug(" Creating Group MBean for group " + group); } if (MBeanUtils.createMBean(group) == null) { throw new IllegalArgumentException ("Cannot create Group MBean for group " + group); } } // Create the MBeans for each defined User Iterator users = database.getUsers(); while (users.hasNext()) { User user = users.next(); if (log.isDebugEnabled()) { log.debug(" Creating User MBean for user " + user); } if (MBeanUtils.createMBean(user) == null) { throw new IllegalArgumentException ("Cannot create User MBean for user " + user); } } } /** * Destroy the MBeans for the interesting global JNDI resources. */ protected void destroyMBeans() { if (log.isDebugEnabled()) { log.debug("Destroying MBeans for Global JNDI Resources"); } } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/ServiceMBean.java0000644000175100017510000001374611443025757024306 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.Executor; import org.apache.catalina.Service; import org.apache.catalina.connector.Connector; import org.apache.tomcat.util.modeler.BaseModelMBean; public class ServiceMBean extends BaseModelMBean { public ServiceMBean() throws MBeanException, RuntimeOperationsException { super(); } /** * Add a new Connector to the set of defined Connectors, and associate it * with this Service's Container. * * @param address The IP address on which to bind * @param port TCP port number to listen on * @param isAjp Create a AJP/1.3 Connector * @param isSSL Create a secure Connector * * @throws MBeanException */ public void addConnector(String address, int port, boolean isAjp, boolean isSSL) throws MBeanException { Service service; try { service = (Service)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } Connector connector = new Connector(); if ((address!=null) && (address.length()>0)) { connector.setProperty("address", address); } connector.setPort(port); connector.setProtocol(isAjp ? "AJP/1.3" : "HTTP/1.1"); connector.setSecure(isSSL); connector.setScheme(isSSL ? "https" : "http"); service.addConnector(connector); } /** * Adds a named executor to the service * @param type Classname of the Executor to be added * @throws MBeanException */ public void addExecutor(String type) throws MBeanException { Service service; try { service = (Service)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } Executor executor; try { executor = (Executor)Class.forName(type).newInstance(); } catch (InstantiationException e) { throw new MBeanException(e); } catch (IllegalAccessException e) { throw new MBeanException(e); } catch (ClassNotFoundException e) { throw new MBeanException(e); } service.addExecutor(executor); } /** * Find and return the set of Connectors associated with this Service. * @throws MBeanException */ public String[] findConnectors() throws MBeanException { Service service; try { service = (Service)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } Connector[] connectors = service.findConnectors(); String[] str = new String[connectors.length]; for(int i=0; i< connectors.length; i++){ str[i] = connectors[i].toString(); } return str; } /** * Retrieves all executors * @throws MBeanException */ public String[] findExecutors() throws MBeanException { Service service; try { service = (Service)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } Executor[] executors = service.findExecutors(); String[] str = new String[executors.length]; for(int i=0; i< executors.length; i++){ str[i] = executors[i].toString(); } return str; } /** * Retrieves executor by name * @param name Name of the executor to be retrieved * @throws MBeanException */ public String getExecutor(String name) throws MBeanException{ Service service; try { service = (Service)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } Executor executor = service.getExecutor(name); return executor.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/UserMBean.java0000644000175100017510000001462212271471332023610 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.util.ArrayList; import java.util.Iterator; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.RuntimeOperationsException; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.tomcat.util.modeler.BaseModelMBean; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; /** *

    A ModelMBean implementation for the * org.apache.catalina.User component.

    * * @author Craig R. McClanahan */ public class UserMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public UserMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables /** * The configuration information registry for our managed beans. */ protected Registry registry = MBeanUtils.createRegistry(); /** * The ManagedBean information describing this MBean. */ protected ManagedBean managed = registry.findManagedBean("User"); // ------------------------------------------------------------- Attributes /** * Return the MBean Names of all groups this user is a member of. */ public String[] getGroups() { User user = (User) this.resource; ArrayList results = new ArrayList(); Iterator groups = user.getGroups(); while (groups.hasNext()) { Group group = null; try { group = groups.next(); ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), group); results.add(oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for group " + group); iae.initCause(e); throw iae; } } return results.toArray(new String[results.size()]); } /** * Return the MBean Names of all roles assigned to this user. */ public String[] getRoles() { User user = (User) this.resource; ArrayList results = new ArrayList(); Iterator roles = user.getRoles(); while (roles.hasNext()) { Role role = null; try { role = roles.next(); ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), role); results.add(oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for role " + role); iae.initCause(e); throw iae; } } return results.toArray(new String[results.size()]); } // ------------------------------------------------------------- Operations /** * Add a new {@link Group} to those this user belongs to. * * @param groupname Group name of the new group */ public void addGroup(String groupname) { User user = (User) this.resource; if (user == null) { return; } Group group = user.getUserDatabase().findGroup(groupname); if (group == null) { throw new IllegalArgumentException ("Invalid group name '" + groupname + "'"); } user.addGroup(group); } /** * Add a new {@link Role} to those this user belongs to. * * @param rolename Role name of the new role */ public void addRole(String rolename) { User user = (User) this.resource; if (user == null) { return; } Role role = user.getUserDatabase().findRole(rolename); if (role == null) { throw new IllegalArgumentException ("Invalid role name '" + rolename + "'"); } user.addRole(role); } /** * Remove a {@link Group} from those this user belongs to. * * @param groupname Group name of the old group */ public void removeGroup(String groupname) { User user = (User) this.resource; if (user == null) { return; } Group group = user.getUserDatabase().findGroup(groupname); if (group == null) { throw new IllegalArgumentException ("Invalid group name '" + groupname + "'"); } user.removeGroup(group); } /** * Remove a {@link Role} from those this user belongs to. * * @param rolename Role name of the old role */ public void removeRole(String rolename) { User user = (User) this.resource; if (user == null) { return; } Role role = user.getUserDatabase().findRole(rolename); if (role == null) { throw new IllegalArgumentException ("Invalid role name '" + rolename + "'"); } user.removeRole(role); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/NamingResourcesMBean.java0000644000175100017510000002600512271471332025774 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.util.ArrayList; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.RuntimeOperationsException; import org.apache.catalina.deploy.ContextEnvironment; import org.apache.catalina.deploy.ContextResource; import org.apache.catalina.deploy.ContextResourceLink; import org.apache.catalina.deploy.NamingResources; import org.apache.tomcat.util.modeler.BaseModelMBean; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; /** *

    A ModelMBean implementation for the * org.apache.catalina.deploy.NamingResources component.

    * * @author Amy Roh */ public class NamingResourcesMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public NamingResourcesMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables /** * The configuration information registry for our managed beans. */ protected Registry registry = MBeanUtils.createRegistry(); /** * The ManagedBean information describing this MBean. */ protected ManagedBean managed = registry.findManagedBean("NamingResources"); // ------------------------------------------------------------- Attributes /** * Return the MBean Names of the set of defined environment entries for * this web application */ public String[] getEnvironments() { ContextEnvironment[] envs = ((NamingResources)this.resource).findEnvironments(); ArrayList results = new ArrayList(); for (int i = 0; i < envs.length; i++) { try { ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), envs[i]); results.add(oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for environment " + envs[i]); iae.initCause(e); throw iae; } } return results.toArray(new String[results.size()]); } /** * Return the MBean Names of all the defined resource references for this * application. */ public String[] getResources() { ContextResource[] resources = ((NamingResources)this.resource).findResources(); ArrayList results = new ArrayList(); for (int i = 0; i < resources.length; i++) { try { ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), resources[i]); results.add(oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for resource " + resources[i]); iae.initCause(e); throw iae; } } return results.toArray(new String[results.size()]); } /** * Return the MBean Names of all the defined resource link references for * this application. */ public String[] getResourceLinks() { ContextResourceLink[] resourceLinks = ((NamingResources)this.resource).findResourceLinks(); ArrayList results = new ArrayList(); for (int i = 0; i < resourceLinks.length; i++) { try { ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), resourceLinks[i]); results.add(oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for resource " + resourceLinks[i]); iae.initCause(e); throw iae; } } return results.toArray(new String[results.size()]); } // ------------------------------------------------------------- Operations /** * Add an environment entry for this web application. * * @param envName New environment entry name * @param type The type of the new environment entry * @param value The value of the new environment entry */ public String addEnvironment(String envName, String type, String value) throws MalformedObjectNameException { NamingResources nresources = (NamingResources) this.resource; if (nresources == null) { return null; } ContextEnvironment env = nresources.findEnvironment(envName); if (env != null) { throw new IllegalArgumentException ("Invalid environment name - already exists '" + envName + "'"); } env = new ContextEnvironment(); env.setName(envName); env.setType(type); env.setValue(value); nresources.addEnvironment(env); // Return the corresponding MBean name ManagedBean managed = registry.findManagedBean("ContextEnvironment"); ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), env); return (oname.toString()); } /** * Add a resource reference for this web application. * * @param resourceName New resource reference name * @param type New resource reference type */ public String addResource(String resourceName, String type) throws MalformedObjectNameException { NamingResources nresources = (NamingResources) this.resource; if (nresources == null) { return null; } ContextResource resource = nresources.findResource(resourceName); if (resource != null) { throw new IllegalArgumentException ("Invalid resource name - already exists'" + resourceName + "'"); } resource = new ContextResource(); resource.setName(resourceName); resource.setType(type); nresources.addResource(resource); // Return the corresponding MBean name ManagedBean managed = registry.findManagedBean("ContextResource"); ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), resource); return (oname.toString()); } /** * Add a resource link reference for this web application. * * @param resourceLinkName New resource link reference name * @param type New resource link reference type */ public String addResourceLink(String resourceLinkName, String type) throws MalformedObjectNameException { NamingResources nresources = (NamingResources) this.resource; if (nresources == null) { return null; } ContextResourceLink resourceLink = nresources.findResourceLink(resourceLinkName); if (resourceLink != null) { throw new IllegalArgumentException ("Invalid resource link name - already exists'" + resourceLinkName + "'"); } resourceLink = new ContextResourceLink(); resourceLink.setName(resourceLinkName); resourceLink.setType(type); nresources.addResourceLink(resourceLink); // Return the corresponding MBean name ManagedBean managed = registry.findManagedBean("ContextResourceLink"); ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), resourceLink); return (oname.toString()); } /** * Remove any environment entry with the specified name. * * @param envName Name of the environment entry to remove */ public void removeEnvironment(String envName) { NamingResources nresources = (NamingResources) this.resource; if (nresources == null) { return; } ContextEnvironment env = nresources.findEnvironment(envName); if (env == null) { throw new IllegalArgumentException ("Invalid environment name '" + envName + "'"); } nresources.removeEnvironment(envName); } /** * Remove any resource reference with the specified name. * * @param resourceName Name of the resource reference to remove */ public void removeResource(String resourceName) { resourceName = ObjectName.unquote(resourceName); NamingResources nresources = (NamingResources) this.resource; if (nresources == null) { return; } ContextResource resource = nresources.findResource(resourceName); if (resource == null) { throw new IllegalArgumentException ("Invalid resource name '" + resourceName + "'"); } nresources.removeResource(resourceName); } /** * Remove any resource link reference with the specified name. * * @param resourceLinkName Name of the resource link reference to remove */ public void removeResourceLink(String resourceLinkName) { resourceLinkName = ObjectName.unquote(resourceLinkName); NamingResources nresources = (NamingResources) this.resource; if (nresources == null) { return; } ContextResourceLink resourceLink = nresources.findResourceLink(resourceLinkName); if (resourceLink == null) { throw new IllegalArgumentException ("Invalid resource Link name '" + resourceLinkName + "'"); } nresources.removeResourceLink(resourceLinkName); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java0000644000175100017510000001420512271471332026641 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.deploy.ContextResourceLink; import org.apache.catalina.deploy.NamingResources; import org.apache.tomcat.util.modeler.BaseModelMBean; /** *

    A ModelMBean implementation for the * org.apache.catalina.deploy.ContextResourceLink component.

    * * @author Amy Roh */ public class ContextResourceLinkMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public ContextResourceLinkMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables // ------------------------------------------------------------- Attributes /** * Obtain and return the value of a specific attribute of this MBean. * * @param name Name of the requested attribute * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException { // Validate the input parameters if (name == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute name is null"), "Attribute name is null"); ContextResourceLink cl = null; try { cl = (ContextResourceLink) getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } String value = null; if ("global".equals(name)) { return (cl.getGlobal()); } else if ("description".equals(name)) { return (cl.getDescription()); } else if ("name".equals(name)) { return (cl.getName()); } else if ("type".equals(name)) { return (cl.getType()); } else { value = (String) cl.getProperty(name); if (value == null) { throw new AttributeNotFoundException ("Cannot find attribute "+name); } } return value; } /** * Set the value of a specific attribute of this MBean. * * @param attribute The identification of the attribute to be set * and the new value * * @exception AttributeNotFoundException if this attribute is not * supported by this MBean * @exception MBeanException if the initializer of an object * throws an exception * @exception ReflectionException if a Java reflection exception * occurs when invoking the getter */ @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { // Validate the input parameters if (attribute == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute is null"), "Attribute is null"); String name = attribute.getName(); Object value = attribute.getValue(); if (name == null) throw new RuntimeOperationsException (new IllegalArgumentException("Attribute name is null"), "Attribute name is null"); ContextResourceLink crl = null; try { crl = (ContextResourceLink) getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } if ("global".equals(name)) { crl.setGlobal((String)value); } else if ("description".equals(name)) { crl.setDescription((String)value); } else if ("name".equals(name)) { crl.setName((String)value); } else if ("type".equals(name)) { crl.setType((String)value); } else { crl.setProperty(name, ""+value); } // cannot use side-effects. It's removed and added back each time // there is a modification in a resource. NamingResources nr = crl.getNamingResources(); nr.removeResourceLink(crl.getName()); nr.addResourceLink(crl); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java0000644000175100017510000003305412274233471027232 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.io.IOException; import java.io.Serializable; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.util.HashMap; import javax.management.MBeanServer; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import javax.management.remote.rmi.RMIConnectorServer; import javax.rmi.ssl.SslRMIClientSocketFactory; import javax.rmi.ssl.SslRMIServerSocketFactory; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * This listener fixes the port used by JMX/RMI Server making things much * simpler if you need to connect jconsole or similar to a remote Tomcat * instance that is running behind a firewall. Only the ports are configured via * the listener. The remainder of the configuration is via the standard system * properties for configuring JMX. */ public class JmxRemoteLifecycleListener implements LifecycleListener { private static final Log log = LogFactory.getLog(JmxRemoteLifecycleListener.class); /** * The string resources for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); protected String rmiBindAddress = null; protected int rmiRegistryPortPlatform = -1; protected int rmiServerPortPlatform = -1; protected boolean rmiSSL = true; protected String ciphers[] = null; protected String protocols[] = null; protected boolean clientAuth = true; protected boolean authenticate = true; protected String passwordFile = null; protected String loginModuleName = null; protected String accessFile = null; protected boolean useLocalPorts = false; protected JMXConnectorServer csPlatform = null; /** * Get the inet address on which the Platform RMI server is exported. * @return The textual representation of inet address */ public String getRmiBindAddress() { return rmiBindAddress; } /** * Set the inet address on which the Platform RMI server is exported. * @param theRmiBindAddress The textual representation of inet address */ public void setRmiBindAddress(String theRmiBindAddress) { rmiBindAddress = theRmiBindAddress; } /** * Get the port on which the Platform RMI server is exported. This is the * port that is normally chosen by the RMI stack. * @return The port number */ public int getRmiServerPortPlatform() { return rmiServerPortPlatform; } /** * Set the port on which the Platform RMI server is exported. This is the * port that is normally chosen by the RMI stack. * @param theRmiServerPortPlatform The port number */ public void setRmiServerPortPlatform(int theRmiServerPortPlatform) { rmiServerPortPlatform = theRmiServerPortPlatform; } /** * Get the port on which the Platform RMI registry is exported. * @return The port number */ public int getRmiRegistryPortPlatform() { return rmiRegistryPortPlatform; } /** * Set the port on which the Platform RMI registry is exported. * @param theRmiRegistryPortPlatform The port number */ public void setRmiRegistryPortPlatform(int theRmiRegistryPortPlatform) { rmiRegistryPortPlatform = theRmiRegistryPortPlatform; } /** * Get the flag that indicates that local ports should be used for all * connections. If using SSH tunnels, or similar, this should be set to * true to ensure the RMI client uses the tunnel. * @return true if local ports should be used */ public boolean getUseLocalPorts() { return useLocalPorts; } /** * Set the flag that indicates that local ports should be used for all * connections. If using SSH tunnels, or similar, this should be set to * true to ensure the RMI client uses the tunnel. * @param useLocalPorts Set to true if local ports should be * used */ public void setUseLocalPorts(boolean useLocalPorts) { this.useLocalPorts = useLocalPorts; } private void init() { // Get all the other parameters required from the standard system // properties. Only need to get the parameters that affect the creation // of the server port. String rmiSSLValue = System.getProperty( "com.sun.management.jmxremote.ssl", "true"); rmiSSL = Boolean.parseBoolean(rmiSSLValue); String protocolsValue = System.getProperty( "com.sun.management.jmxremote.ssl.enabled.protocols"); if (protocolsValue != null) { protocols = protocolsValue.split(","); } String ciphersValue = System.getProperty( "com.sun.management.jmxremote.ssl.enabled.cipher.suites"); if (ciphersValue != null) { ciphers = ciphersValue.split(","); } String clientAuthValue = System.getProperty( "com.sun.management.jmxremote.ssl.need.client.auth", "true"); clientAuth = Boolean.parseBoolean(clientAuthValue); String authenticateValue = System.getProperty( "com.sun.management.jmxremote.authenticate", "true"); authenticate = Boolean.parseBoolean(authenticateValue); passwordFile = System.getProperty( "com.sun.management.jmxremote.password.file", "jmxremote.password"); accessFile = System.getProperty( "com.sun.management.jmxremote.access.file", "jmxremote.access"); loginModuleName = System.getProperty( "com.sun.management.jmxremote.login.config"); } @Override public void lifecycleEvent(LifecycleEvent event) { // When the server starts, configure JMX/RMI if (Lifecycle.START_EVENT == event.getType()) { // Configure using standard jmx system properties init(); // Prevent an attacker guessing the RMI object ID System.setProperty("java.rmi.server.randomIDs", "true"); // Create the environment HashMap env = new HashMap(); RMIClientSocketFactory csf = null; RMIServerSocketFactory ssf = null; // Configure SSL for RMI connection if required if (rmiSSL) { if (rmiBindAddress != null) { throw new IllegalStateException(sm.getString( "jmxRemoteLifecycleListener.sslRmiBindAddress")); } csf = new SslRMIClientSocketFactory(); ssf = new SslRMIServerSocketFactory(ciphers, protocols, clientAuth); } // Force server bind address if required if (rmiBindAddress != null) { try { ssf = new RmiServerBindSocketFactory( InetAddress.getByName(rmiBindAddress)); } catch (UnknownHostException e) { log.error(sm.getString( "jmxRemoteLifecycleListener.invalidRmiBindAddress", rmiBindAddress), e); } } // Force the use of local ports if required if (useLocalPorts) { csf = new RmiClientLocalhostSocketFactory(csf); } // Populate the env properties used to create the server if (csf != null) { env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); env.put("com.sun.jndi.rmi.factory.socket", csf); } if (ssf != null) { env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); } // Configure authentication if (authenticate) { env.put("jmx.remote.x.password.file", passwordFile); env.put("jmx.remote.x.access.file", accessFile); env.put("jmx.remote.x.login.config", loginModuleName); } // Create the Platform server csPlatform = createServer("Platform", rmiBindAddress, rmiRegistryPortPlatform, rmiServerPortPlatform, env, csf, ssf, ManagementFactory.getPlatformMBeanServer()); } else if (Lifecycle.STOP_EVENT == event.getType()) { destroyServer("Platform", csPlatform); } } private JMXConnectorServer createServer(String serverName, String bindAddress, int theRmiRegistryPort, int theRmiServerPort, HashMap theEnv, RMIClientSocketFactory csf, RMIServerSocketFactory ssf, MBeanServer theMBeanServer) { // Create the RMI registry try { LocateRegistry.createRegistry(theRmiRegistryPort, csf, ssf); } catch (RemoteException e) { log.error(sm.getString( "jmxRemoteLifecycleListener.createRegistryFailed", serverName, Integer.toString(theRmiRegistryPort)), e); return null; } if (bindAddress == null) { bindAddress = "localhost"; } // Build the connection string with fixed ports StringBuilder url = new StringBuilder(); url.append("service:jmx:rmi://"); url.append(bindAddress); url.append(":"); url.append(theRmiServerPort); url.append("/jndi/rmi://"); url.append(bindAddress); url.append(":"); url.append(theRmiRegistryPort); url.append("/jmxrmi"); JMXServiceURL serviceUrl; try { serviceUrl = new JMXServiceURL(url.toString()); } catch (MalformedURLException e) { log.error(sm.getString( "jmxRemoteLifecycleListener.invalidURL", serverName, url.toString()), e); return null; } // Start the JMX server with the connection string JMXConnectorServer cs = null; try { cs = JMXConnectorServerFactory.newJMXConnectorServer( serviceUrl, theEnv, theMBeanServer); cs.start(); log.info(sm.getString("jmxRemoteLifecycleListener.start", Integer.toString(theRmiRegistryPort), Integer.toString(theRmiServerPort), serverName)); } catch (IOException e) { log.error(sm.getString( "jmxRemoteLifecycleListener.createServerFailed", serverName), e); } return cs; } private void destroyServer(String serverName, JMXConnectorServer theConnectorServer) { if (theConnectorServer != null) { try { theConnectorServer.stop(); } catch (IOException e) { log.error(sm.getString( "jmxRemoteLifecycleListener.destroyServerFailed", serverName),e); } } } public static class RmiClientLocalhostSocketFactory implements RMIClientSocketFactory, Serializable { private static final long serialVersionUID = 1L; private static final String FORCED_HOST = "localhost"; private RMIClientSocketFactory factory = null; public RmiClientLocalhostSocketFactory(RMIClientSocketFactory theFactory) { factory = theFactory; } @Override public Socket createSocket(String host, int port) throws IOException { if (factory == null) { return new Socket(FORCED_HOST, port); } else { return factory.createSocket(FORCED_HOST, port); } } } public static class RmiServerBindSocketFactory implements RMIServerSocketFactory { private final InetAddress bindAddress; public RmiServerBindSocketFactory(InetAddress address) { bindAddress = address; } @Override public ServerSocket createServerSocket(int port) throws IOException { return new ServerSocket(port, 0, bindAddress); } } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java0000644000175100017510000002657012271471332026433 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.util.ArrayList; import java.util.Iterator; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.RuntimeOperationsException; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; import org.apache.tomcat.util.modeler.BaseModelMBean; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; /** *

    A ModelMBean implementation for the * org.apache.catalina.users.MemoryUserDatabase component.

    * * @author Craig R. McClanahan */ public class MemoryUserDatabaseMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public MemoryUserDatabaseMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables /** * The configuration information registry for our managed beans. */ protected Registry registry = MBeanUtils.createRegistry(); /** * The ManagedBean information describing this MBean. */ protected ManagedBean managed = registry.findManagedBean("MemoryUserDatabase"); /** * The ManagedBean information describing Group MBeans. */ protected ManagedBean managedGroup = registry.findManagedBean("Group"); /** * The ManagedBean information describing Group MBeans. */ protected ManagedBean managedRole = registry.findManagedBean("Role"); /** * The ManagedBean information describing User MBeans. */ protected ManagedBean managedUser = registry.findManagedBean("User"); // ------------------------------------------------------------- Attributes /** * Return the MBean Names of all groups defined in this database. */ public String[] getGroups() { UserDatabase database = (UserDatabase) this.resource; ArrayList results = new ArrayList(); Iterator groups = database.getGroups(); while (groups.hasNext()) { Group group = groups.next(); results.add(findGroup(group.getGroupname())); } return results.toArray(new String[results.size()]); } /** * Return the MBean Names of all roles defined in this database. */ public String[] getRoles() { UserDatabase database = (UserDatabase) this.resource; ArrayList results = new ArrayList(); Iterator roles = database.getRoles(); while (roles.hasNext()) { Role role = roles.next(); results.add(findRole(role.getRolename())); } return results.toArray(new String[results.size()]); } /** * Return the MBean Names of all users defined in this database. */ public String[] getUsers() { UserDatabase database = (UserDatabase) this.resource; ArrayList results = new ArrayList(); Iterator users = database.getUsers(); while (users.hasNext()) { User user = users.next(); results.add(findUser(user.getUsername())); } return results.toArray(new String[results.size()]); } // ------------------------------------------------------------- Operations /** * Create a new Group and return the corresponding MBean Name. * * @param groupname Group name of the new group * @param description Description of the new group */ public String createGroup(String groupname, String description) { UserDatabase database = (UserDatabase) this.resource; Group group = database.createGroup(groupname, description); try { MBeanUtils.createMBean(group); } catch (Exception e) { IllegalArgumentException iae = new IllegalArgumentException ("Exception creating group [" + groupname + "] MBean"); iae.initCause(e); throw iae; } return (findGroup(groupname)); } /** * Create a new Role and return the corresponding MBean Name. * * @param rolename Group name of the new group * @param description Description of the new group */ public String createRole(String rolename, String description) { UserDatabase database = (UserDatabase) this.resource; Role role = database.createRole(rolename, description); try { MBeanUtils.createMBean(role); } catch (Exception e) { IllegalArgumentException iae = new IllegalArgumentException ("Exception creating role [" + rolename + "] MBean"); iae.initCause(e); throw iae; } return (findRole(rolename)); } /** * Create a new User and return the corresponding MBean Name. * * @param username User name of the new user * @param password Password for the new user * @param fullName Full name for the new user */ public String createUser(String username, String password, String fullName) { UserDatabase database = (UserDatabase) this.resource; User user = database.createUser(username, password, fullName); try { MBeanUtils.createMBean(user); } catch (Exception e) { IllegalArgumentException iae = new IllegalArgumentException ("Exception creating user [" + username + "] MBean"); iae.initCause(e); throw iae; } return (findUser(username)); } /** * Return the MBean Name for the specified group name (if any); * otherwise return null. * * @param groupname Group name to look up */ public String findGroup(String groupname) { UserDatabase database = (UserDatabase) this.resource; Group group = database.findGroup(groupname); if (group == null) { return (null); } try { ObjectName oname = MBeanUtils.createObjectName(managedGroup.getDomain(), group); return (oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for group [" + groupname + "]"); iae.initCause(e); throw iae; } } /** * Return the MBean Name for the specified role name (if any); * otherwise return null. * * @param rolename Role name to look up */ public String findRole(String rolename) { UserDatabase database = (UserDatabase) this.resource; Role role = database.findRole(rolename); if (role == null) { return (null); } try { ObjectName oname = MBeanUtils.createObjectName(managedRole.getDomain(), role); return (oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for role [" + rolename + "]"); iae.initCause(e); throw iae; } } /** * Return the MBean Name for the specified user name (if any); * otherwise return null. * * @param username User name to look up */ public String findUser(String username) { UserDatabase database = (UserDatabase) this.resource; User user = database.findUser(username); if (user == null) { return (null); } try { ObjectName oname = MBeanUtils.createObjectName(managedUser.getDomain(), user); return (oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for user [" + username + "]"); iae.initCause(e); throw iae; } } /** * Remove an existing group and destroy the corresponding MBean. * * @param groupname Group name to remove */ public void removeGroup(String groupname) { UserDatabase database = (UserDatabase) this.resource; Group group = database.findGroup(groupname); if (group == null) { return; } try { MBeanUtils.destroyMBean(group); database.removeGroup(group); } catch (Exception e) { IllegalArgumentException iae = new IllegalArgumentException ("Exception destroying group [" + groupname + "] MBean"); iae.initCause(e); throw iae; } } /** * Remove an existing role and destroy the corresponding MBean. * * @param rolename Role name to remove */ public void removeRole(String rolename) { UserDatabase database = (UserDatabase) this.resource; Role role = database.findRole(rolename); if (role == null) { return; } try { MBeanUtils.destroyMBean(role); database.removeRole(role); } catch (Exception e) { IllegalArgumentException iae = new IllegalArgumentException ("Exception destroying role [" + rolename + "] MBean"); iae.initCause(e); throw iae; } } /** * Remove an existing user and destroy the corresponding MBean. * * @param username User name to remove */ public void removeUser(String username) { UserDatabase database = (UserDatabase) this.resource; User user = database.findUser(username); if (user == null) { return; } try { MBeanUtils.destroyMBean(user); database.removeUser(user); } catch (Exception e) { IllegalArgumentException iae = new IllegalArgumentException ("Exception destroying user [" + username + "] MBean"); iae.initCause(e); throw iae; } } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/ClassNameMBean.java0000644000175100017510000000456712271471332024547 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.MBeanException; import javax.management.RuntimeOperationsException; import org.apache.tomcat.util.modeler.BaseModelMBean; /** *

    A convenience base class for ModelMBean implementations * where the underlying base class (and therefore the set of supported * properties) is different for varying implementations of a standard * interface. For Catalina, that includes at least the following: * Connector, Logger, Realm, and Valve. This class creates an artificial * MBean attribute named className, which reports the fully * qualified class name of the managed object as its value.

    * * @author Craig R. McClanahan */ public class ClassNameMBean extends BaseModelMBean { // ---------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initialize of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public ClassNameMBean() throws MBeanException, RuntimeOperationsException { super(); } // ------------------------------------------------------------ Properties /** * Return the fully qualified Java class name of the managed object * for this MBean. */ @Override public String getClassName() { return (this.resource.getClass().getName()); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/ContextMBean.java0000644000175100017510000001767111751711056024327 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.Context; import org.apache.catalina.deploy.ApplicationParameter; import org.apache.catalina.deploy.ErrorPage; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.deploy.SecurityConstraint; public class ContextMBean extends ContainerMBean { public ContextMBean() throws MBeanException, RuntimeOperationsException { super(); } /** * Return the set of application parameters for this application. */ public String[] findApplicationParameters() throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } ApplicationParameter[] params = context.findApplicationParameters(); String[] stringParams = new String[params.length]; for(int counter=0; counter < params.length; counter++){ stringParams[counter]=params[counter].toString(); } return stringParams; } /** * Return the security constraints for this web application. * If there are none, a zero-length array is returned. */ public String[] findConstraints() throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } SecurityConstraint[] constraints = context.findConstraints(); String[] stringConstraints = new String[constraints.length]; for(int counter=0; counter < constraints.length; counter++){ stringConstraints[counter]=constraints[counter].toString(); } return stringConstraints; } /** * Return the error page entry for the specified HTTP error code, * if any; otherwise return null. * * @param errorCode Error code to look up */ public String findErrorPage(int errorCode) throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } return context.findErrorPage(errorCode).toString(); } /** * Return the error page entry for the specified Java exception type, * if any; otherwise return null. * * @param exceptionType Exception type to look up */ public String findErrorPage(String exceptionType) throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } return context.findErrorPage(exceptionType).toString(); } /** * Return the set of defined error pages for all specified error codes * and exception types. */ public String[] findErrorPages() throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } ErrorPage[] pages = context.findErrorPages(); String[] stringPages = new String[pages.length]; for(int counter=0; counter < pages.length; counter++){ stringPages[counter]=pages[counter].toString(); } return stringPages; } /** * Return the filter definition for the specified filter name, if any; * otherwise return null. * * @param name Filter name to look up */ public String findFilterDef(String name) throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } FilterDef filterDef = context.findFilterDef(name); return filterDef.toString(); } /** * Return the set of defined filters for this Context. */ public String[] findFilterDefs() throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } FilterDef[] filterDefs = context.findFilterDefs(); String[] stringFilters = new String[filterDefs.length]; for(int counter=0; counter < filterDefs.length; counter++){ stringFilters[counter]=filterDefs[counter].toString(); } return stringFilters; } /** * Return the set of filter mappings for this Context. */ public String[] findFilterMaps() throws MBeanException { Context context; try { context = (Context)getManagedResource(); } catch (InstanceNotFoundException e) { throw new MBeanException(e); } catch (RuntimeOperationsException e) { throw new MBeanException(e); } catch (InvalidTargetObjectTypeException e) { throw new MBeanException(e); } FilterMap[] maps = context.findFilterMaps(); String[] stringMaps = new String[maps.length]; for(int counter=0; counter < maps.length; counter++){ stringMaps[counter]=maps[counter].toString(); } return stringMaps; } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/MBeanUtils.java0000644000175100017510000016320412271471332023773 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.util.Hashtable; import java.util.Set; import javax.management.DynamicMBean; import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.catalina.Contained; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Group; import org.apache.catalina.Host; import org.apache.catalina.Loader; import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Role; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.User; import org.apache.catalina.UserDatabase; import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Connector; import org.apache.catalina.deploy.ContextEnvironment; import org.apache.catalina.deploy.ContextResource; import org.apache.catalina.deploy.ContextResourceLink; import org.apache.catalina.deploy.NamingResources; import org.apache.catalina.util.ContextName; import org.apache.catalina.valves.ValveBase; import org.apache.coyote.ProtocolHandler; import org.apache.coyote.ajp.AjpAprProtocol; import org.apache.coyote.ajp.AjpProtocol; import org.apache.coyote.http11.Http11AprProtocol; import org.apache.coyote.http11.Http11NioProtocol; import org.apache.coyote.http11.Http11Protocol; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; /** * Public utility methods in support of the server side MBeans implementation. * * @author Craig R. McClanahan * @author Amy Roh */ public class MBeanUtils { // ------------------------------------------------------- Static Variables /** * The set of exceptions to the normal rules used by * createManagedBean(). The first element of each pair * is a class name, and the second element is the managed bean name. */ private static String exceptions[][] = { { "org.apache.catalina.users.MemoryGroup", "Group" }, { "org.apache.catalina.users.MemoryRole", "Role" }, { "org.apache.catalina.users.MemoryUser", "User" }, }; /** * The configuration information registry for our managed beans. */ private static Registry registry = createRegistry(); /** * The MBeanServer for this application. */ private static MBeanServer mserver = createServer(); // --------------------------------------------------------- Static Methods /** * Create and return the name of the ManagedBean that * corresponds to this Catalina component. * * @param component The component for which to create a name */ static String createManagedName(Object component) { // Deal with exceptions to the standard rule String className = component.getClass().getName(); for (int i = 0; i < exceptions.length; i++) { if (className.equals(exceptions[i][0])) { return (exceptions[i][1]); } } // Perform the standard transformation int period = className.lastIndexOf('.'); if (period >= 0) className = className.substring(period + 1); return (className); } /** * Create, register, and return an MBean for this * ContextEnvironment object. * * @param environment The ContextEnvironment to be managed * * @exception Exception if an MBean cannot be created or registered */ public static DynamicMBean createMBean(ContextEnvironment environment) throws Exception { String mname = createManagedName(environment); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(environment); ObjectName oname = createObjectName(domain, environment); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * ContextResource object. * * @param resource The ContextResource to be managed * * @exception Exception if an MBean cannot be created or registered */ public static DynamicMBean createMBean(ContextResource resource) throws Exception { String mname = createManagedName(resource); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(resource); ObjectName oname = createObjectName(domain, resource); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * ContextResourceLink object. * * @param resourceLink The ContextResourceLink to be managed * * @exception Exception if an MBean cannot be created or registered */ public static DynamicMBean createMBean(ContextResourceLink resourceLink) throws Exception { String mname = createManagedName(resourceLink); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(resourceLink); ObjectName oname = createObjectName(domain, resourceLink); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * Group object. * * @param group The Group to be managed * * @exception Exception if an MBean cannot be created or registered */ static DynamicMBean createMBean(Group group) throws Exception { String mname = createManagedName(group); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(group); ObjectName oname = createObjectName(domain, group); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * Loader object. * * @param loader The Loader to be managed * * @exception Exception if an MBean cannot be created or registered * * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static DynamicMBean createMBean(Loader loader) throws Exception { String mname = createManagedName(loader); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(loader); ObjectName oname = createObjectName(domain, loader); if( mserver.isRegistered( oname )) { // side effect: stop it mserver.unregisterMBean( oname ); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * MBeanFactory object. * * @param factory The MBeanFactory to be managed * * @exception Exception if an MBean cannot be created or registered * * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static DynamicMBean createMBean(MBeanFactory factory) throws Exception { String mname = createManagedName(factory); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(factory); ObjectName oname = createObjectName(domain, factory); if( mserver.isRegistered(oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * NamingResources object. * * @param resource The NamingResources to be managed * * @exception Exception if an MBean cannot be created or registered * * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static DynamicMBean createMBean(NamingResources resource) throws Exception { String mname = createManagedName(resource); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(resource); ObjectName oname = createObjectName(domain, resource); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * Role object. * * @param role The Role to be managed * * @exception Exception if an MBean cannot be created or registered */ static DynamicMBean createMBean(Role role) throws Exception { String mname = createManagedName(role); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(role); ObjectName oname = createObjectName(domain, role); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * User object. * * @param user The User to be managed * * @exception Exception if an MBean cannot be created or registered */ static DynamicMBean createMBean(User user) throws Exception { String mname = createManagedName(user); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(user); ObjectName oname = createObjectName(domain, user); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create, register, and return an MBean for this * UserDatabase object. * * @param userDatabase The UserDatabase to be managed * * @exception Exception if an MBean cannot be created or registered */ static DynamicMBean createMBean(UserDatabase userDatabase) throws Exception { String mname = createManagedName(userDatabase); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { Exception e = new Exception("ManagedBean is not found with "+mname); throw new MBeanException(e); } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); DynamicMBean mbean = managed.createMBean(userDatabase); ObjectName oname = createObjectName(domain, userDatabase); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } mserver.registerMBean(mbean, oname); return (mbean); } /** * Create an ObjectName for this * Connector object. * * @param domain Domain in which this name is to be created * @param connector The Connector to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Connector connector) throws MalformedObjectNameException { ObjectName name = null; try { Object addressObj = IntrospectionUtils.getProperty(connector, "address"); Integer port = (Integer) IntrospectionUtils.getProperty(connector, "port"); StringBuilder sb = new StringBuilder(domain); sb.append(":type=Connector"); sb.append(",port="); sb.append(port); if (addressObj != null) { String address = addressObj.toString(); if (address.length() > 0) { sb.append(",address="); sb.append(ObjectName.quote(address)); } } name = new ObjectName(sb.toString()); return (name); } catch (Exception e) { MalformedObjectNameException mone = new MalformedObjectNameException ("Cannot create object name for " + connector); mone.initCause(e); throw mone; } } /** * Create an ObjectName for this * Context object. * * @param domain Domain in which this name is to be created * @param context The Context to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Context context) throws MalformedObjectNameException { ObjectName name = null; Host host = (Host)context.getParent(); ContextName cn = new ContextName(context.getName(), false); name = new ObjectName(domain + ":j2eeType=WebModule,name=//" + host.getName()+ cn.getDisplayName() + ",J2EEApplication=none,J2EEServer=none"); return (name); } /** * Create an ObjectName for this * Service object. * * @param domain Domain in which this name is to be created * @param environment The ContextEnvironment to be named * * @exception MalformedObjectNameException if a name cannot be created */ public static ObjectName createObjectName(String domain, ContextEnvironment environment) throws MalformedObjectNameException { ObjectName name = null; Object container = environment.getNamingResources().getContainer(); if (container instanceof Server) { name = new ObjectName(domain + ":type=Environment" + ",resourcetype=Global,name=" + environment.getName()); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); name = new ObjectName(domain + ":type=Environment" + ",resourcetype=Context,context=" + cn.getDisplayName() + ",host=" + host.getName() + ",name=" + environment.getName()); } return (name); } /** * Create an ObjectName for this * ContextResource object. * * @param domain Domain in which this name is to be created * @param resource The ContextResource to be named * * @exception MalformedObjectNameException if a name cannot be created */ public static ObjectName createObjectName(String domain, ContextResource resource) throws MalformedObjectNameException { ObjectName name = null; String quotedResourceName = ObjectName.quote(resource.getName()); Object container = resource.getNamingResources().getContainer(); if (container instanceof Server) { name = new ObjectName(domain + ":type=Resource" + ",resourcetype=Global,class=" + resource.getType() + ",name=" + quotedResourceName); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); name = new ObjectName(domain + ":type=Resource" + ",resourcetype=Context,context=" + cn.getDisplayName() + ",host=" + host.getName() + ",class=" + resource.getType() + ",name=" + quotedResourceName); } return (name); } /** * Create an ObjectName for this * ContextResourceLink object. * * @param domain Domain in which this name is to be created * @param resourceLink The ContextResourceLink to be named * * @exception MalformedObjectNameException if a name cannot be created */ public static ObjectName createObjectName(String domain, ContextResourceLink resourceLink) throws MalformedObjectNameException { ObjectName name = null; String quotedResourceLinkName = ObjectName.quote(resourceLink.getName()); Object container = resourceLink.getNamingResources().getContainer(); if (container instanceof Server) { name = new ObjectName(domain + ":type=ResourceLink" + ",resourcetype=Global" + ",name=" + quotedResourceLinkName); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); name = new ObjectName(domain + ":type=ResourceLink" + ",resourcetype=Context,context=" + cn.getDisplayName() + ",host=" + host.getName() + ",name=" + quotedResourceLinkName); } return (name); } /** * Create an ObjectName for this * Engine object. * * @param domain Domain in which this name is to be created * @param engine The Engine to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Engine engine) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=Engine"); return (name); } /** * Create an ObjectName for this * Group object. * * @param domain Domain in which this name is to be created * @param group The Group to be named * * @exception MalformedObjectNameException if a name cannot be created */ static ObjectName createObjectName(String domain, Group group) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=Group,groupname=" + ObjectName.quote(group.getGroupname()) + ",database=" + group.getUserDatabase().getId()); return (name); } /** * Create an ObjectName for this * Host object. * * @param domain Domain in which this name is to be created * @param host The Host to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Host host) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=Host,host=" + host.getName()); return (name); } /** * Create an ObjectName for this * Loader object. * * @param domain Domain in which this name is to be created * @param loader The Loader to be named * * @exception MalformedObjectNameException if a name cannot be created */ static ObjectName createObjectName(String domain, Loader loader) throws MalformedObjectNameException { ObjectName name = null; Container container = loader.getContainer(); if (container instanceof Engine) { name = new ObjectName(domain + ":type=Loader"); } else if (container instanceof Host) { name = new ObjectName(domain + ":type=Loader,host=" + container.getName()); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); name = new ObjectName(domain + ":type=Loader,context=" + cn.getDisplayName() + ",host=" + host.getName()); } return (name); } /** * Create an ObjectName for this * Manager object. * * @param domain Domain in which this name is to be created * @param manager The Manager to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Manager manager) throws MalformedObjectNameException { ObjectName name = null; Container container = manager.getContainer(); if (container instanceof Engine) { name = new ObjectName(domain + ":type=Manager"); } else if (container instanceof Host) { name = new ObjectName(domain + ":type=Manager,host=" + container.getName()); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); name = new ObjectName(domain + ":type=Manager,context=" + cn.getDisplayName() + ",host=" + host.getName()); } return (name); } /** * Create an ObjectName for this * Server object. * * @param domain Domain in which this name is to be created * @param resources The NamingResources to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, NamingResources resources) throws MalformedObjectNameException { ObjectName name = null; Object container = resources.getContainer(); if (container instanceof Server) { name = new ObjectName(domain + ":type=NamingResources" + ",resourcetype=Global"); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); name = new ObjectName(domain + ":type=NamingResources" + ",resourcetype=Context,context=" + cn.getDisplayName() + ",host=" + host.getName()); } return (name); } /** * Create an ObjectName for this * MBeanFactory object. * * @param domain Domain in which this name is to be created * @param factory The MBeanFactory to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, MBeanFactory factory) throws MalformedObjectNameException { ObjectName name = new ObjectName(domain + ":type=MBeanFactory"); return (name); } /** * Create an ObjectName for this * Realm object. * * @param domain Domain in which this name is to be created * @param realm The Realm to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Realm realm) throws MalformedObjectNameException { ObjectName name = null; Container container = realm.getContainer(); if (container instanceof Engine) { name = new ObjectName(domain + ":type=Realm"); } else if (container instanceof Host) { name = new ObjectName(domain + ":type=Realm,host=" + container.getName()); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); name = new ObjectName(domain + ":type=Realm,context=" + cn.getDisplayName() + ",host=" + host.getName()); } return (name); } /** * Create an ObjectName for this * Role object. * * @param domain Domain in which this name is to be created * @param role The Role to be named * * @exception MalformedObjectNameException if a name cannot be created */ static ObjectName createObjectName(String domain, Role role) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=Role,rolename=" + role.getRolename() + ",database=" + role.getUserDatabase().getId()); return (name); } /** * Create an ObjectName for this * Server object. * * @param domain Domain in which this name is to be created * @param server The Server to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Server server) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=Server"); return (name); } /** * Create an ObjectName for this * Service object. * * @param domain Domain in which this name is to be created * @param service The Service to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Service service) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=Service,serviceName=" + service.getName()); return (name); } /** * Create an ObjectName for this * User object. * * @param domain Domain in which this name is to be created * @param user The User to be named * * @exception MalformedObjectNameException if a name cannot be created */ static ObjectName createObjectName(String domain, User user) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=User,username=" + ObjectName.quote(user.getUsername()) + ",database=" + user.getUserDatabase().getId()); return (name); } /** * Create an ObjectName for this * UserDatabase object. * * @param domain Domain in which this name is to be created * @param userDatabase The UserDatabase to be named * * @exception MalformedObjectNameException if a name cannot be created */ static ObjectName createObjectName(String domain, UserDatabase userDatabase) throws MalformedObjectNameException { ObjectName name = null; name = new ObjectName(domain + ":type=UserDatabase,database=" + userDatabase.getId()); return (name); } /** * Create an ObjectName for this * Valve object. * * @param domain Domain in which this name is to be created * @param valve The Valve to be named * * @exception MalformedObjectNameException if a name cannot be created * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static ObjectName createObjectName(String domain, Valve valve) throws MalformedObjectNameException { if( valve instanceof ValveBase ) { ObjectName name=((ValveBase)valve).getObjectName(); if( name != null ) return name; } ObjectName name = null; Container container = null; String className=valve.getClass().getName(); int period = className.lastIndexOf('.'); if (period >= 0) className = className.substring(period + 1); if( valve instanceof Contained ) { container = ((Contained)valve).getContainer(); } if( container == null ) { throw new MalformedObjectNameException( "Cannot create mbean for non-contained valve " + valve); } if (container instanceof Engine) { String local=""; int seq = getSeq(local); String ext=""; if( seq > 0 ) { ext=",seq=" + seq; } name = new ObjectName(domain + ":type=Valve,name=" + className + ext + local ); } else if (container instanceof Host) { String local=",host=" +container.getName(); int seq = getSeq(local); String ext=""; if( seq > 0 ) { ext=",seq=" + seq; } name = new ObjectName(domain + ":type=Valve,name=" + className + ext + local ); } else if (container instanceof Context) { Context context = ((Context)container); ContextName cn = new ContextName(context.getName(), false); Container host = context.getParent(); String local=",context=" + cn.getDisplayName() + ",host=" + host.getName(); int seq = getSeq(local); String ext=""; if( seq > 0 ) { ext=",seq=" + seq; } name = new ObjectName(domain + ":type=Valve,name=" + className + ext + local ); } return (name); } /* * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static Hashtable seq = new Hashtable(); /* * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static int getSeq( String key ) { int i[]=seq.get( key ); if (i == null ) { i=new int[1]; i[0]=0; seq.put( key, i); } else { i[0]++; } return i[0]; } /** * Create and configure (if necessary) and return the registry of * managed object descriptions. */ public static synchronized Registry createRegistry() { if (registry == null) { registry = Registry.getRegistry(null, null); ClassLoader cl = MBeanUtils.class.getClassLoader(); registry.loadDescriptors("org.apache.catalina.mbeans", cl); registry.loadDescriptors("org.apache.catalina.authenticator", cl); registry.loadDescriptors("org.apache.catalina.core", cl); registry.loadDescriptors("org.apache.catalina", cl); registry.loadDescriptors("org.apache.catalina.deploy", cl); registry.loadDescriptors("org.apache.catalina.loader", cl); registry.loadDescriptors("org.apache.catalina.realm", cl); registry.loadDescriptors("org.apache.catalina.session", cl); registry.loadDescriptors("org.apache.catalina.startup", cl); registry.loadDescriptors("org.apache.catalina.users", cl); registry.loadDescriptors("org.apache.catalina.ha", cl); registry.loadDescriptors("org.apache.catalina.connector", cl); registry.loadDescriptors("org.apache.catalina.valves", cl); } return (registry); } /** * Create and configure (if necessary) and return the * MBeanServer with which we will be * registering our DynamicMBean implementations. */ public static synchronized MBeanServer createServer() { if (mserver == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); } return (mserver); } /** * Deregister the MBean for this * Connector object. * * @param connector The Connector to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Connector connector, Service service) throws Exception { // domain is engine name String domain = service.getContainer().getName(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, connector); if( mserver.isRegistered( oname )) { mserver.unregisterMBean(oname); } // Unregister associated request processor String worker = null; ProtocolHandler handler = connector.getProtocolHandler(); if (handler instanceof Http11Protocol) { worker = ((Http11Protocol)handler).getName(); } else if (handler instanceof Http11NioProtocol) { worker = ((Http11NioProtocol)handler).getName(); } else if (handler instanceof Http11AprProtocol) { worker = ((Http11AprProtocol)handler).getName(); } else if (handler instanceof AjpProtocol) { worker = ((AjpProtocol)handler).getName(); } else if (handler instanceof AjpAprProtocol) { worker = ((AjpAprProtocol)handler).getName(); } ObjectName query = new ObjectName( domain + ":type=RequestProcessor,worker=" + worker + ",*"); Set results = mserver.queryNames(query, null); for(ObjectName result : results) { mserver.unregisterMBean(result); } } /** * Deregister the MBean for this * Context object. * * @param context The Context to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Context context) throws Exception { String domain = context.getParent().getParent().getName(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, context); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * ContextEnvironment object. * * @param environment The ContextEnvironment to be managed * * @exception Exception if an MBean cannot be deregistered */ public static void destroyMBean(ContextEnvironment environment) throws Exception { String mname = createManagedName(environment); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, environment); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * ContextResource object. * * @param resource The ContextResource to be managed * * @exception Exception if an MBean cannot be deregistered */ public static void destroyMBean(ContextResource resource) throws Exception { // If this is a user database resource need to destroy groups, roles, // users and UserDatabase mbean if ("org.apache.catalina.UserDatabase".equals(resource.getType())) { destroyMBeanUserDatabase(resource.getName()); } String mname = createManagedName(resource); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, resource); if( mserver.isRegistered(oname )) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * ContextResourceLink object. * * @param resourceLink The ContextResourceLink to be managed * * @exception Exception if an MBean cannot be deregistered */ public static void destroyMBean(ContextResourceLink resourceLink) throws Exception { String mname = createManagedName(resourceLink); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, resourceLink); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Engine object. * * @param engine The Engine to be managed * * @exception Exception if an MBean cannot be deregistered * * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Engine engine) throws Exception { String domain = engine.getName(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, engine); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Group object. * * @param group The Group to be managed * * @exception Exception if an MBean cannot be deregistered */ static void destroyMBean(Group group) throws Exception { String mname = createManagedName(group); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, group); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Host object. * * @param host The Host to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Host host) throws Exception { String domain = host.getParent().getName(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, host); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Loader object. * * @param loader The Loader to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Loader loader) throws Exception { String mname = createManagedName(loader); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, loader); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Manager object. * * @param manager The Manager to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Manager manager) throws Exception { String mname = createManagedName(manager); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, manager); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * NamingResources object. * * @param resources The NamingResources to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(NamingResources resources) throws Exception { String mname = createManagedName(resources); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, resources); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Realm object. * * @param realm The Realm to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Realm realm) throws Exception { String mname = createManagedName(realm); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, realm); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Role object. * * @param role The Role to be managed * * @exception Exception if an MBean cannot be deregistered */ static void destroyMBean(Role role) throws Exception { String mname = createManagedName(role); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, role); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Server object. * * @param server The Server to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Server server) throws Exception { String mname = createManagedName(server); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, server); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); // Global String cache - fixed name oname = new ObjectName("Catalina:type=StringCache"); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); // MBean Factory - fixed name oname = new ObjectName("Catalina:type=MBeanFactory"); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * Service object. * * @param service The Service to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Service service) throws Exception { String mname = createManagedName(service); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, service); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * User object. * * @param user The User to be managed * * @exception Exception if an MBean cannot be deregistered */ static void destroyMBean(User user) throws Exception { String mname = createManagedName(user); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, user); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for this * UserDatabase object. * * @param userDatabase The UserDatabase to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(UserDatabase userDatabase) throws Exception { String mname = createManagedName(userDatabase); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, userDatabase); if( mserver.isRegistered(oname) ) mserver.unregisterMBean(oname); } /** * Deregister the MBean for the * UserDatabase object with this name. * * @param userDatabase The UserDatabase to be managed * * @exception Exception if an MBean cannot be deregistered */ static void destroyMBeanUserDatabase(String userDatabase) throws Exception { ObjectName query = null; Set results = null; // Groups query = new ObjectName( "Users:type=Group,database=" + userDatabase + ",*"); results = mserver.queryNames(query, null); for(ObjectName result : results) { mserver.unregisterMBean(result); } // Roles query = new ObjectName( "Users:type=Role,database=" + userDatabase + ",*"); results = mserver.queryNames(query, null); for(ObjectName result : results) { mserver.unregisterMBean(result); } // Users query = new ObjectName( "Users:type=User,database=" + userDatabase + ",*"); results = mserver.queryNames(query, null); for(ObjectName result : results) { mserver.unregisterMBean(result); } // The database itself ObjectName db = new ObjectName( "Users:type=UserDatabase,database=" + userDatabase); if(mserver.isRegistered(db)) { mserver.unregisterMBean(db); } } /** * Deregister the MBean for this * Valve object. * * @param valve The Valve to be managed * * @exception Exception if an MBean cannot be deregistered * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated static void destroyMBean(Valve valve, Container container) throws Exception { ((Contained)valve).setContainer(container); String mname = createManagedName(valve); ManagedBean managed = registry.findManagedBean(mname); if (managed == null) { return; } String domain = managed.getDomain(); if (domain == null) domain = mserver.getDefaultDomain(); ObjectName oname = createObjectName(domain, valve); try { ((Contained)valve).setContainer(null); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } if( mserver.isRegistered(oname) ) { mserver.unregisterMBean(oname); } } /** * Determine the name of the domain to register MBeans for from a given * Service. * * @param service * * @deprecated To be removed since to creates a circular dependency. Will * be replaced in Tomcat 8 by a new method on {@link * Service}. */ @Deprecated public static String getDomain(Service service) { // Null service -> return null if (service == null) { return null; } String domain = null; Container engine = service.getContainer(); // Use the engine name first if (engine != null) { domain = engine.getName(); } // No engine or no engine name, use the service name if (domain == null) { domain = service.getName(); } // No service name, use null return domain; } /** * Determine the name of the domain to register MBeans for from a given * Container. * * @param container * * @deprecated To be removed since to creates a circular dependency. Will * be replaced in Tomcat 8 by a new method on {@link * Container}. */ @Deprecated public static String getDomain(Container container) { String domain = null; Container c = container; while (!(c instanceof Engine) && c != null) { c = c.getParent(); } if (c != null) { domain = c.getName(); } return domain; } /** * Calculate the key properties string to be added to an object's * {@link ObjectName} to indicate that it is associated with that container. * * @param container The container the object is associated with * @return A string suitable for appending to the ObjectName * @deprecated To be removed since to creates a circular dependency. Will * be replaced in Tomcat 8 by a new method on {@link * Container}. */ @Deprecated public static String getContainerKeyProperties(Container container) { Container c = container; StringBuilder keyProperties = new StringBuilder(); int containerCount = 0; // Work up container hierarchy, add a component to the name for // each container while (!(c instanceof Engine)) { if (c instanceof Wrapper) { keyProperties.append(",servlet="); keyProperties.append(c.getName()); } else if (c instanceof Context) { keyProperties.append(",context="); ContextName cn = new ContextName(c.getName(), false); keyProperties.append(cn.getDisplayName()); } else if (c instanceof Host) { keyProperties.append(",host="); keyProperties.append(c.getName()); } else if (c == null) { // May happen in unit testing and/or some embedding scenarios keyProperties.append(",container"); keyProperties.append(containerCount++); keyProperties.append("=null"); break; } else { // Should never happen... keyProperties.append(",container"); keyProperties.append(containerCount++); keyProperties.append('='); keyProperties.append(c.getName()); } c = c.getParent(); } return keyProperties.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/RoleMBean.java0000644000175100017510000000446712271471332023601 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import javax.management.MBeanException; import javax.management.RuntimeOperationsException; import org.apache.tomcat.util.modeler.BaseModelMBean; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; /** *

    A ModelMBean implementation for the * org.apache.catalina.Role component.

    * * @author Craig R. McClanahan */ public class RoleMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public RoleMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables /** * The configuration information registry for our managed beans. */ protected Registry registry = MBeanUtils.createRegistry(); /** * The ManagedBean information describing this MBean. */ protected ManagedBean managed = registry.findManagedBean("Role"); // ------------------------------------------------------------- Attributes // ------------------------------------------------------------- Operations } tomcat7-7.0.52/java/org/apache/catalina/mbeans/MBeanFactory.java0000644000175100017510000010626212271471332024303 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.io.File; import javax.management.MBeanServer; import javax.management.ObjectName; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.Valve; import org.apache.catalina.authenticator.SingleSignOn; import org.apache.catalina.connector.Connector; import org.apache.catalina.core.ContainerBase; import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardEngine; import org.apache.catalina.core.StandardHost; import org.apache.catalina.core.StandardService; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.realm.DataSourceRealm; import org.apache.catalina.realm.JDBCRealm; import org.apache.catalina.realm.JNDIRealm; import org.apache.catalina.realm.MemoryRealm; import org.apache.catalina.realm.UserDatabaseRealm; import org.apache.catalina.session.StandardManager; import org.apache.catalina.startup.ContextConfig; import org.apache.catalina.startup.HostConfig; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.RemoteAddrValve; import org.apache.catalina.valves.RemoteHostValve; import org.apache.catalina.valves.ValveBase; /** *

    A ModelMBean implementation for the * org.apache.catalina.core.StandardServer component.

    * * @author Amy Roh */ public class MBeanFactory { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(MBeanFactory.class); /** * The MBeanServer for this application. */ private static MBeanServer mserver = MBeanUtils.createServer(); // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception javax.management.RuntimeOperationsException if an * IllegalArgumentException occurs */ public MBeanFactory() { super(); } // ------------------------------------------------------------- Attributes /** * The container (Server/Service) for which this factory was created. */ private Object container; // ------------------------------------------------------------- Operations /** * Set the container that this factory was created for. */ public void setContainer(Object container) { this.container = container; } /** * Return the managed bean definition for the specified bean type * * @param type MBean type * * @deprecated Unused */ @Deprecated public String findObjectName(String type) { if (type.equals("org.apache.catalina.core.StandardContext")) { return "StandardContext"; } else if (type.equals("org.apache.catalina.core.StandardEngine")) { return "Engine"; } else if (type.equals("org.apache.catalina.core.StandardHost")) { return "Host"; } else { return null; } } /** * Little convenience method to remove redundant code * when retrieving the path string * * @param t path string * @return empty string if t==null || t.equals("/") */ private final String getPathStr(String t) { if (t == null || t.equals("/")) { return ""; } return t; } /** * Get Parent ContainerBase to add its child component * from parent's ObjectName */ private ContainerBase getParentContainerFromParent(ObjectName pname) throws Exception { String type = pname.getKeyProperty("type"); String j2eeType = pname.getKeyProperty("j2eeType"); Service service = getService(pname); StandardEngine engine = (StandardEngine) service.getContainer(); if ((j2eeType!=null) && (j2eeType.equals("WebModule"))) { String name = pname.getKeyProperty("name"); name = name.substring(2); int i = name.indexOf("/"); String hostName = name.substring(0,i); String path = name.substring(i); Host host = (Host) engine.findChild(hostName); String pathStr = getPathStr(path); StandardContext context = (StandardContext)host.findChild(pathStr); return context; } else if (type != null) { if (type.equals("Engine")) { return engine; } else if (type.equals("Host")) { String hostName = pname.getKeyProperty("host"); StandardHost host = (StandardHost) engine.findChild(hostName); return host; } } return null; } /** * Get Parent ContainerBase to add its child component * from child component's ObjectName as a String */ private ContainerBase getParentContainerFromChild(ObjectName oname) throws Exception { String hostName = oname.getKeyProperty("host"); String path = oname.getKeyProperty("path"); Service service = getService(oname); StandardEngine engine = (StandardEngine) service.getContainer(); if (hostName == null) { // child's container is Engine return engine; } else if (path == null) { // child's container is Host StandardHost host = (StandardHost) engine.findChild(hostName); return host; } else { // child's container is Context StandardHost host = (StandardHost) engine.findChild(hostName); path = getPathStr(path); StandardContext context = (StandardContext) host.findChild(path); return context; } } private Service getService(ObjectName oname) throws Exception { if (container instanceof Service) { // Don't bother checking the domain - this is the only option return (Service) container; } StandardService service = null; String domain = oname.getDomain(); if (container instanceof Server) { Service[] services = ((Server)container).findServices(); for (int i = 0; i < services.length; i++) { service = (StandardService) services[i]; if (domain.equals(service.getObjectName().getDomain())) { break; } } } if (service == null || !service.getObjectName().getDomain().equals(domain)) { throw new Exception("Service with the domain is not found"); } return service; } /** * Create a new AccessLoggerValve. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered * * @deprecated Will be removed in Tomcat 8.0.x. Replaced by {@link * #createValve(String, String)}. */ @Deprecated public String createAccessLoggerValve(String parent) throws Exception { ObjectName pname = new ObjectName(parent); // Create a new AccessLogValve instance AccessLogValve accessLogger = new AccessLogValve(); ContainerBase containerBase = getParentContainerFromParent(pname); // Add the new instance to its parent component containerBase.getPipeline().addValve(accessLogger); ObjectName oname = accessLogger.getObjectName(); return (oname.toString()); } /** * Create a new AjpConnector * * @param parent MBean Name of the associated parent component * @param address The IP address on which to bind * @param port TCP port number to listen on * * @exception Exception if an MBean cannot be created or registered */ public String createAjpConnector(String parent, String address, int port) throws Exception { return createConnector(parent, address, port, true, false); } /** * Create a new DataSource Realm. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered */ public String createDataSourceRealm(String parent, String dataSourceName, String roleNameCol, String userCredCol, String userNameCol, String userRoleTable, String userTable) throws Exception { // Create a new DataSourceRealm instance DataSourceRealm realm = new DataSourceRealm(); realm.setDataSourceName(dataSourceName); realm.setRoleNameCol(roleNameCol); realm.setUserCredCol(userCredCol); realm.setUserNameCol(userNameCol); realm.setUserRoleTable(userRoleTable); realm.setUserTable(userTable); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); // Add the new instance to its parent component containerBase.setRealm(realm); // Return the corresponding MBean name ObjectName oname = realm.getObjectName(); if (oname != null) { return (oname.toString()); } else { return null; } } /** * Create a new HttpConnector * * @param parent MBean Name of the associated parent component * @param address The IP address on which to bind * @param port TCP port number to listen on * * @exception Exception if an MBean cannot be created or registered */ public String createHttpConnector(String parent, String address, int port) throws Exception { return createConnector(parent, address, port, false, false); } /** * Create a new Connector * * @param parent MBean Name of the associated parent component * @param address The IP address on which to bind * @param port TCP port number to listen on * @param isAjp Create a AJP/1.3 Connector * @param isSSL Create a secure Connector * * @exception Exception if an MBean cannot be created or registered */ private String createConnector(String parent, String address, int port, boolean isAjp, boolean isSSL) throws Exception { Connector retobj = new Connector(); if ((address!=null) && (address.length()>0)) { retobj.setProperty("address", address); } // Set port number retobj.setPort(port); // Set the protocol retobj.setProtocol(isAjp ? "AJP/1.3" : "HTTP/1.1"); // Set SSL retobj.setSecure(isSSL); retobj.setScheme(isSSL ? "https" : "http"); // Add the new instance to its parent component // FIX ME - addConnector will fail ObjectName pname = new ObjectName(parent); Service service = getService(pname); service.addConnector(retobj); // Return the corresponding MBean name ObjectName coname = retobj.getObjectName(); return (coname.toString()); } /** * Create a new HttpsConnector * * @param parent MBean Name of the associated parent component * @param address The IP address on which to bind * @param port TCP port number to listen on * * @exception Exception if an MBean cannot be created or registered */ public String createHttpsConnector(String parent, String address, int port) throws Exception { return createConnector(parent, address, port, false, true); } /** * Create a new JDBC Realm. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered */ public String createJDBCRealm(String parent, String driverName, String connectionName, String connectionPassword, String connectionURL) throws Exception { // Create a new JDBCRealm instance JDBCRealm realm = new JDBCRealm(); realm.setDriverName(driverName); realm.setConnectionName(connectionName); realm.setConnectionPassword(connectionPassword); realm.setConnectionURL(connectionURL); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); // Add the new instance to its parent component containerBase.setRealm(realm); // Return the corresponding MBean name ObjectName oname = realm.getObjectName(); if (oname != null) { return (oname.toString()); } else { return null; } } /** * Create a new JNDI Realm. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered */ public String createJNDIRealm(String parent) throws Exception { // Create a new JNDIRealm instance JNDIRealm realm = new JNDIRealm(); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); // Add the new instance to its parent component containerBase.setRealm(realm); // Return the corresponding MBean name ObjectName oname = realm.getObjectName(); if (oname != null) { return (oname.toString()); } else { return null; } } /** * Create a new Memory Realm. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered */ public String createMemoryRealm(String parent) throws Exception { // Create a new MemoryRealm instance MemoryRealm realm = new MemoryRealm(); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); // Add the new instance to its parent component containerBase.setRealm(realm); // Return the corresponding MBean name ObjectName oname = realm.getObjectName(); if (oname != null) { return (oname.toString()); } else { return null; } } /** * Create a new Remote Address Filter Valve. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered * * @deprecated Will be removed in Tomcat 8.0.x. Replaced by {@link * #createValve(String, String)}. */ @Deprecated public String createRemoteAddrValve(String parent) throws Exception { // Create a new RemoteAddrValve instance RemoteAddrValve valve = new RemoteAddrValve(); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); containerBase.getPipeline().addValve(valve); ObjectName oname = valve.getObjectName(); return (oname.toString()); } /** * Create a new Remote Host Filter Valve. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered * * @deprecated Will be removed in Tomcat 8.0.x. Replaced by {@link * #createValve(String, String)}. */ @Deprecated public String createRemoteHostValve(String parent) throws Exception { // Create a new RemoteHostValve instance RemoteHostValve valve = new RemoteHostValve(); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); containerBase.getPipeline().addValve(valve); ObjectName oname = valve.getObjectName(); return (oname.toString()); } /** * Create a new Single Sign On Valve. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered * * @deprecated Will be removed in Tomcat 8.0.x. Replaced by {@link * #createValve(String, String)}. */ @Deprecated public String createSingleSignOn(String parent) throws Exception { // Create a new SingleSignOn instance SingleSignOn valve = new SingleSignOn(); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); containerBase.getPipeline().addValve(valve); ObjectName oname = valve.getObjectName(); return (oname.toString()); } /** * Create a new StandardContext. * * @param parent MBean Name of the associated parent component * @param path The context path for this Context * @param docBase Document base directory (or WAR) for this Context * * @exception Exception if an MBean cannot be created or registered */ public String createStandardContext(String parent, String path, String docBase) throws Exception { return createStandardContext(parent, path, docBase, false, false, false, false); } /** * Create a new StandardContext. * * @param parent MBean Name of the associated parent component * @param path The context path for this Context * @param docBase Document base directory (or WAR) for this Context * * @exception Exception if an MBean cannot be created or registered */ public String createStandardContext(String parent, String path, String docBase, boolean xmlValidation, boolean xmlNamespaceAware, boolean tldValidation, boolean tldNamespaceAware) throws Exception { // Create a new StandardContext instance StandardContext context = new StandardContext(); path = getPathStr(path); context.setPath(path); context.setDocBase(docBase); context.setXmlValidation(xmlValidation); context.setXmlNamespaceAware(xmlNamespaceAware); context.setTldValidation(tldValidation); context.setTldNamespaceAware(tldNamespaceAware); ContextConfig contextConfig = new ContextConfig(); context.addLifecycleListener(contextConfig); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ObjectName deployer = new ObjectName(pname.getDomain()+ ":type=Deployer,host="+ pname.getKeyProperty("host")); if(mserver.isRegistered(deployer)) { String contextName = context.getName(); mserver.invoke(deployer, "addServiced", new Object [] {contextName}, new String [] {"java.lang.String"}); String configPath = (String)mserver.getAttribute(deployer, "configBaseName"); String baseName = context.getBaseName(); File configFile = new File(new File(configPath), baseName+".xml"); if (configFile.isFile()) { context.setConfigFile(configFile.toURI().toURL()); } mserver.invoke(deployer, "manageApp", new Object[] {context}, new String[] {"org.apache.catalina.Context"}); mserver.invoke(deployer, "removeServiced", new Object [] {contextName}, new String [] {"java.lang.String"}); } else { log.warn("Deployer not found for "+pname.getKeyProperty("host")); Service service = getService(pname); Engine engine = (Engine) service.getContainer(); Host host = (Host) engine.findChild(pname.getKeyProperty("host")); host.addChild(context); } // Return the corresponding MBean name return context.getObjectName().toString(); } /** * Create a new StandardHost. * * @param parent MBean Name of the associated parent component * @param name Unique name of this Host * @param appBase Application base directory name * @param autoDeploy Should we auto deploy? * @param deployOnStartup Deploy on server startup? * @param deployXML Should we deploy Context XML config files property? * @param unpackWARs Should we unpack WARs when auto deploying? * * @exception Exception if an MBean cannot be created or registered */ public String createStandardHost(String parent, String name, String appBase, boolean autoDeploy, boolean deployOnStartup, boolean deployXML, boolean unpackWARs) throws Exception { // Create a new StandardHost instance StandardHost host = new StandardHost(); host.setName(name); host.setAppBase(appBase); host.setAutoDeploy(autoDeploy); host.setDeployOnStartup(deployOnStartup); host.setDeployXML(deployXML); host.setUnpackWARs(unpackWARs); // add HostConfig for active reloading HostConfig hostConfig = new HostConfig(); host.addLifecycleListener(hostConfig); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); Service service = getService(pname); Engine engine = (Engine) service.getContainer(); engine.addChild(host); // Return the corresponding MBean name return (host.getObjectName().toString()); } /** * Creates a new StandardService and StandardEngine. * * @param domain Domain name for the container instance * @param defaultHost Name of the default host to be used in the Engine * @param baseDir Base directory value for Engine * * @exception Exception if an MBean cannot be created or registered */ public String createStandardServiceEngine(String domain, String defaultHost, String baseDir) throws Exception{ if (!(container instanceof Server)) { throw new Exception("Container not Server"); } StandardEngine engine = new StandardEngine(); engine.setDomain(domain); engine.setName(domain); engine.setDefaultHost(defaultHost); engine.setBaseDir(baseDir); Service service = new StandardService(); service.setContainer(engine); service.setName(domain); ((Server) container).addService(service); return engine.getObjectName().toString(); } /** * Create a new StandardManager. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered */ public String createStandardManager(String parent) throws Exception { // Create a new StandardManager instance StandardManager manager = new StandardManager(); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); if (containerBase != null) { containerBase.setManager(manager); } ObjectName oname = manager.getObjectName(); if (oname != null) { return (oname.toString()); } else { return null; } } /** * Create a new UserDatabaseRealm. * * @param parent MBean Name of the associated parent component * @param resourceName Global JNDI resource name of the associated * UserDatabase * * @exception Exception if an MBean cannot be created or registered */ public String createUserDatabaseRealm(String parent, String resourceName) throws Exception { // Create a new UserDatabaseRealm instance UserDatabaseRealm realm = new UserDatabaseRealm(); realm.setResourceName(resourceName); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); // Add the new instance to its parent component containerBase.setRealm(realm); // Return the corresponding MBean name ObjectName oname = realm.getObjectName(); // FIXME getObjectName() returns null //ObjectName oname = // MBeanUtils.createObjectName(pname.getDomain(), realm); if (oname != null) { return (oname.toString()); } else { return null; } } /** * Create a new Valve and associate it with a {@link Container}. * * @param className The fully qualified class name of the {@link Valve} to * create * @param parent The MBean name of the associated parent * {@link Container}. * * @return The MBean name of the {@link Valve} that was created or * null if the {@link Valve} does not implement * {@link LifecycleMBeanBase}. */ public String createValve(String className, String parent) throws Exception { // Look for the parent ObjectName parentName = new ObjectName(parent); Container container = getParentContainerFromParent(parentName); if (container == null) { // TODO throw new IllegalArgumentException(); } Valve valve = (Valve) Class.forName(className).newInstance(); container.getPipeline().addValve(valve); if (valve instanceof LifecycleMBeanBase) { return ((LifecycleMBeanBase) valve).getObjectName().toString(); } else { return null; } } /** * Create a new Web Application Loader. * * @param parent MBean Name of the associated parent component * * @exception Exception if an MBean cannot be created or registered */ public String createWebappLoader(String parent) throws Exception { // Create a new WebappLoader instance WebappLoader loader = new WebappLoader(); // Add the new instance to its parent component ObjectName pname = new ObjectName(parent); ContainerBase containerBase = getParentContainerFromParent(pname); if (containerBase != null) { containerBase.setLoader(loader); } // FIXME add Loader.getObjectName //ObjectName oname = loader.getObjectName(); ObjectName oname = MBeanUtils.createObjectName(pname.getDomain(), loader); return (oname.toString()); } /** * Remove an existing Connector. * * @param name MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeConnector(String name) throws Exception { // Acquire a reference to the component to be removed ObjectName oname = new ObjectName(name); Service service = getService(oname); String port = oname.getKeyProperty("port"); //String address = oname.getKeyProperty("address"); Connector conns[] = service.findConnectors(); for (int i = 0; i < conns.length; i++) { String connAddress = String.valueOf(conns[i].getProperty("address")); String connPort = ""+conns[i].getPort(); // if (((address.equals("null")) && if ((connAddress==null) && port.equals(connPort)) { service.removeConnector(conns[i]); conns[i].destroy(); break; } // } else if (address.equals(connAddress)) if (port.equals(connPort)) { // Remove this component from its parent component service.removeConnector(conns[i]); conns[i].destroy(); break; } } } /** * Remove an existing Context. * * @param contextName MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeContext(String contextName) throws Exception { // Acquire a reference to the component to be removed ObjectName oname = new ObjectName(contextName); String domain = oname.getDomain(); StandardService service = (StandardService) getService(oname); Engine engine = (Engine) service.getContainer(); String name = oname.getKeyProperty("name"); name = name.substring(2); int i = name.indexOf("/"); String hostName = name.substring(0,i); String path = name.substring(i); ObjectName deployer = new ObjectName(domain+":type=Deployer,host="+ hostName); String pathStr = getPathStr(path); if(mserver.isRegistered(deployer)) { mserver.invoke(deployer,"addServiced", new Object[]{pathStr}, new String[] {"java.lang.String"}); mserver.invoke(deployer,"unmanageApp", new Object[] {pathStr}, new String[] {"java.lang.String"}); mserver.invoke(deployer,"removeServiced", new Object[] {pathStr}, new String[] {"java.lang.String"}); } else { log.warn("Deployer not found for "+hostName); Host host = (Host) engine.findChild(hostName); Context context = (Context) host.findChild(pathStr); // Remove this component from its parent component host.removeChild(context); if(context instanceof StandardContext) try { ((StandardContext)context).destroy(); } catch (Exception e) { log.warn("Error during context [" + context.getName() + "] destroy ", e); } } } /** * Remove an existing Host. * * @param name MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeHost(String name) throws Exception { // Acquire a reference to the component to be removed ObjectName oname = new ObjectName(name); String hostName = oname.getKeyProperty("host"); Service service = getService(oname); Engine engine = (Engine) service.getContainer(); Host host = (Host) engine.findChild(hostName); // Remove this component from its parent component if(host!=null) { engine.removeChild(host); } } /** * Remove an existing Loader. * * @param name MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeLoader(String name) throws Exception { ObjectName oname = new ObjectName(name); // Acquire a reference to the component to be removed ContainerBase container = getParentContainerFromChild(oname); container.setLoader(null); } /** * Remove an existing Manager. * * @param name MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeManager(String name) throws Exception { ObjectName oname = new ObjectName(name); // Acquire a reference to the component to be removed ContainerBase container = getParentContainerFromChild(oname); container.setManager(null); } /** * Remove an existing Realm. * * @param name MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeRealm(String name) throws Exception { ObjectName oname = new ObjectName(name); // Acquire a reference to the component to be removed ContainerBase container = getParentContainerFromChild(oname); container.setRealm(null); } /** * Remove an existing Service. * * @param name MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeService(String name) throws Exception { if (!(container instanceof Server)) { throw new Exception(); } // Acquire a reference to the component to be removed ObjectName oname = new ObjectName(name); Service service = getService(oname); ((Server) container).removeService(service); } /** * Remove an existing Valve. * * @param name MBean Name of the component to remove * * @exception Exception if a component cannot be removed */ public void removeValve(String name) throws Exception { // Acquire a reference to the component to be removed ObjectName oname = new ObjectName(name); ContainerBase container = getParentContainerFromChild(oname); Valve[] valves = container.getPipeline().getValves(); for (int i = 0; i < valves.length; i++) { ObjectName voname = ((ValveBase) valves[i]).getObjectName(); if (voname.equals(oname)) { container.getPipeline().removeValve(valves[i]); } } } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/GroupMBean.java0000644000175100017510000001256412271471332023771 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.util.ArrayList; import java.util.Iterator; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.RuntimeOperationsException; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.User; import org.apache.tomcat.util.modeler.BaseModelMBean; import org.apache.tomcat.util.modeler.ManagedBean; import org.apache.tomcat.util.modeler.Registry; /** *

    A ModelMBean implementation for the * org.apache.catalina.Group component.

    * * @author Craig R. McClanahan */ public class GroupMBean extends BaseModelMBean { // ----------------------------------------------------------- Constructors /** * Construct a ModelMBean with default * ModelMBeanInfo information. * * @exception MBeanException if the initializer of an object * throws an exception * @exception RuntimeOperationsException if an IllegalArgumentException * occurs */ public GroupMBean() throws MBeanException, RuntimeOperationsException { super(); } // ----------------------------------------------------- Instance Variables /** * The configuration information registry for our managed beans. */ protected Registry registry = MBeanUtils.createRegistry(); /** * The ManagedBean information describing this MBean. */ protected ManagedBean managed = registry.findManagedBean("Group"); // ------------------------------------------------------------- Attributes /** * Return the MBean Names of all authorized roles for this group. */ public String[] getRoles() { Group group = (Group) this.resource; ArrayList results = new ArrayList(); Iterator roles = group.getRoles(); while (roles.hasNext()) { Role role = null; try { role = roles.next(); ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), role); results.add(oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for role " + role); iae.initCause(e); throw iae; } } return results.toArray(new String[results.size()]); } /** * Return the MBean Names of all users that are members of this group. */ public String[] getUsers() { Group group = (Group) this.resource; ArrayList results = new ArrayList(); Iterator users = group.getUsers(); while (users.hasNext()) { User user = null; try { user = users.next(); ObjectName oname = MBeanUtils.createObjectName(managed.getDomain(), user); results.add(oname.toString()); } catch (MalformedObjectNameException e) { IllegalArgumentException iae = new IllegalArgumentException ("Cannot create object name for user " + user); iae.initCause(e); throw iae; } } return results.toArray(new String[results.size()]); } // ------------------------------------------------------------- Operations /** * Add a new {@link Role} to those this group belongs to. * * @param rolename Role name of the new role */ public void addRole(String rolename) { Group group = (Group) this.resource; if (group == null) { return; } Role role = group.getUserDatabase().findRole(rolename); if (role == null) { throw new IllegalArgumentException ("Invalid role name '" + rolename + "'"); } group.addRole(role); } /** * Remove a {@link Role} from those this group belongs to. * * @param rolename Role name of the old role */ public void removeRole(String rolename) { Group group = (Group) this.resource; if (group == null) { return; } Role role = group.getUserDatabase().findRole(rolename); if (role == null) { throw new IllegalArgumentException ("Invalid role name '" + rolename + "'"); } group.removeRole(role); } } tomcat7-7.0.52/java/org/apache/catalina/mbeans/mbeans-descriptors.xml0000644000175100017510000003332412271471332025452 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/mbeans/Constants.java0000644000175100017510000000166212271471332023743 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; public class Constants { public static final String Package = "org.apache.catalina.mbeans"; } tomcat7-7.0.52/java/org/apache/catalina/mbeans/LocalStrings.properties0000644000175100017510000000312412271471332025641 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. jmxRemoteLifecycleListener.createRegistryFailed=Unable to create the RMI registry for the {0} server using port {1} jmxRemoteLifecycleListener.createServerFailed=The JMX connector server could not be created or failed to start for the {0} server jmxRemoteLifecycleListener.destroyServerFailed=The JMX connector server could not be stopped for the {0} server jmxRemoteLifecycleListener.invalidURL=The JMX Service URL requested for the {0} server, "{1}", was invalid jmxRemoteLifecycleListener.start=The JMX Remote Listener has configured the registry on port {0} and the server on port {1} for the {2} server jmxRemoteLifecycleListener.sslRmiBindAddress=rmiBindAddress is incompatible with setting the system property com.sun.management.jmxremote.ssl to true jmxRemoteLifecycleListener.invalidRmiBindAddress=Invalid RMI bind address [{0}] tomcat7-7.0.52/java/org/apache/catalina/mbeans/LocalStrings_fr.properties0000644000175100017510000000267412271471332026341 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. jmxRemoteLifecycleListener.createRegistryFailed=Cr\u00e9ation du r\u00e9pertoire RMI impossible pour le serveur {0} utilisant le port {1} jmxRemoteLifecycleListener.createServerFailed=Le connecteur serveur JMX pour le serveur {0} n''a pas pu \u00eatre cr\u00e9\u00e9 n''a pas d\u00e9marr\u00e9 jmxRemoteLifecycleListener.destroyServerFailed=Le connecteur serveur JMX pour le serveur {0} n''a pas pu \u00eatre stopp\u00e9 jmxRemoteLifecycleListener.invalidURL=L''URL demand\u00e9e pour le serveur {0}, "{1}", est incorrect jmxRemoteLifecycleListener.start=L''\u00e9couteur distant JMX a configur\u00e9 le r\u00e9pertoire sur le port {0} et le serveur sur le port {1} pour le serveur {2} tomcat7-7.0.52/java/org/apache/catalina/mbeans/MBeanDumper.java0000644000175100017510000001656512271471332024136 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.mbeans; import java.lang.reflect.Array; import java.util.Iterator; import java.util.Set; import javax.management.JMRuntimeException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; /** * General helper to dump MBean contents to the log. * */ public class MBeanDumper { private static final Log log = LogFactory.getLog(MBeanDumper.class); private static final String CRLF = "\r\n"; /** * The following code to dump MBeans has been copied from JMXProxyServlet. * */ public static String dumpBeans(MBeanServer mbeanServer, Set names) { StringBuilder buf = new StringBuilder(); Iterator it=names.iterator(); while( it.hasNext()) { ObjectName oname=it.next(); buf.append("Name: "); buf.append(oname.toString()); buf.append(CRLF); try { MBeanInfo minfo=mbeanServer.getMBeanInfo(oname); // can't be null - I think String code=minfo.getClassName(); if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) { code=(String)mbeanServer.getAttribute(oname, "modelerType"); } buf.append("modelerType: "); buf.append(code); buf.append(CRLF); MBeanAttributeInfo attrs[]=minfo.getAttributes(); Object value=null; for (int i=0; i< attrs.length; i++) { if (! attrs[i].isReadable()) continue; String attName=attrs[i].getName(); if ("modelerType".equals(attName)) continue; if (attName.indexOf("=") >=0 || attName.indexOf(":") >=0 || attName.indexOf(" ") >=0 ) { continue; } try { value=mbeanServer.getAttribute(oname, attName); } catch (JMRuntimeException rme) { Throwable cause = rme.getCause(); if (cause instanceof UnsupportedOperationException) { if (log.isDebugEnabled()) { log.debug("Error getting attribute " + oname + " " + attName, rme); } } else if (cause instanceof NullPointerException) { if (log.isDebugEnabled()) { log.debug("Error getting attribute " + oname + " " + attName, rme); } } else { log.error("Error getting attribute " + oname + " " + attName, rme); } continue; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("Error getting attribute " + oname + " " + attName, t); continue; } if (value==null) continue; String valueString; try { Class c = value.getClass(); if (c.isArray()) { int len = Array.getLength(value); StringBuilder sb = new StringBuilder("Array[" + c.getComponentType().getName() + "] of length " + len); if (len > 0) { sb.append(CRLF); } for (int j = 0; j < len; j++) { sb.append("\t"); Object item = Array.get(value, j); if (item == null) { sb.append("NULL VALUE"); } else { try { sb.append(escape(item.toString())); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); sb.append("NON-STRINGABLE VALUE"); } } if (j < len - 1) { sb.append(CRLF); } } valueString = sb.toString(); } else { valueString = escape(value.toString()); } buf.append(attName); buf.append(": "); buf.append(valueString); buf.append(CRLF); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } buf.append(CRLF); } return buf.toString(); } public static String escape(String value) { // The only invalid char is \n // We also need to keep the string short and split it with \nSPACE // XXX TODO int idx=value.indexOf( "\n" ); if( idx < 0 ) return value; int prev=0; StringBuilder sb=new StringBuilder(); while( idx >= 0 ) { appendHead(sb, value, prev, idx); sb.append( "\\n\n "); prev=idx+1; if( idx==value.length() -1 ) break; idx=value.indexOf('\n', idx+1); } if( prev < value.length() ) appendHead( sb, value, prev, value.length()); return sb.toString(); } private static void appendHead( StringBuilder sb, String value, int start, int end) { if (end < 1) return; int pos=start; while( end-pos > 78 ) { sb.append( value.substring(pos, pos+78)); sb.append( "\n "); pos=pos+78; } sb.append( value.substring(pos,end)); } } tomcat7-7.0.52/java/org/apache/catalina/Service.java0000644000175100017510000001063312271471332022120 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import org.apache.catalina.connector.Connector; /** * A Service is a group of one or more * Connectors that share a single Container * to process their incoming requests. This arrangement allows, for example, * a non-SSL and SSL connector to share the same population of web apps. *

    * A given JVM can contain any number of Service instances; however, they are * completely independent of each other and share only the basic JVM facilities * and classes on the system class path. * * @author Craig R. McClanahan */ public interface Service extends Lifecycle { // ------------------------------------------------------------- Properties /** * Return the Container that handles requests for all * Connectors associated with this Service. */ public Container getContainer(); /** * Set the Container that handles requests for all * Connectors associated with this Service. * * @param container The new Container */ public void setContainer(Container container); /** * Return descriptive information about this Service implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo(); /** * Return the name of this Service. */ public String getName(); /** * Set the name of this Service. * * @param name The new service name */ public void setName(String name); /** * Return the Server with which we are associated (if any). */ public Server getServer(); /** * Set the Server with which we are associated (if any). * * @param server The server that owns this Service */ public void setServer(Server server); /** * Return the parent class loader for this component. If not set, return * {@link #getServer()} {@link Server#getParentClassLoader()}. If no server * has been set, return the system class loader. */ public ClassLoader getParentClassLoader(); /** * Set the parent class loader for this service. * * @param parent The new parent class loader */ public void setParentClassLoader(ClassLoader parent); // --------------------------------------------------------- Public Methods /** * Add a new Connector to the set of defined Connectors, and associate it * with this Service's Container. * * @param connector The Connector to be added */ public void addConnector(Connector connector); /** * Find and return the set of Connectors associated with this Service. */ public Connector[] findConnectors(); /** * Remove the specified Connector from the set associated from this * Service. The removed Connector will also be disassociated from our * Container. * * @param connector The Connector to be removed */ public void removeConnector(Connector connector); /** * Adds a named executor to the service * @param ex Executor */ public void addExecutor(Executor ex); /** * Retrieves all executors * @return Executor[] */ public Executor[] findExecutors(); /** * Retrieves executor by name, null if not found * @param name String * @return Executor */ public Executor getExecutor(String name); /** * Removes an executor from the service * @param ex Executor */ public void removeExecutor(Executor ex); } tomcat7-7.0.52/java/org/apache/catalina/Contained.java0000644000175100017510000000322312271471332022421 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** *

    Decoupling interface which specifies that an implementing class is * associated with at most one Container instance.

    * * @author Craig R. McClanahan * @author Peter Donald */ public interface Contained { //-------------------------------------------------------------- Properties /** * Return the Container with which this instance is associated * (if any); otherwise return null. */ public Container getContainer(); /** * Set the Container with which this instance is associated. * * @param container The Container instance with which this instance is to * be associated, or null to disassociate this instance * from any Container */ public void setContainer(Container container); } tomcat7-7.0.52/java/org/apache/catalina/Engine.java0000644000175100017510000000601512271471332021724 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * An Engine is a Container that represents the entire Catalina servlet * engine. It is useful in the following types of scenarios: *
      *
    • You wish to use Interceptors that see every single request processed * by the entire engine. *
    • You wish to run Catalina in with a standalone HTTP connector, but still * want support for multiple virtual hosts. *
    * In general, you would not use an Engine when deploying Catalina connected * to a web server (such as Apache), because the Connector will have * utilized the web server's facilities to determine which Context (or * perhaps even which Wrapper) should be utilized to process this request. *

    * The child containers attached to an Engine are generally implementations * of Host (representing a virtual host) or Context (representing individual * an individual servlet context), depending upon the Engine implementation. *

    * If used, an Engine is always the top level Container in a Catalina * hierarchy. Therefore, the implementation's setParent() method * should throw IllegalArgumentException. * * @author Craig R. McClanahan */ public interface Engine extends Container { // ------------------------------------------------------------- Properties /** * Return the default hostname for this Engine. */ public String getDefaultHost(); /** * Set the default hostname for this Engine. * * @param defaultHost The new default host */ public void setDefaultHost(String defaultHost); /** * Retrieve the JvmRouteId for this engine. */ public String getJvmRoute(); /** * Set the JvmRouteId for this engine. * * @param jvmRouteId the (new) JVM Route ID. Each Engine within a cluster * must have a unique JVM Route ID. */ public void setJvmRoute(String jvmRouteId); /** * Return the Service with which we are associated (if any). */ public Service getService(); /** * Set the Service with which we are associated (if any). * * @param service The service that owns this Engine */ public void setService(Service service); } tomcat7-7.0.52/java/org/apache/catalina/Pipeline.java0000644000175100017510000001261312271471332022265 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** *

    Interface describing a collection of Valves that should be executed * in sequence when the invoke() method is invoked. It is * required that a Valve somewhere in the pipeline (usually the last one) * must process the request and create the corresponding response, rather * than trying to pass the request on.

    * *

    There is generally a single Pipeline instance associated with each * Container. The container's normal request processing functionality is * generally encapsulated in a container-specific Valve, which should always * be executed at the end of a pipeline. To facilitate this, the * setBasic() method is provided to set the Valve instance that * will always be executed last. Other Valves will be executed in the order * that they were added, before the basic Valve is executed.

    * * @author Craig R. McClanahan * @author Peter Donald */ public interface Pipeline { // ------------------------------------------------------------- Properties /** *

    Return the Valve instance that has been distinguished as the basic * Valve for this Pipeline (if any). */ public Valve getBasic(); /** *

    Set the Valve instance that has been distinguished as the basic * Valve for this Pipeline (if any). Prior to setting the basic Valve, * the Valve's setContainer() will be called, if it * implements Contained, with the owning Container as an * argument. The method may throw an IllegalArgumentException * if this Valve chooses not to be associated with this Container, or * IllegalStateException if it is already associated with * a different Container.

    * * @param valve Valve to be distinguished as the basic Valve */ public void setBasic(Valve valve); // --------------------------------------------------------- Public Methods /** *

    Add a new Valve to the end of the pipeline associated with this * Container. Prior to adding the Valve, the Valve's * setContainer() method will be called, if it implements * Contained, with the owning Container as an argument. * The method may throw an * IllegalArgumentException if this Valve chooses not to * be associated with this Container, or IllegalStateException * if it is already associated with a different Container.

    * *

    Implementation note: Implementations are expected to trigger the * {@link Container#ADD_VALVE_EVENT} for the associated container if this * call is successful.

    * * @param valve Valve to be added * * @exception IllegalArgumentException if this Container refused to * accept the specified Valve * @exception IllegalArgumentException if the specified Valve refuses to be * associated with this Container * @exception IllegalStateException if the specified Valve is already * associated with a different Container */ public void addValve(Valve valve); /** * Return the set of Valves in the pipeline associated with this * Container, including the basic Valve (if any). If there are no * such Valves, a zero-length array is returned. */ public Valve[] getValves(); /** * Remove the specified Valve from the pipeline associated with this * Container, if it is found; otherwise, do nothing. If the Valve is * found and removed, the Valve's setContainer(null) method * will be called if it implements Contained. * *

    Implementation note: Implementations are expected to trigger the * {@link Container#REMOVE_VALVE_EVENT} for the associated container if this * call is successful.

    * * @param valve Valve to be removed */ public void removeValve(Valve valve); /** *

    Return the Valve instance that has been distinguished as the basic * Valve for this Pipeline (if any). */ public Valve getFirst(); /** * Returns true if all the valves in this pipeline support async, false otherwise * @return true if all the valves in this pipeline support async, false otherwise */ public boolean isAsyncSupported(); /** * Return the Container with which this Pipeline is associated. */ public Container getContainer(); /** * Set the Container with which this Pipeline is associated. * * @param container The new associated container */ public void setContainer(Container container); } tomcat7-7.0.52/java/org/apache/catalina/websocket/0000755000175100017510000000000012301126371021632 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/websocket/WebSocketServlet.java0000644000175100017510000002213612251115161025733 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.util.Base64; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.res.StringManager; /** * Provides the base implementation of a Servlet for processing WebSocket * connections as per RFC6455. It is expected that applications will extend this * implementation and provide application specific functionality. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public abstract class WebSocketServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final byte[] WS_ACCEPT = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes( B2CConverter.ISO_8859_1); private static final StringManager sm = StringManager.getManager(Constants.Package); private final Queue sha1Helpers = new ConcurrentLinkedQueue(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Information required to send the server handshake message String key; String subProtocol = null; List extensions = Collections.emptyList(); if (!headerContainsToken(req, "upgrade", "websocket")) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } if (!headerContainsToken(req, "connection", "upgrade")) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } if (!headerContainsToken(req, "sec-websocket-version", "13")) { resp.setStatus(426); resp.setHeader("Sec-WebSocket-Version", "13"); return; } key = req.getHeader("Sec-WebSocket-Key"); if (key == null) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } String origin = req.getHeader("Origin"); if (!verifyOrigin(origin)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } List subProtocols = getTokensFromHeader(req, "Sec-WebSocket-Protocol"); if (!subProtocols.isEmpty()) { subProtocol = selectSubProtocol(subProtocols); } // TODO Read client handshake - Sec-WebSocket-Extensions // TODO Extensions require the ability to specify something (API TBD) // that can be passed to the Tomcat internals and process extension // data present when the frame is fragmented. // If we got this far, all is good. Accept the connection. resp.setHeader("Upgrade", "websocket"); resp.setHeader("Connection", "upgrade"); resp.setHeader("Sec-WebSocket-Accept", getWebSocketAccept(key)); if (subProtocol != null) { resp.setHeader("Sec-WebSocket-Protocol", subProtocol); } if (!extensions.isEmpty()) { // TODO } WsHttpServletRequestWrapper wrapper = new WsHttpServletRequestWrapper(req); StreamInbound inbound = createWebSocketInbound(subProtocol, wrapper); wrapper.invalidate(); // Small hack until the Servlet API provides a way to do this. ServletRequest inner = req; // Unwrap the request while (inner instanceof ServletRequestWrapper) { inner = ((ServletRequestWrapper) inner).getRequest(); } if (inner instanceof RequestFacade) { ((RequestFacade) inner).doUpgrade(inbound); } else { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getString("servlet.reqUpgradeFail")); } } /* * This only works for tokens. Quoted strings need more sophisticated * parsing. */ private boolean headerContainsToken(HttpServletRequest req, String headerName, String target) { Enumeration headers = req.getHeaders(headerName); while (headers.hasMoreElements()) { String header = headers.nextElement(); String[] tokens = header.split(","); for (String token : tokens) { if (target.equalsIgnoreCase(token.trim())) { return true; } } } return false; } /* * This only works for tokens. Quoted strings need more sophisticated * parsing. */ private List getTokensFromHeader(HttpServletRequest req, String headerName) { List result = new ArrayList(); Enumeration headers = req.getHeaders(headerName); while (headers.hasMoreElements()) { String header = headers.nextElement(); String[] tokens = header.split(","); for (String token : tokens) { result.add(token.trim()); } } return result; } private String getWebSocketAccept(String key) throws ServletException { MessageDigest sha1Helper = sha1Helpers.poll(); if (sha1Helper == null) { try { sha1Helper = MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException e) { throw new ServletException(e); } } sha1Helper.reset(); sha1Helper.update(key.getBytes(B2CConverter.ISO_8859_1)); String result = Base64.encode(sha1Helper.digest(WS_ACCEPT)); sha1Helpers.add(sha1Helper); return result; } /** * Intended to be overridden by sub-classes that wish to verify the origin * of a WebSocket request before processing it. * * @param origin The value of the origin header from the request which * may be null * * @return true to accept the request. false to * reject it. This default implementation always returns * true. */ protected boolean verifyOrigin(String origin) { return true; } /** * Intended to be overridden by sub-classes that wish to select a * sub-protocol if the client provides a list of supported protocols. * * @param subProtocols The list of sub-protocols supported by the client * in client preference order. The server is under no * obligation to respect the declared preference * @return null if no sub-protocol is selected or the name of * the protocol which must be one of the protocols listed by * the client. This default implementation always returns * null. */ protected String selectSubProtocol(List subProtocols) { return null; } /** * Create the instance that will process this inbound connection. * Applications must provide a new instance for each connection. * * @param subProtocol The sub-protocol agreed between the client and * server or null if none was agreed * @param request The HTTP request that initiated this WebSocket * connection. Note that this object is only * valid inside this method. You must not retain a * reference to it outside the execution of this * method. If Tomcat detects such access, it will throw * an IllegalStateException */ protected abstract StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request); } tomcat7-7.0.52/java/org/apache/catalina/websocket/MessageInbound.java0000644000175100017510000001362312251115161025404 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.nio.ByteBuffer; import java.nio.CharBuffer; import org.apache.tomcat.util.res.StringManager; /** * Base implementation of the class used to process WebSocket connections based * on messages. Applications should extend this class to provide application * specific functionality. Applications that wish to operate on a stream basis * rather than a message basis should use {@link StreamInbound}. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public abstract class MessageInbound extends StreamInbound { private static final StringManager sm = StringManager.getManager(Constants.Package); // 2MB - like maxPostSize private int byteBufferMaxSize = 2097152; private int charBufferMaxSize = 2097152; private ByteBuffer bb = ByteBuffer.allocate(8192); private CharBuffer cb = CharBuffer.allocate(8192); @Override protected final void onBinaryData(InputStream is) throws IOException { int read = 0; while (read > -1) { bb.position(bb.position() + read); if (bb.remaining() == 0) { resizeByteBuffer(); } read = is.read(bb.array(), bb.position(), bb.remaining()); } bb.flip(); onBinaryMessage(bb); bb.clear(); } @Override protected final void onTextData(Reader r) throws IOException { int read = 0; while (read > -1) { cb.position(cb.position() + read); if (cb.remaining() == 0) { resizeCharBuffer(); } read = r.read(cb.array(), cb.position(), cb.remaining()); } cb.flip(); onTextMessage(cb); cb.clear(); } private void resizeByteBuffer() throws IOException { int maxSize = getByteBufferMaxSize(); if (bb.limit() >= maxSize) { throw new IOException(sm.getString("message.bufferTooSmall")); } long newSize = bb.limit() * 2; if (newSize > maxSize) { newSize = maxSize; } // Cast is safe. newSize < maxSize and maxSize is an int ByteBuffer newBuffer = ByteBuffer.allocate((int) newSize); bb.rewind(); newBuffer.put(bb); bb = newBuffer; } private void resizeCharBuffer() throws IOException { int maxSize = getCharBufferMaxSize(); if (cb.limit() >= maxSize) { throw new IOException(sm.getString("message.bufferTooSmall")); } long newSize = cb.limit() * 2; if (newSize > maxSize) { newSize = maxSize; } // Cast is safe. newSize < maxSize and maxSize is an int CharBuffer newBuffer = CharBuffer.allocate((int) newSize); cb.rewind(); newBuffer.put(cb); cb = newBuffer; } /** * Obtain the current maximum size (in bytes) of the buffer used for binary * messages. */ public final int getByteBufferMaxSize() { return byteBufferMaxSize; } /** * Set the maximum size (in bytes) of the buffer used for binary messages. */ public final void setByteBufferMaxSize(int byteBufferMaxSize) { this.byteBufferMaxSize = byteBufferMaxSize; } /** * Obtain the current maximum size (in characters) of the buffer used for * binary messages. */ public final int getCharBufferMaxSize() { return charBufferMaxSize; } /** * Set the maximum size (in characters) of the buffer used for textual * messages. */ public final void setCharBufferMaxSize(int charBufferMaxSize) { this.charBufferMaxSize = charBufferMaxSize; } /** * This method is called when there is a binary WebSocket message available * to process. The message is presented via a ByteBuffer and may have been * formed from one or more frames. The number of frames used to transmit the * message is not made visible to the application. * * @param message The WebSocket message * * @throws IOException If a problem occurs processing the message. Any * exception will trigger the closing of the WebSocket * connection. */ protected abstract void onBinaryMessage(ByteBuffer message) throws IOException; /** * This method is called when there is a textual WebSocket message available * to process. The message is presented via a CharBuffer and may have been * formed from one or more frames. The number of frames used to transmit the * message is not made visible to the application. * * @param message The WebSocket message * * @throws IOException If a problem occurs processing the message. Any * exception will trigger the closing of the WebSocket * connection. */ protected abstract void onTextMessage(CharBuffer message) throws IOException; } tomcat7-7.0.52/java/org/apache/catalina/websocket/WsFrame.java0000644000175100017510000001634412251115161024050 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CoderResult; import org.apache.catalina.util.Conversions; import org.apache.coyote.http11.upgrade.UpgradeProcessor; import org.apache.tomcat.util.buf.Utf8Decoder; import org.apache.tomcat.util.res.StringManager; /** * Represents a complete WebSocket frame with the exception of the payload for * non-control frames. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public class WsFrame { private static final StringManager sm = StringManager.getManager(Constants.Package); private final boolean fin; private final int rsv; private final byte opCode; private final byte[] mask = new byte[4]; private long payloadLength; private final ByteBuffer payload; /** * Create the new WebSocket frame, reading data from the processor as * necessary. * * @param first First byte of data for this frame * @param processor Processor associated with the WebSocket connection on * which the frame has been sent * * @throws IOException If a problem occurs processing the frame. Any * exception will trigger the closing of the WebSocket * connection. */ private WsFrame(byte first, UpgradeProcessor processor) throws IOException { int b = first & 0xFF; fin = (b & 0x80) > 0; rsv = (b & 0x70) >>> 4; opCode = (byte) (b & 0x0F); b = blockingRead(processor); // Client data must be masked if ((b & 0x80) == 0) { throw new IOException(sm.getString("frame.notMasked")); } payloadLength = b & 0x7F; if (payloadLength == 126) { byte[] extended = new byte[2]; blockingRead(processor, extended); payloadLength = Conversions.byteArrayToLong(extended); } else if (payloadLength == 127) { byte[] extended = new byte[8]; blockingRead(processor, extended); payloadLength = Conversions.byteArrayToLong(extended); } if (isControl()) { if (payloadLength > 125) { throw new IOException(); } if (!fin) { throw new IOException(); } } blockingRead(processor, mask); if (isControl()) { // Note: Payload limited to <= 125 bytes by test above payload = ByteBuffer.allocate((int) payloadLength); blockingRead(processor, payload); if (opCode == Constants.OPCODE_CLOSE && payloadLength > 2) { // Check close payload - if present - is valid UTF-8 CharBuffer cb = CharBuffer.allocate((int) payloadLength); Utf8Decoder decoder = new Utf8Decoder(); payload.position(2); CoderResult cr = decoder.decode(payload, cb, true); payload.position(0); if (cr.isError()) { throw new IOException(sm.getString("frame.invalidUtf8")); } } } else { payload = null; } } public boolean getFin() { return fin; } public int getRsv() { return rsv; } public byte getOpCode() { return opCode; } public boolean isControl() { return (opCode & 0x08) > 0; } public byte[] getMask() { return mask; } public long getPayLoadLength() { return payloadLength; } public ByteBuffer getPayLoad() { return payload; } /* * Blocks until a aingle byte has been read */ private int blockingRead(UpgradeProcessor processor) throws IOException { int result = processor.read(); if (result == -1) { throw new IOException(sm.getString("frame.eos")); } return result; } /* * Blocks until the byte array has been filled. */ private void blockingRead(UpgradeProcessor processor, byte[] bytes) throws IOException { int read = 0; int last = 0; while (read < bytes.length) { last = processor.read(true, bytes, read, bytes.length - read); if (last == -1) { throw new IOException(sm.getString("frame.eos")); } read += last; } } /* * Intended to read whole payload and blocks until it has. Therefore able to * unmask the payload data. */ private void blockingRead(UpgradeProcessor processor, ByteBuffer bb) throws IOException { int last = 0; while (bb.hasRemaining()) { last = processor.read(); if (last == -1) { throw new IOException(sm.getString("frame.eos")); } bb.put((byte) (last ^ mask[bb.position() % 4])); } bb.flip(); } /** * Read the next WebSocket frame, reading data from the processor as * necessary. * * @param processor Processor associated with the WebSocket connection on * which the frame has been sent * * @param block Should this method block until a frame is presented if no * data is currently available to process. Note that is a * single byte is available, this method will block until the * complete frame (excluding payload for non-control frames) is * available. * * @throws IOException If a problem occurs processing the frame. Any * exception will trigger the closing of the WebSocket * connection. */ public static WsFrame nextFrame(UpgradeProcessor processor, boolean block) throws IOException { byte[] first = new byte[1]; int read = processor.read(block, first, 0, 1); if (read == 1) { return new WsFrame(first[0], processor); } else if (read == 0) { return null; } else if (read == -1) { throw new EOFException(sm.getString("frame.readEos")); } else { throw new IOException( sm.getString("frame.readFailed", Integer.valueOf(read))); } } } tomcat7-7.0.52/java/org/apache/catalina/websocket/WsHttpServletRequestWrapper.java0000644000175100017510000002373312251115161030214 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.Principal; import java.util.Collection; import java.util.Enumeration; import java.util.Locale; import java.util.Map; import javax.servlet.AsyncContext; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.Part; import org.apache.tomcat.util.res.StringManager; /** * Wrapper for the HttpServletRequest object that allows the underlying request * object to be invalidated. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public class WsHttpServletRequestWrapper implements HttpServletRequest { private static final StringManager sm = StringManager.getManager(Constants.Package); private HttpServletRequest request; public WsHttpServletRequestWrapper(HttpServletRequest request) { this.request = request; } private HttpServletRequest getRequest() { if (request == null) { throw new IllegalStateException(sm.getString("wrapper.invalid")); } return request; } protected void invalidate() { request = null; } @Override public Object getAttribute(String name) { return getRequest().getAttribute(name); } @Override public Enumeration getAttributeNames() { return getRequest().getAttributeNames(); } @Override public String getCharacterEncoding() { return getRequest().getCharacterEncoding(); } @Override public void setCharacterEncoding(String env) throws UnsupportedEncodingException { getRequest().setCharacterEncoding(env); } @Override public int getContentLength() { return getRequest().getContentLength(); } @Override public String getContentType() { return getRequest().getContentType(); } @Override public ServletInputStream getInputStream() throws IOException { return getRequest().getInputStream(); } @Override public String getParameter(String name) { return getRequest().getParameter(name); } @Override public Enumeration getParameterNames() { return getRequest().getParameterNames(); } @Override public String[] getParameterValues(String name) { return getRequest().getParameterValues(name); } @Override public Map getParameterMap() { return getRequest().getParameterMap(); } @Override public String getProtocol() { return getRequest().getProtocol(); } @Override public String getScheme() { return getRequest().getScheme(); } @Override public String getServerName() { return getRequest().getServerName(); } @Override public int getServerPort() { return getRequest().getServerPort(); } @Override public BufferedReader getReader() throws IOException { return getRequest().getReader(); } @Override public String getRemoteAddr() { return getRequest().getRemoteAddr(); } @Override public String getRemoteHost() { return getRequest().getRemoteHost(); } @Override public void setAttribute(String name, Object o) { getRequest().setAttribute(name, o); } @Override public void removeAttribute(String name) { getRequest().removeAttribute(name); } @Override public Locale getLocale() { return getRequest().getLocale(); } @Override public Enumeration getLocales() { return getRequest().getLocales(); } @Override public boolean isSecure() { return getRequest().isSecure(); } @Override public RequestDispatcher getRequestDispatcher(String path) { return getRequest().getRequestDispatcher(path); } @Override @Deprecated public String getRealPath(String path) { return getRequest().getRealPath(path); } @Override public int getRemotePort() { return getRequest().getRemotePort(); } @Override public String getLocalName() { return getRequest().getLocalName(); } @Override public String getLocalAddr() { return getRequest().getLocalAddr(); } @Override public int getLocalPort() { return getRequest().getLocalPort(); } @Override public ServletContext getServletContext() { return getRequest().getServletContext(); } @Override public AsyncContext startAsync() throws IllegalStateException { return getRequest().startAsync(); } @Override public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { return getRequest().startAsync(servletRequest, servletResponse); } @Override public boolean isAsyncStarted() { return getRequest().isAsyncStarted(); } @Override public boolean isAsyncSupported() { return getRequest().isAsyncSupported(); } @Override public AsyncContext getAsyncContext() { return getRequest().getAsyncContext(); } @Override public DispatcherType getDispatcherType() { return getRequest().getDispatcherType(); } @Override public String getAuthType() { return getRequest().getAuthType(); } @Override public Cookie[] getCookies() { return getRequest().getCookies(); } @Override public long getDateHeader(String name) { return getRequest().getDateHeader(name); } @Override public String getHeader(String name) { return getRequest().getHeader(name); } @Override public Enumeration getHeaders(String name) { return getRequest().getHeaders(name); } @Override public Enumeration getHeaderNames() { return getRequest().getHeaderNames(); } @Override public int getIntHeader(String name) { return getRequest().getIntHeader(name); } @Override public String getMethod() { return getRequest().getMethod(); } @Override public String getPathInfo() { return getRequest().getPathInfo(); } @Override public String getPathTranslated() { return getRequest().getPathTranslated(); } @Override public String getContextPath() { return getRequest().getContextPath(); } @Override public String getQueryString() { return getRequest().getQueryString(); } @Override public String getRemoteUser() { return getRequest().getRemoteUser(); } @Override public boolean isUserInRole(String role) { return getRequest().isUserInRole(role); } @Override public Principal getUserPrincipal() { return getRequest().getUserPrincipal(); } @Override public String getRequestedSessionId() { return getRequest().getRequestedSessionId(); } @Override public String getRequestURI() { return getRequest().getRequestURI(); } @Override public StringBuffer getRequestURL() { return getRequest().getRequestURL(); } @Override public String getServletPath() { return getRequest().getServletPath(); } @Override public HttpSession getSession(boolean create) { return getRequest().getSession(create); } @Override public HttpSession getSession() { return getRequest().getSession(); } @Override public boolean isRequestedSessionIdValid() { return getRequest().isRequestedSessionIdValid(); } @Override public boolean isRequestedSessionIdFromCookie() { return getRequest().isRequestedSessionIdFromCookie(); } @Override public boolean isRequestedSessionIdFromURL() { return getRequest().isRequestedSessionIdFromURL(); } @Override @Deprecated public boolean isRequestedSessionIdFromUrl() { return getRequest().isRequestedSessionIdFromUrl(); } @Override public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { return getRequest().authenticate(response); } @Override public void login(String username, String password) throws ServletException { getRequest().login(username, password); } @Override public void logout() throws ServletException { getRequest().logout(); } @Override public Collection getParts() throws IOException, ServletException { return getRequest().getParts(); } @Override public Part getPart(String name) throws IOException, ServletException { return getRequest().getPart(name); } } tomcat7-7.0.52/java/org/apache/catalina/websocket/StreamInbound.java0000644000175100017510000002671112251115161025255 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.nio.ByteBuffer; import java.nio.charset.MalformedInputException; import java.nio.charset.UnmappableCharacterException; import org.apache.coyote.http11.upgrade.UpgradeInbound; import org.apache.coyote.http11.upgrade.UpgradeOutbound; import org.apache.coyote.http11.upgrade.UpgradeProcessor; import org.apache.tomcat.util.buf.Utf8Decoder; import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; /** * Base implementation of the class used to process WebSocket connections based * on streams. Applications should extend this class to provide application * specific functionality. Applications that wish to operate on a message basis * rather than a stream basis should use {@link MessageInbound}. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public abstract class StreamInbound implements UpgradeInbound { private final ClassLoader applicationClassLoader; private UpgradeProcessor processor = null; private WsOutbound outbound; private int outboundByteBufferSize = WsOutbound.DEFAULT_BUFFER_SIZE; private int outboundCharBufferSize = WsOutbound.DEFAULT_BUFFER_SIZE; public StreamInbound() { applicationClassLoader = Thread.currentThread().getContextClassLoader(); } public int getOutboundByteBufferSize() { return outboundByteBufferSize; } /** * This only applies to the {@link WsOutbound} instance returned from * {@link #getWsOutbound()} created by a subsequent call to * {@link #setUpgradeOutbound(UpgradeOutbound)}. The current * {@link WsOutbound} instance, if any, is not affected. * * @param outboundByteBufferSize */ public void setOutboundByteBufferSize(int outboundByteBufferSize) { this.outboundByteBufferSize = outboundByteBufferSize; } public int getOutboundCharBufferSize() { return outboundCharBufferSize; } /** * This only applies to the {@link WsOutbound} instance returned from * {@link #getWsOutbound()} created by a subsequent call to * {@link #setUpgradeOutbound(UpgradeOutbound)}. The current * {@link WsOutbound} instance, if any, is not affected. * * @param outboundCharBufferSize */ public void setOutboundCharBufferSize(int outboundCharBufferSize) { this.outboundCharBufferSize = outboundCharBufferSize; } @Override public final void setUpgradeOutbound(UpgradeOutbound upgradeOutbound) { outbound = new WsOutbound(upgradeOutbound, this, outboundByteBufferSize, outboundCharBufferSize); } @Override public final void setUpgradeProcessor(UpgradeProcessor processor) { this.processor = processor; } /** * Obtain the outbound side of this WebSocket connection used for writing * data to the client. */ public final WsOutbound getWsOutbound() { return outbound; } @Override public final SocketState onData() throws IOException { // Must be start the start of a message (which may consist of multiple // frames) WsInputStream wsIs = new WsInputStream(processor, getWsOutbound()); try { WsFrame frame = wsIs.nextFrame(false); while (frame != null) { // TODO User defined extensions may define values for rsv if (frame.getRsv() > 0) { closeOutboundConnection( Constants.STATUS_PROTOCOL_ERROR, null); return SocketState.CLOSED; } byte opCode = frame.getOpCode(); if (opCode == Constants.OPCODE_BINARY) { doOnBinaryData(wsIs); } else if (opCode == Constants.OPCODE_TEXT) { InputStreamReader r = new InputStreamReader(wsIs, new Utf8Decoder()); doOnTextData(r); } else if (opCode == Constants.OPCODE_CLOSE){ closeOutboundConnection(frame); return SocketState.CLOSED; } else if (opCode == Constants.OPCODE_PING) { getWsOutbound().pong(frame.getPayLoad()); } else if (opCode == Constants.OPCODE_PONG) { doOnPong(frame.getPayLoad()); } else { // Unknown OpCode closeOutboundConnection( Constants.STATUS_PROTOCOL_ERROR, null); return SocketState.CLOSED; } frame = wsIs.nextFrame(false); } } catch (MalformedInputException mie) { // Invalid UTF-8 closeOutboundConnection(Constants.STATUS_BAD_DATA, null); return SocketState.CLOSED; } catch (UnmappableCharacterException uce) { // Invalid UTF-8 closeOutboundConnection(Constants.STATUS_BAD_DATA, null); return SocketState.CLOSED; } catch (IOException ioe) { // Given something must have gone to reach this point, this // might not work but try it anyway. closeOutboundConnection(Constants.STATUS_PROTOCOL_ERROR, null); return SocketState.CLOSED; } return SocketState.UPGRADED; } private void doOnBinaryData(InputStream is) throws IOException { // Need to call onBinaryData using the web application's class loader Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { onBinaryData(is); } finally { t.setContextClassLoader(cl); } } private void doOnTextData(Reader r) throws IOException { // Need to call onTextData using the web application's class loader Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { onTextData(r); } finally { t.setContextClassLoader(cl); } } private void closeOutboundConnection(int status, ByteBuffer data) throws IOException { try { getWsOutbound().close(status, data); } finally { doOnClose(status); } } private void closeOutboundConnection(WsFrame frame) throws IOException { try { getWsOutbound().close(frame); } finally { doOnClose(Constants.STATUS_CLOSE_NORMAL); } } /** * Package private so the outbound connection can signal that the connection * has been closed - usually due to an error. * * @param status The WebSocket status code to report to the application */ void doOnClose(int status) { // Need to call onClose using the web application's class loader Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { onClose(status); } finally { t.setContextClassLoader(cl); } } private void doOnPong(ByteBuffer payload) { // Need to call onPong using the web application's class loader Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { onPong(payload); } finally { t.setContextClassLoader(cl); } } @Override public final void onUpgradeComplete() { // Need to call onOpen using the web application's class loader Thread t = Thread.currentThread(); ClassLoader cl = t.getContextClassLoader(); t.setContextClassLoader(applicationClassLoader); try { onOpen(outbound); } finally { t.setContextClassLoader(cl); } } /** * Intended to be overridden by sub-classes that wish to be notified * when the outbound connection is established. The default implementation * is a NO-OP. * * @param outbound The outbound WebSocket connection. */ protected void onOpen(WsOutbound outbound) { // NO-OP } /** * Intended to be overridden by sub-classes that wish to be notified * when the outbound connection is closed. The default implementation * is a NO-OP. * * @param status The status code of the close reason. */ protected void onClose(int status) { // NO-OP } /** * Intended to be overridden by sub-classes that wish to be notified * when a pong is received. The default implementation is a NO-OP. * * @param payload The payload included in the pong. */ protected void onPong(ByteBuffer payload) { // NO-OP } /** * This method is called when there is a binary WebSocket message available * to process. The message is presented via a stream and may be formed from * one or more frames. The number of frames used to transmit the message is * not made visible to the application. * * @param is The WebSocket message * * @throws IOException If a problem occurs processing the message. Any * exception will trigger the closing of the WebSocket * connection. */ protected abstract void onBinaryData(InputStream is) throws IOException; /** * This method is called when there is a textual WebSocket message available * to process. The message is presented via a reader and may be formed from * one or more frames. The number of frames used to transmit the message is * not made visible to the application. * * @param r The WebSocket message * * @throws IOException If a problem occurs processing the message. Any * exception will trigger the closing of the WebSocket * connection. */ protected abstract void onTextData(Reader r) throws IOException; /** * This default implementation sets the read timeout to infinite and expects * the WebSocket application to close the connection when it is no longer * required. Applications wishing to set an explicit timeout may override * this method and return a value of their choice. * * @return The read timeout in milliseconds or -1 for infinite */ @Override public int getReadTimeout() { return -1; } } tomcat7-7.0.52/java/org/apache/catalina/websocket/Constants.java0000644000175100017510000001164612251115161024460 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; /** * Constants for this Java package. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public class Constants { public static final String Package = "org.apache.catalina.websocket"; // OP Codes public static final byte OPCODE_CONTINUATION = 0x00; public static final byte OPCODE_TEXT = 0x01; public static final byte OPCODE_BINARY = 0x02; public static final byte OPCODE_CLOSE = 0x08; public static final byte OPCODE_PING = 0x09; public static final byte OPCODE_PONG = 0x0A; // Status Codes // Definitions as per RFC 6455 (http://tools.ietf.org/html/rfc6455) /** * 1000 indicates a normal closure, meaning whatever purpose the * connection was established for has been fulfilled. */ public static final int STATUS_CLOSE_NORMAL = 1000; /** * 1001 indicates that an endpoint is "going away", such as a server * going down, or a browser having navigated away from a page. */ public static final int STATUS_SHUTDOWN = 1001; /** * 1002 indicates that an endpoint is terminating the connection due * to a protocol error. */ public static final int STATUS_PROTOCOL_ERROR = 1002; /** * 1003 indicates that an endpoint is terminating the connection * because it has received a type of data it cannot accept (e.g. an * endpoint that understands only text data MAY send this if it * receives a binary message). */ public static final int STATUS_UNEXPECTED_DATA_TYPE = 1003; // 1004 is reserved. The specific meaning might be defined in the future. /** * 1005 is a reserved value and MUST NOT be set as a status code in a * Close control frame by an endpoint. It is designated for use in * applications expecting a status code to indicate that no status * code was actually present. */ public static final int STATUS_CODE_MISSING = 1005; /** * 1006 is a reserved value and MUST NOT be set as a status code in a * Close control frame by an endpoint. It is designated for use in * applications expecting a status code to indicate that the * connection was closed abnormally, e.g. without sending or * receiving a Close control frame. */ public static final int STATUS_CLOSED_UNEXPECTEDLY = 1006; /** * 1007 indicates that an endpoint is terminating the connection * because it has received data within a message that was not * consistent with the type of the message (e.g., non-UTF-8 [RFC3629] * data within a text message). */ public static final int STATUS_BAD_DATA = 1007; /** * 1008 indicates that an endpoint is terminating the connection * because it has received a message that violates its policy. This * is a generic status code that can be returned when there is no * other more suitable status code (e.g. 1003 or 1009), or if there * is a need to hide specific details about the policy. */ public static final int STATUS_POLICY_VIOLATION = 1008; /** * 1009 indicates that an endpoint is terminating the connection * because it has received a message which is too big for it to * process. */ public static final int STATUS_MESSAGE_TOO_LARGE = 1009; /** * 1010 indicates that an endpoint (client) is terminating the * connection because it has expected the server to negotiate one or * more extension, but the server didn't return them in the response * message of the WebSocket handshake. The list of extensions which * are needed SHOULD appear in the /reason/ part of the Close frame. * Note that this status code is not used by the server, because it * can fail the WebSocket handshake instead. */ public static final int STATUS_REQUIRED_EXTENSION = 1010; /** * 1011 indicates that a server is terminating the connection because it * encountered an unexpected condition that prevented it from fulfilling the * request. */ public static final int STATUS_UNEXPECTED_CONDITION = 1011; } tomcat7-7.0.52/java/org/apache/catalina/websocket/LocalStrings.properties0000644000175100017510000000351111772600635026367 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. frame.eos=The end of the stream was reached before the expected number of payload bytes could be read frame.invalidUtf8=A sequence of bytes was received that did not represent valid UTF-8 frame.readFailed=Failed to read the first byte of the next WebSocket frame. The return value from the read was [{0}] frame.readEos=The end of the stream was reached when trying to read the first byte of a new WebSocket frame frame.notMasked=The client frame was not masked but all client frames must be masked is.notContinuation=A frame with the OpCode [{0}] was received when a continuation frame was expected is.unknownOpCode=A frame with the unrecognized OpCode [{0}] was received message.bufferTooSmall=The buffer is not big enough to contain the message currently being processed servlet.reqUpgradeFail=Unable to cast to the Tomcat internal request class in order to complete HTTP upgrade outbound.closed=The WebSocket connection has been closed wrapper.invalid=An attempt was made to access the request object passed to WebSocketServlet.createWebSocketInbound() outside of that methodtomcat7-7.0.52/java/org/apache/catalina/websocket/WsOutbound.java0000644000175100017510000004524412251115161024616 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import org.apache.coyote.http11.upgrade.UpgradeOutbound; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.res.StringManager; /** * Provides the means to write WebSocket messages to the client. All methods * that write to the client (or update a buffer that is later written to the * client) are synchronized to prevent multiple threads trying to write to the * client at the same time. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public class WsOutbound { private static final StringManager sm = StringManager.getManager(Constants.Package); public static final int DEFAULT_BUFFER_SIZE = 8192; /** * This state lock is used rather than synchronized methods to allow error * handling to be managed outside of the synchronization else deadlocks may * occur such as https://issues.apache.org/bugzilla/show_bug.cgi?id=55524 */ private final Object stateLock = new Object(); private UpgradeOutbound upgradeOutbound; private StreamInbound streamInbound; private ByteBuffer bb; private CharBuffer cb; private boolean closed = false; private Boolean text = null; private boolean firstFrame = true; public WsOutbound(UpgradeOutbound upgradeOutbound, StreamInbound streamInbound) { this(upgradeOutbound, streamInbound, DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE); } public WsOutbound(UpgradeOutbound upgradeOutbound, StreamInbound streamInbound, int byteBufferSize, int charBufferSize) { this.upgradeOutbound = upgradeOutbound; this.streamInbound = streamInbound; this.bb = ByteBuffer.allocate(byteBufferSize); this.cb = CharBuffer.allocate(charBufferSize); } /** * Adds the data to the buffer for binary data. If a textual message is * currently in progress that message will be completed and a new binary * message started. If the buffer for binary data is full, the buffer will * be flushed and a new binary continuation fragment started. * * @param b The byte (only the least significant byte is used) of data to * send to the client. * * @throws IOException If a flush is required and an error occurs writing * the WebSocket frame to the client */ public void writeBinaryData(int b) throws IOException { try { synchronized (stateLock) { if (closed) { throw new IOException(sm.getString("outbound.closed")); } if (bb.position() == bb.capacity()) { doFlush(false); } if (text == null) { text = Boolean.FALSE; } else if (text == Boolean.TRUE) { // Flush the character data flush(); text = Boolean.FALSE; } bb.put((byte) (b & 0xFF)); } } catch (IOException ioe) { // Any IOException is terminal. Make sure the inbound side knows // that something went wrong. // The exception handling needs to be outside of the sync to avoid // possible deadlocks (e.g. BZ55524) when triggering the inbound // close as that will execute user code streamInbound.doOnClose(Constants.STATUS_CLOSED_UNEXPECTEDLY); throw ioe; } } /** * Adds the data to the buffer for textual data. If a binary message is * currently in progress that message will be completed and a new textual * message started. If the buffer for textual data is full, the buffer will * be flushed and a new textual continuation fragment started. * * @param c The character to send to the client. * * @throws IOException If a flush is required and an error occurs writing * the WebSocket frame to the client */ public void writeTextData(char c) throws IOException { try { synchronized (stateLock) { if (closed) { throw new IOException(sm.getString("outbound.closed")); } if (cb.position() == cb.capacity()) { doFlush(false); } if (text == null) { text = Boolean.TRUE; } else if (text == Boolean.FALSE) { // Flush the binary data flush(); text = Boolean.TRUE; } cb.append(c); } } catch (IOException ioe) { // Any IOException is terminal. Make sure the Inbound side knows // that something went wrong. // The exception handling needs to be outside of the sync to avoid // possible deadlocks (e.g. BZ55524) when triggering the inbound // close as that will execute user code streamInbound.doOnClose(Constants.STATUS_CLOSED_UNEXPECTEDLY); throw ioe; } } /** * Flush any message (binary or textual) that may be buffered and then send * a WebSocket binary message as a single frame with the provided buffer as * the payload of the message. * * @param msgBb The buffer containing the payload * * @throws IOException If an error occurs writing to the client */ public void writeBinaryMessage(ByteBuffer msgBb) throws IOException { try { synchronized (stateLock) { if (closed) { throw new IOException(sm.getString("outbound.closed")); } if (text != null) { // Empty the buffer flush(); } text = Boolean.FALSE; doWriteBytes(msgBb, true); } } catch (IOException ioe) { // Any IOException is terminal. Make sure the Inbound side knows // that something went wrong. // The exception handling needs to be outside of the sync to avoid // possible deadlocks (e.g. BZ55524) when triggering the inbound // close as that will execute user code streamInbound.doOnClose(Constants.STATUS_CLOSED_UNEXPECTEDLY); throw ioe; } } /** * Flush any message (binary or textual) that may be buffered and then send * a WebSocket text message as a single frame with the provided buffer as * the payload of the message. * * @param msgCb The buffer containing the payload * * @throws IOException If an error occurs writing to the client */ public void writeTextMessage(CharBuffer msgCb) throws IOException { try { synchronized (stateLock) { if (closed) { throw new IOException(sm.getString("outbound.closed")); } if (text != null) { // Empty the buffer flush(); } text = Boolean.TRUE; doWriteText(msgCb, true); } } catch (IOException ioe) { // Any IOException is terminal. Make sure the Inbound side knows // that something went wrong. // The exception handling needs to be outside of the sync to avoid // possible deadlocks (e.g. BZ55524) when triggering the inbound // close as that will execute user code streamInbound.doOnClose(Constants.STATUS_CLOSED_UNEXPECTEDLY); throw ioe; } } /** * Flush any message (binary or textual) that may be buffered. * * @throws IOException If an error occurs writing to the client */ public void flush() throws IOException { try { synchronized (stateLock) { if (closed) { throw new IOException(sm.getString("outbound.closed")); } doFlush(true); } } catch (IOException ioe) { // Any IOException is terminal. Make sure the Inbound side knows // that something went wrong. // The exception handling needs to be outside of the sync to avoid // possible deadlocks (e.g. BZ55524) when triggering the inbound // close as that will execute user code streamInbound.doOnClose(Constants.STATUS_CLOSED_UNEXPECTEDLY); throw ioe; } } private void doFlush(boolean finalFragment) throws IOException { if (text == null) { // No data return; } if (text.booleanValue()) { cb.flip(); doWriteText(cb, finalFragment); } else { bb.flip(); doWriteBytes(bb, finalFragment); } } /** * Respond to a client close by sending a close that echoes the status code * and message. * * @param frame The close frame received from a client * * @throws IOException If an error occurs writing to the client */ protected void close(WsFrame frame) throws IOException { if (frame.getPayLoadLength() > 0) { // Must be status (2 bytes) plus optional message if (frame.getPayLoadLength() == 1) { throw new IOException(); } int status = (frame.getPayLoad().get() & 0xFF) << 8; status += frame.getPayLoad().get() & 0xFF; if (validateCloseStatus(status)) { // Echo the status back to the client close(status, frame.getPayLoad()); } else { // Invalid close code close(Constants.STATUS_PROTOCOL_ERROR, null); } } else { // No status close(0, null); } } private boolean validateCloseStatus(int status) { if (status == Constants.STATUS_CLOSE_NORMAL || status == Constants.STATUS_SHUTDOWN || status == Constants.STATUS_PROTOCOL_ERROR || status == Constants.STATUS_UNEXPECTED_DATA_TYPE || status == Constants.STATUS_BAD_DATA || status == Constants.STATUS_POLICY_VIOLATION || status == Constants.STATUS_MESSAGE_TOO_LARGE || status == Constants.STATUS_REQUIRED_EXTENSION || status == Constants.STATUS_UNEXPECTED_CONDITION || (status > 2999 && status < 5000)) { // Other 1xxx reserved / not permitted // 2xxx reserved // 3xxx framework defined // 4xxx application defined return true; } // <1000 unused // >4999 undefined return false; } /** * Send a close message to the client * * @param status Must be a valid status code or zero to send no code * @param data Optional message. If message is defined, a valid status * code must be provided. * * @throws IOException If an error occurs writing to the client */ public void close(int status, ByteBuffer data) throws IOException { try { synchronized (stateLock) { if (closed) { return; } // Send any partial data we have try { doFlush(false); } finally { closed = true; } upgradeOutbound.write(0x88); if (status == 0) { upgradeOutbound.write(0); } else if (data == null || data.position() == data.limit()) { upgradeOutbound.write(2); upgradeOutbound.write(status >>> 8); upgradeOutbound.write(status); } else { upgradeOutbound.write(2 + data.limit() - data.position()); upgradeOutbound.write(status >>> 8); upgradeOutbound.write(status); upgradeOutbound.write(data.array(), data.position(), data.limit() - data.position()); } upgradeOutbound.flush(); bb = null; cb = null; upgradeOutbound = null; } } catch (IOException ioe) { // Any IOException is terminal. Make sure the Inbound side knows // that something went wrong. // The exception handling needs to be outside of the sync to avoid // possible deadlocks (e.g. BZ55524) when triggering the inbound // close as that will execute user code streamInbound.doOnClose(Constants.STATUS_CLOSED_UNEXPECTEDLY); throw ioe; } } /** * Send a pong message to the client * * @param data Optional message. * * @throws IOException If an error occurs writing to the client */ public void pong(ByteBuffer data) throws IOException { sendControlMessage(data, Constants.OPCODE_PONG); } /** * Send a ping message to the client * * @param data Optional message. * * @throws IOException If an error occurs writing to the client */ public void ping(ByteBuffer data) throws IOException { sendControlMessage(data, Constants.OPCODE_PING); } /** * Generic function to send either a ping or a pong. * * @param data Optional message. * @param opcode The byte to include as the opcode. * * @throws IOException If an error occurs writing to the client */ private void sendControlMessage(ByteBuffer data, byte opcode) throws IOException { try { synchronized (stateLock) { if (closed) { throw new IOException(sm.getString("outbound.closed")); } doFlush(false); upgradeOutbound.write(0x80 | opcode); if (data == null) { upgradeOutbound.write(0); } else { upgradeOutbound.write(data.limit() - data.position()); upgradeOutbound.write(data.array(), data.position(), data.limit() - data.position()); } upgradeOutbound.flush(); } } catch (IOException ioe) { // Any IOException is terminal. Make sure the Inbound side knows // that something went wrong. // The exception handling needs to be outside of the sync to avoid // possible deadlocks (e.g. BZ55524) when triggering the inbound // close as that will execute user code streamInbound.doOnClose(Constants.STATUS_CLOSED_UNEXPECTEDLY); throw ioe; } } /** * Writes the provided bytes as the payload in a new WebSocket frame. * * @param buffer The bytes to include in the payload. * @param finalFragment Do these bytes represent the final fragment of a * WebSocket message? * @throws IOException */ private void doWriteBytes(ByteBuffer buffer, boolean finalFragment) throws IOException { if (closed) { throw new IOException(sm.getString("outbound.closed")); } // Work out the first byte int first = 0x00; if (finalFragment) { first = first + 0x80; } if (firstFrame) { if (text.booleanValue()) { first = first + 0x1; } else { first = first + 0x2; } } // Continuation frame is OpCode 0 upgradeOutbound.write(first); if (buffer.limit() < 126) { upgradeOutbound.write(buffer.limit()); } else if (buffer.limit() < 65536) { upgradeOutbound.write(126); upgradeOutbound.write(buffer.limit() >>> 8); upgradeOutbound.write(buffer.limit() & 0xFF); } else { // Will never be more than 2^31-1 upgradeOutbound.write(127); upgradeOutbound.write(0); upgradeOutbound.write(0); upgradeOutbound.write(0); upgradeOutbound.write(0); upgradeOutbound.write(buffer.limit() >>> 24); upgradeOutbound.write(buffer.limit() >>> 16); upgradeOutbound.write(buffer.limit() >>> 8); upgradeOutbound.write(buffer.limit() & 0xFF); } // Write the content upgradeOutbound.write(buffer.array(), buffer.arrayOffset(), buffer.limit()); upgradeOutbound.flush(); // Reset if (finalFragment) { text = null; firstFrame = true; } else { firstFrame = false; } bb.clear(); } /* * Convert the textual message to bytes and then output it. */ private void doWriteText(CharBuffer buffer, boolean finalFragment) throws IOException { CharsetEncoder encoder = B2CConverter.UTF_8.newEncoder(); do { CoderResult cr = encoder.encode(buffer, bb, true); if (cr.isError()) { cr.throwException(); } bb.flip(); if (buffer.hasRemaining()) { doWriteBytes(bb, false); } else { doWriteBytes(bb, finalFragment); } } while (buffer.hasRemaining()); // Reset - bb will be cleared in doWriteBytes() cb.clear(); } } tomcat7-7.0.52/java/org/apache/catalina/websocket/WsInputStream.java0000644000175100017510000001224112251115161025261 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.websocket; import java.io.IOException; import java.io.InputStream; import org.apache.coyote.http11.upgrade.UpgradeProcessor; import org.apache.tomcat.util.res.StringManager; /** * This class is used to read WebSocket frames from the underlying socket and * makes the payload available for reading as an {@link InputStream}. It only * makes the number of bytes declared in the payload length available for * reading even if more bytes are available from the socket. * * @deprecated Replaced by the JSR356 WebSocket 1.0 implementation and will be * removed in Tomcat 8.0.x. */ @Deprecated public class WsInputStream extends InputStream { private static final StringManager sm = StringManager.getManager(Constants.Package); private final UpgradeProcessor processor; private final WsOutbound outbound; private WsFrame frame; private long remaining; private long readThisFragment; private String error = null; public WsInputStream(UpgradeProcessor processor, WsOutbound outbound) { this.processor = processor; this.outbound = outbound; } /** * Process the next WebSocket frame. * * @param block Should this method block until a frame is presented if no * data is currently available to process. Note that if a * single byte is available, this method will block until the * complete frame (excluding payload for non-control frames) is * available. * * @return The next frame to be processed or null if block is * false and there is no data to be processed. * * @throws IOException If a problem occurs reading the data for the frame. */ public WsFrame nextFrame(boolean block) throws IOException { frame = WsFrame.nextFrame(processor, block); if (frame != null) { readThisFragment = 0; remaining = frame.getPayLoadLength(); } return frame; } // ----------------------------------------------------- InputStream methods @Override public int read() throws IOException { makePayloadDataAvailable(); if (remaining == 0) { return -1; } remaining--; readThisFragment++; int masked = processor.read(); if(masked == -1) { return -1; } return masked ^ (frame.getMask()[(int) ((readThisFragment - 1) % 4)] & 0xFF); } @Override public int read(byte b[], int off, int len) throws IOException { makePayloadDataAvailable(); if (remaining == 0) { return -1; } if (len > remaining) { len = (int) remaining; } int result = processor.read(true, b, off, len); if(result == -1) { return -1; } for (int i = off; i < off + result; i++) { b[i] = (byte) (b[i] ^ frame.getMask()[(int) ((readThisFragment + i - off) % 4)]); } remaining -= result; readThisFragment += result; return result; } /* * Ensures that there is payload data ready to read. */ private void makePayloadDataAvailable() throws IOException { if (error != null) { throw new IOException(error); } while (remaining == 0 && !frame.getFin()) { // Need more data - process next frame nextFrame(true); while (frame.isControl()) { if (frame.getOpCode() == Constants.OPCODE_PING) { outbound.pong(frame.getPayLoad()); } else if (frame.getOpCode() == Constants.OPCODE_PONG) { // NO-OP. Swallow it. } else if (frame.getOpCode() == Constants.OPCODE_CLOSE) { outbound.close(frame); } else{ throw new IOException(sm.getString("is.unknownOpCode", Byte.valueOf(frame.getOpCode()))); } nextFrame(true); } if (frame.getOpCode() != Constants.OPCODE_CONTINUATION) { error = sm.getString("is.notContinuation", Byte.valueOf(frame.getOpCode())); throw new IOException(error); } } } } tomcat7-7.0.52/java/org/apache/catalina/comet/0000755000175100017510000000000012301126371020753 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/comet/CometFilterChain.java0000644000175100017510000000325412271471332025010 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.comet; import java.io.IOException; import javax.servlet.ServletException; /** * A CometFilterChain is an object provided by the servlet container to the developer * giving a view into the invocation chain of a filtered event for a resource. Filters * use the CometFilterChain to invoke the next filter in the chain, or if the calling filter * is the last filter in the chain, to invoke the resource at the end of the chain. * * @author Remy Maucherat * @author Filip Hanik */ public interface CometFilterChain { /** * Causes the next filter in the chain to be invoked, or if the calling filter is the last filter * in the chain, causes the resource at the end of the chain to be invoked. * * @param event the event to pass along the chain. */ public void doFilterEvent(CometEvent event) throws IOException, ServletException; } tomcat7-7.0.52/java/org/apache/catalina/comet/CometFilter.java0000644000175100017510000000717612271471332024054 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.comet; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.ServletException; /** * A Comet filter, similar to regular filters, performs filtering tasks on either * the request to a resource (a Comet servlet), or on the response from a resource, or both. *

    * Filters perform filtering in the doFilterEvent method. Every Filter has access to * a FilterConfig object from which it can obtain its initialization parameters, a * reference to the ServletContext which it can use, for example, to load resources * needed for filtering tasks. *

    * Filters are configured in the deployment descriptor of a web application *

    * Examples that have been identified for this design are
    * 1) Authentication Filters
    * 2) Logging and Auditing Filters
    * 3) Image conversion Filters
    * 4) Data compression Filters
    * 5) Encryption Filters
    * 6) Tokenizing Filters
    * 7) Filters that trigger resource access events
    * 8) XSL/T filters
    * 9) Mime-type chain Filter
    *
    * * @author Remy Maucherat * @author Filip Hanik */ public interface CometFilter extends Filter { /** * The doFilterEvent method of the CometFilter is called by the container * each time a request/response pair is passed through the chain due * to a client event for a resource at the end of the chain. The CometFilterChain passed in to this * method allows the Filter to pass on the event to the next entity in the * chain.

    * A typical implementation of this method would follow the following pattern:-
    * 1. Examine the request
    * 2. Optionally wrap the request object contained in the event with a custom implementation to * filter content or headers for input filtering and pass a CometEvent instance containing * the wrapped request to the next filter
    * 3. Optionally wrap the response object contained in the event with a custom implementation to * filter content or headers for output filtering and pass a CometEvent instance containing * the wrapped request to the next filter
    * 4. a) Either invoke the next entity in the chain using the CometFilterChain object (chain.doFilterEvent()),
    * 4. b) or not pass on the request/response pair to the next entity in the filter chain to block the event processing
    * 5. Directly set fields on the response after invocation of the next entity in the filter chain. * * @param event the event that is being processed. Another event may be passed along the chain. * @param chain * @throws IOException * @throws ServletException */ public void doFilterEvent(CometEvent event, CometFilterChain chain) throws IOException, ServletException; } tomcat7-7.0.52/java/org/apache/catalina/comet/CometEvent.java0000644000175100017510000001561512271471332023705 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.comet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * The CometEvent interface. * * @author Filip Hanik * @author Remy Maucherat */ public interface CometEvent { /** * Enumeration describing the major events that the container can invoke * the CometProcessors event() method with.
    * BEGIN - will be called at the beginning * of the processing of the connection. It can be used to initialize any relevant * fields using the request and response objects. Between the end of the processing * of this event, and the beginning of the processing of the end or error events, * it is possible to use the response object to write data on the open connection. * Note that the response object and dependent OutputStream and Writer are still * not synchronized, so when they are accessed by multiple threads, * synchronization is mandatory. After processing the initial event, the request * is considered to be committed.
    * READ - This indicates that input data is available, and that one read can be made * without blocking. The available and ready methods of the InputStream or * Reader may be used to determine if there is a risk of blocking: the servlet * should read while data is reported available. When encountering a read error, * the servlet should report it by propagating the exception properly. Throwing * an exception will cause the error event to be invoked, and the connection * will be closed. * Alternately, it is also possible to catch any exception, perform clean up * on any data structure the servlet may be using, and using the close method * of the event. It is not allowed to attempt reading data from the request * object outside of the execution of this method.
    * END - End may be called to end the processing of the request. Fields that have * been initialized in the begin method should be reset. After this event has * been processed, the request and response objects, as well as all their dependent * objects will be recycled and used to process other requests. End will also be * called when data is available and the end of file is reached on the request input * (this usually indicates the client has pipelined a request).
    * ERROR - Error will be called by the container in the case where an IO exception * or a similar unrecoverable error occurs on the connection. Fields that have * been initialized in the begin method should be reset. After this event has * been processed, the request and response objects, as well as all their dependent * objects will be recycled and used to process other requests. */ public enum EventType {BEGIN, READ, END, ERROR} /** * Event details.
    * TIMEOUT - the connection timed out (sub type of ERROR); note that this ERROR type is not fatal, and * the connection will not be closed unless the servlet uses the close method of the event
    * CLIENT_DISCONNECT - the client connection was closed (sub type of ERROR)
    * IOEXCEPTION - an IO exception occurred, such as invalid content, for example, an invalid chunk block (sub type of ERROR)
    * WEBAPP_RELOAD - the webapplication is being reloaded (sub type of END)
    * SERVER_SHUTDOWN - the server is shutting down (sub type of END)
    * SESSION_END - the servlet ended the session (sub type of END) */ public enum EventSubType { TIMEOUT, CLIENT_DISCONNECT, IOEXCEPTION, WEBAPP_RELOAD, SERVER_SHUTDOWN, SESSION_END } /** * Returns the HttpServletRequest. * * @return HttpServletRequest */ public HttpServletRequest getHttpServletRequest(); /** * Returns the HttpServletResponse. * * @return HttpServletResponse */ public HttpServletResponse getHttpServletResponse(); /** * Returns the event type. * * @return EventType */ public EventType getEventType(); /** * Returns the sub type of this event. * * @return EventSubType */ public EventSubType getEventSubType(); /** * Ends the Comet session. This signals to the container that * the container wants to end the comet session. This will send back to the * client a notice that the server has no more data to send as part of this * request. The servlet should perform any needed cleanup as if it had received * an END or ERROR event. * * @throws IOException if an IO exception occurs */ public void close() throws IOException; /** * Sets the timeout for this Comet connection. Please NOTE, that the implementation * of a per connection timeout is OPTIONAL and MAY NOT be implemented.
    * This method sets the timeout in milliseconds of idle time on the connection. * The timeout is reset every time data is received from the connection or data is flushed * using response.flushBuffer(). If a timeout occurs, the * error(HttpServletRequest, HttpServletResponse) method is invoked. The * web application SHOULD NOT attempt to reuse the request and response objects after a timeout * as the error(HttpServletRequest, HttpServletResponse) method indicates.
    * This method should not be called asynchronously, as that will have no effect. * * @param timeout The timeout in milliseconds for this connection, must be a positive value, larger than 0 * @throws IOException An IOException may be thrown to indicate an IO error, * or that the EOF has been reached on the connection * @throws ServletException An exception has occurred, as specified by the root * cause * @throws UnsupportedOperationException if per connection timeout is not supported, either at all or at this phase * of the invocation. */ public void setTimeout(int timeout) throws IOException, ServletException, UnsupportedOperationException; } tomcat7-7.0.52/java/org/apache/catalina/comet/CometProcessor.java0000644000175100017510000000316112271471332024574 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.comet; import java.io.IOException; import javax.servlet.Servlet; import javax.servlet.ServletException; /** * This interface should be implemented by servlets which would like to handle * asynchronous IO, receiving events when data is available for reading, and * being able to output data without the need for being invoked by the container. * Note: When this interface is implemented, the service method of the servlet will * never be called, and will be replaced with a begin event. */ public interface CometProcessor extends Servlet{ /** * Process the given Comet event. * * @param event The Comet event that will be processed * @throws IOException * @throws ServletException */ public void event(CometEvent event) throws IOException, ServletException; } tomcat7-7.0.52/java/org/apache/catalina/Lifecycle.java0000644000175100017510000003162412271471332022422 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * Common interface for component life cycle methods. Catalina components * may implement this interface (as well as the appropriate interface(s) for * the functionality they support) in order to provide a consistent mechanism * to start and stop the component. *
    * The valid state transitions for components that support {@link Lifecycle} * are: *

     *            start()
     *  -----------------------------
     *  |                           |
     *  | init()                    |
     * NEW ->-- INITIALIZING        |
     * | |           |              |     ------------------<-----------------------
     * | |           |auto          |     |                                        |
     * | |          \|/    start() \|/   \|/     auto          auto         stop() |
     * | |      INITIALIZED -->-- STARTING_PREP -->- STARTING -->- STARTED -->---  |
     * | |         |                                                  |         |  |
     * | |         |                                                  |         |  |
     * | |         |                                                  |         |  |
     * | |destroy()|                                                  |         |  |
     * | -->-----<--       auto                    auto               |         |  |
     * |     |       ---------<----- MUST_STOP ---------------------<--         |  |
     * |     |       |                                                          |  |
     * |    \|/      ---------------------------<--------------------------------  ^
     * |     |       |                                                             |
     * |     |      \|/            auto                 auto              start()  |
     * |     |  STOPPING_PREP ------>----- STOPPING ------>----- STOPPED ---->------
     * |     |                                ^                  |  |  ^
     * |     |               stop()           |                  |  |  |
     * |     |       --------------------------                  |  |  |
     * |     |       |                                  auto     |  |  |
     * |     |       |                  MUST_DESTROY------<-------  |  |
     * |     |       |                    |                         |  |
     * |     |       |                    |auto                     |  |
     * |     |       |    destroy()      \|/              destroy() |  |
     * |     |    FAILED ---->------ DESTROYING ---<-----------------  |
     * |     |                        ^     |                          |
     * |     |     destroy()          |     |auto                      |
     * |     -------->-----------------    \|/                         |
     * |                                 DESTROYED                     |
     * |                                                               |
     * |                            stop()                             |
     * --->------------------------------>------------------------------
     *
     * Any state can transition to FAILED.
     *
     * Calling start() while a component is in states STARTING_PREP, STARTING or
     * STARTED has no effect.
     *
     * Calling start() while a component is in state NEW will cause init() to be
     * called immediately after the start() method is entered.
     *
     * Calling stop() while a component is in states STOPPING_PREP, STOPPING or
     * STOPPED has no effect.
     *
     * Calling stop() while a component is in state NEW transitions the component
     * to STOPPED. This is typically encountered when a component fails to start and
     * does not start all its sub-components. When the component is stopped, it will
     * try to stop all sub-components - even those it didn't start.
     *
     * MUST_STOP is used to indicate that the {@link #stop()} should be called on
     * the component as soon as {@link #start()} exits. It is typically used when a
     * component has failed to start.
     *
     * MUST_DESTROY is used to indicate that the {@link #destroy()} should be called on
     * the component as soon as {@link #stop()} exits. It is typically used when a
     * component is not designed to be restarted.
     *
     * Attempting any other transition will throw {@link LifecycleException}.
     *
     * 
    * The {@link LifecycleEvent}s fired during state changes are defined in the * methods that trigger the changed. No {@link LifecycleEvent}s are fired if the * attempted transition is not valid. * * TODO: Not all components may transition from STOPPED to STARTING_PREP. These * components should use MUST_DESTROY to signal this. * * @author Craig R. McClanahan */ public interface Lifecycle { // ----------------------------------------------------- Manifest Constants /** * The LifecycleEvent type for the "component after init" event. */ public static final String BEFORE_INIT_EVENT = "before_init"; /** * The LifecycleEvent type for the "component after init" event. */ public static final String AFTER_INIT_EVENT = "after_init"; /** * The LifecycleEvent type for the "component start" event. */ public static final String START_EVENT = "start"; /** * The LifecycleEvent type for the "component before start" event. */ public static final String BEFORE_START_EVENT = "before_start"; /** * The LifecycleEvent type for the "component after start" event. */ public static final String AFTER_START_EVENT = "after_start"; /** * The LifecycleEvent type for the "component stop" event. */ public static final String STOP_EVENT = "stop"; /** * The LifecycleEvent type for the "component before stop" event. */ public static final String BEFORE_STOP_EVENT = "before_stop"; /** * The LifecycleEvent type for the "component after stop" event. */ public static final String AFTER_STOP_EVENT = "after_stop"; /** * The LifecycleEvent type for the "component after destroy" event. */ public static final String AFTER_DESTROY_EVENT = "after_destroy"; /** * The LifecycleEvent type for the "component before destroy" event. */ public static final String BEFORE_DESTROY_EVENT = "before_destroy"; /** * The LifecycleEvent type for the "periodic" event. */ public static final String PERIODIC_EVENT = "periodic"; /** * The LifecycleEvent type for the "configure_start" event. Used by those * components that use a separate component to perform configuration and * need to signal when configuration should be performed - usually after * {@link #BEFORE_START_EVENT} and before {@link #START_EVENT}. */ public static final String CONFIGURE_START_EVENT = "configure_start"; /** * The LifecycleEvent type for the "configure_stop" event. Used by those * components that use a separate component to perform configuration and * need to signal when de-configuration should be performed - usually after * {@link #STOP_EVENT} and before {@link #AFTER_STOP_EVENT}. */ public static final String CONFIGURE_STOP_EVENT = "configure_stop"; // --------------------------------------------------------- Public Methods /** * Add a LifecycleEvent listener to this component. * * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener); /** * Get the life cycle listeners associated with this life cycle. If this * component has no listeners registered, a zero-length array is returned. */ public LifecycleListener[] findLifecycleListeners(); /** * Remove a LifecycleEvent listener from this component. * * @param listener The listener to remove */ public void removeLifecycleListener(LifecycleListener listener); /** * Prepare the component for starting. This method should perform any * initialization required post object creation. The following * {@link LifecycleEvent}s will be fired in the following order: *
      *
    1. INIT_EVENT: On the successful completion of component * initialization.
    2. *
    * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void init() throws LifecycleException; /** * Prepare for the beginning of active use of the public methods other than * property getters/setters and life cycle methods of this component. This * method should be called before any of the public methods other than * property getters/setters and life cycle methods of this component are * utilized. The following {@link LifecycleEvent}s will be fired in the * following order: *
      *
    1. BEFORE_START_EVENT: At the beginning of the method. It is as this * point the state transitions to * {@link LifecycleState#STARTING_PREP}.
    2. *
    3. START_EVENT: During the method once it is safe to call start() for * any child components. It is at this point that the * state transitions to {@link LifecycleState#STARTING} * and that the public methods other than property * getters/setters and life cycle methods may be * used.
    4. *
    5. AFTER_START_EVENT: At the end of the method, immediately before it * returns. It is at this point that the state * transitions to {@link LifecycleState#STARTED}. *
    6. *
    * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void start() throws LifecycleException; /** * Gracefully terminate the active use of the public methods other than * property getters/setters and life cycle methods of this component. Once * the STOP_EVENT is fired, the public methods other than property * getters/setters and life cycle methods should not be used. The following * {@link LifecycleEvent}s will be fired in the following order: *
      *
    1. BEFORE_STOP_EVENT: At the beginning of the method. It is at this * point that the state transitions to * {@link LifecycleState#STOPPING_PREP}.
    2. *
    3. STOP_EVENT: During the method once it is safe to call stop() for * any child components. It is at this point that the * state transitions to {@link LifecycleState#STOPPING} * and that the public methods other than property * getters/setters and life cycle methods may no longer be * used.
    4. *
    5. AFTER_STOP_EVENT: At the end of the method, immediately before it * returns. It is at this point that the state * transitions to {@link LifecycleState#STOPPED}. *
    6. *
    * * Note that if transitioning from {@link LifecycleState#FAILED} then the * three events above will be fired but the component will transition * directly from {@link LifecycleState#FAILED} to * {@link LifecycleState#STOPPING}, bypassing * {@link LifecycleState#STOPPING_PREP} * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ public void stop() throws LifecycleException; /** * Prepare to discard the object. The following {@link LifecycleEvent}s will * be fired in the following order: *
      *
    1. DESTROY_EVENT: On the successful completion of component * destruction.
    2. *
    * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void destroy() throws LifecycleException; /** * Obtain the current state of the source component. * * @return The current state of the source component. */ public LifecycleState getState(); /** * Obtain a textual representation of the current component state. Useful * for JMX. */ public String getStateName(); } tomcat7-7.0.52/java/org/apache/catalina/SessionEvent.java0000644000175100017510000000456112271471332023150 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.EventObject; /** * General event for notifying listeners of significant changes on a Session. * * @author Craig R. McClanahan */ public final class SessionEvent extends EventObject { private static final long serialVersionUID = 1L; /** * The event data associated with this event. */ private Object data = null; /** * The Session on which this event occurred. */ private Session session = null; /** * The event type this instance represents. */ private String type = null; /** * Construct a new SessionEvent with the specified parameters. * * @param session Session on which this event occurred * @param type Event type * @param data Event data */ public SessionEvent(Session session, String type, Object data) { super(session); this.session = session; this.type = type; this.data = data; } /** * Return the event data of this event. */ public Object getData() { return (this.data); } /** * Return the Session on which this event occurred. */ public Session getSession() { return (this.session); } /** * Return the event type of this event. */ public String getType() { return (this.type); } /** * Return a string representation of this event. */ @Override public String toString() { return ("SessionEvent['" + getSession() + "','" + getType() + "']"); } } tomcat7-7.0.52/java/org/apache/catalina/SessionListener.java0000644000175100017510000000231712271471332023651 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.EventListener; /** * Interface defining a listener for significant Session generated events. * * @author Craig R. McClanahan */ public interface SessionListener extends EventListener { /** * Acknowledge the occurrence of the specified event. * * @param event SessionEvent that has occurred */ public void sessionEvent(SessionEvent event); } tomcat7-7.0.52/java/org/apache/catalina/InstanceEvent.java0000644000175100017510000003145212271471332023270 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.EventObject; import javax.servlet.Filter; import javax.servlet.Servlet; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * General event for notifying listeners of significant events related to * a specific instance of a Servlet, or a specific instance of a Filter, * as opposed to the Wrapper component that manages it. * * @author Craig R. McClanahan */ public final class InstanceEvent extends EventObject { private static final long serialVersionUID = 1L; /** * The event indicating that the init() method is about * to be called for this instance. */ public static final String BEFORE_INIT_EVENT = "beforeInit"; /** * The event indicating that the init() method has returned. */ public static final String AFTER_INIT_EVENT = "afterInit"; /** * The event indicating that the service() method is about * to be called on a servlet. The servlet property contains * the servlet being called, and the request and * response properties contain the current request and * response being processed. */ public static final String BEFORE_SERVICE_EVENT = "beforeService"; /** * The event indicating that the service() method has * returned. The servlet property contains the servlet * that was called, and the request and * response properties contain the current request and * response being processed. */ public static final String AFTER_SERVICE_EVENT = "afterService"; /** * The event indicating that the destroy method is about * to be called for this instance. */ public static final String BEFORE_DESTROY_EVENT = "beforeDestroy"; /** * The event indicating that the destroy() method has * returned. */ public static final String AFTER_DESTROY_EVENT = "afterDestroy"; /** * The event indicating that the service() method of a * servlet accessed via a request dispatcher is about to be called. * The servlet property contains a reference to the * dispatched-to servlet instance, and the request and * response properties contain the current request and * response being processed. The wrapper property will * contain a reference to the dispatched-to Wrapper. */ public static final String BEFORE_DISPATCH_EVENT = "beforeDispatch"; /** * The event indicating that the service() method of a * servlet accessed via a request dispatcher has returned. The * servlet property contains a reference to the * dispatched-to servlet instance, and the request and * response properties contain the current request and * response being processed. The wrapper property will * contain a reference to the dispatched-to Wrapper. */ public static final String AFTER_DISPATCH_EVENT = "afterDispatch"; /** * The event indicating that the doFilter() method of a * Filter is about to be called. The filter property * contains a reference to the relevant filter instance, and the * request and response properties contain * the current request and response being processed. */ public static final String BEFORE_FILTER_EVENT = "beforeFilter"; /** * The event indicating that the doFilter() method of a * Filter has returned. The filter property contains * a reference to the relevant filter instance, and the * request and response properties contain * the current request and response being processed. */ public static final String AFTER_FILTER_EVENT = "afterFilter"; // ----------------------------------------------------------- Constructors /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for filter lifecycle events. * * @param wrapper Wrapper managing this servlet instance * @param filter Filter instance for which this event occurred * @param type Event type (required) */ public InstanceEvent(Wrapper wrapper, Filter filter, String type) { super(wrapper); this.filter = filter; this.servlet = null; this.type = type; } /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for filter lifecycle events. * * @param wrapper Wrapper managing this servlet instance * @param filter Filter instance for which this event occurred * @param type Event type (required) * @param exception Exception that occurred */ public InstanceEvent(Wrapper wrapper, Filter filter, String type, Throwable exception) { super(wrapper); this.filter = filter; this.servlet = null; this.type = type; this.exception = exception; } /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for filter processing events. * * @param wrapper Wrapper managing this servlet instance * @param filter Filter instance for which this event occurred * @param type Event type (required) * @param request Servlet request we are processing * @param response Servlet response we are processing */ public InstanceEvent(Wrapper wrapper, Filter filter, String type, ServletRequest request, ServletResponse response) { super(wrapper); this.filter = filter; this.servlet = null; this.type = type; this.request = request; this.response = response; } /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for filter processing events. * * @param wrapper Wrapper managing this servlet instance * @param filter Filter instance for which this event occurred * @param type Event type (required) * @param request Servlet request we are processing * @param response Servlet response we are processing * @param exception Exception that occurred */ public InstanceEvent(Wrapper wrapper, Filter filter, String type, ServletRequest request, ServletResponse response, Throwable exception) { super(wrapper); this.filter = filter; this.servlet = null; this.type = type; this.request = request; this.response = response; this.exception = exception; } /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for processing servlet lifecycle events. * * @param wrapper Wrapper managing this servlet instance * @param servlet Servlet instance for which this event occurred * @param type Event type (required) */ public InstanceEvent(Wrapper wrapper, Servlet servlet, String type) { super(wrapper); this.filter = null; this.servlet = servlet; this.type = type; } /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for processing servlet lifecycle events. * * @param wrapper Wrapper managing this servlet instance * @param servlet Servlet instance for which this event occurred * @param type Event type (required) * @param exception Exception that occurred */ public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, Throwable exception) { super(wrapper); this.filter = null; this.servlet = servlet; this.type = type; this.exception = exception; } /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for processing servlet processing events. * * @param wrapper Wrapper managing this servlet instance * @param servlet Servlet instance for which this event occurred * @param type Event type (required) * @param request Servlet request we are processing * @param response Servlet response we are processing */ public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, ServletRequest request, ServletResponse response) { super(wrapper); this.filter = null; this.servlet = servlet; this.type = type; this.request = request; this.response = response; } /** * Construct a new InstanceEvent with the specified parameters. This * constructor is used for processing servlet processing events. * * @param wrapper Wrapper managing this servlet instance * @param servlet Servlet instance for which this event occurred * @param type Event type (required) * @param request Servlet request we are processing * @param response Servlet response we are processing * @param exception Exception that occurred */ public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, ServletRequest request, ServletResponse response, Throwable exception) { super(wrapper); this.filter = null; this.servlet = servlet; this.type = type; this.request = request; this.response = response; this.exception = exception; } // ----------------------------------------------------- Instance Variables /** * The exception that was thrown during the processing being reported * by this event (AFTER_INIT_EVENT, AFTER_SERVICE_EVENT, * AFTER_DESTROY_EVENT, AFTER_DISPATCH_EVENT, and AFTER_FILTER_EVENT only). */ private Throwable exception = null; /** * The Filter instance for which this event occurred (BEFORE_FILTER_EVENT * and AFTER_FILTER_EVENT only). */ private transient Filter filter = null; /** * The servlet request being processed (BEFORE_FILTER_EVENT, * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT). */ private transient ServletRequest request = null; /** * The servlet response being processed (BEFORE_FILTER_EVENT, * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT). */ private transient ServletResponse response = null; /** * The Servlet instance for which this event occurred (not present on * BEFORE_FILTER_EVENT or AFTER_FILTER_EVENT events). */ private transient Servlet servlet = null; /** * The event type this instance represents. */ private String type = null; // ------------------------------------------------------------- Properties /** * Return the exception that occurred during the processing * that was reported by this event. */ public Throwable getException() { return (this.exception); } /** * Return the filter instance for which this event occurred. */ public Filter getFilter() { return (this.filter); } /** * Return the servlet request for which this event occurred. */ public ServletRequest getRequest() { return (this.request); } /** * Return the servlet response for which this event occurred. */ public ServletResponse getResponse() { return (this.response); } /** * Return the servlet instance for which this event occurred. */ public Servlet getServlet() { return (this.servlet); } /** * Return the event type of this event. */ public String getType() { return (this.type); } /** * Return the Wrapper managing the servlet instance for which this * event occurred. */ public Wrapper getWrapper() { return (Wrapper) getSource(); } } tomcat7-7.0.52/java/org/apache/catalina/Executor.java0000644000175100017510000000330512271471332022314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.concurrent.TimeUnit; public interface Executor extends java.util.concurrent.Executor, Lifecycle { public String getName(); /** * Executes the given command at some time in the future. The command * may execute in a new thread, in a pooled thread, or in the calling * thread, at the discretion of the Executor implementation. * If no threads are available, it will be added to the work queue. * If the work queue is full, the system will wait for the specified * time until it throws a RejectedExecutionException * * @param command the runnable task * @throws java.util.concurrent.RejectedExecutionException if this task * cannot be accepted for execution - the queue is full * @throws NullPointerException if command or unit is null */ void execute(Runnable command, long timeout, TimeUnit unit); }tomcat7-7.0.52/java/org/apache/catalina/User.java0000644000175100017510000001034312271471332021434 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.security.Principal; import java.util.Iterator; /** *

    Abstract representation of a user in a {@link UserDatabase}. Each user * is optionally associated with a set of {@link Group}s through which he or * she inherits additional security roles, and is optionally assigned a set * of specific {@link Role}s.

    * * @author Craig R. McClanahan * @since 4.1 */ public interface User extends Principal { // ------------------------------------------------------------- Properties /** * Return the full name of this user. */ public String getFullName(); /** * Set the full name of this user. * * @param fullName The new full name */ public void setFullName(String fullName); /** * Return the set of {@link Group}s to which this user belongs. */ public Iterator getGroups(); /** * Return the logon password of this user, optionally prefixed with the * identifier of an encoding scheme surrounded by curly braces, such as * {md5}xxxxx. */ public String getPassword(); /** * Set the logon password of this user, optionally prefixed with the * identifier of an encoding scheme surrounded by curly braces, such as * {md5}xxxxx. * * @param password The new logon password */ public void setPassword(String password); /** * Return the set of {@link Role}s assigned specifically to this user. */ public Iterator getRoles(); /** * Return the {@link UserDatabase} within which this User is defined. */ public UserDatabase getUserDatabase(); /** * Return the logon username of this user, which must be unique * within the scope of a {@link UserDatabase}. */ public String getUsername(); /** * Set the logon username of this user, which must be unique within * the scope of a {@link UserDatabase}. * * @param username The new logon username */ public void setUsername(String username); // --------------------------------------------------------- Public Methods /** * Add a new {@link Group} to those this user belongs to. * * @param group The new group */ public void addGroup(Group group); /** * Add a {@link Role} to those assigned specifically to this user. * * @param role The new role */ public void addRole(Role role); /** * Is this user in the specified {@link Group}? * * @param group The group to check */ public boolean isInGroup(Group group); /** * Is this user specifically assigned the specified {@link Role}? This * method does NOT check for roles inherited based on * {@link Group} membership. * * @param role The role to check */ public boolean isInRole(Role role); /** * Remove a {@link Group} from those this user belongs to. * * @param group The old group */ public void removeGroup(Group group); /** * Remove all {@link Group}s from those this user belongs to. */ public void removeGroups(); /** * Remove a {@link Role} from those assigned to this user. * * @param role The old role */ public void removeRole(Role role); /** * Remove all {@link Role}s from those assigned to this user. */ public void removeRoles(); } tomcat7-7.0.52/java/org/apache/catalina/authenticator/0000755000175100017510000000000012301126370022515 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/authenticator/LocalStrings_es.properties0000644000175100017510000000710112271471332027734 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. authenticator.certificates = No hay cadena de certificados del cliente en esta petici\u00F3n authenticator.forbidden = El acceso al recurso pedido ha sido denegado authenticator.formlogin = Referencia directa al formulario de conexi\u00F3n (p\u00E1gina de formulario de login) inv\u00E1lida authenticator.invalid = No es v\u00E1lida la cadena de certificados del cliente en esta petici\u00F3n authenticator.loginFail = No pude ingresar authenticator.keystore = Excepci\u00F3n cargando el almac\u00E9n de claves authenticator.manager = Excepci\u00F3n inicializando administradores de confianza authenticator.noAuthHeader = El cliente no ha enviado autorizaci\u00F3n de cabecera authenticator.notAuthenticated = Error de Configuraci\u00F3n\: No se pueden realizar funciones de control de acceso sin un principal autenticado authenticator.notContext = Error de Configuraci\u00F3n\: Debe de estar unido a un Contexto authenticator.requestBodyTooBig = El cuerpo del requerimiento era demasiado grande para realizar cach\u00E9 durante el proceso de autenticaci\u00F3n authenticator.sessionExpired = El tiempo permitido para realizar login ha sido excedido. Si deseas continuar, debes hacer clik dos veces y volver a hacer clik otra vez o cerrar y reabrir tu navegador authenticator.unauthorized = Imposible autenticar mediante las credenciales suministradas authenticator.userDataConstraint = Esta petici\u00F3n viola una Restrici\u00F3n de Datos de usuario para esta aplicaci\u00F3n digestAuthenticator.cacheRemove = Se ha quitado una entrada v\u00E1lida de la cach\u00E9 "nonce" del cliente para hacer espacio a nuevas entradas.. Ahora es posible un ataque de reinyecci\u00F3n. Para prevenirlos, reduce "nonceValidity" o incrementa "cnonceCacheSize". El resto de mensajes de este tipo ser\u00E1n suspendidos durante 5 minutos. formAuthenticator.forwardErrorFail = Error inesperado de reenv\u00EDo a p\u00E1gina de error formAuthenticator.forwardLoginFail = Error inesperado de reenv\u00EDo a pagina de ingreso formAuthenticator.noErrorPage = No se ha definido p\u00E1gina de error para la autenticaci\u00F3n FORM en el contexto [{0}] formAuthenticator.noLoginPage = No se ha definido p\u00E1gina de ingreso para la autenticaci\u00F3n FORM en el contexto [{0}] spnegoAuthenticator.authHeaderNoToken = La cabecera de Negociaci\u00F3n de autorizaci\u00F3n enviada por el cliente no inclu\u00EDa una ficha spnegoAuthenticator.authHeaderNotNego = La cabecera de autorizaci\u00F3n enviada por el cliente no comenzaba con Negotiate spnegoAuthenticator.hostnameFail = No puedo determinar el nombre de m\u00E1quina para construir el SPN por defecto. Por favor, pon el atributo "spn" del autenticador. spnegoAuthenticator.serviceLoginFail = No puedo ingresar como director del servicio spnegoAuthenticator.ticketValidateFail = No pude validar el billete suministrado por el cliente tomcat7-7.0.52/java/org/apache/catalina/authenticator/DigestAuthenticator.java0000644000175100017510000006162412271471332027352 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.IOException; import java.io.StringReader; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.util.LinkedHashMap; import java.util.Map; import java.util.StringTokenizer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.LifecycleException; import org.apache.catalina.Realm; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.util.ConcurrentMessageDigest; import org.apache.catalina.util.MD5Encoder; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.http.parser.HttpParser; /** * An Authenticator and Valve implementation of HTTP DIGEST * Authentication (see RFC 2069). * * @author Craig R. McClanahan * @author Remy Maucherat */ public class DigestAuthenticator extends AuthenticatorBase { private static final Log log = LogFactory.getLog(DigestAuthenticator.class); // -------------------------------------------------------------- Constants /** * The MD5 helper object for this class. * * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected static final MD5Encoder md5Encoder = new MD5Encoder(); /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.authenticator.DigestAuthenticator/1.0"; /** * Tomcat's DIGEST implementation only supports auth quality of protection. */ protected static final String QOP = "auth"; // ----------------------------------------------------------- Constructors public DigestAuthenticator() { super(); setCache(false); try { if (md5Helper == null) md5Helper = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } } // ----------------------------------------------------- Instance Variables /** * MD5 message digest provider. * @deprecated Unused - will be removed in Tomcat 8.0.x onwards */ @Deprecated protected static volatile MessageDigest md5Helper; /** * List of server nonce values currently being tracked */ protected Map nonces; /** * The last timestamp used to generate a nonce. Each nonce should get a * unique timestamp. */ protected long lastTimestamp = 0; protected final Object lastTimestampLock = new Object(); /** * Maximum number of server nonces to keep in the cache. If not specified, * the default value of 1000 is used. */ protected int nonceCacheSize = 1000; /** * The window size to use to track seen nonce count values for a given * nonce. If not specified, the default of 100 is used. */ protected int nonceCountWindowSize = 100; /** * Private key. */ protected String key = null; /** * How long server nonces are valid for in milliseconds. Defaults to 5 * minutes. */ protected long nonceValidity = 5 * 60 * 1000; /** * Opaque string. */ protected String opaque; /** * Should the URI be validated as required by RFC2617? Can be disabled in * reverse proxies where the proxy has modified the URI. */ protected boolean validateUri = true; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } public int getNonceCountWindowSize() { return nonceCountWindowSize; } public void setNonceCountWindowSize(int nonceCountWindowSize) { this.nonceCountWindowSize = nonceCountWindowSize; } public int getNonceCacheSize() { return nonceCacheSize; } public void setNonceCacheSize(int nonceCacheSize) { this.nonceCacheSize = nonceCacheSize; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public long getNonceValidity() { return nonceValidity; } public void setNonceValidity(long nonceValidity) { this.nonceValidity = nonceValidity; } public String getOpaque() { return opaque; } public void setOpaque(String opaque) { this.opaque = opaque; } public boolean isValidateUri() { return validateUri; } public void setValidateUri(boolean validateUri) { this.validateUri = validateUri; } // --------------------------------------------------------- Public Methods /** * Authenticate the user making this request, based on the specified * login configuration. Return true if any specified * constraint has been satisfied, or false if we have * created a response challenge already. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication * should be performed * * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { // Have we already authenticated someone? Principal principal = request.getUserPrincipal(); //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (log.isDebugEnabled()) log.debug("Already authenticated '" + principal.getName() + "'"); // Associate the session with any existing SSO session in order // to get coordinated session invalidation at logout String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (ssoId != null) associate(ssoId, request.getSessionInternal(true)); return (true); } // NOTE: We don't try to reauthenticate using any existing SSO session, // because that will only work if the original authentication was // BASIC or FORM, which are less secure than the DIGEST auth-type // specified for this webapp // // Uncomment below to allow previous FORM or BASIC authentications // to authenticate users for this webapp // TODO make this a configurable attribute (in SingleSignOn??) /* // Is there an SSO session against which we can try to reauthenticate? if (ssoId != null) { if (log.isDebugEnabled()) log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication"); // Try to reauthenticate using data cached by SSO. If this fails, // either the original SSO logon was of DIGEST or SSL (which // we can't reauthenticate ourselves because there is no // cached username and password), or the realm denied // the user's reauthentication for some reason. // In either case we have to prompt the user for a logon if (reauthenticateFromSSO(ssoId, request)) return true; } */ // Validate any credentials already included with this request String authorization = request.getHeader("authorization"); DigestInfo digestInfo = new DigestInfo(getOpaque(), getNonceValidity(), getKey(), nonces, isValidateUri()); if (authorization != null) { if (digestInfo.parse(request, authorization)) { if (digestInfo.validate(request, config)) { principal = digestInfo.authenticate(context.getRealm()); } if (principal != null && !digestInfo.isNonceStale()) { register(request, response, principal, HttpServletRequest.DIGEST_AUTH, digestInfo.getUsername(), null); return true; } } } // Send an "unauthorized" response and an appropriate challenge // Next, generate a nonce token (that is a token which is supposed // to be unique). String nonce = generateNonce(request); setAuthenticateHeader(request, response, config, nonce, principal != null && digestInfo.isNonceStale()); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } @Override protected String getAuthMethod() { return HttpServletRequest.DIGEST_AUTH; } // ------------------------------------------------------ Protected Methods /** * Parse the username from the specified authorization string. If none * can be identified, return null * * @param authorization Authorization string to be parsed * * @deprecated Unused. Will be removed in Tomcat 8.0.x */ @Deprecated protected String parseUsername(String authorization) { // Validate the authorization credentials format if (authorization == null) return (null); if (!authorization.startsWith("Digest ")) return (null); authorization = authorization.substring(7).trim(); StringTokenizer commaTokenizer = new StringTokenizer(authorization, ","); while (commaTokenizer.hasMoreTokens()) { String currentToken = commaTokenizer.nextToken(); int equalSign = currentToken.indexOf('='); if (equalSign < 0) return null; String currentTokenName = currentToken.substring(0, equalSign).trim(); String currentTokenValue = currentToken.substring(equalSign + 1).trim(); if ("username".equals(currentTokenName)) return (removeQuotes(currentTokenValue)); } return (null); } /** * Removes the quotes on a string. RFC2617 states quotes are optional for * all parameters except realm. */ protected static String removeQuotes(String quotedString, boolean quotesRequired) { //support both quoted and non-quoted if (quotedString.length() > 0 && quotedString.charAt(0) != '"' && !quotesRequired) { return quotedString; } else if (quotedString.length() > 2) { return quotedString.substring(1, quotedString.length() - 1); } else { return ""; } } /** * Removes the quotes on a string. */ protected static String removeQuotes(String quotedString) { return removeQuotes(quotedString, false); } /** * Generate a unique token. The token is generated according to the * following pattern. NOnceToken = Base64 ( MD5 ( client-IP ":" * time-stamp ":" private-key ) ). * * @param request HTTP Servlet request */ protected String generateNonce(Request request) { long currentTime = System.currentTimeMillis(); synchronized (lastTimestampLock) { if (currentTime > lastTimestamp) { lastTimestamp = currentTime; } else { currentTime = ++lastTimestamp; } } String ipTimeKey = request.getRemoteAddr() + ":" + currentTime + ":" + getKey(); byte[] buffer = ConcurrentMessageDigest.digestMD5( ipTimeKey.getBytes(B2CConverter.ISO_8859_1)); String nonce = currentTime + ":" + MD5Encoder.encode(buffer); NonceInfo info = new NonceInfo(currentTime, getNonceCountWindowSize()); synchronized (nonces) { nonces.put(nonce, info); } return nonce; } /** * Generates the WWW-Authenticate header. *

    * The header MUST follow this template : *

         *      WWW-Authenticate    = "WWW-Authenticate" ":" "Digest"
         *                            digest-challenge
         *
         *      digest-challenge    = 1#( realm | [ domain ] | nonce |
         *                  [ digest-opaque ] |[ stale ] | [ algorithm ] )
         *
         *      realm               = "realm" "=" realm-value
         *      realm-value         = quoted-string
         *      domain              = "domain" "=" <"> 1#URI <">
         *      nonce               = "nonce" "=" nonce-value
         *      nonce-value         = quoted-string
         *      opaque              = "opaque" "=" quoted-string
         *      stale               = "stale" "=" ( "true" | "false" )
         *      algorithm           = "algorithm" "=" ( "MD5" | token )
         * 
    * * @param request HTTP Servlet request * @param response HTTP Servlet response * @param config Login configuration describing how authentication * should be performed * @param nonce nonce token */ protected void setAuthenticateHeader(HttpServletRequest request, HttpServletResponse response, LoginConfig config, String nonce, boolean isNonceStale) { // Get the realm name String realmName = config.getRealmName(); if (realmName == null) realmName = REALM_NAME; String authenticateHeader; if (isNonceStale) { authenticateHeader = "Digest realm=\"" + realmName + "\", " + "qop=\"" + QOP + "\", nonce=\"" + nonce + "\", " + "opaque=\"" + getOpaque() + "\", stale=true"; } else { authenticateHeader = "Digest realm=\"" + realmName + "\", " + "qop=\"" + QOP + "\", nonce=\"" + nonce + "\", " + "opaque=\"" + getOpaque() + "\""; } response.setHeader(AUTH_HEADER_NAME, authenticateHeader); } // ------------------------------------------------------- Lifecycle Methods @Override protected synchronized void startInternal() throws LifecycleException { super.startInternal(); // Generate a random secret key if (getKey() == null) { setKey(sessionIdGenerator.generateSessionId()); } // Generate the opaque string the same way if (getOpaque() == null) { setOpaque(sessionIdGenerator.generateSessionId()); } nonces = new LinkedHashMap() { private static final long serialVersionUID = 1L; private static final long LOG_SUPPRESS_TIME = 5 * 60 * 1000; private long lastLog = 0; @Override protected boolean removeEldestEntry( Map.Entry eldest) { // This is called from a sync so keep it simple long currentTime = System.currentTimeMillis(); if (size() > getNonceCacheSize()) { if (lastLog < currentTime && currentTime - eldest.getValue().getTimestamp() < getNonceValidity()) { // Replay attack is possible log.warn(sm.getString( "digestAuthenticator.cacheRemove")); lastLog = currentTime + LOG_SUPPRESS_TIME; } return true; } return false; } }; } private static class DigestInfo { private final String opaque; private final long nonceValidity; private final String key; private final Map nonces; private boolean validateUri = true; private String userName = null; private String method = null; private String uri = null; private String response = null; private String nonce = null; private String nc = null; private String cnonce = null; private String realmName = null; private String qop = null; private String opaqueReceived = null; private boolean nonceStale = false; public DigestInfo(String opaque, long nonceValidity, String key, Map nonces, boolean validateUri) { this.opaque = opaque; this.nonceValidity = nonceValidity; this.key = key; this.nonces = nonces; this.validateUri = validateUri; } public String getUsername() { return userName; } public boolean parse(Request request, String authorization) { // Validate the authorization credentials format if (authorization == null) { return false; } Map directives; try { directives = HttpParser.parseAuthorizationDigest( new StringReader(authorization)); } catch (IOException e) { return false; } if (directives == null) { return false; } method = request.getMethod(); userName = directives.get("username"); realmName = directives.get("realm"); nonce = directives.get("nonce"); nc = directives.get("nc"); cnonce = directives.get("cnonce"); qop = directives.get("qop"); uri = directives.get("uri"); response = directives.get("response"); opaqueReceived = directives.get("opaque"); return true; } public boolean validate(Request request, LoginConfig config) { if ( (userName == null) || (realmName == null) || (nonce == null) || (uri == null) || (response == null) ) { return false; } // Validate the URI - should match the request line sent by client if (validateUri) { String uriQuery; String query = request.getQueryString(); if (query == null) { uriQuery = request.getRequestURI(); } else { uriQuery = request.getRequestURI() + "?" + query; } if (!uri.equals(uriQuery)) { // Some clients (older Android) use an absolute URI for // DIGEST but a relative URI in the request line. // request. 2.3.5 < fixed Android version <= 4.0.3 String host = request.getHeader("host"); String scheme = request.getScheme(); if (host != null && !uriQuery.startsWith(scheme)) { StringBuilder absolute = new StringBuilder(); absolute.append(scheme); absolute.append("://"); absolute.append(host); absolute.append(uriQuery); if (!uri.equals(absolute.toString())) { return false; } } else { return false; } } } // Validate the Realm name String lcRealm = config.getRealmName(); if (lcRealm == null) { lcRealm = REALM_NAME; } if (!lcRealm.equals(realmName)) { return false; } // Validate the opaque string if (!opaque.equals(opaqueReceived)) { return false; } // Validate nonce int i = nonce.indexOf(":"); if (i < 0 || (i + 1) == nonce.length()) { return false; } long nonceTime; try { nonceTime = Long.parseLong(nonce.substring(0, i)); } catch (NumberFormatException nfe) { return false; } String md5clientIpTimeKey = nonce.substring(i + 1); long currentTime = System.currentTimeMillis(); if ((currentTime - nonceTime) > nonceValidity) { nonceStale = true; synchronized (nonces) { nonces.remove(nonce); } } String serverIpTimeKey = request.getRemoteAddr() + ":" + nonceTime + ":" + key; byte[] buffer = ConcurrentMessageDigest.digestMD5( serverIpTimeKey.getBytes(B2CConverter.ISO_8859_1)); String md5ServerIpTimeKey = MD5Encoder.encode(buffer); if (!md5ServerIpTimeKey.equals(md5clientIpTimeKey)) { return false; } // Validate qop if (qop != null && !QOP.equals(qop)) { return false; } // Validate cnonce and nc // Check if presence of nc and Cnonce is consistent with presence of qop if (qop == null) { if (cnonce != null || nc != null) { return false; } } else { if (cnonce == null || nc == null) { return false; } // RFC 2617 says nc must be 8 digits long. Older Android clients // use 6. 2.3.5 < fixed Android version <= 4.0.3 if (nc.length() < 6 || nc.length() > 8) { return false; } long count; try { count = Long.parseLong(nc, 16); } catch (NumberFormatException nfe) { return false; } NonceInfo info; synchronized (nonces) { info = nonces.get(nonce); } if (info == null) { // Nonce is valid but not in cache. It must have dropped out // of the cache - force a re-authentication nonceStale = true; } else { if (!info.nonceCountValid(count)) { return false; } } } return true; } public boolean isNonceStale() { return nonceStale; } public Principal authenticate(Realm realm) { // Second MD5 digest used to calculate the digest : // MD5(Method + ":" + uri) String a2 = method + ":" + uri; byte[] buffer = ConcurrentMessageDigest.digestMD5( a2.getBytes(B2CConverter.ISO_8859_1)); String md5a2 = MD5Encoder.encode(buffer); return realm.authenticate(userName, response, nonce, nc, cnonce, qop, realmName, md5a2); } } private static class NonceInfo { private volatile long timestamp; private volatile boolean seen[]; private volatile int offset; private volatile int count = 0; public NonceInfo(long currentTime, int seenWindowSize) { this.timestamp = currentTime; seen = new boolean[seenWindowSize]; offset = seenWindowSize / 2; } public synchronized boolean nonceCountValid(long nonceCount) { if ((count - offset) >= nonceCount || (nonceCount > count - offset + seen.length)) { return false; } int checkIndex = (int) ((nonceCount + offset) % seen.length); if (seen[checkIndex]) { return false; } else { seen[checkIndex] = true; seen[count % seen.length] = false; count++; return true; } } public long getTimestamp() { return timestamp; } } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/package.html0000644000175100017510000000457712271471332025022 0ustar locutuslocutus

    This package contains Authenticator implementations for the various supported authentication methods (BASIC, DIGEST, and FORM). In addition, there is a convenience base class, AuthenticatorBase, for customized Authenticator implementations.

    If you are using the standard context configuration class (org.apache.catalina.startup.ContextConfig) to configure the Authenticator associated with a particular context, you can register the Java class to be used for each possible authentication method by modifying the following Properties file:

        src/share/org/apache/catalina/startup/Authenticators.properties
    

    Each of the standard implementations extends a common base class (AuthenticatorBase), which is configured by setting the following JavaBeans properties (with default values in square brackets):

    • cache - Should we cache authenticated Principals (thus avoiding per-request lookups in our underyling Realm) if this request is part of an HTTP session? [true]
    • debug - Debugging detail level for this component. [0]

    The standard authentication methods that are currently provided include:

    • BasicAuthenticator - Implements HTTP BASIC authentication, as described in RFC 2617.
    • DigestAuthenticator - Implements HTTP DIGEST authentication, as described in RFC 2617.
    • FormAuthenticator - Implements FORM-BASED authentication, as described in the Servlet API Specification, version 2.2.
    tomcat7-7.0.52/java/org/apache/catalina/authenticator/SingleSignOnEntry.java0000644000175100017510000001435612271471332026761 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.security.Principal; import javax.servlet.http.HttpServletRequest; import org.apache.catalina.Session; /** * A class that represents entries in the cache of authenticated users. * This is necessary to make it available to * AuthenticatorBase subclasses that need it in order to perform * reauthentications when SingleSignOn is in use. * * @author B Stansberry, based on work by Craig R. McClanahan * * @see SingleSignOn * @see AuthenticatorBase#reauthenticateFromSSO */ public class SingleSignOnEntry { // ------------------------------------------------------ Instance Fields protected String authType = null; protected String password = null; protected Principal principal = null; protected Session sessions[] = new Session[0]; protected String username = null; protected boolean canReauthenticate = false; // --------------------------------------------------------- Constructors /** * Creates a new SingleSignOnEntry * * @param principal the Principal returned by the latest * call to Realm.authenticate. * @param authType the type of authenticator used (BASIC, CLIENT_CERT, * DIGEST or FORM) * @param username the username (if any) used for the authentication * @param password the password (if any) used for the authentication */ public SingleSignOnEntry(Principal principal, String authType, String username, String password) { updateCredentials(principal, authType, username, password); } // ------------------------------------------------------- Package Methods /** * Adds a Session to the list of those associated with * this SSO. * * @param sso The SingleSignOn valve that is managing * the SSO session. * @param session The Session being associated with the SSO. */ public synchronized void addSession(SingleSignOn sso, Session session) { for (int i = 0; i < sessions.length; i++) { if (session == sessions[i]) return; } Session results[] = new Session[sessions.length + 1]; System.arraycopy(sessions, 0, results, 0, sessions.length); results[sessions.length] = session; sessions = results; session.addSessionListener(sso); } /** * Removes the given Session from the list of those * associated with this SSO. * * @param session the Session to remove. */ public synchronized void removeSession(Session session) { Session[] nsessions = new Session[sessions.length - 1]; for (int i = 0, j = 0; i < sessions.length; i++) { if (session == sessions[i]) continue; nsessions[j++] = sessions[i]; } sessions = nsessions; } /** * Returns the Sessions associated with this SSO. */ public synchronized Session[] findSessions() { return (this.sessions); } /** * Gets the name of the authentication type originally used to authenticate * the user associated with the SSO. * * @return "BASIC", "CLIENT_CERT", "DIGEST", "FORM" or "NONE" */ public String getAuthType() { return (this.authType); } /** * Gets whether the authentication type associated with the original * authentication supports reauthentication. * * @return true if getAuthType returns * "BASIC" or "FORM", false otherwise. */ public boolean getCanReauthenticate() { return (this.canReauthenticate); } /** * Gets the password credential (if any) associated with the SSO. * * @return the password credential associated with the SSO, or * null if the original authentication type * does not involve a password. */ public String getPassword() { return (this.password); } /** * Gets the Principal that has been authenticated by * the SSO. */ public Principal getPrincipal() { return (this.principal); } /** * Gets the username provided by the user as part of the authentication * process. */ public String getUsername() { return (this.username); } /** * Updates the SingleSignOnEntry to reflect the latest security * information associated with the caller. * * @param principal the Principal returned by the latest * call to Realm.authenticate. * @param authType the type of authenticator used (BASIC, CLIENT_CERT, * DIGEST or FORM) * @param username the username (if any) used for the authentication * @param password the password (if any) used for the authentication */ public void updateCredentials(Principal principal, String authType, String username, String password) { this.principal = principal; this.authType = authType; this.username = username; this.password = password; this.canReauthenticate = (HttpServletRequest.BASIC_AUTH.equals(authType) || HttpServletRequest.FORM_AUTH.equals(authType)); } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/SingleSignOn.java0000644000175100017510000005310412271471332025731 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.IOException; import java.security.Principal; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.SessionEvent; import org.apache.catalina.SessionListener; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.valves.ValveBase; import org.apache.tomcat.util.res.StringManager; /** * A Valve that supports a "single sign on" user experience, * where the security identity of a user who successfully authenticates to one * web application is propagated to other web applications in the same * security domain. For successful use, the following requirements must * be met: *
      *
    • This Valve must be configured on the Container that represents a * virtual host (typically an implementation of Host).
    • *
    • The Realm that contains the shared user and role * information must be configured on the same Container (or a higher * one), and not overridden at the web application level.
    • *
    • The web applications themselves must use one of the standard * Authenticators found in the * org.apache.catalina.authenticator package.
    • *
    * * @author Craig R. McClanahan */ public class SingleSignOn extends ValveBase implements SessionListener { //------------------------------------------------------ Constructor public SingleSignOn() { super(true); } // ----------------------------------------------------- Instance Variables /** * The cache of SingleSignOnEntry instances for authenticated Principals, * keyed by the cookie value that is used to select them. */ protected Map cache = new HashMap(); /** * Descriptive information about this Valve implementation. */ protected static final String info = "org.apache.catalina.authenticator.SingleSignOn"; /** * Indicates whether this valve should require a downstream Authenticator to * reauthenticate each request, or if it itself can bind a UserPrincipal * and AuthType object to the request. */ private boolean requireReauthentication = false; /** * The cache of single sign on identifiers, keyed by the Session that is * associated with them. */ protected Map reverse = new HashMap(); /** * The string manager for this package. */ @Deprecated protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Optional SSO cookie domain. */ private String cookieDomain; // ------------------------------------------------------------- Properties /** * Returns the optional cookie domain. * May return null. * * @return The cookie domain */ public String getCookieDomain() { return cookieDomain; } /** * Sets the domain to be used for sso cookies. * * @param cookieDomain cookie domain name */ public void setCookieDomain(String cookieDomain) { if (cookieDomain != null && cookieDomain.trim().length() == 0) { this.cookieDomain = null; } else { this.cookieDomain = cookieDomain; } } /** * Gets whether each request needs to be reauthenticated (by an * Authenticator downstream in the pipeline) to the security * Realm, or if this Valve can itself bind security info * to the request based on the presence of a valid SSO entry without * rechecking with the Realmtrue if it is required that a downstream * Authenticator reauthenticate each request before calls to * HttpServletRequest.setUserPrincipal() * and HttpServletRequest.setAuthType() are made; * false if the Valve can itself make * those calls relying on the presence of a valid SingleSignOn * entry associated with the request. * * @see #setRequireReauthentication */ public boolean getRequireReauthentication() { return requireReauthentication; } /** * Sets whether each request needs to be reauthenticated (by an * Authenticator downstream in the pipeline) to the security * Realm, or if this Valve can itself bind security info * to the request, based on the presence of a valid SSO entry, without * rechecking with the Realm * If this property is false (the default), this * Valve will bind a UserPrincipal and AuthType to the request * if a valid SSO entry is associated with the request. It will not notify * the security Realm of the incoming request. *

    * This property should be set to true if the overall server * configuration requires that the Realm reauthenticate each * request thread. An example of such a configuration would be one where * the Realm implementation provides security for both a * web tier and an associated EJB tier, and needs to set security * credentials on each request thread in order to support EJB access. *

    * If this property is set to true, this Valve will set flags * on the request notifying the downstream Authenticator that the request * is associated with an SSO session. The Authenticator will then call its * {@link AuthenticatorBase#reauthenticateFromSSO reauthenticateFromSSO} * method to attempt to reauthenticate the request to the * Realm, using any credentials that were cached with this * Valve. *

    * The default value of this property is false, in order * to maintain backward compatibility with previous versions of Tomcat. * * @param required true if it is required that a downstream * Authenticator reauthenticate each request before calls * to HttpServletRequest.setUserPrincipal() * and HttpServletRequest.setAuthType() are * made; false if the Valve can * itself make those calls relying on the presence of a * valid SingleSignOn entry associated with the request. * * @see AuthenticatorBase#reauthenticateFromSSO */ public void setRequireReauthentication(boolean required) { this.requireReauthentication = required; } // ------------------------------------------------ SessionListener Methods /** * Acknowledge the occurrence of the specified event. * * @param event SessionEvent that has occurred */ @Override public void sessionEvent(SessionEvent event) { if (!getState().isAvailable()) { return; } // We only care about session destroyed events if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType()) && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) return; // Look up the single session id associated with this session (if any) Session session = event.getSession(); if (containerLog.isDebugEnabled()) containerLog.debug("Process session destroyed on " + session); String ssoId = null; synchronized (reverse) { ssoId = reverse.get(session); } if (ssoId == null) return; // Was the session destroyed as the result of a timeout? // If so, we'll just remove the expired session from the // SSO. If the session was logged out, we'll log out // of all session associated with the SSO. if (((session.getMaxInactiveInterval() > 0) && (System.currentTimeMillis() - session.getThisAccessedTimeInternal() >= session.getMaxInactiveInterval() * 1000)) || (Session.SESSION_PASSIVATED_EVENT.equals(event.getType())) || (!session.getManager().getContainer().getState().isAvailable())) { removeSession(ssoId, session); } else { // The session was logged out. // Deregister this single session id, invalidating // associated sessions deregister(ssoId); } } // ---------------------------------------------------------- Valve Methods /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Perform single-sign-on support processing for this request. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { request.removeNote(Constants.REQ_SSOID_NOTE); // Has a valid user already been authenticated? if (containerLog.isDebugEnabled()) containerLog.debug("Process request for '" + request.getRequestURI() + "'"); if (request.getUserPrincipal() != null) { if (containerLog.isDebugEnabled()) containerLog.debug(" Principal '" + request.getUserPrincipal().getName() + "' has already been authenticated"); getNext().invoke(request, response); return; } // Check for the single sign on cookie if (containerLog.isDebugEnabled()) containerLog.debug(" Checking for SSO cookie"); Cookie cookie = null; Cookie cookies[] = request.getCookies(); if (cookies == null) cookies = new Cookie[0]; for (int i = 0; i < cookies.length; i++) { if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) { cookie = cookies[i]; break; } } if (cookie == null) { if (containerLog.isDebugEnabled()) containerLog.debug(" SSO cookie is not present"); getNext().invoke(request, response); return; } // Look up the cached Principal associated with this cookie value if (containerLog.isDebugEnabled()) containerLog.debug(" Checking for cached principal for " + cookie.getValue()); SingleSignOnEntry entry = lookup(cookie.getValue()); if (entry != null) { if (containerLog.isDebugEnabled()) containerLog.debug(" Found cached principal '" + (entry.getPrincipal() != null ? entry.getPrincipal().getName() : "") + "' with auth type '" + entry.getAuthType() + "'"); request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue()); // Only set security elements if reauthentication is not required if (!getRequireReauthentication()) { request.setAuthType(entry.getAuthType()); request.setUserPrincipal(entry.getPrincipal()); } } else { if (containerLog.isDebugEnabled()) containerLog.debug(" No cached principal found, erasing SSO cookie"); cookie.setMaxAge(0); response.addCookie(cookie); } // Invoke the next Valve in our pipeline getNext().invoke(request, response); } // ------------------------------------------------------ Protected Methods /** * Associate the specified single sign on identifier with the * specified Session. * * @param ssoId Single sign on identifier * @param session Session to be associated */ protected void associate(String ssoId, Session session) { if (containerLog.isDebugEnabled()) containerLog.debug("Associate sso id " + ssoId + " with session " + session); SingleSignOnEntry sso = lookup(ssoId); if (sso != null) sso.addSession(this, session); synchronized (reverse) { reverse.put(session, ssoId); } } /** * Deregister the specified session. If it is the last session, * then also get rid of the single sign on identifier * * @param ssoId Single sign on identifier * @param session Session to be deregistered */ protected void deregister(String ssoId, Session session) { synchronized (reverse) { reverse.remove(session); } SingleSignOnEntry sso = lookup(ssoId); if (sso == null) return; sso.removeSession(session); // see if we are the last session, if so blow away ssoId Session sessions[] = sso.findSessions(); if (sessions == null || sessions.length == 0) { synchronized (cache) { cache.remove(ssoId); } } } /** * Deregister the specified single sign on identifier, and invalidate * any associated sessions. * * @param ssoId Single sign on identifier to deregister */ protected void deregister(String ssoId) { if (containerLog.isDebugEnabled()) containerLog.debug("Deregistering sso id '" + ssoId + "'"); // Look up and remove the corresponding SingleSignOnEntry SingleSignOnEntry sso = null; synchronized (cache) { sso = cache.remove(ssoId); } if (sso == null) return; // Expire any associated sessions Session sessions[] = sso.findSessions(); for (int i = 0; i < sessions.length; i++) { if (containerLog.isTraceEnabled()) containerLog.trace(" Invalidating session " + sessions[i]); // Remove from reverse cache first to avoid recursion synchronized (reverse) { reverse.remove(sessions[i]); } // Invalidate this session sessions[i].expire(); } // NOTE: Clients may still possess the old single sign on cookie, // but it will be removed on the next request since it is no longer // in the cache } /** * Attempts reauthentication to the given Realm using * the credentials associated with the single sign-on session * identified by argument ssoId. *

    * If reauthentication is successful, the Principal and * authorization type associated with the SSO session will be bound * to the given Request object via calls to * {@link Request#setAuthType Request.setAuthType()} and * {@link Request#setUserPrincipal Request.setUserPrincipal()} *

    * * @param ssoId identifier of SingleSignOn session with which the * caller is associated * @param realm Realm implementation against which the caller is to * be authenticated * @param request the request that needs to be authenticated * * @return true if reauthentication was successful, * false otherwise. */ protected boolean reauthenticate(String ssoId, Realm realm, Request request) { if (ssoId == null || realm == null) return false; boolean reauthenticated = false; SingleSignOnEntry entry = lookup(ssoId); if (entry != null && entry.getCanReauthenticate()) { String username = entry.getUsername(); if (username != null) { Principal reauthPrincipal = realm.authenticate(username, entry.getPassword()); if (reauthPrincipal != null) { reauthenticated = true; // Bind the authorization credentials to the request request.setAuthType(entry.getAuthType()); request.setUserPrincipal(reauthPrincipal); } } } return reauthenticated; } /** * Register the specified Principal as being associated with the specified * value for the single sign on identifier. * * @param ssoId Single sign on identifier to register * @param principal Associated user principal that is identified * @param authType Authentication type used to authenticate this * user principal * @param username Username used to authenticate this user * @param password Password used to authenticate this user */ protected void register(String ssoId, Principal principal, String authType, String username, String password) { if (containerLog.isDebugEnabled()) containerLog.debug("Registering sso id '" + ssoId + "' for user '" + (principal != null ? principal.getName() : "") + "' with auth type '" + authType + "'"); synchronized (cache) { cache.put(ssoId, new SingleSignOnEntry(principal, authType, username, password)); } } /** * Updates any SingleSignOnEntry found under key * ssoId with the given authentication data. *

    * The purpose of this method is to allow an SSO entry that was * established without a username/password combination (i.e. established * following DIGEST or CLIENT_CERT authentication) to be updated with * a username and password if one becomes available through a subsequent * BASIC or FORM authentication. The SSO entry will then be usable for * reauthentication. *

    * NOTE: Only updates the SSO entry if a call to * SingleSignOnEntry.getCanReauthenticate() returns * false; otherwise, it is assumed that the SSO entry already * has sufficient information to allow reauthentication and that no update * is needed. * * @param ssoId identifier of Single sign to be updated * @param principal the Principal returned by the latest * call to Realm.authenticate. * @param authType the type of authenticator used (BASIC, CLIENT_CERT, * DIGEST or FORM) * @param username the username (if any) used for the authentication * @param password the password (if any) used for the authentication */ protected void update(String ssoId, Principal principal, String authType, String username, String password) { SingleSignOnEntry sso = lookup(ssoId); if (sso != null && !sso.getCanReauthenticate()) { if (containerLog.isDebugEnabled()) containerLog.debug("Update sso id " + ssoId + " to auth type " + authType); synchronized(sso) { sso.updateCredentials(principal, authType, username, password); } } } /** * Look up and return the cached SingleSignOn entry associated with this * sso id value, if there is one; otherwise return null. * * @param ssoId Single sign on identifier to look up */ protected SingleSignOnEntry lookup(String ssoId) { synchronized (cache) { return cache.get(ssoId); } } /** * Remove a single Session from a SingleSignOn. Called when * a session is timed out and no longer active. * * @param ssoId Single sign on identifier from which to remove the session. * @param session the session to be removed. */ protected void removeSession(String ssoId, Session session) { if (containerLog.isDebugEnabled()) containerLog.debug("Removing session " + session.toString() + " from sso id " + ssoId ); // Get a reference to the SingleSignOn SingleSignOnEntry entry = lookup(ssoId); if (entry == null) return; // Remove the inactive session from SingleSignOnEntry entry.removeSession(session); // Remove the inactive session from the 'reverse' Map. synchronized(reverse) { reverse.remove(session); } // If there are not sessions left in the SingleSignOnEntry, // deregister the entry. if (entry.findSessions().length == 0) { deregister(ssoId); } } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/SSLAuthenticator.java0000644000175100017510000001511512271471332026566 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.IOException; import java.security.Principal; import java.security.cert.X509Certificate; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; import org.apache.coyote.ActionCode; /** * An Authenticator and Valve implementation of authentication * that utilizes SSL certificates to identify client users. * * @author Craig R. McClanahan */ public class SSLAuthenticator extends AuthenticatorBase { // ------------------------------------------------------------- Properties /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.authenticator.SSLAuthenticator/1.0"; /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Authenticate the user by checking for the existence of a certificate * chain, validating it against the trust manager for the connector and then * validating the user's identity against the configured Realm. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication * should be performed * * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { // Have we already authenticated someone? Principal principal = request.getUserPrincipal(); //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (containerLog.isDebugEnabled()) containerLog.debug("Already authenticated '" + principal.getName() + "'"); // Associate the session with any existing SSO session in order // to get coordinated session invalidation at logout String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (ssoId != null) associate(ssoId, request.getSessionInternal(true)); return (true); } // NOTE: We don't try to reauthenticate using any existing SSO session, // because that will only work if the original authentication was // BASIC or FORM, which are less secure than the CLIENT_CERT auth-type // specified for this webapp // // Uncomment below to allow previous FORM or BASIC authentications // to authenticate users for this webapp // TODO make this a configurable attribute (in SingleSignOn??) /* // Is there an SSO session against which we can try to reauthenticate? if (ssoId != null) { if (log.isDebugEnabled()) log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication"); // Try to reauthenticate using data cached by SSO. If this fails, // either the original SSO logon was of DIGEST or SSL (which // we can't reauthenticate ourselves because there is no // cached username and password), or the realm denied // the user's reauthentication for some reason. // In either case we have to prompt the user for a logon if (reauthenticateFromSSO(ssoId, request)) return true; } */ // Retrieve the certificate chain for this client if (containerLog.isDebugEnabled()) containerLog.debug(" Looking up certificates"); X509Certificate certs[] = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); if ((certs == null) || (certs.length < 1)) { try { request.getCoyoteRequest().action (ActionCode.REQ_SSL_CERTIFICATE, null); } catch (IllegalStateException ise) { // Request body was too large for save buffer response.sendError(HttpServletResponse.SC_UNAUTHORIZED, sm.getString("authenticator.certificates")); return false; } certs = (X509Certificate[]) request.getAttribute(Globals.CERTIFICATES_ATTR); } if ((certs == null) || (certs.length < 1)) { if (containerLog.isDebugEnabled()) containerLog.debug(" No certificates included with this request"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, sm.getString("authenticator.certificates")); return (false); } // Authenticate the specified certificate chain principal = context.getRealm().authenticate(certs); if (principal == null) { if (containerLog.isDebugEnabled()) containerLog.debug(" Realm.authenticate() returned false"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, sm.getString("authenticator.unauthorized")); return (false); } // Cache the principal (if requested) and record this authentication register(request, response, principal, HttpServletRequest.CLIENT_CERT_AUTH, null, null); return (true); } @Override protected String getAuthMethod() { return HttpServletRequest.CLIENT_CERT_AUTH; } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/FormAuthenticator.java0000644000175100017510000006317712271471332027043 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.IOException; import java.io.InputStream; import java.security.Principal; import java.util.Enumeration; import java.util.Iterator; import java.util.Locale; import javax.servlet.RequestDispatcher; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; import org.apache.coyote.ActionCode; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.MimeHeaders; /** * An Authenticator and Valve implementation of FORM BASED * Authentication, as described in the Servlet API Specification, Version 2.2. * * @author Craig R. McClanahan * @author Remy Maucherat */ public class FormAuthenticator extends AuthenticatorBase { private static final Log log = LogFactory.getLog(FormAuthenticator.class); // ----------------------------------------------------- Instance Variables /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.authenticator.FormAuthenticator/1.0"; /** * Character encoding to use to read the username and password parameters * from the request. If not set, the encoding of the request body will be * used. */ protected String characterEncoding = null; /** * Landing page to use if a user tries to access the login page directly or * if the session times out during login. If not set, error responses will * be sent instead. */ protected String landingPage = null; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Return the character encoding to use to read the username and password. */ public String getCharacterEncoding() { return characterEncoding; } /** * Set the character encoding to be used to read the username and password. */ public void setCharacterEncoding(String encoding) { characterEncoding = encoding; } /** * Return the landing page to use when FORM auth is mis-used. */ public String getLandingPage() { return landingPage; } /** * Set the landing page to use when the FORM auth is mis-used. */ public void setLandingPage(String landingPage) { this.landingPage = landingPage; } // --------------------------------------------------------- Public Methods /** * Authenticate the user making this request, based on the specified * login configuration. Return true if any specified * constraint has been satisfied, or false if we have * created a response challenge already. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication * should be performed * * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { // References to objects we will need later Session session = null; // Have we already authenticated someone? Principal principal = request.getUserPrincipal(); String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (log.isDebugEnabled()) { log.debug("Already authenticated '" + principal.getName() + "'"); } // Associate the session with any existing SSO session if (ssoId != null) { associate(ssoId, request.getSessionInternal(true)); } return (true); } // Is there an SSO session against which we can try to reauthenticate? if (ssoId != null) { if (log.isDebugEnabled()) { log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication"); } // Try to reauthenticate using data cached by SSO. If this fails, // either the original SSO logon was of DIGEST or SSL (which // we can't reauthenticate ourselves because there is no // cached username and password), or the realm denied // the user's reauthentication for some reason. // In either case we have to prompt the user for a logon */ if (reauthenticateFromSSO(ssoId, request)) { return true; } } // Have we authenticated this user before but have caching disabled? if (!cache) { session = request.getSessionInternal(true); if (log.isDebugEnabled()) { log.debug("Checking for reauthenticate in session " + session); } String username = (String) session.getNote(Constants.SESS_USERNAME_NOTE); String password = (String) session.getNote(Constants.SESS_PASSWORD_NOTE); if ((username != null) && (password != null)) { if (log.isDebugEnabled()) { log.debug("Reauthenticating username '" + username + "'"); } principal = context.getRealm().authenticate(username, password); if (principal != null) { session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); if (!matchRequest(request)) { register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password); return (true); } } if (log.isDebugEnabled()) { log.debug("Reauthentication failed, proceed normally"); } } } // Is this the re-submit of the original request URI after successful // authentication? If so, forward the *original* request instead. if (matchRequest(request)) { session = request.getSessionInternal(true); if (log.isDebugEnabled()) { log.debug("Restore request from session '" + session.getIdInternal() + "'"); } principal = (Principal) session.getNote(Constants.FORM_PRINCIPAL_NOTE); register(request, response, principal, HttpServletRequest.FORM_AUTH, (String) session.getNote(Constants.SESS_USERNAME_NOTE), (String) session.getNote(Constants.SESS_PASSWORD_NOTE)); // If we're caching principals we no longer need the username // and password in the session, so remove them if (cache) { session.removeNote(Constants.SESS_USERNAME_NOTE); session.removeNote(Constants.SESS_PASSWORD_NOTE); } if (restoreRequest(request, session)) { if (log.isDebugEnabled()) { log.debug("Proceed to restored request"); } return (true); } else { if (log.isDebugEnabled()) { log.debug("Restore of original request failed"); } response.sendError(HttpServletResponse.SC_BAD_REQUEST); return (false); } } // Acquire references to objects we will need to evaluate MessageBytes uriMB = MessageBytes.newInstance(); CharChunk uriCC = uriMB.getCharChunk(); uriCC.setLimit(-1); String contextPath = request.getContextPath(); String requestURI = request.getDecodedRequestURI(); // Is this the action request from the login page? boolean loginAction = requestURI.startsWith(contextPath) && requestURI.endsWith(Constants.FORM_ACTION); // No -- Save this request and redirect to the form login page if (!loginAction) { session = request.getSessionInternal(true); if (log.isDebugEnabled()) { log.debug("Save request in session '" + session.getIdInternal() + "'"); } try { saveRequest(request, session); } catch (IOException ioe) { log.debug("Request body too big to save during authentication"); response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("authenticator.requestBodyTooBig")); return (false); } forwardToLoginPage(request, response, config); return (false); } // Yes -- Acknowledge the request, validate the specified credentials // and redirect to the error page if they are not correct request.getResponse().sendAcknowledgement(); Realm realm = context.getRealm(); if (characterEncoding != null) { request.setCharacterEncoding(characterEncoding); } String username = request.getParameter(Constants.FORM_USERNAME); String password = request.getParameter(Constants.FORM_PASSWORD); if (log.isDebugEnabled()) { log.debug("Authenticating username '" + username + "'"); } principal = realm.authenticate(username, password); if (principal == null) { forwardToErrorPage(request, response, config); return (false); } if (log.isDebugEnabled()) { log.debug("Authentication of '" + username + "' was successful"); } if (session == null) { session = request.getSessionInternal(false); } if (session == null) { if (containerLog.isDebugEnabled()) { containerLog.debug ("User took so long to log on the session expired"); } if (landingPage == null) { response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT, sm.getString("authenticator.sessionExpired")); } else { // Make the authenticator think the user originally requested // the landing page String uri = request.getContextPath() + landingPage; SavedRequest saved = new SavedRequest(); saved.setMethod("GET"); saved.setRequestURI(uri); saved.setDecodedRequestURI(uri); request.getSessionInternal(true).setNote( Constants.FORM_REQUEST_NOTE, saved); response.sendRedirect(response.encodeRedirectURL(uri)); } return (false); } // Save the authenticated Principal in our session session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); // Save the username and password as well session.setNote(Constants.SESS_USERNAME_NOTE, username); session.setNote(Constants.SESS_PASSWORD_NOTE, password); // Redirect the user to the original request URI (which will cause // the original request to be restored) requestURI = savedRequestURL(session); if (log.isDebugEnabled()) { log.debug("Redirecting to original '" + requestURI + "'"); } if (requestURI == null) { if (landingPage == null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, sm.getString("authenticator.formlogin")); } else { // Make the authenticator think the user originally requested // the landing page String uri = request.getContextPath() + landingPage; SavedRequest saved = new SavedRequest(); saved.setMethod("GET"); saved.setRequestURI(uri); saved.setDecodedRequestURI(uri); session.setNote(Constants.FORM_REQUEST_NOTE, saved); response.sendRedirect(response.encodeRedirectURL(uri)); } } else { response.sendRedirect(response.encodeRedirectURL(requestURI)); } return (false); } @Override protected String getAuthMethod() { return HttpServletRequest.FORM_AUTH; } // ------------------------------------------------------ Protected Methods /** * Called to forward to the login page * * @param request Request we are processing * @param response Response we are populating * @param config Login configuration describing how authentication * should be performed * @throws IOException If the forward to the login page fails and the call * to {@link HttpServletResponse#sendError(int, String)} * throws an {@link IOException} */ protected void forwardToLoginPage(Request request, HttpServletResponse response, LoginConfig config) throws IOException { if (log.isDebugEnabled()) { log.debug(sm.getString("formAuthenticator.forwardLogin", request.getRequestURI(), request.getMethod(), config.getLoginPage(), context.getName())); } String loginPage = config.getLoginPage(); if (loginPage == null || loginPage.length() == 0) { String msg = sm.getString("formAuthenticator.noLoginPage", context.getName()); log.warn(msg); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg); return; } if (getChangeSessionIdOnAuthentication()) { Session session = request.getSessionInternal(false); if (session != null) { Manager manager = request.getContext().getManager(); manager.changeSessionId(session); request.changeSessionId(session.getId()); } } // Always use GET for the login page, regardless of the method used String oldMethod = request.getMethod(); request.getCoyoteRequest().method().setString("GET"); RequestDispatcher disp = context.getServletContext().getRequestDispatcher(loginPage); try { if (context.fireRequestInitEvent(request)) { disp.forward(request.getRequest(), response); context.fireRequestDestroyEvent(request); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); String msg = sm.getString("formAuthenticator.forwardLoginFail"); log.warn(msg, t); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg); } finally { // Restore original method so that it is written into access log request.getCoyoteRequest().method().setString(oldMethod); } } /** * Called to forward to the error page * * @param request Request we are processing * @param response Response we are populating * @param config Login configuration describing how authentication * should be performed * @throws IOException If the forward to the error page fails and the call * to {@link HttpServletResponse#sendError(int, String)} * throws an {@link IOException} */ protected void forwardToErrorPage(Request request, HttpServletResponse response, LoginConfig config) throws IOException { String errorPage = config.getErrorPage(); if (errorPage == null || errorPage.length() == 0) { String msg = sm.getString("formAuthenticator.noErrorPage", context.getName()); log.warn(msg); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg); return; } RequestDispatcher disp = context.getServletContext().getRequestDispatcher (config.getErrorPage()); try { if (context.fireRequestInitEvent(request)) { disp.forward(request.getRequest(), response); context.fireRequestDestroyEvent(request); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); String msg = sm.getString("formAuthenticator.forwardErrorFail"); log.warn(msg, t); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg); } } /** * Does this request match the saved one (so that it must be the redirect * we signaled after successful authentication? * * @param request The request to be verified */ protected boolean matchRequest(Request request) { // Has a session been created? Session session = request.getSessionInternal(false); if (session == null) { return (false); } // Is there a saved request? SavedRequest sreq = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); if (sreq == null) { return (false); } // Is there a saved principal? if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null) { return (false); } // Does the request URI match? String decodedRequestURI = request.getDecodedRequestURI(); if (decodedRequestURI == null) { return (false); } return (decodedRequestURI.equals(sreq.getDecodedRequestURI())); } /** * Restore the original request from information stored in our session. * If the original request is no longer present (because the session * timed out), return false; otherwise, return * true. * * @param request The request to be restored * @param session The session containing the saved information */ protected boolean restoreRequest(Request request, Session session) throws IOException { // Retrieve and remove the SavedRequest object from our session SavedRequest saved = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); session.removeNote(Constants.FORM_REQUEST_NOTE); session.removeNote(Constants.FORM_PRINCIPAL_NOTE); if (saved == null) { return (false); } // Swallow any request body since we will be replacing it // Need to do this before headers are restored as AJP connector uses // content length header to determine how much data needs to be read for // request body byte[] buffer = new byte[4096]; InputStream is = request.createInputStream(); while (is.read(buffer) >= 0) { // Ignore request body } // Modify our current request to reflect the original one request.clearCookies(); Iterator cookies = saved.getCookies(); while (cookies.hasNext()) { request.addCookie(cookies.next()); } String method = saved.getMethod(); MimeHeaders rmh = request.getCoyoteRequest().getMimeHeaders(); rmh.recycle(); boolean cachable = "GET".equalsIgnoreCase(method) || "HEAD".equalsIgnoreCase(method); Iterator names = saved.getHeaderNames(); while (names.hasNext()) { String name = names.next(); // The browser isn't expecting this conditional response now. // Assuming that it can quietly recover from an unexpected 412. // BZ 43687 if(!("If-Modified-Since".equalsIgnoreCase(name) || (cachable && "If-None-Match".equalsIgnoreCase(name)))) { Iterator values = saved.getHeaderValues(name); while (values.hasNext()) { rmh.addValue(name).setString(values.next()); } } } request.clearLocales(); Iterator locales = saved.getLocales(); while (locales.hasNext()) { request.addLocale(locales.next()); } request.getCoyoteRequest().getParameters().recycle(); request.getCoyoteRequest().getParameters().setQueryStringEncoding( request.getConnector().getURIEncoding()); ByteChunk body = saved.getBody(); if (body != null) { request.getCoyoteRequest().action (ActionCode.REQ_SET_BODY_REPLAY, body); // Set content type MessageBytes contentType = MessageBytes.newInstance(); // If no content type specified, use default for POST String savedContentType = saved.getContentType(); if (savedContentType == null && "POST".equalsIgnoreCase(method)) { savedContentType = "application/x-www-form-urlencoded"; } contentType.setString(savedContentType); request.getCoyoteRequest().setContentType(contentType); } request.getCoyoteRequest().method().setString(method); request.getCoyoteRequest().queryString().setString (saved.getQueryString()); request.getCoyoteRequest().requestURI().setString (saved.getRequestURI()); return (true); } /** * Save the original request information into our session. * * @param request The request to be saved * @param session The session to contain the saved information * @throws IOException */ protected void saveRequest(Request request, Session session) throws IOException { // Create and populate a SavedRequest object for this request SavedRequest saved = new SavedRequest(); Cookie cookies[] = request.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) { saved.addCookie(cookies[i]); } } Enumeration names = request.getHeaderNames(); while (names.hasMoreElements()) { String name = names.nextElement(); Enumeration values = request.getHeaders(name); while (values.hasMoreElements()) { String value = values.nextElement(); saved.addHeader(name, value); } } Enumeration locales = request.getLocales(); while (locales.hasMoreElements()) { Locale locale = locales.nextElement(); saved.addLocale(locale); } // May need to acknowledge a 100-continue expectation request.getResponse().sendAcknowledgement(); ByteChunk body = new ByteChunk(); body.setLimit(request.getConnector().getMaxSavePostSize()); byte[] buffer = new byte[4096]; int bytesRead; InputStream is = request.getInputStream(); while ( (bytesRead = is.read(buffer) ) >= 0) { body.append(buffer, 0, bytesRead); } // Only save the request body if there is something to save if (body.getLength() > 0) { saved.setContentType(request.getContentType()); saved.setBody(body); } saved.setMethod(request.getMethod()); saved.setQueryString(request.getQueryString()); saved.setRequestURI(request.getRequestURI()); saved.setDecodedRequestURI(request.getDecodedRequestURI()); // Stash the SavedRequest in our session for later use session.setNote(Constants.FORM_REQUEST_NOTE, saved); } /** * Return the request URI (with the corresponding query string, if any) * from the saved request so that we can redirect to it. * * @param session Our current session */ protected String savedRequestURL(Session session) { SavedRequest saved = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); if (saved == null) { return (null); } StringBuilder sb = new StringBuilder(saved.getRequestURI()); if (saved.getQueryString() != null) { sb.append('?'); sb.append(saved.getQueryString()); } return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java0000644000175100017510000001442112271471332027647 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.IOException; import java.security.Principal; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Session; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; /** * An Authenticator and Valve implementation that checks * only security constraints not involving user authentication. * * @author Craig R. McClanahan */ public final class NonLoginAuthenticator extends AuthenticatorBase { // ----------------------------------------------------- Instance Variables /** * Descriptive information about this implementation. */ private static final String info = "org.apache.catalina.authenticator.NonLoginAuthenticator/1.0"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** *

    Authenticate the user making this request, based on the fact that no * login-config has been defined for the container.

    * *

    This implementation means "login the user even though there is no * self-contained way to establish a security Principal for that user".

    * *

    This method is called by the AuthenticatorBase super class to * establish a Principal for the user BEFORE the container security * constraints are examined, i.e. it is not yet known whether the user * will eventually be permitted to access the requested resource. * Therefore, it is necessary to always return true to * indicate the user has not failed authentication.

    * *

    There are two cases: *

      *
    • without SingleSignon: a Session instance does not yet exist * and there is no auth-method to authenticate the * user, so leave Request's Principal as null. * Note: AuthenticatorBase will later examine the security constraints * to determine whether the resource is accessible by a user * without a security Principal and Role (i.e. unauthenticated). *
    • *
    • with SingleSignon: if the user has already authenticated via * another container (using its own login configuration), then * associate this Session with the SSOEntry so it inherits the * already-established security Principal and associated Roles. * Note: This particular session will become a full member of the * SingleSignOnEntry Session collection and so will potentially * keep the SSOE "alive", even if all the other properly * authenticated Sessions expire first... until it expires too. *
    • *

    * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication * should be performed * @return boolean to indicate whether the user is authenticated * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { Principal principal = request.getPrincipal(); if (principal != null) { // excellent... we have already authenticated the client somehow, // probably from another container that has a login-config if (containerLog.isDebugEnabled()) containerLog.debug("Already authenticated as '" + principal.getName() + "'"); if (cache) { // create a new session (only if necessary) Session session = request.getSessionInternal(true); // save the inherited Principal (if necessary) in this // session so it can remain authenticated until it expires session.setPrincipal(principal); // is there an SSO session cookie? String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (ssoId != null) { if (containerLog.isDebugEnabled()) containerLog.debug("User authenticated by existing SSO"); // Associate session with the existing SSO ID if necessary associate(ssoId, session); } } // user was already authenticated, with or without a cookie return true; } // No Principal means the user is not already authenticated // and so will not be assigned any roles. It is safe to // to say the user is now authenticated because access to // protected resources will only be allowed with a matching role. // i.e. SC_FORBIDDEN (403 status) will be generated later. if (containerLog.isDebugEnabled()) containerLog.debug("User authenticated without any roles"); return true; } /** * Return the authentication method, which is vendor-specific and * not defined by HttpServletRequest. */ @Override protected String getAuthMethod() { return "NONE"; } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/mbeans-descriptors.xml0000644000175100017510000003053612271471332027061 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/authenticator/Constants.java0000644000175100017510000001053712271471332025351 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; public class Constants { public static final String Package = "org.apache.catalina.authenticator"; // Authentication methods for login configuration // Servlet spec schemes /** * @deprecated Replaced by HttpServletRequest.BASIC_AUTH */ @Deprecated public static final String BASIC_METHOD = "BASIC"; /** * @deprecated Replaced by HttpServletRequest.CLIENT_CERT_AUTH */ @Deprecated public static final String CERT_METHOD = "CLIENT_CERT"; /** * @deprecated Replaced by HttpServletRequest.DIGEST_AUTH */ @Deprecated public static final String DIGEST_METHOD = "DIGEST"; /** * @deprecated Replaced by HttpServletRequest.FORM_AUTH */ @Deprecated public static final String FORM_METHOD = "FORM"; // Vendor specific schemes public static final String SPNEGO_METHOD = "SPNEGO"; // Form based authentication constants public static final String FORM_ACTION = "/j_security_check"; public static final String FORM_PASSWORD = "j_password"; public static final String FORM_USERNAME = "j_username"; // SPNEGO authentication constants public static final String KRB5_CONF_PROPERTY = "java.security.krb5.conf"; public static final String DEFAULT_KRB5_CONF = "conf/krb5.ini"; public static final String JAAS_CONF_PROPERTY = "java.security.auth.login.config"; public static final String DEFAULT_JAAS_CONF = "conf/jaas.conf"; public static final String DEFAULT_LOGIN_MODULE_NAME = "com.sun.security.jgss.krb5.accept"; public static final String USE_SUBJECT_CREDS_ONLY_PROPERTY = "javax.security.auth.useSubjectCredsOnly"; // Cookie name for single sign on support public static final String SINGLE_SIGN_ON_COOKIE = System.getProperty( "org.apache.catalina.authenticator.Constants.SSO_SESSION_COOKIE_NAME", "JSESSIONIDSSO"); // --------------------------------------------------------- Request Notes /** * The notes key to track the single-sign-on identity with which this * request is associated. */ public static final String REQ_SSOID_NOTE = "org.apache.catalina.request.SSOID"; // ---------------------------------------------------------- Session Notes /** * If the cache property of our authenticator is set, and * the current request is part of a session, authentication information * will be cached to avoid the need for repeated calls to * Realm.authenticate(), under the following keys: */ /** * The notes key for the password used to authenticate this user. */ public static final String SESS_PASSWORD_NOTE = "org.apache.catalina.session.PASSWORD"; /** * The notes key for the username used to authenticate this user. */ public static final String SESS_USERNAME_NOTE = "org.apache.catalina.session.USERNAME"; /** * The following note keys are used during form login processing to * cache required information prior to the completion of authentication. */ /** * The previously authenticated principal (if caching is disabled). */ public static final String FORM_PRINCIPAL_NOTE = "org.apache.catalina.authenticator.PRINCIPAL"; /** * The original request information, to which the user will be * redirected if authentication succeeds. */ public static final String FORM_REQUEST_NOTE = "org.apache.catalina.authenticator.REQUEST"; } tomcat7-7.0.52/java/org/apache/catalina/authenticator/LocalStrings.properties0000644000175100017510000000636212271471332027255 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. authenticator.certificates=No client certificate chain in this request authenticator.forbidden=Access to the requested resource has been denied authenticator.formlogin=Invalid direct reference to form login page authenticator.invalid=Invalid client certificate chain in this request authenticator.loginFail=Login failed authenticator.keystore=Exception loading key store authenticator.manager=Exception initializing trust managers authenticator.noAuthHeader=No authorization header sent by client authenticator.notAuthenticated=Configuration error: Cannot perform access control without an authenticated principal authenticator.notContext=Configuration error: Must be attached to a Context authenticator.requestBodyTooBig=The request body was too large to be cached during the authentication process authenticator.sessionExpired=The time allowed for the login process has been exceeded. If you wish to continue you must either click back twice and re-click the link you requested or close and re-open your browser authenticator.unauthorized=Cannot authenticate with the provided credentials authenticator.userDataConstraint=This request violates a User Data constraint for this application digestAuthenticator.cacheRemove=A valid entry has been removed from client nonce cache to make room for new entries. A replay attack is now possible. To prevent the possibility of replay attacks, reduce nonceValidity or increase cnonceCacheSize. Further warnings of this type will be suppressed for 5 minutes. formAuthenticator.forwardErrorFail=Unexpected error forwarding to error page formAuthenticator.forwardLogin=Forwarding request for [{0}] made with method [{1}] to login page [{2}] of context [{3}] using request method GET formAuthenticator.forwardLoginFail=Unexpected error forwarding to login page formAuthenticator.noErrorPage=No error page was defined for FORM authentication in context [{0}] formAuthenticator.noLoginPage=No login page was defined for FORM authentication in context [{0}] spnegoAuthenticator.authHeaderNoToken=The Negotiate authorization header sent by the client did not include a token spnegoAuthenticator.authHeaderNotNego=The authorization header sent by the client did not start with Negotiate spnegoAuthenticator.hostnameFail=Unable to determine the host name to construct the default SPN. Please set the spn attribute of the authenticator. spnegoAuthenticator.serviceLoginFail=Unable to login as the service principal spnegoAuthenticator.ticketValidateFail=Failed to validate client supplied ticket tomcat7-7.0.52/java/org/apache/catalina/authenticator/LocalStrings_ja.properties0000644000175100017510000000564512271471332027732 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. authenticator.certificates=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u306f\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u305b\u3093 authenticator.forbidden=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f authenticator.formlogin=\u30d5\u30a9\u30fc\u30e0\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8\u3078\u306e\u7121\u52b9\u306a\u76f4\u63a5\u53c2\u7167\u3067\u3059 authenticator.invalid=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u7121\u52b9\u306a\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u3059 authenticator.keystore=\u30ad\u30fc\u30b9\u30c8\u30a2\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 authenticator.manager=\u30c8\u30e9\u30b9\u30c8\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u521d\u671f\u5316\u4e2d\u306e\u4f8b\u5916\u3067\u3059 authenticator.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u306b\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u3092\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 authenticator.notContext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 authenticator.sessionExpired=\u30ed\u30b0\u30a4\u30f3\u30d7\u30ed\u30bb\u30b9\u306b\u8a8d\u3081\u3089\u308c\u3066\u3044\u305f\u6642\u9593\u304c\u904e\u304e\u307e\u3057\u305f\u3002\u7d99\u7d9a\u3057\u305f\u3044\u306a\u3089\u3070\uff0c\u30d0\u30c3\u30af\u30dc\u30bf\u30f3\u30922\u5ea6\u62bc\u3057\u3066\u304b\u3089\u518d\u5ea6\u30ea\u30f3\u30af\u3092\u62bc\u3059\u304b\uff0c\u30d6\u30e9\u30a6\u30b6\u3092\u7acb\u3061\u4e0a\u3052\u76f4\u3057\u3066\u304f\u3060\u3055\u3044 authenticator.unauthorized=\u7528\u610f\u3055\u308c\u305f\u8a3c\u660e\u66f8\u3067\u8a8d\u8a3c\u3067\u304d\u307e\u305b\u3093 authenticator.userDataConstraint=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306f\u3001\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u306e\u5236\u9650\u306b\u9055\u53cd\u3057\u3066\u3044\u307e\u3059 tomcat7-7.0.52/java/org/apache/catalina/authenticator/AuthenticatorBase.java0000644000175100017510000007723112271471332027006 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.IOException; import java.security.Principal; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Authenticator; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.catalina.util.DateTool; import org.apache.catalina.util.SessionIdGenerator; import org.apache.catalina.valves.ValveBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Basic implementation of the Valve interface that enforces the * <security-constraint> elements in the web application * deployment descriptor. This functionality is implemented as a Valve * so that it can be omitted in environments that do not require these * features. Individual implementations of each supported authentication * method can subclass this base class as required. *

    * USAGE CONSTRAINT: When this class is utilized, the Context to * which it is attached (or a parent Container in a hierarchy) must have an * associated Realm that can be used for authenticating users and enumerating * the roles to which they have been assigned. *

    * USAGE CONSTRAINT: This Valve is only useful when processing HTTP * requests. Requests of any other type will simply be passed through. * * @author Craig R. McClanahan */ public abstract class AuthenticatorBase extends ValveBase implements Authenticator { private static final Log log = LogFactory.getLog(AuthenticatorBase.class); //------------------------------------------------------ Constructor public AuthenticatorBase() { super(true); } // ----------------------------------------------------- Instance Variables /** * Authentication header */ protected static final String AUTH_HEADER_NAME = "WWW-Authenticate"; /** * Default authentication realm name. */ protected static final String REALM_NAME = "Authentication required"; /** * Should a session always be used once a user is authenticated? This may * offer some performance benefits since the session can then be used to * cache the authenticated Principal, hence removing the need to * authenticate the user via the Realm on every request. This may be of help * for combinations such as BASIC authentication used with the JNDIRealm or * DataSourceRealms. However there will also be the performance cost of * creating and GC'ing the session. By default, a session will not be * created. */ protected boolean alwaysUseSession = false; /** * Should we cache authenticated Principals if the request is part of * an HTTP session? */ protected boolean cache = true; /** * Should the session ID, if any, be changed upon a successful * authentication to prevent a session fixation attack? */ protected boolean changeSessionIdOnAuthentication = true; /** * The Context to which this Valve is attached. */ protected Context context = null; /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.authenticator.AuthenticatorBase/1.0"; /** * Flag to determine if we disable proxy caching, or leave the issue * up to the webapp developer. */ protected boolean disableProxyCaching = true; /** * Flag to determine if we disable proxy caching with headers incompatible * with IE. */ protected boolean securePagesWithPragma = false; /** * The Java class name of the secure random number generator class to be * used when generating SSO session identifiers. The random number generator * class must be self-seeding and have a zero-argument constructor. If not * specified, an instance of {@link java.security.SecureRandom} will be * generated. */ protected String secureRandomClass = null; /** * The name of the algorithm to use to create instances of * {@link java.security.SecureRandom} which are used to generate SSO session * IDs. If no algorithm is specified, SHA1PRNG is used. To use the platform * default (which may be SHA1PRNG), specify the empty string. If an invalid * algorithm and/or provider is specified the SecureRandom instances will be * created using the defaults. If that fails, the SecureRandom instances * will be created using platform defaults. */ protected String secureRandomAlgorithm = "SHA1PRNG"; /** * The name of the provider to use to create instances of * {@link java.security.SecureRandom} which are used to generate session SSO * IDs. If no algorithm is specified the of SHA1PRNG default is used. If an * invalid algorithm and/or provider is specified the SecureRandom instances * will be created using the defaults. If that fails, the SecureRandom * instances will be created using platform defaults. */ protected String secureRandomProvider = null; protected SessionIdGenerator sessionIdGenerator = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The SingleSignOn implementation in our request processing chain, * if there is one. */ protected SingleSignOn sso = null; /** * "Expires" header always set to Date(1), so generate once only */ private static final String DATE_ONE = (new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, Locale.US)).format(new Date(1)); // ------------------------------------------------------------- Properties public boolean getAlwaysUseSession() { return alwaysUseSession; } public void setAlwaysUseSession(boolean alwaysUseSession) { this.alwaysUseSession = alwaysUseSession; } /** * Return the cache authenticated Principals flag. */ public boolean getCache() { return (this.cache); } /** * Set the cache authenticated Principals flag. * * @param cache The new cache flag */ public void setCache(boolean cache) { this.cache = cache; } /** * Return the Container to which this Valve is attached. */ @Override public Container getContainer() { return (this.context); } /** * Set the Container to which this Valve is attached. * * @param container The container to which we are attached */ @Override public void setContainer(Container container) { if (container != null && !(container instanceof Context)) throw new IllegalArgumentException (sm.getString("authenticator.notContext")); super.setContainer(container); this.context = (Context) container; } /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Return the flag that states if we add headers to disable caching by * proxies. */ public boolean getDisableProxyCaching() { return disableProxyCaching; } /** * Set the value of the flag that states if we add headers to disable * caching by proxies. * @param nocache true if we add headers to disable proxy * caching, false if we leave the headers alone. */ public void setDisableProxyCaching(boolean nocache) { disableProxyCaching = nocache; } /** * Return the flag that states, if proxy caching is disabled, what headers * we add to disable the caching. */ public boolean getSecurePagesWithPragma() { return securePagesWithPragma; } /** * Set the value of the flag that states what headers we add to disable * proxy caching. * @param securePagesWithPragma true if we add headers which * are incompatible with downloading office documents in IE under SSL but * which fix a caching problem in Mozilla. */ public void setSecurePagesWithPragma(boolean securePagesWithPragma) { this.securePagesWithPragma = securePagesWithPragma; } /** * Return the flag that states if we should change the session ID of an * existing session upon successful authentication. * * @return true to change session ID upon successful * authentication, false to do not perform the change. */ public boolean getChangeSessionIdOnAuthentication() { return changeSessionIdOnAuthentication; } /** * Set the value of the flag that states if we should change the session ID * of an existing session upon successful authentication. * * @param changeSessionIdOnAuthentication * true to change session ID upon successful * authentication, false to do not perform the * change. */ public void setChangeSessionIdOnAuthentication( boolean changeSessionIdOnAuthentication) { this.changeSessionIdOnAuthentication = changeSessionIdOnAuthentication; } /** * Return the secure random number generator class name. */ public String getSecureRandomClass() { return (this.secureRandomClass); } /** * Set the secure random number generator class name. * * @param secureRandomClass The new secure random number generator class * name */ public void setSecureRandomClass(String secureRandomClass) { this.secureRandomClass = secureRandomClass; } /** * Return the secure random number generator algorithm name. */ public String getSecureRandomAlgorithm() { return secureRandomAlgorithm; } /** * Set the secure random number generator algorithm name. * * @param secureRandomAlgorithm The new secure random number generator * algorithm name */ public void setSecureRandomAlgorithm(String secureRandomAlgorithm) { this.secureRandomAlgorithm = secureRandomAlgorithm; } /** * Return the secure random number generator provider name. */ public String getSecureRandomProvider() { return secureRandomProvider; } /** * Set the secure random number generator provider name. * * @param secureRandomProvider The new secure random number generator * provider name */ public void setSecureRandomProvider(String secureRandomProvider) { this.secureRandomProvider = secureRandomProvider; } // --------------------------------------------------------- Public Methods /** * Enforce the security restrictions in the web application deployment * descriptor of our associated Context. * * @param request Request to be processed * @param response Response to be processed * * @exception IOException if an input/output error occurs * @exception ServletException if thrown by a processing element */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { if (log.isDebugEnabled()) log.debug("Security checking request " + request.getMethod() + " " + request.getRequestURI()); LoginConfig config = this.context.getLoginConfig(); // Have we got a cached authenticated Principal to record? if (cache) { Principal principal = request.getUserPrincipal(); if (principal == null) { Session session = request.getSessionInternal(false); if (session != null) { principal = session.getPrincipal(); if (principal != null) { if (log.isDebugEnabled()) log.debug("We have cached auth type " + session.getAuthType() + " for principal " + session.getPrincipal()); request.setAuthType(session.getAuthType()); request.setUserPrincipal(principal); } } } } // Special handling for form-based logins to deal with the case // where the login form (and therefore the "j_security_check" URI // to which it submits) might be outside the secured area String contextPath = this.context.getPath(); String requestURI = request.getDecodedRequestURI(); if (requestURI.startsWith(contextPath) && requestURI.endsWith(Constants.FORM_ACTION)) { if (!authenticate(request, response, config)) { if (log.isDebugEnabled()) log.debug(" Failed authenticate() test ??" + requestURI ); return; } } // Special handling for form-based logins to deal with the case where // a resource is protected for some HTTP methods but not protected for // GET which is used after authentication when redirecting to the // protected resource. // TODO: This is similar to the FormAuthenticator.matchRequest() logic // Is there a way to remove the duplication? Session session = request.getSessionInternal(false); if (session != null) { SavedRequest savedRequest = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); if (savedRequest != null) { String decodedRequestURI = request.getDecodedRequestURI(); if (decodedRequestURI != null && decodedRequestURI.equals( savedRequest.getDecodedRequestURI())) { if (!authenticate(request, response)) { if (log.isDebugEnabled()) { log.debug(" Failed authenticate() test"); } /* * ASSERT: Authenticator already set the appropriate * HTTP status code, so we do not have to do anything * special */ return; } } } } // The Servlet may specify security constraints through annotations. // Ensure that they have been processed before constraints are checked Wrapper wrapper = (Wrapper) request.getMappingData().wrapper; if (wrapper != null) { wrapper.servletSecurityAnnotationScan(); } Realm realm = this.context.getRealm(); // Is this request URI subject to a security constraint? SecurityConstraint [] constraints = realm.findSecurityConstraints(request, this.context); if (constraints == null && !context.getPreemptiveAuthentication()) { if (log.isDebugEnabled()) log.debug(" Not subject to any constraint"); getNext().invoke(request, response); return; } // Make sure that constrained resources are not cached by web proxies // or browsers as caching can provide a security hole if (constraints != null && disableProxyCaching && !"POST".equalsIgnoreCase(request.getMethod())) { if (securePagesWithPragma) { // Note: These can cause problems with downloading files with IE response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); } else { response.setHeader("Cache-Control", "private"); } response.setHeader("Expires", DATE_ONE); } int i; if (constraints != null) { // Enforce any user data constraint for this security constraint if (log.isDebugEnabled()) { log.debug(" Calling hasUserDataPermission()"); } if (!realm.hasUserDataPermission(request, response, constraints)) { if (log.isDebugEnabled()) { log.debug(" Failed hasUserDataPermission() test"); } /* * ASSERT: Authenticator already set the appropriate * HTTP status code, so we do not have to do anything special */ return; } } // Since authenticate modifies the response on failure, // we have to check for allow-from-all first. boolean authRequired; if (constraints == null) { authRequired = false; } else { authRequired = true; for(i=0; i < constraints.length && authRequired; i++) { if(!constraints[i].getAuthConstraint()) { authRequired = false; } else if(!constraints[i].getAllRoles()) { String [] roles = constraints[i].findAuthRoles(); if(roles == null || roles.length == 0) { authRequired = false; } } } } if (!authRequired && context.getPreemptiveAuthentication()) { authRequired = request.getCoyoteRequest().getMimeHeaders().getValue( "authorization") != null; } if (!authRequired && context.getPreemptiveAuthentication()) { X509Certificate[] certs = (X509Certificate[]) request.getAttribute( Globals.CERTIFICATES_ATTR); authRequired = certs != null && certs.length > 0; } if(authRequired) { if (log.isDebugEnabled()) { log.debug(" Calling authenticate()"); } if (!authenticate(request, response, config)) { if (log.isDebugEnabled()) { log.debug(" Failed authenticate() test"); } /* * ASSERT: Authenticator already set the appropriate * HTTP status code, so we do not have to do anything * special */ return; } } if (constraints != null) { if (log.isDebugEnabled()) { log.debug(" Calling accessControl()"); } if (!realm.hasResourcePermission(request, response, constraints, this.context)) { if (log.isDebugEnabled()) { log.debug(" Failed accessControl() test"); } /* * ASSERT: AccessControl method has already set the * appropriate HTTP status code, so we do not have to do * anything special */ return; } } // Any and all specified constraints have been satisfied if (log.isDebugEnabled()) { log.debug(" Successfully passed all security constraints"); } getNext().invoke(request, response); } // ------------------------------------------------------ Protected Methods /** * Associate the specified single sign on identifier with the * specified Session. * * @param ssoId Single sign on identifier * @param session Session to be associated */ protected void associate(String ssoId, Session session) { if (sso == null) return; sso.associate(ssoId, session); } /** * Authenticate the user making this request, based on the login * configuration of the {@link Context} with which this Authenticator is * associated. Return true if any specified constraint has * been satisfied, or false if we have created a response * challenge already. * * @param request Request we are processing * @param response Response we are populating * * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response) throws IOException { if (context == null || context.getLoginConfig() == null) { return true; } return authenticate(request, response, context.getLoginConfig()); } /** * Authenticate the user making this request, based on the specified * login configuration. Return true if any specified * constraint has been satisfied, or false if we have * created a response challenge already. * * @param request Request we are processing * @param response Response we are populating * @param config Login configuration describing how authentication * should be performed * * @exception IOException if an input/output error occurs */ @Override public abstract boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException; /** * Attempts reauthentication to the Realm using * the credentials included in argument entry. * * @param ssoId identifier of SingleSignOn session with which the * caller is associated * @param request the request that needs to be authenticated */ protected boolean reauthenticateFromSSO(String ssoId, Request request) { if (sso == null || ssoId == null) return false; boolean reauthenticated = false; Container parent = getContainer(); if (parent != null) { Realm realm = parent.getRealm(); if (realm != null) { reauthenticated = sso.reauthenticate(ssoId, realm, request); } } if (reauthenticated) { associate(ssoId, request.getSessionInternal(true)); if (log.isDebugEnabled()) { log.debug(" Reauthenticated cached principal '" + request.getUserPrincipal().getName() + "' with auth type '" + request.getAuthType() + "'"); } } return reauthenticated; } /** * Register an authenticated Principal and authentication type in our * request, in the current session (if there is one), and with our * SingleSignOn valve, if there is one. Set the appropriate cookie * to be returned. * * @param request The servlet request we are processing * @param response The servlet response we are generating * @param principal The authenticated Principal to be registered * @param authType The authentication type to be registered * @param username Username used to authenticate (if any) * @param password Password used to authenticate (if any) */ public void register(Request request, HttpServletResponse response, Principal principal, String authType, String username, String password) { if (log.isDebugEnabled()) { String name = (principal == null) ? "none" : principal.getName(); log.debug("Authenticated '" + name + "' with type '" + authType + "'"); } // Cache the authentication information in our request request.setAuthType(authType); request.setUserPrincipal(principal); Session session = request.getSessionInternal(false); if (session != null) { if (changeSessionIdOnAuthentication) { Manager manager = request.getContext().getManager(); manager.changeSessionId(session); request.changeSessionId(session.getId()); } } else if (alwaysUseSession) { session = request.getSessionInternal(true); } // Cache the authentication information in our session, if any if (cache) { if (session != null) { session.setAuthType(authType); session.setPrincipal(principal); if (username != null) session.setNote(Constants.SESS_USERNAME_NOTE, username); else session.removeNote(Constants.SESS_USERNAME_NOTE); if (password != null) session.setNote(Constants.SESS_PASSWORD_NOTE, password); else session.removeNote(Constants.SESS_PASSWORD_NOTE); } } // Construct a cookie to be returned to the client if (sso == null) return; // Only create a new SSO entry if the SSO did not already set a note // for an existing entry (as it would do with subsequent requests // for DIGEST and SSL authenticated contexts) String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (ssoId == null) { // Construct a cookie to be returned to the client ssoId = sessionIdGenerator.generateSessionId(); Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId); cookie.setMaxAge(-1); cookie.setPath("/"); // Bugzilla 41217 cookie.setSecure(request.isSecure()); // Bugzilla 34724 String ssoDomain = sso.getCookieDomain(); if(ssoDomain != null) { cookie.setDomain(ssoDomain); } // Configure httpOnly on SSO cookie using same rules as session cookies if (request.getServletContext().getSessionCookieConfig().isHttpOnly() || request.getContext().getUseHttpOnly()) { cookie.setHttpOnly(true); } response.addCookie(cookie); // Register this principal with our SSO valve sso.register(ssoId, principal, authType, username, password); request.setNote(Constants.REQ_SSOID_NOTE, ssoId); } else { if (principal == null) { // Registering a programmatic logout sso.deregister(ssoId); request.removeNote(Constants.REQ_SSOID_NOTE); return; } else { // Update the SSO session with the latest authentication data sso.update(ssoId, principal, authType, username, password); } } // Fix for Bug 10040 // Always associate a session with a new SSO reqistration. // SSO entries are only removed from the SSO registry map when // associated sessions are destroyed; if a new SSO entry is created // above for this request and the user never revisits the context, the // SSO entry will never be cleared if we don't associate the session if (session == null) session = request.getSessionInternal(true); sso.associate(ssoId, session); } @Override public void login(String username, String password, Request request) throws ServletException { Principal principal = doLogin(request, username, password); register(request, request.getResponse(), principal, getAuthMethod(), username, password); } protected abstract String getAuthMethod(); /** * Process the login request. * * @param request Associated request * @param username The user * @param password The password * @return The authenticated Principal * @throws ServletException */ protected Principal doLogin(Request request, String username, String password) throws ServletException { Principal p = context.getRealm().authenticate(username, password); if (p == null) { throw new ServletException(sm.getString("authenticator.loginFail")); } return p; } @Override public void logout(Request request) throws ServletException { register(request, request.getResponse(), null, null, null, null); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Look up the SingleSignOn implementation in our request processing // path, if there is one Container parent = context.getParent(); while ((sso == null) && (parent != null)) { Valve valves[] = parent.getPipeline().getValves(); for (int i = 0; i < valves.length; i++) { if (valves[i] instanceof SingleSignOn) { sso = (SingleSignOn) valves[i]; break; } } if (sso == null) parent = parent.getParent(); } if (log.isDebugEnabled()) { if (sso != null) log.debug("Found SingleSignOn Valve at " + sso); else log.debug("No SingleSignOn Valve is present"); } sessionIdGenerator = new SessionIdGenerator(); sessionIdGenerator.setSecureRandomAlgorithm(getSecureRandomAlgorithm()); sessionIdGenerator.setSecureRandomClass(getSecureRandomClass()); sessionIdGenerator.setSecureRandomProvider(getSecureRandomProvider()); super.startInternal(); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { super.stopInternal(); sso = null; } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/LocalStrings_fr.properties0000644000175100017510000000361712271471332027744 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. authenticator.certificates=Aucune cha\u00eene de certificat client (client certificate chain) dans cette requ\u00eate authenticator.forbidden=L''acc\u00e8s \u00e0 la ressource demand\u00e9e a \u00e9t\u00e9 interdit authenticator.formlogin=R\u00e9f\u00e9rence directe \u00e0 la form de connexion (form login page) invalide authenticator.invalid=Cha\u00eene de certificat client invalide dans cette requ\u00eate authenticator.keystore=Exception lors du chargement du r\u00e9f\u00e9rentiel de clefs (key store) authenticator.manager=Exception lors de l''initialisation des gestionnaires d''authentification (trust managers) authenticator.notAuthenticated=Erreur de configuration: Impossible de proc\u00e9der \u00e0 un contr\u00f4le d''acc\u00e8s sans un principal authentifi\u00e9 (authenticated principal) authenticator.notContext=Erreur de configuration: Doit \u00eatre attach\u00e9 \u00e0 un contexte authenticator.unauthorized=Impossible d''authentifier avec les cr\u00e9dits fournis (provided credentials) authenticator.userDataConstraint=Cette requ\u00eate viole une contrainte donn\u00e9e utilisateur (user data constraint) pour cette application tomcat7-7.0.52/java/org/apache/catalina/authenticator/BasicAuthenticator.java0000644000175100017510000001543712271471332027155 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.IOException; import java.security.Principal; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.codec.binary.Base64; /** * An Authenticator and Valve implementation of HTTP BASIC * Authentication, as outlined in RFC 2617: "HTTP Authentication: Basic * and Digest Access Authentication." * * @author Craig R. McClanahan */ public class BasicAuthenticator extends AuthenticatorBase { private static final Log log = LogFactory.getLog(BasicAuthenticator.class); // ----------------------------------------------------- Instance Variables /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.authenticator.BasicAuthenticator/1.0"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Authenticate the user making this request, based on the specified * login configuration. Return true if any specified * constraint has been satisfied, or false if we have * created a response challenge already. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication * should be performed * * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { // Have we already authenticated someone? Principal principal = request.getUserPrincipal(); String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (log.isDebugEnabled()) log.debug("Already authenticated '" + principal.getName() + "'"); // Associate the session with any existing SSO session if (ssoId != null) associate(ssoId, request.getSessionInternal(true)); return (true); } // Is there an SSO session against which we can try to reauthenticate? if (ssoId != null) { if (log.isDebugEnabled()) log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication"); /* Try to reauthenticate using data cached by SSO. If this fails, either the original SSO logon was of DIGEST or SSL (which we can't reauthenticate ourselves because there is no cached username and password), or the realm denied the user's reauthentication for some reason. In either case we have to prompt the user for a logon */ if (reauthenticateFromSSO(ssoId, request)) return true; } // Validate any credentials already included with this request String username = null; String password = null; MessageBytes authorization = request.getCoyoteRequest().getMimeHeaders() .getValue("authorization"); if (authorization != null) { authorization.toBytes(); ByteChunk authorizationBC = authorization.getByteChunk(); if (authorizationBC.startsWithIgnoreCase("basic ", 0)) { authorizationBC.setOffset(authorizationBC.getOffset() + 6); byte[] decoded = Base64.decodeBase64( authorizationBC.getBuffer(), authorizationBC.getOffset(), authorizationBC.getLength()); // Get username and password int colon = -1; for (int i = 0; i < decoded.length; i++) { if (decoded[i] == ':') { colon = i; break; } } if (colon < 0) { username = new String(decoded, B2CConverter.ISO_8859_1); } else { username = new String( decoded, 0, colon, B2CConverter.ISO_8859_1); password = new String( decoded, colon + 1, decoded.length - colon - 1, B2CConverter.ISO_8859_1); } authorizationBC.setOffset(authorizationBC.getOffset() - 6); } principal = context.getRealm().authenticate(username, password); if (principal != null) { register(request, response, principal, HttpServletRequest.BASIC_AUTH, username, password); return (true); } } StringBuilder value = new StringBuilder(16); value.append("Basic realm=\""); if (config.getRealmName() == null) { value.append(REALM_NAME); } else { value.append(config.getRealmName()); } value.append('\"'); response.setHeader(AUTH_HEADER_NAME, value.toString()); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return (false); } @Override protected String getAuthMethod() { return HttpServletRequest.BASIC_AUTH; } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java0000644000175100017510000003042012267024014027350 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.io.File; import java.io.IOException; import java.security.Principal; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.regex.Pattern; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.startup.Bootstrap; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.codec.binary.Base64; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSManager; import org.ietf.jgss.Oid; /** * A SPNEGO authenticator that uses the SPNEGO/Kerberos support built in to Java * 6. Successful Kerberos authentication depends on the correct configuration of * multiple components. If the configuration is invalid, the error messages are * often cryptic although a Google search will usually point you in the right * direction. */ public class SpnegoAuthenticator extends AuthenticatorBase { private static final Log log = LogFactory.getLog(SpnegoAuthenticator.class); private String loginConfigName = Constants.DEFAULT_LOGIN_MODULE_NAME; public String getLoginConfigName() { return loginConfigName; } public void setLoginConfigName(String loginConfigName) { this.loginConfigName = loginConfigName; } private boolean storeDelegatedCredential = true; public boolean isStoreDelegatedCredential() { return storeDelegatedCredential; } public void setStoreDelegatedCredential( boolean storeDelegatedCredential) { this.storeDelegatedCredential = storeDelegatedCredential; } private Pattern noKeepAliveUserAgents = null; public String getNoKeepAliveUserAgents() { Pattern p = noKeepAliveUserAgents; if (p == null) { return null; } else { return p.pattern(); } } public void setNoKeepAliveUserAgents(String noKeepAliveUserAgents) { if (noKeepAliveUserAgents == null || noKeepAliveUserAgents.length() == 0) { this.noKeepAliveUserAgents = null; } else { this.noKeepAliveUserAgents = Pattern.compile(noKeepAliveUserAgents); } } @Override protected String getAuthMethod() { return Constants.SPNEGO_METHOD; } @Override public String getInfo() { return "org.apache.catalina.authenticator.SpnegoAuthenticator/1.0"; } @Override protected void initInternal() throws LifecycleException { super.initInternal(); // Kerberos configuration file location String krb5Conf = System.getProperty(Constants.KRB5_CONF_PROPERTY); if (krb5Conf == null) { // System property not set, use the Tomcat default File krb5ConfFile = new File(Bootstrap.getCatalinaBase(), Constants.DEFAULT_KRB5_CONF); System.setProperty(Constants.KRB5_CONF_PROPERTY, krb5ConfFile.getAbsolutePath()); } // JAAS configuration file location String jaasConf = System.getProperty(Constants.JAAS_CONF_PROPERTY); if (jaasConf == null) { // System property not set, use the Tomcat default File jaasConfFile = new File(Bootstrap.getCatalinaBase(), Constants.DEFAULT_JAAS_CONF); System.setProperty(Constants.JAAS_CONF_PROPERTY, jaasConfFile.getAbsolutePath()); } } @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { // Have we already authenticated someone? Principal principal = request.getUserPrincipal(); String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (log.isDebugEnabled()) log.debug("Already authenticated '" + principal.getName() + "'"); // Associate the session with any existing SSO session if (ssoId != null) associate(ssoId, request.getSessionInternal(true)); return true; } // Is there an SSO session against which we can try to reauthenticate? if (ssoId != null) { if (log.isDebugEnabled()) log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication"); /* Try to reauthenticate using data cached by SSO. If this fails, either the original SSO logon was of DIGEST or SSL (which we can't reauthenticate ourselves because there is no cached username and password), or the realm denied the user's reauthentication for some reason. In either case we have to prompt the user for a logon */ if (reauthenticateFromSSO(ssoId, request)) return true; } MessageBytes authorization = request.getCoyoteRequest().getMimeHeaders() .getValue("authorization"); if (authorization == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("authenticator.noAuthHeader")); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } authorization.toBytes(); ByteChunk authorizationBC = authorization.getByteChunk(); if (!authorizationBC.startsWithIgnoreCase("negotiate ", 0)) { if (log.isDebugEnabled()) { log.debug(sm.getString( "spnegoAuthenticator.authHeaderNotNego")); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } authorizationBC.setOffset(authorizationBC.getOffset() + 10); byte[] decoded = Base64.decodeBase64(authorizationBC.getBuffer(), authorizationBC.getOffset(), authorizationBC.getLength()); if (decoded.length == 0) { if (log.isDebugEnabled()) { log.debug(sm.getString( "spnegoAuthenticator.authHeaderNoToken")); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } LoginContext lc = null; GSSContext gssContext = null; byte[] outToken = null; try { try { lc = new LoginContext(getLoginConfigName()); lc.login(); } catch (LoginException e) { log.error(sm.getString("spnegoAuthenticator.serviceLoginFail"), e); response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return false; } // Assume the GSSContext is stateless // TODO: Confirm this assumption final GSSManager manager = GSSManager.getInstance(); // IBM JDK only understands indefinite lifetime final int credentialLifetime; if (Globals.IS_IBM_JVM) { credentialLifetime = GSSCredential.INDEFINITE_LIFETIME; } else { credentialLifetime = GSSCredential.DEFAULT_LIFETIME; } final PrivilegedExceptionAction action = new PrivilegedExceptionAction() { @Override public GSSCredential run() throws GSSException { return manager.createCredential(null, credentialLifetime, new Oid("1.3.6.1.5.5.2"), GSSCredential.ACCEPT_ONLY); } }; gssContext = manager.createContext(Subject.doAs(lc.getSubject(), action)); outToken = Subject.doAs(lc.getSubject(), new AcceptAction(gssContext, decoded)); if (outToken == null) { if (log.isDebugEnabled()) { log.debug(sm.getString( "spnegoAuthenticator.ticketValidateFail")); } // Start again response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } principal = context.getRealm().authenticate(gssContext, isStoreDelegatedCredential()); } catch (GSSException e) { if (log.isDebugEnabled()) { log.debug(sm.getString("spnegoAuthenticator.ticketValidateFail"), e); } response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } catch (PrivilegedActionException e) { log.error(sm.getString("spnegoAuthenticator.serviceLoginFail"), e); response.setHeader("WWW-Authenticate", "Negotiate"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } finally { if (gssContext != null) { try { gssContext.dispose(); } catch (GSSException e) { // Ignore } } if (lc != null) { try { lc.logout(); } catch (LoginException e) { // Ignore } } } // Send response token on success and failure response.setHeader("WWW-Authenticate", "Negotiate " + Base64.encodeBase64String(outToken)); if (principal != null) { register(request, response, principal, Constants.SPNEGO_METHOD, principal.getName(), null); Pattern p = noKeepAliveUserAgents; if (p != null) { MessageBytes ua = request.getCoyoteRequest().getMimeHeaders().getValue( "user-agent"); if (ua != null && p.matcher(ua.toString()).matches()) { response.setHeader("Connection", "close"); } } return true; } response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } /** * This class gets a gss credential via a privileged action. */ private static class AcceptAction implements PrivilegedExceptionAction { GSSContext gssContext; byte[] decoded; AcceptAction(GSSContext context, byte[] decodedToken) { this.gssContext = context; this.decoded = decodedToken; } @Override public byte[] run() throws GSSException { return gssContext.acceptSecContext(decoded, 0, decoded.length); } } } tomcat7-7.0.52/java/org/apache/catalina/authenticator/SavedRequest.java0000644000175100017510000001134612271471332026007 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.authenticator; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import javax.servlet.http.Cookie; import org.apache.tomcat.util.buf.ByteChunk; /** * Object that saves the critical information from a request so that * form-based authentication can reproduce it once the user has been * authenticated. *

    * IMPLEMENTATION NOTE - It is assumed that this object is accessed * only from the context of a single thread, so no synchronization around * internal collection classes is performed. * * @author Craig R. McClanahan */ public final class SavedRequest { /** * The set of Cookies associated with this Request. */ private ArrayList cookies = new ArrayList(); public void addCookie(Cookie cookie) { cookies.add(cookie); } public Iterator getCookies() { return (cookies.iterator()); } /** * The set of Headers associated with this Request. Each key is a header * name, while the value is a ArrayList containing one or more actual * values for this header. The values are returned as an Iterator when * you ask for them. */ private HashMap> headers = new HashMap>(); public void addHeader(String name, String value) { ArrayList values = headers.get(name); if (values == null) { values = new ArrayList(); headers.put(name, values); } values.add(value); } public Iterator getHeaderNames() { return (headers.keySet().iterator()); } public Iterator getHeaderValues(String name) { ArrayList values = headers.get(name); if (values == null) return ((new ArrayList()).iterator()); else return (values.iterator()); } /** * The set of Locales associated with this Request. */ private ArrayList locales = new ArrayList(); public void addLocale(Locale locale) { locales.add(locale); } public Iterator getLocales() { return (locales.iterator()); } /** * The request method used on this Request. */ private String method = null; public String getMethod() { return (this.method); } public void setMethod(String method) { this.method = method; } /** * The query string associated with this Request. */ private String queryString = null; public String getQueryString() { return (this.queryString); } public void setQueryString(String queryString) { this.queryString = queryString; } /** * The request URI associated with this Request. */ private String requestURI = null; public String getRequestURI() { return (this.requestURI); } public void setRequestURI(String requestURI) { this.requestURI = requestURI; } /** * The decode request URI associated with this Request. Path parameters are * also excluded */ private String decodedRequestURI = null; public String getDecodedRequestURI() { return (this.decodedRequestURI); } public void setDecodedRequestURI(String decodedRequestURI) { this.decodedRequestURI = decodedRequestURI; } /** * The body of this request. */ private ByteChunk body = null; public ByteChunk getBody() { return (this.body); } public void setBody(ByteChunk body) { this.body = body; } /** * The content type of the request, used if this is a POST. */ private String contentType = null; public String getContentType() { return (this.contentType); } public void setContentType(String contentType) { this.contentType = contentType; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/0000755000175100017510000000000012301126371021140 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/deploy/ErrorPage.java0000644000175100017510000001005612271471332023701 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import org.apache.catalina.util.RequestUtil; /** * Representation of an error page element for a web application, * as represented in a <error-page> element in the * deployment descriptor. * * @author Craig R. McClanahan */ public class ErrorPage implements Serializable { private static final long serialVersionUID = 1L; // ----------------------------------------------------- Instance Variables /** * The error (status) code for which this error page is active. Note that * status code 0 is used for the default error page. */ private int errorCode = 0; /** * The exception type for which this error page is active. */ private String exceptionType = null; /** * The context-relative location to handle this error or exception. */ private String location = null; // ------------------------------------------------------------- Properties /** * Return the error code. */ public int getErrorCode() { return (this.errorCode); } /** * Set the error code. * * @param errorCode The new error code */ public void setErrorCode(int errorCode) { this.errorCode = errorCode; } /** * Set the error code (hack for default XmlMapper data type). * * @param errorCode The new error code */ public void setErrorCode(String errorCode) { try { this.errorCode = Integer.parseInt(errorCode); } catch (NumberFormatException nfe) { this.errorCode = 0; } } /** * Return the exception type. */ public String getExceptionType() { return (this.exceptionType); } /** * Set the exception type. * * @param exceptionType The new exception type */ public void setExceptionType(String exceptionType) { this.exceptionType = exceptionType; } /** * Return the location. */ public String getLocation() { return (this.location); } /** * Set the location. * * @param location The new location */ public void setLocation(String location) { // if ((location == null) || !location.startsWith("/")) // throw new IllegalArgumentException // ("Error Page Location must start with a '/'"); this.location = RequestUtil.URLDecode(location); } // --------------------------------------------------------- Public Methods /** * Render a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ErrorPage["); if (exceptionType == null) { sb.append("errorCode="); sb.append(errorCode); } else { sb.append("exceptionType="); sb.append(exceptionType); } sb.append(", location="); sb.append(location); sb.append("]"); return (sb.toString()); } public String getName() { if (exceptionType == null) { return Integer.toString(errorCode); } else { return exceptionType; } } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ApplicationParameter.java0000644000175100017510000000616312271471332026123 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; /** * Representation of a context initialization parameter that is configured * in the server configuration file, rather than the application deployment * descriptor. This is convenient for establishing default values (which * may be configured to allow application overrides or not) without having * to modify the application deployment descriptor itself. * * @author Craig R. McClanahan */ public class ApplicationParameter implements Serializable { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The description of this environment entry. */ private String description = null; public String getDescription() { return (this.description); } public void setDescription(String description) { this.description = description; } /** * The name of this application parameter. */ private String name = null; public String getName() { return (this.name); } public void setName(String name) { this.name = name; } /** * Does this application parameter allow overrides by the application * deployment descriptor? */ private boolean override = true; public boolean getOverride() { return (this.override); } public void setOverride(boolean override) { this.override = override; } /** * The value of this application parameter. */ private String value = null; public String getValue() { return (this.value); } public void setValue(String value) { this.value = value; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ApplicationParameter["); sb.append("name="); sb.append(name); if (description != null) { sb.append(", description="); sb.append(description); } sb.append(", value="); sb.append(value); sb.append(", override="); sb.append(override); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/deploy/SecurityRoleRef.java0000644000175100017510000000410712271471332025101 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** *

    Representation of a security role reference for a web application, as * represented in a <security-role-ref> element * in the deployment descriptor.

    * * @author Mark Thomas * @since Tomcat 5.5 */ public class SecurityRoleRef { // ------------------------------------------------------------- Properties /** * The (required) role name. */ private String name = null; public String getName() { return (this.name); } public void setName(String name) { this.name = name; } /** * The optional role link. */ private String link = null; public String getLink() { return (this.link); } public void setLink(String link) { this.link = link; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SecurityRoleRef["); sb.append("name="); sb.append(name); if (link != null) { sb.append(", link="); sb.append(link); } sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ApplicationListener.java0000644000175100017510000000261612156140711025763 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** * Enables additional attributes other than just the name to be recorded for * an application listener. */ public class ApplicationListener { private final String className; private final boolean pluggabilityBlocked; public ApplicationListener(String className, boolean pluggabilityBlocked) { this.className = className; this.pluggabilityBlocked = pluggabilityBlocked; } public String getClassName() { return className; } public boolean isPluggabilityBlocked() { return pluggabilityBlocked; } }tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextResourceEnvRef.java0000644000175100017510000000536412271471332026263 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** * Representation of an application resource reference, as represented in * an <res-env-refy> element in the deployment descriptor. * * @author Craig R. McClanahan * @author Peter Rossbach (pero@apache.org) */ public class ContextResourceEnvRef extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * Does this environment entry allow overrides by the application * deployment descriptor? */ private boolean override = true; public boolean getOverride() { return (this.override); } public void setOverride(boolean override) { this.override = override; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextResourceEnvRef["); sb.append("name="); sb.append(getName()); if (getType() != null) { sb.append(", type="); sb.append(getType()); } sb.append(", override="); sb.append(override); sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (override ? 1231 : 1237); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextResourceEnvRef other = (ContextResourceEnvRef) obj; if (override != other.override) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/SecurityConstraint.java0000644000175100017510000003732512271471332025677 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.servlet.HttpConstraintElement; import javax.servlet.HttpMethodConstraintElement; import javax.servlet.ServletSecurityElement; import javax.servlet.annotation.ServletSecurity; import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; /** * Representation of a security constraint element for a web application, * as represented in a <security-constraint> element in the * deployment descriptor. *

    * WARNING: It is assumed that instances of this class will be created * and modified only within the context of a single thread, before the instance * is made visible to the remainder of the application. After that, only read * access is expected. Therefore, none of the read and write access within * this class is synchronized. * * @author Craig R. McClanahan */ public class SecurityConstraint implements Serializable { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Construct a new security constraint instance with default values. */ public SecurityConstraint() { super(); } // ----------------------------------------------------- Instance Variables /** * Was the "all roles" wildcard included in the authorization constraints * for this security constraint? */ private boolean allRoles = false; /** * Was an authorization constraint included in this security constraint? * This is necessary to distinguish the case where an auth-constraint with * no roles (signifying no direct access at all) was requested, versus * a lack of auth-constraint which implies no access control checking. */ private boolean authConstraint = false; /** * The set of roles permitted to access resources protected by this * security constraint. */ private String authRoles[] = new String[0]; /** * The set of web resource collections protected by this security * constraint. */ private SecurityCollection collections[] = new SecurityCollection[0]; /** * The display name of this security constraint. */ private String displayName = null; /** * The user data constraint for this security constraint. Must be NONE, * INTEGRAL, or CONFIDENTIAL. */ private String userConstraint = "NONE"; // ------------------------------------------------------------- Properties /** * Was the "all roles" wildcard included in this authentication * constraint? */ public boolean getAllRoles() { return (this.allRoles); } /** * Return the authorization constraint present flag for this security * constraint. */ public boolean getAuthConstraint() { return (this.authConstraint); } /** * Set the authorization constraint present flag for this security * constraint. */ public void setAuthConstraint(boolean authConstraint) { this.authConstraint = authConstraint; } /** * Return the display name of this security constraint. */ public String getDisplayName() { return (this.displayName); } /** * Set the display name of this security constraint. */ public void setDisplayName(String displayName) { this.displayName = displayName; } /** * Return the user data constraint for this security constraint. */ public String getUserConstraint() { return (userConstraint); } /** * Set the user data constraint for this security constraint. * * @param userConstraint The new user data constraint */ public void setUserConstraint(String userConstraint) { if (userConstraint != null) this.userConstraint = userConstraint; } // --------------------------------------------------------- Public Methods /** * Add an authorization role, which is a role name that will be * permitted access to the resources protected by this security constraint. * * @param authRole Role name to be added */ public void addAuthRole(String authRole) { if (authRole == null) return; if ("*".equals(authRole)) { allRoles = true; return; } String results[] = new String[authRoles.length + 1]; for (int i = 0; i < authRoles.length; i++) results[i] = authRoles[i]; results[authRoles.length] = authRole; authRoles = results; authConstraint = true; } /** * Add a new web resource collection to those protected by this * security constraint. * * @param collection The new web resource collection */ public void addCollection(SecurityCollection collection) { if (collection == null) return; SecurityCollection results[] = new SecurityCollection[collections.length + 1]; for (int i = 0; i < collections.length; i++) results[i] = collections[i]; results[collections.length] = collection; collections = results; } /** * Return true if the specified role is permitted access to * the resources protected by this security constraint. * * @param role Role name to be checked */ public boolean findAuthRole(String role) { if (role == null) return (false); for (int i = 0; i < authRoles.length; i++) { if (role.equals(authRoles[i])) return (true); } return (false); } /** * Return the set of roles that are permitted access to the resources * protected by this security constraint. If none have been defined, * a zero-length array is returned (which implies that all authenticated * users are permitted access). */ public String[] findAuthRoles() { return (authRoles); } /** * Return the web resource collection for the specified name, if any; * otherwise, return null. * * @param name Web resource collection name to return */ public SecurityCollection findCollection(String name) { if (name == null) return (null); for (int i = 0; i < collections.length; i++) { if (name.equals(collections[i].getName())) return (collections[i]); } return (null); } /** * Return all of the web resource collections protected by this * security constraint. If there are none, a zero-length array is * returned. */ public SecurityCollection[] findCollections() { return (collections); } /** * Return true if the specified context-relative URI (and * associated HTTP method) are protected by this security constraint. * * @param uri Context-relative URI to check * @param method Request method being used */ public boolean included(String uri, String method) { // We cannot match without a valid request method if (method == null) return (false); // Check all of the collections included in this constraint for (int i = 0; i < collections.length; i++) { if (!collections[i].findMethod(method)) continue; String patterns[] = collections[i].findPatterns(); for (int j = 0; j < patterns.length; j++) { if (matchPattern(uri, patterns[j])) return (true); } } // No collection included in this constraint matches this request return (false); } /** * Remove the specified role from the set of roles permitted to access * the resources protected by this security constraint. * * @param authRole Role name to be removed */ public void removeAuthRole(String authRole) { if (authRole == null) return; int n = -1; for (int i = 0; i < authRoles.length; i++) { if (authRoles[i].equals(authRole)) { n = i; break; } } if (n >= 0) { int j = 0; String results[] = new String[authRoles.length - 1]; for (int i = 0; i < authRoles.length; i++) { if (i != n) results[j++] = authRoles[i]; } authRoles = results; } } /** * Remove the specified web resource collection from those protected by * this security constraint. * * @param collection Web resource collection to be removed */ public void removeCollection(SecurityCollection collection) { if (collection == null) return; int n = -1; for (int i = 0; i < collections.length; i++) { if (collections[i].equals(collection)) { n = i; break; } } if (n >= 0) { int j = 0; SecurityCollection results[] = new SecurityCollection[collections.length - 1]; for (int i = 0; i < collections.length; i++) { if (i != n) results[j++] = collections[i]; } collections = results; } } /** * Return a String representation of this security constraint. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SecurityConstraint["); for (int i = 0; i < collections.length; i++) { if (i > 0) sb.append(", "); sb.append(collections[i].getName()); } sb.append("]"); return (sb.toString()); } // -------------------------------------------------------- Private Methods /** * Does the specified request path match the specified URL pattern? * This method follows the same rules (in the same order) as those used * for mapping requests to servlets. * * @param path Context-relative request path to be checked * (must start with '/') * @param pattern URL pattern to be compared against */ private boolean matchPattern(String path, String pattern) { // Normalize the argument strings if ((path == null) || (path.length() == 0)) path = "/"; if ((pattern == null) || (pattern.length() == 0)) pattern = "/"; // Check for exact match if (path.equals(pattern)) return (true); // Check for path prefix matching if (pattern.startsWith("/") && pattern.endsWith("/*")) { pattern = pattern.substring(0, pattern.length() - 2); if (pattern.length() == 0) return (true); // "/*" is the same as "/" if (path.endsWith("/")) path = path.substring(0, path.length() - 1); while (true) { if (pattern.equals(path)) return (true); int slash = path.lastIndexOf('/'); if (slash <= 0) break; path = path.substring(0, slash); } return (false); } // Check for suffix matching if (pattern.startsWith("*.")) { int slash = path.lastIndexOf('/'); int period = path.lastIndexOf('.'); if ((slash >= 0) && (period > slash) && path.endsWith(pattern.substring(1))) { return (true); } return (false); } // Check for universal mapping if (pattern.equals("/")) return (true); return (false); } /** * Convert a {@link ServletSecurityElement} to an array of * {@link SecurityConstraint}(s). * * @param element The element to be converted * @param urlPattern The url pattern that the element should be applied * to * @return The (possibly zero length) array of constraints that * are the equivalent to the input */ public static SecurityConstraint[] createConstraints( ServletSecurityElement element, String urlPattern) { Set result = new HashSet(); // Add the per method constraints Collection methods = element.getHttpMethodConstraints(); Iterator methodIter = methods.iterator(); while (methodIter.hasNext()) { HttpMethodConstraintElement methodElement = methodIter.next(); SecurityConstraint constraint = createConstraint(methodElement, urlPattern, true); // There will always be a single collection SecurityCollection collection = constraint.findCollections()[0]; collection.addMethod(methodElement.getMethodName()); result.add(constraint); } // Add the constraint for all the other methods SecurityConstraint constraint = createConstraint(element, urlPattern, false); if (constraint != null) { // There will always be a single collection SecurityCollection collection = constraint.findCollections()[0]; Iterator ommittedMethod = element.getMethodNames().iterator(); while (ommittedMethod.hasNext()) { collection.addOmittedMethod(ommittedMethod.next()); } result.add(constraint); } return result.toArray(new SecurityConstraint[result.size()]); } private static SecurityConstraint createConstraint( HttpConstraintElement element, String urlPattern, boolean alwaysCreate) { SecurityConstraint constraint = new SecurityConstraint(); SecurityCollection collection = new SecurityCollection(); boolean create = alwaysCreate; if (element.getTransportGuarantee() != ServletSecurity.TransportGuarantee.NONE) { constraint.setUserConstraint(element.getTransportGuarantee().name()); create = true; } if (element.getRolesAllowed().length > 0) { String[] roles = element.getRolesAllowed(); for (String role : roles) { constraint.addAuthRole(role); } create = true; } if (element.getEmptyRoleSemantic() != EmptyRoleSemantic.PERMIT) { constraint.setAuthConstraint(true); create = true; } if (create) { collection.addPattern(urlPattern); constraint.addCollection(collection); return constraint; } return null; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextHandler.java0000644000175100017510000001361412271471332024740 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; /** * Representation of a handler reference for a web service, as * represented in a <handler> element in the * deployment descriptor. * * @author Fabien Carrion */ public class ContextHandler extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The Handler reference class. */ private String handlerclass = null; public String getHandlerclass() { return (this.handlerclass); } public void setHandlerclass(String handlerclass) { this.handlerclass = handlerclass; } /** * A list of QName specifying the SOAP Headers the handler will work on. * -namespace and locapart values must be found inside the WSDL. * * A service-qname is composed by a namespaceURI and a localpart. * * soapHeader[0] : namespaceURI * soapHeader[1] : localpart */ private final HashMap soapHeaders = new HashMap(); public Iterator getLocalparts() { return soapHeaders.keySet().iterator(); } public String getNamespaceuri(String localpart) { return soapHeaders.get(localpart); } public void addSoapHeaders(String localpart, String namespaceuri) { soapHeaders.put(localpart, namespaceuri); } /** * Set a configured property. */ public void setProperty(String name, String value) { this.setProperty(name, (Object) value); } /** * The soapRole. */ private final ArrayList soapRoles = new ArrayList(); public String getSoapRole(int i) { return this.soapRoles.get(i); } public int getSoapRolesSize() { return this.soapRoles.size(); } public void addSoapRole(String soapRole) { this.soapRoles.add(soapRole); } /** * The portName. */ private final ArrayList portNames = new ArrayList(); public String getPortName(int i) { return this.portNames.get(i); } public int getPortNamesSize() { return this.portNames.size(); } public void addPortName(String portName) { this.portNames.add(portName); } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextHandler["); sb.append("name="); sb.append(getName()); if (handlerclass != null) { sb.append(", class="); sb.append(handlerclass); } if (this.soapHeaders != null) { sb.append(", soap-headers="); sb.append(this.soapHeaders); } if (this.getSoapRolesSize() > 0) { sb.append(", soap-roles="); sb.append(soapRoles); } if (this.getPortNamesSize() > 0) { sb.append(", port-name="); sb.append(portNames); } if (this.listProperties() != null) { sb.append(", init-param="); sb.append(this.listProperties()); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((handlerclass == null) ? 0 : handlerclass.hashCode()); result = prime * result + ((portNames == null) ? 0 : portNames.hashCode()); result = prime * result + ((soapHeaders == null) ? 0 : soapHeaders.hashCode()); result = prime * result + ((soapRoles == null) ? 0 : soapRoles.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextHandler other = (ContextHandler) obj; if (handlerclass == null) { if (other.handlerclass != null) { return false; } } else if (!handlerclass.equals(other.handlerclass)) { return false; } if (portNames == null) { if (other.portNames != null) { return false; } } else if (!portNames.equals(other.portNames)) { return false; } if (soapHeaders == null) { if (other.soapHeaders != null) { return false; } } else if (!soapHeaders.equals(other.soapHeaders)) { return false; } if (soapRoles == null) { if (other.soapRoles != null) { return false; } } else if (!soapRoles.equals(other.soapRoles)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextService.java0000644000175100017510000002435412271471332024766 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; /** * Representation of a web service reference for a web application, as * represented in a <service-ref> element in the * deployment descriptor. * * @author Fabien Carrion */ public class ContextService extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The WebService reference name. */ private String displayname = null; public String getDisplayname() { return (this.displayname); } public void setDisplayname(String displayname) { this.displayname = displayname; } /** * A large icon for this WebService. */ private String largeIcon = null; public String getLargeIcon() { return (this.largeIcon); } public void setLargeIcon(String largeIcon) { this.largeIcon = largeIcon; } /** * A small icon for this WebService. */ private String smallIcon = null; public String getSmallIcon() { return (this.smallIcon); } public void setSmallIcon(String smallIcon) { this.smallIcon = smallIcon; } /** * The fully qualified class name of the JAX-WS Service interface that the * client depends on. */ private String serviceInterface = null; public String getInterface() { return serviceInterface; } public void setInterface(String serviceInterface) { this.serviceInterface = serviceInterface; } /** * Contains the location (relative to the root of * the module) of the web service WSDL description. */ private String wsdlfile = null; public String getWsdlfile() { return (this.wsdlfile); } public void setWsdlfile(String wsdlfile) { this.wsdlfile = wsdlfile; } /** * A file specifying the correlation of the WSDL definition * to the interfaces (Service Endpoint Interface, Service Interface). */ private String jaxrpcmappingfile = null; public String getJaxrpcmappingfile() { return (this.jaxrpcmappingfile); } public void setJaxrpcmappingfile(String jaxrpcmappingfile) { this.jaxrpcmappingfile = jaxrpcmappingfile; } /** * Declares the specific WSDL service element that is being referred to. * It is not specified if no wsdl-file is declared or if WSDL contains only * 1 service element. * * A service-qname is composed by a namespaceURI and a localpart. * It must be defined if more than 1 service is declared in the WSDL. * * serviceqname[0] : namespaceURI * serviceqname[1] : localpart */ private String[] serviceqname = new String[2]; public String[] getServiceqname() { return (this.serviceqname); } public String getServiceqname(int i) { return this.serviceqname[i]; } public String getServiceqnameNamespaceURI() { return this.serviceqname[0]; } public String getServiceqnameLocalpart() { return this.serviceqname[1]; } public void setServiceqname(String[] serviceqname) { this.serviceqname = serviceqname; } public void setServiceqname(String serviceqname, int i) { this.serviceqname[i] = serviceqname; } public void setServiceqnameNamespaceURI(String namespaceuri) { this.serviceqname[0] = namespaceuri; } public void setServiceqnameLocalpart(String localpart) { this.serviceqname[1] = localpart; } /** * Declares a client dependency on the container to resolving a Service Endpoint Interface * to a WSDL port. It optionally associates the Service Endpoint Interface with a * particular port-component. * */ public Iterator getServiceendpoints() { return this.listProperties(); } public String getPortlink(String serviceendpoint) { return (String) this.getProperty(serviceendpoint); } public void addPortcomponent(String serviceendpoint, String portlink) { if (portlink == null) portlink = ""; this.setProperty(serviceendpoint, portlink); } /** * A list of Handlers to use for this service-ref. * * The instantiation of the handler have to be done. */ private final HashMap handlers = new HashMap(); public Iterator getHandlers() { return handlers.keySet().iterator(); } public ContextHandler getHandler(String handlername) { return handlers.get(handlername); } public void addHandler(ContextHandler handler) { handlers.put(handler.getName(), handler); } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextService["); sb.append("name="); sb.append(getName()); if (getDescription() != null) { sb.append(", description="); sb.append(getDescription()); } if (getType() != null) { sb.append(", type="); sb.append(getType()); } if (displayname != null) { sb.append(", displayname="); sb.append(displayname); } if (largeIcon != null) { sb.append(", largeIcon="); sb.append(largeIcon); } if (smallIcon != null) { sb.append(", smallIcon="); sb.append(smallIcon); } if (wsdlfile != null) { sb.append(", wsdl-file="); sb.append(wsdlfile); } if (jaxrpcmappingfile != null) { sb.append(", jaxrpc-mapping-file="); sb.append(jaxrpcmappingfile); } if (serviceqname[0] != null) { sb.append(", service-qname/namespaceURI="); sb.append(serviceqname[0]); } if (serviceqname[1] != null) { sb.append(", service-qname/localpart="); sb.append(serviceqname[1]); } if (this.getServiceendpoints() != null) { sb.append(", port-component/service-endpoint-interface="); sb.append(this.getServiceendpoints()); } if (handlers != null) { sb.append(", handler="); sb.append(handlers); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((displayname == null) ? 0 : displayname.hashCode()); result = prime * result + ((handlers == null) ? 0 : handlers.hashCode()); result = prime * result + ((jaxrpcmappingfile == null) ? 0 : jaxrpcmappingfile.hashCode()); result = prime * result + ((largeIcon == null) ? 0 : largeIcon.hashCode()); result = prime * result + ((serviceInterface == null) ? 0 : serviceInterface.hashCode()); result = prime * result + Arrays.hashCode(serviceqname); result = prime * result + ((smallIcon == null) ? 0 : smallIcon.hashCode()); result = prime * result + ((wsdlfile == null) ? 0 : wsdlfile.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextService other = (ContextService) obj; if (displayname == null) { if (other.displayname != null) { return false; } } else if (!displayname.equals(other.displayname)) { return false; } if (handlers == null) { if (other.handlers != null) { return false; } } else if (!handlers.equals(other.handlers)) { return false; } if (jaxrpcmappingfile == null) { if (other.jaxrpcmappingfile != null) { return false; } } else if (!jaxrpcmappingfile.equals(other.jaxrpcmappingfile)) { return false; } if (largeIcon == null) { if (other.largeIcon != null) { return false; } } else if (!largeIcon.equals(other.largeIcon)) { return false; } if (serviceInterface == null) { if (other.serviceInterface != null) { return false; } } else if (!serviceInterface.equals(other.serviceInterface)) { return false; } if (!Arrays.equals(serviceqname, other.serviceqname)) { return false; } if (smallIcon == null) { if (other.smallIcon != null) { return false; } } else if (!smallIcon.equals(other.smallIcon)) { return false; } if (wsdlfile == null) { if (other.wsdlfile != null) { return false; } } else if (!wsdlfile.equals(other.wsdlfile)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/FilterDef.java0000644000175100017510000001217312271471332023661 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import javax.servlet.Filter; import org.apache.tomcat.util.res.StringManager; /** * Representation of a filter definition for a web application, as represented * in a <filter> element in the deployment descriptor. * * @author Craig R. McClanahan */ public class FilterDef implements Serializable { private static final long serialVersionUID = 1L; private static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------------------------------------- Properties /** * The description of this filter. */ private String description = null; public String getDescription() { return (this.description); } public void setDescription(String description) { this.description = description; } /** * The display name of this filter. */ private String displayName = null; public String getDisplayName() { return (this.displayName); } public void setDisplayName(String displayName) { this.displayName = displayName; } /** * The filter instance associated with this definition */ private transient Filter filter = null; public Filter getFilter() { return filter; } public void setFilter(Filter filter) { this.filter = filter; } /** * The fully qualified name of the Java class that implements this filter. */ private String filterClass = null; public String getFilterClass() { return (this.filterClass); } public void setFilterClass(String filterClass) { this.filterClass = filterClass; } /** * The name of this filter, which must be unique among the filters * defined for a particular web application. */ private String filterName = null; public String getFilterName() { return (this.filterName); } public void setFilterName(String filterName) { if (filterName == null || filterName.equals("")) { throw new IllegalArgumentException( sm.getString("filterDef.invalidFilterName", filterName)); } this.filterName = filterName; } /** * The large icon associated with this filter. */ private String largeIcon = null; public String getLargeIcon() { return (this.largeIcon); } public void setLargeIcon(String largeIcon) { this.largeIcon = largeIcon; } /** * The set of initialization parameters for this filter, keyed by * parameter name. */ private Map parameters = new HashMap(); public Map getParameterMap() { return (this.parameters); } /** * The small icon associated with this filter. */ private String smallIcon = null; public String getSmallIcon() { return (this.smallIcon); } public void setSmallIcon(String smallIcon) { this.smallIcon = smallIcon; } private String asyncSupported = null; public String getAsyncSupported() { return asyncSupported; } public void setAsyncSupported(String asyncSupported) { this.asyncSupported = asyncSupported; } // --------------------------------------------------------- Public Methods /** * Add an initialization parameter to the set of parameters associated * with this filter. * * @param name The initialization parameter name * @param value The initialization parameter value */ public void addInitParameter(String name, String value) { if (parameters.containsKey(name)) { // The spec does not define this but the TCK expects the first // definition to take precedence return; } parameters.put(name, value); } /** * Render a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("FilterDef["); sb.append("filterName="); sb.append(this.filterName); sb.append(", filterClass="); sb.append(this.filterClass); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextResource.java0000644000175100017510000001201512271471332025144 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** * Representation of a resource reference for a web application, as * represented in a <resource-ref> element in the * deployment descriptor. * * @author Craig R. McClanahan * @author Peter Rossbach (pero@apache.org) */ public class ContextResource extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The authorization requirement for this resource * (Application or Container). */ private String auth = null; public String getAuth() { return (this.auth); } public void setAuth(String auth) { this.auth = auth; } /** * The sharing scope of this resource factory (Shareable * or Unshareable). */ private String scope = "Shareable"; public String getScope() { return (this.scope); } public void setScope(String scope) { this.scope = scope; } /** * Is this resource known to be a singleton resource. The default value is * true since this is what users expect although the JavaEE spec implies * that the default should be false. */ private boolean singleton = true; public boolean getSingleton() { return singleton; } public void setSingleton(boolean singleton) { this.singleton = singleton; } /** * The name of the zero argument method to be called when the resource is * no longer required to clean-up resources. This method must only speed up * the clean-up of resources that would otherwise happen via garbage * collection. */ private String closeMethod = null; public String getCloseMethod() { return closeMethod; } public void setCloseMethod(String closeMethod) { this.closeMethod = closeMethod; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextResource["); sb.append("name="); sb.append(getName()); if (getDescription() != null) { sb.append(", description="); sb.append(getDescription()); } if (getType() != null) { sb.append(", type="); sb.append(getType()); } if (auth != null) { sb.append(", auth="); sb.append(auth); } if (scope != null) { sb.append(", scope="); sb.append(scope); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((auth == null) ? 0 : auth.hashCode()); result = prime * result + ((closeMethod == null) ? 0 : closeMethod.hashCode()); result = prime * result + ((scope == null) ? 0 : scope.hashCode()); result = prime * result + (singleton ? 1231 : 1237); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextResource other = (ContextResource) obj; if (auth == null) { if (other.auth != null) { return false; } } else if (!auth.equals(other.auth)) { return false; } if (closeMethod == null) { if (other.closeMethod != null) { return false; } } else if (!closeMethod.equals(other.closeMethod)) { return false; } if (scope == null) { if (other.scope != null) { return false; } } else if (!scope.equals(other.scope)) { return false; } if (singleton != other.singleton) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/MessageDestination.java0000644000175100017510000001047212271471332025603 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** *

    Representation of a message destination for a web application, as * represented in a <message-destination> element * in the deployment descriptor.

    * * @author Craig R. McClanahan * @since Tomcat 5.0 */ public class MessageDestination extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The display name of this destination. */ private String displayName = null; public String getDisplayName() { return (this.displayName); } public void setDisplayName(String displayName) { this.displayName = displayName; } /** * The large icon of this destination. */ private String largeIcon = null; public String getLargeIcon() { return (this.largeIcon); } public void setLargeIcon(String largeIcon) { this.largeIcon = largeIcon; } /** * The small icon of this destination. */ private String smallIcon = null; public String getSmallIcon() { return (this.smallIcon); } public void setSmallIcon(String smallIcon) { this.smallIcon = smallIcon; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("MessageDestination["); sb.append("name="); sb.append(getName()); if (displayName != null) { sb.append(", displayName="); sb.append(displayName); } if (largeIcon != null) { sb.append(", largeIcon="); sb.append(largeIcon); } if (smallIcon != null) { sb.append(", smallIcon="); sb.append(smallIcon); } if (getDescription() != null) { sb.append(", description="); sb.append(getDescription()); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((displayName == null) ? 0 : displayName.hashCode()); result = prime * result + ((largeIcon == null) ? 0 : largeIcon.hashCode()); result = prime * result + ((smallIcon == null) ? 0 : smallIcon.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } MessageDestination other = (MessageDestination) obj; if (displayName == null) { if (other.displayName != null) { return false; } } else if (!displayName.equals(other.displayName)) { return false; } if (largeIcon == null) { if (other.largeIcon != null) { return false; } } else if (!largeIcon.equals(other.largeIcon)) { return false; } if (smallIcon == null) { if (other.smallIcon != null) { return false; } } else if (!smallIcon.equals(other.smallIcon)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/LoginConfig.java0000644000175100017510000001406412271471332024214 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import org.apache.catalina.util.RequestUtil; /** * Representation of a login configuration element for a web application, * as represented in a <login-config> element in the * deployment descriptor. * * @author Craig R. McClanahan */ public class LoginConfig implements Serializable { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Construct a new LoginConfig with default properties. */ public LoginConfig() { super(); } /** * Construct a new LoginConfig with the specified properties. * * @param authMethod The authentication method * @param realmName The realm name * @param loginPage The login page URI * @param errorPage The error page URI */ public LoginConfig(String authMethod, String realmName, String loginPage, String errorPage) { super(); setAuthMethod(authMethod); setRealmName(realmName); setLoginPage(loginPage); setErrorPage(errorPage); } // ------------------------------------------------------------- Properties /** * The authentication method to use for application login. Must be * BASIC, DIGEST, FORM, or CLIENT-CERT. */ private String authMethod = null; public String getAuthMethod() { return (this.authMethod); } public void setAuthMethod(String authMethod) { this.authMethod = authMethod; } /** * The context-relative URI of the error page for form login. */ private String errorPage = null; public String getErrorPage() { return (this.errorPage); } public void setErrorPage(String errorPage) { // if ((errorPage == null) || !errorPage.startsWith("/")) // throw new IllegalArgumentException // ("Error Page resource path must start with a '/'"); this.errorPage = RequestUtil.URLDecode(errorPage); } /** * The context-relative URI of the login page for form login. */ private String loginPage = null; public String getLoginPage() { return (this.loginPage); } public void setLoginPage(String loginPage) { // if ((loginPage == null) || !loginPage.startsWith("/")) // throw new IllegalArgumentException // ("Login Page resource path must start with a '/'"); this.loginPage = RequestUtil.URLDecode(loginPage); } /** * The realm name used when challenging the user for authentication * credentials. */ private String realmName = null; public String getRealmName() { return (this.realmName); } public void setRealmName(String realmName) { this.realmName = realmName; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("LoginConfig["); sb.append("authMethod="); sb.append(authMethod); if (realmName != null) { sb.append(", realmName="); sb.append(realmName); } if (loginPage != null) { sb.append(", loginPage="); sb.append(loginPage); } if (errorPage != null) { sb.append(", errorPage="); sb.append(errorPage); } sb.append("]"); return (sb.toString()); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((authMethod == null) ? 0 : authMethod.hashCode()); result = prime * result + ((errorPage == null) ? 0 : errorPage.hashCode()); result = prime * result + ((loginPage == null) ? 0 : loginPage.hashCode()); result = prime * result + ((realmName == null) ? 0 : realmName.hashCode()); return result; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof LoginConfig)) return false; LoginConfig other = (LoginConfig) obj; if (authMethod == null) { if (other.authMethod != null) return false; } else if (!authMethod.equals(other.authMethod)) return false; if (errorPage == null) { if (other.errorPage != null) return false; } else if (!errorPage.equals(other.errorPage)) return false; if (loginPage == null) { if (other.loginPage != null) return false; } else if (!loginPage.equals(other.loginPage)) return false; if (realmName == null) { if (other.realmName != null) return false; } else if (!realmName.equals(other.realmName)) return false; return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/WebXml.java0000644000175100017510000030641112276431250023214 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.net.URL; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletContext; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.servlet.descriptor.JspPropertyGroupDescriptor; import javax.servlet.descriptor.TaglibDescriptor; import org.apache.catalina.Context; import org.apache.catalina.Wrapper; import org.apache.catalina.core.ApplicationJspPropertyGroupDescriptor; import org.apache.catalina.core.ApplicationTaglibDescriptor; import org.apache.tomcat.util.descriptor.XmlIdentifiers; import org.apache.tomcat.util.res.StringManager; /** * Representation of common elements of web.xml and web-fragment.xml. Provides * a repository for parsed data before the elements are merged. * Validation is spread between multiple classes: * The digester checks for structural correctness (eg single login-config) * This class checks for invalid duplicates (eg filter/servlet names) * StandardContext will check validity of values (eg URL formats etc) */ public class WebXml { protected static final String ORDER_OTHERS = "org.apache.catalina.order.others"; private static final StringManager sm = StringManager.getManager(Constants.Package); private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog(WebXml.class); // Global defaults are overridable but Servlets and Servlet mappings need to // be unique. Duplicates normally trigger an error. This flag indicates if // newly added Servlet elements are marked as overridable. private boolean overridable = false; public boolean isOverridable() { return overridable; } public void setOverridable(boolean overridable) { this.overridable = overridable; } // web.xml only elements // Absolute Ordering private Set absoluteOrdering = null; public void createAbsoluteOrdering() { if (absoluteOrdering == null) { absoluteOrdering = new LinkedHashSet(); } } public void addAbsoluteOrdering(String fragmentName) { createAbsoluteOrdering(); absoluteOrdering.add(fragmentName); } public void addAbsoluteOrderingOthers() { createAbsoluteOrdering(); absoluteOrdering.add(ORDER_OTHERS); } public Set getAbsoluteOrdering() { return absoluteOrdering; } // web-fragment.xml only elements // Relative ordering private Set after = new LinkedHashSet(); public void addAfterOrdering(String fragmentName) { after.add(fragmentName); } public void addAfterOrderingOthers() { if (before.contains(ORDER_OTHERS)) { throw new IllegalArgumentException(sm.getString( "webXml.multipleOther")); } after.add(ORDER_OTHERS); } public Set getAfterOrdering() { return after; } private Set before = new LinkedHashSet(); public void addBeforeOrdering(String fragmentName) { before.add(fragmentName); } public void addBeforeOrderingOthers() { if (after.contains(ORDER_OTHERS)) { throw new IllegalArgumentException(sm.getString( "webXml.multipleOther")); } before.add(ORDER_OTHERS); } public Set getBeforeOrdering() { return before; } // Common elements and attributes // Required attribute of web-app element public String getVersion() { StringBuilder sb = new StringBuilder(3); sb.append(majorVersion); sb.append('.'); sb.append(minorVersion); return sb.toString(); } /** * Set the version for this web.xml file * @param version Values of null will be ignored */ public void setVersion(String version) { if (version == null) { return; } if ("2.4".equals(version)) { majorVersion = 2; minorVersion = 4; } else if ("2.5".equals(version)) { majorVersion = 2; minorVersion = 5; } else if ("3.0".equals(version)) { majorVersion = 3; minorVersion = 0; } else { log.warn(sm.getString("webXml.version.unknown", version)); } } // Optional publicId attribute private String publicId = null; public String getPublicId() { return publicId; } public void setPublicId(String publicId) { // Update major and minor version if (publicId == null) { return; } if (XmlIdentifiers.WEB_22_PUBLIC.equals(publicId)) { majorVersion = 2; minorVersion = 2; this.publicId = publicId; } else if (XmlIdentifiers.WEB_23_PUBLIC.equals(publicId)) { majorVersion = 2; minorVersion = 3; this.publicId = publicId; } else { log.warn(sm.getString("webXml.unrecognisedPublicId", publicId)); } } // Optional metadata-complete attribute private boolean metadataComplete = false; public boolean isMetadataComplete() { return metadataComplete; } public void setMetadataComplete(boolean metadataComplete) { this.metadataComplete = metadataComplete; } // Optional name element private String name = null; public String getName() { return name; } public void setName(String name) { if (ORDER_OTHERS.equalsIgnoreCase(name)) { // This is unusual. This name will be ignored. Log the fact. log.warn(sm.getString("webXml.reservedName", name)); } else { this.name = name; } } // Derived major and minor version attributes // Default to 3.0 until we know otherwise private int majorVersion = 3; private int minorVersion = 0; public int getMajorVersion() { return majorVersion; } public int getMinorVersion() { return minorVersion; } // web-app elements // TODO: Ignored elements: // - description // - icon // display-name - TODO should support multiple with language private String displayName = null; public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } // distributable private boolean distributable = false; public boolean isDistributable() { return distributable; } public void setDistributable(boolean distributable) { this.distributable = distributable; } // context-param // TODO: description (multiple with language) is ignored private Map contextParams = new HashMap(); public void addContextParam(String param, String value) { contextParams.put(param, value); } public Map getContextParams() { return contextParams; } // filter // TODO: Should support multiple description elements with language // TODO: Should support multiple display-name elements with language // TODO: Should support multiple icon elements // TODO: Description for init-param is ignored private Map filters = new LinkedHashMap(); public void addFilter(FilterDef filter) { if (filters.containsKey(filter.getFilterName())) { // Filter names must be unique within a web(-fragment).xml throw new IllegalArgumentException( sm.getString("webXml.duplicateFilter", filter.getFilterName())); } filters.put(filter.getFilterName(), filter); } public Map getFilters() { return filters; } // filter-mapping private Set filterMaps = new LinkedHashSet(); private Set filterMappingNames = new HashSet(); public void addFilterMapping(FilterMap filterMap) { filterMaps.add(filterMap); filterMappingNames.add(filterMap.getFilterName()); } public Set getFilterMappings() { return filterMaps; } // listener // TODO: description (multiple with language) is ignored // TODO: display-name (multiple with language) is ignored // TODO: icon (multiple) is ignored private Set listeners = new LinkedHashSet(); public void addListener(String className) { listeners.add(className); } public Set getListeners() { return listeners; } // servlet // TODO: description (multiple with language) is ignored // TODO: display-name (multiple with language) is ignored // TODO: icon (multiple) is ignored // TODO: init-param/description (multiple with language) is ignored // TODO: security-role-ref/description (multiple with language) is ignored private Map servlets = new HashMap(); public void addServlet(ServletDef servletDef) { servlets.put(servletDef.getServletName(), servletDef); if (overridable) { servletDef.setOverridable(overridable); } } public Map getServlets() { return servlets; } // servlet-mapping private Map servletMappings = new HashMap(); private Set servletMappingNames = new HashSet(); public void addServletMapping(String urlPattern, String servletName) { String oldServletName = servletMappings.put(urlPattern, servletName); if (oldServletName != null) { // Duplicate mapping. As per clarification from the Servlet EG, // deployment should fail. throw new IllegalArgumentException(sm.getString( "webXml.duplicateServletMapping", oldServletName, servletName, urlPattern)); } servletMappingNames.add(servletName); } public Map getServletMappings() { return servletMappings; } // session-config // Digester will check there is only one of these private SessionConfig sessionConfig = new SessionConfig(); public void setSessionConfig(SessionConfig sessionConfig) { this.sessionConfig = sessionConfig; } public SessionConfig getSessionConfig() { return sessionConfig; } // mime-mapping private Map mimeMappings = new HashMap(); public void addMimeMapping(String extension, String mimeType) { mimeMappings.put(extension, mimeType); } public Map getMimeMappings() { return mimeMappings; } // welcome-file-list merge control private boolean replaceWelcomeFiles = false; private boolean alwaysAddWelcomeFiles = true; /** * When merging/parsing web.xml files into this web.xml should the current * set be completely replaced? */ public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) { this.replaceWelcomeFiles = replaceWelcomeFiles; } /** * When merging from this web.xml, should the welcome files be added to the * target web.xml even if it already contains welcome file definitions. */ public void setAlwaysAddWelcomeFiles(boolean alwaysAddWelcomeFiles) { this.alwaysAddWelcomeFiles = alwaysAddWelcomeFiles; } // welcome-file-list private Set welcomeFiles = new LinkedHashSet(); public void addWelcomeFile(String welcomeFile) { if (replaceWelcomeFiles) { welcomeFiles.clear(); replaceWelcomeFiles = false; } welcomeFiles.add(welcomeFile); } public Set getWelcomeFiles() { return welcomeFiles; } // error-page private Map errorPages = new HashMap(); public void addErrorPage(ErrorPage errorPage) { errorPages.put(errorPage.getName(), errorPage); } public Map getErrorPages() { return errorPages; } // Digester will check there is only one jsp-config // jsp-config/taglib or taglib (2.3 and earlier) private Map taglibs = new HashMap(); public void addTaglib(String uri, String location) { if (taglibs.containsKey(uri)) { // Taglib URIs must be unique within a web(-fragment).xml throw new IllegalArgumentException( sm.getString("webXml.duplicateTaglibUri", uri)); } taglibs.put(uri, location); } public Map getTaglibs() { return taglibs; } // jsp-config/jsp-property-group private Set jspPropertyGroups = new LinkedHashSet(); public void addJspPropertyGroup(JspPropertyGroup propertyGroup) { jspPropertyGroups.add(propertyGroup); } public Set getJspPropertyGroups() { return jspPropertyGroups; } // security-constraint // TODO: Should support multiple display-name elements with language // TODO: Should support multiple description elements with language private Set securityConstraints = new HashSet(); public void addSecurityConstraint(SecurityConstraint securityConstraint) { securityConstraints.add(securityConstraint); } public Set getSecurityConstraints() { return securityConstraints; } // login-config // Digester will check there is only one of these private LoginConfig loginConfig = null; public void setLoginConfig(LoginConfig loginConfig) { this.loginConfig = loginConfig; } public LoginConfig getLoginConfig() { return loginConfig; } // security-role // TODO: description (multiple with language) is ignored private Set securityRoles = new HashSet(); public void addSecurityRole(String securityRole) { securityRoles.add(securityRole); } public Set getSecurityRoles() { return securityRoles; } // env-entry // TODO: Should support multiple description elements with language private Map envEntries = new HashMap(); public void addEnvEntry(ContextEnvironment envEntry) { if (envEntries.containsKey(envEntry.getName())) { // env-entry names must be unique within a web(-fragment).xml throw new IllegalArgumentException( sm.getString("webXml.duplicateEnvEntry", envEntry.getName())); } envEntries.put(envEntry.getName(),envEntry); } public Map getEnvEntries() { return envEntries; } // ejb-ref // TODO: Should support multiple description elements with language private Map ejbRefs = new HashMap(); public void addEjbRef(ContextEjb ejbRef) { ejbRefs.put(ejbRef.getName(),ejbRef); } public Map getEjbRefs() { return ejbRefs; } // ejb-local-ref // TODO: Should support multiple description elements with language private Map ejbLocalRefs = new HashMap(); public void addEjbLocalRef(ContextLocalEjb ejbLocalRef) { ejbLocalRefs.put(ejbLocalRef.getName(),ejbLocalRef); } public Map getEjbLocalRefs() { return ejbLocalRefs; } // service-ref // TODO: Should support multiple description elements with language // TODO: Should support multiple display-names elements with language // TODO: Should support multiple icon elements ??? private Map serviceRefs = new HashMap(); public void addServiceRef(ContextService serviceRef) { serviceRefs.put(serviceRef.getName(), serviceRef); } public Map getServiceRefs() { return serviceRefs; } // resource-ref // TODO: Should support multiple description elements with language private Map resourceRefs = new HashMap(); public void addResourceRef(ContextResource resourceRef) { if (resourceRefs.containsKey(resourceRef.getName())) { // resource-ref names must be unique within a web(-fragment).xml throw new IllegalArgumentException( sm.getString("webXml.duplicateResourceRef", resourceRef.getName())); } resourceRefs.put(resourceRef.getName(), resourceRef); } public Map getResourceRefs() { return resourceRefs; } // resource-env-ref // TODO: Should support multiple description elements with language private Map resourceEnvRefs = new HashMap(); public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) { if (resourceEnvRefs.containsKey(resourceEnvRef.getName())) { // resource-env-ref names must be unique within a web(-fragment).xml throw new IllegalArgumentException( sm.getString("webXml.duplicateResourceEnvRef", resourceEnvRef.getName())); } resourceEnvRefs.put(resourceEnvRef.getName(), resourceEnvRef); } public Map getResourceEnvRefs() { return resourceEnvRefs; } // message-destination-ref // TODO: Should support multiple description elements with language private Map messageDestinationRefs = new HashMap(); public void addMessageDestinationRef( MessageDestinationRef messageDestinationRef) { if (messageDestinationRefs.containsKey( messageDestinationRef.getName())) { // message-destination-ref names must be unique within a // web(-fragment).xml throw new IllegalArgumentException(sm.getString( "webXml.duplicateMessageDestinationRef", messageDestinationRef.getName())); } messageDestinationRefs.put(messageDestinationRef.getName(), messageDestinationRef); } public Map getMessageDestinationRefs() { return messageDestinationRefs; } // message-destination // TODO: Should support multiple description elements with language // TODO: Should support multiple display-names elements with language // TODO: Should support multiple icon elements ??? private Map messageDestinations = new HashMap(); public void addMessageDestination( MessageDestination messageDestination) { if (messageDestinations.containsKey( messageDestination.getName())) { // message-destination names must be unique within a // web(-fragment).xml throw new IllegalArgumentException( sm.getString("webXml.duplicateMessageDestination", messageDestination.getName())); } messageDestinations.put(messageDestination.getName(), messageDestination); } public Map getMessageDestinations() { return messageDestinations; } // locale-encoding-mapping-list private Map localeEncodingMappings = new HashMap(); public void addLocaleEncodingMapping(String locale, String encoding) { localeEncodingMappings.put(locale, encoding); } public Map getLocalEncodingMappings() { return localeEncodingMappings; } // post-construct elements private Map postConstructMethods = new HashMap(); public void addPostConstructMethods(String clazz, String method) { if (!postConstructMethods.containsKey(clazz)) { postConstructMethods.put(clazz, method); } } public Map getPostConstructMethods() { return postConstructMethods; } // pre-destroy elements private Map preDestroyMethods = new HashMap(); public void addPreDestroyMethods(String clazz, String method) { if (!preDestroyMethods.containsKey(clazz)) { preDestroyMethods.put(clazz, method); } } public Map getPreDestroyMethods() { return preDestroyMethods; } // Attributes not defined in web.xml or web-fragment.xml // URL of JAR / exploded JAR for this web-fragment private URL uRL = null; public void setURL(URL url) { this.uRL = url; } public URL getURL() { return uRL; } // Name of jar file private String jarName = null; public void setJarName(String jarName) { this.jarName = jarName; } public String getJarName() { return jarName; } @Override public String toString() { StringBuilder buf = new StringBuilder(32); buf.append("Name: "); buf.append(getName()); buf.append(", URL: "); buf.append(getURL()); return buf.toString(); } private static final String INDENT2 = " "; private static final String INDENT4 = " "; private static final String INDENT6 = " "; /** * Generate a web.xml in String form that matches the representation stored * in this object. * * @return The complete contents of web.xml as a String */ public String toXml() { StringBuilder sb = new StringBuilder(2048); // TODO - Various, icon, description etc elements are skipped - mainly // because they are ignored when web.xml is parsed - see above // Declaration sb.append("\n"); // Root element if (publicId != null) { sb.append("\n"); sb.append(""); } else { String javaeeNamespace = null; String webXmlSchemaLocation = null; String version = getVersion(); if ("2.4".equals(version)) { javaeeNamespace = XmlIdentifiers.JAVAEE_1_4_NS; webXmlSchemaLocation = XmlIdentifiers.WEB_24_XSD; } else if ("2.5".equals(version)) { javaeeNamespace = XmlIdentifiers.JAVAEE_5_NS; webXmlSchemaLocation = XmlIdentifiers.WEB_25_XSD; } else if ("3.0".equals(version)) { javaeeNamespace = XmlIdentifiers.JAVAEE_6_NS; webXmlSchemaLocation = XmlIdentifiers.WEB_30_XSD; } sb.append("\n\n"); } else { sb.append("\n metadata-complete=\"true\">\n\n"); } } appendElement(sb, INDENT2, "display-name", displayName); if (isDistributable()) { sb.append(" \n\n"); } for (Map.Entry entry : contextParams.entrySet()) { sb.append(" \n"); appendElement(sb, INDENT4, "param-name", entry.getKey()); appendElement(sb, INDENT4, "param-value", entry.getValue()); sb.append(" \n"); } sb.append('\n'); for (Map.Entry entry : filters.entrySet()) { FilterDef filterDef = entry.getValue(); sb.append(" \n"); appendElement(sb, INDENT4, "description", filterDef.getDescription()); appendElement(sb, INDENT4, "display-name", filterDef.getDisplayName()); appendElement(sb, INDENT4, "filter-name", filterDef.getFilterName()); appendElement(sb, INDENT4, "filter-class", filterDef.getFilterClass()); appendElement(sb, INDENT4, "async-supported", filterDef.getAsyncSupported()); for (Map.Entry param : filterDef.getParameterMap().entrySet()) { sb.append(" \n"); appendElement(sb, INDENT6, "param-name", param.getKey()); appendElement(sb, INDENT6, "param-value", param.getValue()); sb.append(" \n"); } sb.append(" \n"); } sb.append('\n'); for (FilterMap filterMap : filterMaps) { sb.append(" \n"); appendElement(sb, INDENT4, "filter-name", filterMap.getFilterName()); if (filterMap.getMatchAllServletNames()) { sb.append(" *\n"); } else { for (String servletName : filterMap.getServletNames()) { appendElement(sb, INDENT4, "servlet-name", servletName); } } if (filterMap.getMatchAllUrlPatterns()) { sb.append(" *\n"); } else { for (String urlPattern : filterMap.getURLPatterns()) { appendElement(sb, INDENT4, "url-pattern", urlPattern); } } for (String dispatcher : filterMap.getDispatcherNames()) { appendElement(sb, INDENT4, "dispatcher", dispatcher); } sb.append(" \n"); } sb.append('\n'); for (String listener : listeners) { sb.append(" \n"); appendElement(sb, INDENT4, "listener-class", listener); sb.append(" \n"); } sb.append('\n'); for (Map.Entry entry : servlets.entrySet()) { ServletDef servletDef = entry.getValue(); sb.append(" \n"); appendElement(sb, INDENT4, "description", servletDef.getDescription()); appendElement(sb, INDENT4, "display-name", servletDef.getDisplayName()); appendElement(sb, INDENT4, "servlet-name", entry.getKey()); appendElement(sb, INDENT4, "servlet-class", servletDef.getServletClass()); appendElement(sb, INDENT4, "jsp-file", servletDef.getJspFile()); for (Map.Entry param : servletDef.getParameterMap().entrySet()) { sb.append(" \n"); appendElement(sb, INDENT6, "param-name", param.getKey()); appendElement(sb, INDENT6, "param-value", param.getValue()); sb.append(" \n"); } appendElement(sb, INDENT4, "load-on-startup", servletDef.getLoadOnStartup()); appendElement(sb, INDENT4, "enabled", servletDef.getEnabled()); appendElement(sb, INDENT4, "async-supported", servletDef.getAsyncSupported()); if (servletDef.getRunAs() != null) { sb.append(" \n"); appendElement(sb, INDENT6, "role-name", servletDef.getRunAs()); sb.append(" \n"); } for (SecurityRoleRef roleRef : servletDef.getSecurityRoleRefs()) { sb.append(" \n"); appendElement(sb, INDENT6, "role-name", roleRef.getName()); appendElement(sb, INDENT6, "role-link", roleRef.getLink()); sb.append(" \n"); } MultipartDef multipartDef = servletDef.getMultipartDef(); if (multipartDef != null) { sb.append(" \n"); appendElement(sb, INDENT6, "location", multipartDef.getLocation()); appendElement(sb, INDENT6, "max-file-size", multipartDef.getMaxFileSize()); appendElement(sb, INDENT6, "max-request-size", multipartDef.getMaxRequestSize()); appendElement(sb, INDENT6, "file-size-threshold", multipartDef.getFileSizeThreshold()); sb.append(" \n"); } sb.append(" \n"); } sb.append('\n'); for (Map.Entry entry : servletMappings.entrySet()) { sb.append(" \n"); appendElement(sb, INDENT4, "servlet-name", entry.getValue()); appendElement(sb, INDENT4, "url-pattern", entry.getKey()); sb.append(" \n"); } sb.append('\n'); if (sessionConfig != null) { sb.append(" \n"); appendElement(sb, INDENT4, "session-timeout", sessionConfig.getSessionTimeout()); if (majorVersion >= 3) { sb.append(" \n"); appendElement(sb, INDENT6, "name", sessionConfig.getCookieName()); appendElement(sb, INDENT6, "domain", sessionConfig.getCookieDomain()); appendElement(sb, INDENT6, "path", sessionConfig.getCookiePath()); appendElement(sb, INDENT6, "comment", sessionConfig.getCookieComment()); appendElement(sb, INDENT6, "http-only", sessionConfig.getCookieHttpOnly()); appendElement(sb, INDENT6, "secure", sessionConfig.getCookieSecure()); appendElement(sb, INDENT6, "max-age", sessionConfig.getCookieMaxAge()); sb.append(" \n"); for (SessionTrackingMode stm : sessionConfig.getSessionTrackingModes()) { appendElement(sb, INDENT4, "tracking-mode", stm.name()); } } sb.append(" \n\n"); } for (Map.Entry entry : mimeMappings.entrySet()) { sb.append(" \n"); appendElement(sb, INDENT4, "extension", entry.getKey()); appendElement(sb, INDENT4, "mime-type", entry.getValue()); sb.append(" \n"); } sb.append('\n'); if (welcomeFiles.size() > 0) { sb.append(" \n"); for (String welcomeFile : welcomeFiles) { appendElement(sb, INDENT4, "welcome-file", welcomeFile); } sb.append(" \n\n"); } for (ErrorPage errorPage : errorPages.values()) { sb.append(" \n"); if (errorPage.getExceptionType() == null) { appendElement(sb, INDENT4, "error-code", Integer.toString(errorPage.getErrorCode())); } else { appendElement(sb, INDENT4, "exception-type", errorPage.getExceptionType()); } appendElement(sb, INDENT4, "location", errorPage.getLocation()); sb.append(" \n"); } sb.append('\n'); if (taglibs.size() > 0 || jspPropertyGroups.size() > 0) { sb.append(" \n"); for (Map.Entry entry : taglibs.entrySet()) { sb.append(" \n"); appendElement(sb, INDENT6, "taglib-uri", entry.getKey()); appendElement(sb, INDENT6, "taglib-location", entry.getValue()); sb.append(" \n"); } for (JspPropertyGroup jpg : jspPropertyGroups) { sb.append(" \n"); for (String urlPattern : jpg.getUrlPatterns()) { appendElement(sb, INDENT6, "url-pattern", urlPattern); } appendElement(sb, INDENT6, "el-ignored", jpg.getElIgnored()); appendElement(sb, INDENT6, "page-encoding", jpg.getPageEncoding()); appendElement(sb, INDENT6, "scripting-invalid", jpg.getScriptingInvalid()); appendElement(sb, INDENT6, "is-xml", jpg.getIsXml()); for (String prelude : jpg.getIncludePreludes()) { appendElement(sb, INDENT6, "include-prelude", prelude); } for (String coda : jpg.getIncludeCodas()) { appendElement(sb, INDENT6, "include-coda", coda); } appendElement(sb, INDENT6, "deferred-syntax-allowed-as-literal", jpg.getDeferredSyntax()); appendElement(sb, INDENT6, "trim-directive-whitespaces", jpg.getTrimWhitespace()); appendElement(sb, INDENT6, "default-content-type", jpg.getDefaultContentType()); appendElement(sb, INDENT6, "buffer", jpg.getBuffer()); appendElement(sb, INDENT6, "error-on-undeclared-namespace", jpg.getErrorOnUndeclaredNamespace()); sb.append(" \n"); } sb.append(" \n\n"); } for (SecurityConstraint constraint : securityConstraints) { sb.append(" \n"); appendElement(sb, INDENT4, "display-name", constraint.getDisplayName()); for (SecurityCollection collection : constraint.findCollections()) { sb.append(" \n"); appendElement(sb, INDENT6, "web-resource-name", collection.getName()); appendElement(sb, INDENT6, "description", collection.getDescription()); for (String urlPattern : collection.findPatterns()) { appendElement(sb, INDENT6, "url-pattern", urlPattern); } for (String method : collection.findMethods()) { appendElement(sb, INDENT6, "http-method", method); } for (String method : collection.findOmittedMethods()) { appendElement(sb, INDENT6, "http-method-omission", method); } sb.append(" \n"); } if (constraint.findAuthRoles().length > 0) { sb.append(" \n"); for (String role : constraint.findAuthRoles()) { appendElement(sb, INDENT6, "role-name", role); } sb.append(" \n"); } if (constraint.getUserConstraint() != null) { sb.append(" \n"); appendElement(sb, INDENT6, "transport-guarantee", constraint.getUserConstraint()); sb.append(" \n"); } sb.append(" \n"); } sb.append('\n'); if (loginConfig != null) { sb.append(" \n"); appendElement(sb, INDENT4, "auth-method", loginConfig.getAuthMethod()); appendElement(sb,INDENT4, "realm-name", loginConfig.getRealmName()); if (loginConfig.getErrorPage() != null || loginConfig.getLoginPage() != null) { sb.append(" \n"); appendElement(sb, INDENT6, "form-login-page", loginConfig.getLoginPage()); appendElement(sb, INDENT6, "form-error-page", loginConfig.getErrorPage()); sb.append(" \n"); } sb.append(" \n\n"); } for (String roleName : securityRoles) { sb.append(" \n"); appendElement(sb, INDENT4, "role-name", roleName); sb.append(" \n"); } for (ContextEnvironment envEntry : envEntries.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", envEntry.getDescription()); appendElement(sb, INDENT4, "env-entry-name", envEntry.getName()); appendElement(sb, INDENT4, "env-entry-type", envEntry.getType()); appendElement(sb, INDENT4, "env-entry-value", envEntry.getValue()); // TODO mapped-name for (InjectionTarget target : envEntry.getInjectionTargets()) { sb.append(" \n"); appendElement(sb, INDENT6, "injection-target-class", target.getTargetClass()); appendElement(sb, INDENT6, "injection-target-name", target.getTargetName()); sb.append(" \n"); } // TODO lookup-name sb.append(" \n"); } sb.append('\n'); for (ContextEjb ejbRef : ejbRefs.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", ejbRef.getDescription()); appendElement(sb, INDENT4, "ejb-ref-name", ejbRef.getName()); appendElement(sb, INDENT4, "ejb-ref-type", ejbRef.getType()); appendElement(sb, INDENT4, "home", ejbRef.getHome()); appendElement(sb, INDENT4, "remote", ejbRef.getRemote()); appendElement(sb, INDENT4, "ejb-link", ejbRef.getLink()); // TODO mapped-name for (InjectionTarget target : ejbRef.getInjectionTargets()) { sb.append(" \n"); appendElement(sb, INDENT6, "injection-target-class", target.getTargetClass()); appendElement(sb, INDENT6, "injection-target-name", target.getTargetName()); sb.append(" \n"); } // TODO lookup-name sb.append(" \n"); } sb.append('\n'); for (ContextLocalEjb ejbLocalRef : ejbLocalRefs.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", ejbLocalRef.getDescription()); appendElement(sb, INDENT4, "ejb-ref-name", ejbLocalRef.getName()); appendElement(sb, INDENT4, "ejb-ref-type", ejbLocalRef.getType()); appendElement(sb, INDENT4, "local-home", ejbLocalRef.getHome()); appendElement(sb, INDENT4, "local", ejbLocalRef.getLocal()); appendElement(sb, INDENT4, "ejb-link", ejbLocalRef.getLink()); // TODO mapped-name for (InjectionTarget target : ejbLocalRef.getInjectionTargets()) { sb.append(" \n"); appendElement(sb, INDENT6, "injection-target-class", target.getTargetClass()); appendElement(sb, INDENT6, "injection-target-name", target.getTargetName()); sb.append(" \n"); } // TODO lookup-name sb.append(" \n"); } sb.append('\n'); for (ContextService serviceRef : serviceRefs.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", serviceRef.getDescription()); appendElement(sb, INDENT4, "display-name", serviceRef.getDisplayname()); appendElement(sb, INDENT4, "service-ref-name", serviceRef.getName()); appendElement(sb, INDENT4, "service-interface", serviceRef.getInterface()); appendElement(sb, INDENT4, "service-ref-type", serviceRef.getType()); appendElement(sb, INDENT4, "wsdl-file", serviceRef.getWsdlfile()); appendElement(sb, INDENT4, "jaxrpc-mapping-file", serviceRef.getJaxrpcmappingfile()); String qname = serviceRef.getServiceqnameNamespaceURI(); if (qname != null) { qname = qname + ":"; } qname = qname + serviceRef.getServiceqnameLocalpart(); appendElement(sb, INDENT4, "service-qname", qname); Iterator endpointIter = serviceRef.getServiceendpoints(); while (endpointIter.hasNext()) { String endpoint = endpointIter.next(); sb.append(" \n"); appendElement(sb, INDENT6, "service-endpoint-interface", endpoint); appendElement(sb, INDENT6, "port-component-link", serviceRef.getProperty(endpoint)); sb.append(" \n"); } Iterator handlerIter = serviceRef.getHandlers(); while (handlerIter.hasNext()) { String handler = handlerIter.next(); sb.append(" \n"); ContextHandler ch = serviceRef.getHandler(handler); appendElement(sb, INDENT6, "handler-name", ch.getName()); appendElement(sb, INDENT6, "handler-class", ch.getHandlerclass()); sb.append(" \n"); } // TODO handler-chains // TODO mapped-name for (InjectionTarget target : serviceRef.getInjectionTargets()) { sb.append(" \n"); appendElement(sb, INDENT6, "injection-target-class", target.getTargetClass()); appendElement(sb, INDENT6, "injection-target-name", target.getTargetName()); sb.append(" \n"); } // TODO lookup-name sb.append(" \n"); } sb.append('\n'); for (ContextResource resourceRef : resourceRefs.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", resourceRef.getDescription()); appendElement(sb, INDENT4, "res-ref-name", resourceRef.getName()); appendElement(sb, INDENT4, "res-type", resourceRef.getType()); appendElement(sb, INDENT4, "res-auth", resourceRef.getAuth()); appendElement(sb, INDENT4, "res-sharing-scope", resourceRef.getScope()); // TODO mapped-name for (InjectionTarget target : resourceRef.getInjectionTargets()) { sb.append(" \n"); appendElement(sb, INDENT6, "injection-target-class", target.getTargetClass()); appendElement(sb, INDENT6, "injection-target-name", target.getTargetName()); sb.append(" \n"); } // TODO lookup-name sb.append(" \n"); } sb.append('\n'); for (ContextResourceEnvRef resourceEnvRef : resourceEnvRefs.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", resourceEnvRef.getDescription()); appendElement(sb, INDENT4, "resource-env-ref-name", resourceEnvRef.getName()); appendElement(sb, INDENT4, "resource-env-ref-type", resourceEnvRef.getType()); // TODO mapped-name for (InjectionTarget target : resourceEnvRef.getInjectionTargets()) { sb.append(" \n"); appendElement(sb, INDENT6, "injection-target-class", target.getTargetClass()); appendElement(sb, INDENT6, "injection-target-name", target.getTargetName()); sb.append(" \n"); } // TODO lookup-name sb.append(" \n"); } sb.append('\n'); if (!postConstructMethods.isEmpty()) { for (Entry entry : postConstructMethods .entrySet()) { sb.append(" \n"); appendElement(sb, INDENT4, "lifecycle-callback-class", entry.getKey()); appendElement(sb, INDENT4, "lifecycle-callback-method", entry.getValue()); sb.append(" \n"); } sb.append('\n'); } if (!preDestroyMethods.isEmpty()) { for (Entry entry : preDestroyMethods .entrySet()) { sb.append(" \n"); appendElement(sb, INDENT4, "lifecycle-callback-class", entry.getKey()); appendElement(sb, INDENT4, "lifecycle-callback-method", entry.getValue()); sb.append(" \n"); } sb.append('\n'); } for (MessageDestinationRef mdr : messageDestinationRefs.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", mdr.getDescription()); appendElement(sb, INDENT4, "message-destination-ref-name", mdr.getName()); appendElement(sb, INDENT4, "message-destination-type", mdr.getType()); appendElement(sb, INDENT4, "message-destination-usage", mdr.getUsage()); appendElement(sb, INDENT4, "message-destination-link", mdr.getLink()); // TODO mapped-name for (InjectionTarget target : mdr.getInjectionTargets()) { sb.append(" \n"); appendElement(sb, INDENT6, "injection-target-class", target.getTargetClass()); appendElement(sb, INDENT6, "injection-target-name", target.getTargetName()); sb.append(" \n"); } // TODO lookup-name sb.append(" \n"); } sb.append('\n'); for (MessageDestination md : messageDestinations.values()) { sb.append(" \n"); appendElement(sb, INDENT4, "description", md.getDescription()); appendElement(sb, INDENT4, "display-name", md.getDisplayName()); appendElement(sb, INDENT4, "message-destination-name", md.getName()); // TODO mapped-name sb.append(" \n"); } sb.append('\n'); if (localeEncodingMappings.size() > 0) { sb.append(" \n"); for (Map.Entry entry : localeEncodingMappings.entrySet()) { sb.append(" \n"); appendElement(sb, INDENT6, "locale", entry.getKey()); appendElement(sb, INDENT6, "encoding", entry.getValue()); sb.append(" \n"); } sb.append(" \n"); } sb.append(""); return sb.toString(); } private static void appendElement(StringBuilder sb, String indent, String elementName, String value) { if (value == null || value.length() == 0) return; sb.append(indent); sb.append('<'); sb.append(elementName); sb.append('>'); sb.append(escapeXml(value)); sb.append("\n"); } private static void appendElement(StringBuilder sb, String indent, String elementName, Object value) { if (value == null) return; appendElement(sb, indent, elementName, value.toString()); } /** * Escape the 5 entities defined by XML. */ private static String escapeXml(String s) { if (s == null) return null; StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '<') { sb.append("<"); } else if (c == '>') { sb.append(">"); } else if (c == '\'') { sb.append("'"); } else if (c == '&') { sb.append("&"); } else if (c == '"') { sb.append("""); } else { sb.append(c); } } return sb.toString(); } /** * Configure a {@link Context} using the stored web.xml representation. * * @param context The context to be configured */ public void configureContext(Context context) { // As far as possible, process in alphabetical order so it is easy to // check everything is present // Some validation depends on correct public ID context.setPublicId(publicId); // Everything else in order context.setEffectiveMajorVersion(getMajorVersion()); context.setEffectiveMinorVersion(getMinorVersion()); for (Entry entry : contextParams.entrySet()) { context.addParameter(entry.getKey(), entry.getValue()); } context.setDisplayName(displayName); context.setDistributable(distributable); for (ContextLocalEjb ejbLocalRef : ejbLocalRefs.values()) { context.getNamingResources().addLocalEjb(ejbLocalRef); } for (ContextEjb ejbRef : ejbRefs.values()) { context.getNamingResources().addEjb(ejbRef); } for (ContextEnvironment environment : envEntries.values()) { context.getNamingResources().addEnvironment(environment); } for (ErrorPage errorPage : errorPages.values()) { context.addErrorPage(errorPage); } for (FilterDef filter : filters.values()) { if (filter.getAsyncSupported() == null) { filter.setAsyncSupported("false"); } context.addFilterDef(filter); } for (FilterMap filterMap : filterMaps) { context.addFilterMap(filterMap); } for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) { JspPropertyGroupDescriptor descriptor = new ApplicationJspPropertyGroupDescriptor(jspPropertyGroup); context.getJspConfigDescriptor().getJspPropertyGroups().add( descriptor); } for (String listener : listeners) { context.addApplicationListener( new ApplicationListener(listener, false)); } for (Entry entry : localeEncodingMappings.entrySet()) { context.addLocaleEncodingMappingParameter(entry.getKey(), entry.getValue()); } // Prevents IAE if (loginConfig != null) { context.setLoginConfig(loginConfig); } for (MessageDestinationRef mdr : messageDestinationRefs.values()) { context.getNamingResources().addMessageDestinationRef(mdr); } // messageDestinations were ignored in Tomcat 6, so ignore here context.setIgnoreAnnotations(metadataComplete); for (Entry entry : mimeMappings.entrySet()) { context.addMimeMapping(entry.getKey(), entry.getValue()); } // Name is just used for ordering for (ContextResourceEnvRef resource : resourceEnvRefs.values()) { context.getNamingResources().addResourceEnvRef(resource); } for (ContextResource resource : resourceRefs.values()) { context.getNamingResources().addResource(resource); } for (SecurityConstraint constraint : securityConstraints) { context.addConstraint(constraint); } for (String role : securityRoles) { context.addSecurityRole(role); } for (ContextService service : serviceRefs.values()) { context.getNamingResources().addService(service); } for (ServletDef servlet : servlets.values()) { Wrapper wrapper = context.createWrapper(); // Description is ignored // Display name is ignored // Icons are ignored // jsp-file gets passed to the JSP Servlet as an init-param if (servlet.getLoadOnStartup() != null) { wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue()); } if (servlet.getEnabled() != null) { wrapper.setEnabled(servlet.getEnabled().booleanValue()); } wrapper.setName(servlet.getServletName()); Map params = servlet.getParameterMap(); for (Entry entry : params.entrySet()) { wrapper.addInitParameter(entry.getKey(), entry.getValue()); } wrapper.setRunAs(servlet.getRunAs()); Set roleRefs = servlet.getSecurityRoleRefs(); for (SecurityRoleRef roleRef : roleRefs) { wrapper.addSecurityReference( roleRef.getName(), roleRef.getLink()); } wrapper.setServletClass(servlet.getServletClass()); MultipartDef multipartdef = servlet.getMultipartDef(); if (multipartdef != null) { if (multipartdef.getMaxFileSize() != null && multipartdef.getMaxRequestSize()!= null && multipartdef.getFileSizeThreshold() != null) { wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocation(), Long.parseLong(multipartdef.getMaxFileSize()), Long.parseLong(multipartdef.getMaxRequestSize()), Integer.parseInt( multipartdef.getFileSizeThreshold()))); } else { wrapper.setMultipartConfigElement(new MultipartConfigElement( multipartdef.getLocation())); } } if (servlet.getAsyncSupported() != null) { wrapper.setAsyncSupported( servlet.getAsyncSupported().booleanValue()); } wrapper.setOverridable(servlet.isOverridable()); context.addChild(wrapper); } for (Entry entry : servletMappings.entrySet()) { context.addServletMapping(entry.getKey(), entry.getValue()); } if (sessionConfig != null) { if (sessionConfig.getSessionTimeout() != null) { context.setSessionTimeout( sessionConfig.getSessionTimeout().intValue()); } SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig(); scc.setName(sessionConfig.getCookieName()); scc.setDomain(sessionConfig.getCookieDomain()); scc.setPath(sessionConfig.getCookiePath()); scc.setComment(sessionConfig.getCookieComment()); if (sessionConfig.getCookieHttpOnly() != null) { scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue()); } if (sessionConfig.getCookieSecure() != null) { scc.setSecure(sessionConfig.getCookieSecure().booleanValue()); } if (sessionConfig.getCookieMaxAge() != null) { scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue()); } if (sessionConfig.getSessionTrackingModes().size() > 0) { context.getServletContext().setSessionTrackingModes( sessionConfig.getSessionTrackingModes()); } } for (Entry entry : taglibs.entrySet()) { TaglibDescriptor descriptor = new ApplicationTaglibDescriptor( entry.getValue(), entry.getKey()); context.getJspConfigDescriptor().getTaglibs().add(descriptor); } // Context doesn't use version directly for (String welcomeFile : welcomeFiles) { /* * The following will result in a welcome file of "" so don't add * that to the context * * * */ if (welcomeFile != null && welcomeFile.length() > 0) { context.addWelcomeFile(welcomeFile); } } // Do this last as it depends on servlets for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) { String jspServletName = context.findServletMapping("*.jsp"); if (jspServletName == null) { jspServletName = "jsp"; } if (context.findChild(jspServletName) != null) { for (String urlPattern : jspPropertyGroup.getUrlPatterns()) { context.addServletMapping(urlPattern, jspServletName, true); } } else { if(log.isDebugEnabled()) { for (String urlPattern : jspPropertyGroup.getUrlPatterns()) { log.debug("Skiping " + urlPattern + " , no servlet " + jspServletName); } } } } for (Entry entry : postConstructMethods.entrySet()) { context.addPostConstructMethod(entry.getKey(), entry.getValue()); } for (Entry entry : preDestroyMethods.entrySet()) { context.addPreDestroyMethod(entry.getKey(), entry.getValue()); } } /** * Merge the supplied web fragments into this main web.xml. * * @param fragments The fragments to merge in * @return true if merge is successful, else * false */ public boolean merge(Set fragments) { // As far as possible, process in alphabetical order so it is easy to // check everything is present // Merge rules vary from element to element. See SRV.8.2.3 WebXml temp = new WebXml(); for (WebXml fragment : fragments) { if (!mergeMap(fragment.getContextParams(), contextParams, temp.getContextParams(), fragment, "Context Parameter")) { return false; } } contextParams.putAll(temp.getContextParams()); if (displayName == null) { for (WebXml fragment : fragments) { String value = fragment.getDisplayName(); if (value != null) { if (temp.getDisplayName() == null) { temp.setDisplayName(value); } else { log.error(sm.getString( "webXml.mergeConflictDisplayName", fragment.getName(), fragment.getURL())); return false; } } } displayName = temp.getDisplayName(); } if (distributable) { for (WebXml fragment : fragments) { if (!fragment.isDistributable()) { distributable = false; break; } } } for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getEjbLocalRefs(), ejbLocalRefs, temp.getEjbLocalRefs(), fragment)) { return false; } } ejbLocalRefs.putAll(temp.getEjbLocalRefs()); for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getEjbRefs(), ejbRefs, temp.getEjbRefs(), fragment)) { return false; } } ejbRefs.putAll(temp.getEjbRefs()); for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getEnvEntries(), envEntries, temp.getEnvEntries(), fragment)) { return false; } } envEntries.putAll(temp.getEnvEntries()); for (WebXml fragment : fragments) { if (!mergeMap(fragment.getErrorPages(), errorPages, temp.getErrorPages(), fragment, "Error Page")) { return false; } } errorPages.putAll(temp.getErrorPages()); // As per 'clarification' from the Servlet EG, filter definitions in the // main web.xml override those in fragments and those in fragments // override those in annotations List filterMapsToAdd = new ArrayList(); for (WebXml fragment : fragments) { for (FilterMap filterMap : fragment.getFilterMappings()) { if (!filterMappingNames.contains(filterMap.getFilterName())) { filterMapsToAdd.add(filterMap); } } } for (FilterMap filterMap : filterMapsToAdd) { // Additive addFilterMapping(filterMap); } for (WebXml fragment : fragments) { for (Map.Entry entry : fragment.getFilters().entrySet()) { if (filters.containsKey(entry.getKey())) { mergeFilter(entry.getValue(), filters.get(entry.getKey()), false); } else { if (temp.getFilters().containsKey(entry.getKey())) { if (!(mergeFilter(entry.getValue(), temp.getFilters().get(entry.getKey()), true))) { log.error(sm.getString( "webXml.mergeConflictFilter", entry.getKey(), fragment.getName(), fragment.getURL())); return false; } } else { temp.getFilters().put(entry.getKey(), entry.getValue()); } } } } filters.putAll(temp.getFilters()); for (WebXml fragment : fragments) { for (JspPropertyGroup jspPropertyGroup : fragment.getJspPropertyGroups()) { // Always additive addJspPropertyGroup(jspPropertyGroup); } } for (WebXml fragment : fragments) { for (String listener : fragment.getListeners()) { // Always additive addListener(listener); } } for (WebXml fragment : fragments) { if (!mergeMap(fragment.getLocalEncodingMappings(), localeEncodingMappings, temp.getLocalEncodingMappings(), fragment, "Locale Encoding Mapping")) { return false; } } localeEncodingMappings.putAll(temp.getLocalEncodingMappings()); if (getLoginConfig() == null) { LoginConfig tempLoginConfig = null; for (WebXml fragment : fragments) { LoginConfig fragmentLoginConfig = fragment.loginConfig; if (fragmentLoginConfig != null) { if (tempLoginConfig == null || fragmentLoginConfig.equals(tempLoginConfig)) { tempLoginConfig = fragmentLoginConfig; } else { log.error(sm.getString( "webXml.mergeConflictLoginConfig", fragment.getName(), fragment.getURL())); } } } loginConfig = tempLoginConfig; } for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getMessageDestinationRefs(), messageDestinationRefs, temp.getMessageDestinationRefs(), fragment)) { return false; } } messageDestinationRefs.putAll(temp.getMessageDestinationRefs()); for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getMessageDestinations(), messageDestinations, temp.getMessageDestinations(), fragment)) { return false; } } messageDestinations.putAll(temp.getMessageDestinations()); for (WebXml fragment : fragments) { if (!mergeMap(fragment.getMimeMappings(), mimeMappings, temp.getMimeMappings(), fragment, "Mime Mapping")) { return false; } } mimeMappings.putAll(temp.getMimeMappings()); for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getResourceEnvRefs(), resourceEnvRefs, temp.getResourceEnvRefs(), fragment)) { return false; } } resourceEnvRefs.putAll(temp.getResourceEnvRefs()); for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getResourceRefs(), resourceRefs, temp.getResourceRefs(), fragment)) { return false; } } resourceRefs.putAll(temp.getResourceRefs()); for (WebXml fragment : fragments) { for (SecurityConstraint constraint : fragment.getSecurityConstraints()) { // Always additive addSecurityConstraint(constraint); } } for (WebXml fragment : fragments) { for (String role : fragment.getSecurityRoles()) { // Always additive addSecurityRole(role); } } for (WebXml fragment : fragments) { if (!mergeResourceMap(fragment.getServiceRefs(), serviceRefs, temp.getServiceRefs(), fragment)) { return false; } } serviceRefs.putAll(temp.getServiceRefs()); // As per 'clarification' from the Servlet EG, servlet definitions and // mappings in the main web.xml override those in fragments and those in // fragments override those in annotations // Skip servlet definitions and mappings from fragments that are // defined in web.xml List> servletMappingsToAdd = new ArrayList>(); for (WebXml fragment : fragments) { for (Map.Entry servletMap : fragment.getServletMappings().entrySet()) { if (!servletMappingNames.contains(servletMap.getValue()) && !servletMappings.containsKey(servletMap.getKey())) { servletMappingsToAdd.add(servletMap); } } } // Add fragment mappings for (Map.Entry mapping : servletMappingsToAdd) { addServletMapping(mapping.getKey(), mapping.getValue()); } for (WebXml fragment : fragments) { for (Map.Entry entry : fragment.getServlets().entrySet()) { if (servlets.containsKey(entry.getKey())) { mergeServlet(entry.getValue(), servlets.get(entry.getKey()), false); } else { if (temp.getServlets().containsKey(entry.getKey())) { if (!(mergeServlet(entry.getValue(), temp.getServlets().get(entry.getKey()), true))) { log.error(sm.getString( "webXml.mergeConflictServlet", entry.getKey(), fragment.getName(), fragment.getURL())); return false; } } else { temp.getServlets().put(entry.getKey(), entry.getValue()); } } } } servlets.putAll(temp.getServlets()); if (sessionConfig.getSessionTimeout() == null) { for (WebXml fragment : fragments) { Integer value = fragment.getSessionConfig().getSessionTimeout(); if (value != null) { if (temp.getSessionConfig().getSessionTimeout() == null) { temp.getSessionConfig().setSessionTimeout(value.toString()); } else if (value.equals( temp.getSessionConfig().getSessionTimeout())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionTimeout", fragment.getName(), fragment.getURL())); return false; } } } if (temp.getSessionConfig().getSessionTimeout() != null) { sessionConfig.setSessionTimeout( temp.getSessionConfig().getSessionTimeout().toString()); } } if (sessionConfig.getCookieName() == null) { for (WebXml fragment : fragments) { String value = fragment.getSessionConfig().getCookieName(); if (value != null) { if (temp.getSessionConfig().getCookieName() == null) { temp.getSessionConfig().setCookieName(value); } else if (value.equals( temp.getSessionConfig().getCookieName())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionCookieName", fragment.getName(), fragment.getURL())); return false; } } } sessionConfig.setCookieName( temp.getSessionConfig().getCookieName()); } if (sessionConfig.getCookieDomain() == null) { for (WebXml fragment : fragments) { String value = fragment.getSessionConfig().getCookieDomain(); if (value != null) { if (temp.getSessionConfig().getCookieDomain() == null) { temp.getSessionConfig().setCookieDomain(value); } else if (value.equals( temp.getSessionConfig().getCookieDomain())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionCookieDomain", fragment.getName(), fragment.getURL())); return false; } } } sessionConfig.setCookieDomain( temp.getSessionConfig().getCookieDomain()); } if (sessionConfig.getCookiePath() == null) { for (WebXml fragment : fragments) { String value = fragment.getSessionConfig().getCookiePath(); if (value != null) { if (temp.getSessionConfig().getCookiePath() == null) { temp.getSessionConfig().setCookiePath(value); } else if (value.equals( temp.getSessionConfig().getCookiePath())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionCookiePath", fragment.getName(), fragment.getURL())); return false; } } } sessionConfig.setCookiePath( temp.getSessionConfig().getCookiePath()); } if (sessionConfig.getCookieComment() == null) { for (WebXml fragment : fragments) { String value = fragment.getSessionConfig().getCookieComment(); if (value != null) { if (temp.getSessionConfig().getCookieComment() == null) { temp.getSessionConfig().setCookieComment(value); } else if (value.equals( temp.getSessionConfig().getCookieComment())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionCookieComment", fragment.getName(), fragment.getURL())); return false; } } } sessionConfig.setCookieComment( temp.getSessionConfig().getCookieComment()); } if (sessionConfig.getCookieHttpOnly() == null) { for (WebXml fragment : fragments) { Boolean value = fragment.getSessionConfig().getCookieHttpOnly(); if (value != null) { if (temp.getSessionConfig().getCookieHttpOnly() == null) { temp.getSessionConfig().setCookieHttpOnly(value.toString()); } else if (value.equals( temp.getSessionConfig().getCookieHttpOnly())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionCookieHttpOnly", fragment.getName(), fragment.getURL())); return false; } } } if (temp.getSessionConfig().getCookieHttpOnly() != null) { sessionConfig.setCookieHttpOnly( temp.getSessionConfig().getCookieHttpOnly().toString()); } } if (sessionConfig.getCookieSecure() == null) { for (WebXml fragment : fragments) { Boolean value = fragment.getSessionConfig().getCookieSecure(); if (value != null) { if (temp.getSessionConfig().getCookieSecure() == null) { temp.getSessionConfig().setCookieSecure(value.toString()); } else if (value.equals( temp.getSessionConfig().getCookieSecure())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionCookieSecure", fragment.getName(), fragment.getURL())); return false; } } } if (temp.getSessionConfig().getCookieSecure() != null) { sessionConfig.setCookieSecure( temp.getSessionConfig().getCookieSecure().toString()); } } if (sessionConfig.getCookieMaxAge() == null) { for (WebXml fragment : fragments) { Integer value = fragment.getSessionConfig().getCookieMaxAge(); if (value != null) { if (temp.getSessionConfig().getCookieMaxAge() == null) { temp.getSessionConfig().setCookieMaxAge(value.toString()); } else if (value.equals( temp.getSessionConfig().getCookieMaxAge())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionCookieMaxAge", fragment.getName(), fragment.getURL())); return false; } } } if (temp.getSessionConfig().getCookieMaxAge() != null) { sessionConfig.setCookieMaxAge( temp.getSessionConfig().getCookieMaxAge().toString()); } } if (sessionConfig.getSessionTrackingModes().size() == 0) { for (WebXml fragment : fragments) { EnumSet value = fragment.getSessionConfig().getSessionTrackingModes(); if (value.size() > 0) { if (temp.getSessionConfig().getSessionTrackingModes().size() == 0) { temp.getSessionConfig().getSessionTrackingModes().addAll(value); } else if (value.equals( temp.getSessionConfig().getSessionTrackingModes())) { // Fragments use same value - no conflict } else { log.error(sm.getString( "webXml.mergeConflictSessionTrackingMode", fragment.getName(), fragment.getURL())); return false; } } } sessionConfig.getSessionTrackingModes().addAll( temp.getSessionConfig().getSessionTrackingModes()); } for (WebXml fragment : fragments) { if (!mergeMap(fragment.getTaglibs(), taglibs, temp.getTaglibs(), fragment, "Taglibs")) { return false; } } taglibs.putAll(temp.getTaglibs()); for (WebXml fragment : fragments) { if (fragment.alwaysAddWelcomeFiles || welcomeFiles.size() == 0) { for (String welcomeFile : fragment.getWelcomeFiles()) { addWelcomeFile(welcomeFile); } } } if (postConstructMethods.isEmpty()) { for (WebXml fragment : fragments) { if (!mergeLifecycleCallback(fragment.getPostConstructMethods(), temp.getPostConstructMethods(), fragment, "Post Construct Methods")) { return false; } } postConstructMethods.putAll(temp.getPostConstructMethods()); } if (preDestroyMethods.isEmpty()) { for (WebXml fragment : fragments) { if (!mergeLifecycleCallback(fragment.getPreDestroyMethods(), temp.getPreDestroyMethods(), fragment, "Pre Destroy Methods")) { return false; } } preDestroyMethods.putAll(temp.getPreDestroyMethods()); } return true; } private static boolean mergeResourceMap( Map fragmentResources, Map mainResources, Map tempResources, WebXml fragment) { for (T resource : fragmentResources.values()) { String resourceName = resource.getName(); if (mainResources.containsKey(resourceName)) { mainResources.get(resourceName).getInjectionTargets().addAll( resource.getInjectionTargets()); } else { // Not defined in main web.xml T existingResource = tempResources.get(resourceName); if (existingResource != null) { if (!existingResource.equals(resource)) { log.error(sm.getString( "webXml.mergeConflictResource", resourceName, fragment.getName(), fragment.getURL())); return false; } } else { tempResources.put(resourceName, resource); } } } return true; } private static boolean mergeMap(Map fragmentMap, Map mainMap, Map tempMap, WebXml fragment, String mapName) { for (Entry entry : fragmentMap.entrySet()) { final String key = entry.getKey(); if (!mainMap.containsKey(key)) { // Not defined in main web.xml T value = entry.getValue(); if (tempMap.containsKey(key)) { if (value != null && !value.equals( tempMap.get(key))) { log.error(sm.getString( "webXml.mergeConflictString", mapName, key, fragment.getName(), fragment.getURL())); return false; } } else { tempMap.put(key, value); } } } return true; } private static boolean mergeFilter(FilterDef src, FilterDef dest, boolean failOnConflict) { if (dest.getAsyncSupported() == null) { dest.setAsyncSupported(src.getAsyncSupported()); } else if (src.getAsyncSupported() != null) { if (failOnConflict && !src.getAsyncSupported().equals(dest.getAsyncSupported())) { return false; } } if (dest.getFilterClass() == null) { dest.setFilterClass(src.getFilterClass()); } else if (src.getFilterClass() != null) { if (failOnConflict && !src.getFilterClass().equals(dest.getFilterClass())) { return false; } } for (Map.Entry srcEntry : src.getParameterMap().entrySet()) { if (dest.getParameterMap().containsKey(srcEntry.getKey())) { if (failOnConflict && !dest.getParameterMap().get( srcEntry.getKey()).equals(srcEntry.getValue())) { return false; } } else { dest.addInitParameter(srcEntry.getKey(), srcEntry.getValue()); } } return true; } private static boolean mergeServlet(ServletDef src, ServletDef dest, boolean failOnConflict) { // These tests should be unnecessary... if (dest.getServletClass() != null && dest.getJspFile() != null) { return false; } if (src.getServletClass() != null && src.getJspFile() != null) { return false; } if (dest.getServletClass() == null && dest.getJspFile() == null) { dest.setServletClass(src.getServletClass()); dest.setJspFile(src.getJspFile()); } else if (failOnConflict) { if (src.getServletClass() != null && (dest.getJspFile() != null || !src.getServletClass().equals(dest.getServletClass()))) { return false; } if (src.getJspFile() != null && (dest.getServletClass() != null || !src.getJspFile().equals(dest.getJspFile()))) { return false; } } // Additive for (SecurityRoleRef securityRoleRef : src.getSecurityRoleRefs()) { dest.addSecurityRoleRef(securityRoleRef); } if (dest.getLoadOnStartup() == null) { if (src.getLoadOnStartup() != null) { dest.setLoadOnStartup(src.getLoadOnStartup().toString()); } } else if (src.getLoadOnStartup() != null) { if (failOnConflict && !src.getLoadOnStartup().equals(dest.getLoadOnStartup())) { return false; } } if (dest.getEnabled() == null) { if (src.getEnabled() != null) { dest.setEnabled(src.getEnabled().toString()); } } else if (src.getEnabled() != null) { if (failOnConflict && !src.getEnabled().equals(dest.getEnabled())) { return false; } } for (Map.Entry srcEntry : src.getParameterMap().entrySet()) { if (dest.getParameterMap().containsKey(srcEntry.getKey())) { if (failOnConflict && !dest.getParameterMap().get( srcEntry.getKey()).equals(srcEntry.getValue())) { return false; } } else { dest.addInitParameter(srcEntry.getKey(), srcEntry.getValue()); } } if (dest.getMultipartDef() == null) { dest.setMultipartDef(src.getMultipartDef()); } else if (src.getMultipartDef() != null) { return mergeMultipartDef(src.getMultipartDef(), dest.getMultipartDef(), failOnConflict); } if (dest.getAsyncSupported() == null) { if (src.getAsyncSupported() != null) { dest.setAsyncSupported(src.getAsyncSupported().toString()); } } else if (src.getAsyncSupported() != null) { if (failOnConflict && !src.getAsyncSupported().equals(dest.getAsyncSupported())) { return false; } } return true; } private static boolean mergeMultipartDef(MultipartDef src, MultipartDef dest, boolean failOnConflict) { if (dest.getLocation() == null) { dest.setLocation(src.getLocation()); } else if (src.getLocation() != null) { if (failOnConflict && !src.getLocation().equals(dest.getLocation())) { return false; } } if (dest.getFileSizeThreshold() == null) { dest.setFileSizeThreshold(src.getFileSizeThreshold()); } else if (src.getFileSizeThreshold() != null) { if (failOnConflict && !src.getFileSizeThreshold().equals( dest.getFileSizeThreshold())) { return false; } } if (dest.getMaxFileSize() == null) { dest.setMaxFileSize(src.getMaxFileSize()); } else if (src.getLocation() != null) { if (failOnConflict && !src.getMaxFileSize().equals(dest.getMaxFileSize())) { return false; } } if (dest.getMaxRequestSize() == null) { dest.setMaxRequestSize(src.getMaxRequestSize()); } else if (src.getMaxRequestSize() != null) { if (failOnConflict && !src.getMaxRequestSize().equals( dest.getMaxRequestSize())) { return false; } } return true; } private static boolean mergeLifecycleCallback( Map fragmentMap, Map tempMap, WebXml fragment, String mapName) { for (Entry entry : fragmentMap.entrySet()) { final String key = entry.getKey(); final String value = entry.getValue(); if (tempMap.containsKey(key)) { if (value != null && !value.equals(tempMap.get(key))) { log.error(sm.getString("webXml.mergeConflictString", mapName, key, fragment.getName(), fragment.getURL())); return false; } } else { tempMap.put(key, value); } } return true; } /** * Generates the sub-set of the web-fragment.xml files to be processed in * the order that the fragments must be processed as per the rules in the * Servlet spec. * * @param application The application web.xml file * @param fragments The map of fragment names to web fragments * @param servletContext The servlet context the fragments are associated * with * @return Ordered list of web-fragment.xml files to process */ public static Set orderWebFragments(WebXml application, Map fragments, ServletContext servletContext) { Set orderedFragments = new LinkedHashSet(); boolean absoluteOrdering = (application.getAbsoluteOrdering() != null); boolean orderingPresent = false; if (absoluteOrdering) { orderingPresent = true; // Only those fragments listed should be processed Set requestedOrder = application.getAbsoluteOrdering(); for (String requestedName : requestedOrder) { if (WebXml.ORDER_OTHERS.equals(requestedName)) { // Add all fragments not named explicitly at this point for (Entry entry : fragments.entrySet()) { if (!requestedOrder.contains(entry.getKey())) { WebXml fragment = entry.getValue(); if (fragment != null) { orderedFragments.add(fragment); } } } } else { WebXml fragment = fragments.get(requestedName); if (fragment != null) { orderedFragments.add(fragment); } else { log.warn(sm.getString("webXml.wrongFragmentName",requestedName)); } } } } else { // Stage 1. Make all dependencies bi-directional - this makes the // next stage simpler. for (WebXml fragment : fragments.values()) { Iterator before = fragment.getBeforeOrdering().iterator(); while (before.hasNext()) { orderingPresent = true; String beforeEntry = before.next(); if (!beforeEntry.equals(ORDER_OTHERS)) { WebXml beforeFragment = fragments.get(beforeEntry); if (beforeFragment == null) { before.remove(); } else { beforeFragment.addAfterOrdering(fragment.getName()); } } } Iterator after = fragment.getAfterOrdering().iterator(); while (after.hasNext()) { orderingPresent = true; String afterEntry = after.next(); if (!afterEntry.equals(ORDER_OTHERS)) { WebXml afterFragment = fragments.get(afterEntry); if (afterFragment == null) { after.remove(); } else { afterFragment.addBeforeOrdering(fragment.getName()); } } } } // Stage 2. Make all fragments that are implicitly before/after // others explicitly so. This is iterative so the next // stage doesn't have to be. for (WebXml fragment : fragments.values()) { if (fragment.getBeforeOrdering().contains(ORDER_OTHERS)) { makeBeforeOthersExplicit(fragment.getAfterOrdering(), fragments); } if (fragment.getAfterOrdering().contains(ORDER_OTHERS)) { makeAfterOthersExplicit(fragment.getBeforeOrdering(), fragments); } } // Stage 3. Separate into three groups Set beforeSet = new HashSet(); Set othersSet = new HashSet(); Set afterSet = new HashSet(); for (WebXml fragment : fragments.values()) { if (fragment.getBeforeOrdering().contains(ORDER_OTHERS)) { beforeSet.add(fragment); fragment.getBeforeOrdering().remove(ORDER_OTHERS); } else if (fragment.getAfterOrdering().contains(ORDER_OTHERS)) { afterSet.add(fragment); fragment.getAfterOrdering().remove(ORDER_OTHERS); } else { othersSet.add(fragment); } } // Stage 4. Decouple the groups so the ordering requirements for // each fragment in the group only refer to other fragments // in the group. Ordering requirements outside the group // will be handled by processing the groups in order. // Note: Only after ordering requirements are considered. // This is OK because of the processing in stage 1. decoupleOtherGroups(beforeSet); decoupleOtherGroups(othersSet); decoupleOtherGroups(afterSet); // Stage 5. Order each group // Note: Only after ordering requirements are considered. // This is OK because of the processing in stage 1. orderFragments(orderedFragments, beforeSet); orderFragments(orderedFragments, othersSet); orderFragments(orderedFragments, afterSet); } // Avoid NPE when unit testing if (servletContext != null) { // Publish the ordered fragments List orderedJarFileNames = null; if (orderingPresent) { orderedJarFileNames = new ArrayList(); for (WebXml fragment: orderedFragments) { orderedJarFileNames.add(fragment.getJarName()); } } servletContext.setAttribute(ServletContext.ORDERED_LIBS, orderedJarFileNames); } return orderedFragments; } private static void decoupleOtherGroups(Set group) { Set names = new HashSet(); for (WebXml fragment : group) { names.add(fragment.getName()); } for (WebXml fragment : group) { Iterator after = fragment.getAfterOrdering().iterator(); while (after.hasNext()) { String entry = after.next(); if (!names.contains(entry)) { after.remove(); } } } } private static void orderFragments(Set orderedFragments, Set unordered) { Set addedThisRound = new HashSet(); Set addedLastRound = new HashSet(); while (unordered.size() > 0) { Iterator source = unordered.iterator(); while (source.hasNext()) { WebXml fragment = source.next(); for (WebXml toRemove : addedLastRound) { fragment.getAfterOrdering().remove(toRemove.getName()); } if (fragment.getAfterOrdering().isEmpty()) { addedThisRound.add(fragment); orderedFragments.add(fragment); source.remove(); } } if (addedThisRound.size() == 0) { // Circular throw new IllegalArgumentException( sm.getString("webXml.mergeConflictOrder")); } addedLastRound.clear(); addedLastRound.addAll(addedThisRound); addedThisRound.clear(); } } private static void makeBeforeOthersExplicit(Set beforeOrdering, Map fragments) { for (String before : beforeOrdering) { if (!before.equals(ORDER_OTHERS)) { WebXml webXml = fragments.get(before); if (!webXml.getBeforeOrdering().contains(ORDER_OTHERS)) { webXml.addBeforeOrderingOthers(); makeBeforeOthersExplicit(webXml.getAfterOrdering(), fragments); } } } } private static void makeAfterOthersExplicit(Set afterOrdering, Map fragments) { for (String after : afterOrdering) { if (!after.equals(ORDER_OTHERS)) { WebXml webXml = fragments.get(after); if (!webXml.getAfterOrdering().contains(ORDER_OTHERS)) { webXml.addAfterOrderingOthers(); makeAfterOthersExplicit(webXml.getBeforeOrdering(), fragments); } } } } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextEnvironment.java0000644000175100017510000000664212271471332025672 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** * Representation of an application environment entry, as represented in * an <env-entry> element in the deployment descriptor. * * @author Craig R. McClanahan */ public class ContextEnvironment extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * Does this environment entry allow overrides by the application * deployment descriptor? */ private boolean override = true; public boolean getOverride() { return (this.override); } public void setOverride(boolean override) { this.override = override; } /** * The value of this environment entry. */ private String value = null; public String getValue() { return (this.value); } public void setValue(String value) { this.value = value; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextEnvironment["); sb.append("name="); sb.append(getName()); if (getDescription() != null) { sb.append(", description="); sb.append(getDescription()); } if (getType() != null) { sb.append(", type="); sb.append(getType()); } if (value != null) { sb.append(", value="); sb.append(value); } sb.append(", override="); sb.append(override); sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (override ? 1231 : 1237); result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextEnvironment other = (ContextEnvironment) obj; if (override != other.override) { return false; } if (value == null) { if (other.value != null) { return false; } } else if (!value.equals(other.value)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextEjb.java0000644000175100017510000001021412271471332024054 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** * Representation of an EJB resource reference for a web application, as * represented in a <ejb-ref> element in the * deployment descriptor. * * @author Craig R. McClanahan * @author Peter Rossbach (pero@apache.org) */ public class ContextEjb extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The name of the EJB home implementation class. */ private String home = null; public String getHome() { return (this.home); } public void setHome(String home) { this.home = home; } /** * The link to a J2EE EJB definition. */ private String link = null; public String getLink() { return (this.link); } public void setLink(String link) { this.link = link; } /** * The name of the EJB remote implementation class. */ private String remote = null; public String getRemote() { return (this.remote); } public void setRemote(String remote) { this.remote = remote; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextEjb["); sb.append("name="); sb.append(getName()); if (getDescription() != null) { sb.append(", description="); sb.append(getDescription()); } if (getType() != null) { sb.append(", type="); sb.append(getType()); } if (home != null) { sb.append(", home="); sb.append(home); } if (remote != null) { sb.append(", remote="); sb.append(remote); } if (link != null) { sb.append(", link="); sb.append(link); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((home == null) ? 0 : home.hashCode()); result = prime * result + ((link == null) ? 0 : link.hashCode()); result = prime * result + ((remote == null) ? 0 : remote.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextEjb other = (ContextEjb) obj; if (home == null) { if (other.home != null) { return false; } } else if (!home.equals(other.home)) { return false; } if (link == null) { if (other.link != null) { return false; } } else if (!link.equals(other.link)) { return false; } if (remote == null) { if (other.remote != null) { return false; } } else if (!remote.equals(other.remote)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/package.html0000644000175100017510000000227412271471332023434 0ustar locutuslocutus

    This package contains Java objects that represent complex data structures from the web application deployment descriptor file (web.xml). It is assumed that these objects will be initialized within the context of a single thread, and then referenced in a read-only manner subsequent to that time. Therefore, no multi-thread synchronization is utilized within the implementation classes.

    tomcat7-7.0.52/java/org/apache/catalina/deploy/Injectable.java0000644000175100017510000000205012271471332024046 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.util.List; public interface Injectable { public String getName(); public void addInjectionTarget(String injectionTargetName, String jndiName); public List getInjectionTargets(); } tomcat7-7.0.52/java/org/apache/catalina/deploy/SecurityCollection.java0000644000175100017510000002474312271471332025646 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import org.apache.catalina.util.RequestUtil; /** * Representation of a web resource collection for a web application's security * constraint, as represented in a <web-resource-collection> * element in the deployment descriptor. *

    * WARNING: It is assumed that instances of this class will be created * and modified only within the context of a single thread, before the instance * is made visible to the remainder of the application. After that, only read * access is expected. Therefore, none of the read and write access within * this class is synchronized. * * @author Craig R. McClanahan */ public class SecurityCollection implements Serializable { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Construct a new security collection instance with default values. */ public SecurityCollection() { this(null, null); } /** * Construct a new security collection instance with specified values. * * @param name Name of this security collection */ public SecurityCollection(String name) { this(name, null); } /** * Construct a new security collection instance with specified values. * * @param name Name of this security collection * @param description Description of this security collection */ public SecurityCollection(String name, String description) { super(); setName(name); setDescription(description); } // ----------------------------------------------------- Instance Variables /** * Description of this web resource collection. */ private String description = null; /** * The HTTP methods explicitly covered by this web resource collection. */ private String methods[] = new String[0]; /** * The HTTP methods explicitly excluded from this web resource collection. */ private String omittedMethods[] = new String[0]; /** * The name of this web resource collection. */ private String name = null; /** * The URL patterns protected by this security collection. */ private String patterns[] = new String[0]; /** * This security collection was established by a deployment descriptor. * Defaults to true. */ private boolean isFromDescriptor = true; // ------------------------------------------------------------- Properties /** * Return the description of this web resource collection. */ public String getDescription() { return (this.description); } /** * Set the description of this web resource collection. * * @param description The new description */ public void setDescription(String description) { this.description = description; } /** * Return the name of this web resource collection. */ public String getName() { return (this.name); } /** * Set the name of this web resource collection * * @param name The new name */ public void setName(String name) { this.name = name; } /** * Return if this constraint was defined in a deployment descriptor. */ public boolean isFromDescriptor() { return isFromDescriptor; } /** * Set if this constraint was defined in a deployment descriptor. */ public void setFromDescriptor(boolean isFromDescriptor) { this.isFromDescriptor = isFromDescriptor; } // --------------------------------------------------------- Public Methods /** * Add an HTTP request method to be explicitly part of this web resource * collection. */ public void addMethod(String method) { if (method == null) return; String results[] = new String[methods.length + 1]; for (int i = 0; i < methods.length; i++) results[i] = methods[i]; results[methods.length] = method; methods = results; } /** * Add an HTTP request method to the methods explicitly excluded from this * web resource collection. */ public void addOmittedMethod(String method) { if (method == null) return; String results[] = new String[omittedMethods.length + 1]; for (int i = 0; i < omittedMethods.length; i++) results[i] = omittedMethods[i]; results[omittedMethods.length] = method; omittedMethods = results; } /** * Add a URL pattern to be part of this web resource collection. */ public void addPattern(String pattern) { if (pattern == null) return; String decodedPattern = RequestUtil.URLDecode(pattern); String results[] = new String[patterns.length + 1]; for (int i = 0; i < patterns.length; i++) { results[i] = patterns[i]; } results[patterns.length] = decodedPattern; patterns = results; } /** * Return true if the specified HTTP request method is * part of this web resource collection. * * @param method Request method to check */ public boolean findMethod(String method) { if (methods.length == 0 && omittedMethods.length == 0) return (true); if (methods.length > 0) { for (int i = 0; i < methods.length; i++) { if (methods[i].equals(method)) return true; } return false; } if (omittedMethods.length > 0) { for (int i = 0; i < omittedMethods.length; i++) { if (omittedMethods[i].equals(method)) return false; } } return true; } /** * Return the set of HTTP request methods that are part of this web * resource collection, or a zero-length array if no methods have been * explicitly included. */ public String[] findMethods() { return (methods); } /** * Return the set of HTTP request methods that are explicitly excluded from * this web resource collection, or a zero-length array if no request * methods are excluded. */ public String[] findOmittedMethods() { return (omittedMethods); } /** * Is the specified pattern part of this web resource collection? * * @param pattern Pattern to be compared */ public boolean findPattern(String pattern) { for (int i = 0; i < patterns.length; i++) { if (patterns[i].equals(pattern)) return (true); } return (false); } /** * Return the set of URL patterns that are part of this web resource * collection. If none have been specified, a zero-length array is * returned. */ public String[] findPatterns() { return (patterns); } /** * Remove the specified HTTP request method from those that are part * of this web resource collection. * * @param method Request method to be removed */ public void removeMethod(String method) { if (method == null) return; int n = -1; for (int i = 0; i < methods.length; i++) { if (methods[i].equals(method)) { n = i; break; } } if (n >= 0) { int j = 0; String results[] = new String[methods.length - 1]; for (int i = 0; i < methods.length; i++) { if (i != n) results[j++] = methods[i]; } methods = results; } } /** * Remove the specified HTTP request method from those that are explicitly * excluded from this web resource collection. * * @param method Request method to be removed */ public void removeOmittedMethod(String method) { if (method == null) return; int n = -1; for (int i = 0; i < omittedMethods.length; i++) { if (omittedMethods[i].equals(method)) { n = i; break; } } if (n >= 0) { int j = 0; String results[] = new String[omittedMethods.length - 1]; for (int i = 0; i < omittedMethods.length; i++) { if (i != n) results[j++] = omittedMethods[i]; } omittedMethods = results; } } /** * Remove the specified URL pattern from those that are part of this * web resource collection. * * @param pattern Pattern to be removed */ public void removePattern(String pattern) { if (pattern == null) return; int n = -1; for (int i = 0; i < patterns.length; i++) { if (patterns[i].equals(pattern)) { n = i; break; } } if (n >= 0) { int j = 0; String results[] = new String[patterns.length - 1]; for (int i = 0; i < patterns.length; i++) { if (i != n) results[j++] = patterns[i]; } patterns = results; } } /** * Return a String representation of this security collection. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SecurityCollection["); sb.append(name); if (description != null) { sb.append(", "); sb.append(description); } sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextTransaction.java0000644000175100017510000000540512271471332025647 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; /** * Representation of an application resource reference, as represented in * an <res-env-refy> element in the deployment descriptor. * * @author Craig R. McClanahan */ public class ContextTransaction implements Serializable { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * Holder for our configured properties. */ private HashMap properties = new HashMap(); /** * Return a configured property. */ public Object getProperty(String name) { return properties.get(name); } /** * Set a configured property. */ public void setProperty(String name, Object value) { properties.put(name, value); } /** * remove a configured property. */ public void removeProperty(String name) { properties.remove(name); } /** * List properties. */ public Iterator listProperties() { return properties.keySet().iterator(); } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("Transaction["); sb.append("]"); return (sb.toString()); } // -------------------------------------------------------- Package Methods /** * The NamingResources with which we are associated (if any). */ @Deprecated protected NamingResources resources = null; @Deprecated public NamingResources getNamingResources() { return (this.resources); } @Deprecated void setNamingResources(NamingResources resources) { this.resources = resources; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ResourceBase.java0000644000175100017510000001273112271471332024377 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; /** * Representation of an Context element * * @author Peter Rossbach (pero@apache.org) */ public class ResourceBase implements Serializable, Injectable { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The description of this resource. */ private String description = null; public String getDescription() { return (this.description); } public void setDescription(String description) { this.description = description; } /** * The name of this resource. */ private String name = null; @Override public String getName() { return (this.name); } public void setName(String name) { this.name = name; } /** * The name of the resource implementation class. */ private String type = null; public String getType() { return (this.type); } public void setType(String type) { this.type = type; } /** * Holder for our configured properties. */ private final HashMap properties = new HashMap(); /** * Return a configured property. */ public Object getProperty(String name) { return properties.get(name); } /** * Set a configured property. */ public void setProperty(String name, Object value) { properties.put(name, value); } /** * Remove a configured property. */ public void removeProperty(String name) { properties.remove(name); } /** * List properties. */ public Iterator listProperties() { return properties.keySet().iterator(); } private final List injectionTargets = new ArrayList(); @Override public void addInjectionTarget(String injectionTargetName, String jndiName) { InjectionTarget target = new InjectionTarget(injectionTargetName, jndiName); injectionTargets.add(target); } @Override public List getInjectionTargets() { return injectionTargets; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((description == null) ? 0 : description.hashCode()); result = prime * result + ((injectionTargets == null) ? 0 : injectionTargets.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((properties == null) ? 0 : properties.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ResourceBase other = (ResourceBase) obj; if (description == null) { if (other.description != null) { return false; } } else if (!description.equals(other.description)) { return false; } if (injectionTargets == null) { if (other.injectionTargets != null) { return false; } } else if (!injectionTargets.equals(other.injectionTargets)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (properties == null) { if (other.properties != null) { return false; } } else if (!properties.equals(other.properties)) { return false; } if (type == null) { if (other.type != null) { return false; } } else if (!type.equals(other.type)) { return false; } return true; } // -------------------------------------------------------- Package Methods /** * The NamingResources with which we are associated (if any). */ protected NamingResources resources = null; public NamingResources getNamingResources() { return (this.resources); } void setNamingResources(NamingResources resources) { this.resources = resources; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextLocalEjb.java0000644000175100017510000001023012271471332025025 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** * Representation of a local EJB resource reference for a web application, as * represented in a <ejb-local-ref> element in the * deployment descriptor. * * @author Craig R. McClanahan * @author Peter Rossbach (pero@apache.org) */ public class ContextLocalEjb extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The name of the EJB home implementation class. */ private String home = null; public String getHome() { return (this.home); } public void setHome(String home) { this.home = home; } /** * The link to a J2EE EJB definition. */ private String link = null; public String getLink() { return (this.link); } public void setLink(String link) { this.link = link; } /** * The name of the EJB local implementation class. */ private String local = null; public String getLocal() { return (this.local); } public void setLocal(String local) { this.local = local; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextLocalEjb["); sb.append("name="); sb.append(getName()); if (getDescription() != null) { sb.append(", description="); sb.append(getDescription()); } if (getType() != null) { sb.append(", type="); sb.append(getType()); } if (home != null) { sb.append(", home="); sb.append(home); } if (link != null) { sb.append(", link="); sb.append(link); } if (local != null) { sb.append(", local="); sb.append(local); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((home == null) ? 0 : home.hashCode()); result = prime * result + ((link == null) ? 0 : link.hashCode()); result = prime * result + ((local == null) ? 0 : local.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextLocalEjb other = (ContextLocalEjb) obj; if (home == null) { if (other.home != null) { return false; } } else if (!home.equals(other.home)) { return false; } if (link == null) { if (other.link != null) { return false; } } else if (!link.equals(other.link)) { return false; } if (local == null) { if (other.local != null) { return false; } } else if (!local.equals(other.local)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/MultipartDef.java0000644000175100017510000000756211514620721024420 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; /** * Representation of a the multipart configuration for a servlet. */ public class MultipartDef implements Serializable { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties private String location; public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } private String maxFileSize; public String getMaxFileSize() { return maxFileSize; } public void setMaxFileSize(String maxFileSize) { this.maxFileSize = maxFileSize; } private String maxRequestSize; public String getMaxRequestSize() { return maxRequestSize; } public void setMaxRequestSize(String maxRequestSize) { this.maxRequestSize = maxRequestSize; } private String fileSizeThreshold; public String getFileSizeThreshold() { return fileSizeThreshold; } public void setFileSizeThreshold(String fileSizeThreshold) { this.fileSizeThreshold = fileSizeThreshold; } // ---------------------------------------------------------- Object methods @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((fileSizeThreshold == null) ? 0 : fileSizeThreshold .hashCode()); result = prime * result + ((location == null) ? 0 : location.hashCode()); result = prime * result + ((maxFileSize == null) ? 0 : maxFileSize.hashCode()); result = prime * result + ((maxRequestSize == null) ? 0 : maxRequestSize.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof MultipartDef)) { return false; } MultipartDef other = (MultipartDef) obj; if (fileSizeThreshold == null) { if (other.fileSizeThreshold != null) { return false; } } else if (!fileSizeThreshold.equals(other.fileSizeThreshold)) { return false; } if (location == null) { if (other.location != null) { return false; } } else if (!location.equals(other.location)) { return false; } if (maxFileSize == null) { if (other.maxFileSize != null) { return false; } } else if (!maxFileSize.equals(other.maxFileSize)) { return false; } if (maxRequestSize == null) { if (other.maxRequestSize != null) { return false; } } else if (!maxRequestSize.equals(other.maxRequestSize)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/mbeans-descriptors.xml0000644000175100017510000001736512271471332025510 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/deploy/Constants.java0000644000175100017510000000166112271471332023771 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; public class Constants { public static final String Package = "org.apache.catalina.deploy"; } tomcat7-7.0.52/java/org/apache/catalina/deploy/LocalStrings.properties0000644000175100017510000001353312271471332025675 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. filterDef.invalidFilterName=Invalid [{0}] in filter definition. servletDef.invalidServletName=Invalid [{0}] in servlet definition. webXml.duplicateEnvEntry=Duplicate env-entry name [{0}] webXml.duplicateFilter=Duplicate filter name [{0}] webXml.duplicateMessageDestination=Duplicate message-destination name [{0}] webXml.duplicateMessageDestinationRef=Duplicate message-destination-ref name [{0}] webXml.duplicateResourceEnvRef=Duplicate resource-env-ref name [{0}] webXml.duplicateResourceRef=Duplicate resource-ref name [{0}] webXml.duplicateServletMapping=The servlets named [{0}] and [{1}] are both mapped to the url-pattern [{2}] which is not permitted webXml.duplicateTaglibUri=Duplicate tag library URI [{0}] webXml.reservedName=A web.xml file was detected using a reserved name [{0}]. The name element will be ignored for this fragment. webXml.mergeConflictDisplayName=The display name was defined in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictErrorPage=The Error Page for [{0}] was defined inconsistently in multiple fragments including fragment with name [{1}] located at [{2}] webXml.mergeConflictFilter=The Filter [{0}] was defined inconsistently in multiple fragments including fragment with name [{1}] located at [{2}] webXml.mergeConflictLoginConfig=A LoginConfig was defined inconsistently in multiple fragments including fragment with name [{0}] located at [{1}] webXml.mergeConflictOrder=Fragment relative ordering contains circular references. Thsi can be resolved by using absolute ordering in web.xml. webXml.mergeConflictResource=The Resource [{0}] was defined inconsistently in multiple fragments including fragment with name [{1}] located at [{2}] webXml.mergeConflictServlet=The Servlet [{0}] was defined inconsistently in multiple fragments including fragment with name [{1}] located at [{2}] webXml.mergeConflictSessionCookieName=The session cookie name was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionCookieDomain=The session cookie domain was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionCookiePath=The session cookie path was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionCookieComment=The session cookie comment was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionCookieHttpOnly=The session cookie http-only flag was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionCookieSecure=The session cookie secure flag was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionCookieMaxAge=The session cookie max-age was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionTimeout=The session timeout was defined inconsistently in multiple fragments with different values including fragment with name [{0}] located at [{1}] webXml.mergeConflictSessionTrackingMode=The session tracking modes were defined inconsistently in multiple fragments including fragment with name [{0}] located at [{1}] webXml.mergeConflictString=The [{0}] with name [{1}] was defined inconsistently in multiple fragments including fragment with name [{2}] located at [{3}] webXml.multipleOther=Multiple others entries in ordering webxml.unrecognisedPublicId=The public ID [{0}] did not match any of the known public ID's for web.xml files so the version could not be identified webXml.version.unknown=Unknown version string [{0}]. Default version will be used. webXml.wrongFragmentName=Used a wrong fragment name {0} at web.xml absolute-ordering tag! namingResources.cleanupCloseFailed=Failed to invoke method [{0}] for resource [{1}] in container [{2}] so no cleanup was performed for that resource namingResources.cleanupCloseSecurity=Unable to retrieve method [{0}] for resource [{1}] in container [{2}] so no cleanup was performed for that resource namingResources.cleanupNoClose=Resource [{0}] in container [{1}] does not have a [{2}] method so no cleanup was performed for that resource namingResources.cleanupNoContext=Failed to retrieve JNDI naming context for container [{0}] so no cleanup was performed for that container namingResources.cleanupNoResource=Failed to retrieve JNDI resource [{0}] for container [{1}] so no cleanup was performed for that resource namingResources.mbeanCreateFail=Failed to create MBean for naming resource [{0}] namingResources.mbeanDestroyFail=Failed to destroy MBean for naming resource [{0}] namingResources.resourceTypeFail=The JNDI resource named [{0}] is of type [{1}] but the type is inconsistent with the type(s) of the injection target(s) configured for that resourcetomcat7-7.0.52/java/org/apache/catalina/deploy/SessionConfig.java0000644000175100017510000000640711344022073024563 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.util.EnumSet; import javax.servlet.SessionTrackingMode; /** * Representation of a session configuration element for a web application, * as represented in a <session-config> element in the * deployment descriptor. */ public class SessionConfig { private Integer sessionTimeout; private String cookieName; private String cookieDomain; private String cookiePath; private String cookieComment; private Boolean cookieHttpOnly; private Boolean cookieSecure; private Integer cookieMaxAge; private EnumSet sessionTrackingModes = EnumSet.noneOf(SessionTrackingMode.class); public Integer getSessionTimeout() { return sessionTimeout; } public void setSessionTimeout(String sessionTimeout) { this.sessionTimeout = Integer.valueOf(sessionTimeout); } public String getCookieName() { return cookieName; } public void setCookieName(String cookieName) { this.cookieName = cookieName; } public String getCookieDomain() { return cookieDomain; } public void setCookieDomain(String cookieDomain) { this.cookieDomain = cookieDomain; } public String getCookiePath() { return cookiePath; } public void setCookiePath(String cookiePath) { this.cookiePath = cookiePath; } public String getCookieComment() { return cookieComment; } public void setCookieComment(String cookieComment) { this.cookieComment = cookieComment; } public Boolean getCookieHttpOnly() { return cookieHttpOnly; } public void setCookieHttpOnly(String cookieHttpOnly) { this.cookieHttpOnly = Boolean.valueOf(cookieHttpOnly); } public Boolean getCookieSecure() { return cookieSecure; } public void setCookieSecure(String cookieSecure) { this.cookieSecure = Boolean.valueOf(cookieSecure); } public Integer getCookieMaxAge() { return cookieMaxAge; } public void setCookieMaxAge(String cookieMaxAge) { this.cookieMaxAge = Integer.valueOf(cookieMaxAge); } public EnumSet getSessionTrackingModes() { return sessionTrackingModes; } public void addSessionTrackingMode(String sessionTrackingMode) { sessionTrackingModes.add( SessionTrackingMode.valueOf(sessionTrackingMode)); } } tomcat7-7.0.52/java/org/apache/catalina/deploy/JspPropertyGroup.java0000644000175100017510000000742212271471332025334 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.util.LinkedHashSet; import java.util.Set; /** * Representation of a jsp-property-group element in web.xml. */ public class JspPropertyGroup { private Boolean deferredSyntax = null; public void setDeferredSyntax(String deferredSyntax) { this.deferredSyntax = Boolean.valueOf(deferredSyntax); } public Boolean getDeferredSyntax() { return deferredSyntax; } private Boolean elIgnored = null; public void setElIgnored(String elIgnored) { this.elIgnored = Boolean.valueOf(elIgnored); } public Boolean getElIgnored() { return elIgnored; } private Set includeCodas = new LinkedHashSet(); public void addIncludeCoda(String includeCoda) { includeCodas.add(includeCoda); } public Set getIncludeCodas() { return includeCodas; } private Set includePreludes = new LinkedHashSet(); public void addIncludePrelude(String includePrelude) { includePreludes.add(includePrelude); } public Set getIncludePreludes() { return includePreludes; } private Boolean isXml = null; public void setIsXml(String isXml) { this.isXml = Boolean.valueOf(isXml); } public Boolean getIsXml() { return isXml; } private String pageEncoding = null; public void setPageEncoding(String pageEncoding) { this.pageEncoding = pageEncoding; } public String getPageEncoding() { return this.pageEncoding; } private Boolean scriptingInvalid = null; public void setScriptingInvalid(String scriptingInvalid) { this.scriptingInvalid = Boolean.valueOf(scriptingInvalid); } public Boolean getScriptingInvalid() { return scriptingInvalid; } private Boolean trimWhitespace = null; public void setTrimWhitespace(String trimWhitespace) { this.trimWhitespace = Boolean.valueOf(trimWhitespace); } public Boolean getTrimWhitespace() { return trimWhitespace; } private LinkedHashSet urlPattern = new LinkedHashSet(); public void addUrlPattern(String urlPattern) { this.urlPattern.add(urlPattern); } public Set getUrlPatterns() { return this.urlPattern; } private String defaultContentType = null; public void setDefaultContentType(String defaultContentType) { this.defaultContentType = defaultContentType; } public String getDefaultContentType() { return this.defaultContentType; } private Integer buffer = null; public void setBuffer(String buffer) { this.buffer = Integer.valueOf(buffer); } public Integer getBuffer() { return this.buffer; } private Boolean errorOnUndeclaredNamespace = null; public void setErrorOnUndeclaredNamespace( String errorOnUndeclaredNamespace) { this.errorOnUndeclaredNamespace = Boolean.valueOf(errorOnUndeclaredNamespace); } public Boolean getErrorOnUndeclaredNamespace() { return this.errorOnUndeclaredNamespace; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ServletDef.java0000644000175100017510000001610012271471332024052 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.tomcat.util.res.StringManager; /** * Representation of a servlet definition for a web application, as represented * in a <servlet> element in the deployment descriptor. */ public class ServletDef implements Serializable { private static final long serialVersionUID = 1L; private static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------------------------------------- Properties /** * The description of this servlet. */ private String description = null; public String getDescription() { return (this.description); } public void setDescription(String description) { this.description = description; } /** * The display name of this servlet. */ private String displayName = null; public String getDisplayName() { return (this.displayName); } public void setDisplayName(String displayName) { this.displayName = displayName; } /** * The small icon associated with this servlet. */ private String smallIcon = null; public String getSmallIcon() { return (this.smallIcon); } public void setSmallIcon(String smallIcon) { this.smallIcon = smallIcon; } /** * The large icon associated with this servlet. */ private String largeIcon = null; public String getLargeIcon() { return (this.largeIcon); } public void setLargeIcon(String largeIcon) { this.largeIcon = largeIcon; } /** * The name of this servlet, which must be unique among the servlets * defined for a particular web application. */ private String servletName = null; public String getServletName() { return (this.servletName); } public void setServletName(String servletName) { if (servletName == null || servletName.equals("")) { throw new IllegalArgumentException( sm.getString("servletDef.invalidServletName", servletName)); } this.servletName = servletName; } /** * The fully qualified name of the Java class that implements this servlet. */ private String servletClass = null; public String getServletClass() { return (this.servletClass); } public void setServletClass(String servletClass) { this.servletClass = servletClass; } /** * The name of the JSP file to which this servlet definition applies */ private String jspFile = null; public String getJspFile() { return (this.jspFile); } public void setJspFile(String jspFile) { this.jspFile = jspFile; } /** * The set of initialization parameters for this servlet, keyed by * parameter name. */ private Map parameters = new HashMap(); public Map getParameterMap() { return (this.parameters); } /** * Add an initialization parameter to the set of parameters associated * with this servlet. * * @param name The initialisation parameter name * @param value The initialisation parameter value */ public void addInitParameter(String name, String value) { if (parameters.containsKey(name)) { // The spec does not define this but the TCK expects the first // definition to take precedence return; } parameters.put(name, value); } /** * The load-on-startup order for this servlet */ private Integer loadOnStartup = null; public Integer getLoadOnStartup() { return (this.loadOnStartup); } public void setLoadOnStartup(String loadOnStartup) { this.loadOnStartup = Integer.valueOf(loadOnStartup); } /** * The run-as configuration for this servlet */ private String runAs = null; public String getRunAs() { return (this.runAs); } public void setRunAs(String runAs) { this.runAs = runAs; } /** * The set of security role references for this servlet */ private Set securityRoleRefs = new HashSet(); public Set getSecurityRoleRefs() { return (this.securityRoleRefs); } /** * Add a security-role-ref to the set of security-role-refs associated * with this servlet. */ public void addSecurityRoleRef(SecurityRoleRef securityRoleRef) { securityRoleRefs.add(securityRoleRef); } /** * Add a security-role-ref to the set of security-role-refs associated * with this servlet. * @deprecated */ @Deprecated public void addSecurityRoleRef(String roleName, String roleLink) { SecurityRoleRef srr = new SecurityRoleRef(); srr.setName(roleName); srr.setLink(roleLink); securityRoleRefs.add(srr); } /** * The multipart configuration, if any, for this servlet */ private MultipartDef multipartDef = null; public MultipartDef getMultipartDef() { return this.multipartDef; } public void setMultipartDef(MultipartDef multipartDef) { this.multipartDef = multipartDef; } /** * Does this servlet support async. */ private Boolean asyncSupported = null; public Boolean getAsyncSupported() { return this.asyncSupported; } public void setAsyncSupported(String asyncSupported) { this.asyncSupported = Boolean.valueOf(asyncSupported); } /** * Is this servlet enabled. */ private Boolean enabled = null; public Boolean getEnabled() { return this.enabled; } public void setEnabled(String enabled) { this.enabled = Boolean.valueOf(enabled); } /** * Can this ServletDef be overridden by an SCI? */ private boolean overridable = false; public boolean isOverridable() { return overridable; } public void setOverridable(boolean overridable) { this.overridable = overridable; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/ContextResourceLink.java0000644000175100017510000000661512271471332025773 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** * Representation of a resource link for a web application, as * represented in a <ResourceLink> element in the * server configuration file. * * @author Remy Maucherat * @author Peter Rossbach (Peter Rossbach (pero@apache.org)) */ public class ContextResourceLink extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The global name of this resource. */ private String global = null; /** * The factory to be used for creating the object */ private String factory = null; public String getGlobal() { return (this.global); } public void setGlobal(String global) { this.global = global; } public String getFactory() { return factory; } public void setFactory(String factory) { this.factory = factory; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ContextResourceLink["); sb.append("name="); sb.append(getName()); if (getType() != null) { sb.append(", type="); sb.append(getType()); } if (getGlobal() != null) { sb.append(", global="); sb.append(getGlobal()); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((factory == null) ? 0 : factory.hashCode()); result = prime * result + ((global == null) ? 0 : global.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } ContextResourceLink other = (ContextResourceLink) obj; if (factory == null) { if (other.factory != null) { return false; } } else if (!factory.equals(other.factory)) { return false; } if (global == null) { if (other.global != null) { return false; } } else if (!global.equals(other.global)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/MessageDestinationRef.java0000644000175100017510000000707012271471332026240 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; /** *

    Representation of a message destination reference for a web application, * as represented in a <message-destination-ref> element * in the deployment descriptor.

    * * @author Craig R. McClanahan * @since Tomcat 5.0 */ public class MessageDestinationRef extends ResourceBase { private static final long serialVersionUID = 1L; // ------------------------------------------------------------- Properties /** * The link of this destination ref. */ private String link = null; public String getLink() { return (this.link); } public void setLink(String link) { this.link = link; } /** * The usage of this destination ref. */ private String usage = null; public String getUsage() { return (this.usage); } public void setUsage(String usage) { this.usage = usage; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("MessageDestination["); sb.append("name="); sb.append(getName()); if (link != null) { sb.append(", link="); sb.append(link); } if (getType() != null) { sb.append(", type="); sb.append(getType()); } if (usage != null) { sb.append(", usage="); sb.append(usage); } if (getDescription() != null) { sb.append(", description="); sb.append(getDescription()); } sb.append("]"); return (sb.toString()); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((link == null) ? 0 : link.hashCode()); result = prime * result + ((usage == null) ? 0 : usage.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } MessageDestinationRef other = (MessageDestinationRef) obj; if (link == null) { if (other.link != null) { return false; } } else if (!link.equals(other.link)) { return false; } if (usage == null) { if (other.usage != null) { return false; } } else if (!usage.equals(other.usage)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/InjectionTarget.java0000644000175100017510000000271512271471332025107 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; public class InjectionTarget { private String targetClass; private String targetName; public InjectionTarget() { // NOOP } public InjectionTarget(String targetClass, String targetName) { this.targetClass = targetClass; this.targetName = targetName; } public String getTargetClass() { return targetClass; } public void setTargetClass(String targetClass) { this.targetClass = targetClass; } public String getTargetName() { return targetName; } public void setTargetName(String targetName) { this.targetName = targetName; } } tomcat7-7.0.52/java/org/apache/catalina/deploy/FilterMap.java0000644000175100017510000001554012271471332023701 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.io.Serializable; import java.util.ArrayList; import java.util.Locale; import javax.servlet.DispatcherType; import org.apache.catalina.util.RequestUtil; /** * Representation of a filter mapping for a web application, as represented * in a <filter-mapping> element in the deployment * descriptor. Each filter mapping must contain a filter name plus either * a URL pattern or a servlet name. * * @author Craig R. McClanahan */ public class FilterMap implements Serializable { // ------------------------------------------------------------- Properties private static final long serialVersionUID = 1L; /** * The name of this filter to be executed when this mapping matches * a particular request. */ public static final int ERROR = 1; public static final int FORWARD = 2; public static final int INCLUDE = 4; public static final int REQUEST = 8; public static final int ASYNC = 16; // represents nothing having been set. This will be seen // as equal to a REQUEST private static final int NOT_SET = 0; private int dispatcherMapping = NOT_SET; private String filterName = null; public String getFilterName() { return (this.filterName); } public void setFilterName(String filterName) { this.filterName = filterName; } /** * The servlet name this mapping matches. */ private String[] servletNames = new String[0]; public String[] getServletNames() { if (matchAllServletNames) { return new String[] {}; } else { return (this.servletNames); } } public void addServletName(String servletName) { if ("*".equals(servletName)) { this.matchAllServletNames = true; } else { String[] results = new String[servletNames.length + 1]; System.arraycopy(servletNames, 0, results, 0, servletNames.length); results[servletNames.length] = servletName; servletNames = results; } } /** * The flag that indicates this mapping will match all url-patterns */ private boolean matchAllUrlPatterns = false; public boolean getMatchAllUrlPatterns() { return matchAllUrlPatterns; } /** * The flag that indicates this mapping will match all servlet-names */ private boolean matchAllServletNames = false; public boolean getMatchAllServletNames() { return matchAllServletNames; } /** * The URL pattern this mapping matches. */ private String[] urlPatterns = new String[0]; public String[] getURLPatterns() { if (matchAllUrlPatterns) { return new String[] {}; } else { return (this.urlPatterns); } } public void addURLPattern(String urlPattern) { if ("*".equals(urlPattern)) { this.matchAllUrlPatterns = true; } else { String[] results = new String[urlPatterns.length + 1]; System.arraycopy(urlPatterns, 0, results, 0, urlPatterns.length); results[urlPatterns.length] = RequestUtil.URLDecode(urlPattern); urlPatterns = results; } } /** * * This method will be used to set the current state of the FilterMap * representing the state of when filters should be applied. */ public void setDispatcher(String dispatcherString) { String dispatcher = dispatcherString.toUpperCase(Locale.ENGLISH); if (dispatcher.equals(DispatcherType.FORWARD.name())) { // apply FORWARD to the global dispatcherMapping. dispatcherMapping |= FORWARD; } else if (dispatcher.equals(DispatcherType.INCLUDE.name())) { // apply INCLUDE to the global dispatcherMapping. dispatcherMapping |= INCLUDE; } else if (dispatcher.equals(DispatcherType.REQUEST.name())) { // apply REQUEST to the global dispatcherMapping. dispatcherMapping |= REQUEST; } else if (dispatcher.equals(DispatcherType.ERROR.name())) { // apply ERROR to the global dispatcherMapping. dispatcherMapping |= ERROR; } else if (dispatcher.equals(DispatcherType.ASYNC.name())) { // apply ERROR to the global dispatcherMapping. dispatcherMapping |= ASYNC; } } public int getDispatcherMapping() { // per the SRV.6.2.5 absence of any dispatcher elements is // equivalent to a REQUEST value if (dispatcherMapping == NOT_SET) return REQUEST; return dispatcherMapping; } public String[] getDispatcherNames() { ArrayList result = new ArrayList(); if ((dispatcherMapping & FORWARD) > 0) { result.add(DispatcherType.FORWARD.name()); } if ((dispatcherMapping & INCLUDE) > 0) { result.add(DispatcherType.INCLUDE.name()); } if ((dispatcherMapping & REQUEST) > 0) { result.add(DispatcherType.REQUEST.name()); } if ((dispatcherMapping & ERROR) > 0) { result.add(DispatcherType.ERROR.name()); } if ((dispatcherMapping & ASYNC) > 0) { result.add(DispatcherType.ASYNC.name()); } return result.toArray(new String[result.size()]); } // --------------------------------------------------------- Public Methods /** * Render a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("FilterMap["); sb.append("filterName="); sb.append(this.filterName); for (int i = 0; i < servletNames.length; i++) { sb.append(", servletName="); sb.append(servletNames[i]); } for (int i = 0; i < urlPatterns.length; i++) { sb.append(", urlPattern="); sb.append(urlPatterns[i]); } sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/deploy/NamingResources.java0000644000175100017510000011112412271471332025115 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.deploy; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import javax.naming.NamingException; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Server; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.Introspection; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.naming.ContextBindings; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Holds and manages the naming resources defined in the J2EE Enterprise * Naming Context and their associated JNDI context. * * @author Remy Maucherat */ public class NamingResources extends LifecycleMBeanBase implements Serializable { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(NamingResources.class); private static final StringManager sm = StringManager.getManager(Constants.Package); private volatile boolean resourceRequireExplicitRegistration = false; // ----------------------------------------------------------- Constructors /** * Create a new NamingResources instance. */ public NamingResources() { // NOOP } // ----------------------------------------------------- Instance Variables /** * Associated container object. */ private Object container = null; /** * Set of naming entries, keyed by name. */ private Set entries = new HashSet(); /** * The EJB resource references for this web application, keyed by name. */ private HashMap ejbs = new HashMap(); /** * The environment entries for this web application, keyed by name. */ private HashMap envs = new HashMap(); /** * The local EJB resource references for this web application, keyed by * name. */ private HashMap localEjbs = new HashMap(); /** * The message destination referencess for this web application, * keyed by name. */ private HashMap mdrs = new HashMap(); /** * The resource environment references for this web application, * keyed by name. */ private HashMap resourceEnvRefs = new HashMap(); /** * The resource references for this web application, keyed by name. */ private HashMap resources = new HashMap(); /** * The resource links for this web application, keyed by name. */ private HashMap resourceLinks = new HashMap(); /** * The web service references for this web application, keyed by name. */ private HashMap services = new HashMap(); /** * The transaction for this webapp. */ private ContextTransaction transaction = null; /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); // ------------------------------------------------------------- Properties /** * Get the container with which the naming resources are associated. */ public Object getContainer() { return container; } /** * Set the container with which the naming resources are associated. */ public void setContainer(Object container) { this.container = container; } /** * Set the transaction object. */ public void setTransaction(ContextTransaction transaction) { this.transaction = transaction; } /** * Get the transaction object. */ public ContextTransaction getTransaction() { return transaction; } /** * Add an EJB resource reference for this web application. * * @param ejb New EJB resource reference */ public void addEjb(ContextEjb ejb) { if (entries.contains(ejb.getName())) { return; } else { entries.add(ejb.getName()); } synchronized (ejbs) { ejb.setNamingResources(this); ejbs.put(ejb.getName(), ejb); } support.firePropertyChange("ejb", null, ejb); } /** * Add an environment entry for this web application. * * @param environment New environment entry */ public void addEnvironment(ContextEnvironment environment) { if (entries.contains(environment.getName())) { ContextEnvironment ce = findEnvironment(environment.getName()); ContextResourceLink rl = findResourceLink(environment.getName()); if (ce != null) { if (ce.getOverride()) { removeEnvironment(environment.getName()); } else { return; } } else if (rl != null) { // Link. Need to look at the global resources NamingResources global = getServer().getGlobalNamingResources(); if (global.findEnvironment(rl.getGlobal()) != null) { if (global.findEnvironment(rl.getGlobal()).getOverride()) { removeResourceLink(environment.getName()); } else { return; } } } else { // It exists but it isn't an env or a res link... return; } } if (!checkResourceType(environment)) { throw new IllegalArgumentException(sm.getString( "namingResources.resourceTypeFail", environment.getName(), environment.getType())); } entries.add(environment.getName()); synchronized (envs) { environment.setNamingResources(this); envs.put(environment.getName(), environment); } support.firePropertyChange("environment", null, environment); // Register with JMX if (resourceRequireExplicitRegistration) { try { MBeanUtils.createMBean(environment); } catch (Exception e) { log.warn(sm.getString("namingResources.mbeanCreateFail", environment.getName()), e); } } } // Container should be an instance of Server or Context. If it is anything // else, return null which will trigger a NPE. private Server getServer() { if (container instanceof Server) { return (Server) container; } if (container instanceof Context) { // Could do this in one go. Lots of casts so split out for clarity Engine engine = (Engine) ((Context) container).getParent().getParent(); return engine.getService().getServer(); } return null; } /** * Add a local EJB resource reference for this web application. * * @param ejb New EJB resource reference */ public void addLocalEjb(ContextLocalEjb ejb) { if (entries.contains(ejb.getName())) { return; } else { entries.add(ejb.getName()); } synchronized (localEjbs) { ejb.setNamingResources(this); localEjbs.put(ejb.getName(), ejb); } support.firePropertyChange("localEjb", null, ejb); } /** * Add a message destination reference for this web application. * * @param mdr New message destination reference */ public void addMessageDestinationRef(MessageDestinationRef mdr) { if (entries.contains(mdr.getName())) { return; } else { if (!checkResourceType(mdr)) { throw new IllegalArgumentException(sm.getString( "namingResources.resourceTypeFail", mdr.getName(), mdr.getType())); } entries.add(mdr.getName()); } synchronized (mdrs) { mdr.setNamingResources(this); mdrs.put(mdr.getName(), mdr); } support.firePropertyChange("messageDestinationRef", null, mdr); } /** * Add a property change listener to this component. * * @param listener The listener to add */ public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } /** * Add a resource reference for this web application. * * @param resource New resource reference */ public void addResource(ContextResource resource) { if (entries.contains(resource.getName())) { return; } else { if (!checkResourceType(resource)) { throw new IllegalArgumentException(sm.getString( "namingResources.resourceTypeFail", resource.getName(), resource.getType())); } entries.add(resource.getName()); } synchronized (resources) { resource.setNamingResources(this); resources.put(resource.getName(), resource); } support.firePropertyChange("resource", null, resource); // Register with JMX if (resourceRequireExplicitRegistration) { try { MBeanUtils.createMBean(resource); } catch (Exception e) { log.warn(sm.getString("namingResources.mbeanCreateFail", resource.getName()), e); } } } /** * Add a resource environment reference for this web application. * * @param resource The resource */ public void addResourceEnvRef(ContextResourceEnvRef resource) { if (entries.contains(resource.getName())) { return; } else { if (!checkResourceType(resource)) { throw new IllegalArgumentException(sm.getString( "namingResources.resourceTypeFail", resource.getName(), resource.getType())); } entries.add(resource.getName()); } synchronized (resourceEnvRefs) { resource.setNamingResources(this); resourceEnvRefs.put(resource.getName(), resource); } support.firePropertyChange("resourceEnvRef", null, resource); } /** * Add a resource link for this web application. * * @param resourceLink New resource link */ public void addResourceLink(ContextResourceLink resourceLink) { if (entries.contains(resourceLink.getName())) { return; } else { entries.add(resourceLink.getName()); } synchronized (resourceLinks) { resourceLink.setNamingResources(this); resourceLinks.put(resourceLink.getName(), resourceLink); } support.firePropertyChange("resourceLink", null, resourceLink); // Register with JMX if (resourceRequireExplicitRegistration) { try { MBeanUtils.createMBean(resourceLink); } catch (Exception e) { log.warn(sm.getString("namingResources.mbeanCreateFail", resourceLink.getName()), e); } } } /** * Add a web service reference for this web application. * * @param service New web service reference */ public void addService(ContextService service) { if (entries.contains(service.getName())) { return; } else { entries.add(service.getName()); } synchronized (services) { service.setNamingResources(this); services.put(service.getName(), service); } support.firePropertyChange("service", null, service); } /** * Return the EJB resource reference with the specified name, if any; * otherwise, return null. * * @param name Name of the desired EJB resource reference */ public ContextEjb findEjb(String name) { synchronized (ejbs) { return ejbs.get(name); } } /** * Return the defined EJB resource references for this application. * If there are none, a zero-length array is returned. */ public ContextEjb[] findEjbs() { synchronized (ejbs) { ContextEjb results[] = new ContextEjb[ejbs.size()]; return ejbs.values().toArray(results); } } /** * Return the environment entry with the specified name, if any; * otherwise, return null. * * @param name Name of the desired environment entry */ public ContextEnvironment findEnvironment(String name) { synchronized (envs) { return envs.get(name); } } /** * Return the set of defined environment entries for this web * application. If none have been defined, a zero-length array * is returned. */ public ContextEnvironment[] findEnvironments() { synchronized (envs) { ContextEnvironment results[] = new ContextEnvironment[envs.size()]; return envs.values().toArray(results); } } /** * Return the local EJB resource reference with the specified name, if any; * otherwise, return null. * * @param name Name of the desired EJB resource reference */ public ContextLocalEjb findLocalEjb(String name) { synchronized (localEjbs) { return localEjbs.get(name); } } /** * Return the defined local EJB resource references for this application. * If there are none, a zero-length array is returned. */ public ContextLocalEjb[] findLocalEjbs() { synchronized (localEjbs) { ContextLocalEjb results[] = new ContextLocalEjb[localEjbs.size()]; return localEjbs.values().toArray(results); } } /** * Return the message destination reference with the specified name, * if any; otherwise, return null. * * @param name Name of the desired message destination reference */ public MessageDestinationRef findMessageDestinationRef(String name) { synchronized (mdrs) { return mdrs.get(name); } } /** * Return the defined message destination references for this application. * If there are none, a zero-length array is returned. */ public MessageDestinationRef[] findMessageDestinationRefs() { synchronized (mdrs) { MessageDestinationRef results[] = new MessageDestinationRef[mdrs.size()]; return mdrs.values().toArray(results); } } /** * Return the resource reference with the specified name, if any; * otherwise return null. * * @param name Name of the desired resource reference */ public ContextResource findResource(String name) { synchronized (resources) { return resources.get(name); } } /** * Return the resource link with the specified name, if any; * otherwise return null. * * @param name Name of the desired resource link */ public ContextResourceLink findResourceLink(String name) { synchronized (resourceLinks) { return resourceLinks.get(name); } } /** * Return the defined resource links for this application. If * none have been defined, a zero-length array is returned. */ public ContextResourceLink[] findResourceLinks() { synchronized (resourceLinks) { ContextResourceLink results[] = new ContextResourceLink[resourceLinks.size()]; return resourceLinks.values().toArray(results); } } /** * Return the defined resource references for this application. If * none have been defined, a zero-length array is returned. */ public ContextResource[] findResources() { synchronized (resources) { ContextResource results[] = new ContextResource[resources.size()]; return resources.values().toArray(results); } } /** * Return the resource environment reference type for the specified * name, if any; otherwise return null. * * @param name Name of the desired resource environment reference */ public ContextResourceEnvRef findResourceEnvRef(String name) { synchronized (resourceEnvRefs) { return resourceEnvRefs.get(name); } } /** * Return the set of resource environment reference names for this * web application. If none have been specified, a zero-length * array is returned. */ public ContextResourceEnvRef[] findResourceEnvRefs() { synchronized (resourceEnvRefs) { ContextResourceEnvRef results[] = new ContextResourceEnvRef[resourceEnvRefs.size()]; return resourceEnvRefs.values().toArray(results); } } /** * Return the web service reference for the specified * name, if any; otherwise return null. * * @param name Name of the desired web service */ public ContextService findService(String name) { synchronized (services) { return services.get(name); } } /** * Return the defined web service references for this application. If * none have been defined, a zero-length array is returned. */ public ContextService[] findServices() { synchronized (services) { ContextService results[] = new ContextService[services.size()]; return services.values().toArray(results); } } /** * Return true if the name specified already exists. */ @Deprecated public boolean exists(String name) { return (entries.contains(name)); } /** * Remove any EJB resource reference with the specified name. * * @param name Name of the EJB resource reference to remove */ public void removeEjb(String name) { entries.remove(name); ContextEjb ejb = null; synchronized (ejbs) { ejb = ejbs.remove(name); } if (ejb != null) { support.firePropertyChange("ejb", ejb, null); ejb.setNamingResources(null); } } /** * Remove any environment entry with the specified name. * * @param name Name of the environment entry to remove */ public void removeEnvironment(String name) { entries.remove(name); ContextEnvironment environment = null; synchronized (envs) { environment = envs.remove(name); } if (environment != null) { support.firePropertyChange("environment", environment, null); // De-register with JMX if (resourceRequireExplicitRegistration) { try { MBeanUtils.destroyMBean(environment); } catch (Exception e) { log.warn(sm.getString("namingResources.mbeanDestroyFail", environment.getName()), e); } } environment.setNamingResources(null); } } /** * Remove any local EJB resource reference with the specified name. * * @param name Name of the EJB resource reference to remove */ public void removeLocalEjb(String name) { entries.remove(name); ContextLocalEjb localEjb = null; synchronized (localEjbs) { localEjb = localEjbs.remove(name); } if (localEjb != null) { support.firePropertyChange("localEjb", localEjb, null); localEjb.setNamingResources(null); } } /** * Remove any message destination reference with the specified name. * * @param name Name of the message destination resource reference to remove */ public void removeMessageDestinationRef(String name) { entries.remove(name); MessageDestinationRef mdr = null; synchronized (mdrs) { mdr = mdrs.remove(name); } if (mdr != null) { support.firePropertyChange("messageDestinationRef", mdr, null); mdr.setNamingResources(null); } } /** * Remove a property change listener from this component. * * @param listener The listener to remove */ public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } /** * Remove any resource reference with the specified name. * * @param name Name of the resource reference to remove */ public void removeResource(String name) { entries.remove(name); ContextResource resource = null; synchronized (resources) { resource = resources.remove(name); } if (resource != null) { support.firePropertyChange("resource", resource, null); // De-register with JMX if (resourceRequireExplicitRegistration) { try { MBeanUtils.destroyMBean(resource); } catch (Exception e) { log.warn(sm.getString("namingResources.mbeanDestroyFail", resource.getName()), e); } } resource.setNamingResources(null); } } /** * Remove any resource environment reference with the specified name. * * @param name Name of the resource environment reference to remove */ public void removeResourceEnvRef(String name) { entries.remove(name); ContextResourceEnvRef resourceEnvRef = null; synchronized (resourceEnvRefs) { resourceEnvRef = resourceEnvRefs.remove(name); } if (resourceEnvRef != null) { support.firePropertyChange("resourceEnvRef", resourceEnvRef, null); resourceEnvRef.setNamingResources(null); } } /** * Remove any resource link with the specified name. * * @param name Name of the resource link to remove */ public void removeResourceLink(String name) { entries.remove(name); ContextResourceLink resourceLink = null; synchronized (resourceLinks) { resourceLink = resourceLinks.remove(name); } if (resourceLink != null) { support.firePropertyChange("resourceLink", resourceLink, null); // De-register with JMX if (resourceRequireExplicitRegistration) { try { MBeanUtils.destroyMBean(resourceLink); } catch (Exception e) { log.warn(sm.getString("namingResources.mbeanDestroyFail", resourceLink.getName()), e); } } resourceLink.setNamingResources(null); } } /** * Remove any web service reference with the specified name. * * @param name Name of the web service reference to remove */ public void removeService(String name) { entries.remove(name); ContextService service = null; synchronized (services) { service = services.remove(name); } if (service != null) { support.firePropertyChange("service", service, null); service.setNamingResources(null); } } // ------------------------------------------------------- Lifecycle methods @Override protected void initInternal() throws LifecycleException { super.initInternal(); // Set this before we register currently known naming resources to avoid // timing issues. Duplication registration is not an issue. resourceRequireExplicitRegistration = true; for (ContextResource cr : resources.values()) { try { MBeanUtils.createMBean(cr); } catch (Exception e) { log.warn(sm.getString( "namingResources.mbeanCreateFail", cr.getName()), e); } } for (ContextEnvironment ce : envs.values()) { try { MBeanUtils.createMBean(ce); } catch (Exception e) { log.warn(sm.getString( "namingResources.mbeanCreateFail", ce.getName()), e); } } for (ContextResourceLink crl : resourceLinks.values()) { try { MBeanUtils.createMBean(crl); } catch (Exception e) { log.warn(sm.getString( "namingResources.mbeanCreateFail", crl.getName()), e); } } } @Override protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null); setState(LifecycleState.STARTING); } @Override protected void stopInternal() throws LifecycleException { cleanUp(); setState(LifecycleState.STOPPING); fireLifecycleEvent(CONFIGURE_STOP_EVENT, null); } /** * Close those resources that an explicit close may help clean-up faster. */ private void cleanUp() { if (resources.size() == 0) { return; } javax.naming.Context ctxt; try { if (container instanceof Server) { ctxt = ((Server) container).getGlobalNamingContext(); } else { ctxt = ContextBindings.getClassLoader(); ctxt = (javax.naming.Context) ctxt.lookup("comp/env"); } } catch (NamingException e) { log.warn(sm.getString("namingResources.cleanupNoContext", container), e); return; } for (ContextResource cr: resources.values()) { if (cr.getSingleton()) { String closeMethod = cr.getCloseMethod(); if (closeMethod != null && closeMethod.length() > 0) { String name = cr.getName(); Object resource; try { resource = ctxt.lookup(name); } catch (NamingException e) { log.warn(sm.getString( "namingResources.cleanupNoResource", cr.getName(), container), e); continue; } cleanUp(resource, name, closeMethod); } } } } /** * Clean up a resource by calling the defined close method. For example, * closing a database connection pool will close it's open connections. This * will happen on GC but that leaves db connections open that may cause * issues. * * @param resource The resource to close. */ private void cleanUp(Object resource, String name, String closeMethod) { // Look for a zero-arg close() method Method m = null; try { m = resource.getClass().getMethod(closeMethod, (Class[]) null); } catch (SecurityException e) { log.debug(sm.getString("namingResources.cleanupCloseSecurity", closeMethod, name, container)); return; } catch (NoSuchMethodException e) { log.debug(sm.getString("namingResources.cleanupNoClose", name, container, closeMethod)); return; } if (m != null) { try { m.invoke(resource, (Object[]) null); } catch (IllegalArgumentException e) { log.warn(sm.getString("namingResources.cleanupCloseFailed", closeMethod, name, container), e); } catch (IllegalAccessException e) { log.warn(sm.getString("namingResources.cleanupCloseFailed", closeMethod, name, container), e); } catch (InvocationTargetException e) { Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); log.warn(sm.getString("namingResources.cleanupCloseFailed", closeMethod, name, container), t); } } } @Override protected void destroyInternal() throws LifecycleException { // Set this before we de-register currently known naming resources to // avoid timing issues. Duplication de-registration is not an issue. resourceRequireExplicitRegistration = false; // Destroy in reverse order to create, although it should not matter for (ContextResourceLink crl : resourceLinks.values()) { try { MBeanUtils.destroyMBean(crl); } catch (Exception e) { log.warn(sm.getString( "namingResources.mbeanDestroyFail", crl.getName()), e); } } for (ContextEnvironment ce : envs.values()) { try { MBeanUtils.destroyMBean(ce); } catch (Exception e) { log.warn(sm.getString( "namingResources.mbeanDestroyFail", ce.getName()), e); } } for (ContextResource cr : resources.values()) { try { MBeanUtils.destroyMBean(cr); } catch (Exception e) { log.warn(sm.getString( "namingResources.mbeanDestroyFail", cr.getName()), e); } } super.destroyInternal(); } @Override protected String getDomainInternal() { // Use the same domain as our associated container if we have one Object c = getContainer(); if (c instanceof LifecycleMBeanBase) { return ((LifecycleMBeanBase) c).getDomain(); } return null; } @Override protected String getObjectNameKeyProperties() { Object c = getContainer(); if (c instanceof Container) { return "type=NamingResources" + MBeanUtils.getContainerKeyProperties((Container) c); } // Server or just unknown return "type=NamingResources"; } /** * Checks that the configuration of the type for the specified resource is * consistent with any injection targets and if the type is not specified, * tries to configure the type based on the injection targets * * @param resource The resource to check * * @return true if the type for the resource is now valid (if * previously null this means it is now set) or * false if the current resource type is inconsistent * with the injection targets and/or cannot be determined */ private boolean checkResourceType(ResourceBase resource) { if (!(container instanceof Context)) { // Only Context's will have injection targets return true; } if (resource.getInjectionTargets() == null || resource.getInjectionTargets().size() == 0) { // No injection targets so use the defined type for the resource return true; } Context context = (Context) container; String typeName = resource.getType(); Class typeClass = null; if (typeName != null) { typeClass = Introspection.loadClass(context, typeName); if (typeClass == null) { // Can't load the type - will trigger a failure later so don't // fail here return true; } } Class compatibleClass = getCompatibleType(context, resource, typeClass); if (compatibleClass == null) { // Indicates that a compatible type could not be identified that // worked for all injection targets return false; } resource.setType(compatibleClass.getCanonicalName()); return true; } private Class getCompatibleType(Context context, ResourceBase resource, Class typeClass) { Class result = null; for (InjectionTarget injectionTarget : resource.getInjectionTargets()) { Class clazz = Introspection.loadClass( context, injectionTarget.getTargetClass()); if (clazz == null) { // Can't load class - therefore ignore this target continue; } // Look for a match String targetName = injectionTarget.getTargetName(); // Look for a setter match first Class targetType = getSetterType(clazz, targetName); if (targetType == null) { // Try a field match if no setter match targetType = getFieldType(clazz,targetName); } if (targetType == null) { // No match - ignore this injection target continue; } targetType = Introspection.convertPrimitiveType(targetType); if (typeClass == null) { // Need to find a common type amongst the injection targets if (result == null) { result = targetType; } else if (targetType.isAssignableFrom(result)) { // NO-OP - This will work } else if (result.isAssignableFrom(targetType)) { // Need to use more specific type result = targetType; } else { // Incompatible types return null; } } else { // Each injection target needs to be consistent with the defined // type if (targetType.isAssignableFrom(typeClass)) { result = typeClass; } else { // Incompatible types return null; } } } return result; } private Class getSetterType(Class clazz, String name) { Method[] methods = Introspection.getDeclaredMethods(clazz); if (methods != null && methods.length > 0) { for (Method method : methods) { if (Introspection.isValidSetter(method) && Introspection.getPropertyName(method).equals(name)) { return method.getParameterTypes()[0]; } } } return null; } private Class getFieldType(Class clazz, String name) { Field[] fields = Introspection.getDeclaredFields(clazz); if (fields != null && fields.length > 0) { for (Field field : fields) { if (field.getName().equals(name)) { return field.getType(); } } } return null; } } tomcat7-7.0.52/java/org/apache/catalina/ContainerListener.java0000644000175100017510000000242312271471332024146 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * Interface defining a listener for significant Container generated events. * Note that "container start" and "container stop" events are normally * LifecycleEvents, not ContainerEvents. * * @author Craig R. McClanahan */ public interface ContainerListener { /** * Acknowledge the occurrence of the specified event. * * @param event ContainerEvent that has occurred */ public void containerEvent(ContainerEvent event); } tomcat7-7.0.52/java/org/apache/catalina/mbeans-descriptors.xml0000644000175100017510000001271012271471332024201 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/AsyncDispatcher.java0000644000175100017510000000247212012536663023610 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public interface AsyncDispatcher { /** * Perform an asynchronous dispatch. The method does not check if the * request is in an appropriate state for this; it is the caller's * responsibility to check this. */ public void dispatch(ServletRequest request, ServletResponse response) throws ServletException, IOException; } tomcat7-7.0.52/java/org/apache/catalina/servlets/0000755000175100017510000000000012301126370021512 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/servlets/LocalStrings_es.properties0000644000175100017510000000312212271471332026730 0ustar locutuslocutusdefaultServlet.missingResource = El recurso requerido {0} no se encuentra disponible # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. defaultservlet.directorylistingfor = Listado de Directorio para\: defaultservlet.upto = Atr\u00E1s a\: defaultservlet.subdirectories = Subdirectorios\: defaultservlet.files = Ficheros\: defaultservlet.skipfail = S\u00F3lo se han saltado [{0}] cuando se requirieron [{1}] webdavservlet.jaxpfailed = Fall\u00F3 la inicializaci\u00F3n de JAXP webdavservlet.enternalEntityIgnored = El requerimiento inclu\u00EDa una referencia a una entidad externa con PublicID {0} y SystemID {1} que fue ignorada directory.filename = Nombre de Fichero\: directory.lastModified = \u00DAltima Modificaci\u00F3n directory.parent = Atr\u00E1s A {0} directory.size = Medida directory.title = Listado de Directorio Para {0} directory.version = Tomcat Catalina versi\u00F3n 4.0 tomcat7-7.0.52/java/org/apache/catalina/servlets/CGIServlet.java0000644000175100017510000021303012271471332024332 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.servlets; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; import java.util.Vector; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.catalina.util.IOTools; /** * CGI-invoking servlet for web applications, used to execute scripts which * comply to the Common Gateway Interface (CGI) specification and are named * in the path-info used to invoke this servlet. * *

    * Note: This code compiles and even works for simple CGI cases. * Exhaustive testing has not been done. Please consider it beta * quality. Feedback is appreciated to the author (see below). *

    *

    * * Example:
    * If an instance of this servlet was mapped (using * <web-app>/WEB-INF/web.xml) to: *

    *

    * * <web-app>/cgi-bin/* * *

    *

    * then the following request: *

    *

    * * http://localhost:8080/<web-app>/cgi-bin/dir1/script/pathinfo1 * *

    *

    * would result in the execution of the script *

    *

    * * <web-app-root>/WEB-INF/cgi/dir1/script * *

    *

    * with the script's PATH_INFO set to /pathinfo1. *

    *

    * Recommendation: House all your CGI scripts under * <webapp>/WEB-INF/cgi. This will ensure that you do not * accidentally expose your cgi scripts' code to the outside world and that * your cgis will be cleanly ensconced underneath the WEB-INF (i.e., * non-content) area. *

    *

    * The default CGI location is mentioned above. You have the flexibility to * put CGIs wherever you want, however: *

    *

    * The CGI search path will start at * webAppRootDir + File.separator + cgiPathPrefix * (or webAppRootDir alone if cgiPathPrefix is * null). *

    *

    * cgiPathPrefix is defined by setting * this servlet's cgiPathPrefix init parameter *

    * *

    * * CGI Specification:
    derived from * http://cgi-spec.golux.com. * A work-in-progress & expired Internet Draft. Note no actual RFC describing * the CGI specification exists. Where the behavior of this servlet differs * from the specification cited above, it is either documented here, a bug, * or an instance where the specification cited differs from Best * Community Practice (BCP). * Such instances should be well-documented here. Please email the * Tomcat group [dev@tomcat.apache.org] * with amendments. * *

    *

    * * Canonical metavariables:
    * The CGI specification defines the following canonical metavariables: *
    * [excerpt from CGI specification] *

     *  AUTH_TYPE
     *  CONTENT_LENGTH
     *  CONTENT_TYPE
     *  GATEWAY_INTERFACE
     *  PATH_INFO
     *  PATH_TRANSLATED
     *  QUERY_STRING
     *  REMOTE_ADDR
     *  REMOTE_HOST
     *  REMOTE_IDENT
     *  REMOTE_USER
     *  REQUEST_METHOD
     *  SCRIPT_NAME
     *  SERVER_NAME
     *  SERVER_PORT
     *  SERVER_PROTOCOL
     *  SERVER_SOFTWARE
     * 
    *

    * Metavariables with names beginning with the protocol name (e.g., * "HTTP_ACCEPT") are also canonical in their description of request header * fields. The number and meaning of these fields may change independently * of this specification. (See also section 6.1.5 [of the CGI specification].) *

    * [end excerpt] * *

    *

    Implementation notes

    *

    * * standard input handling: If your script accepts standard input, * then the client must start sending input within a certain timeout period, * otherwise the servlet will assume no input is coming and carry on running * the script. The script's the standard input will be closed and handling of * any further input from the client is undefined. Most likely it will be * ignored. If this behavior becomes undesirable, then this servlet needs * to be enhanced to handle threading of the spawned process' stdin, stdout, * and stderr (which should not be too hard). *
    * If you find your cgi scripts are timing out receiving input, you can set * the init parameter of your webapps' cgi-handling servlet * to be *

    *

    * * Metavariable Values: According to the CGI specification, * implementations may choose to represent both null or missing values in an * implementation-specific manner, but must define that manner. This * implementation chooses to always define all required metavariables, but * set the value to "" for all metavariables whose value is either null or * undefined. PATH_TRANSLATED is the sole exception to this rule, as per the * CGI Specification. * *

    *

    * * NPH -- Non-parsed-header implementation: This implementation does * not support the CGI NPH concept, whereby server ensures that the data * supplied to the script are precisely as supplied by the client and * unaltered by the server. *

    *

    * The function of a servlet container (including Tomcat) is specifically * designed to parse and possible alter CGI-specific variables, and as * such makes NPH functionality difficult to support. *

    *

    * The CGI specification states that compliant servers MAY support NPH output. * It does not state servers MUST support NPH output to be unconditionally * compliant. Thus, this implementation maintains unconditional compliance * with the specification though NPH support is not present. *

    *

    * * The CGI specification is located at * http://cgi-spec.golux.com. * *

    *

    *

    TODO:

    *
      *
    • Support for setting headers (for example, Location headers don't work) *
    • Support for collapsing multiple header lines (per RFC 2616) *
    • Ensure handling of POST method does not interfere with 2.3 Filters *
    • Refactor some debug code out of core *
    • Ensure header handling preserves encoding *
    • Possibly rewrite CGIRunner.run()? *
    • Possibly refactor CGIRunner and CGIEnvironment as non-inner classes? *
    • Document handling of cgi stdin when there is no stdin *
    • Revisit IOException handling in CGIRunner.run() *
    • Better documentation *
    • Confirm use of ServletInputStream.available() in CGIRunner.run() is * not needed *
    • [add more to this TODO list] *
    *

    * * @author Martin T Dengler [root@martindengler.com] * @author Amy Roh * @since Tomcat 4.0 */ public final class CGIServlet extends HttpServlet { /* some vars below copied from Craig R. McClanahan's InvokerServlet */ private static final long serialVersionUID = 1L; /** the debugging detail level for this servlet. */ private int debug = 0; /** * The CGI search path will start at * webAppRootDir + File.separator + cgiPathPrefix * (or webAppRootDir alone if cgiPathPrefix is * null) */ private String cgiPathPrefix = null; /** the executable to use with the script */ private String cgiExecutable = "perl"; /** additional arguments for the executable */ private List cgiExecutableArgs = null; /** the encoding to use for parameters */ private String parameterEncoding = System.getProperty("file.encoding", "UTF-8"); /** * The time (in milliseconds) to wait for the reading of stderr to complete * before terminating the CGI process. */ private long stderrTimeout = 2000; /** object used to ensure multiple threads don't try to expand same file */ static Object expandFileLock = new Object(); /** the shell environment variables to be passed to the CGI script */ Hashtable shellEnv = new Hashtable(); /** * Sets instance variables. *

    * Modified from Craig R. McClanahan's InvokerServlet *

    * * @param config a ServletConfig object * containing the servlet's * configuration and initialization * parameters * * @exception ServletException if an exception has occurred that * interferes with the servlet's normal * operation */ @Override public void init(ServletConfig config) throws ServletException { super.init(config); // Set our properties from the initialization parameters if (getServletConfig().getInitParameter("debug") != null) debug = Integer.parseInt(getServletConfig().getInitParameter("debug")); cgiPathPrefix = getServletConfig().getInitParameter("cgiPathPrefix"); boolean passShellEnvironment = Boolean.valueOf(getServletConfig().getInitParameter("passShellEnvironment")).booleanValue(); if (passShellEnvironment) { shellEnv.putAll(System.getenv()); } if (getServletConfig().getInitParameter("executable") != null) { cgiExecutable = getServletConfig().getInitParameter("executable"); } if (getServletConfig().getInitParameter("executable-arg-1") != null) { List args = new ArrayList(); for (int i = 1;; i++) { String arg = getServletConfig().getInitParameter( "executable-arg-" + i); if (arg == null) { break; } args.add(arg); } cgiExecutableArgs = args; } if (getServletConfig().getInitParameter("parameterEncoding") != null) { parameterEncoding = getServletConfig().getInitParameter("parameterEncoding"); } if (getServletConfig().getInitParameter("stderrTimeout") != null) { stderrTimeout = Long.parseLong(getServletConfig().getInitParameter( "stderrTimeout")); } } /** * Prints out important Servlet API and container information * *

    * Copied from SnoopAllServlet by Craig R. McClanahan *

    * * @param out ServletOutputStream as target of the information * @param req HttpServletRequest object used as source of information * @param res HttpServletResponse object currently not used but could * provide future information * * @exception IOException if a write operation exception occurs * */ protected void printServletEnvironment(ServletOutputStream out, HttpServletRequest req, HttpServletResponse res) throws IOException { // Document the properties from ServletRequest out.println("

    ServletRequest Properties

    "); out.println("
      "); Enumeration attrs = req.getAttributeNames(); while (attrs.hasMoreElements()) { String attr = attrs.nextElement(); out.println("
    • attribute " + attr + " = " + req.getAttribute(attr)); } out.println("
    • characterEncoding = " + req.getCharacterEncoding()); out.println("
    • contentLength = " + req.getContentLength()); out.println("
    • contentType = " + req.getContentType()); Enumeration locales = req.getLocales(); while (locales.hasMoreElements()) { Locale locale = locales.nextElement(); out.println("
    • locale = " + locale); } Enumeration params = req.getParameterNames(); while (params.hasMoreElements()) { String param = params.nextElement(); String values[] = req.getParameterValues(param); for (int i = 0; i < values.length; i++) out.println("
    • parameter " + param + " = " + values[i]); } out.println("
    • protocol = " + req.getProtocol()); out.println("
    • remoteAddr = " + req.getRemoteAddr()); out.println("
    • remoteHost = " + req.getRemoteHost()); out.println("
    • scheme = " + req.getScheme()); out.println("
    • secure = " + req.isSecure()); out.println("
    • serverName = " + req.getServerName()); out.println("
    • serverPort = " + req.getServerPort()); out.println("
    "); out.println("
    "); // Document the properties from HttpServletRequest out.println("

    HttpServletRequest Properties

    "); out.println("
      "); out.println("
    • authType = " + req.getAuthType()); out.println("
    • contextPath = " + req.getContextPath()); Cookie cookies[] = req.getCookies(); if (cookies!=null) { for (int i = 0; i < cookies.length; i++) out.println("
    • cookie " + cookies[i].getName() +" = " +cookies[i].getValue()); } Enumeration headers = req.getHeaderNames(); while (headers.hasMoreElements()) { String header = headers.nextElement(); out.println("
    • header " + header + " = " + req.getHeader(header)); } out.println("
    • method = " + req.getMethod()); out.println("
    • pathInfo = " + req.getPathInfo()); out.println("
    • pathTranslated = " + req.getPathTranslated()); out.println("
    • queryString = " + req.getQueryString()); out.println("
    • remoteUser = " + req.getRemoteUser()); out.println("
    • requestedSessionId = " + req.getRequestedSessionId()); out.println("
    • requestedSessionIdFromCookie = " + req.isRequestedSessionIdFromCookie()); out.println("
    • requestedSessionIdFromURL = " + req.isRequestedSessionIdFromURL()); out.println("
    • requestedSessionIdValid = " + req.isRequestedSessionIdValid()); out.println("
    • requestURI = " + req.getRequestURI()); out.println("
    • servletPath = " + req.getServletPath()); out.println("
    • userPrincipal = " + req.getUserPrincipal()); out.println("
    "); out.println("
    "); // Document the servlet request attributes out.println("

    ServletRequest Attributes

    "); out.println("
      "); attrs = req.getAttributeNames(); while (attrs.hasMoreElements()) { String attr = attrs.nextElement(); out.println("
    • " + attr + " = " + req.getAttribute(attr)); } out.println("
    "); out.println("
    "); // Process the current session (if there is one) HttpSession session = req.getSession(false); if (session != null) { // Document the session properties out.println("

    HttpSession Properties

    "); out.println("
      "); out.println("
    • id = " + session.getId()); out.println("
    • creationTime = " + new Date(session.getCreationTime())); out.println("
    • lastAccessedTime = " + new Date(session.getLastAccessedTime())); out.println("
    • maxInactiveInterval = " + session.getMaxInactiveInterval()); out.println("
    "); out.println("
    "); // Document the session attributes out.println("

    HttpSession Attributes

    "); out.println("
      "); attrs = session.getAttributeNames(); while (attrs.hasMoreElements()) { String attr = attrs.nextElement(); out.println("
    • " + attr + " = " + session.getAttribute(attr)); } out.println("
    "); out.println("
    "); } // Document the servlet configuration properties out.println("

    ServletConfig Properties

    "); out.println("
      "); out.println("
    • servletName = " + getServletConfig().getServletName()); out.println("
    "); out.println("
    "); // Document the servlet configuration initialization parameters out.println("

    ServletConfig Initialization Parameters

    "); out.println("
      "); params = getServletConfig().getInitParameterNames(); while (params.hasMoreElements()) { String param = params.nextElement(); String value = getServletConfig().getInitParameter(param); out.println("
    • " + param + " = " + value); } out.println("
    "); out.println("
    "); // Document the servlet context properties out.println("

    ServletContext Properties

    "); out.println("
      "); out.println("
    • majorVersion = " + getServletContext().getMajorVersion()); out.println("
    • minorVersion = " + getServletContext().getMinorVersion()); out.println("
    • realPath('/') = " + getServletContext().getRealPath("/")); out.println("
    • serverInfo = " + getServletContext().getServerInfo()); out.println("
    "); out.println("
    "); // Document the servlet context initialization parameters out.println("

    ServletContext Initialization Parameters

    "); out.println("
      "); params = getServletContext().getInitParameterNames(); while (params.hasMoreElements()) { String param = params.nextElement(); String value = getServletContext().getInitParameter(param); out.println("
    • " + param + " = " + value); } out.println("
    "); out.println("
    "); // Document the servlet context attributes out.println("

    ServletContext Attributes

    "); out.println("
      "); attrs = getServletContext().getAttributeNames(); while (attrs.hasMoreElements()) { String attr = attrs.nextElement(); out.println("
    • " + attr + " = " + getServletContext().getAttribute(attr)); } out.println("
    "); out.println("
    "); } /** * Provides CGI Gateway service -- delegates to doGet * * @param req HttpServletRequest passed in by servlet container * @param res HttpServletResponse passed in by servlet container * * @exception ServletException if a servlet-specific exception occurs * @exception IOException if a read/write exception occurs * * @see javax.servlet.http.HttpServlet * */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { doGet(req, res); } /** * Provides CGI Gateway service * * @param req HttpServletRequest passed in by servlet container * @param res HttpServletResponse passed in by servlet container * * @exception ServletException if a servlet-specific exception occurs * @exception IOException if a read/write exception occurs * * @see javax.servlet.http.HttpServlet * */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { CGIEnvironment cgiEnv = new CGIEnvironment(req, getServletContext()); if (cgiEnv.isValid()) { CGIRunner cgi = new CGIRunner(cgiEnv.getCommand(), cgiEnv.getEnvironment(), cgiEnv.getWorkingDirectory(), cgiEnv.getParameters()); //if POST, we need to cgi.setInput //REMIND: how does this interact with Servlet API 2.3's Filters?! if ("POST".equals(req.getMethod())) { cgi.setInput(req.getInputStream()); } cgi.setResponse(res); cgi.run(); } if (!cgiEnv.isValid()) { res.setStatus(404); } if (debug >= 10) { ServletOutputStream out = res.getOutputStream(); out.println("$Name$"); out.println("$Header$

    "); if (cgiEnv.isValid()) { out.println(cgiEnv.toString()); } else { out.println("

    "); out.println("CGI script not found or not specified."); out.println("

    "); out.println("

    "); out.println("Check the HttpServletRequest "); out.println("pathInfo "); out.println("property to see if it is what you meant "); out.println("it to be. You must specify an existant "); out.println("and executable file as part of the "); out.println("path-info."); out.println("

    "); out.println("

    "); out.println("For a good discussion of how CGI scripts "); out.println("work and what their environment variables "); out.println("mean, please visit the CGI "); out.println("Specification page."); out.println("

    "); } printServletEnvironment(out, req, res); out.println(""); } } //doGet /** * Encapsulates the CGI environment and rules to derive * that environment from the servlet container and request information. * *

    *

    * * @since Tomcat 4.0 */ protected class CGIEnvironment { /** context of the enclosing servlet */ private ServletContext context = null; /** context path of enclosing servlet */ private String contextPath = null; /** servlet URI of the enclosing servlet */ private String servletPath = null; /** pathInfo for the current request */ private String pathInfo = null; /** real file system directory of the enclosing servlet's web app */ private String webAppRootDir = null; /** tempdir for context - used to expand scripts in unexpanded wars */ private File tmpDir = null; /** derived cgi environment */ private Hashtable env = null; /** cgi command to be invoked */ private String command = null; /** cgi command's desired working directory */ private File workingDirectory = null; /** cgi command's command line parameters */ private ArrayList cmdLineParameters = new ArrayList(); /** whether or not this object is valid or not */ private boolean valid = false; /** * Creates a CGIEnvironment and derives the necessary environment, * query parameters, working directory, cgi command, etc. * * @param req HttpServletRequest for information provided by * the Servlet API * @param context ServletContext for information provided by the * Servlet API * */ protected CGIEnvironment(HttpServletRequest req, ServletContext context) throws IOException { setupFromContext(context); setupFromRequest(req); this.valid = setCGIEnvironment(req); if (this.valid) { workingDirectory = new File(command.substring(0, command.lastIndexOf(File.separator))); } } /** * Uses the ServletContext to set some CGI variables * * @param context ServletContext for information provided by the * Servlet API */ protected void setupFromContext(ServletContext context) { this.context = context; this.webAppRootDir = context.getRealPath("/"); this.tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR); } /** * Uses the HttpServletRequest to set most CGI variables * * @param req HttpServletRequest for information provided by * the Servlet API * @throws UnsupportedEncodingException */ protected void setupFromRequest(HttpServletRequest req) throws UnsupportedEncodingException { boolean isIncluded = false; // Look to see if this request is an include if (req.getAttribute( RequestDispatcher.INCLUDE_REQUEST_URI) != null) { isIncluded = true; } if (isIncluded) { this.contextPath = (String) req.getAttribute( RequestDispatcher.INCLUDE_CONTEXT_PATH); this.servletPath = (String) req.getAttribute( RequestDispatcher.INCLUDE_SERVLET_PATH); this.pathInfo = (String) req.getAttribute( RequestDispatcher.INCLUDE_PATH_INFO); } else { this.contextPath = req.getContextPath(); this.servletPath = req.getServletPath(); this.pathInfo = req.getPathInfo(); } // If getPathInfo() returns null, must be using extension mapping // In this case, pathInfo should be same as servletPath if (this.pathInfo == null) { this.pathInfo = this.servletPath; } // If the request method is GET, POST or HEAD and the query string // does not contain an unencoded "=" this is an indexed query. // The parsed query string becomes the command line parameters // for the cgi command. if (req.getMethod().equals("GET") || req.getMethod().equals("POST") || req.getMethod().equals("HEAD")) { String qs; if (isIncluded) { qs = (String) req.getAttribute( RequestDispatcher.INCLUDE_QUERY_STRING); } else { qs = req.getQueryString(); } if (qs != null && qs.indexOf("=") == -1) { StringTokenizer qsTokens = new StringTokenizer(qs, "+"); while ( qsTokens.hasMoreTokens() ) { cmdLineParameters.add(URLDecoder.decode(qsTokens.nextToken(), parameterEncoding)); } } } } /** * Resolves core information about the cgi script. * *

    * Example URI: *

     /servlet/cgigateway/dir1/realCGIscript/pathinfo1 
    *
      *
    • path = $CATALINA_HOME/mywebapp/dir1/realCGIscript *
    • scriptName = /servlet/cgigateway/dir1/realCGIscript *
    • cgiName = /dir1/realCGIscript *
    • name = realCGIscript *
    *

    *

    * CGI search algorithm: search the real path below * <my-webapp-root> and find the first non-directory in * the getPathTranslated("/"), reading/searching from left-to-right. *

    *

    * The CGI search path will start at * webAppRootDir + File.separator + cgiPathPrefix * (or webAppRootDir alone if cgiPathPrefix is * null). *

    *

    * cgiPathPrefix is defined by setting * this servlet's cgiPathPrefix init parameter * *

    * * @param pathInfo String from HttpServletRequest.getPathInfo() * @param webAppRootDir String from context.getRealPath("/") * @param contextPath String as from * HttpServletRequest.getContextPath() * @param servletPath String as from * HttpServletRequest.getServletPath() * @param cgiPathPrefix subdirectory of webAppRootDir below which * the web app's CGIs may be stored; can be null. * The CGI search path will start at * webAppRootDir + File.separator + cgiPathPrefix * (or webAppRootDir alone if cgiPathPrefix is * null). cgiPathPrefix is defined by setting * the servlet's cgiPathPrefix init parameter. * * * @return *
      *
    • * path - full file-system path to valid cgi script, * or null if no cgi was found *
    • * scriptName - * CGI variable SCRIPT_NAME; the full URL path * to valid cgi script or null if no cgi was * found *
    • * cgiName - servlet pathInfo fragment corresponding to * the cgi script itself, or null if not found *
    • * name - simple name (no directories) of the * cgi script, or null if no cgi was found *
    * * @since Tomcat 4.0 */ protected String[] findCGI(String pathInfo, String webAppRootDir, String contextPath, String servletPath, String cgiPathPrefix) { String path = null; String name = null; String scriptname = null; String cginame = ""; if ((webAppRootDir != null) && (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1))) { //strip the trailing "/" from the webAppRootDir webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1)); } if (cgiPathPrefix != null) { webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix; } if (debug >= 2) { log("findCGI: path=" + pathInfo + ", " + webAppRootDir); } File currentLocation = new File(webAppRootDir); StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/"); if (debug >= 3) { log("findCGI: currentLoc=" + currentLocation); } while (!currentLocation.isFile() && dirWalker.hasMoreElements()) { if (debug >= 3) { log("findCGI: currentLoc=" + currentLocation); } String nextElement = (String) dirWalker.nextElement(); currentLocation = new File(currentLocation, nextElement); cginame = cginame + "/" + nextElement; } if (!currentLocation.isFile()) { return new String[] { null, null, null, null }; } if (debug >= 2) { log("findCGI: FOUND cgi at " + currentLocation); } path = currentLocation.getAbsolutePath(); name = currentLocation.getName(); if (".".equals(contextPath)) { scriptname = servletPath; } else { scriptname = contextPath + servletPath; } if (!servletPath.equals(cginame)) { scriptname = scriptname + cginame; } if (debug >= 1) { log("findCGI calc: name=" + name + ", path=" + path + ", scriptname=" + scriptname + ", cginame=" + cginame); } return new String[] { path, scriptname, cginame, name }; } /** * Constructs the CGI environment to be supplied to the invoked CGI * script; relies heavily on Servlet API methods and findCGI * * @param req request associated with the CGI * Invocation * * @return true if environment was set OK, false if there * was a problem and no environment was set */ protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { /* * This method is slightly ugly; c'est la vie. * "You cannot stop [ugliness], you can only hope to contain [it]" * (apologies to Marv Albert regarding MJ) */ Hashtable envp = new Hashtable(); // Add the shell environment variables (if any) envp.putAll(shellEnv); // Add the CGI environment variables String sPathInfoOrig = null; String sPathInfoCGI = null; String sPathTranslatedCGI = null; String sCGIFullPath = null; String sCGIScriptName = null; String sCGIFullName = null; String sCGIName = null; String[] sCGINames; sPathInfoOrig = this.pathInfo; sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig; if (webAppRootDir == null ) { // The app has not been deployed in exploded form webAppRootDir = tmpDir.toString(); expandCGIScript(); } sCGINames = findCGI(sPathInfoOrig, webAppRootDir, contextPath, servletPath, cgiPathPrefix); sCGIFullPath = sCGINames[0]; sCGIScriptName = sCGINames[1]; sCGIFullName = sCGINames[2]; sCGIName = sCGINames[3]; if (sCGIFullPath == null || sCGIScriptName == null || sCGIFullName == null || sCGIName == null) { return false; } envp.put("SERVER_SOFTWARE", "TOMCAT"); envp.put("SERVER_NAME", nullsToBlanks(req.getServerName())); envp.put("GATEWAY_INTERFACE", "CGI/1.1"); envp.put("SERVER_PROTOCOL", nullsToBlanks(req.getProtocol())); int port = req.getServerPort(); Integer iPort = (port == 0 ? Integer.valueOf(-1) : Integer.valueOf(port)); envp.put("SERVER_PORT", iPort.toString()); envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod())); envp.put("REQUEST_URI", nullsToBlanks(req.getRequestURI())); /*- * PATH_INFO should be determined by using sCGIFullName: * 1) Let sCGIFullName not end in a "/" (see method findCGI) * 2) Let sCGIFullName equal the pathInfo fragment which * corresponds to the actual cgi script. * 3) Thus, PATH_INFO = request.getPathInfo().substring( * sCGIFullName.length()) * * (see method findCGI, where the real work is done) * */ if (pathInfo == null || (pathInfo.substring(sCGIFullName.length()).length() <= 0)) { sPathInfoCGI = ""; } else { sPathInfoCGI = pathInfo.substring(sCGIFullName.length()); } envp.put("PATH_INFO", sPathInfoCGI); /*- * PATH_TRANSLATED must be determined after PATH_INFO (and the * implied real cgi-script) has been taken into account. * * The following example demonstrates: * * servlet info = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2 * cgifullpath = /servlet/cgigw/dir1/dir2/cgi1 * path_info = /trans1/trans2 * webAppRootDir = servletContext.getRealPath("/") * * path_translated = servletContext.getRealPath("/trans1/trans2") * * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI * (unless sPathInfoCGI is null or blank, then the CGI * specification dictates that the PATH_TRANSLATED metavariable * SHOULD NOT be defined. * */ if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) { sPathTranslatedCGI = context.getRealPath(sPathInfoCGI); } if (sPathTranslatedCGI == null || "".equals(sPathTranslatedCGI)) { //NOOP } else { envp.put("PATH_TRANSLATED", nullsToBlanks(sPathTranslatedCGI)); } envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName)); envp.put("QUERY_STRING", nullsToBlanks(req.getQueryString())); envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost())); envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr())); envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType())); envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser())); envp.put("REMOTE_IDENT", ""); //not necessary for full compliance envp.put("CONTENT_TYPE", nullsToBlanks(req.getContentType())); /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined * if there is no content, so we cannot put 0 or -1 in as per the * Servlet API spec. */ int contentLength = req.getContentLength(); String sContentLength = (contentLength <= 0 ? "" : (Integer.valueOf(contentLength)).toString()); envp.put("CONTENT_LENGTH", sContentLength); Enumeration headers = req.getHeaderNames(); String header = null; while (headers.hasMoreElements()) { header = null; header = headers.nextElement().toUpperCase(Locale.ENGLISH); //REMIND: rewrite multiple headers as if received as single //REMIND: change character set //REMIND: I forgot what the previous REMIND means if ("AUTHORIZATION".equalsIgnoreCase(header) || "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) { //NOOP per CGI specification section 11.2 } else { envp.put("HTTP_" + header.replace('-', '_'), req.getHeader(header)); } } File fCGIFullPath = new File(sCGIFullPath); command = fCGIFullPath.getCanonicalPath(); envp.put("X_TOMCAT_SCRIPT_PATH", command); //for kicks envp.put("SCRIPT_FILENAME", command); //for PHP this.env = envp; return true; } /** * Extracts requested resource from web app archive to context work * directory to enable CGI script to be executed. */ protected void expandCGIScript() { StringBuilder srcPath = new StringBuilder(); StringBuilder destPath = new StringBuilder(); InputStream is = null; // paths depend on mapping if (cgiPathPrefix == null ) { srcPath.append(pathInfo); is = context.getResourceAsStream(srcPath.toString()); destPath.append(tmpDir); destPath.append(pathInfo); } else { // essentially same search algorithm as findCGI() srcPath.append(cgiPathPrefix); StringTokenizer pathWalker = new StringTokenizer (pathInfo, "/"); // start with first element while (pathWalker.hasMoreElements() && (is == null)) { srcPath.append("/"); srcPath.append(pathWalker.nextElement()); is = context.getResourceAsStream(srcPath.toString()); } destPath.append(tmpDir); destPath.append("/"); destPath.append(srcPath); } if (is == null) { // didn't find anything, give up now if (debug >= 2) { log("expandCGIScript: source '" + srcPath + "' not found"); } return; } File f = new File(destPath.toString()); if (f.exists()) { // Don't need to expand if it already exists return; } // create directories String dirPath = destPath.toString().substring( 0,destPath.toString().lastIndexOf("/")); File dir = new File(dirPath); if (!dir.mkdirs() && !dir.isDirectory()) { if (debug >= 2) { log("expandCGIScript: failed to create directories for '" + dir.getAbsolutePath() + "'"); } return; } try { synchronized (expandFileLock) { // make sure file doesn't exist if (f.exists()) { return; } // create file if (!f.createNewFile()) { return; } FileOutputStream fos = new FileOutputStream(f); // copy data IOTools.flow(is, fos); is.close(); fos.close(); if (debug >= 2) { log("expandCGIScript: expanded '" + srcPath + "' to '" + destPath + "'"); } } } catch (IOException ioe) { // delete in case file is corrupted if (f.exists()) { if (!f.delete() && debug >= 2) { log("expandCGIScript: failed to delete '" + f.getAbsolutePath() + "'"); } } } } /** * Print important CGI environment information in a easy-to-read HTML * table * * @return HTML string containing CGI environment info * */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(""); sb.append(""); sb.append(""); if (isValid()) { Enumeration envk = env.keys(); while (envk.hasMoreElements()) { String s = envk.nextElement(); sb.append(""); } } sb.append(""); sb.append(""); sb.append(""); sb.append(""); sb.append("
    "); sb.append("CGIEnvironment Info
    Debug Level"); sb.append(debug); sb.append("
    Validity:"); sb.append(isValid()); sb.append("
    "); sb.append(s); sb.append(""); sb.append(blanksToString(env.get(s), "[will be set to blank]")); sb.append("

    Derived Command"); sb.append(nullsToBlanks(command)); sb.append("
    Working Directory"); if (workingDirectory != null) { sb.append(workingDirectory.toString()); } sb.append("
    Command Line Params"); for (int i=0; i < cmdLineParameters.size(); i++) { String param = cmdLineParameters.get(i); sb.append("

    "); sb.append(param); sb.append("

    "); } sb.append("

    end."); return sb.toString(); } /** * Gets derived command string * * @return command string * */ protected String getCommand() { return command; } /** * Gets derived CGI working directory * * @return working directory * */ protected File getWorkingDirectory() { return workingDirectory; } /** * Gets derived CGI environment * * @return CGI environment * */ protected Hashtable getEnvironment() { return env; } /** * Gets derived CGI query parameters * * @return CGI query parameters * */ protected ArrayList getParameters() { return cmdLineParameters; } /** * Gets validity status * * @return true if this environment is valid, false * otherwise * */ protected boolean isValid() { return valid; } /** * Converts null strings to blank strings ("") * * @param s string to be converted if necessary * @return a non-null string, either the original or the empty string * ("") if the original was null */ protected String nullsToBlanks(String s) { return nullsToString(s, ""); } /** * Converts null strings to another string * * @param couldBeNull string to be converted if necessary * @param subForNulls string to return instead of a null string * @return a non-null string, either the original or the substitute * string if the original was null */ protected String nullsToString(String couldBeNull, String subForNulls) { return (couldBeNull == null ? subForNulls : couldBeNull); } /** * Converts blank strings to another string * * @param couldBeBlank string to be converted if necessary * @param subForBlanks string to return instead of a blank string * @return a non-null string, either the original or the substitute * string if the original was null or empty ("") */ protected String blanksToString(String couldBeBlank, String subForBlanks) { return (("".equals(couldBeBlank) || couldBeBlank == null) ? subForBlanks : couldBeBlank); } } //class CGIEnvironment /** * Encapsulates the knowledge of how to run a CGI script, given the * script's desired environment and (optionally) input/output streams * *

    * * Exposes a run method used to actually invoke the * CGI. * *

    *

    * * The CGI environment and settings are derived from the information * passed to the constructor. * *

    *

    * * The input and output streams can be set by the setInput * and setResponse methods, respectively. *

    */ protected class CGIRunner { /** script/command to be executed */ private String command = null; /** environment used when invoking the cgi script */ private Hashtable env = null; /** working directory used when invoking the cgi script */ private File wd = null; /** command line parameters to be passed to the invoked script */ private ArrayList params = null; /** stdin to be passed to cgi script */ private InputStream stdin = null; /** response object used to set headers & get output stream */ private HttpServletResponse response = null; /** boolean tracking whether this object has enough info to run() */ private boolean readyToRun = false; /** * Creates a CGIRunner and initializes its environment, working * directory, and query parameters. *
    * Input/output streams (optional) are set using the * setInput and setResponse methods, * respectively. * * @param command string full path to command to be executed * @param env Hashtable with the desired script environment * @param wd File with the script's desired working directory * @param params ArrayList with the script's query command line * parameters as strings */ protected CGIRunner(String command, Hashtable env, File wd, ArrayList params) { this.command = command; this.env = env; this.wd = wd; this.params = params; updateReadyStatus(); } /** * Checks & sets ready status */ protected void updateReadyStatus() { if (command != null && env != null && wd != null && params != null && response != null) { readyToRun = true; } else { readyToRun = false; } } /** * Gets ready status * * @return false if not ready (run will throw * an exception), true if ready */ protected boolean isReady() { return readyToRun; } /** * Sets HttpServletResponse object used to set headers and send * output to * * @param response HttpServletResponse to be used * */ protected void setResponse(HttpServletResponse response) { this.response = response; updateReadyStatus(); } /** * Sets standard input to be passed on to the invoked cgi script * * @param stdin InputStream to be used * */ protected void setInput(InputStream stdin) { this.stdin = stdin; updateReadyStatus(); } /** * Converts a Hashtable to a String array by converting each * key/value pair in the Hashtable to a String in the form * "key=value" (hashkey + "=" + hash.get(hashkey).toString()) * * @param h Hashtable to convert * * @return converted string array * * @exception NullPointerException if a hash key has a null value * */ protected String[] hashToStringArray(Hashtable h) throws NullPointerException { Vector v = new Vector(); Enumeration e = h.keys(); while (e.hasMoreElements()) { String k = e.nextElement(); v.add(k + "=" + h.get(k).toString()); } String[] strArr = new String[v.size()]; v.copyInto(strArr); return strArr; } /** * Executes a CGI script with the desired environment, current working * directory, and input/output streams * *

    * This implements the following CGI specification recommedations: *

      *
    • Servers SHOULD provide the "query" component of * the script-URI as command-line arguments to scripts if it * does not contain any unencoded "=" characters and the * command-line arguments can be generated in an unambiguous * manner. *
    • Servers SHOULD set the AUTH_TYPE metavariable to the value * of the "auth-scheme" token of the * "Authorization" if it was supplied as part of the * request header. See getCGIEnvironment method. *
    • Where applicable, servers SHOULD set the current working * directory to the directory in which the script is located * before invoking it. *
    • Server implementations SHOULD define their behavior for the * following cases: *
        *
      • Allowed characters in pathInfo: This implementation * does not allow ASCII NUL nor any character which cannot * be URL-encoded according to internet standards; *
      • Allowed characters in path segments: This * implementation does not allow non-terminal NULL * segments in the the path -- IOExceptions may be thrown; *
      • "." and ".." path * segments: * This implementation does not allow "." and * ".." in the the path, and such characters * will result in an IOException being thrown (this should * never happen since Tomcat normalises the requestURI * before determining the contextPath, servletPath and * pathInfo); *
      • Implementation limitations: This implementation * does not impose any limitations except as documented * above. This implementation may be limited by the * servlet container used to house this implementation. * In particular, all the primary CGI variable values * are derived either directly or indirectly from the * container's implementation of the Servlet API methods. *
      *
    *

    * * @exception IOException if problems during reading/writing occur * * @see java.lang.Runtime#exec(String command, String[] envp, * File dir) */ protected void run() throws IOException { /* * REMIND: this method feels too big; should it be re-written? */ if (!isReady()) { throw new IOException(this.getClass().getName() + ": not ready to run."); } if (debug >= 1 ) { log("runCGI(envp=[" + env + "], command=" + command + ")"); } if ((command.indexOf(File.separator + "." + File.separator) >= 0) || (command.indexOf(File.separator + "..") >= 0) || (command.indexOf(".." + File.separator) >= 0)) { throw new IOException(this.getClass().getName() + "Illegal Character in CGI command " + "path ('.' or '..') detected. Not " + "running CGI [" + command + "]."); } /* original content/structure of this section taken from * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4216884 * with major modifications by Martin Dengler */ Runtime rt = null; BufferedReader cgiHeaderReader = null; InputStream cgiOutput = null; BufferedReader commandsStdErr = null; Thread errReaderThread = null; BufferedOutputStream commandsStdIn = null; Process proc = null; int bufRead = -1; List cmdAndArgs = new ArrayList(); if (cgiExecutable.length() != 0) { cmdAndArgs.add(cgiExecutable); } if (cgiExecutableArgs != null) { cmdAndArgs.addAll(cgiExecutableArgs); } cmdAndArgs.add(command); cmdAndArgs.addAll(params); try { rt = Runtime.getRuntime(); proc = rt.exec( cmdAndArgs.toArray(new String[cmdAndArgs.size()]), hashToStringArray(env), wd); String sContentLength = env.get("CONTENT_LENGTH"); if(!"".equals(sContentLength)) { commandsStdIn = new BufferedOutputStream(proc.getOutputStream()); IOTools.flow(stdin, commandsStdIn); commandsStdIn.flush(); commandsStdIn.close(); } /* we want to wait for the process to exit, Process.waitFor() * is useless in our situation; see * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4223650 */ boolean isRunning = true; commandsStdErr = new BufferedReader (new InputStreamReader(proc.getErrorStream())); final BufferedReader stdErrRdr = commandsStdErr ; errReaderThread = new Thread() { @Override public void run () { sendToLog(stdErrRdr) ; } }; errReaderThread.start(); InputStream cgiHeaderStream = new HTTPHeaderInputStream(proc.getInputStream()); cgiHeaderReader = new BufferedReader(new InputStreamReader(cgiHeaderStream)); while (isRunning) { try { //set headers String line = null; while (((line = cgiHeaderReader.readLine()) != null) && !("".equals(line))) { if (debug >= 2) { log("runCGI: addHeader(\"" + line + "\")"); } if (line.startsWith("HTTP")) { response.setStatus(getSCFromHttpStatusLine(line)); } else if (line.indexOf(":") >= 0) { String header = line.substring(0, line.indexOf(":")).trim(); String value = line.substring(line.indexOf(":") + 1).trim(); if (header.equalsIgnoreCase("status")) { response.setStatus(getSCFromCGIStatusHeader(value)); } else { response.addHeader(header , value); } } else { log("runCGI: bad header line \"" + line + "\""); } } //write output byte[] bBuf = new byte[2048]; OutputStream out = response.getOutputStream(); cgiOutput = proc.getInputStream(); try { while ((bufRead = cgiOutput.read(bBuf)) != -1) { if (debug >= 4) { log("runCGI: output " + bufRead + " bytes of data"); } out.write(bBuf, 0, bufRead); } } finally { // Attempt to consume any leftover byte if something bad happens, // such as a socket disconnect on the servlet side; otherwise, the // external process could hang if (bufRead != -1) { while ((bufRead = cgiOutput.read(bBuf)) != -1) { // NOOP - just read the data } } } proc.exitValue(); // Throws exception if alive isRunning = false; } catch (IllegalThreadStateException e) { try { Thread.sleep(500); } catch (InterruptedException ignored) { // Ignore } } } //replacement for Process.waitFor() } catch (IOException e){ log ("Caught exception " + e); throw e; } finally{ // Close the header reader if (cgiHeaderReader != null) { try { cgiHeaderReader.close(); } catch (IOException ioe) { log ("Exception closing header reader " + ioe); } } // Close the output stream if used if (cgiOutput != null) { try { cgiOutput.close(); } catch (IOException ioe) { log ("Exception closing output stream " + ioe); } } // Make sure the error stream reader has finished if (errReaderThread != null) { try { errReaderThread.join(stderrTimeout); } catch (InterruptedException e) { log ("Interupted waiting for stderr reader thread"); } } if (debug > 4) { log ("Running finally block"); } if (proc != null){ proc.destroy(); proc = null; } } } /** * Parses the Status-Line and extracts the status code. * * @param line The HTTP Status-Line (RFC2616, section 6.1) * @return The extracted status code or the code representing an * internal error if a valid status code cannot be extracted. */ private int getSCFromHttpStatusLine(String line) { int statusStart = line.indexOf(' ') + 1; if (statusStart < 1 || line.length() < statusStart + 3) { // Not a valid HTTP Status-Line log ("runCGI: invalid HTTP Status-Line:" + line); return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; } String status = line.substring(statusStart, statusStart + 3); int statusCode; try { statusCode = Integer.parseInt(status); } catch (NumberFormatException nfe) { // Not a valid status code log ("runCGI: invalid status code:" + status); return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; } return statusCode; } /** * Parses the CGI Status Header value and extracts the status code. * * @param value The CGI Status value of the form * digit digit digit SP reason-phrase * @return The extracted status code or the code representing an * internal error if a valid status code cannot be extracted. */ private int getSCFromCGIStatusHeader(String value) { if (value.length() < 3) { // Not a valid status value log ("runCGI: invalid status value:" + value); return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; } String status = value.substring(0, 3); int statusCode; try { statusCode = Integer.parseInt(status); } catch (NumberFormatException nfe) { // Not a valid status code log ("runCGI: invalid status code:" + status); return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; } return statusCode; } private void sendToLog(BufferedReader rdr) { String line = null; int lineCount = 0 ; try { while ((line = rdr.readLine()) != null) { log("runCGI (stderr):" + line) ; lineCount++ ; } } catch (IOException e) { log("sendToLog error", e) ; } finally { try { rdr.close() ; } catch (IOException ce) { log("sendToLog error", ce) ; } } if ( lineCount > 0 && debug > 2) { log("runCGI: " + lineCount + " lines received on stderr") ; } } } //class CGIRunner /** * This is an input stream specifically for reading HTTP headers. It reads * upto and including the two blank lines terminating the headers. It * allows the content to be read using bytes or characters as appropriate. */ protected static class HTTPHeaderInputStream extends InputStream { private static final int STATE_CHARACTER = 0; private static final int STATE_FIRST_CR = 1; private static final int STATE_FIRST_LF = 2; private static final int STATE_SECOND_CR = 3; private static final int STATE_HEADER_END = 4; private InputStream input; private int state; HTTPHeaderInputStream(InputStream theInput) { input = theInput; state = STATE_CHARACTER; } /** * @see java.io.InputStream#read() */ @Override public int read() throws IOException { if (state == STATE_HEADER_END) { return -1; } int i = input.read(); // Update the state // State machine looks like this // // -------->-------- // | (CR) | // | | // CR1--->--- | // | | | // ^(CR) |(LF) | // | | | // CHAR--->--LF1--->--EOH // (LF) | (LF) | // |(CR) ^(LF) // | | // (CR2)-->--- if (i == 10) { // LF switch(state) { case STATE_CHARACTER: state = STATE_FIRST_LF; break; case STATE_FIRST_CR: state = STATE_FIRST_LF; break; case STATE_FIRST_LF: case STATE_SECOND_CR: state = STATE_HEADER_END; break; } } else if (i == 13) { // CR switch(state) { case STATE_CHARACTER: state = STATE_FIRST_CR; break; case STATE_FIRST_CR: state = STATE_HEADER_END; break; case STATE_FIRST_LF: state = STATE_SECOND_CR; break; } } else { state = STATE_CHARACTER; } return i; } } // class HTTPHeaderInputStream } //class CGIServlet tomcat7-7.0.52/java/org/apache/catalina/servlets/DefaultServlet.java0000644000175100017510000021705612271471332025330 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.servlets; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.StringTokenizer; import javax.naming.InitialContext; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.catalina.Globals; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.connector.ResponseFacade; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.catalina.util.URLEncoder; import org.apache.naming.resources.CacheEntry; import org.apache.naming.resources.ProxyDirContext; import org.apache.naming.resources.Resource; import org.apache.naming.resources.ResourceAttributes; import org.apache.tomcat.util.res.StringManager; /** *

    The default resource-serving servlet for most web applications, * used to serve static resources such as HTML pages and images. *

    *

    * This servlet is intended to be mapped to / e.g.: *

    *
     *   <servlet-mapping>
     *       <servlet-name>default</servlet-name>
     *       <url-pattern>/</url-pattern>
     *   </servlet-mapping>
     * 
    *

    It can be mapped to sub-paths, however in all cases resources are served * from the web appplication resource root using the full path from the root * of the web application context. *
    e.g. given a web application structure: *

    *
     * /context
     *   /images
     *     tomcat2.jpg
     *   /static
     *     /images
     *       tomcat.jpg
     * 
    *

    * ... and a servlet mapping that maps only /static/* to the default servlet: *

    *
     *   <servlet-mapping>
     *       <servlet-name>default</servlet-name>
     *       <url-pattern>/static/*</url-pattern>
     *   </servlet-mapping>
     * 
    *

    * Then a request to /context/static/images/tomcat.jpg will succeed * while a request to /context/images/tomcat2.jpg will fail. *

    * @author Craig R. McClanahan * @author Remy Maucherat */ public class DefaultServlet extends HttpServlet { private static final long serialVersionUID = 1L; // ----------------------------------------------------- Instance Variables /** * The debugging detail level for this servlet. */ protected int debug = 0; /** * The input buffer size to use when serving resources. */ protected int input = 2048; /** * Should we generate directory listings? */ protected boolean listings = false; /** * Read only flag. By default, it's set to true. */ protected boolean readOnly = true; /** * The output buffer size to use when serving resources. */ protected int output = 2048; /** * Array containing the safe characters set. */ protected static final URLEncoder urlEncoder; /** * Allow customized directory listing per directory. */ protected String localXsltFile = null; /** * Allow customized directory listing per context. */ protected String contextXsltFile = null; /** * Allow customized directory listing per instance. */ protected String globalXsltFile = null; /** * Allow a readme file to be included. */ protected String readmeFile = null; /** * Proxy directory context. */ protected transient ProxyDirContext resources = null; /** * File encoding to be used when reading static files. If none is specified * the platform default is used. */ protected String fileEncoding = null; /** * Minimum size for sendfile usage in bytes. */ protected int sendfileSize = 48 * 1024; /** * Should the Accept-Ranges: bytes header be send with static resources? */ protected boolean useAcceptRanges = true; /** * Full range marker. */ protected static final ArrayList FULL = new ArrayList(); // ----------------------------------------------------- Static Initializer /** * GMT timezone - all HTTP dates are on GMT */ static { urlEncoder = new URLEncoder(); urlEncoder.addSafeCharacter('-'); urlEncoder.addSafeCharacter('_'); urlEncoder.addSafeCharacter('.'); urlEncoder.addSafeCharacter('*'); urlEncoder.addSafeCharacter('/'); } /** * MIME multipart separation string */ protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY"; /** * JNDI resources name. */ protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources"; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Size of file transfer buffer in bytes. */ protected static final int BUFFER_SIZE = 4096; // --------------------------------------------------------- Public Methods /** * Finalize this servlet. */ @Override public void destroy() { // NOOP } /** * Initialize this servlet. */ @Override public void init() throws ServletException { if (getServletConfig().getInitParameter("debug") != null) debug = Integer.parseInt(getServletConfig().getInitParameter("debug")); if (getServletConfig().getInitParameter("input") != null) input = Integer.parseInt(getServletConfig().getInitParameter("input")); if (getServletConfig().getInitParameter("output") != null) output = Integer.parseInt(getServletConfig().getInitParameter("output")); listings = Boolean.parseBoolean(getServletConfig().getInitParameter("listings")); if (getServletConfig().getInitParameter("readonly") != null) readOnly = Boolean.parseBoolean(getServletConfig().getInitParameter("readonly")); if (getServletConfig().getInitParameter("sendfileSize") != null) sendfileSize = Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024; fileEncoding = getServletConfig().getInitParameter("fileEncoding"); globalXsltFile = getServletConfig().getInitParameter("globalXsltFile"); contextXsltFile = getServletConfig().getInitParameter("contextXsltFile"); localXsltFile = getServletConfig().getInitParameter("localXsltFile"); readmeFile = getServletConfig().getInitParameter("readmeFile"); if (getServletConfig().getInitParameter("useAcceptRanges") != null) useAcceptRanges = Boolean.parseBoolean(getServletConfig().getInitParameter("useAcceptRanges")); // Sanity check on the specified buffer sizes if (input < 256) input = 256; if (output < 256) output = 256; if (debug > 0) { log("DefaultServlet.init: input buffer size=" + input + ", output buffer size=" + output); } // Load the proxy dir context. resources = (ProxyDirContext) getServletContext() .getAttribute(Globals.RESOURCES_ATTR); if (resources == null) { try { resources = (ProxyDirContext) new InitialContext() .lookup(RESOURCES_JNDI_NAME); } catch (NamingException e) { // Failed throw new ServletException("No resources", e); } } if (resources == null) { throw new UnavailableException("No resources"); } } // ------------------------------------------------------ Protected Methods /** * Return the relative path associated with this servlet. * * @param request The servlet request we are processing */ protected String getRelativePath(HttpServletRequest request) { // IMPORTANT: DefaultServlet can be mapped to '/' or '/path/*' but always // serves resources from the web app root with context rooted paths. // i.e. it can not be used to mount the web app root under a sub-path // This method must construct a complete context rooted path, although // subclasses can change this behaviour. // Are we being processed by a RequestDispatcher.include()? if (request.getAttribute( RequestDispatcher.INCLUDE_REQUEST_URI) != null) { String result = (String) request.getAttribute( RequestDispatcher.INCLUDE_PATH_INFO); if (result == null) { result = (String) request.getAttribute( RequestDispatcher.INCLUDE_SERVLET_PATH); } else { result = (String) request.getAttribute( RequestDispatcher.INCLUDE_SERVLET_PATH) + result; } if ((result == null) || (result.equals(""))) { result = "/"; } return (result); } // No, extract the desired path directly from the request String result = request.getPathInfo(); if (result == null) { result = request.getServletPath(); } else { result = request.getServletPath() + result; } if ((result == null) || (result.equals(""))) { result = "/"; } return (result); } /** * Determines the appropriate path to prepend resources with * when generating directory listings. Depending on the behaviour of * {@link #getRelativePath(HttpServletRequest)} this will change. * @param request the request to determine the path for * @return the prefix to apply to all resources in the listing. */ protected String getPathPrefix(final HttpServletRequest request) { return request.getContextPath(); } /** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Serve the requested resource, including the data content serveResource(request, response, true); } /** * Process a HEAD request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override protected void doHead(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Serve the requested resource, without the data content serveResource(request, response, false); } /** * Override default implementation to ensure that TRACE is correctly * handled. * * @param req the {@link HttpServletRequest} object that * contains the request the client made of * the servlet * * @param resp the {@link HttpServletResponse} object that * contains the response the servlet returns * to the client * * @exception IOException if an input or output error occurs * while the servlet is handling the * OPTIONS request * * @exception ServletException if the request for the * OPTIONS cannot be handled */ @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { StringBuilder allow = new StringBuilder(); // There is a doGet method allow.append("GET, HEAD"); // There is a doPost allow.append(", POST"); // There is a doPut allow.append(", PUT"); // There is a doDelete allow.append(", DELETE"); // Trace - assume disabled unless we can prove otherwise if (req instanceof RequestFacade && ((RequestFacade) req).getAllowTrace()) { allow.append(", TRACE"); } // Always allow options allow.append(", OPTIONS"); resp.setHeader("Allow", allow.toString()); } /** * Process a POST request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } /** * Process a PUT request for the specified resource. * * @param req The servlet request we are processing * @param resp The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (readOnly) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } String path = getRelativePath(req); boolean exists = true; try { resources.lookup(path); } catch (NamingException e) { exists = false; } boolean result = true; // Temp. content file used to support partial PUT File contentFile = null; Range range = parseContentRange(req, resp); InputStream resourceInputStream = null; // Append data specified in ranges to existing content for this // resource - create a temp. file on the local filesystem to // perform this operation // Assume just one range is specified for now if (range != null) { contentFile = executePartialPut(req, range, path); resourceInputStream = new FileInputStream(contentFile); } else { resourceInputStream = req.getInputStream(); } try { Resource newResource = new Resource(resourceInputStream); // FIXME: Add attributes if (exists) { resources.rebind(path, newResource); } else { resources.bind(path, newResource); } } catch(NamingException e) { result = false; } if (result) { if (exists) { resp.setStatus(HttpServletResponse.SC_NO_CONTENT); } else { resp.setStatus(HttpServletResponse.SC_CREATED); } } else { resp.sendError(HttpServletResponse.SC_CONFLICT); } } /** * Handle a partial PUT. New content specified in request is appended to * existing content in oldRevisionContent (if present). This code does * not support simultaneous partial updates to the same resource. */ protected File executePartialPut(HttpServletRequest req, Range range, String path) throws IOException { // Append data specified in ranges to existing content for this // resource - create a temp. file on the local filesystem to // perform this operation File tempDir = (File) getServletContext().getAttribute (ServletContext.TEMPDIR); // Convert all '/' characters to '.' in resourcePath String convertedResourcePath = path.replace('/', '.'); File contentFile = new File(tempDir, convertedResourcePath); if (contentFile.createNewFile()) { // Clean up contentFile when Tomcat is terminated contentFile.deleteOnExit(); } RandomAccessFile randAccessContentFile = new RandomAccessFile(contentFile, "rw"); Resource oldResource = null; try { Object obj = resources.lookup(path); if (obj instanceof Resource) oldResource = (Resource) obj; } catch (NamingException e) { // Ignore } // Copy data in oldRevisionContent to contentFile if (oldResource != null) { BufferedInputStream bufOldRevStream = new BufferedInputStream(oldResource.streamContent(), BUFFER_SIZE); int numBytesRead; byte[] copyBuffer = new byte[BUFFER_SIZE]; while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) { randAccessContentFile.write(copyBuffer, 0, numBytesRead); } bufOldRevStream.close(); } randAccessContentFile.setLength(range.length); // Append data in request input stream to contentFile randAccessContentFile.seek(range.start); int numBytesRead; byte[] transferBuffer = new byte[BUFFER_SIZE]; BufferedInputStream requestBufInStream = new BufferedInputStream(req.getInputStream(), BUFFER_SIZE); while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) { randAccessContentFile.write(transferBuffer, 0, numBytesRead); } randAccessContentFile.close(); requestBufInStream.close(); return contentFile; } /** * Process a DELETE request for the specified resource. * * @param req The servlet request we are processing * @param resp The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (readOnly) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } String path = getRelativePath(req); boolean exists = true; try { resources.lookup(path); } catch (NamingException e) { exists = false; } if (exists) { boolean result = true; try { resources.unbind(path); } catch (NamingException e) { result = false; } if (result) { resp.setStatus(HttpServletResponse.SC_NO_CONTENT); } else { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } } else { resp.sendError(HttpServletResponse.SC_NOT_FOUND); } } /** * Check if the conditions specified in the optional If headers are * satisfied. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param resourceAttributes The resource information * @return boolean true if the resource meets all the specified conditions, * and false if any of the conditions is not satisfied, in which case * request processing is stopped */ protected boolean checkIfHeaders(HttpServletRequest request, HttpServletResponse response, ResourceAttributes resourceAttributes) throws IOException { return checkIfMatch(request, response, resourceAttributes) && checkIfModifiedSince(request, response, resourceAttributes) && checkIfNoneMatch(request, response, resourceAttributes) && checkIfUnmodifiedSince(request, response, resourceAttributes); } /** * URL rewriter. * * @param path Path which has to be rewritten */ protected String rewriteUrl(String path) { return urlEncoder.encode( path ); } /** * Display the size of a file. * @deprecated Will be removed in Tomcat 8.0.x. Replaced by * {@link #renderSize(long)} */ @Deprecated protected void displaySize(StringBuilder buf, int filesize) { int leftside = filesize / 1024; int rightside = (filesize % 1024) / 103; // makes 1 digit // To avoid 0.0 for non-zero file, we bump to 0.1 if (leftside == 0 && rightside == 0 && filesize != 0) rightside = 1; buf.append(leftside).append(".").append(rightside); buf.append(" KB"); } /** * Serve the specified resource, optionally including the data content. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param content Should the content be included? * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ protected void serveResource(HttpServletRequest request, HttpServletResponse response, boolean content) throws IOException, ServletException { boolean serveContent = content; // Identify the requested resource path String path = getRelativePath(request); if (debug > 0) { if (serveContent) log("DefaultServlet.serveResource: Serving resource '" + path + "' headers and data"); else log("DefaultServlet.serveResource: Serving resource '" + path + "' headers only"); } CacheEntry cacheEntry = resources.lookupCache(path); if (!cacheEntry.exists) { // Check if we're included so we can return the appropriate // missing resource name in the error String requestUri = (String) request.getAttribute( RequestDispatcher.INCLUDE_REQUEST_URI); if (requestUri == null) { requestUri = request.getRequestURI(); } else { // We're included // SRV.9.3 says we must throw a FNFE throw new FileNotFoundException( sm.getString("defaultServlet.missingResource", requestUri)); } response.sendError(HttpServletResponse.SC_NOT_FOUND, requestUri); return; } // If the resource is not a collection, and the resource path // ends with "/" or "\", return NOT FOUND if (cacheEntry.context == null) { if (path.endsWith("/") || (path.endsWith("\\"))) { // Check if we're included so we can return the appropriate // missing resource name in the error String requestUri = (String) request.getAttribute( RequestDispatcher.INCLUDE_REQUEST_URI); if (requestUri == null) { requestUri = request.getRequestURI(); } response.sendError(HttpServletResponse.SC_NOT_FOUND, requestUri); return; } } boolean isError = response.getStatus() >= HttpServletResponse.SC_BAD_REQUEST; // Check if the conditions specified in the optional If headers are // satisfied. if (cacheEntry.context == null) { // Checking If headers boolean included = (request.getAttribute( RequestDispatcher.INCLUDE_CONTEXT_PATH) != null); if (!included && !isError && !checkIfHeaders(request, response, cacheEntry.attributes)) { return; } } // Find content type. String contentType = cacheEntry.attributes.getMimeType(); if (contentType == null) { contentType = getServletContext().getMimeType(cacheEntry.name); cacheEntry.attributes.setMimeType(contentType); } ArrayList ranges = null; long contentLength = -1L; if (cacheEntry.context != null) { // Skip directory listings if we have been configured to // suppress them if (!listings) { response.sendError(HttpServletResponse.SC_NOT_FOUND, request.getRequestURI()); return; } contentType = "text/html;charset=UTF-8"; } else { if (!isError) { if (useAcceptRanges) { // Accept ranges header response.setHeader("Accept-Ranges", "bytes"); } // Parse range specifier ranges = parseRange(request, response, cacheEntry.attributes); // ETag header response.setHeader("ETag", cacheEntry.attributes.getETag()); // Last-Modified header response.setHeader("Last-Modified", cacheEntry.attributes.getLastModifiedHttp()); } // Get content length contentLength = cacheEntry.attributes.getContentLength(); // Special case for zero length files, which would cause a // (silent) ISE when setting the output buffer size if (contentLength == 0L) { serveContent = false; } } ServletOutputStream ostream = null; PrintWriter writer = null; if (serveContent) { // Trying to retrieve the servlet output stream try { ostream = response.getOutputStream(); } catch (IllegalStateException e) { // If it fails, we try to get a Writer instead if we're // trying to serve a text file if ( (contentType == null) || (contentType.startsWith("text")) || (contentType.endsWith("xml")) || (contentType.contains("/javascript")) ) { writer = response.getWriter(); // Cannot reliably serve partial content with a Writer ranges = FULL; } else { throw e; } } } // Check to see if a Filter, Valve of wrapper has written some content. // If it has, disable range requests and setting of a content length // since neither can be done reliably. ServletResponse r = response; long contentWritten = 0; while (r instanceof ServletResponseWrapper) { r = ((ServletResponseWrapper) r).getResponse(); } if (r instanceof ResponseFacade) { contentWritten = ((ResponseFacade) r).getContentWritten(); } if (contentWritten > 0) { ranges = FULL; } if ( (cacheEntry.context != null) || isError || ( ((ranges == null) || (ranges.isEmpty())) && (request.getHeader("Range") == null) ) || (ranges == FULL) ) { // Set the appropriate output headers if (contentType != null) { if (debug > 0) log("DefaultServlet.serveFile: contentType='" + contentType + "'"); response.setContentType(contentType); } if ((cacheEntry.resource != null) && (contentLength >= 0) && (!serveContent || ostream != null)) { if (debug > 0) log("DefaultServlet.serveFile: contentLength=" + contentLength); // Don't set a content length if something else has already // written to the response. if (contentWritten == 0) { if (contentLength < Integer.MAX_VALUE) { response.setContentLength((int) contentLength); } else { // Set the content-length as String to be able to use a // long response.setHeader("content-length", "" + contentLength); } } } InputStream renderResult = null; if (cacheEntry.context != null) { if (serveContent) { // Serve the directory browser renderResult = render(getPathPrefix(request), cacheEntry); } } // Copy the input stream to our output stream (if requested) if (serveContent) { try { response.setBufferSize(output); } catch (IllegalStateException e) { // Silent catch } if (ostream != null) { if (!checkSendfile(request, response, cacheEntry, contentLength, null)) copy(cacheEntry, renderResult, ostream); } else { copy(cacheEntry, renderResult, writer); } } } else { if ((ranges == null) || (ranges.isEmpty())) return; // Partial content response. response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); if (ranges.size() == 1) { Range range = ranges.get(0); response.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length); long length = range.end - range.start + 1; if (length < Integer.MAX_VALUE) { response.setContentLength((int) length); } else { // Set the content-length as String to be able to use a long response.setHeader("content-length", "" + length); } if (contentType != null) { if (debug > 0) log("DefaultServlet.serveFile: contentType='" + contentType + "'"); response.setContentType(contentType); } if (serveContent) { try { response.setBufferSize(output); } catch (IllegalStateException e) { // Silent catch } if (ostream != null) { if (!checkSendfile(request, response, cacheEntry, range.end - range.start + 1, range)) copy(cacheEntry, ostream, range); } else { // we should not get here throw new IllegalStateException(); } } } else { response.setContentType("multipart/byteranges; boundary=" + mimeSeparation); if (serveContent) { try { response.setBufferSize(output); } catch (IllegalStateException e) { // Silent catch } if (ostream != null) { copy(cacheEntry, ostream, ranges.iterator(), contentType); } else { // we should not get here throw new IllegalStateException(); } } } } } /** * Parse the content-range header. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @return Range */ protected Range parseContentRange(HttpServletRequest request, HttpServletResponse response) throws IOException { // Retrieving the content-range header (if any is specified String rangeHeader = request.getHeader("Content-Range"); if (rangeHeader == null) return null; // bytes is the only range unit supported if (!rangeHeader.startsWith("bytes")) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } rangeHeader = rangeHeader.substring(6).trim(); int dashPos = rangeHeader.indexOf('-'); int slashPos = rangeHeader.indexOf('/'); if (dashPos == -1) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } if (slashPos == -1) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } Range range = new Range(); try { range.start = Long.parseLong(rangeHeader.substring(0, dashPos)); range.end = Long.parseLong(rangeHeader.substring(dashPos + 1, slashPos)); range.length = Long.parseLong (rangeHeader.substring(slashPos + 1, rangeHeader.length())); } catch (NumberFormatException e) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } if (!range.validate()) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return null; } return range; } /** * Parse the range header. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @return Vector of ranges */ protected ArrayList parseRange(HttpServletRequest request, HttpServletResponse response, ResourceAttributes resourceAttributes) throws IOException { // Checking If-Range String headerValue = request.getHeader("If-Range"); if (headerValue != null) { long headerValueTime = (-1L); try { headerValueTime = request.getDateHeader("If-Range"); } catch (IllegalArgumentException e) { // Ignore } String eTag = resourceAttributes.getETag(); long lastModified = resourceAttributes.getLastModified(); if (headerValueTime == (-1L)) { // If the ETag the client gave does not match the entity // etag, then the entire entity is returned. if (!eTag.equals(headerValue.trim())) return FULL; } else { // If the timestamp of the entity the client got is older than // the last modification date of the entity, the entire entity // is returned. if (lastModified > (headerValueTime + 1000)) return FULL; } } long fileLength = resourceAttributes.getContentLength(); if (fileLength == 0) return null; // Retrieving the range header (if any is specified String rangeHeader = request.getHeader("Range"); if (rangeHeader == null) return null; // bytes is the only range unit supported (and I don't see the point // of adding new ones). if (!rangeHeader.startsWith("bytes")) { response.addHeader("Content-Range", "bytes */" + fileLength); response.sendError (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; } rangeHeader = rangeHeader.substring(6); // Vector which will contain all the ranges which are successfully // parsed. ArrayList result = new ArrayList(); StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ","); // Parsing the range list while (commaTokenizer.hasMoreTokens()) { String rangeDefinition = commaTokenizer.nextToken().trim(); Range currentRange = new Range(); currentRange.length = fileLength; int dashPos = rangeDefinition.indexOf('-'); if (dashPos == -1) { response.addHeader("Content-Range", "bytes */" + fileLength); response.sendError (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; } if (dashPos == 0) { try { long offset = Long.parseLong(rangeDefinition); currentRange.start = fileLength + offset; currentRange.end = fileLength - 1; } catch (NumberFormatException e) { response.addHeader("Content-Range", "bytes */" + fileLength); response.sendError (HttpServletResponse .SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; } } else { try { currentRange.start = Long.parseLong (rangeDefinition.substring(0, dashPos)); if (dashPos < rangeDefinition.length() - 1) currentRange.end = Long.parseLong (rangeDefinition.substring (dashPos + 1, rangeDefinition.length())); else currentRange.end = fileLength - 1; } catch (NumberFormatException e) { response.addHeader("Content-Range", "bytes */" + fileLength); response.sendError (HttpServletResponse .SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; } } if (!currentRange.validate()) { response.addHeader("Content-Range", "bytes */" + fileLength); response.sendError (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; } result.add(currentRange); } return result; } /** * Decide which way to render. HTML or XML. */ protected InputStream render(String contextPath, CacheEntry cacheEntry) throws IOException, ServletException { InputStream xsltInputStream = findXsltInputStream(cacheEntry.context); if (xsltInputStream==null) { return renderHtml(contextPath, cacheEntry); } return renderXml(contextPath, cacheEntry, xsltInputStream); } /** * Return an InputStream to an HTML representation of the contents * of this directory. * * @param contextPath Context path to which our internal paths are * relative */ protected InputStream renderXml(String contextPath, CacheEntry cacheEntry, InputStream xsltInputStream) throws IOException, ServletException { StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(""); sb.append(""); try { // Render the directory entries within this directory NamingEnumeration enumeration = resources.list(cacheEntry.name); // rewriteUrl(contextPath) is expensive. cache result for later reuse String rewrittenContextPath = rewriteUrl(contextPath); while (enumeration.hasMoreElements()) { NameClassPair ncPair = enumeration.nextElement(); String resourceName = ncPair.getName(); String trimmed = resourceName/*.substring(trim)*/; if (trimmed.equalsIgnoreCase("WEB-INF") || trimmed.equalsIgnoreCase("META-INF") || trimmed.equalsIgnoreCase(localXsltFile)) continue; if ((cacheEntry.name + trimmed).equals(contextXsltFile)) continue; CacheEntry childCacheEntry = resources.lookupCache(cacheEntry.name + resourceName); if (!childCacheEntry.exists) { continue; } sb.append(""); sb.append(RequestUtil.filter(trimmed)); if (childCacheEntry.context != null) sb.append("/"); sb.append(""); } } catch (NamingException e) { // Something went wrong throw new ServletException("Error accessing resource", e); } sb.append(""); String readme = getReadme(cacheEntry.context); if (readme!=null) { sb.append(""); } sb.append(""); try { TransformerFactory tFactory = TransformerFactory.newInstance(); Source xmlSource = new StreamSource(new StringReader(sb.toString())); Source xslSource = new StreamSource(xsltInputStream); Transformer transformer = tFactory.newTransformer(xslSource); ByteArrayOutputStream stream = new ByteArrayOutputStream(); OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8"); StreamResult out = new StreamResult(osWriter); transformer.transform(xmlSource, out); osWriter.flush(); return (new ByteArrayInputStream(stream.toByteArray())); } catch (TransformerException e) { throw new ServletException("XSL transformer error", e); } } /** * Return an InputStream to an HTML representation of the contents * of this directory. * * @param contextPath Context path to which our internal paths are * relative */ protected InputStream renderHtml(String contextPath, CacheEntry cacheEntry) throws IOException, ServletException { String name = cacheEntry.name; // Prepare a writer to a buffered area ByteArrayOutputStream stream = new ByteArrayOutputStream(); OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8"); PrintWriter writer = new PrintWriter(osWriter); StringBuilder sb = new StringBuilder(); // rewriteUrl(contextPath) is expensive. cache result for later reuse String rewrittenContextPath = rewriteUrl(contextPath); // Render the page header sb.append("\r\n"); sb.append("\r\n"); sb.append(""); sb.append(sm.getString("directory.title", name)); sb.append("\r\n"); sb.append(" "); sb.append("\r\n"); sb.append(""); sb.append("

    "); sb.append(sm.getString("directory.title", name)); // Render the link to our parent (if required) String parentDirectory = name; if (parentDirectory.endsWith("/")) { parentDirectory = parentDirectory.substring(0, parentDirectory.length() - 1); } int slash = parentDirectory.lastIndexOf('/'); if (slash >= 0) { String parent = name.substring(0, slash); sb.append(" - "); sb.append(""); sb.append(sm.getString("directory.parent", parent)); sb.append(""); sb.append(""); } sb.append("

    "); sb.append("
    "); sb.append("\r\n"); // Render the column headings sb.append("\r\n"); sb.append("\r\n"); sb.append("\r\n"); sb.append("\r\n"); sb.append(""); try { // Render the directory entries within this directory NamingEnumeration enumeration = resources.list(cacheEntry.name); boolean shade = false; while (enumeration.hasMoreElements()) { NameClassPair ncPair = enumeration.nextElement(); String resourceName = ncPair.getName(); String trimmed = resourceName/*.substring(trim)*/; if (trimmed.equalsIgnoreCase("WEB-INF") || trimmed.equalsIgnoreCase("META-INF")) continue; CacheEntry childCacheEntry = resources.lookupCache(cacheEntry.name + resourceName); if (!childCacheEntry.exists) { continue; } sb.append("\r\n"); shade = !shade; sb.append("\r\n"); sb.append("\r\n"); sb.append("\r\n"); sb.append("\r\n"); } } catch (NamingException e) { // Something went wrong throw new ServletException("Error accessing resource", e); } // Render the page footer sb.append("
    "); sb.append(sm.getString("directory.filename")); sb.append(""); sb.append(sm.getString("directory.size")); sb.append(""); sb.append(sm.getString("directory.lastModified")); sb.append("
      \r\n"); sb.append(""); sb.append(RequestUtil.filter(trimmed)); if (childCacheEntry.context != null) sb.append("/"); sb.append(""); if (childCacheEntry.context != null) sb.append(" "); else sb.append(renderSize(childCacheEntry.attributes.getContentLength())); sb.append(""); sb.append(childCacheEntry.attributes.getLastModifiedHttp()); sb.append("
    \r\n"); sb.append("
    "); String readme = getReadme(cacheEntry.context); if (readme!=null) { sb.append(readme); sb.append("
    "); } sb.append("

    ").append(ServerInfo.getServerInfo()).append("

    "); sb.append("\r\n"); sb.append("\r\n"); // Return an input stream to the underlying bytes writer.write(sb.toString()); writer.flush(); return (new ByteArrayInputStream(stream.toByteArray())); } /** * Render the specified file size (in bytes). * * @param size File size (in bytes) */ protected String renderSize(long size) { long leftSide = size / 1024; long rightSide = (size % 1024) / 103; // Makes 1 digit if ((leftSide == 0) && (rightSide == 0) && (size > 0)) rightSide = 1; return ("" + leftSide + "." + rightSide + " kb"); } /** * Get the readme file as a string. */ protected String getReadme(DirContext directory) throws IOException { if (readmeFile != null) { try { Object obj = directory.lookup(readmeFile); if ((obj != null) && (obj instanceof Resource)) { StringWriter buffer = new StringWriter(); InputStream is = ((Resource) obj).streamContent(); copyRange(new InputStreamReader(is), new PrintWriter(buffer)); return buffer.toString(); } } catch (NamingException e) { if (debug > 10) log("readme '" + readmeFile + "' not found", e); return null; } } return null; } /** * Return the xsl template inputstream (if possible) */ protected InputStream findXsltInputStream(DirContext directory) throws IOException { if (localXsltFile != null) { try { Object obj = directory.lookup(localXsltFile); if ((obj != null) && (obj instanceof Resource)) { InputStream is = ((Resource) obj).streamContent(); if (is != null) return is; } } catch (NamingException e) { if (debug > 10) log("localXsltFile '" + localXsltFile + "' not found", e); } } if (contextXsltFile != null) { InputStream is = getServletContext().getResourceAsStream(contextXsltFile); if (is != null) return is; if (debug > 10) log("contextXsltFile '" + contextXsltFile + "' not found"); } /* Open and read in file in one fell swoop to reduce chance * chance of leaving handle open. */ if (globalXsltFile!=null) { FileInputStream fis = null; try { File f = new File(globalXsltFile); if (f.exists()){ fis =new FileInputStream(f); byte b[] = new byte[(int)f.length()]; /* danger! */ fis.read(b); return new ByteArrayInputStream(b); } } finally { if (fis!=null) fis.close(); } } return null; } // -------------------------------------------------------- protected Methods /** * Check if sendfile can be used. */ protected boolean checkSendfile(HttpServletRequest request, HttpServletResponse response, CacheEntry entry, long length, Range range) { if ((sendfileSize > 0) && (entry.resource != null) && ((length > sendfileSize) || (entry.resource.getContent() == null)) && (entry.attributes.getCanonicalPath() != null) && (Boolean.TRUE == request.getAttribute(Globals.SENDFILE_SUPPORTED_ATTR)) && (request.getClass().getName().equals("org.apache.catalina.connector.RequestFacade")) && (response.getClass().getName().equals("org.apache.catalina.connector.ResponseFacade"))) { request.setAttribute(Globals.SENDFILE_FILENAME_ATTR, entry.attributes.getCanonicalPath()); if (range == null) { request.setAttribute(Globals.SENDFILE_FILE_START_ATTR, Long.valueOf(0L)); request.setAttribute(Globals.SENDFILE_FILE_END_ATTR, Long.valueOf(length)); } else { request.setAttribute(Globals.SENDFILE_FILE_START_ATTR, Long.valueOf(range.start)); request.setAttribute(Globals.SENDFILE_FILE_END_ATTR, Long.valueOf(range.end + 1)); } return true; } return false; } /** * Check if the if-match condition is satisfied. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param resourceAttributes File object * @return boolean true if the resource meets the specified condition, * and false if the condition is not satisfied, in which case request * processing is stopped */ protected boolean checkIfMatch(HttpServletRequest request, HttpServletResponse response, ResourceAttributes resourceAttributes) throws IOException { String eTag = resourceAttributes.getETag(); String headerValue = request.getHeader("If-Match"); if (headerValue != null) { if (headerValue.indexOf('*') == -1) { StringTokenizer commaTokenizer = new StringTokenizer (headerValue, ","); boolean conditionSatisfied = false; while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) { String currentToken = commaTokenizer.nextToken(); if (currentToken.trim().equals(eTag)) conditionSatisfied = true; } // If none of the given ETags match, 412 Precodition failed is // sent back if (!conditionSatisfied) { response.sendError (HttpServletResponse.SC_PRECONDITION_FAILED); return false; } } } return true; } /** * Check if the if-modified-since condition is satisfied. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param resourceAttributes File object * @return boolean true if the resource meets the specified condition, * and false if the condition is not satisfied, in which case request * processing is stopped */ protected boolean checkIfModifiedSince(HttpServletRequest request, HttpServletResponse response, ResourceAttributes resourceAttributes) { try { long headerValue = request.getDateHeader("If-Modified-Since"); long lastModified = resourceAttributes.getLastModified(); if (headerValue != -1) { // If an If-None-Match header has been specified, if modified since // is ignored. if ((request.getHeader("If-None-Match") == null) && (lastModified < headerValue + 1000)) { // The entity has not been modified since the date // specified by the client. This is not an error case. response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setHeader("ETag", resourceAttributes.getETag()); return false; } } } catch (IllegalArgumentException illegalArgument) { return true; } return true; } /** * Check if the if-none-match condition is satisfied. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param resourceAttributes File object * @return boolean true if the resource meets the specified condition, * and false if the condition is not satisfied, in which case request * processing is stopped */ protected boolean checkIfNoneMatch(HttpServletRequest request, HttpServletResponse response, ResourceAttributes resourceAttributes) throws IOException { String eTag = resourceAttributes.getETag(); String headerValue = request.getHeader("If-None-Match"); if (headerValue != null) { boolean conditionSatisfied = false; if (!headerValue.equals("*")) { StringTokenizer commaTokenizer = new StringTokenizer(headerValue, ","); while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) { String currentToken = commaTokenizer.nextToken(); if (currentToken.trim().equals(eTag)) conditionSatisfied = true; } } else { conditionSatisfied = true; } if (conditionSatisfied) { // For GET and HEAD, we should respond with // 304 Not Modified. // For every other method, 412 Precondition Failed is sent // back. if ( ("GET".equals(request.getMethod())) || ("HEAD".equals(request.getMethod())) ) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setHeader("ETag", eTag); return false; } response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return false; } } return true; } /** * Check if the if-unmodified-since condition is satisfied. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param resourceAttributes File object * @return boolean true if the resource meets the specified condition, * and false if the condition is not satisfied, in which case request * processing is stopped */ protected boolean checkIfUnmodifiedSince(HttpServletRequest request, HttpServletResponse response, ResourceAttributes resourceAttributes) throws IOException { try { long lastModified = resourceAttributes.getLastModified(); long headerValue = request.getDateHeader("If-Unmodified-Since"); if (headerValue != -1) { if ( lastModified >= (headerValue + 1000)) { // The entity has not been modified since the date // specified by the client. This is not an error case. response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return false; } } } catch(IllegalArgumentException illegalArgument) { return true; } return true; } /** * Copy the contents of the specified input stream to the specified * output stream, and ensure that both streams are closed before returning * (even in the face of an exception). * * @param cacheEntry The cache entry for the source resource * @param is The input stream to read the source resource from * @param ostream The output stream to write to * * @exception IOException if an input/output error occurs */ protected void copy(CacheEntry cacheEntry, InputStream is, ServletOutputStream ostream) throws IOException { IOException exception = null; InputStream resourceInputStream = null; // Optimization: If the binary content has already been loaded, send // it directly if (cacheEntry.resource != null) { byte buffer[] = cacheEntry.resource.getContent(); if (buffer != null) { ostream.write(buffer, 0, buffer.length); return; } resourceInputStream = cacheEntry.resource.streamContent(); } else { resourceInputStream = is; } InputStream istream = new BufferedInputStream (resourceInputStream, input); // Copy the input stream to the output stream exception = copyRange(istream, ostream); // Clean up the input stream istream.close(); // Rethrow any exception that has occurred if (exception != null) throw exception; } /** * Copy the contents of the specified input stream to the specified * output stream, and ensure that both streams are closed before returning * (even in the face of an exception). * * @param cacheEntry The cache entry for the source resource * @param is The input stream to read the source resource from * @param writer The writer to write to * * @exception IOException if an input/output error occurs */ protected void copy(CacheEntry cacheEntry, InputStream is, PrintWriter writer) throws IOException { IOException exception = null; InputStream resourceInputStream = null; if (cacheEntry.resource != null) { resourceInputStream = cacheEntry.resource.streamContent(); } else { resourceInputStream = is; } Reader reader; if (fileEncoding == null) { reader = new InputStreamReader(resourceInputStream); } else { reader = new InputStreamReader(resourceInputStream, fileEncoding); } // Copy the input stream to the output stream exception = copyRange(reader, writer); // Clean up the reader reader.close(); // Rethrow any exception that has occurred if (exception != null) throw exception; } /** * Copy the contents of the specified input stream to the specified * output stream, and ensure that both streams are closed before returning * (even in the face of an exception). * * @param cacheEntry The cache entry for the source resource * @param ostream The output stream to write to * @param range Range the client wanted to retrieve * @exception IOException if an input/output error occurs */ protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream, Range range) throws IOException { IOException exception = null; InputStream resourceInputStream = cacheEntry.resource.streamContent(); InputStream istream = new BufferedInputStream(resourceInputStream, input); exception = copyRange(istream, ostream, range.start, range.end); // Clean up the input stream istream.close(); // Rethrow any exception that has occurred if (exception != null) throw exception; } /** * Copy the contents of the specified input stream to the specified * output stream, and ensure that both streams are closed before returning * (even in the face of an exception). * * @param cacheEntry The cache entry for the source resource * @param ostream The output stream to write to * @param ranges Enumeration of the ranges the client wanted to retrieve * @param contentType Content type of the resource * @exception IOException if an input/output error occurs */ protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream, Iterator ranges, String contentType) throws IOException { IOException exception = null; while ( (exception == null) && (ranges.hasNext()) ) { InputStream resourceInputStream = cacheEntry.resource.streamContent(); InputStream istream = new BufferedInputStream(resourceInputStream, input); Range currentRange = ranges.next(); // Writing MIME header. ostream.println(); ostream.println("--" + mimeSeparation); if (contentType != null) ostream.println("Content-Type: " + contentType); ostream.println("Content-Range: bytes " + currentRange.start + "-" + currentRange.end + "/" + currentRange.length); ostream.println(); // Printing content exception = copyRange(istream, ostream, currentRange.start, currentRange.end); istream.close(); } ostream.println(); ostream.print("--" + mimeSeparation + "--"); // Rethrow any exception that has occurred if (exception != null) throw exception; } /** * Copy the contents of the specified input stream to the specified * output stream, and ensure that both streams are closed before returning * (even in the face of an exception). * * @param istream The input stream to read from * @param ostream The output stream to write to * @return Exception which occurred during processing */ protected IOException copyRange(InputStream istream, ServletOutputStream ostream) { // Copy the input stream to the output stream IOException exception = null; byte buffer[] = new byte[input]; int len = buffer.length; while (true) { try { len = istream.read(buffer); if (len == -1) break; ostream.write(buffer, 0, len); } catch (IOException e) { exception = e; len = -1; break; } } return exception; } /** * Copy the contents of the specified input stream to the specified * output stream, and ensure that both streams are closed before returning * (even in the face of an exception). * * @param reader The reader to read from * @param writer The writer to write to * @return Exception which occurred during processing */ protected IOException copyRange(Reader reader, PrintWriter writer) { // Copy the input stream to the output stream IOException exception = null; char buffer[] = new char[input]; int len = buffer.length; while (true) { try { len = reader.read(buffer); if (len == -1) break; writer.write(buffer, 0, len); } catch (IOException e) { exception = e; len = -1; break; } } return exception; } /** * Copy the contents of the specified input stream to the specified * output stream, and ensure that both streams are closed before returning * (even in the face of an exception). * * @param istream The input stream to read from * @param ostream The output stream to write to * @param start Start of the range which will be copied * @param end End of the range which will be copied * @return Exception which occurred during processing */ protected IOException copyRange(InputStream istream, ServletOutputStream ostream, long start, long end) { if (debug > 10) log("Serving bytes:" + start + "-" + end); long skipped = 0; try { skipped = istream.skip(start); } catch (IOException e) { return e; } if (skipped < start) { return new IOException(sm.getString("defaultservlet.skipfail", Long.valueOf(skipped), Long.valueOf(start))); } IOException exception = null; long bytesToRead = end - start + 1; byte buffer[] = new byte[input]; int len = buffer.length; while ( (bytesToRead > 0) && (len >= buffer.length)) { try { len = istream.read(buffer); if (bytesToRead >= len) { ostream.write(buffer, 0, len); bytesToRead -= len; } else { ostream.write(buffer, 0, (int) bytesToRead); bytesToRead = 0; } } catch (IOException e) { exception = e; len = -1; } if (len < buffer.length) break; } return exception; } // ------------------------------------------------------ Range Inner Class protected static class Range { public long start; public long end; public long length; /** * Validate range. */ public boolean validate() { if (end >= length) end = length - 1; return (start >= 0) && (end >= 0) && (start <= end) && (length > 0); } } } tomcat7-7.0.52/java/org/apache/catalina/servlets/WebdavServlet.java0000644000175100017510000033003412271471332025144 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.servlets; import java.io.FileNotFoundException; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.Locale; import java.util.Stack; import java.util.TimeZone; import java.util.Vector; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.catalina.util.DOMWriter; import org.apache.catalina.util.MD5Encoder; import org.apache.catalina.util.XMLWriter; import org.apache.naming.resources.CacheEntry; import org.apache.naming.resources.Resource; import org.apache.naming.resources.ResourceAttributes; import org.apache.tomcat.util.http.FastHttpDateFormat; import org.apache.tomcat.util.http.RequestUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Servlet which adds support for WebDAV level 2. All the basic HTTP requests * are handled by the DefaultServlet. The WebDAVServlet must not be used as the * default servlet (ie mapped to '/') as it will not work in this configuration. *

    * Mapping a subpath (e.g. /webdav/* to this servlet has the effect * of re-mounting the entire web application under that sub-path, with WebDAV * access to all the resources. This WEB-INF and META-INF * directories are protected in this re-mounted resource tree. *

    * To enable WebDAV for a context add the following to web.xml: *

     * <servlet>
     *  <servlet-name>webdav</servlet-name>
     *  <servlet-class>org.apache.catalina.servlets.WebdavServlet</servlet-class>
     *    <init-param>
     *      <param-name>debug</param-name>
     *      <param-value>0</param-value>
     *    </init-param>
     *    <init-param>
     *      <param-name>listings</param-name>
     *      <param-value>false</param-value>
     *    </init-param>
     *  </servlet>
     *  <servlet-mapping>
     *    <servlet-name>webdav</servlet-name>
     *    <url-pattern>/*</url-pattern>
     *  </servlet-mapping>
     * 
    * This will enable read only access. To enable read-write access add: *
     *  <init-param>
     *    <param-name>readonly</param-name>
     *    <param-value>false</param-value>
     *  </init-param>
     * 
    * To make the content editable via a different URL, use the following * mapping: *
     *  <servlet-mapping>
     *    <servlet-name>webdav</servlet-name>
     *    <url-pattern>/webdavedit/*</url-pattern>
     *  </servlet-mapping>
     * 
    * By default access to /WEB-INF and META-INF are not available via WebDAV. To * enable access to these URLs, use add: *
     *  <init-param>
     *    <param-name>allowSpecialPaths</param-name>
     *    <param-value>true</param-value>
     *  </init-param>
     * 
    * Don't forget to secure access appropriately to the editing URLs, especially * if allowSpecialPaths is used. With the mapping configuration above, the * context will be accessible to normal users as before. Those users with the * necessary access will be able to edit content available via * http://host:port/context/content using * http://host:port/context/webdavedit/content * * @author Remy Maucherat */ public class WebdavServlet extends DefaultServlet { private static final long serialVersionUID = 1L; // -------------------------------------------------------------- Constants private static final String METHOD_PROPFIND = "PROPFIND"; private static final String METHOD_PROPPATCH = "PROPPATCH"; private static final String METHOD_MKCOL = "MKCOL"; private static final String METHOD_COPY = "COPY"; private static final String METHOD_MOVE = "MOVE"; private static final String METHOD_LOCK = "LOCK"; private static final String METHOD_UNLOCK = "UNLOCK"; /** * PROPFIND - Specify a property mask. */ private static final int FIND_BY_PROPERTY = 0; /** * PROPFIND - Display all properties. */ private static final int FIND_ALL_PROP = 1; /** * PROPFIND - Return property names. */ private static final int FIND_PROPERTY_NAMES = 2; /** * Create a new lock. */ private static final int LOCK_CREATION = 0; /** * Refresh lock. */ private static final int LOCK_REFRESH = 1; /** * Default lock timeout value. */ private static final int DEFAULT_TIMEOUT = 3600; /** * Maximum lock timeout. */ private static final int MAX_TIMEOUT = 604800; /** * Default namespace. */ protected static final String DEFAULT_NAMESPACE = "DAV:"; /** * Simple date format for the creation date ISO representation (partial). */ protected static final SimpleDateFormat creationDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); /** * MD5 message digest provider. */ protected static MessageDigest md5Helper; /** * The MD5 helper object for this class. * * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected static final MD5Encoder md5Encoder = new MD5Encoder(); static { creationDateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); } // ----------------------------------------------------- Instance Variables /** * Repository of the locks put on single resources. *

    * Key : path
    * Value : LockInfo */ private Hashtable resourceLocks = new Hashtable(); /** * Repository of the lock-null resources. *

    * Key : path of the collection containing the lock-null resource
    * Value : Vector of lock-null resource which are members of the * collection. Each element of the Vector is the path associated with * the lock-null resource. */ private Hashtable> lockNullResources = new Hashtable>(); /** * Vector of the heritable locks. *

    * Key : path
    * Value : LockInfo */ private Vector collectionLocks = new Vector(); /** * Secret information used to generate reasonably secure lock ids. */ private String secret = "catalina"; /** * Default depth in spec is infinite. Limit depth to 3 by default as * infinite depth makes operations very expensive. */ private int maxDepth = 3; /** * Is access allowed via WebDAV to the special paths (/WEB-INF and * /META-INF)? */ private boolean allowSpecialPaths = false; // --------------------------------------------------------- Public Methods /** * Initialize this servlet. */ @Override public void init() throws ServletException { super.init(); if (getServletConfig().getInitParameter("secret") != null) secret = getServletConfig().getInitParameter("secret"); if (getServletConfig().getInitParameter("maxDepth") != null) maxDepth = Integer.parseInt( getServletConfig().getInitParameter("maxDepth")); if (getServletConfig().getInitParameter("allowSpecialPaths") != null) allowSpecialPaths = Boolean.parseBoolean( getServletConfig().getInitParameter("allowSpecialPaths")); // Load the MD5 helper used to calculate signatures. try { md5Helper = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new UnavailableException("No MD5"); } } // ------------------------------------------------------ Protected Methods /** * Return JAXP document builder instance. */ protected DocumentBuilder getDocumentBuilder() throws ServletException { DocumentBuilder documentBuilder = null; DocumentBuilderFactory documentBuilderFactory = null; try { documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); documentBuilderFactory.setExpandEntityReferences(false); documentBuilder = documentBuilderFactory.newDocumentBuilder(); documentBuilder.setEntityResolver( new WebdavResolver(this.getServletContext())); } catch(ParserConfigurationException e) { throw new ServletException (sm.getString("webdavservlet.jaxpfailed")); } return documentBuilder; } /** * Handles the special WebDAV methods. */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { final String path = getRelativePath(req); // Block access to special subdirectories. // DefaultServlet assumes it services resources from the root of the web app // and doesn't add any special path protection // WebdavServlet remounts the webapp under a new path, so this check is // necessary on all methods (including GET). if (isSpecialPath(path)) { resp.sendError(WebdavStatus.SC_NOT_FOUND); return; } final String method = req.getMethod(); if (debug > 0) { log("[" + method + "] " + path); } if (method.equals(METHOD_PROPFIND)) { doPropfind(req, resp); } else if (method.equals(METHOD_PROPPATCH)) { doProppatch(req, resp); } else if (method.equals(METHOD_MKCOL)) { doMkcol(req, resp); } else if (method.equals(METHOD_COPY)) { doCopy(req, resp); } else if (method.equals(METHOD_MOVE)) { doMove(req, resp); } else if (method.equals(METHOD_LOCK)) { doLock(req, resp); } else if (method.equals(METHOD_UNLOCK)) { doUnlock(req, resp); } else { // DefaultServlet processing super.service(req, resp); } } /** * Checks whether a given path refers to a resource under * WEB-INF or META-INF. * @param path the full path of the resource being accessed * @return true if the resource specified is under a special path */ private final boolean isSpecialPath(final String path) { return !allowSpecialPaths && ( path.toUpperCase(Locale.ENGLISH).startsWith("/WEB-INF") || path.toUpperCase(Locale.ENGLISH).startsWith("/META-INF")); } /** * Check if the conditions specified in the optional If headers are * satisfied. * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param resourceAttributes The resource information * @return boolean true if the resource meets all the specified conditions, * and false if any of the conditions is not satisfied, in which case * request processing is stopped */ @Override protected boolean checkIfHeaders(HttpServletRequest request, HttpServletResponse response, ResourceAttributes resourceAttributes) throws IOException { if (!super.checkIfHeaders(request, response, resourceAttributes)) return false; // TODO : Checking the WebDAV If header return true; } /** * Override the DefaultServlet implementation and only use the PathInfo. If * the ServletPath is non-null, it will be because the WebDAV servlet has * been mapped to a url other than /* to configure editing at different url * than normal viewing. * * @param request The servlet request we are processing */ @Override protected String getRelativePath(HttpServletRequest request) { // Are we being processed by a RequestDispatcher.include()? if (request.getAttribute( RequestDispatcher.INCLUDE_REQUEST_URI) != null) { String result = (String) request.getAttribute( RequestDispatcher.INCLUDE_PATH_INFO); if ((result == null) || (result.equals(""))) result = "/"; return (result); } // No, extract the desired path directly from the request String result = request.getPathInfo(); if ((result == null) || (result.equals(""))) { result = "/"; } return (result); } /** * Determines the prefix for standard directory GET listings. */ @Override protected String getPathPrefix(final HttpServletRequest request) { // Repeat the servlet path (e.g. /webdav/) in the listing path String contextPath = request.getContextPath(); if (request.getServletPath() != null) { contextPath = contextPath + request.getServletPath(); } return contextPath; } /** * OPTIONS Method. * * @param req The request * @param resp The response * @throws ServletException If an error occurs * @throws IOException If an IO error occurs */ @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.addHeader("DAV", "1,2"); StringBuilder methodsAllowed = determineMethodsAllowed(resources, req); resp.addHeader("Allow", methodsAllowed.toString()); resp.addHeader("MS-Author-Via", "DAV"); } /** * PROPFIND Method. */ protected void doPropfind(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (!listings) { // Get allowed methods StringBuilder methodsAllowed = determineMethodsAllowed(resources, req); resp.addHeader("Allow", methodsAllowed.toString()); resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED); return; } String path = getRelativePath(req); if (path.endsWith("/")) path = path.substring(0, path.length() - 1); // Properties which are to be displayed. Vector properties = null; // Propfind depth int depth = maxDepth; // Propfind type int type = FIND_ALL_PROP; String depthStr = req.getHeader("Depth"); if (depthStr == null) { depth = maxDepth; } else { if (depthStr.equals("0")) { depth = 0; } else if (depthStr.equals("1")) { depth = 1; } else if (depthStr.equals("infinity")) { depth = maxDepth; } } Node propNode = null; if (req.getContentLength() > 0) { DocumentBuilder documentBuilder = getDocumentBuilder(); try { Document document = documentBuilder.parse (new InputSource(req.getInputStream())); // Get the root element of the document Element rootElement = document.getDocumentElement(); NodeList childList = rootElement.getChildNodes(); for (int i=0; i < childList.getLength(); i++) { Node currentNode = childList.item(i); switch (currentNode.getNodeType()) { case Node.TEXT_NODE: break; case Node.ELEMENT_NODE: if (currentNode.getNodeName().endsWith("prop")) { type = FIND_BY_PROPERTY; propNode = currentNode; } if (currentNode.getNodeName().endsWith("propname")) { type = FIND_PROPERTY_NAMES; } if (currentNode.getNodeName().endsWith("allprop")) { type = FIND_ALL_PROP; } break; } } } catch (SAXException e) { // Something went wrong - bad request resp.sendError(WebdavStatus.SC_BAD_REQUEST); } catch (IOException e) { // Something went wrong - bad request resp.sendError(WebdavStatus.SC_BAD_REQUEST); } } if (type == FIND_BY_PROPERTY) { properties = new Vector(); // propNode must be non-null if type == FIND_BY_PROPERTY @SuppressWarnings("null") NodeList childList = propNode.getChildNodes(); for (int i=0; i < childList.getLength(); i++) { Node currentNode = childList.item(i); switch (currentNode.getNodeType()) { case Node.TEXT_NODE: break; case Node.ELEMENT_NODE: String nodeName = currentNode.getNodeName(); String propertyName = null; if (nodeName.indexOf(':') != -1) { propertyName = nodeName.substring (nodeName.indexOf(':') + 1); } else { propertyName = nodeName; } // href is a live property which is handled differently properties.addElement(propertyName); break; } } } boolean exists = true; Object object = null; try { object = resources.lookup(path); } catch (NamingException e) { exists = false; int slash = path.lastIndexOf('/'); if (slash != -1) { String parentPath = path.substring(0, slash); Vector currentLockNullResources = lockNullResources.get(parentPath); if (currentLockNullResources != null) { Enumeration lockNullResourcesList = currentLockNullResources.elements(); while (lockNullResourcesList.hasMoreElements()) { String lockNullPath = lockNullResourcesList.nextElement(); if (lockNullPath.equals(path)) { resp.setStatus(WebdavStatus.SC_MULTI_STATUS); resp.setContentType("text/xml; charset=UTF-8"); // Create multistatus object XMLWriter generatedXML = new XMLWriter(resp.getWriter()); generatedXML.writeXMLHeader(); generatedXML.writeElement("D", DEFAULT_NAMESPACE, "multistatus", XMLWriter.OPENING); parseLockNullProperties (req, generatedXML, lockNullPath, type, properties); generatedXML.writeElement("D", "multistatus", XMLWriter.CLOSING); generatedXML.sendData(); return; } } } } } if (!exists) { resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); return; } resp.setStatus(WebdavStatus.SC_MULTI_STATUS); resp.setContentType("text/xml; charset=UTF-8"); // Create multistatus object XMLWriter generatedXML = new XMLWriter(resp.getWriter()); generatedXML.writeXMLHeader(); generatedXML.writeElement("D", DEFAULT_NAMESPACE, "multistatus", XMLWriter.OPENING); if (depth == 0) { parseProperties(req, generatedXML, path, type, properties); } else { // The stack always contains the object of the current level Stack stack = new Stack(); stack.push(path); // Stack of the objects one level below Stack stackBelow = new Stack(); while ((!stack.isEmpty()) && (depth >= 0)) { String currentPath = stack.pop(); parseProperties(req, generatedXML, currentPath, type, properties); try { object = resources.lookup(currentPath); } catch (NamingException e) { continue; } if ((object instanceof DirContext) && (depth > 0)) { try { NamingEnumeration enumeration = resources.list(currentPath); while (enumeration.hasMoreElements()) { NameClassPair ncPair = enumeration.nextElement(); String newPath = currentPath; if (!(newPath.endsWith("/"))) newPath += "/"; newPath += ncPair.getName(); stackBelow.push(newPath); } } catch (NamingException e) { resp.sendError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); return; } // Displaying the lock-null resources present in that // collection String lockPath = currentPath; if (lockPath.endsWith("/")) lockPath = lockPath.substring(0, lockPath.length() - 1); Vector currentLockNullResources = lockNullResources.get(lockPath); if (currentLockNullResources != null) { Enumeration lockNullResourcesList = currentLockNullResources.elements(); while (lockNullResourcesList.hasMoreElements()) { String lockNullPath = lockNullResourcesList.nextElement(); parseLockNullProperties (req, generatedXML, lockNullPath, type, properties); } } } if (stack.isEmpty()) { depth--; stack = stackBelow; stackBelow = new Stack(); } generatedXML.sendData(); } } generatedXML.writeElement("D", "multistatus", XMLWriter.CLOSING); generatedXML.sendData(); } /** * PROPPATCH Method. */ protected void doProppatch(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (readOnly) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return; } if (isLocked(req)) { resp.sendError(WebdavStatus.SC_LOCKED); return; } resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); } /** * MKCOL Method. */ protected void doMkcol(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (readOnly) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return; } if (isLocked(req)) { resp.sendError(WebdavStatus.SC_LOCKED); return; } String path = getRelativePath(req); boolean exists = true; try { resources.lookup(path); } catch (NamingException e) { exists = false; } // Can't create a collection if a resource already exists at the given // path if (exists) { // Get allowed methods StringBuilder methodsAllowed = determineMethodsAllowed(resources, req); resp.addHeader("Allow", methodsAllowed.toString()); resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED); return; } if (req.getContentLength() > 0) { DocumentBuilder documentBuilder = getDocumentBuilder(); try { // Document document = documentBuilder.parse(new InputSource(req.getInputStream())); // TODO : Process this request body resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED); return; } catch(SAXException saxe) { // Parse error - assume invalid content resp.sendError(WebdavStatus.SC_UNSUPPORTED_MEDIA_TYPE); return; } } boolean result = true; try { resources.createSubcontext(path); } catch (NamingException e) { result = false; } if (!result) { resp.sendError(WebdavStatus.SC_CONFLICT, WebdavStatus.getStatusText (WebdavStatus.SC_CONFLICT)); } else { resp.setStatus(WebdavStatus.SC_CREATED); // Removing any lock-null resource which would be present lockNullResources.remove(path); } } /** * DELETE Method. */ @Override protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (readOnly) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return; } if (isLocked(req)) { resp.sendError(WebdavStatus.SC_LOCKED); return; } deleteResource(req, resp); } /** * Process a PUT request for the specified resource. * * @param req The servlet request we are processing * @param resp The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */ @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (isLocked(req)) { resp.sendError(WebdavStatus.SC_LOCKED); return; } super.doPut(req, resp); String path = getRelativePath(req); // Removing any lock-null resource which would be present lockNullResources.remove(path); } /** * COPY Method. */ protected void doCopy(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (readOnly) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return; } copyResource(req, resp); } /** * MOVE Method. */ protected void doMove(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (readOnly) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return; } if (isLocked(req)) { resp.sendError(WebdavStatus.SC_LOCKED); return; } String path = getRelativePath(req); if (copyResource(req, resp)) { deleteResource(path, req, resp, false); } } /** * LOCK Method. */ protected void doLock(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (readOnly) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return; } if (isLocked(req)) { resp.sendError(WebdavStatus.SC_LOCKED); return; } LockInfo lock = new LockInfo(); // Parsing lock request // Parsing depth header String depthStr = req.getHeader("Depth"); if (depthStr == null) { lock.depth = maxDepth; } else { if (depthStr.equals("0")) { lock.depth = 0; } else { lock.depth = maxDepth; } } // Parsing timeout header int lockDuration = DEFAULT_TIMEOUT; String lockDurationStr = req.getHeader("Timeout"); if (lockDurationStr == null) { lockDuration = DEFAULT_TIMEOUT; } else { int commaPos = lockDurationStr.indexOf(","); // If multiple timeouts, just use the first if (commaPos != -1) { lockDurationStr = lockDurationStr.substring(0,commaPos); } if (lockDurationStr.startsWith("Second-")) { lockDuration = (new Integer(lockDurationStr.substring(7))).intValue(); } else { if (lockDurationStr.equalsIgnoreCase("infinity")) { lockDuration = MAX_TIMEOUT; } else { try { lockDuration = (new Integer(lockDurationStr)).intValue(); } catch (NumberFormatException e) { lockDuration = MAX_TIMEOUT; } } } if (lockDuration == 0) { lockDuration = DEFAULT_TIMEOUT; } if (lockDuration > MAX_TIMEOUT) { lockDuration = MAX_TIMEOUT; } } lock.expiresAt = System.currentTimeMillis() + (lockDuration * 1000); int lockRequestType = LOCK_CREATION; Node lockInfoNode = null; DocumentBuilder documentBuilder = getDocumentBuilder(); try { Document document = documentBuilder.parse(new InputSource (req.getInputStream())); // Get the root element of the document Element rootElement = document.getDocumentElement(); lockInfoNode = rootElement; } catch (IOException e) { lockRequestType = LOCK_REFRESH; } catch (SAXException e) { lockRequestType = LOCK_REFRESH; } if (lockInfoNode != null) { // Reading lock information NodeList childList = lockInfoNode.getChildNodes(); StringWriter strWriter = null; DOMWriter domWriter = null; Node lockScopeNode = null; Node lockTypeNode = null; Node lockOwnerNode = null; for (int i=0; i < childList.getLength(); i++) { Node currentNode = childList.item(i); switch (currentNode.getNodeType()) { case Node.TEXT_NODE: break; case Node.ELEMENT_NODE: String nodeName = currentNode.getNodeName(); if (nodeName.endsWith("lockscope")) { lockScopeNode = currentNode; } if (nodeName.endsWith("locktype")) { lockTypeNode = currentNode; } if (nodeName.endsWith("owner")) { lockOwnerNode = currentNode; } break; } } if (lockScopeNode != null) { childList = lockScopeNode.getChildNodes(); for (int i=0; i < childList.getLength(); i++) { Node currentNode = childList.item(i); switch (currentNode.getNodeType()) { case Node.TEXT_NODE: break; case Node.ELEMENT_NODE: String tempScope = currentNode.getNodeName(); if (tempScope.indexOf(':') != -1) { lock.scope = tempScope.substring (tempScope.indexOf(':') + 1); } else { lock.scope = tempScope; } break; } } if (lock.scope == null) { // Bad request resp.setStatus(WebdavStatus.SC_BAD_REQUEST); } } else { // Bad request resp.setStatus(WebdavStatus.SC_BAD_REQUEST); } if (lockTypeNode != null) { childList = lockTypeNode.getChildNodes(); for (int i=0; i < childList.getLength(); i++) { Node currentNode = childList.item(i); switch (currentNode.getNodeType()) { case Node.TEXT_NODE: break; case Node.ELEMENT_NODE: String tempType = currentNode.getNodeName(); if (tempType.indexOf(':') != -1) { lock.type = tempType.substring(tempType.indexOf(':') + 1); } else { lock.type = tempType; } break; } } if (lock.type == null) { // Bad request resp.setStatus(WebdavStatus.SC_BAD_REQUEST); } } else { // Bad request resp.setStatus(WebdavStatus.SC_BAD_REQUEST); } if (lockOwnerNode != null) { childList = lockOwnerNode.getChildNodes(); for (int i=0; i < childList.getLength(); i++) { Node currentNode = childList.item(i); switch (currentNode.getNodeType()) { case Node.TEXT_NODE: lock.owner += currentNode.getNodeValue(); break; case Node.ELEMENT_NODE: strWriter = new StringWriter(); domWriter = new DOMWriter(strWriter, true); domWriter.setQualifiedNames(false); domWriter.print(currentNode); lock.owner += strWriter.toString(); break; } } if (lock.owner == null) { // Bad request resp.setStatus(WebdavStatus.SC_BAD_REQUEST); } } else { lock.owner = ""; } } String path = getRelativePath(req); lock.path = path; boolean exists = true; Object object = null; try { object = resources.lookup(path); } catch (NamingException e) { exists = false; } Enumeration locksList = null; if (lockRequestType == LOCK_CREATION) { // Generating lock id String lockTokenStr = req.getServletPath() + "-" + lock.type + "-" + lock.scope + "-" + req.getUserPrincipal() + "-" + lock.depth + "-" + lock.owner + "-" + lock.tokens + "-" + lock.expiresAt + "-" + System.currentTimeMillis() + "-" + secret; String lockToken = MD5Encoder.encode(md5Helper.digest( lockTokenStr.getBytes(Charset.defaultCharset()))); if ( (exists) && (object instanceof DirContext) && (lock.depth == maxDepth) ) { // Locking a collection (and all its member resources) // Checking if a child resource of this collection is // already locked Vector lockPaths = new Vector(); locksList = collectionLocks.elements(); while (locksList.hasMoreElements()) { LockInfo currentLock = locksList.nextElement(); if (currentLock.hasExpired()) { resourceLocks.remove(currentLock.path); continue; } if ( (currentLock.path.startsWith(lock.path)) && ((currentLock.isExclusive()) || (lock.isExclusive())) ) { // A child collection of this collection is locked lockPaths.addElement(currentLock.path); } } locksList = resourceLocks.elements(); while (locksList.hasMoreElements()) { LockInfo currentLock = locksList.nextElement(); if (currentLock.hasExpired()) { resourceLocks.remove(currentLock.path); continue; } if ( (currentLock.path.startsWith(lock.path)) && ((currentLock.isExclusive()) || (lock.isExclusive())) ) { // A child resource of this collection is locked lockPaths.addElement(currentLock.path); } } if (!lockPaths.isEmpty()) { // One of the child paths was locked // We generate a multistatus error report Enumeration lockPathsList = lockPaths.elements(); resp.setStatus(WebdavStatus.SC_CONFLICT); XMLWriter generatedXML = new XMLWriter(); generatedXML.writeXMLHeader(); generatedXML.writeElement("D", DEFAULT_NAMESPACE, "multistatus", XMLWriter.OPENING); while (lockPathsList.hasMoreElements()) { generatedXML.writeElement("D", "response", XMLWriter.OPENING); generatedXML.writeElement("D", "href", XMLWriter.OPENING); generatedXML.writeText(lockPathsList.nextElement()); generatedXML.writeElement("D", "href", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML .writeText("HTTP/1.1 " + WebdavStatus.SC_LOCKED + " " + WebdavStatus .getStatusText(WebdavStatus.SC_LOCKED)); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "response", XMLWriter.CLOSING); } generatedXML.writeElement("D", "multistatus", XMLWriter.CLOSING); Writer writer = resp.getWriter(); writer.write(generatedXML.toString()); writer.close(); return; } boolean addLock = true; // Checking if there is already a shared lock on this path locksList = collectionLocks.elements(); while (locksList.hasMoreElements()) { LockInfo currentLock = locksList.nextElement(); if (currentLock.path.equals(lock.path)) { if (currentLock.isExclusive()) { resp.sendError(WebdavStatus.SC_LOCKED); return; } else { if (lock.isExclusive()) { resp.sendError(WebdavStatus.SC_LOCKED); return; } } currentLock.tokens.addElement(lockToken); lock = currentLock; addLock = false; } } if (addLock) { lock.tokens.addElement(lockToken); collectionLocks.addElement(lock); } } else { // Locking a single resource // Retrieving an already existing lock on that resource LockInfo presentLock = resourceLocks.get(lock.path); if (presentLock != null) { if ((presentLock.isExclusive()) || (lock.isExclusive())) { // If either lock is exclusive, the lock can't be // granted resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED); return; } else { presentLock.tokens.addElement(lockToken); lock = presentLock; } } else { lock.tokens.addElement(lockToken); resourceLocks.put(lock.path, lock); // Checking if a resource exists at this path exists = true; try { object = resources.lookup(path); } catch (NamingException e) { exists = false; } if (!exists) { // "Creating" a lock-null resource int slash = lock.path.lastIndexOf('/'); String parentPath = lock.path.substring(0, slash); Vector lockNulls = lockNullResources.get(parentPath); if (lockNulls == null) { lockNulls = new Vector(); lockNullResources.put(parentPath, lockNulls); } lockNulls.addElement(lock.path); } // Add the Lock-Token header as by RFC 2518 8.10.1 // - only do this for newly created locks resp.addHeader("Lock-Token", ""); } } } if (lockRequestType == LOCK_REFRESH) { String ifHeader = req.getHeader("If"); if (ifHeader == null) ifHeader = ""; // Checking resource locks LockInfo toRenew = resourceLocks.get(path); Enumeration tokenList = null; if (toRenew != null) { // At least one of the tokens of the locks must have been given tokenList = toRenew.tokens.elements(); while (tokenList.hasMoreElements()) { String token = tokenList.nextElement(); if (ifHeader.indexOf(token) != -1) { toRenew.expiresAt = lock.expiresAt; lock = toRenew; } } } // Checking inheritable collection locks Enumeration collectionLocksList = collectionLocks.elements(); while (collectionLocksList.hasMoreElements()) { toRenew = collectionLocksList.nextElement(); if (path.equals(toRenew.path)) { tokenList = toRenew.tokens.elements(); while (tokenList.hasMoreElements()) { String token = tokenList.nextElement(); if (ifHeader.indexOf(token) != -1) { toRenew.expiresAt = lock.expiresAt; lock = toRenew; } } } } } // Set the status, then generate the XML response containing // the lock information XMLWriter generatedXML = new XMLWriter(); generatedXML.writeXMLHeader(); generatedXML.writeElement("D", DEFAULT_NAMESPACE, "prop", XMLWriter.OPENING); generatedXML.writeElement("D", "lockdiscovery", XMLWriter.OPENING); lock.toXML(generatedXML); generatedXML.writeElement("D", "lockdiscovery", XMLWriter.CLOSING); generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); resp.setStatus(WebdavStatus.SC_OK); resp.setContentType("text/xml; charset=UTF-8"); Writer writer = resp.getWriter(); writer.write(generatedXML.toString()); writer.close(); } /** * UNLOCK Method. */ protected void doUnlock(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (readOnly) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return; } if (isLocked(req)) { resp.sendError(WebdavStatus.SC_LOCKED); return; } String path = getRelativePath(req); String lockTokenHeader = req.getHeader("Lock-Token"); if (lockTokenHeader == null) lockTokenHeader = ""; // Checking resource locks LockInfo lock = resourceLocks.get(path); Enumeration tokenList = null; if (lock != null) { // At least one of the tokens of the locks must have been given tokenList = lock.tokens.elements(); while (tokenList.hasMoreElements()) { String token = tokenList.nextElement(); if (lockTokenHeader.indexOf(token) != -1) { lock.tokens.removeElement(token); } } if (lock.tokens.isEmpty()) { resourceLocks.remove(path); // Removing any lock-null resource which would be present lockNullResources.remove(path); } } // Checking inheritable collection locks Enumeration collectionLocksList = collectionLocks.elements(); while (collectionLocksList.hasMoreElements()) { lock = collectionLocksList.nextElement(); if (path.equals(lock.path)) { tokenList = lock.tokens.elements(); while (tokenList.hasMoreElements()) { String token = tokenList.nextElement(); if (lockTokenHeader.indexOf(token) != -1) { lock.tokens.removeElement(token); break; } } if (lock.tokens.isEmpty()) { collectionLocks.removeElement(lock); // Removing any lock-null resource which would be present lockNullResources.remove(path); } } } resp.setStatus(WebdavStatus.SC_NO_CONTENT); } // -------------------------------------------------------- Private Methods /** * Check to see if a resource is currently write locked. The method * will look at the "If" header to make sure the client * has give the appropriate lock tokens. * * @param req Servlet request * @return boolean true if the resource is locked (and no appropriate * lock token has been found for at least one of the non-shared locks which * are present on the resource). */ private boolean isLocked(HttpServletRequest req) { String path = getRelativePath(req); String ifHeader = req.getHeader("If"); if (ifHeader == null) ifHeader = ""; String lockTokenHeader = req.getHeader("Lock-Token"); if (lockTokenHeader == null) lockTokenHeader = ""; return isLocked(path, ifHeader + lockTokenHeader); } /** * Check to see if a resource is currently write locked. * * @param path Path of the resource * @param ifHeader "If" HTTP header which was included in the request * @return boolean true if the resource is locked (and no appropriate * lock token has been found for at least one of the non-shared locks which * are present on the resource). */ private boolean isLocked(String path, String ifHeader) { // Checking resource locks LockInfo lock = resourceLocks.get(path); Enumeration tokenList = null; if ((lock != null) && (lock.hasExpired())) { resourceLocks.remove(path); } else if (lock != null) { // At least one of the tokens of the locks must have been given tokenList = lock.tokens.elements(); boolean tokenMatch = false; while (tokenList.hasMoreElements()) { String token = tokenList.nextElement(); if (ifHeader.indexOf(token) != -1) { tokenMatch = true; break; } } if (!tokenMatch) return true; } // Checking inheritable collection locks Enumeration collectionLocksList = collectionLocks.elements(); while (collectionLocksList.hasMoreElements()) { lock = collectionLocksList.nextElement(); if (lock.hasExpired()) { collectionLocks.removeElement(lock); } else if (path.startsWith(lock.path)) { tokenList = lock.tokens.elements(); boolean tokenMatch = false; while (tokenList.hasMoreElements()) { String token = tokenList.nextElement(); if (ifHeader.indexOf(token) != -1) { tokenMatch = true; break; } } if (!tokenMatch) return true; } } return false; } /** * Copy a resource. * * @param req Servlet request * @param resp Servlet response * @return boolean true if the copy is successful */ private boolean copyResource(HttpServletRequest req, HttpServletResponse resp) throws IOException { // Parsing destination header String destinationPath = req.getHeader("Destination"); if (destinationPath == null) { resp.sendError(WebdavStatus.SC_BAD_REQUEST); return false; } // Remove url encoding from destination destinationPath = org.apache.catalina.util.RequestUtil.URLDecode( destinationPath, "UTF8"); int protocolIndex = destinationPath.indexOf("://"); if (protocolIndex >= 0) { // if the Destination URL contains the protocol, we can safely // trim everything upto the first "/" character after "://" int firstSeparator = destinationPath.indexOf("/", protocolIndex + 4); if (firstSeparator < 0) { destinationPath = "/"; } else { destinationPath = destinationPath.substring(firstSeparator); } } else { String hostName = req.getServerName(); if ((hostName != null) && (destinationPath.startsWith(hostName))) { destinationPath = destinationPath.substring(hostName.length()); } int portIndex = destinationPath.indexOf(":"); if (portIndex >= 0) { destinationPath = destinationPath.substring(portIndex); } if (destinationPath.startsWith(":")) { int firstSeparator = destinationPath.indexOf("/"); if (firstSeparator < 0) { destinationPath = "/"; } else { destinationPath = destinationPath.substring(firstSeparator); } } } // Normalise destination path (remove '.' and '..') destinationPath = RequestUtil.normalize(destinationPath); String contextPath = req.getContextPath(); if ((contextPath != null) && (destinationPath.startsWith(contextPath))) { destinationPath = destinationPath.substring(contextPath.length()); } String pathInfo = req.getPathInfo(); if (pathInfo != null) { String servletPath = req.getServletPath(); if ((servletPath != null) && (destinationPath.startsWith(servletPath))) { destinationPath = destinationPath .substring(servletPath.length()); } } if (debug > 0) log("Dest path :" + destinationPath); // Check destination path to protect special subdirectories if (isSpecialPath(destinationPath)) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return false; } String path = getRelativePath(req); if (destinationPath.equals(path)) { resp.sendError(WebdavStatus.SC_FORBIDDEN); return false; } // Parsing overwrite header boolean overwrite = true; String overwriteHeader = req.getHeader("Overwrite"); if (overwriteHeader != null) { if (overwriteHeader.equalsIgnoreCase("T")) { overwrite = true; } else { overwrite = false; } } // Overwriting the destination boolean exists = true; try { resources.lookup(destinationPath); } catch (NamingException e) { exists = false; } if (overwrite) { // Delete destination resource, if it exists if (exists) { if (!deleteResource(destinationPath, req, resp, true)) { return false; } } else { resp.setStatus(WebdavStatus.SC_CREATED); } } else { // If the destination exists, then it's a conflict if (exists) { resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED); return false; } } // Copying source to destination Hashtable errorList = new Hashtable(); boolean result = copyResource(resources, errorList, path, destinationPath); if ((!result) || (!errorList.isEmpty())) { if (errorList.size() == 1) { resp.sendError(errorList.elements().nextElement().intValue()); } else { sendReport(req, resp, errorList); } return false; } // Copy was successful if (exists) { resp.setStatus(WebdavStatus.SC_NO_CONTENT); } else { resp.setStatus(WebdavStatus.SC_CREATED); } // Removing any lock-null resource which would be present at // the destination path lockNullResources.remove(destinationPath); return true; } /** * Copy a collection. * * @param dirContext Resources implementation to be used * @param errorList Hashtable containing the list of errors which occurred * during the copy operation * @param source Path of the resource to be copied * @param dest Destination path */ private boolean copyResource(DirContext dirContext, Hashtable errorList, String source, String dest) { if (debug > 1) log("Copy: " + source + " To: " + dest); Object object = null; try { object = dirContext.lookup(source); } catch (NamingException e) { // Ignore } if (object instanceof DirContext) { try { dirContext.createSubcontext(dest); } catch (NamingException e) { errorList.put (dest, new Integer(WebdavStatus.SC_CONFLICT)); return false; } try { NamingEnumeration enumeration = dirContext.list(source); while (enumeration.hasMoreElements()) { NameClassPair ncPair = enumeration.nextElement(); String childDest = dest; if (!childDest.equals("/")) childDest += "/"; childDest += ncPair.getName(); String childSrc = source; if (!childSrc.equals("/")) childSrc += "/"; childSrc += ncPair.getName(); copyResource(dirContext, errorList, childSrc, childDest); } } catch (NamingException e) { errorList.put (dest, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); return false; } } else { if (object instanceof Resource) { try { dirContext.bind(dest, object); } catch (NamingException e) { if (e.getCause() instanceof FileNotFoundException) { // We know the source exists so it must be the // destination dir that can't be found errorList.put(source, new Integer(WebdavStatus.SC_CONFLICT)); } else { errorList.put(source, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); } return false; } } else { errorList.put (source, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); return false; } } return true; } /** * Delete a resource. * * @param req Servlet request * @param resp Servlet response * @return boolean true if the copy is successful */ private boolean deleteResource(HttpServletRequest req, HttpServletResponse resp) throws IOException { String path = getRelativePath(req); return deleteResource(path, req, resp, true); } /** * Delete a resource. * * @param path Path of the resource which is to be deleted * @param req Servlet request * @param resp Servlet response * @param setStatus Should the response status be set on successful * completion */ private boolean deleteResource(String path, HttpServletRequest req, HttpServletResponse resp, boolean setStatus) throws IOException { String ifHeader = req.getHeader("If"); if (ifHeader == null) ifHeader = ""; String lockTokenHeader = req.getHeader("Lock-Token"); if (lockTokenHeader == null) lockTokenHeader = ""; if (isLocked(path, ifHeader + lockTokenHeader)) { resp.sendError(WebdavStatus.SC_LOCKED); return false; } boolean exists = true; Object object = null; try { object = resources.lookup(path); } catch (NamingException e) { exists = false; } if (!exists) { resp.sendError(WebdavStatus.SC_NOT_FOUND); return false; } boolean collection = (object instanceof DirContext); if (!collection) { try { resources.unbind(path); } catch (NamingException e) { resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR); return false; } } else { Hashtable errorList = new Hashtable(); deleteCollection(req, resources, path, errorList); try { resources.unbind(path); } catch (NamingException e) { errorList.put(path, new Integer (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); } if (!errorList.isEmpty()) { sendReport(req, resp, errorList); return false; } } if (setStatus) { resp.setStatus(WebdavStatus.SC_NO_CONTENT); } return true; } /** * Deletes a collection. * * @param dirContext Resources implementation associated with the context * @param path Path to the collection to be deleted * @param errorList Contains the list of the errors which occurred */ private void deleteCollection(HttpServletRequest req, DirContext dirContext, String path, Hashtable errorList) { if (debug > 1) log("Delete:" + path); // Prevent deletion of special subdirectories if (isSpecialPath(path)) { errorList.put(path, new Integer(WebdavStatus.SC_FORBIDDEN)); return; } String ifHeader = req.getHeader("If"); if (ifHeader == null) ifHeader = ""; String lockTokenHeader = req.getHeader("Lock-Token"); if (lockTokenHeader == null) lockTokenHeader = ""; Enumeration enumeration = null; try { enumeration = dirContext.list(path); } catch (NamingException e) { errorList.put(path, new Integer (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); return; } while (enumeration.hasMoreElements()) { NameClassPair ncPair = enumeration.nextElement(); String childName = path; if (!childName.equals("/")) childName += "/"; childName += ncPair.getName(); if (isLocked(childName, ifHeader + lockTokenHeader)) { errorList.put(childName, new Integer(WebdavStatus.SC_LOCKED)); } else { try { Object object = dirContext.lookup(childName); if (object instanceof DirContext) { deleteCollection(req, dirContext, childName, errorList); } try { dirContext.unbind(childName); } catch (NamingException e) { if (!(object instanceof DirContext)) { // If it's not a collection, then it's an unknown // error errorList.put (childName, new Integer (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); } } } catch (NamingException e) { errorList.put (childName, new Integer (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); } } } } /** * Send a multistatus element containing a complete error report to the * client. * * @param req Servlet request * @param resp Servlet response * @param errorList List of error to be displayed */ private void sendReport(HttpServletRequest req, HttpServletResponse resp, Hashtable errorList) throws IOException { resp.setStatus(WebdavStatus.SC_MULTI_STATUS); String absoluteUri = req.getRequestURI(); String relativePath = getRelativePath(req); XMLWriter generatedXML = new XMLWriter(); generatedXML.writeXMLHeader(); generatedXML.writeElement("D", DEFAULT_NAMESPACE, "multistatus", XMLWriter.OPENING); Enumeration pathList = errorList.keys(); while (pathList.hasMoreElements()) { String errorPath = pathList.nextElement(); int errorCode = errorList.get(errorPath).intValue(); generatedXML.writeElement("D", "response", XMLWriter.OPENING); generatedXML.writeElement("D", "href", XMLWriter.OPENING); String toAppend = errorPath.substring(relativePath.length()); if (!toAppend.startsWith("/")) toAppend = "/" + toAppend; generatedXML.writeText(absoluteUri + toAppend); generatedXML.writeElement("D", "href", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText("HTTP/1.1 " + errorCode + " " + WebdavStatus.getStatusText(errorCode)); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "response", XMLWriter.CLOSING); } generatedXML.writeElement("D", "multistatus", XMLWriter.CLOSING); Writer writer = resp.getWriter(); writer.write(generatedXML.toString()); writer.close(); } /** * Propfind helper method. * * @param req The servlet request * @param resources Resources object associated with this context * @param generatedXML XML response to the Propfind request * @param path Path of the current resource * @param type Propfind type * @param propertiesVector If the propfind type is find properties by * name, then this Vector contains those properties */ private void parseProperties(HttpServletRequest req, XMLWriter generatedXML, String path, int type, Vector propertiesVector) { // Exclude any resource in the /WEB-INF and /META-INF subdirectories if (isSpecialPath(path)) return; CacheEntry cacheEntry = resources.lookupCache(path); if (!cacheEntry.exists) { // File is in directory listing but doesn't appear to exist // Broken symlink or odd permission settings? return; } generatedXML.writeElement("D", "response", XMLWriter.OPENING); String status = "HTTP/1.1 " + WebdavStatus.SC_OK + " " + WebdavStatus.getStatusText(WebdavStatus.SC_OK); // Generating href element generatedXML.writeElement("D", "href", XMLWriter.OPENING); String href = req.getContextPath() + req.getServletPath(); if ((href.endsWith("/")) && (path.startsWith("/"))) href += path.substring(1); else href += path; if ((cacheEntry.context != null) && (!href.endsWith("/"))) href += "/"; generatedXML.writeText(rewriteUrl(href)); generatedXML.writeElement("D", "href", XMLWriter.CLOSING); String resourceName = path; int lastSlash = path.lastIndexOf('/'); if (lastSlash != -1) resourceName = resourceName.substring(lastSlash + 1); switch (type) { case FIND_ALL_PROP : generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); generatedXML.writeProperty("D", "creationdate", getISOCreationDate(cacheEntry.attributes.getCreation())); generatedXML.writeElement("D", "displayname", XMLWriter.OPENING); generatedXML.writeData(resourceName); generatedXML.writeElement("D", "displayname", XMLWriter.CLOSING); if (cacheEntry.resource != null) { generatedXML.writeProperty ("D", "getlastmodified", FastHttpDateFormat.formatDate (cacheEntry.attributes.getLastModified(), null)); generatedXML.writeProperty ("D", "getcontentlength", String.valueOf(cacheEntry.attributes.getContentLength())); String contentType = getServletContext().getMimeType (cacheEntry.name); if (contentType != null) { generatedXML.writeProperty("D", "getcontenttype", contentType); } generatedXML.writeProperty("D", "getetag", cacheEntry.attributes.getETag()); generatedXML.writeElement("D", "resourcetype", XMLWriter.NO_CONTENT); } else { generatedXML.writeElement("D", "resourcetype", XMLWriter.OPENING); generatedXML.writeElement("D", "collection", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "resourcetype", XMLWriter.CLOSING); } generatedXML.writeProperty("D", "source", ""); String supportedLocks = "" + "" + "" + "" + "" + "" + "" + ""; generatedXML.writeElement("D", "supportedlock", XMLWriter.OPENING); generatedXML.writeText(supportedLocks); generatedXML.writeElement("D", "supportedlock", XMLWriter.CLOSING); generateLockDiscovery(path, generatedXML); generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); break; case FIND_PROPERTY_NAMES : generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); generatedXML.writeElement("D", "creationdate", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "displayname", XMLWriter.NO_CONTENT); if (cacheEntry.resource != null) { generatedXML.writeElement("D", "getcontentlanguage", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getcontentlength", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getcontenttype", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getetag", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getlastmodified", XMLWriter.NO_CONTENT); } generatedXML.writeElement("D", "resourcetype", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "source", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "lockdiscovery", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); break; case FIND_BY_PROPERTY : Vector propertiesNotFound = new Vector(); // Parse the list of properties generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); Enumeration properties = propertiesVector.elements(); while (properties.hasMoreElements()) { String property = properties.nextElement(); if (property.equals("creationdate")) { generatedXML.writeProperty ("D", "creationdate", getISOCreationDate(cacheEntry.attributes.getCreation())); } else if (property.equals("displayname")) { generatedXML.writeElement ("D", "displayname", XMLWriter.OPENING); generatedXML.writeData(resourceName); generatedXML.writeElement ("D", "displayname", XMLWriter.CLOSING); } else if (property.equals("getcontentlanguage")) { if (cacheEntry.context != null) { propertiesNotFound.addElement(property); } else { generatedXML.writeElement("D", "getcontentlanguage", XMLWriter.NO_CONTENT); } } else if (property.equals("getcontentlength")) { if (cacheEntry.context != null) { propertiesNotFound.addElement(property); } else { generatedXML.writeProperty ("D", "getcontentlength", (String.valueOf(cacheEntry.attributes.getContentLength()))); } } else if (property.equals("getcontenttype")) { if (cacheEntry.context != null) { propertiesNotFound.addElement(property); } else { generatedXML.writeProperty ("D", "getcontenttype", getServletContext().getMimeType (cacheEntry.name)); } } else if (property.equals("getetag")) { if (cacheEntry.context != null) { propertiesNotFound.addElement(property); } else { generatedXML.writeProperty ("D", "getetag", cacheEntry.attributes.getETag()); } } else if (property.equals("getlastmodified")) { if (cacheEntry.context != null) { propertiesNotFound.addElement(property); } else { generatedXML.writeProperty ("D", "getlastmodified", FastHttpDateFormat.formatDate (cacheEntry.attributes.getLastModified(), null)); } } else if (property.equals("resourcetype")) { if (cacheEntry.context != null) { generatedXML.writeElement("D", "resourcetype", XMLWriter.OPENING); generatedXML.writeElement("D", "collection", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "resourcetype", XMLWriter.CLOSING); } else { generatedXML.writeElement("D", "resourcetype", XMLWriter.NO_CONTENT); } } else if (property.equals("source")) { generatedXML.writeProperty("D", "source", ""); } else if (property.equals("supportedlock")) { supportedLocks = "" + "" + "" + "" + "" + "" + "" + ""; generatedXML.writeElement("D", "supportedlock", XMLWriter.OPENING); generatedXML.writeText(supportedLocks); generatedXML.writeElement("D", "supportedlock", XMLWriter.CLOSING); } else if (property.equals("lockdiscovery")) { if (!generateLockDiscovery(path, generatedXML)) propertiesNotFound.addElement(property); } else { propertiesNotFound.addElement(property); } } generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); Enumeration propertiesNotFoundList = propertiesNotFound.elements(); if (propertiesNotFoundList.hasMoreElements()) { status = "HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND + " " + WebdavStatus.getStatusText(WebdavStatus.SC_NOT_FOUND); generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); while (propertiesNotFoundList.hasMoreElements()) { generatedXML.writeElement ("D", propertiesNotFoundList.nextElement(), XMLWriter.NO_CONTENT); } generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); } break; } generatedXML.writeElement("D", "response", XMLWriter.CLOSING); } /** * Propfind helper method. Displays the properties of a lock-null resource. * * @param resources Resources object associated with this context * @param generatedXML XML response to the Propfind request * @param path Path of the current resource * @param type Propfind type * @param propertiesVector If the propfind type is find properties by * name, then this Vector contains those properties */ private void parseLockNullProperties(HttpServletRequest req, XMLWriter generatedXML, String path, int type, Vector propertiesVector) { // Exclude any resource in the /WEB-INF and /META-INF subdirectories if (isSpecialPath(path)) return; // Retrieving the lock associated with the lock-null resource LockInfo lock = resourceLocks.get(path); if (lock == null) return; generatedXML.writeElement("D", "response", XMLWriter.OPENING); String status = "HTTP/1.1 " + WebdavStatus.SC_OK + " " + WebdavStatus.getStatusText(WebdavStatus.SC_OK); // Generating href element generatedXML.writeElement("D", "href", XMLWriter.OPENING); String absoluteUri = req.getRequestURI(); String relativePath = getRelativePath(req); String toAppend = path.substring(relativePath.length()); if (!toAppend.startsWith("/")) toAppend = "/" + toAppend; generatedXML.writeText(rewriteUrl(RequestUtil.normalize( absoluteUri + toAppend))); generatedXML.writeElement("D", "href", XMLWriter.CLOSING); String resourceName = path; int lastSlash = path.lastIndexOf('/'); if (lastSlash != -1) resourceName = resourceName.substring(lastSlash + 1); switch (type) { case FIND_ALL_PROP : generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); generatedXML.writeProperty("D", "creationdate", getISOCreationDate(lock.creationDate.getTime())); generatedXML.writeElement("D", "displayname", XMLWriter.OPENING); generatedXML.writeData(resourceName); generatedXML.writeElement("D", "displayname", XMLWriter.CLOSING); generatedXML.writeProperty("D", "getlastmodified", FastHttpDateFormat.formatDate (lock.creationDate.getTime(), null)); generatedXML.writeProperty("D", "getcontentlength", String.valueOf(0)); generatedXML.writeProperty("D", "getcontenttype", ""); generatedXML.writeProperty("D", "getetag", ""); generatedXML.writeElement("D", "resourcetype", XMLWriter.OPENING); generatedXML.writeElement("D", "lock-null", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "resourcetype", XMLWriter.CLOSING); generatedXML.writeProperty("D", "source", ""); String supportedLocks = "" + "" + "" + "" + "" + "" + "" + ""; generatedXML.writeElement("D", "supportedlock", XMLWriter.OPENING); generatedXML.writeText(supportedLocks); generatedXML.writeElement("D", "supportedlock", XMLWriter.CLOSING); generateLockDiscovery(path, generatedXML); generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); break; case FIND_PROPERTY_NAMES : generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); generatedXML.writeElement("D", "creationdate", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "displayname", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getcontentlanguage", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getcontentlength", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getcontenttype", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getetag", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "getlastmodified", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "resourcetype", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "source", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "lockdiscovery", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); break; case FIND_BY_PROPERTY : Vector propertiesNotFound = new Vector(); // Parse the list of properties generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); Enumeration properties = propertiesVector.elements(); while (properties.hasMoreElements()) { String property = properties.nextElement(); if (property.equals("creationdate")) { generatedXML.writeProperty("D", "creationdate", getISOCreationDate(lock.creationDate.getTime())); } else if (property.equals("displayname")) { generatedXML.writeElement("D", "displayname", XMLWriter.OPENING); generatedXML.writeData(resourceName); generatedXML.writeElement("D", "displayname", XMLWriter.CLOSING); } else if (property.equals("getcontentlanguage")) { generatedXML.writeElement("D", "getcontentlanguage", XMLWriter.NO_CONTENT); } else if (property.equals("getcontentlength")) { generatedXML.writeProperty("D", "getcontentlength", (String.valueOf(0))); } else if (property.equals("getcontenttype")) { generatedXML.writeProperty("D", "getcontenttype", ""); } else if (property.equals("getetag")) { generatedXML.writeProperty("D", "getetag", ""); } else if (property.equals("getlastmodified")) { generatedXML.writeProperty ("D", "getlastmodified", FastHttpDateFormat.formatDate (lock.creationDate.getTime(), null)); } else if (property.equals("resourcetype")) { generatedXML.writeElement("D", "resourcetype", XMLWriter.OPENING); generatedXML.writeElement("D", "lock-null", XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "resourcetype", XMLWriter.CLOSING); } else if (property.equals("source")) { generatedXML.writeProperty("D", "source", ""); } else if (property.equals("supportedlock")) { supportedLocks = "" + "" + "" + "" + "" + "" + "" + ""; generatedXML.writeElement("D", "supportedlock", XMLWriter.OPENING); generatedXML.writeText(supportedLocks); generatedXML.writeElement("D", "supportedlock", XMLWriter.CLOSING); } else if (property.equals("lockdiscovery")) { if (!generateLockDiscovery(path, generatedXML)) propertiesNotFound.addElement(property); } else { propertiesNotFound.addElement(property); } } generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); Enumeration propertiesNotFoundList = propertiesNotFound.elements(); if (propertiesNotFoundList.hasMoreElements()) { status = "HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND + " " + WebdavStatus.getStatusText(WebdavStatus.SC_NOT_FOUND); generatedXML.writeElement("D", "propstat", XMLWriter.OPENING); generatedXML.writeElement("D", "prop", XMLWriter.OPENING); while (propertiesNotFoundList.hasMoreElements()) { generatedXML.writeElement ("D", propertiesNotFoundList.nextElement(), XMLWriter.NO_CONTENT); } generatedXML.writeElement("D", "prop", XMLWriter.CLOSING); generatedXML.writeElement("D", "status", XMLWriter.OPENING); generatedXML.writeText(status); generatedXML.writeElement("D", "status", XMLWriter.CLOSING); generatedXML.writeElement("D", "propstat", XMLWriter.CLOSING); } break; } generatedXML.writeElement("D", "response", XMLWriter.CLOSING); } /** * Print the lock discovery information associated with a path. * * @param path Path * @param generatedXML XML data to which the locks info will be appended * @return true if at least one lock was displayed */ private boolean generateLockDiscovery (String path, XMLWriter generatedXML) { LockInfo resourceLock = resourceLocks.get(path); Enumeration collectionLocksList = collectionLocks.elements(); boolean wroteStart = false; if (resourceLock != null) { wroteStart = true; generatedXML.writeElement("D", "lockdiscovery", XMLWriter.OPENING); resourceLock.toXML(generatedXML); } while (collectionLocksList.hasMoreElements()) { LockInfo currentLock = collectionLocksList.nextElement(); if (path.startsWith(currentLock.path)) { if (!wroteStart) { wroteStart = true; generatedXML.writeElement("D", "lockdiscovery", XMLWriter.OPENING); } currentLock.toXML(generatedXML); } } if (wroteStart) { generatedXML.writeElement("D", "lockdiscovery", XMLWriter.CLOSING); } else { return false; } return true; } /** * Get creation date in ISO format. */ private String getISOCreationDate(long creationDate) { StringBuilder creationDateValue = new StringBuilder (creationDateFormat.format (new Date(creationDate))); /* int offset = Calendar.getInstance().getTimeZone().getRawOffset() / 3600000; // FIXME ? if (offset < 0) { creationDateValue.append("-"); offset = -offset; } else if (offset > 0) { creationDateValue.append("+"); } if (offset != 0) { if (offset < 10) creationDateValue.append("0"); creationDateValue.append(offset + ":00"); } else { creationDateValue.append("Z"); } */ return creationDateValue.toString(); } /** * Determines the methods normally allowed for the resource. * */ private StringBuilder determineMethodsAllowed(DirContext dirContext, HttpServletRequest req) { StringBuilder methodsAllowed = new StringBuilder(); boolean exists = true; Object object = null; try { String path = getRelativePath(req); object = dirContext.lookup(path); } catch (NamingException e) { exists = false; } if (!exists) { methodsAllowed.append("OPTIONS, MKCOL, PUT, LOCK"); return methodsAllowed; } methodsAllowed.append("OPTIONS, GET, HEAD, POST, DELETE, TRACE"); methodsAllowed.append(", PROPPATCH, COPY, MOVE, LOCK, UNLOCK"); if (listings) { methodsAllowed.append(", PROPFIND"); } if (!(object instanceof DirContext)) { methodsAllowed.append(", PUT"); } return methodsAllowed; } // -------------------------------------------------- LockInfo Inner Class /** * Holds a lock information. */ private class LockInfo { // -------------------------------------------------------- Constructor /** * Constructor. */ public LockInfo() { // Ignore } // ------------------------------------------------- Instance Variables String path = "/"; String type = "write"; String scope = "exclusive"; int depth = 0; String owner = ""; Vector tokens = new Vector(); long expiresAt = 0; Date creationDate = new Date(); // ----------------------------------------------------- Public Methods /** * Get a String representation of this lock token. */ @Override public String toString() { StringBuilder result = new StringBuilder("Type:"); result.append(type); result.append("\nScope:"); result.append(scope); result.append("\nDepth:"); result.append(depth); result.append("\nOwner:"); result.append(owner); result.append("\nExpiration:"); result.append(FastHttpDateFormat.formatDate(expiresAt, null)); Enumeration tokensList = tokens.elements(); while (tokensList.hasMoreElements()) { result.append("\nToken:"); result.append(tokensList.nextElement()); } result.append("\n"); return result.toString(); } /** * Return true if the lock has expired. */ public boolean hasExpired() { return (System.currentTimeMillis() > expiresAt); } /** * Return true if the lock is exclusive. */ public boolean isExclusive() { return (scope.equals("exclusive")); } /** * Get an XML representation of this lock token. This method will * append an XML fragment to the given XML writer. */ public void toXML(XMLWriter generatedXML) { generatedXML.writeElement("D", "activelock", XMLWriter.OPENING); generatedXML.writeElement("D", "locktype", XMLWriter.OPENING); generatedXML.writeElement("D", type, XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "locktype", XMLWriter.CLOSING); generatedXML.writeElement("D", "lockscope", XMLWriter.OPENING); generatedXML.writeElement("D", scope, XMLWriter.NO_CONTENT); generatedXML.writeElement("D", "lockscope", XMLWriter.CLOSING); generatedXML.writeElement("D", "depth", XMLWriter.OPENING); if (depth == maxDepth) { generatedXML.writeText("Infinity"); } else { generatedXML.writeText("0"); } generatedXML.writeElement("D", "depth", XMLWriter.CLOSING); generatedXML.writeElement("D", "owner", XMLWriter.OPENING); generatedXML.writeText(owner); generatedXML.writeElement("D", "owner", XMLWriter.CLOSING); generatedXML.writeElement("D", "timeout", XMLWriter.OPENING); long timeout = (expiresAt - System.currentTimeMillis()) / 1000; generatedXML.writeText("Second-" + timeout); generatedXML.writeElement("D", "timeout", XMLWriter.CLOSING); generatedXML.writeElement("D", "locktoken", XMLWriter.OPENING); Enumeration tokensList = tokens.elements(); while (tokensList.hasMoreElements()) { generatedXML.writeElement("D", "href", XMLWriter.OPENING); generatedXML.writeText("opaquelocktoken:" + tokensList.nextElement()); generatedXML.writeElement("D", "href", XMLWriter.CLOSING); } generatedXML.writeElement("D", "locktoken", XMLWriter.CLOSING); generatedXML.writeElement("D", "activelock", XMLWriter.CLOSING); } } // --------------------------------------------- WebdavResolver Inner Class /** * Work around for XML parsers that don't fully respect * {@link DocumentBuilderFactory#setExpandEntityReferences(boolean)} when * called with false. External references are filtered out for * security reasons. See CVE-2007-5461. */ private static class WebdavResolver implements EntityResolver { private ServletContext context; public WebdavResolver(ServletContext theContext) { context = theContext; } @Override public InputSource resolveEntity (String publicId, String systemId) { context.log(sm.getString("webdavservlet.enternalEntityIgnored", publicId, systemId)); return new InputSource( new StringReader("Ignored external entity")); } } } // -------------------------------------------------------- WebdavStatus Class /** * Wraps the HttpServletResponse class to abstract the * specific protocol used. To support other protocols * we would only need to modify this class and the * WebDavRetCode classes. * * @author Marc Eaddy * @version 1.0, 16 Nov 1997 */ class WebdavStatus { // ----------------------------------------------------- Instance Variables /** * This Hashtable contains the mapping of HTTP and WebDAV * status codes to descriptive text. This is a static * variable. */ private static Hashtable mapStatusCodes = new Hashtable(); // ------------------------------------------------------ HTTP Status Codes /** * Status code (200) indicating the request succeeded normally. */ public static final int SC_OK = HttpServletResponse.SC_OK; /** * Status code (201) indicating the request succeeded and created * a new resource on the server. */ public static final int SC_CREATED = HttpServletResponse.SC_CREATED; /** * Status code (202) indicating that a request was accepted for * processing, but was not completed. */ public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED; /** * Status code (204) indicating that the request succeeded but that * there was no new information to return. */ public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT; /** * Status code (301) indicating that the resource has permanently * moved to a new location, and that future references should use a * new URI with their requests. */ public static final int SC_MOVED_PERMANENTLY = HttpServletResponse.SC_MOVED_PERMANENTLY; /** * Status code (302) indicating that the resource has temporarily * moved to another location, but that future references should * still use the original URI to access the resource. */ public static final int SC_MOVED_TEMPORARILY = HttpServletResponse.SC_MOVED_TEMPORARILY; /** * Status code (304) indicating that a conditional GET operation * found that the resource was available and not modified. */ public static final int SC_NOT_MODIFIED = HttpServletResponse.SC_NOT_MODIFIED; /** * Status code (400) indicating the request sent by the client was * syntactically incorrect. */ public static final int SC_BAD_REQUEST = HttpServletResponse.SC_BAD_REQUEST; /** * Status code (401) indicating that the request requires HTTP * authentication. */ public static final int SC_UNAUTHORIZED = HttpServletResponse.SC_UNAUTHORIZED; /** * Status code (403) indicating the server understood the request * but refused to fulfill it. */ public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN; /** * Status code (404) indicating that the requested resource is not * available. */ public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND; /** * Status code (500) indicating an error inside the HTTP service * which prevented it from fulfilling the request. */ public static final int SC_INTERNAL_SERVER_ERROR = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; /** * Status code (501) indicating the HTTP service does not support * the functionality needed to fulfill the request. */ public static final int SC_NOT_IMPLEMENTED = HttpServletResponse.SC_NOT_IMPLEMENTED; /** * Status code (502) indicating that the HTTP server received an * invalid response from a server it consulted when acting as a * proxy or gateway. */ public static final int SC_BAD_GATEWAY = HttpServletResponse.SC_BAD_GATEWAY; /** * Status code (503) indicating that the HTTP service is * temporarily overloaded, and unable to handle the request. */ public static final int SC_SERVICE_UNAVAILABLE = HttpServletResponse.SC_SERVICE_UNAVAILABLE; /** * Status code (100) indicating the client may continue with * its request. This interim response is used to inform the * client that the initial part of the request has been * received and has not yet been rejected by the server. */ public static final int SC_CONTINUE = 100; /** * Status code (405) indicating the method specified is not * allowed for the resource. */ public static final int SC_METHOD_NOT_ALLOWED = 405; /** * Status code (409) indicating that the request could not be * completed due to a conflict with the current state of the * resource. */ public static final int SC_CONFLICT = 409; /** * Status code (412) indicating the precondition given in one * or more of the request-header fields evaluated to false * when it was tested on the server. */ public static final int SC_PRECONDITION_FAILED = 412; /** * Status code (413) indicating the server is refusing to * process a request because the request entity is larger * than the server is willing or able to process. */ public static final int SC_REQUEST_TOO_LONG = 413; /** * Status code (415) indicating the server is refusing to service * the request because the entity of the request is in a format * not supported by the requested resource for the requested * method. */ public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; // -------------------------------------------- Extended WebDav status code /** * Status code (207) indicating that the response requires * providing status for multiple independent operations. */ public static final int SC_MULTI_STATUS = 207; // This one collides with HTTP 1.1 // "207 Partial Update OK" /** * Status code (418) indicating the entity body submitted with * the PATCH method was not understood by the resource. */ public static final int SC_UNPROCESSABLE_ENTITY = 418; // This one collides with HTTP 1.1 // "418 Reauthentication Required" /** * Status code (419) indicating that the resource does not have * sufficient space to record the state of the resource after the * execution of this method. */ public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419; // This one collides with HTTP 1.1 // "419 Proxy Reauthentication Required" /** * Status code (420) indicating the method was not executed on * a particular resource within its scope because some part of * the method's execution failed causing the entire method to be * aborted. */ public static final int SC_METHOD_FAILURE = 420; /** * Status code (423) indicating the destination resource of a * method is locked, and either the request did not contain a * valid Lock-Info header, or the Lock-Info header identifies * a lock held by another principal. */ public static final int SC_LOCKED = 423; // ------------------------------------------------------------ Initializer static { // HTTP 1.0 status Code addStatusCodeMap(SC_OK, "OK"); addStatusCodeMap(SC_CREATED, "Created"); addStatusCodeMap(SC_ACCEPTED, "Accepted"); addStatusCodeMap(SC_NO_CONTENT, "No Content"); addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently"); addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily"); addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified"); addStatusCodeMap(SC_BAD_REQUEST, "Bad Request"); addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized"); addStatusCodeMap(SC_FORBIDDEN, "Forbidden"); addStatusCodeMap(SC_NOT_FOUND, "Not Found"); addStatusCodeMap(SC_INTERNAL_SERVER_ERROR, "Internal Server Error"); addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented"); addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway"); addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable"); addStatusCodeMap(SC_CONTINUE, "Continue"); addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed"); addStatusCodeMap(SC_CONFLICT, "Conflict"); addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed"); addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long"); addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"); // WebDav Status Codes addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status"); addStatusCodeMap(SC_UNPROCESSABLE_ENTITY, "Unprocessable Entity"); addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE, "Insufficient Space On Resource"); addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure"); addStatusCodeMap(SC_LOCKED, "Locked"); } // --------------------------------------------------------- Public Methods /** * Returns the HTTP status text for the HTTP or WebDav status code * specified by looking it up in the static mapping. This is a * static function. * * @param nHttpStatusCode [IN] HTTP or WebDAV status code * @return A string with a short descriptive phrase for the * HTTP status code (e.g., "OK"). */ public static String getStatusText(int nHttpStatusCode) { Integer intKey = Integer.valueOf(nHttpStatusCode); if (!mapStatusCodes.containsKey(intKey)) { return ""; } else { return mapStatusCodes.get(intKey); } } // -------------------------------------------------------- Private Methods /** * Adds a new status code -> status text mapping. This is a static * method because the mapping is a static variable. * * @param nKey [IN] HTTP or WebDAV status code * @param strVal [IN] HTTP status text */ private static void addStatusCodeMap(int nKey, String strVal) { mapStatusCodes.put(Integer.valueOf(nKey), strVal); } } tomcat7-7.0.52/java/org/apache/catalina/servlets/package.html0000644000175100017510000000320312271471332024000 0ustar locutuslocutus

    This package contains Servlets that implement some of the standard functionality provided by the Catalina servlet container. Because these servlets are in the org.apache.catalina package hierarchy, they are in the privileged position of being able to reference internal server data structures, which application level servlets are prevented from accessing (by the application class loader implementation).

    To the extent that these servlets depend upon internal Catalina data structures, they are obviously not portable to other servlet container environments. However, they can be used as models for creating application level servlets that provide similar capabilities -- most obviously the DefaultServlet implementation, which serves static resources when Catalina runs stand-alone.

    tomcat7-7.0.52/java/org/apache/catalina/servlets/Constants.java0000644000175100017510000000166412271471332024347 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.servlets; public class Constants { public static final String Package = "org.apache.catalina.servlets"; } tomcat7-7.0.52/java/org/apache/catalina/servlets/LocalStrings.properties0000644000175100017510000000272212271471332026246 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. defaultServlet.missingResource=The requested resource ({0}) is not available defaultservlet.directorylistingfor=Directory Listing for: defaultservlet.upto=Up to: defaultservlet.subdirectories=Subdirectories: defaultservlet.files=Files: defaultservlet.skipfail=Only skipped [{0}] bytes when [{1}] were requested webdavservlet.jaxpfailed=JAXP initialization failed webdavservlet.enternalEntityIgnored=The request included a reference to an external entity with PublicID {0} and SystemID {1} which was ignored directory.filename=Filename directory.lastModified=Last Modified directory.parent=Up To {0} directory.size=Size directory.title=Directory Listing For {0} directory.version=Tomcat Catalina version 4.0 tomcat7-7.0.52/java/org/apache/catalina/servlets/LocalStrings_ja.properties0000644000175100017510000000271312271471332026720 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. defaultservlet.directorylistingfor=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7: defaultservlet.upto=\u89aa\u30c7\u30a3\u30ec\u30af\u30c8\u30ea: defaultservlet.subdirectories=\u30b5\u30d6\u30c7\u30a3\u30ec\u30af\u30c8\u30ea: defaultservlet.files=\u30d5\u30a1\u30a4\u30eb: webdavservlet.jaxpfailed=JAXP\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f directory.filename=\u30d5\u30a1\u30a4\u30eb\u540d directory.lastModified=\u6700\u7d42\u66f4\u65b0 directory.parent={0} \u306b\u79fb\u52d5 directory.size=\u30b5\u30a4\u30ba directory.title={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7 directory.version=Tomcat Catalina \u30d0\u30fc\u30b8\u30e7\u30f3 4.0 tomcat7-7.0.52/java/org/apache/catalina/servlets/LocalStrings_fr.properties0000644000175100017510000000236012271471332026733 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. defaultservlet.directorylistingfor=Liste du r\u00e9pertoire pour : defaultservlet.upto=Jusqu''\u00e0: defaultservlet.subdirectories=Sous-r\u00e9pertoires: defaultservlet.files=Fichiers: webdavservlet.jaxpfailed=Erreur d''initialisation de JAXP directory.filename=Nom de fichier directory.lastModified=Derni\u00e8re modification directory.parent=Jusqu''\u00e0 {0} directory.size=Taille directory.title=Liste du r\u00e9pertoire pour {0} directory.version=Tomcat Catalina version 4.0 tomcat7-7.0.52/java/org/apache/catalina/Store.java0000644000175100017510000001025012271471332021607 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.beans.PropertyChangeListener; import java.io.IOException; /** * A Store is the abstraction of a Catalina component that provides * persistent storage and loading of Sessions and their associated user data. * Implementations are free to save and load the Sessions to any media they * wish, but it is assumed that saved Sessions are persistent across * server or context restarts. * * @author Craig R. McClanahan */ public interface Store { // ------------------------------------------------------------- Properties /** * Return descriptive information about this Store implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo(); /** * Return the Manager instance associated with this Store. */ public Manager getManager(); /** * Set the Manager associated with this Store. * * @param manager The Manager which will use this Store. */ public void setManager(Manager manager); /** * Return the number of Sessions present in this Store. * * @exception IOException if an input/output error occurs */ public int getSize() throws IOException; // --------------------------------------------------------- Public Methods /** * Add a property change listener to this component. * * @param listener The listener to add */ public void addPropertyChangeListener(PropertyChangeListener listener); /** * Return an array containing the session identifiers of all Sessions * currently saved in this Store. If there are no such Sessions, a * zero-length array is returned. * * @exception IOException if an input/output error occurred */ public String[] keys() throws IOException; /** * Load and return the Session associated with the specified session * identifier from this Store, without removing it. If there is no * such stored Session, return null. * * @param id Session identifier of the session to load * * @exception ClassNotFoundException if a deserialization error occurs * @exception IOException if an input/output error occurs */ public Session load(String id) throws ClassNotFoundException, IOException; /** * Remove the Session with the specified session identifier from * this Store, if present. If no such Session is present, this method * takes no action. * * @param id Session identifier of the Session to be removed * * @exception IOException if an input/output error occurs */ public void remove(String id) throws IOException; /** * Remove all Sessions from this Store. */ public void clear() throws IOException; /** * Remove a property change listener from this component. * * @param listener The listener to remove */ public void removePropertyChangeListener(PropertyChangeListener listener); /** * Save the specified Session into this Store. Any previously saved * information for the associated session identifier is replaced. * * @param session Session to be saved * * @exception IOException if an input/output error occurs */ public void save(Session session) throws IOException; } tomcat7-7.0.52/java/org/apache/catalina/LifecycleException.java0000644000175100017510000000427412271471332024302 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * General purpose exception that is thrown to indicate a lifecycle related * problem. Such exceptions should generally be considered fatal to the * operation of the application containing this component. * * @author Craig R. McClanahan */ public final class LifecycleException extends Exception { private static final long serialVersionUID = 1L; //------------------------------------------------------------ Constructors /** * Construct a new LifecycleException with no other information. */ public LifecycleException() { super(); } /** * Construct a new LifecycleException for the specified message. * * @param message Message describing this exception */ public LifecycleException(String message) { super(message); } /** * Construct a new LifecycleException for the specified throwable. * * @param throwable Throwable that caused this exception */ public LifecycleException(Throwable throwable) { super(throwable); } /** * Construct a new LifecycleException for the specified message * and throwable. * * @param message Message describing this exception * @param throwable Throwable that caused this exception */ public LifecycleException(String message, Throwable throwable) { super(message, throwable); } }tomcat7-7.0.52/java/org/apache/catalina/Server.java0000644000175100017510000001233012271471332021762 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import org.apache.catalina.deploy.NamingResources; import org.apache.catalina.startup.Catalina; /** * A Server element represents the entire Catalina * servlet container. Its attributes represent the characteristics of * the servlet container as a whole. A Server may contain * one or more Services, and the top level set of naming * resources. *

    * Normally, an implementation of this interface will also implement * Lifecycle, such that when the start() and * stop() methods are called, all of the defined * Services are also started or stopped. *

    * In between, the implementation must open a server socket on the port number * specified by the port property. When a connection is accepted, * the first line is read and compared with the specified shutdown command. * If the command matches, shutdown of the server is initiated. *

    * NOTE - The concrete implementation of this class should * register the (singleton) instance with the ServerFactory * class in its constructor(s). * * @author Craig R. McClanahan */ public interface Server extends Lifecycle { // ------------------------------------------------------------- Properties /** * Return descriptive information about this Server implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo(); /** * Return the global naming resources. */ public NamingResources getGlobalNamingResources(); /** * Set the global naming resources. * * @param globalNamingResources The new global naming resources */ public void setGlobalNamingResources (NamingResources globalNamingResources); /** * Return the global naming resources context. */ public javax.naming.Context getGlobalNamingContext(); /** * Return the port number we listen to for shutdown commands. */ public int getPort(); /** * Set the port number we listen to for shutdown commands. * * @param port The new port number */ public void setPort(int port); /** * Return the address on which we listen to for shutdown commands. */ public String getAddress(); /** * Set the address on which we listen to for shutdown commands. * * @param address The new address */ public void setAddress(String address); /** * Return the shutdown command string we are waiting for. */ public String getShutdown(); /** * Set the shutdown command we are waiting for. * * @param shutdown The new shutdown command */ public void setShutdown(String shutdown); /** * Return the parent class loader for this component. If not set, return * {@link #getCatalina()} {@link Catalina#getParentClassLoader()}. If * catalina has not been set, return the system class loader. */ public ClassLoader getParentClassLoader(); /** * Set the parent class loader for this server. * * @param parent The new parent class loader */ public void setParentClassLoader(ClassLoader parent); /** * Return the outer Catalina startup/shutdown component if present. */ public Catalina getCatalina(); /** * Set the outer Catalina startup/shutdown component if present. */ public void setCatalina(Catalina catalina); // --------------------------------------------------------- Public Methods /** * Add a new Service to the set of defined Services. * * @param service The Service to be added */ public void addService(Service service); /** * Wait until a proper shutdown command is received, then return. */ public void await(); /** * Return the specified Service (if it exists); otherwise return * null. * * @param name Name of the Service to be returned */ public Service findService(String name); /** * Return the set of Services defined within this Server. */ public Service[] findServices(); /** * Remove the specified Service from the set associated from this * Server. * * @param service The Service to be removed */ public void removeService(Service service); } tomcat7-7.0.52/java/org/apache/catalina/session/0000755000175100017510000000000012301126371021327 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/session/LocalStrings_es.properties0000644000175100017510000001306112271471332026547 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationSession.session.ise = estado inv\u00E1lido de sesi\u00F3n applicationSession.value.iae = valor nulo fileStore.saving = Salvando Sesi\u00F3n {0} en archivo {1} fileStore.loading = Cargando Sesi\u00F3n {0} desde archivo {1} fileStore.removing = Quitando Sesi\u00F3n {0} en archivo {1} JDBCStore.close = Excepci\u00F3n cerrando conexi\u00F3n a base de datos {0} JDBCStore.saving = Salvando Sesi\u00F3n {0} en base de datos {1} JDBCStore.loading = Cargando Sesi\u00F3n {0} desde base de datos {1} JDBCStore.removing = Quitando Sesi\u00F3n {0} en base de datos {1} JDBCStore.SQLException = Error SQL {0} JDBCStore.checkConnectionDBClosed = La conexi\u00F3na a base de datos es nula o est\u00E1 cerrada. Intentando reabrirla. JDBCStore.checkConnectionDBReOpenFail = Fall\u00F3 la reapertura de la base de datos. Puede que la base de datos est\u00E9 ca\u00EDda. JDBCStore.checkConnectionSQLException = Ha tenido lugar una excepci\u00F3n SQL {0} JDBCStore.checkConnectionClassNotFoundException = No se ha hallado la clase del manejador (driver) JDBC {0} managerBase.createSession.ise = createSession\: Demasiadas sesiones activas managerBase.sessionTimeout = Valor inv\u00E1lido de Tiempo Agotado de sesi\u00F3n {0} serverSession.value.iae = valor nulo standardManager.expireException = processsExpire\: Excepci\u00F3n durante la expiraci\u00F3n de sesi\u00F3n standardManager.loading = Cargando sesiones persistidas desde {0} standardManager.loading.cnfe = ClassNotFoundException al cargar sesiones persistidas\: {0} standardManager.loading.ioe = IOException al cargar sesiones persistidas\: {0} standardManager.unloading = Salvando sesiones persistidas a {0} standardManager.unloading.ioe = IOException al salvar sesiones persistidas\: {0} standardManager.managerLoad = Excepci\u00F3n cargando sesiones desde almacenamiento persistente standardManager.managerUnload = Excepci\u00F3n descargando sesiones a almacenamiento persistente standardSession.attributeEvent = El oyente de eventos de atributo de Sesi\u00F3n lanz\u00F3 una excepci\u00F3n standardSession.bindingEvent = El oyente de eventos de ligado de Sesi\u00F3n lanz\u00F3 una excepci\u00F3n standardSession.invalidate.ise = invalidate\: La Sesi\u00F3n ya ha sido invalidada standardSession.isNew.ise = isNew\: La Sesi\u00F3n ya ha sido invalidada standardSession.getAttribute.ise = getAttribute\: La Sesi\u00F3n ya ha sido invalidada standardSession.getAttributeNames.ise = getAttributeNames\: La Sesi\u00F3n ya ha sido invalidada standardSession.getCreationTime.ise = getCreationTime\: La Sesi\u00F3n ya ha sido invalidada standardSession.getThisAccessedTime.ise = getThisAccessedTime\: La Sesi\u00F3n ya ha sido invalidada standardSession.getLastAccessedTime.ise = getLastAccessedTime\: La Sesi\u00F3n ya ha sido invalidada standardSession.getId.ise = getId\: La Sesi\u00F3n ya ha sido invalidada standardSession.getMaxInactiveInterval.ise = getMaxInactiveInterval\: La Sesi\u00F3n ya ha sido invalidada standardSession.getValueNames.ise = getValueNames\: La Sesi\u00F3n ya ha sido invalidada standardSession.notSerializable = No puedo serializar atributo de sesi\u00F3n {0} para sesi\u00F3n {1} standardSession.removeAttribute.ise = removeAttribute\: La Sesi\u00F3n ya ha sido invalidada standardSession.sessionEvent = El oyente de evento de Sesi\u00F3n lanz\u00F3 una execpci\u00F3n standardSession.setAttribute.iae = setAttribute\: Atributo {0} no serializable standardSession.setAttribute.ise = setAttribute\: La Sesi\u00F3n ya ha sido invalidada standardSession.setAttribute.namenull = setAttribute\: el nuevo par\u00E1metro no puede ser nulo standardSession.sessionCreated = Creada Sesi\u00F3n id \= {0} persistentManager.loading = Cargando {0} sesiones persistidas persistentManager.unloading = Salvando {0} sesiones persistidas persistentManager.expiring = Expirando {0} sesiones antes de salvarlas persistentManager.deserializeError = Error des-serializando Sesi\u00F3n {0}\: {1} persistentManager.serializeError = Error serializando Sesi\u00F3n {0}\: {1} persistentManager.swapMaxIdle = Intercambiando sesi\u00F3n {0} a fuera a Almac\u00E9n, ociosa durante {1} segundos persistentManager.backupMaxIdle = Respaldando sesi\u00F3n {0} a Almac\u00E9n, ociosa durante {1} segundos persistentManager.backupException = Ha tenido lugar una excepci\u00F3n al respaldar la Sesi\u00F3n {0}\: {1} persistentManager.tooManyActive = Demasiadas sesiones activas, {0}, buscando sesiones ociosas para intercambiar persistentManager.swapTooManyActive = Intercambiando sesi\u00F3n {0} a fuera, ociosa durante {1} segundos\: Demasiadas sesiones activas persistentManager.processSwaps = Mirando qu\u00E9 sesiones intercambiar a fuera, {0} sesiones activas en memoria persistentManager.activeSession = La sesi\u00F3n {0} ha estado ociosa durante {1} segundos persistentManager.swapIn = Intercambiando sesi\u00F3n {0} a dentro desde Almac\u00E9n tomcat7-7.0.52/java/org/apache/catalina/session/ManagerBase.java0000644000175100017510000011465712271471332024363 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.Deque; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.LifecycleException; import org.apache.catalina.Manager; import org.apache.catalina.Session; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.catalina.util.SessionIdGenerator; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Minimal implementation of the Manager interface that supports * no session persistence or distributable capabilities. This class may * be subclassed to create more sophisticated Manager implementations. * * @author Craig R. McClanahan */ public abstract class ManagerBase extends LifecycleMBeanBase implements Manager, PropertyChangeListener { private final Log log = LogFactory.getLog(ManagerBase.class); // must not be static // ----------------------------------------------------- Instance Variables /** * The Container with which this Manager is associated. */ protected Container container; /** * The distributable flag for Sessions created by this Manager. If this * flag is set to true, any user attributes added to a * session controlled by this Manager must be Serializable. */ protected boolean distributable; /** * The descriptive information string for this implementation. */ private static final String info = "ManagerBase/1.0"; /** * The descriptive name of this Manager implementation (for logging). */ private static final String name = "ManagerBase"; /** * The default maximum inactive interval for Sessions created by * this Manager. */ protected int maxInactiveInterval = 30 * 60; /** * The session id length of Sessions created by this Manager. */ protected int sessionIdLength = 16; /** * The Java class name of the secure random number generator class to be * used when generating session identifiers. The random number generator * class must be self-seeding and have a zero-argument constructor. If not * specified, an instance of {@link java.security.SecureRandom} will be * generated. */ protected String secureRandomClass = null; /** * The name of the algorithm to use to create instances of * {@link java.security.SecureRandom} which are used to generate session IDs. * If no algorithm is specified, SHA1PRNG is used. To use the platform * default (which may be SHA1PRNG), specify the empty string. If an invalid * algorithm and/or provider is specified the SecureRandom instances will be * created using the defaults. If that fails, the SecureRandom instances * will be created using platform defaults. */ protected String secureRandomAlgorithm = "SHA1PRNG"; /** * The name of the provider to use to create instances of * {@link java.security.SecureRandom} which are used to generate session IDs. * If no algorithm is specified the of SHA1PRNG default is used. If an * invalid algorithm and/or provider is specified the SecureRandom instances * will be created using the defaults. If that fails, the SecureRandom * instances will be created using platform defaults. */ protected String secureRandomProvider = null; protected SessionIdGenerator sessionIdGenerator = null; /** * The longest time (in seconds) that an expired session had been alive. */ protected volatile int sessionMaxAliveTime; private final Object sessionMaxAliveTimeUpdateLock = new Object(); protected static final int TIMING_STATS_CACHE_SIZE = 100; protected final Deque sessionCreationTiming = new LinkedList(); protected final Deque sessionExpirationTiming = new LinkedList(); /** * Number of sessions that have expired. */ protected final AtomicLong expiredSessions = new AtomicLong(0); /** * The set of currently active Sessions for this Manager, keyed by * session identifier. */ protected Map sessions = new ConcurrentHashMap(); // Number of sessions created by this manager protected long sessionCounter=0; protected volatile int maxActive=0; private final Object maxActiveUpdateLock = new Object(); /** * The maximum number of active Sessions allowed, or -1 for no limit. */ protected int maxActiveSessions = -1; /** * Number of session creations that failed due to maxActiveSessions. */ protected int rejectedSessions = 0; // number of duplicated session ids - anything >0 means we have problems protected volatile int duplicates=0; /** * Processing time during session expiration. */ protected long processingTime = 0; /** * Iteration count for background processing. */ private int count = 0; /** * Frequency of the session expiration, and related manager operations. * Manager operations will be done once for the specified amount of * backgrondProcess calls (ie, the lower the amount, the most often the * checks will occur). */ protected int processExpiresFrequency = 6; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The property change support for this component. */ protected final PropertyChangeSupport support = new PropertyChangeSupport(this); // ------------------------------------------------------------- Properties /** * Return the Container with which this Manager is associated. */ @Override public Container getContainer() { return (this.container); } /** * Set the Container with which this Manager is associated. * * @param container The newly associated Container */ @Override public void setContainer(Container container) { // De-register from the old Container (if any) if ((this.container != null) && (this.container instanceof Context)) ((Context) this.container).removePropertyChangeListener(this); Container oldContainer = this.container; this.container = container; support.firePropertyChange("container", oldContainer, this.container); // Register with the new Container (if any) if ((this.container != null) && (this.container instanceof Context)) { setMaxInactiveInterval ( ((Context) this.container).getSessionTimeout()*60 ); ((Context) this.container).addPropertyChangeListener(this); } } /** Returns the name of the implementation class. */ public String getClassName() { return this.getClass().getName(); } /** * Return the distributable flag for the sessions supported by * this Manager. */ @Override public boolean getDistributable() { return (this.distributable); } /** * Set the distributable flag for the sessions supported by this * Manager. If this flag is set, all user data objects added to * sessions associated with this manager must implement Serializable. * * @param distributable The new distributable flag */ @Override public void setDistributable(boolean distributable) { boolean oldDistributable = this.distributable; this.distributable = distributable; support.firePropertyChange("distributable", Boolean.valueOf(oldDistributable), Boolean.valueOf(this.distributable)); } /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return the default maximum inactive interval (in seconds) * for Sessions created by this Manager. */ @Override public int getMaxInactiveInterval() { return (this.maxInactiveInterval); } /** * Set the default maximum inactive interval (in seconds) * for Sessions created by this Manager. * * @param interval The new default value */ @Override public void setMaxInactiveInterval(int interval) { int oldMaxInactiveInterval = this.maxInactiveInterval; this.maxInactiveInterval = interval; support.firePropertyChange("maxInactiveInterval", Integer.valueOf(oldMaxInactiveInterval), Integer.valueOf(this.maxInactiveInterval)); } /** * Gets the session id length (in bytes) of Sessions created by * this Manager. * * @return The session id length */ @Override public int getSessionIdLength() { return (this.sessionIdLength); } /** * Sets the session id length (in bytes) for Sessions created by this * Manager. * * @param idLength The session id length */ @Override public void setSessionIdLength(int idLength) { int oldSessionIdLength = this.sessionIdLength; this.sessionIdLength = idLength; support.firePropertyChange("sessionIdLength", Integer.valueOf(oldSessionIdLength), Integer.valueOf(this.sessionIdLength)); } /** * Return the descriptive short name of this Manager implementation. */ public String getName() { return (name); } /** * Return the secure random number generator class name. */ public String getSecureRandomClass() { return (this.secureRandomClass); } /** * Set the secure random number generator class name. * * @param secureRandomClass The new secure random number generator class * name */ public void setSecureRandomClass(String secureRandomClass) { String oldSecureRandomClass = this.secureRandomClass; this.secureRandomClass = secureRandomClass; support.firePropertyChange("secureRandomClass", oldSecureRandomClass, this.secureRandomClass); } /** * Return the secure random number generator algorithm name. */ public String getSecureRandomAlgorithm() { return secureRandomAlgorithm; } /** * Set the secure random number generator algorithm name. * * @param secureRandomAlgorithm The new secure random number generator * algorithm name */ public void setSecureRandomAlgorithm(String secureRandomAlgorithm) { this.secureRandomAlgorithm = secureRandomAlgorithm; } /** * Return the secure random number generator provider name. */ public String getSecureRandomProvider() { return secureRandomProvider; } /** * Set the secure random number generator provider name. * * @param secureRandomProvider The new secure random number generator * provider name */ public void setSecureRandomProvider(String secureRandomProvider) { this.secureRandomProvider = secureRandomProvider; } /** * Number of session creations that failed due to maxActiveSessions * * @return The count */ @Override public int getRejectedSessions() { return rejectedSessions; } /** * Gets the number of sessions that have expired. * * @return Number of sessions that have expired */ @Override public long getExpiredSessions() { return expiredSessions.get(); } /** * Sets the number of sessions that have expired. * * @param expiredSessions Number of sessions that have expired */ @Override public void setExpiredSessions(long expiredSessions) { this.expiredSessions.set(expiredSessions); } public long getProcessingTime() { return processingTime; } public void setProcessingTime(long processingTime) { this.processingTime = processingTime; } /** * Return the frequency of manager checks. */ public int getProcessExpiresFrequency() { return (this.processExpiresFrequency); } /** * Set the manager checks frequency. * * @param processExpiresFrequency the new manager checks frequency */ public void setProcessExpiresFrequency(int processExpiresFrequency) { if (processExpiresFrequency <= 0) { return; } int oldProcessExpiresFrequency = this.processExpiresFrequency; this.processExpiresFrequency = processExpiresFrequency; support.firePropertyChange("processExpiresFrequency", Integer.valueOf(oldProcessExpiresFrequency), Integer.valueOf(this.processExpiresFrequency)); } // --------------------------------------------------------- Public Methods /** * Implements the Manager interface, direct call to processExpires */ @Override public void backgroundProcess() { count = (count + 1) % processExpiresFrequency; if (count == 0) processExpires(); } /** * Invalidate all sessions that have expired. */ public void processExpires() { long timeNow = System.currentTimeMillis(); Session sessions[] = findSessions(); int expireHere = 0 ; if(log.isDebugEnabled()) log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); for (int i = 0; i < sessions.length; i++) { if (sessions[i]!=null && !sessions[i].isValid()) { expireHere++; } } long timeEnd = System.currentTimeMillis(); if(log.isDebugEnabled()) log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); processingTime += ( timeEnd - timeNow ); } @Override protected void initInternal() throws LifecycleException { super.initInternal(); setDistributable(((Context) getContainer()).getDistributable()); } @Override protected void startInternal() throws LifecycleException { // Ensure caches for timing stats are the right size by filling with // nulls. while (sessionCreationTiming.size() < TIMING_STATS_CACHE_SIZE) { sessionCreationTiming.add(null); } while (sessionExpirationTiming.size() < TIMING_STATS_CACHE_SIZE) { sessionExpirationTiming.add(null); } sessionIdGenerator = new SessionIdGenerator(); sessionIdGenerator.setJvmRoute(getJvmRoute()); sessionIdGenerator.setSecureRandomAlgorithm(getSecureRandomAlgorithm()); sessionIdGenerator.setSecureRandomClass(getSecureRandomClass()); sessionIdGenerator.setSecureRandomProvider(getSecureRandomProvider()); sessionIdGenerator.setSessionIdLength(getSessionIdLength()); // Force initialization of the random number generator if (log.isDebugEnabled()) log.debug("Force random number initialization starting"); sessionIdGenerator.generateSessionId(); if (log.isDebugEnabled()) log.debug("Force random number initialization completed"); } @Override protected void stopInternal() throws LifecycleException { this.sessionIdGenerator = null; } /** * Add this Session to the set of active Sessions for this Manager. * * @param session Session to be added */ @Override public void add(Session session) { sessions.put(session.getIdInternal(), session); int size = getActiveSessions(); if( size > maxActive ) { synchronized(maxActiveUpdateLock) { if( size > maxActive ) { maxActive = size; } } } } /** * Add a property change listener to this component. * * @param listener The listener to add */ @Override public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } /** * Construct and return a new session object, based on the default * settings specified by this Manager's properties. The session * id specified will be used as the session id. * If a new session cannot be created for any reason, return * null. * * @param sessionId The session id which should be used to create the * new session; if null, a new session id will be * generated * @exception IllegalStateException if a new session cannot be * instantiated for any reason */ @Override public Session createSession(String sessionId) { if ((maxActiveSessions >= 0) && (getActiveSessions() >= maxActiveSessions)) { rejectedSessions++; throw new TooManyActiveSessionsException( sm.getString("managerBase.createSession.ise"), maxActiveSessions); } // Recycle or create a Session instance Session session = createEmptySession(); // Initialize the properties of the new session and return it session.setNew(true); session.setValid(true); session.setCreationTime(System.currentTimeMillis()); session.setMaxInactiveInterval(this.maxInactiveInterval); String id = sessionId; if (id == null) { id = generateSessionId(); } session.setId(id); sessionCounter++; SessionTiming timing = new SessionTiming(session.getCreationTime(), 0); synchronized (sessionCreationTiming) { sessionCreationTiming.add(timing); sessionCreationTiming.poll(); } return (session); } /** * Get a session from the recycled ones or create a new empty one. * The PersistentManager manager does not need to create session data * because it reads it from the Store. */ @Override public Session createEmptySession() { return (getNewSession()); } /** * Return the active Session, associated with this Manager, with the * specified session id (if any); otherwise return null. * * @param id The session id for the session to be returned * * @exception IllegalStateException if a new session cannot be * instantiated for any reason * @exception IOException if an input/output error occurs while * processing this request */ @Override public Session findSession(String id) throws IOException { if (id == null) return (null); return sessions.get(id); } /** * Return the set of active Sessions associated with this Manager. * If this Manager has no active Sessions, a zero-length array is returned. */ @Override public Session[] findSessions() { return sessions.values().toArray(new Session[0]); } /** * Remove this Session from the active Sessions for this Manager. * * @param session Session to be removed */ @Override public void remove(Session session) { remove(session, false); } /** * Remove this Session from the active Sessions for this Manager. * * @param session Session to be removed * @param update Should the expiration statistics be updated */ @Override public void remove(Session session, boolean update) { // If the session has expired - as opposed to just being removed from // the manager because it is being persisted - update the expired stats if (update) { long timeNow = System.currentTimeMillis(); int timeAlive = (int) (timeNow - session.getCreationTimeInternal())/1000; updateSessionMaxAliveTime(timeAlive); expiredSessions.incrementAndGet(); SessionTiming timing = new SessionTiming(timeNow, timeAlive); synchronized (sessionExpirationTiming) { sessionExpirationTiming.add(timing); sessionExpirationTiming.poll(); } } if (session.getIdInternal() != null) { sessions.remove(session.getIdInternal()); } } /** * Remove a property change listener from this component. * * @param listener The listener to remove */ @Override public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } /** * Change the session ID of the current session to a new randomly generated * session ID. * * @param session The session to change the session ID for */ @Override public void changeSessionId(Session session) { String oldId = session.getIdInternal(); session.setId(generateSessionId(), false); String newId = session.getIdInternal(); container.fireContainerEvent(Context.CHANGE_SESSION_ID_EVENT, new String[] {oldId, newId}); } // ------------------------------------------------------ Protected Methods /** * Get new session class to be used in the doLoad() method. */ protected StandardSession getNewSession() { return new StandardSession(this); } /** * Generate and return a new session identifier. */ protected String generateSessionId() { String result = null; do { if (result != null) { // Not thread-safe but if one of multiple increments is lost // that is not a big deal since the fact that there was any // duplicate is a much bigger issue. duplicates++; } result = sessionIdGenerator.generateSessionId(); } while (sessions.containsKey(result)); return result; } // ------------------------------------------------------ Protected Methods /** * Retrieve the enclosing Engine for this Manager. * * @return an Engine object (or null). */ public Engine getEngine() { Engine e = null; for (Container c = getContainer(); e == null && c != null ; c = c.getParent()) { if (c instanceof Engine) { e = (Engine)c; } } return e; } /** * Retrieve the JvmRoute for the enclosing Engine. * @return the JvmRoute or null. */ public String getJvmRoute() { Engine e = getEngine(); return e == null ? null : e.getJvmRoute(); } // -------------------------------------------------------- Package Methods @Override public void setSessionCounter(long sessionCounter) { this.sessionCounter = sessionCounter; } /** * Total sessions created by this manager. * * @return sessions created */ @Override public long getSessionCounter() { return sessionCounter; } /** * Number of duplicated session IDs generated by the random source. * Anything bigger than 0 means problems. * * @return The count of duplicates */ public int getDuplicates() { return duplicates; } public void setDuplicates(int duplicates) { this.duplicates = duplicates; } /** * Returns the number of active sessions * * @return number of sessions active */ @Override public int getActiveSessions() { return sessions.size(); } /** * Max number of concurrent active sessions * * @return The highest number of concurrent active sessions */ @Override public int getMaxActive() { return maxActive; } @Override public void setMaxActive(int maxActive) { synchronized (maxActiveUpdateLock) { this.maxActive = maxActive; } } /** * Return the maximum number of active Sessions allowed, or -1 for * no limit. */ public int getMaxActiveSessions() { return (this.maxActiveSessions); } /** * Set the maximum number of active Sessions allowed, or -1 for * no limit. * * @param max The new maximum number of sessions */ public void setMaxActiveSessions(int max) { int oldMaxActiveSessions = this.maxActiveSessions; this.maxActiveSessions = max; support.firePropertyChange("maxActiveSessions", Integer.valueOf(oldMaxActiveSessions), Integer.valueOf(this.maxActiveSessions)); } /** * Gets the longest time (in seconds) that an expired session had been * alive. * * @return Longest time (in seconds) that an expired session had been * alive. */ @Override public int getSessionMaxAliveTime() { return sessionMaxAliveTime; } /** * Sets the longest time (in seconds) that an expired session had been * alive. Typically used for resetting the current value. * * @param sessionMaxAliveTime Longest time (in seconds) that an expired * session had been alive. */ @Override public void setSessionMaxAliveTime(int sessionMaxAliveTime) { synchronized (sessionMaxAliveTimeUpdateLock) { this.sessionMaxAliveTime = sessionMaxAliveTime; } } /** * Updates the sessionMaxAliveTime attribute if the candidate value is * larger than the current value. * * @param sessionAliveTime The candidate value (in seconds) for the new * sessionMaxAliveTime value. */ public void updateSessionMaxAliveTime(int sessionAliveTime) { if (sessionAliveTime > this.sessionMaxAliveTime) { synchronized (sessionMaxAliveTimeUpdateLock) { if (sessionAliveTime > this.sessionMaxAliveTime) { this.sessionMaxAliveTime = sessionAliveTime; } } } } /** * Gets the average time (in seconds) that expired sessions had been * alive based on the last 100 sessions to expire. If less than * 100 sessions have expired then all available data is used. * * @return Average time (in seconds) that expired sessions had been * alive. */ @Override public int getSessionAverageAliveTime() { // Copy current stats List copy = new ArrayList(); synchronized (sessionExpirationTiming) { copy.addAll(sessionExpirationTiming); } // Init int counter = 0; int result = 0; Iterator iter = copy.iterator(); // Calculate average while (iter.hasNext()) { SessionTiming timing = iter.next(); if (timing != null) { int timeAlive = timing.getDuration(); counter++; // Very careful not to overflow - probably not necessary result = (result * ((counter - 1)/counter)) + (timeAlive/counter); } } return result; } /** * Gets the current rate of session creation (in session per minute) based * on the creation time of the previous 100 sessions created. If less than * 100 sessions have been created then all available data is used. * * @return The current rate (in sessions per minute) of session creation */ @Override public int getSessionCreateRate() { long now = System.currentTimeMillis(); // Copy current stats List copy = new ArrayList(); synchronized (sessionCreationTiming) { copy.addAll(sessionCreationTiming); } // Init long oldest = now; int counter = 0; int result = 0; Iterator iter = copy.iterator(); // Calculate rate while (iter.hasNext()) { SessionTiming timing = iter.next(); if (timing != null) { counter++; if (timing.getTimestamp() < oldest) { oldest = timing.getTimestamp(); } } } if (counter > 0) { if (oldest < now) { result = (1000*60*counter)/(int) (now - oldest); } else { result = Integer.MAX_VALUE; } } return result; } /** * Gets the current rate of session expiration (in session per minute) based * on the expiry time of the previous 100 sessions expired. If less than * 100 sessions have expired then all available data is used. * * @return The current rate (in sessions per minute) of session expiration */ @Override public int getSessionExpireRate() { long now = System.currentTimeMillis(); // Copy current stats List copy = new ArrayList(); synchronized (sessionExpirationTiming) { copy.addAll(sessionExpirationTiming); } // Init long oldest = now; int counter = 0; int result = 0; Iterator iter = copy.iterator(); // Calculate rate while (iter.hasNext()) { SessionTiming timing = iter.next(); if (timing != null) { counter++; if (timing.getTimestamp() < oldest) { oldest = timing.getTimestamp(); } } } if (counter > 0) { if (oldest < now) { result = (1000*60*counter)/(int) (now - oldest); } else { // Better than reporting zero result = Integer.MAX_VALUE; } } return result; } /** * For debugging: return a list of all session ids currently active * */ public String listSessionIds() { StringBuilder sb=new StringBuilder(); Iterator keys = sessions.keySet().iterator(); while (keys.hasNext()) { sb.append(keys.next()).append(" "); } return sb.toString(); } /** * For debugging: get a session attribute * * @param sessionId * @param key * @return The attribute value, if found, null otherwise */ public String getSessionAttribute( String sessionId, String key ) { Session s = sessions.get(sessionId); if( s==null ) { if(log.isInfoEnabled()) log.info("Session not found " + sessionId); return null; } Object o=s.getSession().getAttribute(key); if( o==null ) return null; return o.toString(); } /** * Returns information about the session with the given session id. * *

    The session information is organized as a HashMap, mapping * session attribute names to the String representation of their values. * * @param sessionId Session id * * @return HashMap mapping session attribute names to the String * representation of their values, or null if no session with the * specified id exists, or if the session does not have any attributes */ public HashMap getSession(String sessionId) { Session s = sessions.get(sessionId); if (s == null) { if (log.isInfoEnabled()) { log.info("Session not found " + sessionId); } return null; } Enumeration ee = s.getSession().getAttributeNames(); if (ee == null || !ee.hasMoreElements()) { return null; } HashMap map = new HashMap(); while (ee.hasMoreElements()) { String attrName = ee.nextElement(); map.put(attrName, getSessionAttribute(sessionId, attrName)); } return map; } public void expireSession( String sessionId ) { Session s=sessions.get(sessionId); if( s==null ) { if(log.isInfoEnabled()) log.info("Session not found " + sessionId); return; } s.expire(); } public long getThisAccessedTimestamp( String sessionId ) { Session s=sessions.get(sessionId); if(s== null) return -1 ; return s.getThisAccessedTime(); } public String getThisAccessedTime( String sessionId ) { Session s=sessions.get(sessionId); if( s==null ) { if(log.isInfoEnabled()) log.info("Session not found " + sessionId); return ""; } return new Date(s.getThisAccessedTime()).toString(); } public long getLastAccessedTimestamp( String sessionId ) { Session s=sessions.get(sessionId); if(s== null) return -1 ; return s.getLastAccessedTime(); } public String getLastAccessedTime( String sessionId ) { Session s=sessions.get(sessionId); if( s==null ) { if(log.isInfoEnabled()) log.info("Session not found " + sessionId); return ""; } return new Date(s.getLastAccessedTime()).toString(); } public String getCreationTime( String sessionId ) { Session s=sessions.get(sessionId); if( s==null ) { if(log.isInfoEnabled()) log.info("Session not found " + sessionId); return ""; } return new Date(s.getCreationTime()).toString(); } public long getCreationTimestamp( String sessionId ) { Session s=sessions.get(sessionId); if(s== null) return -1 ; return s.getCreationTime(); } /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append('['); if (container == null) { sb.append("Container is null"); } else { sb.append(container.getName()); } sb.append(']'); return sb.toString(); } // -------------------- JMX and Registration -------------------- @Override public String getObjectNameKeyProperties() { StringBuilder name = new StringBuilder("type=Manager"); if (container instanceof Context) { name.append(",context="); String contextName = container.getName(); if (!contextName.startsWith("/")) { name.append('/'); } name.append(contextName); Context context = (Context) container; name.append(",host="); name.append(context.getParent().getName()); } else { // Unlikely / impossible? Handle it to be safe name.append(",container="); name.append(container.getName()); } return name.toString(); } @Override public String getDomainInternal() { return MBeanUtils.getDomain(container); } // ----------------------------------------- PropertyChangeListener Methods /** * Process property change events from our associated Context. * * @param event * The property change event that has occurred */ @Override public void propertyChange(PropertyChangeEvent event) { // Validate the source of this event if (!(event.getSource() instanceof Context)) return; // Process a relevant property change if (event.getPropertyName().equals("sessionTimeout")) { try { setMaxInactiveInterval( ((Integer) event.getNewValue()).intValue() * 60); } catch (NumberFormatException e) { log.error(sm.getString("managerBase.sessionTimeout", event.getNewValue())); } } } // ----------------------------------------------------------- Inner classes protected static final class SessionTiming { private final long timestamp; private final int duration; public SessionTiming(long timestamp, int duration) { this.timestamp = timestamp; this.duration = duration; } /** * Time stamp associated with this piece of timing information in * milliseconds. */ public long getTimestamp() { return timestamp; } /** * Duration associated with this piece of timing information in seconds. */ public int getDuration() { return duration; } } } tomcat7-7.0.52/java/org/apache/catalina/session/StandardSession.java0000644000175100017510000016467012271471332025322 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.AccessController; import java.security.Principal; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Manager; import org.apache.catalina.Session; import org.apache.catalina.SessionEvent; import org.apache.catalina.SessionListener; import org.apache.catalina.core.StandardContext; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.security.SecurityUtil; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Standard implementation of the Session interface. This object is * serializable, so that it can be stored in persistent storage or transferred * to a different JVM for distributable session support. *

    * IMPLEMENTATION NOTE: An instance of this class represents both the * internal (Session) and application level (HttpSession) view of the session. * However, because the class itself is not declared public, Java logic outside * of the org.apache.catalina.session package cannot cast an * HttpSession view of this instance back to a Session view. *

    * IMPLEMENTATION NOTE: If you add fields to this class, you must * make sure that you carry them over in the read/writeObject methods so * that this class is properly serialized. * * @author Craig R. McClanahan * @author Sean Legassick * @author Jon S. Stevens */ public class StandardSession implements HttpSession, Session, Serializable { private static final long serialVersionUID = 1L; protected static final boolean STRICT_SERVLET_COMPLIANCE; protected static final boolean ACTIVITY_CHECK; protected static final boolean LAST_ACCESS_AT_START; static { STRICT_SERVLET_COMPLIANCE = Globals.STRICT_SERVLET_COMPLIANCE; String activityCheck = System.getProperty( "org.apache.catalina.session.StandardSession.ACTIVITY_CHECK"); if (activityCheck == null) { ACTIVITY_CHECK = STRICT_SERVLET_COMPLIANCE; } else { ACTIVITY_CHECK = Boolean.valueOf(activityCheck).booleanValue(); } String lastAccessAtStart = System.getProperty( "org.apache.catalina.session.StandardSession.LAST_ACCESS_AT_START"); if (lastAccessAtStart == null) { LAST_ACCESS_AT_START = STRICT_SERVLET_COMPLIANCE; } else { LAST_ACCESS_AT_START = Boolean.valueOf(lastAccessAtStart).booleanValue(); } } // ----------------------------------------------------------- Constructors /** * Construct a new Session associated with the specified Manager. * * @param manager The manager with which this Session is associated */ public StandardSession(Manager manager) { super(); this.manager = manager; // Initialize access count if (ACTIVITY_CHECK) { accessCount = new AtomicInteger(); } } // ----------------------------------------------------- Instance Variables /** * Type array. */ protected static final String EMPTY_ARRAY[] = new String[0]; /** * The dummy attribute value serialized when a NotSerializableException is * encountered in writeObject(). */ protected static final String NOT_SERIALIZED = "___NOT_SERIALIZABLE_EXCEPTION___"; /** * The collection of user data attributes associated with this Session. */ protected Map attributes = new ConcurrentHashMap(); /** * The authentication type used to authenticate our cached Principal, * if any. NOTE: This value is not included in the serialized * version of this object. */ protected transient String authType = null; /** * The time this session was created, in milliseconds since midnight, * January 1, 1970 GMT. */ protected long creationTime = 0L; /** * Set of attribute names which are not allowed to be persisted. */ protected static final String[] excludedAttributes = { Globals.SUBJECT_ATTR, Globals.GSS_CREDENTIAL_ATTR }; /** * We are currently processing a session expiration, so bypass * certain IllegalStateException tests. NOTE: This value is not * included in the serialized version of this object. */ protected transient volatile boolean expiring = false; /** * The facade associated with this session. NOTE: This value is not * included in the serialized version of this object. */ protected transient StandardSessionFacade facade = null; /** * The session identifier of this Session. */ protected String id = null; /** * Descriptive information describing this Session implementation. */ protected static final String info = "StandardSession/1.0"; /** * The last accessed time for this Session. */ protected volatile long lastAccessedTime = creationTime; /** * The session event listeners for this Session. */ protected transient ArrayList listeners = new ArrayList(); /** * The Manager with which this Session is associated. */ protected transient Manager manager = null; /** * The maximum time interval, in seconds, between client requests before * the servlet container may invalidate this session. A negative time * indicates that the session should never time out. */ protected int maxInactiveInterval = -1; /** * Flag indicating whether this session is new or not. */ protected boolean isNew = false; /** * Flag indicating whether this session is valid or not. */ protected volatile boolean isValid = false; /** * Internal notes associated with this session by Catalina components * and event listeners. IMPLEMENTATION NOTE: This object is * not saved and restored across session serializations! */ protected transient Map notes = new Hashtable(); /** * The authenticated Principal associated with this session, if any. * IMPLEMENTATION NOTE: This object is not saved and * restored across session serializations! */ protected transient Principal principal = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The HTTP session context associated with this session. */ @Deprecated protected static volatile javax.servlet.http.HttpSessionContext sessionContext = null; /** * The property change support for this component. NOTE: This value * is not included in the serialized version of this object. */ protected transient PropertyChangeSupport support = new PropertyChangeSupport(this); /** * The current accessed time for this session. */ protected volatile long thisAccessedTime = creationTime; /** * The access count for this session. */ protected transient AtomicInteger accessCount = null; // ----------------------------------------------------- Session Properties /** * Return the authentication type used to authenticate our cached * Principal, if any. */ @Override public String getAuthType() { return (this.authType); } /** * Set the authentication type used to authenticate our cached * Principal, if any. * * @param authType The new cached authentication type */ @Override public void setAuthType(String authType) { String oldAuthType = this.authType; this.authType = authType; support.firePropertyChange("authType", oldAuthType, this.authType); } /** * Set the creation time for this session. This method is called by the * Manager when an existing Session instance is reused. * * @param time The new creation time */ @Override public void setCreationTime(long time) { this.creationTime = time; this.lastAccessedTime = time; this.thisAccessedTime = time; } /** * Return the session identifier for this session. */ @Override public String getId() { return (this.id); } /** * Return the session identifier for this session. */ @Override public String getIdInternal() { return (this.id); } /** * Set the session identifier for this session. * * @param id The new session identifier */ @Override public void setId(String id) { setId(id, true); } /** * {@inheritDoc} */ @Override public void setId(String id, boolean notify) { if ((this.id != null) && (manager != null)) manager.remove(this); this.id = id; if (manager != null) manager.add(this); if (notify) { tellNew(); } } /** * Inform the listeners about the new session. * */ public void tellNew() { // Notify interested session event listeners fireSessionEvent(Session.SESSION_CREATED_EVENT, null); // Notify interested application event listeners Context context = (Context) manager.getContainer(); Object listeners[] = context.getApplicationLifecycleListeners(); if (listeners != null) { HttpSessionEvent event = new HttpSessionEvent(getSession()); for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof HttpSessionListener)) continue; HttpSessionListener listener = (HttpSessionListener) listeners[i]; try { context.fireContainerEvent("beforeSessionCreated", listener); listener.sessionCreated(event); context.fireContainerEvent("afterSessionCreated", listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); try { context.fireContainerEvent("afterSessionCreated", listener); } catch (Exception e) { // Ignore } manager.getContainer().getLogger().error (sm.getString("standardSession.sessionEvent"), t); } } } } /** * Return descriptive information about this Session implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return the last time the client sent a request associated with this * session, as the number of milliseconds since midnight, January 1, 1970 * GMT. Actions that your application takes, such as getting or setting * a value associated with the session, do not affect the access time. * This one gets updated whenever a request starts. */ @Override public long getThisAccessedTime() { if (!isValidInternal()) { throw new IllegalStateException (sm.getString("standardSession.getThisAccessedTime.ise")); } return (this.thisAccessedTime); } /** * Return the last client access time without invalidation check * @see #getThisAccessedTime() */ @Override public long getThisAccessedTimeInternal() { return (this.thisAccessedTime); } /** * Return the last time the client sent a request associated with this * session, as the number of milliseconds since midnight, January 1, 1970 * GMT. Actions that your application takes, such as getting or setting * a value associated with the session, do not affect the access time. * This one gets updated whenever a request finishes. */ @Override public long getLastAccessedTime() { if (!isValidInternal()) { throw new IllegalStateException (sm.getString("standardSession.getLastAccessedTime.ise")); } return (this.lastAccessedTime); } /** * Return the last client access time without invalidation check * @see #getLastAccessedTime() */ @Override public long getLastAccessedTimeInternal() { return (this.lastAccessedTime); } /** * Return the Manager within which this Session is valid. */ @Override public Manager getManager() { return (this.manager); } /** * Set the Manager within which this Session is valid. * * @param manager The new Manager */ @Override public void setManager(Manager manager) { this.manager = manager; } /** * Return the maximum time interval, in seconds, between client requests * before the servlet container will invalidate the session. A negative * time indicates that the session should never time out. */ @Override public int getMaxInactiveInterval() { return (this.maxInactiveInterval); } /** * Set the maximum time interval, in seconds, between client requests * before the servlet container will invalidate the session. A zero or * negative time indicates that the session should never time out. * * @param interval The new maximum interval */ @Override public void setMaxInactiveInterval(int interval) { this.maxInactiveInterval = interval; } /** * Set the isNew flag for this session. * * @param isNew The new value for the isNew flag */ @Override public void setNew(boolean isNew) { this.isNew = isNew; } /** * Return the authenticated Principal that is associated with this Session. * This provides an Authenticator with a means to cache a * previously authenticated Principal, and avoid potentially expensive * Realm.authenticate() calls on every request. If there * is no current associated Principal, return null. */ @Override public Principal getPrincipal() { return (this.principal); } /** * Set the authenticated Principal that is associated with this Session. * This provides an Authenticator with a means to cache a * previously authenticated Principal, and avoid potentially expensive * Realm.authenticate() calls on every request. * * @param principal The new Principal, or null if none */ @Override public void setPrincipal(Principal principal) { Principal oldPrincipal = this.principal; this.principal = principal; support.firePropertyChange("principal", oldPrincipal, this.principal); } /** * Return the HttpSession for which this object * is the facade. */ @Override public HttpSession getSession() { if (facade == null){ if (SecurityUtil.isPackageProtectionEnabled()){ final StandardSession fsession = this; facade = AccessController.doPrivileged( new PrivilegedAction(){ @Override public StandardSessionFacade run(){ return new StandardSessionFacade(fsession); } }); } else { facade = new StandardSessionFacade(this); } } return (facade); } /** * Return the isValid flag for this session. */ @Override public boolean isValid() { if (!this.isValid) { return false; } if (this.expiring) { return true; } if (ACTIVITY_CHECK && accessCount.get() > 0) { return true; } if (maxInactiveInterval > 0) { long timeNow = System.currentTimeMillis(); int timeIdle; if (LAST_ACCESS_AT_START) { timeIdle = (int) ((timeNow - lastAccessedTime) / 1000L); } else { timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L); } if (timeIdle >= maxInactiveInterval) { expire(true); } } return this.isValid; } /** * Set the isValid flag for this session. * * @param isValid The new value for the isValid flag */ @Override public void setValid(boolean isValid) { this.isValid = isValid; } // ------------------------------------------------- Session Public Methods /** * Update the accessed time information for this session. This method * should be called by the context when a request comes in for a particular * session, even if the application does not reference it. */ @Override public void access() { this.thisAccessedTime = System.currentTimeMillis(); if (ACTIVITY_CHECK) { accessCount.incrementAndGet(); } } /** * End the access. */ @Override public void endAccess() { isNew = false; /** * The servlet spec mandates to ignore request handling time * in lastAccessedTime. */ if (LAST_ACCESS_AT_START) { this.lastAccessedTime = this.thisAccessedTime; this.thisAccessedTime = System.currentTimeMillis(); } else { this.thisAccessedTime = System.currentTimeMillis(); this.lastAccessedTime = this.thisAccessedTime; } if (ACTIVITY_CHECK) { accessCount.decrementAndGet(); } } /** * Add a session event listener to this component. */ @Override public void addSessionListener(SessionListener listener) { listeners.add(listener); } /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. */ @Override public void expire() { expire(true); } /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. * * @param notify Should we notify listeners about the demise of * this session? */ public void expire(boolean notify) { // Check to see if session has already been invalidated. // Do not check expiring at this point as expire should not return until // isValid is false if (!isValid) return; synchronized (this) { // Check again, now we are inside the sync so this code only runs once // Double check locking - isValid needs to be volatile if (!isValid) return; if (manager == null) return; // Mark this session as "being expired" expiring = true; // Notify interested application event listeners // FIXME - Assumes we call listeners in reverse order Context context = (Context) manager.getContainer(); // The call to expire() may not have been triggered by the webapp. // Make sure the webapp's class loader is set when calling the // listeners ClassLoader oldTccl = null; if (context.getLoader() != null && context.getLoader().getClassLoader() != null) { oldTccl = Thread.currentThread().getContextClassLoader(); if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( context.getLoader().getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader( context.getLoader().getClassLoader()); } } try { Object listeners[] = context.getApplicationLifecycleListeners(); if (notify && (listeners != null)) { HttpSessionEvent event = new HttpSessionEvent(getSession()); for (int i = 0; i < listeners.length; i++) { int j = (listeners.length - 1) - i; if (!(listeners[j] instanceof HttpSessionListener)) continue; HttpSessionListener listener = (HttpSessionListener) listeners[j]; try { context.fireContainerEvent("beforeSessionDestroyed", listener); listener.sessionDestroyed(event); context.fireContainerEvent("afterSessionDestroyed", listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); try { context.fireContainerEvent( "afterSessionDestroyed", listener); } catch (Exception e) { // Ignore } manager.getContainer().getLogger().error (sm.getString("standardSession.sessionEvent"), t); } } } } finally { if (oldTccl != null) { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl(oldTccl); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(oldTccl); } } } if (ACTIVITY_CHECK) { accessCount.set(0); } // Remove this session from our manager's active sessions manager.remove(this, true); // Notify interested session event listeners if (notify) { fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null); } // Call the logout method if (principal instanceof GenericPrincipal) { GenericPrincipal gp = (GenericPrincipal) principal; try { gp.logout(); } catch (Exception e) { manager.getContainer().getLogger().error( sm.getString("standardSession.logoutfail"), e); } } // We have completed expire of this session setValid(false); expiring = false; // Unbind any objects associated with this session String keys[] = keys(); for (int i = 0; i < keys.length; i++) removeAttributeInternal(keys[i], notify); } } /** * Perform the internal processing required to passivate * this session. */ public void passivate() { // Notify interested session event listeners fireSessionEvent(Session.SESSION_PASSIVATED_EVENT, null); // Notify ActivationListeners HttpSessionEvent event = null; String keys[] = keys(); for (int i = 0; i < keys.length; i++) { Object attribute = attributes.get(keys[i]); if (attribute instanceof HttpSessionActivationListener) { if (event == null) event = new HttpSessionEvent(getSession()); try { ((HttpSessionActivationListener)attribute) .sessionWillPassivate(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); manager.getContainer().getLogger().error (sm.getString("standardSession.attributeEvent"), t); } } } } /** * Perform internal processing required to activate this * session. */ public void activate() { // Initialize access count if (ACTIVITY_CHECK) { accessCount = new AtomicInteger(); } // Notify interested session event listeners fireSessionEvent(Session.SESSION_ACTIVATED_EVENT, null); // Notify ActivationListeners HttpSessionEvent event = null; String keys[] = keys(); for (int i = 0; i < keys.length; i++) { Object attribute = attributes.get(keys[i]); if (attribute instanceof HttpSessionActivationListener) { if (event == null) event = new HttpSessionEvent(getSession()); try { ((HttpSessionActivationListener)attribute) .sessionDidActivate(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); manager.getContainer().getLogger().error (sm.getString("standardSession.attributeEvent"), t); } } } } /** * Return the object bound with the specified name to the internal notes * for this session, or null if no such binding exists. * * @param name Name of the note to be returned */ @Override public Object getNote(String name) { return (notes.get(name)); } /** * Return an Iterator containing the String names of all notes bindings * that exist for this session. */ @Override public Iterator getNoteNames() { return (notes.keySet().iterator()); } /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ @Override public void recycle() { // Reset the instance variables associated with this Session attributes.clear(); setAuthType(null); creationTime = 0L; expiring = false; id = null; lastAccessedTime = 0L; maxInactiveInterval = -1; notes.clear(); setPrincipal(null); isNew = false; isValid = false; manager = null; } /** * Remove any object bound to the specified name in the internal notes * for this session. * * @param name Name of the note to be removed */ @Override public void removeNote(String name) { notes.remove(name); } /** * Remove a session event listener from this component. */ @Override public void removeSessionListener(SessionListener listener) { listeners.remove(listener); } /** * Bind an object to a specified name in the internal notes associated * with this session, replacing any existing binding for this name. * * @param name Name to which the object should be bound * @param value Object to be bound to the specified name */ @Override public void setNote(String name, Object value) { notes.put(name, value); } /** * Return a string representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("StandardSession["); sb.append(id); sb.append("]"); return (sb.toString()); } // ------------------------------------------------ Session Package Methods /** * Read a serialized version of the contents of this session object from * the specified object input stream, without requiring that the * StandardSession itself have been serialized. * * @param stream The object input stream to read from * * @exception ClassNotFoundException if an unknown class is specified * @exception IOException if an input/output error occurs */ public void readObjectData(ObjectInputStream stream) throws ClassNotFoundException, IOException { readObject(stream); } /** * Write a serialized version of the contents of this session object to * the specified object output stream, without requiring that the * StandardSession itself have been serialized. * * @param stream The object output stream to write to * * @exception IOException if an input/output error occurs */ public void writeObjectData(ObjectOutputStream stream) throws IOException { writeObject(stream); } // ------------------------------------------------- HttpSession Properties /** * Return the time when this session was created, in milliseconds since * midnight, January 1, 1970 GMT. * * @exception IllegalStateException if this method is called on an * invalidated session */ @Override public long getCreationTime() { if (!isValidInternal()) throw new IllegalStateException (sm.getString("standardSession.getCreationTime.ise")); return (this.creationTime); } /** * Return the time when this session was created, in milliseconds since * midnight, January 1, 1970 GMT, bypassing the session validation checks. */ @Override public long getCreationTimeInternal() { return this.creationTime; } /** * Return the ServletContext to which this session belongs. */ @Override public ServletContext getServletContext() { if (manager == null) return (null); Context context = (Context) manager.getContainer(); if (context == null) return (null); else return (context.getServletContext()); } /** * Return the session context with which this session is associated. * * @deprecated As of Version 2.1, this method is deprecated and has no * replacement. It will be removed in a future version of the * Java Servlet API. */ @Override @Deprecated public javax.servlet.http.HttpSessionContext getSessionContext() { if (sessionContext == null) sessionContext = new StandardSessionContext(); return (sessionContext); } // ----------------------------------------------HttpSession Public Methods /** * Return the object bound with the specified name in this session, or * null if no object is bound with that name. * * @param name Name of the attribute to be returned * * @exception IllegalStateException if this method is called on an * invalidated session */ @Override public Object getAttribute(String name) { if (!isValidInternal()) throw new IllegalStateException (sm.getString("standardSession.getAttribute.ise")); if (name == null) return null; return (attributes.get(name)); } /** * Return an Enumeration of String objects * containing the names of the objects bound to this session. * * @exception IllegalStateException if this method is called on an * invalidated session */ @Override public Enumeration getAttributeNames() { if (!isValidInternal()) throw new IllegalStateException (sm.getString("standardSession.getAttributeNames.ise")); Set names = new HashSet(); names.addAll(attributes.keySet()); return Collections.enumeration(names); } /** * Return the object bound with the specified name in this session, or * null if no object is bound with that name. * * @param name Name of the value to be returned * * @exception IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * getAttribute() */ @Override @Deprecated public Object getValue(String name) { return (getAttribute(name)); } /** * Return the set of names of objects bound to this session. If there * are no such objects, a zero-length array is returned. * * @exception IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * getAttributeNames() */ @Override @Deprecated public String[] getValueNames() { if (!isValidInternal()) throw new IllegalStateException (sm.getString("standardSession.getValueNames.ise")); return (keys()); } /** * Invalidates this session and unbinds any objects bound to it. * * @exception IllegalStateException if this method is called on * an invalidated session */ @Override public void invalidate() { if (!isValidInternal()) throw new IllegalStateException (sm.getString("standardSession.invalidate.ise")); // Cause this session to expire expire(); } /** * Return true if the client does not yet know about the * session, or if the client chooses not to join the session. For * example, if the server used only cookie-based sessions, and the client * has disabled the use of cookies, then a session would be new on each * request. * * @exception IllegalStateException if this method is called on an * invalidated session */ @Override public boolean isNew() { if (!isValidInternal()) throw new IllegalStateException (sm.getString("standardSession.isNew.ise")); return (this.isNew); } /** * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is * replaced. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueBound() on the object. * * @param name Name to which the object is bound, cannot be null * @param value Object to be bound, cannot be null * * @exception IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * setAttribute() */ @Override @Deprecated public void putValue(String name, Object value) { setAttribute(name, value); } /** * Remove the object bound with the specified name from this session. If * the session does not have an object bound with this name, this method * does nothing. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueUnbound() on the object. * * @param name Name of the object to remove from this session. * * @exception IllegalStateException if this method is called on an * invalidated session */ @Override public void removeAttribute(String name) { removeAttribute(name, true); } /** * Remove the object bound with the specified name from this session. If * the session does not have an object bound with this name, this method * does nothing. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueUnbound() on the object. * * @param name Name of the object to remove from this session. * @param notify Should we notify interested listeners that this * attribute is being removed? * * @exception IllegalStateException if this method is called on an * invalidated session */ public void removeAttribute(String name, boolean notify) { // Validate our current state if (!isValidInternal()) throw new IllegalStateException (sm.getString("standardSession.removeAttribute.ise")); removeAttributeInternal(name, notify); } /** * Remove the object bound with the specified name from this session. If * the session does not have an object bound with this name, this method * does nothing. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueUnbound() on the object. * * @param name Name of the object to remove from this session. * * @exception IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * removeAttribute() */ @Override @Deprecated public void removeValue(String name) { removeAttribute(name); } /** * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is * replaced. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueBound() on the object. * * @param name Name to which the object is bound, cannot be null * @param value Object to be bound, cannot be null * * @exception IllegalArgumentException if an attempt is made to add a * non-serializable object in an environment marked distributable. * @exception IllegalStateException if this method is called on an * invalidated session */ @Override public void setAttribute(String name, Object value) { setAttribute(name,value,true); } /** * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is * replaced. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueBound() on the object. * * @param name Name to which the object is bound, cannot be null * @param value Object to be bound, cannot be null * @param notify whether to notify session listeners * @exception IllegalArgumentException if an attempt is made to add a * non-serializable object in an environment marked distributable. * @exception IllegalStateException if this method is called on an * invalidated session */ public void setAttribute(String name, Object value, boolean notify) { // Name cannot be null if (name == null) throw new IllegalArgumentException (sm.getString("standardSession.setAttribute.namenull")); // Null value is the same as removeAttribute() if (value == null) { removeAttribute(name); return; } // Validate our current state if (!isValidInternal()) throw new IllegalStateException(sm.getString( "standardSession.setAttribute.ise", getIdInternal())); if ((manager != null) && manager.getDistributable() && !isAttributeDistributable(name, value)) throw new IllegalArgumentException (sm.getString("standardSession.setAttribute.iae", name)); // Construct an event with the new value HttpSessionBindingEvent event = null; // Call the valueBound() method if necessary if (notify && value instanceof HttpSessionBindingListener) { // Don't call any notification if replacing with the same value Object oldValue = attributes.get(name); if (value != oldValue) { event = new HttpSessionBindingEvent(getSession(), name, value); try { ((HttpSessionBindingListener) value).valueBound(event); } catch (Throwable t){ manager.getContainer().getLogger().error (sm.getString("standardSession.bindingEvent"), t); } } } // Replace or add this attribute Object unbound = attributes.put(name, value); // Call the valueUnbound() method if necessary if (notify && (unbound != null) && (unbound != value) && (unbound instanceof HttpSessionBindingListener)) { try { ((HttpSessionBindingListener) unbound).valueUnbound (new HttpSessionBindingEvent(getSession(), name)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); manager.getContainer().getLogger().error (sm.getString("standardSession.bindingEvent"), t); } } if ( !notify ) return; // Notify interested application event listeners Context context = (Context) manager.getContainer(); Object listeners[] = context.getApplicationEventListeners(); if (listeners == null) return; for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof HttpSessionAttributeListener)) continue; HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i]; try { if (unbound != null) { context.fireContainerEvent("beforeSessionAttributeReplaced", listener); if (event == null) { event = new HttpSessionBindingEvent (getSession(), name, unbound); } listener.attributeReplaced(event); context.fireContainerEvent("afterSessionAttributeReplaced", listener); } else { context.fireContainerEvent("beforeSessionAttributeAdded", listener); if (event == null) { event = new HttpSessionBindingEvent (getSession(), name, value); } listener.attributeAdded(event); context.fireContainerEvent("afterSessionAttributeAdded", listener); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); try { if (unbound != null) { context.fireContainerEvent( "afterSessionAttributeReplaced", listener); } else { context.fireContainerEvent("afterSessionAttributeAdded", listener); } } catch (Exception e) { // Ignore } manager.getContainer().getLogger().error (sm.getString("standardSession.attributeEvent"), t); } } } // ------------------------------------------ HttpSession Protected Methods /** * Return the isValid flag for this session without any expiration * check. */ protected boolean isValidInternal() { return this.isValid; } /** * Check whether the Object can be distributed. This implementation * simply checks for serializability. Derived classes might use other * distribution technology not based on serialization and can extend * this check. * @param name The name of the attribute to check * @param value The value of the attribute to check * @return true if the attribute is distributable, false otherwise */ protected boolean isAttributeDistributable(String name, Object value) { return value instanceof Serializable; } /** * Read a serialized version of this session object from the specified * object input stream. *

    * IMPLEMENTATION NOTE: The reference to the owning Manager * is not restored by this method, and must be set explicitly. * * @param stream The input stream to read from * * @exception ClassNotFoundException if an unknown class is specified * @exception IOException if an input/output error occurs */ protected void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { // Deserialize the scalar instance variables (except Manager) authType = null; // Transient only creationTime = ((Long) stream.readObject()).longValue(); lastAccessedTime = ((Long) stream.readObject()).longValue(); maxInactiveInterval = ((Integer) stream.readObject()).intValue(); isNew = ((Boolean) stream.readObject()).booleanValue(); isValid = ((Boolean) stream.readObject()).booleanValue(); thisAccessedTime = ((Long) stream.readObject()).longValue(); principal = null; // Transient only // setId((String) stream.readObject()); id = (String) stream.readObject(); if (manager.getContainer().getLogger().isDebugEnabled()) manager.getContainer().getLogger().debug ("readObject() loading session " + id); // Deserialize the attribute count and attribute values if (attributes == null) attributes = new ConcurrentHashMap(); int n = ((Integer) stream.readObject()).intValue(); boolean isValidSave = isValid; isValid = true; for (int i = 0; i < n; i++) { String name = (String) stream.readObject(); Object value = stream.readObject(); if ((value instanceof String) && (value.equals(NOT_SERIALIZED))) continue; if (manager.getContainer().getLogger().isDebugEnabled()) manager.getContainer().getLogger().debug(" loading attribute '" + name + "' with value '" + value + "'"); attributes.put(name, value); } isValid = isValidSave; if (listeners == null) { listeners = new ArrayList(); } if (notes == null) { notes = new Hashtable(); } } /** * Write a serialized version of this session object to the specified * object output stream. *

    * IMPLEMENTATION NOTE: The owning Manager will not be stored * in the serialized representation of this Session. After calling * readObject(), you must set the associated Manager * explicitly. *

    * IMPLEMENTATION NOTE: Any attribute that is not Serializable * will be unbound from the session, with appropriate actions if it * implements HttpSessionBindingListener. If you do not want any such * attributes, be sure the distributable property of the * associated Manager is set to true. * * @param stream The output stream to write to * * @exception IOException if an input/output error occurs */ protected void writeObject(ObjectOutputStream stream) throws IOException { // Write the scalar instance variables (except Manager) stream.writeObject(Long.valueOf(creationTime)); stream.writeObject(Long.valueOf(lastAccessedTime)); stream.writeObject(Integer.valueOf(maxInactiveInterval)); stream.writeObject(Boolean.valueOf(isNew)); stream.writeObject(Boolean.valueOf(isValid)); stream.writeObject(Long.valueOf(thisAccessedTime)); stream.writeObject(id); if (manager.getContainer().getLogger().isDebugEnabled()) manager.getContainer().getLogger().debug ("writeObject() storing session " + id); // Accumulate the names of serializable and non-serializable attributes String keys[] = keys(); ArrayList saveNames = new ArrayList(); ArrayList saveValues = new ArrayList(); for (int i = 0; i < keys.length; i++) { Object value = attributes.get(keys[i]); if (value == null) continue; else if ( (value instanceof Serializable) && (!exclude(keys[i]) )) { saveNames.add(keys[i]); saveValues.add(value); } else { removeAttributeInternal(keys[i], true); } } // Serialize the attribute count and the Serializable attributes int n = saveNames.size(); stream.writeObject(Integer.valueOf(n)); for (int i = 0; i < n; i++) { stream.writeObject(saveNames.get(i)); try { stream.writeObject(saveValues.get(i)); if (manager.getContainer().getLogger().isDebugEnabled()) manager.getContainer().getLogger().debug (" storing attribute '" + saveNames.get(i) + "' with value '" + saveValues.get(i) + "'"); } catch (NotSerializableException e) { manager.getContainer().getLogger().warn (sm.getString("standardSession.notSerializable", saveNames.get(i), id), e); stream.writeObject(NOT_SERIALIZED); if (manager.getContainer().getLogger().isDebugEnabled()) manager.getContainer().getLogger().debug (" storing attribute '" + saveNames.get(i) + "' with value NOT_SERIALIZED"); } } } /** * Exclude standard attributes that cannot be serialized. * @param name the attribute's name */ protected boolean exclude(String name){ for (int i = 0; i < excludedAttributes.length; i++) { if (name.equalsIgnoreCase(excludedAttributes[i])) return true; } return false; } // ------------------------------------------------------ Protected Methods /** * Fire container events if the Context implementation is the * org.apache.catalina.core.StandardContext. * * @param context Context for which to fire events * @param type Event type * @param data Event data * * @exception Exception occurred during event firing * * @deprecated No longer necessary since {@link StandardContext} implements * the {@link org.apache.catalina.Container} interface. * */ @Deprecated protected void fireContainerEvent(Context context, String type, Object data) throws Exception { if (context instanceof StandardContext) { ((StandardContext) context).fireContainerEvent(type, data); } } /** * Notify all session event listeners that a particular event has * occurred for this Session. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param data Event data */ public void fireSessionEvent(String type, Object data) { if (listeners.size() < 1) return; SessionEvent event = new SessionEvent(this, type, data); SessionListener list[] = new SessionListener[0]; synchronized (listeners) { list = listeners.toArray(list); } for (int i = 0; i < list.length; i++){ (list[i]).sessionEvent(event); } } /** * Return the names of all currently defined session attributes * as an array of Strings. If there are no defined attributes, a * zero-length array is returned. */ protected String[] keys() { return attributes.keySet().toArray(EMPTY_ARRAY); } /** * Remove the object bound with the specified name from this session. If * the session does not have an object bound with this name, this method * does nothing. *

    * After this method executes, and if the object implements * HttpSessionBindingListener, the container calls * valueUnbound() on the object. * * @param name Name of the object to remove from this session. * @param notify Should we notify interested listeners that this * attribute is being removed? */ protected void removeAttributeInternal(String name, boolean notify) { // Avoid NPE if (name == null) return; // Remove this attribute from our collection Object value = attributes.remove(name); // Do we need to do valueUnbound() and attributeRemoved() notification? if (!notify || (value == null)) { return; } // Call the valueUnbound() method if necessary HttpSessionBindingEvent event = null; if (value instanceof HttpSessionBindingListener) { event = new HttpSessionBindingEvent(getSession(), name, value); ((HttpSessionBindingListener) value).valueUnbound(event); } // Notify interested application event listeners Context context = (Context) manager.getContainer(); Object listeners[] = context.getApplicationEventListeners(); if (listeners == null) return; for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof HttpSessionAttributeListener)) continue; HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i]; try { context.fireContainerEvent("beforeSessionAttributeRemoved", listener); if (event == null) { event = new HttpSessionBindingEvent (getSession(), name, value); } listener.attributeRemoved(event); context.fireContainerEvent("afterSessionAttributeRemoved", listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); try { context.fireContainerEvent("afterSessionAttributeRemoved", listener); } catch (Exception e) { // Ignore } manager.getContainer().getLogger().error (sm.getString("standardSession.attributeEvent"), t); } } } private static class PrivilegedSetTccl implements PrivilegedAction { private ClassLoader cl; PrivilegedSetTccl(ClassLoader cl) { this.cl = cl; } @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); return null; } } } // ------------------------------------------------------------ Protected Class /** * This class is a dummy implementation of the HttpSessionContext * interface, to conform to the requirement that such an object be returned * when HttpSession.getSessionContext() is called. * * @author Craig R. McClanahan * * @deprecated As of Java Servlet API 2.1 with no replacement. The * interface will be removed in a future version of this API. */ @Deprecated final class StandardSessionContext implements javax.servlet.http.HttpSessionContext { private static final List emptyString = Collections.emptyList(); /** * Return the session identifiers of all sessions defined * within this context. * * @deprecated As of Java Servlet API 2.1 with no replacement. * This method must return an empty Enumeration * and will be removed in a future version of the API. */ @Override @Deprecated public Enumeration getIds() { return Collections.enumeration(emptyString); } /** * Return the HttpSession associated with the * specified session identifier. * * @param id Session identifier for which to look up a session * * @deprecated As of Java Servlet API 2.1 with no replacement. * This method must return null and will be removed in a * future version of the API. */ @Override @Deprecated public HttpSession getSession(String id) { return (null); } } tomcat7-7.0.52/java/org/apache/catalina/session/JDBCStore.java0000644000175100017510000010577212271471332023733 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.sql.Connection; import java.sql.Driver; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import org.apache.catalina.Container; import org.apache.catalina.LifecycleException; import org.apache.catalina.Loader; import org.apache.catalina.Session; import org.apache.catalina.util.CustomObjectInputStream; import org.apache.tomcat.util.ExceptionUtils; /** * Implementation of the Store interface that stores * serialized session objects in a database. Sessions that are * saved are still subject to being expired based on inactivity. * * @author Bip Thelin */ public class JDBCStore extends StoreBase { /** * The descriptive information about this implementation. */ protected static final String info = "JDBCStore/1.0"; /** * Context name associated with this Store */ private String name = null; /** * Name to register for this Store, used for logging. */ protected static String storeName = "JDBCStore"; /** * Name to register for the background thread. */ protected String threadName = "JDBCStore"; /** * The connection username to use when trying to connect to the database. */ protected String connectionName = null; /** * The connection URL to use when trying to connect to the database. */ protected String connectionPassword = null; /** * Connection string to use when connecting to the DB. */ protected String connectionURL = null; /** * The database connection. */ private Connection dbConnection = null; /** * Instance of the JDBC Driver class we use as a connection factory. */ protected Driver driver = null; /** * Driver to use. */ protected String driverName = null; /** * name of the JNDI resource */ protected String dataSourceName = null; /** * DataSource to use */ protected DataSource dataSource = null; // ------------------------------------------------------------- Table & cols /** * Table to use. */ protected String sessionTable = "tomcat$sessions"; /** * Column to use for /Engine/Host/Context name */ protected String sessionAppCol = "app"; /** * Id column to use. */ protected String sessionIdCol = "id"; /** * Data column to use. */ protected String sessionDataCol = "data"; /** * Is Valid column to use. */ protected String sessionValidCol = "valid"; /** * Max Inactive column to use. */ protected String sessionMaxInactiveCol = "maxinactive"; /** * Last Accessed column to use. */ protected String sessionLastAccessedCol = "lastaccess"; // ------------------------------------------------------------- SQL Variables /** * Variable to hold the getSize() prepared statement. */ protected PreparedStatement preparedSizeSql = null; /** * Variable to hold the keys() prepared statement. */ protected PreparedStatement preparedKeysSql = null; /** * Variable to hold the save() prepared statement. */ protected PreparedStatement preparedSaveSql = null; /** * Variable to hold the clear() prepared statement. */ protected PreparedStatement preparedClearSql = null; /** * Variable to hold the remove() prepared statement. */ protected PreparedStatement preparedRemoveSql = null; /** * Variable to hold the load() prepared statement. */ protected PreparedStatement preparedLoadSql = null; // ------------------------------------------------------------- Properties /** * Return the info for this Store. */ @Override public String getInfo() { return (info); } /** * Return the name for this instance (built from container name) */ public String getName() { if (name == null) { Container container = manager.getContainer(); String contextName = container.getName(); if (!contextName.startsWith("/")) { contextName = "/" + contextName; } String hostName = ""; String engineName = ""; if (container.getParent() != null) { Container host = container.getParent(); hostName = host.getName(); if (host.getParent() != null) { engineName = host.getParent().getName(); } } name = "/" + engineName + "/" + hostName + contextName; } return name; } /** * Return the thread name for this Store. */ public String getThreadName() { return (threadName); } /** * Return the name for this Store, used for logging. */ @Override public String getStoreName() { return (storeName); } /** * Set the driver for this Store. * * @param driverName The new driver */ public void setDriverName(String driverName) { String oldDriverName = this.driverName; this.driverName = driverName; support.firePropertyChange("driverName", oldDriverName, this.driverName); this.driverName = driverName; } /** * Return the driver for this Store. */ public String getDriverName() { return (this.driverName); } /** * Return the username to use to connect to the database. * */ public String getConnectionName() { return connectionName; } /** * Set the username to use to connect to the database. * * @param connectionName Username */ public void setConnectionName(String connectionName) { this.connectionName = connectionName; } /** * Return the password to use to connect to the database. * */ public String getConnectionPassword() { return connectionPassword; } /** * Set the password to use to connect to the database. * * @param connectionPassword User password */ public void setConnectionPassword(String connectionPassword) { this.connectionPassword = connectionPassword; } /** * Set the Connection URL for this Store. * * @param connectionURL The new Connection URL */ public void setConnectionURL(String connectionURL) { String oldConnString = this.connectionURL; this.connectionURL = connectionURL; support.firePropertyChange("connectionURL", oldConnString, this.connectionURL); } /** * Return the Connection URL for this Store. */ public String getConnectionURL() { return (this.connectionURL); } /** * Set the table for this Store. * * @param sessionTable The new table */ public void setSessionTable(String sessionTable) { String oldSessionTable = this.sessionTable; this.sessionTable = sessionTable; support.firePropertyChange("sessionTable", oldSessionTable, this.sessionTable); } /** * Return the table for this Store. */ public String getSessionTable() { return (this.sessionTable); } /** * Set the App column for the table. * * @param sessionAppCol the column name */ public void setSessionAppCol(String sessionAppCol) { String oldSessionAppCol = this.sessionAppCol; this.sessionAppCol = sessionAppCol; support.firePropertyChange("sessionAppCol", oldSessionAppCol, this.sessionAppCol); } /** * Return the web application name column for the table. */ public String getSessionAppCol() { return (this.sessionAppCol); } /** * Set the Id column for the table. * * @param sessionIdCol the column name */ public void setSessionIdCol(String sessionIdCol) { String oldSessionIdCol = this.sessionIdCol; this.sessionIdCol = sessionIdCol; support.firePropertyChange("sessionIdCol", oldSessionIdCol, this.sessionIdCol); } /** * Return the Id column for the table. */ public String getSessionIdCol() { return (this.sessionIdCol); } /** * Set the Data column for the table * * @param sessionDataCol the column name */ public void setSessionDataCol(String sessionDataCol) { String oldSessionDataCol = this.sessionDataCol; this.sessionDataCol = sessionDataCol; support.firePropertyChange("sessionDataCol", oldSessionDataCol, this.sessionDataCol); } /** * Return the data column for the table */ public String getSessionDataCol() { return (this.sessionDataCol); } /** * Set the Is Valid column for the table * * @param sessionValidCol The column name */ public void setSessionValidCol(String sessionValidCol) { String oldSessionValidCol = this.sessionValidCol; this.sessionValidCol = sessionValidCol; support.firePropertyChange("sessionValidCol", oldSessionValidCol, this.sessionValidCol); } /** * Return the Is Valid column */ public String getSessionValidCol() { return (this.sessionValidCol); } /** * Set the Max Inactive column for the table * * @param sessionMaxInactiveCol The column name */ public void setSessionMaxInactiveCol(String sessionMaxInactiveCol) { String oldSessionMaxInactiveCol = this.sessionMaxInactiveCol; this.sessionMaxInactiveCol = sessionMaxInactiveCol; support.firePropertyChange("sessionMaxInactiveCol", oldSessionMaxInactiveCol, this.sessionMaxInactiveCol); } /** * Return the Max Inactive column */ public String getSessionMaxInactiveCol() { return (this.sessionMaxInactiveCol); } /** * Set the Last Accessed column for the table * * @param sessionLastAccessedCol The column name */ public void setSessionLastAccessedCol(String sessionLastAccessedCol) { String oldSessionLastAccessedCol = this.sessionLastAccessedCol; this.sessionLastAccessedCol = sessionLastAccessedCol; support.firePropertyChange("sessionLastAccessedCol", oldSessionLastAccessedCol, this.sessionLastAccessedCol); } /** * Return the Last Accessed column */ public String getSessionLastAccessedCol() { return (this.sessionLastAccessedCol); } /** * Set the JNDI name of a DataSource-factory to use for db access * * @param dataSourceName The JNDI name of the DataSource-factory */ public void setDataSourceName(String dataSourceName) { if (dataSourceName == null || "".equals(dataSourceName.trim())) { manager.getContainer().getLogger().warn( sm.getString(getStoreName() + ".missingDataSourceName")); return; } this.dataSourceName = dataSourceName; } /** * Return the name of the JNDI DataSource-factory */ public String getDataSourceName() { return this.dataSourceName; } // --------------------------------------------------------- Public Methods /** * Return an array containing the session identifiers of all Sessions * currently saved in this Store. If there are no such Sessions, a * zero-length array is returned. * * @exception IOException if an input/output error occurred */ @Override public String[] keys() throws IOException { ResultSet rst = null; String keys[] = null; synchronized (this) { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return (new String[0]); } try { if (preparedKeysSql == null) { String keysSql = "SELECT " + sessionIdCol + " FROM " + sessionTable + " WHERE " + sessionAppCol + " = ?"; preparedKeysSql = _conn.prepareStatement(keysSql); } preparedKeysSql.setString(1, getName()); rst = preparedKeysSql.executeQuery(); ArrayList tmpkeys = new ArrayList(); if (rst != null) { while (rst.next()) { tmpkeys.add(rst.getString(1)); } } keys = tmpkeys.toArray(new String[tmpkeys.size()]); // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); keys = new String[0]; // Close the connection so that it gets reopened next time if (dbConnection != null) close(dbConnection); } finally { try { if (rst != null) { rst.close(); } } catch (SQLException e) { // Ignore } release(_conn); } numberOfTries--; } } return (keys); } /** * Return an integer containing a count of all Sessions * currently saved in this Store. If there are no Sessions, * 0 is returned. * * @exception IOException if an input/output error occurred */ @Override public int getSize() throws IOException { int size = 0; ResultSet rst = null; synchronized (this) { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return (size); } try { if (preparedSizeSql == null) { String sizeSql = "SELECT COUNT(" + sessionIdCol + ") FROM " + sessionTable + " WHERE " + sessionAppCol + " = ?"; preparedSizeSql = _conn.prepareStatement(sizeSql); } preparedSizeSql.setString(1, getName()); rst = preparedSizeSql.executeQuery(); if (rst.next()) { size = rst.getInt(1); } // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); if (dbConnection != null) close(dbConnection); } finally { try { if (rst != null) rst.close(); } catch (SQLException e) { // Ignore } release(_conn); } numberOfTries--; } } return (size); } /** * Load the Session associated with the id id. * If no such session is found null is returned. * * @param id a value of type String * @return the stored Session * @exception ClassNotFoundException if an error occurs * @exception IOException if an input/output error occurred */ @Override public Session load(String id) throws ClassNotFoundException, IOException { ResultSet rst = null; StandardSession _session = null; Loader loader = null; ClassLoader classLoader = null; ObjectInputStream ois = null; BufferedInputStream bis = null; Container container = manager.getContainer(); synchronized (this) { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return (null); } ClassLoader oldThreadContextCL = Thread.currentThread().getContextClassLoader(); try { if (preparedLoadSql == null) { String loadSql = "SELECT " + sessionIdCol + ", " + sessionDataCol + " FROM " + sessionTable + " WHERE " + sessionIdCol + " = ? AND " + sessionAppCol + " = ?"; preparedLoadSql = _conn.prepareStatement(loadSql); } preparedLoadSql.setString(1, id); preparedLoadSql.setString(2, getName()); rst = preparedLoadSql.executeQuery(); if (rst.next()) { bis = new BufferedInputStream(rst.getBinaryStream(2)); if (container != null) { loader = container.getLoader(); } if (loader != null) { classLoader = loader.getClassLoader(); } if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); ois = new CustomObjectInputStream(bis, classLoader); } else { ois = new ObjectInputStream(bis); } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".loading", id, sessionTable)); } _session = (StandardSession) manager.createEmptySession(); _session.readObjectData(ois); _session.setManager(manager); } else if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(getStoreName() + ": No persisted data object found"); } // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); if (dbConnection != null) close(dbConnection); } finally { try { if (rst != null) { rst.close(); } } catch (SQLException e) { // Ignore } if (ois != null) { try { ois.close(); } catch (IOException e) { // Ignore } } Thread.currentThread().setContextClassLoader(oldThreadContextCL); release(_conn); } numberOfTries--; } } return (_session); } /** * Remove the Session with the specified session identifier from * this Store, if present. If no such Session is present, this method * takes no action. * * @param id Session identifier of the Session to be removed * * @exception IOException if an input/output error occurs */ @Override public void remove(String id) throws IOException { synchronized (this) { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return; } try { remove(id, _conn); // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); if (dbConnection != null) close(dbConnection); } finally { release(_conn); } numberOfTries--; } } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".removing", id, sessionTable)); } } /** * Remove the Session with the specified session identifier from * this Store, if present. If no such Session is present, this method * takes no action. * * @param id Session identifier of the Session to be removed * @param _conn open connection to be used * @throws SQLException if an error occurs while talking to the database */ private void remove(String id, Connection _conn) throws SQLException { if (preparedRemoveSql == null) { String removeSql = "DELETE FROM " + sessionTable + " WHERE " + sessionIdCol + " = ? AND " + sessionAppCol + " = ?"; preparedRemoveSql = _conn.prepareStatement(removeSql); } preparedRemoveSql.setString(1, id); preparedRemoveSql.setString(2, getName()); preparedRemoveSql.execute(); } /** * Remove all of the Sessions in this Store. * * @exception IOException if an input/output error occurs */ @Override public void clear() throws IOException { synchronized (this) { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return; } try { if (preparedClearSql == null) { String clearSql = "DELETE FROM " + sessionTable + " WHERE " + sessionAppCol + " = ?"; preparedClearSql = _conn.prepareStatement(clearSql); } preparedClearSql.setString(1, getName()); preparedClearSql.execute(); // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); if (dbConnection != null) close(dbConnection); } finally { release(_conn); } numberOfTries--; } } } /** * Save a session to the Store. * * @param session the session to be stored * @exception IOException if an input/output error occurs */ @Override public void save(Session session) throws IOException { ObjectOutputStream oos = null; ByteArrayOutputStream bos = null; ByteArrayInputStream bis = null; InputStream in = null; synchronized (this) { int numberOfTries = 2; while (numberOfTries > 0) { Connection _conn = getConnection(); if (_conn == null) { return; } try { // If sessions already exist in DB, remove and insert again. // TODO: // * Check if ID exists in database and if so use UPDATE. remove(session.getIdInternal(), _conn); bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(new BufferedOutputStream(bos)); ((StandardSession) session).writeObjectData(oos); oos.close(); oos = null; byte[] obs = bos.toByteArray(); int size = obs.length; bis = new ByteArrayInputStream(obs, 0, size); in = new BufferedInputStream(bis, size); if (preparedSaveSql == null) { String saveSql = "INSERT INTO " + sessionTable + " (" + sessionIdCol + ", " + sessionAppCol + ", " + sessionDataCol + ", " + sessionValidCol + ", " + sessionMaxInactiveCol + ", " + sessionLastAccessedCol + ") VALUES (?, ?, ?, ?, ?, ?)"; preparedSaveSql = _conn.prepareStatement(saveSql); } preparedSaveSql.setString(1, session.getIdInternal()); preparedSaveSql.setString(2, getName()); preparedSaveSql.setBinaryStream(3, in, size); preparedSaveSql.setString(4, session.isValid() ? "1" : "0"); preparedSaveSql.setInt(5, session.getMaxInactiveInterval()); preparedSaveSql.setLong(6, session.getLastAccessedTime()); preparedSaveSql.execute(); // Break out after the finally block numberOfTries = 0; } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); if (dbConnection != null) close(dbConnection); } catch (IOException e) { // Ignore } finally { if (oos != null) { oos.close(); } if (bis != null) { bis.close(); } if (in != null) { in.close(); } release(_conn); } numberOfTries--; } } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".saving", session.getIdInternal(), sessionTable)); } } // --------------------------------------------------------- Protected Methods /** * Check the connection associated with this store, if it's * null or closed try to reopen it. * Returns null if the connection could not be established. * * @return Connection if the connection succeeded */ protected Connection getConnection() { Connection conn = null; try { conn = open(); if (conn == null || conn.isClosed()) { manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBClosed")); conn = open(); if (conn == null || conn.isClosed()) { manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBReOpenFail")); } } } catch (SQLException ex) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionSQLException", ex.toString())); } return conn; } /** * Open (if necessary) and return a database connection for use by * this Realm. * * @exception SQLException if a database error occurs */ protected Connection open() throws SQLException { // Do nothing if there is a database connection already open if (dbConnection != null) return (dbConnection); if (dataSourceName != null && dataSource == null) { Context initCtx; try { initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); this.dataSource = (DataSource) envCtx.lookup(this.dataSourceName); } catch (NamingException e) { manager.getContainer().getLogger().error( sm.getString(getStoreName() + ".wrongDataSource", this.dataSourceName), e); } } if (dataSource != null) { return dataSource.getConnection(); } // Instantiate our database driver if necessary if (driver == null) { try { Class clazz = Class.forName(driverName); driver = (Driver) clazz.newInstance(); } catch (ClassNotFoundException ex) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", ex.toString())); } catch (InstantiationException ex) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", ex.toString())); } catch (IllegalAccessException ex) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", ex.toString())); } } // Open a new connection Properties props = new Properties(); if (connectionName != null) props.put("user", connectionName); if (connectionPassword != null) props.put("password", connectionPassword); dbConnection = driver.connect(connectionURL, props); dbConnection.setAutoCommit(true); return (dbConnection); } /** * Close the specified database connection. * * @param dbConnection The connection to be closed */ protected void close(Connection dbConnection) { // Do nothing if the database connection is already closed if (dbConnection == null) return; // Close our prepared statements (if any) try { preparedSizeSql.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.preparedSizeSql = null; try { preparedKeysSql.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.preparedKeysSql = null; try { preparedSaveSql.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.preparedSaveSql = null; try { preparedClearSql.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } try { preparedRemoveSql.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.preparedRemoveSql = null; try { preparedLoadSql.close(); } catch (Throwable f) { ExceptionUtils.handleThrowable(f); } this.preparedLoadSql = null; // Commit if autoCommit is false try { if (!dbConnection.getAutoCommit()) { dbConnection.commit(); } } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".commitSQLException"), e); } // Close this database connection, and log any errors try { dbConnection.close(); } catch (SQLException e) { manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".close", e.toString())); // Just log it here } finally { this.dbConnection = null; } } /** * Release the connection, if it * is associated with a connection pool. * * @param conn The connection to be released */ protected void release(Connection conn) { if (dataSource != null) { close(conn); } } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { if (dataSourceName == null) { // If not using a connection pool, open a connection to the database this.dbConnection = getConnection(); } super.startInternal(); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { super.stopInternal(); // Close and release everything associated with our db. if (dbConnection != null) { try { dbConnection.commit(); } catch (SQLException e) { // Ignore } close(dbConnection); } } } tomcat7-7.0.52/java/org/apache/catalina/session/StoreBase.java0000644000175100017510000001721112271471332024071 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Manager; import org.apache.catalina.Store; import org.apache.catalina.util.LifecycleBase; import org.apache.tomcat.util.res.StringManager; /** * Abstract implementation of the Store interface to * support most of the functionality required by a Store. * * @author Bip Thelin */ public abstract class StoreBase extends LifecycleBase implements Store { // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ protected static final String info = "StoreBase/1.0"; /** * Name to register for this Store, used for logging. */ protected static String storeName = "StoreBase"; /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The Manager with which this JDBCStore is associated. */ protected Manager manager; // ------------------------------------------------------------- Properties /** * Return the info for this Store. */ @Override public String getInfo() { return(info); } /** * Return the name for this Store, used for logging. */ public String getStoreName() { return(storeName); } /** * Set the Manager with which this Store is associated. * * @param manager The newly associated Manager */ @Override public void setManager(Manager manager) { Manager oldManager = this.manager; this.manager = manager; support.firePropertyChange("manager", oldManager, this.manager); } /** * Return the Manager with which the Store is associated. */ @Override public Manager getManager() { return(this.manager); } // --------------------------------------------------------- Public Methods /** * Add a property change listener to this component. * * @param listener a value of type 'PropertyChangeListener' */ @Override public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } /** * Remove a property change listener from this component. * * @param listener The listener to remove */ @Override public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } // --------------------------------------------------------- Protected Methods /** * Called by our background reaper thread to check if Sessions * saved in our store are subject of being expired. If so expire * the Session and remove it from the Store. * */ public void processExpires() { String[] keys = null; if(!getState().isAvailable()) { return; } try { keys = keys(); } catch (IOException e) { manager.getContainer().getLogger().error("Error getting keys", e); return; } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires check number of " + keys.length + " sessions" ); } long timeNow = System.currentTimeMillis(); for (int i = 0; i < keys.length; i++) { try { StandardSession session = (StandardSession) load(keys[i]); if (session == null) { continue; } int timeIdle = (int) ((timeNow - session.getThisAccessedTime()) / 1000L); if (timeIdle < session.getMaxInactiveInterval()) { continue; } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires expire store session " + keys[i] ); } boolean isLoaded = false; if (manager instanceof PersistentManagerBase) { isLoaded = ((PersistentManagerBase) manager).isLoaded(keys[i]); } else { try { if (manager.findSession(keys[i]) != null) { isLoaded = true; } } catch (IOException ioe) { // Ignore - session will be expired } } if (isLoaded) { // recycle old backup session session.recycle(); } else { // expire swapped out session session.expire(); } remove(keys[i]); } catch (Exception e) { manager.getContainer().getLogger().error("Session: "+keys[i]+"; ", e); try { remove(keys[i]); } catch (IOException e2) { manager.getContainer().getLogger().error("Error removing key", e2); } } } } @Override protected void initInternal() { // NOOP } /** * Start this component and implement the requirements * of {@link LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); } @Override protected void destroyInternal() { // NOOP } /** * Return a String rendering of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append('['); if (manager == null) { sb.append("Manager is null"); } else { sb.append(manager); } sb.append(']'); return sb.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/session/PersistentManager.java0000644000175100017510000000445112271471332025637 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; /** * Implementation of the Manager interface that makes use of * a Store to swap active Sessions to disk. It can be configured to * achieve several different goals: * *

  • Persist sessions across restarts of the Container
  • *
  • Fault tolerance, keep sessions backed up on disk to allow * recovery in the event of unplanned restarts.
  • *
  • Limit the number of active sessions kept in memory by * swapping less active sessions out to disk.
  • * * @author Kief Morris (kief@kief.com) */ public final class PersistentManager extends PersistentManagerBase { // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ private static final String info = "PersistentManager/1.0"; /** * The descriptive name of this Manager implementation (for logging). */ protected static String name = "PersistentManager"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return the descriptive short name of this Manager implementation. */ @Override public String getName() { return (name); } } tomcat7-7.0.52/java/org/apache/catalina/session/PersistentManagerBase.java0000644000175100017510000010150212271471332026425 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.catalina.DistributedManager; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Session; import org.apache.catalina.Store; import org.apache.catalina.security.SecurityUtil; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Extends the ManagerBase class to implement most of the * functionality required by a Manager which supports any kind of * persistence, even if only for restarts. *

    * IMPLEMENTATION NOTE: Correct behavior of session storing and * reloading depends upon external calls to the start() and * stop() methods of this class at the correct times. * * @author Craig R. McClanahan * @author Jean-Francois Arcand */ public abstract class PersistentManagerBase extends ManagerBase implements DistributedManager { private static final Log log = LogFactory.getLog(PersistentManagerBase.class); // ---------------------------------------------------- Security Classes private class PrivilegedStoreClear implements PrivilegedExceptionAction { PrivilegedStoreClear() { // NOOP } @Override public Void run() throws Exception{ store.clear(); return null; } } private class PrivilegedStoreRemove implements PrivilegedExceptionAction { private String id; PrivilegedStoreRemove(String id) { this.id = id; } @Override public Void run() throws Exception{ store.remove(id); return null; } } private class PrivilegedStoreLoad implements PrivilegedExceptionAction { private String id; PrivilegedStoreLoad(String id) { this.id = id; } @Override public Session run() throws Exception{ return store.load(id); } } private class PrivilegedStoreSave implements PrivilegedExceptionAction { private Session session; PrivilegedStoreSave(Session session) { this.session = session; } @Override public Void run() throws Exception{ store.save(session); return null; } } private class PrivilegedStoreKeys implements PrivilegedExceptionAction { PrivilegedStoreKeys() { // NOOP } @Override public String[] run() throws Exception{ return store.keys(); } } // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ private static final String info = "PersistentManagerBase/1.1"; /** * The descriptive name of this Manager implementation (for logging). */ private static String name = "PersistentManagerBase"; /** * Store object which will manage the Session store. */ protected Store store = null; /** * Whether to save and reload sessions when the Manager unload * and load methods are called. */ protected boolean saveOnRestart = true; /** * How long a session must be idle before it should be backed up. * -1 means sessions won't be backed up. */ protected int maxIdleBackup = -1; /** * Minimum time a session must be idle before it is swapped to disk. * This overrides maxActiveSessions, to prevent thrashing if there are lots * of active sessions. Setting to -1 means it's ignored. */ protected int minIdleSwap = -1; /** * The maximum time a session may be idle before it should be swapped * to file just on general principle. Setting this to -1 means sessions * should not be forced out. */ protected int maxIdleSwap = -1; /** * Sessions currently being swapped in and the associated locks */ private final Map sessionSwapInLocks = new HashMap(); // ------------------------------------------------------------- Properties /** * Indicates how many seconds old a session can get, after its last use in a * request, before it should be backed up to the store. -1 means sessions * are not backed up. */ public int getMaxIdleBackup() { return maxIdleBackup; } /** * Sets the option to back sessions up to the Store after they * are used in a request. Sessions remain available in memory * after being backed up, so they are not passivated as they are * when swapped out. The value set indicates how old a session * may get (since its last use) before it must be backed up: -1 * means sessions are not backed up. *

    * Note that this is not a hard limit: sessions are checked * against this age limit periodically according to processExpiresFrequency. * This value should be considered to indicate when a session is * ripe for backing up. *

    * So it is possible that a session may be idle for maxIdleBackup + * processExpiresFrequency * engine.backgroundProcessorDelay seconds, plus the time it takes to handle other * session expiration, swapping, etc. tasks. * * @param backup The number of seconds after their last accessed * time when they should be written to the Store. */ public void setMaxIdleBackup (int backup) { if (backup == this.maxIdleBackup) return; int oldBackup = this.maxIdleBackup; this.maxIdleBackup = backup; support.firePropertyChange("maxIdleBackup", Integer.valueOf(oldBackup), Integer.valueOf(this.maxIdleBackup)); } /** * The time in seconds after which a session should be swapped out of * memory to disk. */ public int getMaxIdleSwap() { return maxIdleSwap; } /** * Sets the time in seconds after which a session should be swapped out of * memory to disk. */ public void setMaxIdleSwap(int max) { if (max == this.maxIdleSwap) return; int oldMaxIdleSwap = this.maxIdleSwap; this.maxIdleSwap = max; support.firePropertyChange("maxIdleSwap", Integer.valueOf(oldMaxIdleSwap), Integer.valueOf(this.maxIdleSwap)); } /** * The minimum time in seconds that a session must be idle before * it can be swapped out of memory, or -1 if it can be swapped out * at any time. */ public int getMinIdleSwap() { return minIdleSwap; } /** * Sets the minimum time in seconds that a session must be idle before * it can be swapped out of memory due to maxActiveSession. Set it to -1 * if it can be swapped out at any time. */ public void setMinIdleSwap(int min) { if (this.minIdleSwap == min) return; int oldMinIdleSwap = this.minIdleSwap; this.minIdleSwap = min; support.firePropertyChange("minIdleSwap", Integer.valueOf(oldMinIdleSwap), Integer.valueOf(this.minIdleSwap)); } /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return true, if the session id is loaded in memory * otherwise false is returned * * @param id The session id for the session to be searched for */ public boolean isLoaded( String id ){ try { if ( super.findSession(id) != null ) return true; } catch (IOException e) { log.error("checking isLoaded for id, " + id + ", "+e.getMessage(), e); } return false; } /** * Return the descriptive short name of this Manager implementation. */ @Override public String getName() { return (name); } /** * Set the Store object which will manage persistent Session * storage for this Manager. * * @param store the associated Store */ public void setStore(Store store) { this.store = store; store.setManager(this); } /** * Return the Store object which manages persistent Session * storage for this Manager. */ public Store getStore() { return (this.store); } /** * Indicates whether sessions are saved when the Manager is shut down * properly. This requires the unload() method to be called. */ public boolean getSaveOnRestart() { return saveOnRestart; } /** * Set the option to save sessions to the Store when the Manager is * shut down, then loaded when the Manager starts again. If set to * false, any sessions found in the Store may still be picked up when * the Manager is started again. * * @param saveOnRestart true if sessions should be saved on restart, false if * they should be ignored. */ public void setSaveOnRestart(boolean saveOnRestart) { if (saveOnRestart == this.saveOnRestart) return; boolean oldSaveOnRestart = this.saveOnRestart; this.saveOnRestart = saveOnRestart; support.firePropertyChange("saveOnRestart", Boolean.valueOf(oldSaveOnRestart), Boolean.valueOf(this.saveOnRestart)); } // --------------------------------------------------------- Public Methods /** * Clear all sessions from the Store. */ public void clearStore() { if (store == null) return; try { if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged(new PrivilegedStoreClear()); }catch(PrivilegedActionException ex){ Exception exception = ex.getException(); log.error("Exception clearing the Store: " + exception, exception); } } else { store.clear(); } } catch (IOException e) { log.error("Exception clearing the Store: " + e, e); } } /** * Implements the Manager interface, direct call to processExpires and processPersistenceChecks */ @Override public void processExpires() { long timeNow = System.currentTimeMillis(); Session sessions[] = findSessions(); int expireHere = 0 ; if(log.isDebugEnabled()) log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); for (int i = 0; i < sessions.length; i++) { if (!sessions[i].isValid()) { expiredSessions.incrementAndGet(); expireHere++; } } processPersistenceChecks(); if ((getStore() != null) && (getStore() instanceof StoreBase)) { ((StoreBase) getStore()).processExpires(); } long timeEnd = System.currentTimeMillis(); if(log.isDebugEnabled()) log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); processingTime += (timeEnd - timeNow); } /** * Called by the background thread after active sessions have been checked * for expiration, to allow sessions to be swapped out, backed up, etc. */ public void processPersistenceChecks() { processMaxIdleSwaps(); processMaxActiveSwaps(); processMaxIdleBackups(); } /** * Return the active Session, associated with this Manager, with the * specified session id (if any); otherwise return null. * This method checks the persistence store if persistence is enabled, * otherwise just uses the functionality from ManagerBase. * * @param id The session id for the session to be returned * * @exception IllegalStateException if a new session cannot be * instantiated for any reason * @exception IOException if an input/output error occurs while * processing this request */ @Override public Session findSession(String id) throws IOException { Session session = super.findSession(id); // OK, at this point, we're not sure if another thread is trying to // remove the session or not so the only way around this is to lock it // (or attempt to) and then try to get it by this session id again. If // the other code ran swapOut, then we should get a null back during // this run, and if not, we lock it out so we can access the session // safely. if(session != null) { synchronized(session){ session = super.findSession(session.getIdInternal()); if(session != null){ // To keep any external calling code from messing up the // concurrency. session.access(); session.endAccess(); } } } if (session != null) return (session); // See if the Session is in the Store session = swapIn(id); return (session); } /** * Remove this Session from the active Sessions for this Manager, * but not from the Store. (Used by the PersistentValve) * * @param session Session to be removed */ public void removeSuper(Session session) { super.remove (session); } /** * Load all sessions found in the persistence mechanism, assuming * they are marked as valid and have not passed their expiration * limit. If persistence is not supported, this method returns * without doing anything. *

    * Note that by default, this method is not called by the MiddleManager * class. In order to use it, a subclass must specifically call it, * for example in the start() and/or processPersistenceChecks() methods. */ @Override public void load() { // Initialize our internal data structures sessions.clear(); if (store == null) return; String[] ids = null; try { if (SecurityUtil.isPackageProtectionEnabled()){ try{ ids = AccessController.doPrivileged( new PrivilegedStoreKeys()); }catch(PrivilegedActionException ex){ Exception exception = ex.getException(); log.error("Exception in the Store during load: " + exception, exception); return; } } else { ids = store.keys(); } } catch (IOException e) { log.error("Can't load sessions from store, " + e.getMessage(), e); return; } int n = ids.length; if (n == 0) return; if (log.isDebugEnabled()) log.debug(sm.getString("persistentManager.loading", String.valueOf(n))); for (int i = 0; i < n; i++) try { swapIn(ids[i]); } catch (IOException e) { log.error("Failed load session from store, " + e.getMessage(), e); } } /** * Remove this Session from the active Sessions for this Manager, * and from the Store. * * @param session Session to be removed */ @Override public void remove(Session session, boolean update) { super.remove (session, update); if (store != null){ removeSession(session.getIdInternal()); } } /** * Remove this Session from the active Sessions for this Manager, * and from the Store. * * @param id Session's id to be removed */ protected void removeSession(String id){ try { if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged(new PrivilegedStoreRemove(id)); }catch(PrivilegedActionException ex){ Exception exception = ex.getException(); log.error("Exception in the Store during removeSession: " + exception, exception); } } else { store.remove(id); } } catch (IOException e) { log.error("Exception removing session " + e.getMessage(), e); } } /** * Save all currently active sessions in the appropriate persistence * mechanism, if any. If persistence is not supported, this method * returns without doing anything. *

    * Note that by default, this method is not called by the MiddleManager * class. In order to use it, a subclass must specifically call it, * for example in the stop() and/or processPersistenceChecks() methods. */ @Override public void unload() { if (store == null) return; Session sessions[] = findSessions(); int n = sessions.length; if (n == 0) return; if (log.isDebugEnabled()) log.debug(sm.getString("persistentManager.unloading", String.valueOf(n))); for (int i = 0; i < n; i++) try { swapOut(sessions[i]); } catch (IOException e) { // This is logged in writeSession() } } @Override public int getActiveSessionsFull() { // In memory session count int result = getActiveSessions(); try { // Store session count result += getStore().getSize(); } catch (IOException ioe) { log.warn(sm.getString("persistentManager.storeSizeException")); } return result; } @Override public Set getSessionIdsFull() { Set sessionIds = new HashSet(); // In memory session ID list sessionIds.addAll(sessions.keySet()); // Store session ID list String[] storeKeys; try { storeKeys = getStore().keys(); for (String storeKey : storeKeys) { sessionIds.add(storeKey); } } catch (IOException e) { log.warn(sm.getString("persistentManager.storeKeysException")); } return sessionIds; } // ------------------------------------------------------ Protected Methods /** * Look for a session in the Store and, if found, restore * it in the Manager's list of active sessions if appropriate. * The session will be removed from the Store after swapping * in, but will not be added to the active session list if it * is invalid or past its expiration. */ protected Session swapIn(String id) throws IOException { if (store == null) return null; Object swapInLock = null; /* * The purpose of this sync and these locks is to make sure that a * session is only loaded once. It doesn't matter if the lock is removed * and then another thread enters this method and tries to load the same * session. That thread will re-create a swapIn lock for that session, * quickly find that the session is already in sessions, use it and * carry on. */ synchronized (this) { swapInLock = sessionSwapInLocks.get(id); if (swapInLock == null) { swapInLock = new Object(); sessionSwapInLocks.put(id, swapInLock); } } Session session = null; synchronized (swapInLock) { // First check to see if another thread has loaded the session into // the manager session = sessions.get(id); if (session == null) { try { if (SecurityUtil.isPackageProtectionEnabled()){ try { session = AccessController.doPrivileged( new PrivilegedStoreLoad(id)); } catch (PrivilegedActionException ex) { Exception e = ex.getException(); log.error(sm.getString( "persistentManager.swapInException", id), e); if (e instanceof IOException){ throw (IOException)e; } else if (e instanceof ClassNotFoundException) { throw (ClassNotFoundException)e; } } } else { session = store.load(id); } } catch (ClassNotFoundException e) { String msg = sm.getString( "persistentManager.deserializeError", id); log.error(msg, e); throw new IllegalStateException(msg, e); } if (session != null && !session.isValid()) { log.error(sm.getString( "persistentManager.swapInInvalid", id)); session.expire(); removeSession(id); session = null; } if (session != null) { if(log.isDebugEnabled()) log.debug(sm.getString("persistentManager.swapIn", id)); session.setManager(this); // make sure the listeners know about it. ((StandardSession)session).tellNew(); add(session); ((StandardSession)session).activate(); // endAccess() to ensure timeouts happen correctly. // access() to keep access count correct or it will end up // negative session.access(); session.endAccess(); } } } // Make sure the lock is removed synchronized (this) { sessionSwapInLocks.remove(id); } return (session); } /** * Remove the session from the Manager's list of active * sessions and write it out to the Store. If the session * is past its expiration or invalid, this method does * nothing. * * @param session The Session to write out. */ protected void swapOut(Session session) throws IOException { if (store == null || !session.isValid()) { return; } ((StandardSession)session).passivate(); writeSession(session); super.remove(session, true); session.recycle(); } /** * Write the provided session to the Store without modifying * the copy in memory or triggering passivation events. Does * nothing if the session is invalid or past its expiration. */ protected void writeSession(Session session) throws IOException { if (store == null || !session.isValid()) { return; } try { if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged(new PrivilegedStoreSave(session)); }catch(PrivilegedActionException ex){ Exception exception = ex.getException(); if (exception instanceof IOException) { throw (IOException) exception; } log.error("Exception in the Store during writeSession: " + exception, exception); } } else { store.save(session); } } catch (IOException e) { log.error(sm.getString ("persistentManager.serializeError", session.getIdInternal(), e)); throw e; } } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { super.startInternal(); if (store == null) log.error("No Store configured, persistence disabled"); else if (store instanceof Lifecycle) ((Lifecycle)store).start(); setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { if (log.isDebugEnabled()) log.debug("Stopping"); setState(LifecycleState.STOPPING); if (getStore() != null && saveOnRestart) { unload(); } else { // Expire all active sessions Session sessions[] = findSessions(); for (int i = 0; i < sessions.length; i++) { StandardSession session = (StandardSession) sessions[i]; if (!session.isValid()) continue; session.expire(); } } if (getStore() != null && getStore() instanceof Lifecycle) ((Lifecycle)getStore()).stop(); // Require a new random number generator if we are restarted super.stopInternal(); } // ------------------------------------------------------ Protected Methods /** * Swap idle sessions out to Store if they are idle too long. */ protected void processMaxIdleSwaps() { if (!getState().isAvailable() || maxIdleSwap < 0) return; Session sessions[] = findSessions(); long timeNow = System.currentTimeMillis(); // Swap out all sessions idle longer than maxIdleSwap if (maxIdleSwap >= 0) { for (int i = 0; i < sessions.length; i++) { StandardSession session = (StandardSession) sessions[i]; synchronized (session) { if (!session.isValid()) continue; int timeIdle; if (StandardSession.LAST_ACCESS_AT_START) { timeIdle = (int) ((timeNow - session.getLastAccessedTime()) / 1000L); } else { timeIdle = (int) ((timeNow - session.getThisAccessedTime()) / 1000L); } if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) { if (session.accessCount != null && session.accessCount.get() > 0) { // Session is currently being accessed - skip it continue; } if (log.isDebugEnabled()) log.debug(sm.getString ("persistentManager.swapMaxIdle", session.getIdInternal(), Integer.valueOf(timeIdle))); try { swapOut(session); } catch (IOException e) { // This is logged in writeSession() } } } } } } /** * Swap idle sessions out to Store if too many are active */ protected void processMaxActiveSwaps() { if (!getState().isAvailable() || getMaxActiveSessions() < 0) return; Session sessions[] = findSessions(); // FIXME: Smarter algorithm (LRU) if (getMaxActiveSessions() >= sessions.length) return; if(log.isDebugEnabled()) log.debug(sm.getString ("persistentManager.tooManyActive", Integer.valueOf(sessions.length))); int toswap = sessions.length - getMaxActiveSessions(); long timeNow = System.currentTimeMillis(); for (int i = 0; i < sessions.length && toswap > 0; i++) { StandardSession session = (StandardSession) sessions[i]; synchronized (session) { int timeIdle; if (StandardSession.LAST_ACCESS_AT_START) { timeIdle = (int) ((timeNow - session.getLastAccessedTime()) / 1000L); } else { timeIdle = (int) ((timeNow - session.getThisAccessedTime()) / 1000L); } if (timeIdle > minIdleSwap) { if (session.accessCount != null && session.accessCount.get() > 0) { // Session is currently being accessed - skip it continue; } if(log.isDebugEnabled()) log.debug(sm.getString ("persistentManager.swapTooManyActive", session.getIdInternal(), Integer.valueOf(timeIdle))); try { swapOut(session); } catch (IOException e) { // This is logged in writeSession() } toswap--; } } } } /** * Back up idle sessions. */ protected void processMaxIdleBackups() { if (!getState().isAvailable() || maxIdleBackup < 0) return; Session sessions[] = findSessions(); long timeNow = System.currentTimeMillis(); // Back up all sessions idle longer than maxIdleBackup if (maxIdleBackup >= 0) { for (int i = 0; i < sessions.length; i++) { StandardSession session = (StandardSession) sessions[i]; synchronized (session) { if (!session.isValid()) continue; int timeIdle; if (StandardSession.LAST_ACCESS_AT_START) { timeIdle = (int) ((timeNow - session.getLastAccessedTime()) / 1000L); } else { timeIdle = (int) ((timeNow - session.getThisAccessedTime()) / 1000L); } if (timeIdle > maxIdleBackup) { if (log.isDebugEnabled()) log.debug(sm.getString ("persistentManager.backupMaxIdle", session.getIdInternal(), Integer.valueOf(timeIdle))); try { writeSession(session); } catch (IOException e) { // This is logged in writeSession() } } } } } } } tomcat7-7.0.52/java/org/apache/catalina/session/package.html0000644000175100017510000000674112271471332023626 0ustar locutuslocutus

    This package contains the standard Manager and Session implementations that represent the collection of active sessions and the individual sessions themselves, respectively, that are associated with a Context. Additional implementations of the Manager interface can be based upon the supplied convenience base class (ManagerBase), if desired. Different implementations of Session are possible, but a need for functionality beyond what is provided by the standard implementation (StandardSession) is not expected.

    The convenience ManagerBase base class is configured by setting the following properties:

    • algorithm - Message digest algorithm to be used when generating session identifiers. This must be the name of an algorithm supported by the java.security.MessageDigest class on your platform. [DEFAULT_ALGORITHM]
    • debug - Debugging detail level for this component. [0]
    • distributable - Has the web application we are associated with been marked as "distributable"? If it has, attempts to add or replace a session attribute object that does not implement the java.io.Serializable interface will be rejected. [false]
    • entropy - A string initialization parameter that is used to increase the entropy of the seeding of the random number generator used in creation of session identifiers. [NONE]
    • maxInactiveInterval - The default maximum inactive interval, in minutes, for sessions created by this Manager. The standard implementation automatically updates this value based on the configuration settings in the web application deployment descriptor. [60]
    • randomClass - The Java class name of the random number generator to be used when creating session identifiers for this Manager. [java.security.SecureRandom]

    The standard implementation of the Manager interface (StandardManager) supports the following additional configuration properties:

    • checkInterval - The interval, in seconds, between checks for sessions that have expired and should be invalidated. [60]
    • maxActiveSessions - The maximum number of active sessions that will be allowed, or -1 for no limit. [-1]
    • pathname - Pathname to the file that is used to store session data persistently across container restarts. If this pathname is relative, it is resolved against the temporary working directory provided by our associated Context, if any. ["sessions.ser"]
    tomcat7-7.0.52/java/org/apache/catalina/session/FileStore.java0000644000175100017510000003233012271471332024075 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import javax.servlet.ServletContext; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Loader; import org.apache.catalina.Session; import org.apache.catalina.util.CustomObjectInputStream; /** * Concrete implementation of the Store interface that utilizes * a file per saved Session in a configured directory. Sessions that are * saved are still subject to being expired based on inactivity. * * @author Craig R. McClanahan */ public final class FileStore extends StoreBase { // ----------------------------------------------------- Constants /** * The extension to use for serialized session filenames. */ private static final String FILE_EXT = ".session"; // ----------------------------------------------------- Instance Variables /** * The pathname of the directory in which Sessions are stored. * This may be an absolute pathname, or a relative path that is * resolved against the temporary work directory for this application. */ private String directory = "."; /** * A File representing the directory in which Sessions are stored. */ private File directoryFile = null; /** * The descriptive information about this implementation. */ private static final String info = "FileStore/1.0"; /** * Name to register for this Store, used for logging. */ private static final String storeName = "fileStore"; /** * Name to register for the background thread. */ private static final String threadName = "FileStore"; // ------------------------------------------------------------- Properties /** * Return the directory path for this Store. */ public String getDirectory() { return (directory); } /** * Set the directory path for this Store. * * @param path The new directory path */ public void setDirectory(String path) { String oldDirectory = this.directory; this.directory = path; this.directoryFile = null; support.firePropertyChange("directory", oldDirectory, this.directory); } /** * Return descriptive information about this Store implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return the thread name for this Store. */ public String getThreadName() { return(threadName); } /** * Return the name for this Store, used for logging. */ @Override public String getStoreName() { return(storeName); } /** * Return the number of Sessions present in this Store. * * @exception IOException if an input/output error occurs */ @Override public int getSize() throws IOException { // Acquire the list of files in our storage directory File file = directory(); if (file == null) { return (0); } String files[] = file.list(); // Figure out which files are sessions int keycount = 0; for (int i = 0; i < files.length; i++) { if (files[i].endsWith(FILE_EXT)) { keycount++; } } return (keycount); } // --------------------------------------------------------- Public Methods /** * Remove all of the Sessions in this Store. * * @exception IOException if an input/output error occurs */ @Override public void clear() throws IOException { String[] keys = keys(); for (int i = 0; i < keys.length; i++) { remove(keys[i]); } } /** * Return an array containing the session identifiers of all Sessions * currently saved in this Store. If there are no such Sessions, a * zero-length array is returned. * * @exception IOException if an input/output error occurred */ @Override public String[] keys() throws IOException { // Acquire the list of files in our storage directory File file = directory(); if (file == null) { return (new String[0]); } String files[] = file.list(); // Bugzilla 32130 if((files == null) || (files.length < 1)) { return (new String[0]); } // Build and return the list of session identifiers ArrayList list = new ArrayList(); int n = FILE_EXT.length(); for (int i = 0; i < files.length; i++) { if (files[i].endsWith(FILE_EXT)) { list.add(files[i].substring(0, files[i].length() - n)); } } return list.toArray(new String[list.size()]); } /** * Load and return the Session associated with the specified session * identifier from this Store, without removing it. If there is no * such stored Session, return null. * * @param id Session identifier of the session to load * * @exception ClassNotFoundException if a deserialization error occurs * @exception IOException if an input/output error occurs */ @Override public Session load(String id) throws ClassNotFoundException, IOException { // Open an input stream to the specified pathname, if any File file = file(id); if (file == null) { return (null); } if (! file.exists()) { return (null); } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".loading", id, file.getAbsolutePath())); } FileInputStream fis = null; BufferedInputStream bis = null; ObjectInputStream ois = null; Loader loader = null; ClassLoader classLoader = null; ClassLoader oldThreadContextCL = Thread.currentThread().getContextClassLoader(); try { fis = new FileInputStream(file.getAbsolutePath()); bis = new BufferedInputStream(fis); Container container = manager.getContainer(); if (container != null) loader = container.getLoader(); if (loader != null) classLoader = loader.getClassLoader(); if (classLoader != null) { Thread.currentThread().setContextClassLoader(classLoader); ois = new CustomObjectInputStream(bis, classLoader); } else { ois = new ObjectInputStream(bis); } StandardSession session = (StandardSession) manager.createEmptySession(); session.readObjectData(ois); session.setManager(manager); return (session); } catch (FileNotFoundException e) { if (manager.getContainer().getLogger().isDebugEnabled()) manager.getContainer().getLogger().debug("No persisted data file found"); return (null); } catch (IOException e) { if (bis != null) { try { bis.close(); } catch (IOException f) { // Ignore } } if (fis != null) { try { fis.close(); } catch (IOException f) { // Ignore } } throw e; } finally { if (ois != null) { // Close the input stream try { ois.close(); } catch (IOException f) { // Ignore } } Thread.currentThread().setContextClassLoader(oldThreadContextCL); } } /** * Remove the Session with the specified session identifier from * this Store, if present. If no such Session is present, this method * takes no action. * * @param id Session identifier of the Session to be removed * * @exception IOException if an input/output error occurs */ @Override public void remove(String id) throws IOException { File file = file(id); if (file == null) { return; } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".removing", id, file.getAbsolutePath())); } file.delete(); } /** * Save the specified Session into this Store. Any previously saved * information for the associated session identifier is replaced. * * @param session Session to be saved * * @exception IOException if an input/output error occurs */ @Override public void save(Session session) throws IOException { // Open an output stream to the specified pathname, if any File file = file(session.getIdInternal()); if (file == null) { return; } if (manager.getContainer().getLogger().isDebugEnabled()) { manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".saving", session.getIdInternal(), file.getAbsolutePath())); } FileOutputStream fos = null; ObjectOutputStream oos = null; try { fos = new FileOutputStream(file.getAbsolutePath()); oos = new ObjectOutputStream(new BufferedOutputStream(fos)); } catch (IOException e) { if (fos != null) { try { fos.close(); } catch (IOException f) { // Ignore } } throw e; } try { ((StandardSession)session).writeObjectData(oos); } finally { oos.close(); } } // -------------------------------------------------------- Private Methods /** * Return a File object representing the pathname to our * session persistence directory, if any. The directory will be * created if it does not already exist. */ private File directory() throws IOException { if (this.directory == null) { return (null); } if (this.directoryFile != null) { // NOTE: Race condition is harmless, so do not synchronize return (this.directoryFile); } File file = new File(this.directory); if (!file.isAbsolute()) { Container container = manager.getContainer(); if (container instanceof Context) { ServletContext servletContext = ((Context) container).getServletContext(); File work = (File) servletContext.getAttribute(ServletContext.TEMPDIR); file = new File(work, this.directory); } else { throw new IllegalArgumentException ("Parent Container is not a Context"); } } if (!file.exists() || !file.isDirectory()) { if (!file.delete() && file.exists()) { throw new IOException( sm.getString("fileStore.deleteFailed", file)); } if (!file.mkdirs() && !file.isDirectory()) { throw new IOException( sm.getString("fileStore.createFailed", file)); } } this.directoryFile = file; return (file); } /** * Return a File object representing the pathname to our * session persistence file, if any. * * @param id The ID of the Session to be retrieved. This is * used in the file naming. */ private File file(String id) throws IOException { if (this.directory == null) { return (null); } String filename = id + FILE_EXT; File file = new File(directory(), filename); return (file); } } tomcat7-7.0.52/java/org/apache/catalina/session/mbeans-descriptors.xml0000644000175100017510000003547212271471332025676 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/session/Constants.java0000644000175100017510000000206012271471332024152 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; /** * Manifest constants for the org.apache.catalina.session * package. * * @author Craig R. McClanahan */ public class Constants { public static final String Package = "org.apache.catalina.session"; } tomcat7-7.0.52/java/org/apache/catalina/session/LocalStrings.properties0000644000175100017510000001364512271471332026070 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationSession.session.ise=invalid session state applicationSession.value.iae=null value fileStore.saving=Saving Session {0} to file {1} fileStore.loading=Loading Session {0} from file {1} fileStore.removing=Removing Session {0} at file {1} fileStore.deleteFailed=Unable to delete file [{0}] which is preventing the creation of the session storage location fileStore.createFailed=Unable to create directory [{0}] for the storage of session data JDBCStore.close=Exception closing database connection {0} JDBCStore.saving=Saving Session {0} to database {1} JDBCStore.loading=Loading Session {0} from database {1} JDBCStore.removing=Removing Session {0} at database {1} JDBCStore.SQLException=SQL Error {0} JDBCStore.checkConnectionDBClosed=The database connection is null or was found to be closed. Trying to re-open it. JDBCStore.checkConnectionDBReOpenFail=The re-open on the database failed. The database could be down. JDBCStore.checkConnectionSQLException=A SQL exception occurred {0} JDBCStore.checkConnectionClassNotFoundException=JDBC driver class not found {0} JDBCStore.wrongDataSource=Cannot open JNDI DataSource [{0}] JDBCStore.missingDataSourceName=No valid JNDI name was given. JDBCStore.commitSQLException=SQLException committing connection before closing managerBase.createRandom=Created random number generator for session ID generation in {0}ms. managerBase.createSession.ise=createSession: Too many active sessions managerBase.sessionTimeout=Invalid session timeout setting {0} serverSession.value.iae=null value standardManager.expireException=processsExpire: Exception during session expiration standardManager.loading=Loading persisted sessions from {0} standardManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0} standardManager.loading.ioe=IOException while loading persisted sessions: {0} standardManager.unloading=Saving persisted sessions to {0} standardManager.unloading.debug=Unloading persisted sessions standardManager.unloading.ioe=IOException while saving persisted sessions: {0} standardManager.unloading.nosessions=No persisted sessions to unload standardManager.managerLoad=Exception loading sessions from persistent storage standardManager.managerUnload=Exception unloading sessions to persistent storage standardSession.attributeEvent=Session attribute event listener threw exception standardSession.bindingEvent=Session binding event listener threw exception standardSession.invalidate.ise=invalidate: Session already invalidated standardSession.isNew.ise=isNew: Session already invalidated standardSession.getAttribute.ise=getAttribute: Session already invalidated standardSession.getAttributeNames.ise=getAttributeNames: Session already invalidated standardSession.getCreationTime.ise=getCreationTime: Session already invalidated standardSession.getThisAccessedTime.ise=getThisAccessedTime: Session already invalidated standardSession.getLastAccessedTime.ise=getLastAccessedTime: Session already invalidated standardSession.getId.ise=getId: Session already invalidated standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: Session already invalidated standardSession.getValueNames.ise=getValueNames: Session already invalidated standardSession.logoutfail=Exception logging out user when expiring session standardSession.notSerializable=Cannot serialize session attribute {0} for session {1} standardSession.removeAttribute.ise=removeAttribute: Session already invalidated standardSession.sessionEvent=Session event listener threw exception standardSession.setAttribute.iae=setAttribute: Non-serializable attribute {0} standardSession.setAttribute.ise=setAttribute: Session [{0}] has already been invalidated standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null standardSession.sessionCreated=Created Session id = {0} persistentManager.loading=Loading {0} persisted sessions persistentManager.unloading=Saving {0} persisted sessions persistentManager.expiring=Expiring {0} sessions before saving them persistentManager.deserializeError=Error deserializing Session {0}: {1} persistentManager.serializeError=Error serializing Session {0}: {1} persistentManager.swapMaxIdle=Swapping session {0} to Store, idle for {1} seconds persistentManager.backupMaxIdle=Backing up session {0} to Store, idle for {1} seconds persistentManager.backupException=Exception occurred when backing up Session {0}: {1} persistentManager.tooManyActive=Too many active sessions, {0}, looking for idle sessions to swap out persistentManager.swapTooManyActive=Swapping out session {0}, idle for {1} seconds too many sessions active persistentManager.processSwaps=Checking for sessions to swap out, {0} active sessions in memory persistentManager.activeSession=Session {0} has been idle for {1} seconds persistentManager.swapIn=Swapping session {0} in from Store persistentManager.swapInException=Exception in the Store during swapIn: {0} persistentManager.swapInInvalid=Swapped session {0} is invalid persistentManager.storeKeysException=Unable to determine the list of session IDs for sessions in the session store, assuming that the store is empty persistentManager.storeSizeException=Unable to determine the number of sessions in the session store, assuming that the store is emptytomcat7-7.0.52/java/org/apache/catalina/session/StandardManager.java0000644000175100017510000004463012271471332025242 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Iterator; import javax.servlet.ServletContext; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Loader; import org.apache.catalina.Session; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.util.CustomObjectInputStream; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; /** * Standard implementation of the Manager interface that provides * simple session persistence across restarts of this component (such as * when the entire server is shut down and restarted, or when a particular * web application is reloaded. *

    * IMPLEMENTATION NOTE: Correct behavior of session storing and * reloading depends upon external calls to the start() and * stop() methods of this class at the correct times. * * @author Craig R. McClanahan * @author Jean-Francois Arcand */ public class StandardManager extends ManagerBase { private final Log log = LogFactory.getLog(StandardManager.class); // must not be static // ---------------------------------------------------- Security Classes private class PrivilegedDoLoad implements PrivilegedExceptionAction { PrivilegedDoLoad() { // NOOP } @Override public Void run() throws Exception{ doLoad(); return null; } } private class PrivilegedDoUnload implements PrivilegedExceptionAction { PrivilegedDoUnload() { // NOOP } @Override public Void run() throws Exception{ doUnload(); return null; } } // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ protected static final String info = "StandardManager/1.0"; /** * The descriptive name of this Manager implementation (for logging). */ protected static final String name = "StandardManager"; /** * Path name of the disk file in which active sessions are saved * when we stop, and from which these sessions are loaded when we start. * A null value indicates that no persistence is desired. * If this pathname is relative, it will be resolved against the * temporary working directory provided by our context, available via * the javax.servlet.context.tempdir context attribute. */ protected String pathname = "SESSIONS.ser"; // ------------------------------------------------------------- Properties /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return the descriptive short name of this Manager implementation. */ @Override public String getName() { return (name); } /** * Return the session persistence pathname, if any. */ public String getPathname() { return (this.pathname); } /** * Set the session persistence pathname to the specified value. If no * persistence support is desired, set the pathname to null. * * @param pathname New session persistence pathname */ public void setPathname(String pathname) { String oldPathname = this.pathname; this.pathname = pathname; support.firePropertyChange("pathname", oldPathname, this.pathname); } // --------------------------------------------------------- Public Methods /** * Load any currently active sessions that were previously unloaded * to the appropriate persistence mechanism, if any. If persistence is not * supported, this method returns without doing anything. * * @exception ClassNotFoundException if a serialized class cannot be * found during the reload * @exception IOException if an input/output error occurs */ @Override public void load() throws ClassNotFoundException, IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged( new PrivilegedDoLoad() ); } catch (PrivilegedActionException ex){ Exception exception = ex.getException(); if (exception instanceof ClassNotFoundException){ throw (ClassNotFoundException)exception; } else if (exception instanceof IOException){ throw (IOException)exception; } if (log.isDebugEnabled()) log.debug("Unreported exception in load() " + exception); } } else { doLoad(); } } /** * Load any currently active sessions that were previously unloaded * to the appropriate persistence mechanism, if any. If persistence is not * supported, this method returns without doing anything. * * @exception ClassNotFoundException if a serialized class cannot be * found during the reload * @exception IOException if an input/output error occurs */ protected void doLoad() throws ClassNotFoundException, IOException { if (log.isDebugEnabled()) log.debug("Start: Loading persisted sessions"); // Initialize our internal data structures sessions.clear(); // Open an input stream to the specified pathname, if any File file = file(); if (file == null) return; if (log.isDebugEnabled()) log.debug(sm.getString("standardManager.loading", pathname)); FileInputStream fis = null; BufferedInputStream bis = null; ObjectInputStream ois = null; Loader loader = null; ClassLoader classLoader = null; try { fis = new FileInputStream(file.getAbsolutePath()); bis = new BufferedInputStream(fis); if (container != null) loader = container.getLoader(); if (loader != null) classLoader = loader.getClassLoader(); if (classLoader != null) { if (log.isDebugEnabled()) log.debug("Creating custom object input stream for class loader "); ois = new CustomObjectInputStream(bis, classLoader); } else { if (log.isDebugEnabled()) log.debug("Creating standard object input stream"); ois = new ObjectInputStream(bis); } } catch (FileNotFoundException e) { if (log.isDebugEnabled()) log.debug("No persisted data file found"); return; } catch (IOException e) { log.error(sm.getString("standardManager.loading.ioe", e), e); if (fis != null) { try { fis.close(); } catch (IOException f) { // Ignore } } if (bis != null) { try { bis.close(); } catch (IOException f) { // Ignore } } throw e; } // Load the previously unloaded active sessions synchronized (sessions) { try { Integer count = (Integer) ois.readObject(); int n = count.intValue(); if (log.isDebugEnabled()) log.debug("Loading " + n + " persisted sessions"); for (int i = 0; i < n; i++) { StandardSession session = getNewSession(); session.readObjectData(ois); session.setManager(this); sessions.put(session.getIdInternal(), session); session.activate(); if (!session.isValidInternal()) { // If session is already invalid, // expire session to prevent memory leak. session.setValid(true); session.expire(); } sessionCounter++; } } catch (ClassNotFoundException e) { log.error(sm.getString("standardManager.loading.cnfe", e), e); try { ois.close(); } catch (IOException f) { // Ignore } throw e; } catch (IOException e) { log.error(sm.getString("standardManager.loading.ioe", e), e); try { ois.close(); } catch (IOException f) { // Ignore } throw e; } finally { // Close the input stream try { ois.close(); } catch (IOException f) { // ignored } // Delete the persistent storage file if (file.exists() ) file.delete(); } } if (log.isDebugEnabled()) log.debug("Finish: Loading persisted sessions"); } /** * Save any currently active sessions in the appropriate persistence * mechanism, if any. If persistence is not supported, this method * returns without doing anything. * * @exception IOException if an input/output error occurs */ @Override public void unload() throws IOException { if (SecurityUtil.isPackageProtectionEnabled()){ try{ AccessController.doPrivileged( new PrivilegedDoUnload() ); } catch (PrivilegedActionException ex){ Exception exception = ex.getException(); if (exception instanceof IOException){ throw (IOException)exception; } if (log.isDebugEnabled()) log.debug("Unreported exception in unLoad() " + exception); } } else { doUnload(); } } /** * Save any currently active sessions in the appropriate persistence * mechanism, if any. If persistence is not supported, this method * returns without doing anything. * * @exception IOException if an input/output error occurs */ protected void doUnload() throws IOException { if (log.isDebugEnabled()) log.debug(sm.getString("standardManager.unloading.debug")); if (sessions.isEmpty()) { log.debug(sm.getString("standardManager.unloading.nosessions")); return; // nothing to do } // Open an output stream to the specified pathname, if any File file = file(); if (file == null) return; if (log.isDebugEnabled()) log.debug(sm.getString("standardManager.unloading", pathname)); FileOutputStream fos = null; BufferedOutputStream bos = null; ObjectOutputStream oos = null; boolean error = false; try { fos = new FileOutputStream(file.getAbsolutePath()); bos = new BufferedOutputStream(fos); oos = new ObjectOutputStream(bos); } catch (IOException e) { error = true; log.error(sm.getString("standardManager.unloading.ioe", e), e); throw e; } finally { if (error) { if (oos != null) { try { oos.close(); } catch (IOException ioe) { // Ignore } } if (bos != null) { try { bos.close(); } catch (IOException ioe) { // Ignore } } if (fos != null) { try { fos.close(); } catch (IOException ioe) { // Ignore } } } } // Write the number of active sessions, followed by the details ArrayList list = new ArrayList(); synchronized (sessions) { if (log.isDebugEnabled()) log.debug("Unloading " + sessions.size() + " sessions"); try { oos.writeObject(new Integer(sessions.size())); Iterator elements = sessions.values().iterator(); while (elements.hasNext()) { StandardSession session = (StandardSession) elements.next(); list.add(session); session.passivate(); session.writeObjectData(oos); } } catch (IOException e) { log.error(sm.getString("standardManager.unloading.ioe", e), e); try { oos.close(); } catch (IOException f) { // Ignore } throw e; } } // Flush and close the output stream try { oos.flush(); } finally { try { oos.close(); } catch (IOException f) { // Ignore } } // Expire all the sessions we just wrote if (log.isDebugEnabled()) log.debug("Expiring " + list.size() + " persisted sessions"); Iterator expires = list.iterator(); while (expires.hasNext()) { StandardSession session = expires.next(); try { session.expire(false); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } finally { session.recycle(); } } if (log.isDebugEnabled()) log.debug("Unloading complete"); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { super.startInternal(); // Load unloaded sessions, if any try { load(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("standardManager.managerLoad"), t); } setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { if (log.isDebugEnabled()) log.debug("Stopping"); setState(LifecycleState.STOPPING); // Write out sessions try { unload(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("standardManager.managerUnload"), t); } // Expire all active sessions Session sessions[] = findSessions(); for (int i = 0; i < sessions.length; i++) { Session session = sessions[i]; try { if (session.isValid()) { session.expire(); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } finally { // Measure against memory leaking if references to the session // object are kept in a shared field somewhere session.recycle(); } } // Require a new random number generator if we are restarted super.stopInternal(); } // ------------------------------------------------------ Protected Methods /** * Return a File object representing the pathname to our * persistence file, if any. */ protected File file() { if ((pathname == null) || (pathname.length() == 0)) return (null); File file = new File(pathname); if (!file.isAbsolute()) { if (container instanceof Context) { ServletContext servletContext = ((Context) container).getServletContext(); File tempdir = (File) servletContext.getAttribute(ServletContext.TEMPDIR); if (tempdir != null) file = new File(tempdir, pathname); } } // if (!file.isAbsolute()) // return (null); return (file); } } tomcat7-7.0.52/java/org/apache/catalina/session/LocalStrings_ja.properties0000644000175100017510000002337012271471332026536 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationSession.session.ise=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u72b6\u614b\u3067\u3059 applicationSession.value.iae=null\u5024\u3067\u3059 fileStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059 fileStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059 fileStore.removing=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059 JDBCStore.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a {0} \u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 JDBCStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059 JDBCStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059 JDBCStore.removing= \u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059 JDBCStore.SQLException=SQL\u30a8\u30e9\u30fc {0} JDBCStore.checkConnectionDBClosed=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u304cnull\u3067\u3042\u308b\u304b\u3001\u30af\u30ed\u30fc\u30ba\u3055\u308c\u3066\u3044\u308b\u306e\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\u518d\u30aa\u30fc\u30d7\u30f3\u3057\u3066\u304f\u3060\u3055\u3044\u3002 JDBCStore.checkConnectionDBReOpenFail=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u518d\u30aa\u30fc\u30d7\u30f3\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u30c0\u30a6\u30f3\u3057\u3066\u3044\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 JDBCStore.checkConnectionSQLException=SQL\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0} JDBCStore.checkConnectionClassNotFoundException=JDBC\u30c9\u30e9\u30a4\u30d0\u30af\u30e9\u30b9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 {0} managerBase.createSession.ise=createSession: \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059 managerBase.sessionTimeout=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u8a2d\u5b9a\u3067\u3059 {0} serverSession.value.iae=null\u5024\u3067\u3059 standardManager.expireException=processsExpire: \u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u7d42\u4e86\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardManager.loading={0} \u304b\u3089\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u3066\u3044\u307e\u3059 standardManager.loading.cnfe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306bClassNotFoundException\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} standardManager.loading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306eIOException\u3067\u3059: {0} standardManager.unloading=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092 {0} \u306b\u4fdd\u5b58\u3057\u307e\u3059 standardManager.unloading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u4fdd\u5b58\u4e2d\u306eIOException\u3067\u3059: {0} standardManager.managerLoad=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u304b\u3089\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardManager.managerUnload=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30a2\u30f3\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardSession.attributeEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardSession.bindingEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardSession.invalidate.ise=invalidate: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.isNew.ise=isNew: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getAttribute.ise=getAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getAttributeNames.ise=getAttributeNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getCreationTime.ise=getCreationTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getThisAccessedTime.ise=getThisAccessedTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getLastAccessedTime.ise=getLastAccessedTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getId.ise=getId: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.getValueNames.ise=getValueNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.notSerializable=\u30bb\u30c3\u30b7\u30e7\u30f3 {1} \u306e\u305f\u3081\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u307e\u305b\u3093 standardSession.removeAttribute.ise=removeAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.sessionEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardSession.setAttribute.iae=setAttribute: \u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u306a\u3044\u5c5e\u6027\u3067\u3059 standardSession.setAttribute.ise=setAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 standardSession.setAttribute.namenull=setAttribute: name\u30d1\u30e9\u30e1\u30bf\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 standardSession.sessionCreated=\u30bb\u30c3\u30b7\u30e7\u30f3ID = {0} \u3092\u751f\u6210\u3057\u307e\u3057\u305f persistentManager.loading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 persistentManager.unloading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3057\u307e\u3059 persistentManager.expiring= {0} \u306e\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3059\u308b\u524d\u306b\u671f\u9650\u5207\u308c\u306b\u306a\u308a\u307e\u3057\u305f persistentManager.deserializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} persistentManager.serializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} persistentManager.swapMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30b9\u30ef\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 persistentManager.backupMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 persistentManager.backupException=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3059\u308b\u6642\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {1} persistentManager.tooManyActive=\u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059\u3001{0}\u3001\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3059\u308b\u305f\u3081\u306b\u30a2\u30a4\u30c9\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u63a2\u3057\u3066\u3044\u307e\u3059 persistentManager.swapTooManyActive=\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u308b\u306e\u3067\u3001{1}\u79d2\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3057\u307e\u3059 persistentManager.processSwaps=\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30b9\u30ef\u30c3\u30d7\u3059\u308b\u305f\u3081\u306b\u30c1\u30a7\u30c3\u30af\u3057\u3066\u3044\u307e\u3059, \u30e1\u30e2\u30ea\u4e2d\u306b {0} \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u5b58\u5728\u3057\u307e\u3059 persistentManager.activeSession=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u306f{1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u307e\u3059 persistentManager.swapIn=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a4\u30f3\u3057\u3066\u3044\u307e\u3059 tomcat7-7.0.52/java/org/apache/catalina/session/StandardSessionFacade.java0000644000175100017510000001040312271471332026366 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; import java.util.Enumeration; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; /** * Facade for the StandardSession object. * * @author Remy Maucherat */ public class StandardSessionFacade implements HttpSession { // ----------------------------------------------------------- Constructors /** * Construct a new session facade. */ public StandardSessionFacade(StandardSession session) { super(); this.session = session; } /** * Construct a new session facade. */ public StandardSessionFacade(HttpSession session) { super(); this.session = session; } // ----------------------------------------------------- Instance Variables /** * Wrapped session object. */ private HttpSession session = null; // ---------------------------------------------------- HttpSession Methods @Override public long getCreationTime() { return session.getCreationTime(); } @Override public String getId() { return session.getId(); } @Override public long getLastAccessedTime() { return session.getLastAccessedTime(); } @Override public ServletContext getServletContext() { // FIXME : Facade this object ? return session.getServletContext(); } @Override public void setMaxInactiveInterval(int interval) { session.setMaxInactiveInterval(interval); } @Override public int getMaxInactiveInterval() { return session.getMaxInactiveInterval(); } /** * @deprecated As of Version 2.1, this method is deprecated and has no * replacement. */ @Override @Deprecated public javax.servlet.http.HttpSessionContext getSessionContext() { return session.getSessionContext(); } @Override public Object getAttribute(String name) { return session.getAttribute(name); } /** * @deprecated As of Version 2.2, this method is replaced by * {@link #getAttribute}. */ @Override @Deprecated public Object getValue(String name) { return session.getAttribute(name); } @Override public Enumeration getAttributeNames() { return session.getAttributeNames(); } /** * @deprecated As of Version 2.2, this method is replaced by * {@link #getAttributeNames} */ @Override @Deprecated public String[] getValueNames() { return session.getValueNames(); } @Override public void setAttribute(String name, Object value) { session.setAttribute(name, value); } /** * @deprecated As of Version 2.2, this method is replaced by * {@link #setAttribute} */ @Override @Deprecated public void putValue(String name, Object value) { session.setAttribute(name, value); } @Override public void removeAttribute(String name) { session.removeAttribute(name); } /** * @deprecated As of Version 2.2, this method is replaced by * {@link #removeAttribute} */ @Override @Deprecated public void removeValue(String name) { session.removeAttribute(name); } @Override public void invalidate() { session.invalidate(); } @Override public boolean isNew() { return session.isNew(); } } tomcat7-7.0.52/java/org/apache/catalina/session/TooManyActiveSessionsException.java0000644000175100017510000000366411763516505030350 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.session; /** * An exception that indicates the maximum number of active sessions has been * reached and the server is refusing to create any new sessions. */ public class TooManyActiveSessionsException extends IllegalStateException { private static final long serialVersionUID = 1L; /** * The maximum number of active sessions the server will tolerate. */ private final int maxActiveSessions; /** * Creates a new TooManyActiveSessionsException. * * @param message A description for the exception. * @param maxActive The maximum number of active sessions allowed by the * session manager. */ public TooManyActiveSessionsException(String message, int maxActive) { super(message); maxActiveSessions = maxActive; } /** * Gets the maximum number of sessions allowed by the session manager. * * @return The maximum number of sessions allowed by the session manager. */ public int getMaxActiveSessions() { return maxActiveSessions; } } tomcat7-7.0.52/java/org/apache/catalina/session/LocalStrings_fr.properties0000644000175100017510000001351512271471332026553 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationSession.session.ise=\u00e9tat de session invalide applicationSession.value.iae=valeur nulle fileStore.saving=Sauvegarde de la Session {0} vers le fichier {1} fileStore.loading=Chargement de la Session {0} depuis le fichier {1} fileStore.removing=Retrait de la Session {0} du fichier {1} JDBCStore.saving=Sauvegarde de la Session {0} vers la base de donn\u00e9es {1} JDBCStore.loading=Chargement de la Session {0} depuis la base de donn\u00e9es {1} JDBCStore.removing=Retrait de la Session {0} de la base de donn\u00e9es {1} JDBCStore.SQLException=Erreur SQL {0} JDBCStore.checkConnectionDBClosed=La connexion \u00e0 la base de donn\u00e9es est nulle ou a \u00e9t\u00e9 trouv\u00e9e ferm\u00e9e. Tentative de r\u00e9ouverture. JDBCStore.checkConnectionDBReOpenFail=La tentative de r\u00e9ouverture de la base de donn\u00e9es a \u00e9chou\u00e9. La base de donn\u00e9es est peut-\u00eatre arr\u00eat\u00e9e. JDBCStore.checkConnectionSQLException=Une exception SQL s''est produite {0} JDBCStore.checkConnectionClassNotFoundException=La classe du driver JDBC n''a pas \u00e9t\u00e9 trouv\u00e9e {0} managerBase.createSession.ise="createSession": Trop de sessions actives managerBase.sessionTimeout=R\u00e9glage du d\u00e9lai d''inactivit\u00e9 (timeout) de session invalide {0} serverSession.value.iae=valeur nulle standardManager.expireException="processsExpire": Exception lors de l''expiration de la session standardManager.loading=Chargement des sessions qui ont persist\u00e9 depuis {0} standardManager.loading.cnfe="ClassNotFoundException" lors du chargement de sessions persistantes: {0} standardManager.loading.ioe="IOException" lors du chargement de sessions persistantes: {0} standardManager.unloading=Sauvegarde des sessions ayant persist\u00e9 vers {0} standardManager.unloading.ioe="IOException" lors de la sauvegarde de sessions persistantes: {0} standardManager.managerLoad=Exception au chargement des sessions depuis le stockage persistant (persistent storage) standardManager.managerUnload=Exception au d\u00e9chargement des sessions vers le stockage persistant (persistent storage) standardSession.attributeEvent=L''\u00e9couteur d''\u00e9v\u00e8nement Attribut de Session (attribute event listener) a g\u00e9n\u00e9r\u00e9 une exception standardSession.invalidate.ise="invalidate": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.isNew.ise="isNew": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getAttribute.ise="getAttribute": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getAttributeNames.ise="getAttributeNames": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getCreationTime.ise="getCreationTime": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getThisAccessedTime.ise="getThisAccessedTime": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getLastAccessedTime.ise="getLastAccessedTime": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getId.ise=getId: Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getMaxInactiveInterval.ise="getMaxInactiveInterval": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.getValueNames.ise="getValueNames": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.notSerializable=Impossible de s\u00e9rialiser l''attribut de session {0} pour la session {1} standardSession.removeAttribute.ise="removeAttribute": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.sessionEvent=L''\u00e9couteur d''\u00e9v\u00e8nement de session (session event listener) a g\u00e9n\u00e9r\u00e9 une exception standardSession.setAttribute.iae="setAttribute": Attribut {0} non s\u00e9rialisable standardSession.setAttribute.ise="setAttribute": Session d\u00e9j\u00e0 invalid\u00e9e standardSession.setAttribute.namenull="setAttribute": le nom de param\u00e8tre ne peut \u00eatre nul standardSession.sessionCreated=Cr\u00e9ation de l''Id de Session = {0} persistentManager.loading=Chargement de {0} sessions persistantes persistentManager.unloading=Sauvegarde de {0} sessions persistantes persistentManager.expiring=Expiration de {0} sessions avant leur sauvegarde persistentManager.deserializeError=Erreur lors de la d\u00e9s\u00e9rialisation de la session {0}: {1} persistentManager.serializeError=Erreur lors de la s\u00e9rialisation de la session {0}: {1} persistentManager.swapMaxIdle=Basculement de la session {0} vers le stockage (Store), en attente pour {1} secondes persistentManager.backupMaxIdle=Sauvegarde de la session {0} vers le stockage (Store), en attente pour {1} secondes persistentManager.backupException=Exception lors de la sauvegarde de la session {0}: {1} persistentManager.tooManyActive=Trop de sessions actives, {0}, \u00e0 la recherche de sessions en attente pour basculement vers stockage (swap out) persistentManager.swapTooManyActive=Basculement vers stockage (swap out) de la session {0}, en attente pour {1} secondes trop de sessions actives persistentManager.processSwaps=Recherche de sessions \u00e0 basculer vers stockage (swap out), {0} sessions actives en m\u00e9moire persistentManager.activeSession=La session {0} a \u00e9t\u00e9 en attente durant {1} secondes persistentManager.swapIn=Basculement depuis le stockage (swap in) de la session {0} tomcat7-7.0.52/java/org/apache/catalina/util/0000755000175100017510000000000012301126371020621 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/util/LocalStrings_es.properties0000644000175100017510000000332412271471332026042 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. parameterMap.locked = No se permiten modificaciones en un ParameterMap bloqueado resourceSet.locked = No se permiten modificaciones en un ResourceSet bloqueado hexUtil.bad = D\u00EDgito hexadecimal incorrecto hexUtil.odd = N\u00FAmero de d\u00EDgitos hexadecimales impar #Default Messages Utilized by the ExtensionValidator extensionValidator.web-application-manifest = Manifiesto de Aplicaci\u00F3n Web extensionValidator.extension-not-found-error = ExtensionValidator[{0}][{1}]\: La extensi\u00F3n no encuentra el "{2}" requerido. extensionValidator.extension-validation-error = ExtensionValidator[{0}]\: Imposible de hallar la(s) extension(es) {1} requerida(s). extensionValidator.failload = No pude cargar la extensi\u00F3n {0} SecurityUtil.doAsPrivilege = Una excepci\u00F3n se ha producido durante la ejecuci\u00F3n del bloque PrivilegedExceptionAction. sessionIdGenerator.random = Excepci\u00F3n inicializando generador de n\u00FAmeros aleatorios de clase {0} tomcat7-7.0.52/java/org/apache/catalina/util/CharsetMapper.java0000644000175100017510000001026312271471332024232 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.InputStream; import java.util.Locale; import java.util.Properties; import org.apache.tomcat.util.ExceptionUtils; /** * Utility class that attempts to map from a Locale to the corresponding * character set to be used for interpreting input text (or generating * output text) when the Content-Type header does not include one. You * can customize the behavior of this class by modifying the mapping data * it loads, or by subclassing it (to change the algorithm) and then using * your own version for a particular web application. * * @author Craig R. McClanahan */ public class CharsetMapper { // ---------------------------------------------------- Manifest Constants /** * Default properties resource name. */ public static final String DEFAULT_RESOURCE = "/org/apache/catalina/util/CharsetMapperDefault.properties"; // ---------------------------------------------------------- Constructors /** * Construct a new CharsetMapper using the default properties resource. */ public CharsetMapper() { this(DEFAULT_RESOURCE); } /** * Construct a new CharsetMapper using the specified properties resource. * * @param name Name of a properties resource to be loaded * * @exception IllegalArgumentException if the specified properties * resource could not be loaded for any reason. */ public CharsetMapper(String name) { try { InputStream stream = this.getClass().getResourceAsStream(name); map.load(stream); stream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); throw new IllegalArgumentException(t.toString()); } } // ---------------------------------------------------- Instance Variables /** * The mapping properties that have been initialized from the specified or * default properties resource. */ private Properties map = new Properties(); // ------------------------------------------------------- Public Methods /** * Calculate the name of a character set to be assumed, given the specified * Locale and the absence of a character set specified as part of the * content type header. * * @param locale The locale for which to calculate a character set */ public String getCharset(Locale locale) { // Match full language_country_variant first, then language_country, // then language only String charset = map.getProperty(locale.toString()); if (charset == null) { charset = map.getProperty(locale.getLanguage() + "_" + locale.getCountry()); if (charset == null) { charset = map.getProperty(locale.getLanguage()); } } return (charset); } /** * The deployment descriptor can have a * locale-encoding-mapping-list element which describes the * webapp's desired mapping from locale to charset. This method * gets called when processing the web.xml file for a context * * @param locale The locale for a character set * @param charset The charset to be associated with the locale */ public void addCharsetMappingFromDeploymentDescriptor(String locale, String charset) { map.put(locale, charset); } } tomcat7-7.0.52/java/org/apache/catalina/util/MD5Encoder.java0000644000175100017510000000423712271471332023365 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; /** * Encode an MD5 digest into a String. *

    * The 128 bit MD5 hash is converted into a 32 character long String. * Each character of the String is the hexadecimal representation of 4 bits * of the digest. * * @author Remy Maucherat */ public final class MD5Encoder { /** * @deprecated Will be made private in Tomcat 8.0.x */ @Deprecated public MD5Encoder() { // NOOP } // ----------------------------------------------------- Instance Variables private static final char[] hexadecimal = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; // --------------------------------------------------------- Public Methods /** * Encodes the 128 bit (16 bytes) MD5 into a 32 character String. * * @param binaryData Array containing the digest * @return Encoded MD5, or null if encoding failed */ public static String encode( byte[] binaryData ) { if (binaryData.length != 16) return null; char[] buffer = new char[32]; for (int i=0; i<16; i++) { int low = binaryData[i] & 0x0f; int high = (binaryData[i] & 0xf0) >> 4; buffer[i*2] = hexadecimal[high]; buffer[i*2 + 1] = hexadecimal[low]; } return new String(buffer); } } tomcat7-7.0.52/java/org/apache/catalina/util/ExtensionValidator.java0000644000175100017510000004077412271471332025330 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.Locale; import java.util.NoSuchElementException; import java.util.StringTokenizer; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import javax.naming.Binding; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.DirContext; import org.apache.catalina.Context; import org.apache.naming.resources.Resource; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Ensures that all extension dependencies are resolved for a WEB application * are met. This class builds a master list of extensions available to an * application and then validates those extensions. * * See http://docs.oracle.com/javase/1.4.2/docs/guide/extensions/spec.html * for a detailed explanation of the extension mechanism in Java. * * @author Greg Murray * @author Justyna Horwat */ public final class ExtensionValidator { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog(ExtensionValidator.class); /** * The string resources for this package. */ private static final StringManager sm = StringManager.getManager("org.apache.catalina.util"); private static volatile ArrayList containerAvailableExtensions = null; private static ArrayList containerManifestResources = new ArrayList(); // ----------------------------------------------------- Static Initializer /** * This static initializer loads the container level extensions that are * available to all web applications. This method scans all extension * directories available via the "java.ext.dirs" System property. * * The System Class-Path is also scanned for jar files that may contain * available extensions. */ static { // check for container level optional packages String systemClasspath = System.getProperty("java.class.path"); StringTokenizer strTok = new StringTokenizer(systemClasspath, File.pathSeparator); // build a list of jar files in the classpath while (strTok.hasMoreTokens()) { String classpathItem = strTok.nextToken(); if (classpathItem.toLowerCase(Locale.ENGLISH).endsWith(".jar")) { File item = new File(classpathItem); if (item.isFile()) { try { addSystemResource(item); } catch (IOException e) { log.error(sm.getString ("extensionValidator.failload", item), e); } } } } // add specified folders to the list addFolderList("java.ext.dirs"); } // --------------------------------------------------------- Public Methods /** * Runtime validation of a Web Application. * * This method uses JNDI to look up the resources located under a * DirContext. It locates Web Application MANIFEST.MF * file in the /META-INF/ directory of the application and all * MANIFEST.MF files in each JAR file located in the WEB-INF/lib * directory and creates an ArrayList of * ManifestResorce objects. These objects are then passed * to the validateManifestResources method for validation. * * @param dirContext The JNDI root of the Web Application * @param context The context from which the Logger and path to the * application * * @return true if all required extensions satisfied */ public static synchronized boolean validateApplication( DirContext dirContext, Context context) throws IOException { String appName = context.getName(); ArrayList appManifestResources = new ArrayList(); // If the application context is null it does not exist and // therefore is not valid if (dirContext == null) return false; // Find the Manifest for the Web Application InputStream inputStream = null; try { NamingEnumeration wne = dirContext.listBindings("/META-INF/"); Binding binding = wne.nextElement(); if (binding.getName().toUpperCase(Locale.ENGLISH).equals("MANIFEST.MF")) { Resource resource = (Resource)dirContext.lookup ("/META-INF/" + binding.getName()); inputStream = resource.streamContent(); Manifest manifest = new Manifest(inputStream); inputStream.close(); inputStream = null; ManifestResource mre = new ManifestResource (sm.getString("extensionValidator.web-application-manifest"), manifest, ManifestResource.WAR); appManifestResources.add(mre); } } catch (NamingException nex) { // Application does not contain a MANIFEST.MF file } catch (NoSuchElementException nse) { // Application does not contain a MANIFEST.MF file } finally { if (inputStream != null) { try { inputStream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } // Locate the Manifests for all bundled JARs NamingEnumeration ne = null; // Primarily used for error reporting String jarName = null; try { ne = dirContext.listBindings("WEB-INF/lib/"); while ((ne != null) && ne.hasMoreElements()) { Binding binding = ne.nextElement(); jarName = binding.getName(); if (!jarName.toLowerCase(Locale.ENGLISH).endsWith(".jar")) { continue; } Object obj = dirContext.lookup("/WEB-INF/lib/" + jarName); if (!(obj instanceof Resource)) { // Probably a directory named xxx.jar - ignore it continue; } Resource resource = (Resource) obj; inputStream = resource.streamContent(); Manifest jmanifest = getManifest(inputStream); if (jmanifest != null) { ManifestResource mre = new ManifestResource(jarName, jmanifest, ManifestResource.APPLICATION); appManifestResources.add(mre); } } } catch (NamingException nex) { // Jump out of the check for this application because it // has no resources } catch (IOException ioe) { throw new IOException("Jar: " + jarName, ioe); } finally { if (inputStream != null) { try { inputStream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } return validateManifestResources(appName, appManifestResources); } /** * Checks to see if the given system JAR file contains a MANIFEST, and adds * it to the container's manifest resources. * * @param jarFile The system JAR whose manifest to add */ public static void addSystemResource(File jarFile) throws IOException { Manifest manifest = getManifest(new FileInputStream(jarFile)); if (manifest != null) { ManifestResource mre = new ManifestResource(jarFile.getAbsolutePath(), manifest, ManifestResource.SYSTEM); containerManifestResources.add(mre); } } // -------------------------------------------------------- Private Methods /** * Validates a ArrayList of ManifestResource * objects. This method requires an application name (which is the * context root of the application at runtime). * * false is returned if the extension dependencies * represented by any given ManifestResource objects * is not met. * * This method should also provide static validation of a Web Application * if provided with the necessary parameters. * * @param appName The name of the Application that will appear in the * error messages * @param resources A list of ManifestResource objects * to be validated. * * @return true if manifest resource file requirements are met */ private static boolean validateManifestResources(String appName, ArrayList resources) { boolean passes = true; int failureCount = 0; ArrayList availableExtensions = null; Iterator it = resources.iterator(); while (it.hasNext()) { ManifestResource mre = it.next(); ArrayList requiredList = mre.getRequiredExtensions(); if (requiredList == null) { continue; } // build the list of available extensions if necessary if (availableExtensions == null) { availableExtensions = buildAvailableExtensionsList(resources); } // load the container level resource map if it has not been built // yet if (containerAvailableExtensions == null) { containerAvailableExtensions = buildAvailableExtensionsList(containerManifestResources); } // iterate through the list of required extensions Iterator rit = requiredList.iterator(); while (rit.hasNext()) { boolean found = false; Extension requiredExt = rit.next(); // check the application itself for the extension if (availableExtensions != null) { Iterator ait = availableExtensions.iterator(); while (ait.hasNext()) { Extension targetExt = ait.next(); if (targetExt.isCompatibleWith(requiredExt)) { requiredExt.setFulfilled(true); found = true; break; } } } // check the container level list for the extension if (!found && containerAvailableExtensions != null) { Iterator cit = containerAvailableExtensions.iterator(); while (cit.hasNext()) { Extension targetExt = cit.next(); if (targetExt.isCompatibleWith(requiredExt)) { requiredExt.setFulfilled(true); found = true; break; } } } if (!found) { // Failure log.info(sm.getString( "extensionValidator.extension-not-found-error", appName, mre.getResourceName(), requiredExt.getExtensionName())); passes = false; failureCount++; } } } if (!passes) { log.info(sm.getString( "extensionValidator.extension-validation-error", appName, failureCount + "")); } return passes; } /* * Build this list of available extensions so that we do not have to * re-build this list every time we iterate through the list of required * extensions. All available extensions in all of the * MainfestResource objects will be added to a * HashMap which is returned on the first dependency list * processing pass. * * The key is the name + implementation version. * * NOTE: A list is built only if there is a dependency that needs * to be checked (performance optimization). * * @param resources A list of ManifestResource objects * * @return HashMap Map of available extensions */ private static ArrayList buildAvailableExtensionsList( ArrayList resources) { ArrayList availableList = null; Iterator it = resources.iterator(); while (it.hasNext()) { ManifestResource mre = it.next(); ArrayList list = mre.getAvailableExtensions(); if (list != null) { Iterator values = list.iterator(); while (values.hasNext()) { Extension ext = values.next(); if (availableList == null) { availableList = new ArrayList(); availableList.add(ext); } else { availableList.add(ext); } } } } return availableList; } /** * Return the Manifest from a jar file or war file * * @param inStream Input stream to a WAR or JAR file * @return The WAR's or JAR's manifest */ private static Manifest getManifest(InputStream inStream) throws IOException { Manifest manifest = null; JarInputStream jin = null; try { jin = new JarInputStream(inStream); manifest = jin.getManifest(); jin.close(); jin = null; } finally { if (jin != null) { try { jin.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } return manifest; } /** * Add the JARs specified to the extension list. */ private static void addFolderList(String property) { // get the files in the extensions directory String extensionsDir = System.getProperty(property); if (extensionsDir != null) { StringTokenizer extensionsTok = new StringTokenizer(extensionsDir, File.pathSeparator); while (extensionsTok.hasMoreTokens()) { File targetDir = new File(extensionsTok.nextToken()); if (!targetDir.isDirectory()) { continue; } File[] files = targetDir.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].getName().toLowerCase(Locale.ENGLISH).endsWith(".jar") && files[i].isFile()) { try { addSystemResource(files[i]); } catch (IOException e) { log.error (sm.getString ("extensionValidator.failload", files[i]), e); } } } } } } } tomcat7-7.0.52/java/org/apache/catalina/util/Base64.java0000644000175100017510000002122412271471332022517 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import javax.xml.bind.DatatypeConverter; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.CharChunk; /** * This class provides encode/decode for RFC 2045 Base64 as defined by * RFC 2045, N. Freed and N. Borenstein. RFC 2045: * Multipurpose Internet Mail Extensions (MIME) Part One: Format of * Internet Message Bodies. Reference 1996 * * @author Jeffrey Rodriguez * * @deprecated Use {@link org.apache.tomcat.util.codec.binary.Base64} * This class will be removed in Tomcat 8. */ @Deprecated public final class Base64 { private static final int BASELENGTH = 255; private static final int LOOKUPLENGTH = 64; private static final int FOURBYTE = 4; private static final byte PAD = (byte) '='; private static final byte [] base64Alphabet = new byte[BASELENGTH]; private static final byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; static { for (int i = 0; i < BASELENGTH; i++ ) { base64Alphabet[i] = -1; } for (int i = 'Z'; i >= 'A'; i--) { base64Alphabet[i] = (byte) (i - 'A'); } for (int i = 'z'; i>= 'a'; i--) { base64Alphabet[i] = (byte) (i - 'a' + 26); } for (int i = '9'; i >= '0'; i--) { base64Alphabet[i] = (byte) (i - '0' + 52); } base64Alphabet['+'] = 62; base64Alphabet['/'] = 63; for (int i = 0; i <= 25; i++ ) lookUpBase64Alphabet[i] = (byte) ('A' + i); for (int i = 26, j = 0; i <= 51; i++, j++ ) lookUpBase64Alphabet[i] = (byte) ('a'+ j); for (int i = 52, j = 0; i <= 61; i++, j++ ) lookUpBase64Alphabet[i] = (byte) ('0' + j); lookUpBase64Alphabet[62] = (byte) '+'; lookUpBase64Alphabet[63] = (byte) '/'; } /** * Encodes hex octets into Base64. * * @param binaryData Array containing binary data to encode. * @return Base64-encoded data. * * @deprecated Use {@link DatatypeConverter#printBase64Binary(byte[])}. * This method will be removed in Tomcat 8.0.x. */ @Deprecated public static String encode(byte[] binaryData) { return DatatypeConverter.printBase64Binary(binaryData); } /** * Decodes Base64 data into octets * * @param base64DataBC Byte array containing Base64 data * @param decodedDataCC The decoded data chars */ public static void decode( ByteChunk base64DataBC, CharChunk decodedDataCC) { int start = base64DataBC.getStart(); int end = base64DataBC.getEnd(); byte[] base64Data = base64DataBC.getBuffer(); decodedDataCC.recycle(); // handle the edge case, so we don't have to worry about it later if(end - start == 0) { return; } int numberQuadruple = (end - start)/FOURBYTE; byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0; // Throw away anything not in base64Data int encodedIndex = 0; int dataIndex = start; char[] decodedData = null; { // this sizes the output array properly - rlw int lastData = end - start; // ignore the '=' padding while (base64Data[start+lastData-1] == PAD) { if (--lastData == 0) { return; } } decodedDataCC.allocate(lastData - numberQuadruple, -1); decodedDataCC.setEnd(lastData - numberQuadruple); decodedData = decodedDataCC.getBuffer(); } for (int i = 0; i < numberQuadruple; i++) { dataIndex = start + i * 4; marker0 = base64Data[dataIndex + 2]; marker1 = base64Data[dataIndex + 3]; b1 = base64Alphabet[base64Data[dataIndex]]; b2 = base64Alphabet[base64Data[dataIndex +1]]; if (marker0 != PAD && marker1 != PAD) { //No PAD e.g 3cQl b3 = base64Alphabet[ marker0 ]; b4 = base64Alphabet[ marker1 ]; decodedData[encodedIndex] = (char) (( b1 <<2 | b2>>4 ) & 0xff); decodedData[encodedIndex + 1] = (char) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff); decodedData[encodedIndex + 2] = (char) (( b3<<6 | b4 ) & 0xff); } else if (marker0 == PAD) { //Two PAD e.g. 3c[Pad][Pad] decodedData[encodedIndex] = (char) (( b1 <<2 | b2>>4 ) & 0xff); } else if (marker1 == PAD) { //One PAD e.g. 3cQ[Pad] b3 = base64Alphabet[ marker0 ]; decodedData[encodedIndex] = (char) (( b1 <<2 | b2>>4 ) & 0xff); decodedData[encodedIndex + 1] = (char) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff); } encodedIndex += 3; } } /** * Decodes Base64 data into octets * * @param base64DataBC Byte array containing Base64 data * @param decodedDataBC The decoded data bytes */ public static void decode( ByteChunk base64DataBC, ByteChunk decodedDataBC) { int start = base64DataBC.getStart(); int end = base64DataBC.getEnd(); byte[] base64Data = base64DataBC.getBuffer(); decodedDataBC.recycle(); // handle the edge case, so we don't have to worry about it later if(end - start == 0) { return; } int numberQuadruple = (end - start)/FOURBYTE; byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0; // Throw away anything not in base64Data int encodedIndex = 0; int dataIndex = start; byte[] decodedData = null; { // this sizes the output array properly - rlw int lastData = end - start; // ignore the '=' padding while (base64Data[start+lastData-1] == PAD) { if (--lastData == 0) { return; } } decodedDataBC.allocate(lastData - numberQuadruple, -1); decodedDataBC.setEnd(lastData - numberQuadruple); decodedData = decodedDataBC.getBuffer(); } for (int i = 0; i < numberQuadruple; i++) { dataIndex = start + i * 4; marker0 = base64Data[dataIndex + 2]; marker1 = base64Data[dataIndex + 3]; b1 = base64Alphabet[base64Data[dataIndex]]; b2 = base64Alphabet[base64Data[dataIndex +1]]; if (marker0 != PAD && marker1 != PAD) { //No PAD e.g 3cQl b3 = base64Alphabet[ marker0 ]; b4 = base64Alphabet[ marker1 ]; decodedData[encodedIndex] = (byte) (( b1 <<2 | b2>>4 ) & 0xff); decodedData[encodedIndex + 1] = (byte) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff); decodedData[encodedIndex + 2] = (byte) (( b3<<6 | b4 ) & 0xff); } else if (marker0 == PAD) { //Two PAD e.g. 3c[Pad][Pad] decodedData[encodedIndex] = (byte) (( b1 <<2 | b2>>4 ) & 0xff); } else if (marker1 == PAD) { //One PAD e.g. 3cQ[Pad] b3 = base64Alphabet[ marker0 ]; decodedData[encodedIndex] = (byte) (( b1 <<2 | b2>>4 ) & 0xff); decodedData[encodedIndex + 1] = (byte) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff); } encodedIndex += 3; } } } tomcat7-7.0.52/java/org/apache/catalina/util/Strftime.java0000644000175100017510000002176712271471332023304 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.Properties; import java.util.TimeZone; /** * Converts dates to strings using the same format specifiers as strftime * * Note: This does not mimic strftime perfectly. Certain strftime commands, * are not supported, and will convert as if they were literals. * * Certain complicated commands, like those dealing with the week of the year * probably don't have exactly the same behavior as strftime. * * These limitations are due to use SimpleDateTime. If the conversion was done * manually, all these limitations could be eliminated. * * The interface looks like a subset of DateFormat. Maybe someday someone will make this class * extend DateFormat. * * @author Bip Thelin * @author Dan Sandberg */ public class Strftime { protected static Properties translate; protected SimpleDateFormat simpleDateFormat; /** * Initialize our pattern translation */ static { translate = new Properties(); translate.put("a","EEE"); translate.put("A","EEEE"); translate.put("b","MMM"); translate.put("B","MMMM"); translate.put("c","EEE MMM d HH:mm:ss yyyy"); //There's no way to specify the century in SimpleDateFormat. We don't want to hard-code //20 since this could be wrong for the pre-2000 files. //translate.put("C", "20"); translate.put("d","dd"); translate.put("D","MM/dd/yy"); translate.put("e","dd"); //will show as '03' instead of ' 3' translate.put("F","yyyy-MM-dd"); translate.put("g","yy"); translate.put("G","yyyy"); translate.put("H","HH"); translate.put("h","MMM"); translate.put("I","hh"); translate.put("j","DDD"); translate.put("k","HH"); //will show as '07' instead of ' 7' translate.put("l","hh"); //will show as '07' instead of ' 7' translate.put("m","MM"); translate.put("M","mm"); translate.put("n","\n"); translate.put("p","a"); translate.put("P","a"); //will show as pm instead of PM translate.put("r","hh:mm:ss a"); translate.put("R","HH:mm"); //There's no way to specify this with SimpleDateFormat //translate.put("s","seconds since epoch"); translate.put("S","ss"); translate.put("t","\t"); translate.put("T","HH:mm:ss"); //There's no way to specify this with SimpleDateFormat //translate.put("u","day of week ( 1-7 )"); //There's no way to specify this with SimpleDateFormat //translate.put("U","week in year with first Sunday as first day..."); translate.put("V","ww"); //I'm not sure this is always exactly the same //There's no way to specify this with SimpleDateFormat //translate.put("W","week in year with first Monday as first day..."); //There's no way to specify this with SimpleDateFormat //translate.put("w","E"); translate.put("X","HH:mm:ss"); translate.put("x","MM/dd/yy"); translate.put("y","yy"); translate.put("Y","yyyy"); translate.put("Z","z"); translate.put("z","Z"); translate.put("%","%"); } /** * Create an instance of this date formatting class * * @see #Strftime( String, Locale ) */ public Strftime( String origFormat ) { String convertedFormat = convertDateFormat( origFormat ); simpleDateFormat = new SimpleDateFormat( convertedFormat ); } /** * Create an instance of this date formatting class * * @param origFormat the strftime-style formatting string * @param locale the locale to use for locale-specific conversions */ public Strftime( String origFormat, Locale locale ) { String convertedFormat = convertDateFormat( origFormat ); simpleDateFormat = new SimpleDateFormat( convertedFormat, locale ); } /** * Format the date according to the strftime-style string given in the constructor. * * @param date the date to format * @return the formatted date */ public String format( Date date ) { return simpleDateFormat.format( date ); } /** * Get the timezone used for formatting conversions * * @return the timezone */ public TimeZone getTimeZone() { return simpleDateFormat.getTimeZone(); } /** * Change the timezone used to format dates * * @see SimpleDateFormat#setTimeZone */ public void setTimeZone( TimeZone timeZone ) { simpleDateFormat.setTimeZone( timeZone ); } /** * Search the provided pattern and get the C standard * Date/Time formatting rules and convert them to the * Java equivalent. * * @param pattern The pattern to search * @return The modified pattern */ protected String convertDateFormat( String pattern ) { boolean inside = false; boolean mark = false; boolean modifiedCommand = false; StringBuilder buf = new StringBuilder(); for(int i = 0; i < pattern.length(); i++) { char c = pattern.charAt(i); if ( c=='%' && !mark ) { mark=true; } else { if ( mark ) { if ( modifiedCommand ) { //don't do anything--we just wanted to skip a char modifiedCommand = false; mark = false; } else { inside = translateCommand( buf, pattern, i, inside ); //It's a modifier code if ( c=='O' || c=='E' ) { modifiedCommand = true; } else { mark=false; } } } else { if ( !inside && c != ' ' ) { //We start a literal, which we need to quote buf.append("'"); inside = true; } buf.append(c); } } } if ( buf.length() > 0 ) { char lastChar = buf.charAt( buf.length() - 1 ); if( lastChar!='\'' && inside ) { buf.append('\''); } } return buf.toString(); } protected String quote( String str, boolean insideQuotes ) { String retVal = str; if ( !insideQuotes ) { retVal = '\'' + retVal + '\''; } return retVal; } /** * Try to get the Java Date/Time formatting associated with * the C standard provided. * * @param buf The buffer * @param pattern The date/time pattern * @param index The char index * @param oldInside Flag value * @return True if new is inside buffer */ protected boolean translateCommand( StringBuilder buf, String pattern, int index, boolean oldInside ) { char firstChar = pattern.charAt( index ); boolean newInside = oldInside; //O and E are modifiers, they mean to present an alternative representation of the next char //we just handle the next char as if the O or E wasn't there if ( firstChar == 'O' || firstChar == 'E' ) { if ( index + 1 < pattern.length() ) { newInside = translateCommand( buf, pattern, index + 1, oldInside ); } else { buf.append( quote("%" + firstChar, oldInside ) ); } } else { String command = translate.getProperty( String.valueOf( firstChar ) ); //If we don't find a format, treat it as a literal--That's what apache does if ( command == null ) { buf.append( quote( "%" + firstChar, oldInside ) ); } else { //If we were inside quotes, close the quotes if ( oldInside ) { buf.append( '\'' ); } buf.append( command ); newInside = false; } } return newInside; } } tomcat7-7.0.52/java/org/apache/catalina/util/ConcurrentMessageDigest.java0000644000175100017510000000664512017771634026302 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; /** * A thread safe wrapper around {@link MessageDigest} that does not make use * of ThreadLocal and - broadly - only creates enough MessageDigest objects * to satisfy the concurrency requirements. */ public class ConcurrentMessageDigest { private static final String MD5 = "MD5"; private static final Map> queues = new HashMap>(); private ConcurrentMessageDigest() { // Hide default constructor for this utility class } static { try { // Init commonly used algorithms init(MD5); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException(e); } } public static byte[] digestMD5(byte[] input) { return digest(MD5, input); } public static byte[] digest(String algorithm, byte[] input) { Queue queue = queues.get(algorithm); if (queue == null) { throw new IllegalStateException("Must call init() first"); } MessageDigest md = queue.poll(); if (md == null) { try { md = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { // Ignore. Impossible if init() has been successfully called // first. throw new IllegalStateException("Must call init() first"); } } byte[] result = md.digest(input); queue.add(md); return result; } /** * Ensures that {@link #digest(String, byte[])} will support the specified * algorithm. This method must be called and return successfully * before using {@link #digest(String, byte[])}. * * @param algorithm The message digest algorithm to be supported * * @throws NoSuchAlgorithmException If the algorithm is not supported by the * JVM */ public static void init(String algorithm) throws NoSuchAlgorithmException { synchronized (queues) { if (!queues.containsKey(algorithm)) { MessageDigest md = MessageDigest.getInstance(algorithm); Queue queue = new ConcurrentLinkedQueue(); queue.add(md); queues.put(algorithm, queue); } } } } tomcat7-7.0.52/java/org/apache/catalina/util/Enumerator.java0000644000175100017510000001101712271471332023613 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; /** * Adapter class that wraps an Enumeration around a Java2 * collection classes object Iterator so that existing APIs * returning Enumerations can easily run on top of the new collections. * Constructors are provided to easily create such wrappers. * * @author Craig R. McClanahan * @deprecated Replaced by java.util.Collections#enumeration(..) */ @Deprecated public final class Enumerator implements Enumeration { // ----------------------------------------------------------- Constructors /** * Return an Enumeration over the values of the specified Collection. * * @param collection Collection whose values should be enumerated */ public Enumerator(Collection collection) { this(collection.iterator()); } /** * Return an Enumeration over the values of the specified Collection. * * @param collection Collection whose values should be enumerated * @param clone true to clone iterator */ public Enumerator(Collection collection, boolean clone) { this(collection.iterator(), clone); } /** * Return an Enumeration over the values returned by the * specified Iterator. * * @param iterator Iterator to be wrapped */ public Enumerator(Iterator iterator) { super(); this.iterator = iterator; } /** * Return an Enumeration over the values returned by the * specified Iterator. * * @param iterator Iterator to be wrapped * @param clone true to clone iterator */ public Enumerator(Iterator iterator, boolean clone) { super(); if (!clone) { this.iterator = iterator; } else { List list = new ArrayList(); while (iterator.hasNext()) { list.add(iterator.next()); } this.iterator = list.iterator(); } } /** * Return an Enumeration over the values of the specified Map. * * @param map Map whose values should be enumerated */ public Enumerator(Map map) { this(map.values().iterator()); } /** * Return an Enumeration over the values of the specified Map. * * @param map Map whose values should be enumerated * @param clone true to clone iterator */ public Enumerator(Map map, boolean clone) { this(map.values().iterator(), clone); } // ----------------------------------------------------- Instance Variables /** * The Iterator over which the Enumeration * represented by this class actually operates. */ private Iterator iterator = null; // --------------------------------------------------------- Public Methods /** * Tests if this enumeration contains more elements. * * @return true if and only if this enumeration object * contains at least one more element to provide, false * otherwise */ @Override public boolean hasMoreElements() { return (iterator.hasNext()); } /** * Returns the next element of this enumeration if this enumeration * has at least one more element to provide. * * @return the next element of this enumeration * * @exception NoSuchElementException if no more elements exist */ @Override public T nextElement() throws NoSuchElementException { return (iterator.next()); } } tomcat7-7.0.52/java/org/apache/catalina/util/SchemaResolver.java0000644000175100017510000001003212271471332024410 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.HashMap; import org.apache.tomcat.util.digester.Digester; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * This class implements a local SAX's EntityResolver. All * DTDs and schemas used to validate the web.xml file will re-directed * to a local file stored in the servlet-api.jar and jsp-api.jar. * * @author Jean-Francois Arcand * @deprecated Use {@link org.apache.tomcat.util.descriptor.LocalResolver} */ @Deprecated public class SchemaResolver implements EntityResolver { /** * The digester instance for which this class is the entity resolver. */ protected Digester digester; /** * The URLs of dtds and schemas that have been registered, keyed by the * public identifier that corresponds. */ protected HashMap entityValidator = new HashMap(); /** * Extension to make the difference between DTD and Schema. */ protected String schemaExtension = "xsd"; /** * Create a new EntityResolver that will redirect * all remote dtds and schema to a local destination. * @param digester The digester instance. */ public SchemaResolver(Digester digester) { this.digester = digester; } /** * Register the specified DTD/Schema URL for the specified public * identifier. This must be called before the first call to * parse(). * * When adding a schema file (*.xsd), only the name of the file * will get added. If two schemas with the same name are added, * only the last one will be stored. * * @param publicId Public identifier of the DTD to be resolved * @param entityURL The URL to use for reading this DTD */ public void register(String publicId, String entityURL) { String key = publicId; if (publicId.indexOf(schemaExtension) != -1) key = publicId.substring(publicId.lastIndexOf('/')+1); entityValidator.put(key, entityURL); } /** * Resolve the requested external entity. * * @param publicId The public identifier of the entity being referenced * @param systemId The system identifier of the entity being referenced * * @exception SAXException if a parsing exception occurs * */ @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException { if (publicId != null) { digester.setPublicId(publicId); } // Has this system identifier been registered? String entityURL = null; if (publicId != null) { entityURL = entityValidator.get(publicId); } // Redirect the schema location to a local destination String key = null; if (entityURL == null && systemId != null) { key = systemId.substring(systemId.lastIndexOf('/')+1); entityURL = entityValidator.get(key); } if (entityURL == null) { return (null); } try { return (new InputSource(entityURL)); } catch (Exception e) { throw new SAXException(e); } } } tomcat7-7.0.52/java/org/apache/catalina/util/TomcatCSS.java0000644000175100017510000000312312271471332023271 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; public class TomcatCSS { public static final String TOMCAT_CSS = "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} " + "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} " + "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} " + "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " + "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} " + "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" + "A {color : black;}" + "A.name {color : black;}" + "HR {color : #525D76;}"; } tomcat7-7.0.52/java/org/apache/catalina/util/ServerInfo.properties0000644000175100017510000000155512271471332025035 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. server.info=Apache Tomcat/@VERSION@ server.number=@VERSION_NUMBER@ server.built=@VERSION_BUILT@tomcat7-7.0.52/java/org/apache/catalina/util/ParameterMap.java0000644000175100017510000001273312271471332024056 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.LinkedHashMap; import java.util.Map; import org.apache.tomcat.util.res.StringManager; /** * Extended implementation of HashMap that includes a * locked property. This class can be used to safely expose * Catalina internal parameter map objects to user classes without having * to clone them in order to avoid modifications. When first created, a * ParmaeterMap instance is not locked. * * @author Craig R. McClanahan */ public final class ParameterMap extends LinkedHashMap { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Construct a new, empty map with the default initial capacity and * load factor. */ public ParameterMap() { super(); } /** * Construct a new, empty map with the specified initial capacity and * default load factor. * * @param initialCapacity The initial capacity of this map */ public ParameterMap(int initialCapacity) { super(initialCapacity); } /** * Construct a new, empty map with the specified initial capacity and * load factor. * * @param initialCapacity The initial capacity of this map * @param loadFactor The load factor of this map */ public ParameterMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } /** * Construct a new map with the same mappings as the given map. * * @param map Map whose contents are duplicated in the new map */ public ParameterMap(Map map) { super(map); } // ------------------------------------------------------------- Properties /** * The current lock state of this parameter map. */ private boolean locked = false; /** * Return the locked state of this parameter map. */ public boolean isLocked() { return (this.locked); } /** * Set the locked state of this parameter map. * * @param locked The new locked state */ public void setLocked(boolean locked) { this.locked = locked; } /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager("org.apache.catalina.util"); // --------------------------------------------------------- Public Methods /** * Remove all mappings from this map. * * @exception IllegalStateException if this map is currently locked */ @Override public void clear() { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); super.clear(); } /** * Associate the specified value with the specified key in this map. If * the map previously contained a mapping for this key, the old value is * replaced. * * @param key Key with which the specified value is to be associated * @param value Value to be associated with the specified key * * @return The previous value associated with the specified key, or * null if there was no mapping for key * * @exception IllegalStateException if this map is currently locked */ @Override public V put(K key, V value) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); return (super.put(key, value)); } /** * Copy all of the mappings from the specified map to this one. These * mappings replace any mappings that this map had for any of the keys * currently in the specified Map. * * @param map Mappings to be stored into this map * * @exception IllegalStateException if this map is currently locked */ @Override public void putAll(Map map) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); super.putAll(map); } /** * Remove the mapping for this key from the map if present. * * @param key Key whose mapping is to be removed from the map * * @return The previous value associated with the specified key, or * null if there was no mapping for that key * * @exception IllegalStateException if this map is currently locked */ @Override public V remove(Object key) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); return (super.remove(key)); } } tomcat7-7.0.52/java/org/apache/catalina/util/LifecycleSupport.java0000644000175100017510000001036112271471332024767 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; /** * Support class to assist in firing LifecycleEvent notifications to * registered LifecycleListeners. * * @author Craig R. McClanahan */ public final class LifecycleSupport { // ----------------------------------------------------------- Constructors /** * Construct a new LifecycleSupport object associated with the specified * Lifecycle component. * * @param lifecycle The Lifecycle component that will be the source * of events that we fire */ public LifecycleSupport(Lifecycle lifecycle) { super(); this.lifecycle = lifecycle; } // ----------------------------------------------------- Instance Variables /** * The source component for lifecycle events that we will fire. */ private Lifecycle lifecycle = null; /** * The set of registered LifecycleListeners for event notifications. */ private LifecycleListener listeners[] = new LifecycleListener[0]; private final Object listenersLock = new Object(); // Lock object for changes to listeners // --------------------------------------------------------- Public Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { synchronized (listenersLock) { LifecycleListener results[] = new LifecycleListener[listeners.length + 1]; for (int i = 0; i < listeners.length; i++) results[i] = listeners[i]; results[listeners.length] = listener; listeners = results; } } /** * Get the lifecycle listeners associated with this lifecycle. If this * Lifecycle has no listeners registered, a zero-length array is returned. */ public LifecycleListener[] findLifecycleListeners() { return listeners; } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param data Event data */ public void fireLifecycleEvent(String type, Object data) { LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); LifecycleListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].lifecycleEvent(event); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to remove */ public void removeLifecycleListener(LifecycleListener listener) { synchronized (listenersLock) { int n = -1; for (int i = 0; i < listeners.length; i++) { if (listeners[i] == listener) { n = i; break; } } if (n < 0) return; LifecycleListener results[] = new LifecycleListener[listeners.length - 1]; int j = 0; for (int i = 0; i < listeners.length; i++) { if (i != n) results[j++] = listeners[i]; } listeners = results; } } } tomcat7-7.0.52/java/org/apache/catalina/util/ResourceSet.java0000644000175100017510000001075612271471332023746 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.Collection; import java.util.HashSet; import org.apache.tomcat.util.res.StringManager; /** * Extended implementation of HashSet that includes a * locked property. This class can be used to safely expose * resource path sets to user classes without having to clone them in order * to avoid modifications. When first created, a ResourceMap * is not locked. * * @author Craig R. McClanahan */ public final class ResourceSet extends HashSet { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Construct a new, empty set with the default initial capacity and * load factor. */ public ResourceSet() { super(); } /** * Construct a new, empty set with the specified initial capacity and * default load factor. * * @param initialCapacity The initial capacity of this set */ public ResourceSet(int initialCapacity) { super(initialCapacity); } /** * Construct a new, empty set with the specified initial capacity and * load factor. * * @param initialCapacity The initial capacity of this set * @param loadFactor The load factor of this set */ public ResourceSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } /** * Construct a new set with the same contents as the existing collection. * * @param coll The collection whose contents we should copy */ public ResourceSet(Collection coll) { super(coll); } // ------------------------------------------------------------- Properties /** * The current lock state of this parameter map. */ private boolean locked = false; /** * Return the locked state of this parameter map. */ public boolean isLocked() { return (this.locked); } /** * Set the locked state of this parameter map. * * @param locked The new locked state */ public void setLocked(boolean locked) { this.locked = locked; } /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager("org.apache.catalina.util"); // --------------------------------------------------------- Public Methods /** * Add the specified element to this set if it is not already present. * Return true if the element was added. * * @param o The object to be added * * @exception IllegalStateException if this ResourceSet is locked */ @Override public boolean add(T o) { if (locked) throw new IllegalStateException (sm.getString("resourceSet.locked")); return (super.add(o)); } /** * Remove all of the elements from this set. * * @exception IllegalStateException if this ResourceSet is locked */ @Override public void clear() { if (locked) throw new IllegalStateException (sm.getString("resourceSet.locked")); super.clear(); } /** * Remove the given element from this set if it is present. * Return true if the element was removed. * * @param o The object to be removed * * @exception IllegalStateException if this ResourceSet is locked */ @Override public boolean remove(Object o) { if (locked) throw new IllegalStateException (sm.getString("resourceSet.locked")); return (super.remove(o)); } } tomcat7-7.0.52/java/org/apache/catalina/util/CustomObjectInputStream.java0000644000175100017510000000712412271471332026273 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.lang.reflect.Proxy; /** * Custom subclass of ObjectInputStream that loads from the * class loader for this web application. This allows classes defined only * with the web application to be found correctly. * * @author Craig R. McClanahan * @author Bip Thelin */ public final class CustomObjectInputStream extends ObjectInputStream { /** * The class loader we will use to resolve classes. */ private ClassLoader classLoader = null; /** * Construct a new instance of CustomObjectInputStream * * @param stream The input stream we will read from * @param classLoader The class loader used to instantiate objects * * @exception IOException if an input/output error occurs */ public CustomObjectInputStream(InputStream stream, ClassLoader classLoader) throws IOException { super(stream); this.classLoader = classLoader; } /** * Load the local class equivalent of the specified stream class * description, by using the class loader assigned to this Context. * * @param classDesc Class description from the input stream * * @exception ClassNotFoundException if this class cannot be found * @exception IOException if an input/output error occurs */ @Override public Class resolveClass(ObjectStreamClass classDesc) throws ClassNotFoundException, IOException { try { return Class.forName(classDesc.getName(), false, classLoader); } catch (ClassNotFoundException e) { try { // Try also the superclass because of primitive types return super.resolveClass(classDesc); } catch (ClassNotFoundException e2) { // Rethrow original exception, as it can have more information // about why the class was not found. BZ 48007 throw e; } } } /** * Return a proxy class that implements the interfaces named in a proxy * class descriptor. Do this using the class loader assigned to this * Context. */ @Override protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { Class[] cinterfaces = new Class[interfaces.length]; for (int i = 0; i < interfaces.length; i++) cinterfaces[i] = classLoader.loadClass(interfaces[i]); try { return Proxy.getProxyClass(classLoader, cinterfaces); } catch (IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } } } tomcat7-7.0.52/java/org/apache/catalina/util/ManifestResource.java0000644000175100017510000001774312271471332024764 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.ArrayList; import java.util.Iterator; import java.util.jar.Attributes; import java.util.jar.Manifest; /** * Representation of a Manifest file and its available extensions and * required extensions * * @author Greg Murray * @author Justyna Horwat */ public class ManifestResource { // ------------------------------------------------------------- Properties // These are the resource types for determining effect error messages public static final int SYSTEM = 1; public static final int WAR = 2; public static final int APPLICATION = 3; private ArrayList availableExtensions = null; private ArrayList requiredExtensions = null; private String resourceName = null; private int resourceType = -1; public ManifestResource(String resourceName, Manifest manifest, int resourceType) { this.resourceName = resourceName; this.resourceType = resourceType; processManifest(manifest); } /** * Gets the name of the resource * * @return The name of the resource */ public String getResourceName() { return resourceName; } /** * Gets the list of available extensions * * @return List of available extensions */ public ArrayList getAvailableExtensions() { return availableExtensions; } /** * Gets the list of required extensions * * @return List of required extensions */ public ArrayList getRequiredExtensions() { return requiredExtensions; } // --------------------------------------------------------- Public Methods /** * Gets the number of available extensions * * @return The number of available extensions */ public int getAvailableExtensionCount() { return (availableExtensions != null) ? availableExtensions.size() : 0; } /** * Gets the number of required extensions * * @return The number of required extensions */ public int getRequiredExtensionCount() { return (requiredExtensions != null) ? requiredExtensions.size() : 0; } /** * Convenience method to check if this ManifestResource * has an requires extensions. * * @return true if required extensions are present */ public boolean requiresExtensions() { return (requiredExtensions != null) ? true : false; } /** * Returns true if all required extension dependencies * have been meet for this ManifestResource object. * * @return boolean true if all extension dependencies have been satisfied */ public boolean isFulfilled() { if (requiredExtensions == null) { return true; } Iterator it = requiredExtensions.iterator(); while (it.hasNext()) { Extension ext = it.next(); if (!ext.isFulfilled()) return false; } return true; } @Override public String toString() { StringBuilder sb = new StringBuilder("ManifestResource["); sb.append(resourceName); sb.append(", isFulfilled="); sb.append(isFulfilled() +""); sb.append(", requiredExtensionCount ="); sb.append(getRequiredExtensionCount()); sb.append(", availableExtensionCount="); sb.append(getAvailableExtensionCount()); switch (resourceType) { case SYSTEM : sb.append(", resourceType=SYSTEM"); break; case WAR : sb.append(", resourceType=WAR"); break; case APPLICATION : sb.append(", resourceType=APPLICATION"); break; } sb.append("]"); return (sb.toString()); } // -------------------------------------------------------- Private Methods private void processManifest(Manifest manifest) { availableExtensions = getAvailableExtensions(manifest); requiredExtensions = getRequiredExtensions(manifest); } /** * Return the set of Extension objects representing optional * packages that are required by the application associated with the * specified Manifest. * * @param manifest Manifest to be parsed * * @return List of required extensions, or null if the application * does not require any extensions */ private ArrayList getRequiredExtensions(Manifest manifest) { Attributes attributes = manifest.getMainAttributes(); String names = attributes.getValue("Extension-List"); if (names == null) return null; ArrayList extensionList = new ArrayList(); names += " "; while (true) { int space = names.indexOf(' '); if (space < 0) break; String name = names.substring(0, space).trim(); names = names.substring(space + 1); String value = attributes.getValue(name + "-Extension-Name"); if (value == null) continue; Extension extension = new Extension(); extension.setExtensionName(value); extension.setImplementationURL (attributes.getValue(name + "-Implementation-URL")); extension.setImplementationVendorId (attributes.getValue(name + "-Implementation-Vendor-Id")); String version = attributes.getValue(name + "-Implementation-Version"); extension.setImplementationVersion(version); extension.setSpecificationVersion (attributes.getValue(name + "-Specification-Version")); extensionList.add(extension); } return extensionList; } /** * Return the set of Extension objects representing optional * packages that are bundled with the application associated with the * specified Manifest. * * @param manifest Manifest to be parsed * * @return List of available extensions, or null if the web application * does not bundle any extensions */ private ArrayList getAvailableExtensions(Manifest manifest) { Attributes attributes = manifest.getMainAttributes(); String name = attributes.getValue("Extension-Name"); if (name == null) return null; ArrayList extensionList = new ArrayList(); Extension extension = new Extension(); extension.setExtensionName(name); extension.setImplementationURL( attributes.getValue("Implementation-URL")); extension.setImplementationVendor( attributes.getValue("Implementation-Vendor")); extension.setImplementationVendorId( attributes.getValue("Implementation-Vendor-Id")); extension.setImplementationVersion( attributes.getValue("Implementation-Version")); extension.setSpecificationVersion( attributes.getValue("Specification-Version")); extensionList.add(extension); return extensionList; } } tomcat7-7.0.52/java/org/apache/catalina/util/CharsetMapperDefault.properties0000644000175100017510000000145212271471332027012 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. en=ISO-8859-1 fr=ISO-8859-1 tomcat7-7.0.52/java/org/apache/catalina/util/URLEncoder.java0000644000175100017510000000664612271471332023450 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.BitSet; /** * * This class is very similar to the java.net.URLEncoder class. * * Unfortunately, with java.net.URLEncoder there is no way to specify to the * java.net.URLEncoder which characters should NOT be encoded. * * This code was moved from DefaultServlet.java * * @author Craig R. McClanahan * @author Remy Maucherat */ public class URLEncoder { protected static final char[] hexadecimal = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; //Array containing the safe characters set. protected BitSet safeCharacters = new BitSet(256); public URLEncoder() { for (char i = 'a'; i <= 'z'; i++) { addSafeCharacter(i); } for (char i = 'A'; i <= 'Z'; i++) { addSafeCharacter(i); } for (char i = '0'; i <= '9'; i++) { addSafeCharacter(i); } } public void addSafeCharacter( char c ) { safeCharacters.set( c ); } public String encode( String path ) { int maxBytesPerChar = 10; StringBuilder rewrittenPath = new StringBuilder(path.length()); ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar); OutputStreamWriter writer = null; try { writer = new OutputStreamWriter(buf, "UTF8"); } catch (Exception e) { e.printStackTrace(); writer = new OutputStreamWriter(buf); } for (int i = 0; i < path.length(); i++) { int c = path.charAt(i); if (safeCharacters.get(c)) { rewrittenPath.append((char)c); } else { // convert to external encoding before hex conversion try { writer.write((char)c); writer.flush(); } catch(IOException e) { buf.reset(); continue; } byte[] ba = buf.toByteArray(); for (int j = 0; j < ba.length; j++) { // Converting each byte in the buffer byte toEncode = ba[j]; rewrittenPath.append('%'); int low = toEncode & 0x0f; int high = (toEncode & 0xf0) >> 4; rewrittenPath.append(hexadecimal[high]); rewrittenPath.append(hexadecimal[low]); } buf.reset(); } } return rewrittenPath.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/util/DOMWriter.java0000644000175100017510000002540512271471332023314 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * A sample DOM writer. This sample program illustrates how to * traverse a DOM tree in order to print a document that is parsed. */ public class DOMWriter { // // Data // /** Default Encoding */ private static String PRINTWRITER_ENCODING = "UTF8"; private static String MIME2JAVA_ENCODINGS[] = { "Default", "UTF-8", "US-ASCII", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-2022-JP", "SHIFT_JIS", "EUC-JP","GB2312", "BIG5", "EUC-KR", "ISO-2022-KR", "KOI8-R", "EBCDIC-CP-US", "EBCDIC-CP-CA", "EBCDIC-CP-NL", "EBCDIC-CP-DK", "EBCDIC-CP-NO", "EBCDIC-CP-FI", "EBCDIC-CP-SE", "EBCDIC-CP-IT", "EBCDIC-CP-ES", "EBCDIC-CP-GB", "EBCDIC-CP-FR", "EBCDIC-CP-AR1", "EBCDIC-CP-HE", "EBCDIC-CP-CH", "EBCDIC-CP-ROECE","EBCDIC-CP-YU", "EBCDIC-CP-IS", "EBCDIC-CP-AR2", "UTF-16" }; /** Output qualified names */ private boolean qualifiedNames = true; /** Print writer. */ protected PrintWriter out; /** Canonical output. */ protected boolean canonical; /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public DOMWriter(String encoding, boolean canonical) throws UnsupportedEncodingException { out = new PrintWriter(new OutputStreamWriter(System.out, encoding)); this.canonical = canonical; } // (String,boolean) // // Constructors // /** * Default constructor. * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public DOMWriter(boolean canonical) throws UnsupportedEncodingException { this( getWriterEncoding(), canonical); } public DOMWriter(Writer writer, boolean canonical) { out = new PrintWriter(writer); this.canonical = canonical; } /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public boolean getQualifiedNames() { return this.qualifiedNames; } /** * @deprecated Unnecessary - will be removed in 8.0.x */ @Deprecated public void setQualifiedNames(boolean qualifiedNames) { this.qualifiedNames = qualifiedNames; } public static String getWriterEncoding( ) { return (PRINTWRITER_ENCODING); }// getWriterEncoding /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static void setWriterEncoding( String encoding ) { if( encoding.equalsIgnoreCase( "DEFAULT" ) ) PRINTWRITER_ENCODING = "UTF8"; else if( encoding.equalsIgnoreCase( "UTF-16" ) ) PRINTWRITER_ENCODING = "Unicode"; else PRINTWRITER_ENCODING = MIME2Java.convert( encoding ); }// setWriterEncoding /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static boolean isValidJavaEncoding( String encoding ) { for ( int i = 0; i < MIME2JAVA_ENCODINGS.length; i++ ) if ( encoding.equals( MIME2JAVA_ENCODINGS[i] ) ) return (true); return (false); }// isValidJavaEncoding /** Prints the specified node, recursively. */ public void print(Node node) { // is there anything to do? if ( node == null ) { return; } int type = node.getNodeType(); switch ( type ) { // print document case Node.DOCUMENT_NODE: { if ( !canonical ) { String Encoding = getWriterEncoding(); if( Encoding.equalsIgnoreCase( "DEFAULT" ) ) Encoding = "UTF-8"; else if( Encoding.equalsIgnoreCase( "Unicode" ) ) Encoding = "UTF-16"; else Encoding = MIME2Java.reverse( Encoding ); out.println(""); } print(((Document)node).getDocumentElement()); out.flush(); break; } // print element with attributes case Node.ELEMENT_NODE: { out.print('<'); if (this.qualifiedNames) { out.print(node.getNodeName()); } else { out.print(node.getLocalName()); } Attr attrs[] = sortAttributes(node.getAttributes()); for ( int i = 0; i < attrs.length; i++ ) { Attr attr = attrs[i]; out.print(' '); if (this.qualifiedNames) { out.print(attr.getNodeName()); } else { out.print(attr.getLocalName()); } out.print("=\""); out.print(normalize(attr.getNodeValue())); out.print('"'); } out.print('>'); NodeList children = node.getChildNodes(); if ( children != null ) { int len = children.getLength(); for ( int i = 0; i < len; i++ ) { print(children.item(i)); } } break; } // handle entity reference nodes case Node.ENTITY_REFERENCE_NODE: { if ( canonical ) { NodeList children = node.getChildNodes(); if ( children != null ) { int len = children.getLength(); for ( int i = 0; i < len; i++ ) { print(children.item(i)); } } } else { out.print('&'); if (this.qualifiedNames) { out.print(node.getNodeName()); } else { out.print(node.getLocalName()); } out.print(';'); } break; } // print cdata sections case Node.CDATA_SECTION_NODE: { if ( canonical ) { out.print(normalize(node.getNodeValue())); } else { out.print(""); } break; } // print text case Node.TEXT_NODE: { out.print(normalize(node.getNodeValue())); break; } // print processing instruction case Node.PROCESSING_INSTRUCTION_NODE: { out.print(" 0 ) { out.print(' '); out.print(data); } out.print("?>"); break; } } if ( type == Node.ELEMENT_NODE ) { out.print("'); } out.flush(); } // print(Node) /** Returns a sorted list of attributes. */ protected Attr[] sortAttributes(NamedNodeMap attrs) { if (attrs == null) { return new Attr[0]; } int len = attrs.getLength(); Attr array[] = new Attr[len]; for ( int i = 0; i < len; i++ ) { array[i] = (Attr)attrs.item(i); } for ( int i = 0; i < len - 1; i++ ) { String name = null; if (this.qualifiedNames) { name = array[i].getNodeName(); } else { name = array[i].getLocalName(); } int index = i; for ( int j = i + 1; j < len; j++ ) { String curName = null; if (this.qualifiedNames) { curName = array[j].getNodeName(); } else { curName = array[j].getLocalName(); } if ( curName.compareTo(name) < 0 ) { name = curName; index = j; } } if ( index != i ) { Attr temp = array[i]; array[i] = array[index]; array[index] = temp; } } return (array); } // sortAttributes(NamedNodeMap):Attr[] /** Normalizes the given string. */ protected String normalize(String s) { if (s == null) { return ""; } StringBuilder str = new StringBuilder(); int len = s.length(); for ( int i = 0; i < len; i++ ) { char ch = s.charAt(i); switch ( ch ) { case '<': { str.append("<"); break; } case '>': { str.append(">"); break; } case '&': { str.append("&"); break; } case '"': { str.append("""); break; } case '\r': case '\n': { if ( canonical ) { str.append("&#"); str.append(Integer.toString(ch)); str.append(';'); break; } // else, default append char } //$FALL-THROUGH$ default: { str.append(ch); } } } return (str.toString()); } // normalize(String):String } tomcat7-7.0.52/java/org/apache/catalina/util/Conversions.java0000644000175100017510000000257011730473463024014 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.IOException; public class Conversions { private Conversions() { // Utility class. Hide default constructor. } public static long byteArrayToLong(byte[] input) throws IOException { if (input.length > 8) { // TODO: Better message throw new IOException(); } int shift = 0; long result = 0; for (int i = input.length - 1; i >= 0; i--) { result = result + ((input[i] & 0xFF) << shift); shift += 8; } return result; } } tomcat7-7.0.52/java/org/apache/catalina/util/DateTool.java0000644000175100017510000000737712271471332023223 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.TimeZone; /** * Common place for date utils. * * @author dac@eng.sun.com * @author Jason Hunter [jch@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Costin Manolache * @author fhanik * * @deprecated Mostly unused and will be removed in 8.0.x onwards */ @Deprecated public class DateTool { /** * US locale - all HTTP dates are in English * @deprecated Use {@link Locale#US} */ @Deprecated public static final Locale LOCALE_US = Locale.US; /** * GMT timezone - all HTTP dates are on GMT */ public static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); /** * format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT" */ public static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; /** * Format for http response header date field */ public static final String HTTP_RESPONSE_DATE_HEADER = "EEE, dd MMM yyyy HH:mm:ss zzz"; // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT" private static final String rfc1036Pattern = "EEEEEEEEE, dd-MMM-yy HH:mm:ss z"; // format for C asctime() date string -- "Sun Nov 6 08:49:37 1994" private static final String asctimePattern = "EEE MMM d HH:mm:ss yyyyy"; /** * Pattern used for old cookies */ public static final String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; /** * DateFormat to be used to format dates */ public static final ThreadLocal rfc1123Format = new ThreadLocal() { @Override public DateFormat initialValue() { DateFormat result = new SimpleDateFormat(RFC1123_PATTERN, Locale.US); result.setTimeZone(GMT_ZONE); return result; } }; /** * DateFormat to be used to format old netscape cookies */ public static final ThreadLocal oldCookieFormat = new ThreadLocal() { @Override public DateFormat initialValue() { DateFormat result = new SimpleDateFormat(OLD_COOKIE_PATTERN, Locale.US); result.setTimeZone(GMT_ZONE); return result; } }; public static final ThreadLocal rfc1036Format = new ThreadLocal() { @Override public DateFormat initialValue() { DateFormat result = new SimpleDateFormat(rfc1036Pattern, Locale.US); result.setTimeZone(GMT_ZONE); return result; } }; public static final ThreadLocal asctimeFormat = new ThreadLocal() { @Override public DateFormat initialValue() { DateFormat result = new SimpleDateFormat(asctimePattern, Locale.US); result.setTimeZone(GMT_ZONE); return result; } }; } tomcat7-7.0.52/java/org/apache/catalina/util/LifecycleBase.java0000644000175100017510000003332112050050143024152 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.LifecycleState; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Base implementation of the {@link Lifecycle} interface that implements the * state transition rules for {@link Lifecycle#start()} and * {@link Lifecycle#stop()} */ public abstract class LifecycleBase implements Lifecycle { private static Log log = LogFactory.getLog(LifecycleBase.class); private static StringManager sm = StringManager.getManager("org.apache.catalina.util"); /** * Used to handle firing lifecycle events. * TODO: Consider merging LifecycleSupport into this class. */ private LifecycleSupport lifecycle = new LifecycleSupport(this); /** * The current state of the source component. */ private volatile LifecycleState state = LifecycleState.NEW; /** * {@inheritDoc} */ @Override public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * {@inheritDoc} */ @Override public LifecycleListener[] findLifecycleListeners() { return lifecycle.findLifecycleListeners(); } /** * {@inheritDoc} */ @Override public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Allow sub classes to fire {@link Lifecycle} events. * * @param type Event type * @param data Data associated with event. */ protected void fireLifecycleEvent(String type, Object data) { lifecycle.fireLifecycleEvent(type, data); } @Override public final synchronized void init() throws LifecycleException { if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } setStateInternal(LifecycleState.INITIALIZING, null, false); try { initInternal(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.initFail",toString()), t); } setStateInternal(LifecycleState.INITIALIZED, null, false); } protected abstract void initInternal() throws LifecycleException; /** * {@inheritDoc} */ @Override public final synchronized void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init(); } else if (state.equals(LifecycleState.FAILED)){ stop(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } setStateInternal(LifecycleState.STARTING_PREP, null, false); try { startInternal(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.startFail",toString()), t); } if (state.equals(LifecycleState.FAILED) || state.equals(LifecycleState.MUST_STOP)) { stop(); } else { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. if (!state.equals(LifecycleState.STARTING)) { invalidTransition(Lifecycle.AFTER_START_EVENT); } setStateInternal(LifecycleState.STARTED, null, false); } } /** * Sub-classes must ensure that the state is changed to * {@link LifecycleState#STARTING} during the execution of this method. * Changing state will trigger the {@link Lifecycle#START_EVENT} event. * * If a component fails to start it may either throw a * {@link LifecycleException} which will cause it's parent to fail to start * or it can place itself in the error state in which case {@link #stop()} * will be called on the failed component but the parent component will * continue to start normally. * * @throws LifecycleException */ protected abstract void startInternal() throws LifecycleException; /** * {@inheritDoc} */ @Override public final synchronized void stop() throws LifecycleException { if (LifecycleState.STOPPING_PREP.equals(state) || LifecycleState.STOPPING.equals(state) || LifecycleState.STOPPED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStopped", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStopped", toString())); } return; } if (state.equals(LifecycleState.NEW)) { state = LifecycleState.STOPPED; return; } if (!state.equals(LifecycleState.STARTED) && !state.equals(LifecycleState.FAILED) && !state.equals(LifecycleState.MUST_STOP)) { invalidTransition(Lifecycle.BEFORE_STOP_EVENT); } if (state.equals(LifecycleState.FAILED)) { // Don't transition to STOPPING_PREP as that would briefly mark the // component as available but do ensure the BEFORE_STOP_EVENT is // fired fireLifecycleEvent(BEFORE_STOP_EVENT, null); } else { setStateInternal(LifecycleState.STOPPING_PREP, null, false); } try { stopInternal(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.stopFail",toString()), t); } if (state.equals(LifecycleState.MUST_DESTROY)) { // Complete stop process first setStateInternal(LifecycleState.STOPPED, null, false); destroy(); } else if (!state.equals(LifecycleState.FAILED)){ // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. if (!state.equals(LifecycleState.STOPPING)) { invalidTransition(Lifecycle.AFTER_STOP_EVENT); } setStateInternal(LifecycleState.STOPPED, null, false); } } /** * Sub-classes must ensure that the state is changed to * {@link LifecycleState#STOPPING} during the execution of this method. * Changing state will trigger the {@link Lifecycle#STOP_EVENT} event. * * @throws LifecycleException */ protected abstract void stopInternal() throws LifecycleException; @Override public final synchronized void destroy() throws LifecycleException { if (LifecycleState.FAILED.equals(state)) { try { // Triggers clean-up stop(); } catch (LifecycleException e) { // Just log. Still want to destroy. log.warn(sm.getString( "lifecycleBase.destroyStopFail", toString()), e); } } if (LifecycleState.DESTROYING.equals(state) || LifecycleState.DESTROYED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyDestroyed", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyDestroyed", toString())); } return; } if (!state.equals(LifecycleState.STOPPED) && !state.equals(LifecycleState.FAILED) && !state.equals(LifecycleState.NEW) && !state.equals(LifecycleState.INITIALIZED)) { invalidTransition(Lifecycle.BEFORE_DESTROY_EVENT); } setStateInternal(LifecycleState.DESTROYING, null, false); try { destroyInternal(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.destroyFail",toString()), t); } setStateInternal(LifecycleState.DESTROYED, null, false); } protected abstract void destroyInternal() throws LifecycleException; /** * {@inheritDoc} */ @Override public LifecycleState getState() { return state; } /** * {@inheritDoc} */ @Override public String getStateName() { return getState().toString(); } /** * Provides a mechanism for sub-classes to update the component state. * Calling this method will automatically fire any associated * {@link Lifecycle} event. It will also check that any attempted state * transition is valid for a sub-class. * * @param state The new state for this component */ protected synchronized void setState(LifecycleState state) throws LifecycleException { setStateInternal(state, null, true); } /** * Provides a mechanism for sub-classes to update the component state. * Calling this method will automatically fire any associated * {@link Lifecycle} event. It will also check that any attempted state * transition is valid for a sub-class. * * @param state The new state for this component * @param data The data to pass to the associated {@link Lifecycle} event */ protected synchronized void setState(LifecycleState state, Object data) throws LifecycleException { setStateInternal(state, data, true); } private synchronized void setStateInternal(LifecycleState state, Object data, boolean check) throws LifecycleException { if (log.isDebugEnabled()) { log.debug(sm.getString("lifecycleBase.setState", this, state)); } if (check) { // Must have been triggered by one of the abstract methods (assume // code in this class is correct) // null is never a valid state if (state == null) { invalidTransition("null"); // Unreachable code - here to stop eclipse complaining about // a possible NPE further down the method return; } // Any method can transition to failed // startInternal() permits STARTING_PREP to STARTING // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to // STOPPING if (!(state == LifecycleState.FAILED || (this.state == LifecycleState.STARTING_PREP && state == LifecycleState.STARTING) || (this.state == LifecycleState.STOPPING_PREP && state == LifecycleState.STOPPING) || (this.state == LifecycleState.FAILED && state == LifecycleState.STOPPING))) { // No other transition permitted invalidTransition(state.name()); } } this.state = state; String lifecycleEvent = state.getLifecycleEvent(); if (lifecycleEvent != null) { fireLifecycleEvent(lifecycleEvent, data); } } private void invalidTransition(String type) throws LifecycleException { String msg = sm.getString("lifecycleBase.invalidTransition", type, toString(), state); throw new LifecycleException(msg); } } tomcat7-7.0.52/java/org/apache/catalina/util/LifecycleMBeanBase.java0000644000175100017510000001674311524251416025101 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import javax.management.InstanceNotFoundException; import javax.management.MBeanRegistration; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; public abstract class LifecycleMBeanBase extends LifecycleBase implements MBeanRegistration { private static Log log = LogFactory.getLog(LifecycleMBeanBase.class); private static StringManager sm = StringManager.getManager("org.apache.catalina.util"); /* Cache components of the MBean registration. */ private String domain = null; private ObjectName oname = null; protected MBeanServer mserver = null; /** * Sub-classes wishing to perform additional initialization should override * this method, ensuring that super.initInternal() is the first call in the * overriding method. */ @Override protected void initInternal() throws LifecycleException { // If oname is not null then registration has already happened via // preRegister(). if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); oname = register(this, getObjectNameKeyProperties()); } } /** * Sub-classes wishing to perform additional clean-up should override this * method, ensuring that super.destroyInternal() is the last call in the * overriding method. */ @Override protected void destroyInternal() throws LifecycleException { unregister(oname); } /** * Specify the domain under which this component should be registered. Used * with components that cannot (easily) navigate the component hierarchy to * determine the correct domain to use. */ public final void setDomain(String domain) { this.domain = domain; } /** * Obtain the domain under which this component will be / has been * registered. */ public final String getDomain() { if (domain == null) { domain = getDomainInternal(); } if (domain == null) { domain = Globals.DEFAULT_MBEAN_DOMAIN; } return domain; } /** * Method implemented by sub-classes to identify the domain in which MBeans * should be registered. * * @return The name of the domain to use to register MBeans. */ protected abstract String getDomainInternal(); /** * Obtain the name under which this component has been registered with JMX. */ public final ObjectName getObjectName() { return oname; } /** * Allow sub-classes to specify the key properties component of the * {@link ObjectName} that will be used to register this component. * * @return The string representation of the key properties component of the * desired {@link ObjectName} */ protected abstract String getObjectNameKeyProperties(); /** * Utility method to enable sub-classes to easily register additional * components that don't implement {@link MBeanRegistration} with * an MBean server.
    * Note: This method should only be used once {@link #initInternal()} has * been called and before {@link #destroyInternal()} has been called. * * @param obj The object the register * @param objectNameKeyProperties The key properties component of the * object name to use to register the * object * * @return The name used to register the object */ protected final ObjectName register(Object obj, String objectNameKeyProperties) { // Construct an object name with the right domain StringBuilder name = new StringBuilder(getDomain()); name.append(':'); name.append(objectNameKeyProperties); ObjectName on = null; try { on = new ObjectName(name.toString()); Registry.getRegistry(null, null).registerComponent(obj, on, null); } catch (MalformedObjectNameException e) { log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name), e); } catch (Exception e) { log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name), e); } return on; } /** * Utility method to enable sub-classes to easily unregister additional * components that don't implement {@link MBeanRegistration} with * an MBean server.
    * Note: This method should only be used once {@link #initInternal()} has * been called and before {@link #destroyInternal()} has been called. * * @param on The name of the component to unregister */ protected final void unregister(ObjectName on) { // If null ObjectName, just return without complaint if (on == null) { return; } // If the MBeanServer is null, log a warning & return if (mserver == null) { log.warn(sm.getString("lifecycleMBeanBase.unregisterNoServer", on)); return; } try { mserver.unregisterMBean(on); } catch (MBeanRegistrationException e) { log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e); } catch (InstanceNotFoundException e) { log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e); } } /** * Not used - NOOP. */ @Override public final void postDeregister() { // NOOP } /** * Not used - NOOP. */ @Override public final void postRegister(Boolean registrationDone) { // NOOP } /** * Not used - NOOP. */ @Override public final void preDeregister() throws Exception { // NOOP } /** * Allows the object to be registered with an alternative * {@link MBeanServer} and/or {@link ObjectName}. */ @Override public final ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { this.mserver = server; this.oname = name; this.domain = name.getDomain(); return oname; } } tomcat7-7.0.52/java/org/apache/catalina/util/StringParser.java0000644000175100017510000002007412271471332024120 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; /** * Utility class for string parsing that is higher performance than * StringParser for simple delimited text cases. Parsing is performed * by setting the string, and then using the findXxxx() and * skipXxxx() families of methods to remember significant * offsets. To retrieve the parsed substrings, call the extract() * method with the appropriate saved offset values. * * @author Craig R. McClanahan */ public final class StringParser { // ----------------------------------------------------------- Constructors /** * Construct a string parser with no preset string to be parsed. */ public StringParser() { this(null); } /** * Construct a string parser that is initialized to parse the specified * string. * * @param string The string to be parsed */ public StringParser(String string) { super(); setString(string); } // ----------------------------------------------------- Instance Variables /** * The characters of the current string, as a character array. Stored * when the string is first specified to speed up access to characters * being compared during parsing. */ private char chars[] = null; /** * The zero-relative index of the current point at which we are * positioned within the string being parsed. NOTE: * the value of this index can be one larger than the index of the last * character of the string (i.e. equal to the string length) if you * parse off the end of the string. This value is useful for extracting * substrings that include the end of the string. */ private int index = 0; /** * The length of the String we are currently parsing. Stored when the * string is first specified to avoid repeated recalculations. */ private int length = 0; /** * The String we are currently parsing. */ private String string = null; // ------------------------------------------------------------- Properties /** * Return the zero-relative index of our current parsing position * within the string being parsed. */ public int getIndex() { return (this.index); } /** * Return the length of the string we are parsing. */ public int getLength() { return (this.length); } /** * Return the String we are currently parsing. */ public String getString() { return (this.string); } /** * Set the String we are currently parsing. The parser state is also reset * to begin at the start of this string. * * @param string The string to be parsed. */ public void setString(String string) { this.string = string; if (string != null) { this.length = string.length(); chars = this.string.toCharArray(); } else { this.length = 0; chars = new char[0]; } reset(); } // --------------------------------------------------------- Public Methods /** * Advance the current parsing position by one, if we are not already * past the end of the string. */ public void advance() { if (index < length) index++; } /** * Extract and return a substring that starts at the specified position, * and extends to the end of the string being parsed. If this is not * possible, a zero-length string is returned. * * @param start Starting index, zero relative, inclusive */ public String extract(int start) { if ((start < 0) || (start >= length)) return (""); else return (string.substring(start)); } /** * Extract and return a substring that starts at the specified position, * and ends at the character before the specified position. If this is * not possible, a zero-length string is returned. * * @param start Starting index, zero relative, inclusive * @param end Ending index, zero relative, exclusive */ public String extract(int start, int end) { if ((start < 0) || (start >= end) || (end > length)) return (""); else return (string.substring(start, end)); } /** * Return the index of the next occurrence of the specified character, * or the index of the character after the last position of the string * if no more occurrences of this character are found. The current * parsing position is updated to the returned value. * * @param ch Character to be found */ public int findChar(char ch) { while ((index < length) && (ch != chars[index])) index++; return (index); } /** * Return the index of the next occurrence of a non-whitespace character, * or the index of the character after the last position of the string * if no more non-whitespace characters are found. The current * parsing position is updated to the returned value. */ public int findText() { while ((index < length) && isWhite(chars[index])) index++; return (index); } /** * Return the index of the next occurrence of a whitespace character, * or the index of the character after the last position of the string * if no more whitespace characters are found. The current parsing * position is updated to the returned value. */ public int findWhite() { while ((index < length) && !isWhite(chars[index])) index++; return (index); } /** * Reset the current state of the parser to the beginning of the * current string being parsed. */ public void reset() { index = 0; } /** * Advance the current parsing position while it is pointing at the * specified character, or until it moves past the end of the string. * Return the final value. * * @param ch Character to be skipped */ public int skipChar(char ch) { while ((index < length) && (ch == chars[index])) index++; return (index); } /** * Advance the current parsing position while it is pointing at a * non-whitespace character, or until it moves past the end of the string. * Return the final value. */ public int skipText() { while ((index < length) && !isWhite(chars[index])) index++; return (index); } /** * Advance the current parsing position while it is pointing at a * whitespace character, or until it moves past the end of the string. * Return the final value. */ public int skipWhite() { while ((index < length) && isWhite(chars[index])) index++; return (index); } // ------------------------------------------------------ Protected Methods /** * Is the specified character considered to be whitespace? * * @param ch Character to be checked */ protected boolean isWhite(char ch) { if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')) return (true); else return (false); } } tomcat7-7.0.52/java/org/apache/catalina/util/XMLWriter.java0000644000175100017510000001363212271471332023334 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.IOException; import java.io.Writer; /** * XMLWriter helper class. * * @author Remy Maucherat */ public class XMLWriter { // -------------------------------------------------------------- Constants /** * Opening tag. */ public static final int OPENING = 0; /** * Closing tag. */ public static final int CLOSING = 1; /** * Element with no content. */ public static final int NO_CONTENT = 2; // ----------------------------------------------------- Instance Variables /** * Buffer. */ protected StringBuilder buffer = new StringBuilder(); /** * Writer. */ protected Writer writer = null; // ----------------------------------------------------------- Constructors /** * Constructor. */ public XMLWriter() { } /** * Constructor. */ public XMLWriter(Writer writer) { this.writer = writer; } // --------------------------------------------------------- Public Methods /** * Retrieve generated XML. * * @return String containing the generated XML */ @Override public String toString() { return buffer.toString(); } /** * Write property to the XML. * * @param namespace Namespace * @param namespaceInfo Namespace info * @param name Property name * @param value Property value */ public void writeProperty(String namespace, String namespaceInfo, String name, String value) { writeElement(namespace, namespaceInfo, name, OPENING); buffer.append(value); writeElement(namespace, namespaceInfo, name, CLOSING); } /** * Write property to the XML. * * @param namespace Namespace * @param name Property name * @param value Property value */ public void writeProperty(String namespace, String name, String value) { writeElement(namespace, name, OPENING); buffer.append(value); writeElement(namespace, name, CLOSING); } /** * Write property to the XML. * * @param namespace Namespace * @param name Property name */ public void writeProperty(String namespace, String name) { writeElement(namespace, name, NO_CONTENT); } /** * Write an element. * * @param name Element name * @param namespace Namespace abbreviation * @param type Element type */ public void writeElement(String namespace, String name, int type) { writeElement(namespace, null, name, type); } /** * Write an element. * * @param namespace Namespace abbreviation * @param namespaceInfo Namespace info * @param name Element name * @param type Element type */ public void writeElement(String namespace, String namespaceInfo, String name, int type) { if ((namespace != null) && (namespace.length() > 0)) { switch (type) { case OPENING: if (namespaceInfo != null) { buffer.append("<" + namespace + ":" + name + " xmlns:" + namespace + "=\"" + namespaceInfo + "\">"); } else { buffer.append("<" + namespace + ":" + name + ">"); } break; case CLOSING: buffer.append("\n"); break; case NO_CONTENT: default: if (namespaceInfo != null) { buffer.append("<" + namespace + ":" + name + " xmlns:" + namespace + "=\"" + namespaceInfo + "\"/>"); } else { buffer.append("<" + namespace + ":" + name + "/>"); } break; } } else { switch (type) { case OPENING: buffer.append("<" + name + ">"); break; case CLOSING: buffer.append("\n"); break; case NO_CONTENT: default: buffer.append("<" + name + "/>"); break; } } } /** * Write text. * * @param text Text to append */ public void writeText(String text) { buffer.append(text); } /** * Write data. * * @param data Data to append */ public void writeData(String data) { buffer.append(""); } /** * Write XML Header. */ public void writeXMLHeader() { buffer.append("\n"); } /** * Send data and reinitializes buffer. */ public void sendData() throws IOException { if (writer != null) { writer.write(buffer.toString()); buffer = new StringBuilder(); } } } tomcat7-7.0.52/java/org/apache/catalina/util/LocalStrings.properties0000644000175100017510000000731012271471332025352 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. parameterMap.locked=No modifications are allowed to a locked ParameterMap resourceSet.locked=No modifications are allowed to a locked ResourceSet hexUtil.bad=Bad hexadecimal digit hexUtil.odd=Odd number of hexadecimal digits #Default Messages Utilized by the ExtensionValidator extensionValidator.web-application-manifest=Web Application Manifest extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension [{2}] not found. extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failure to find [{1}] required extension(s). extensionValidator.failload=Failure loading extension [{0}] introspection.classLoadFailed=Failed to load class [{0}] lifecycleBase.alreadyDestroyed=The destroy() method was called on component [{0}] after destroy() had already been called. The second call will be ignored. lifecycleBase.alreadyStarted=The start() method was called on component [{0}] after start() had already been called. The second call will be ignored. lifecycleBase.alreadyStopped=The stop() method was called on component [{0}] after stop() had already been called. The second call will be ignored. lifecycleBase.destroyFail=Failed to destroy component [{0}] lifecycleBase.destroyStopFail=Calling stop() on failed component [{0}] to trigger clean-up did not complete. lifecycleBase.initFail=Failed to initialize component [{0}] lifecycleBase.initMBeanFail=Failed to register component [{0}] with MBean name [{1}] lifecycleBase.invalidTransition=An invalid Lifecycle transition was attempted ([{0}]) for component [{1}] in state [{2}] lifecycleBase.setState=Setting state for [{0}] to [{1}] lifecycleBase.startFail=Failed to start component [{0}] lifecycleBase.stopFail=Failed to stop component [{0}] lifecycleMBeanBase.registerFail=Failed to register object [{0}] with name [{0}] during component initialisation lifecycleMBeanBase.unregisterFail=Failed to unregister MBean with name [{0}] during component destruction lifecycleMBeanBase.unregisterNoServer=No MBean server was available to unregister the MBean [{0}] requestUtil.convertHexDigit.notHex=[{0}] is not a hexadecimal digit requestUtil.parseParameters.uee=Unable to parse the parameters since the encoding [{0}] is not supported. requestUtil.urlDecode.missingDigit=The % character must be followed by two hexademical digits requestUtil.urlDecode.uee=Unable to URL decode the specified input since the encoding [{0}] is not supported. SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block. sessionIdGenerator.createRandom=Creation of SecureRandom instance for session ID generation using [{0}] took [{1}] milliseconds. sessionIdGenerator.random=Exception initializing random number generator of class [{0}]. Falling back to java.secure.SecureRandom sessionIdGenerator.randomAlgorithm=Exception initializing random number generator using algorithm [{0}] sessionIdGenerator.randomProviderException initializing random number generator using provider [{0}] tomcat7-7.0.52/java/org/apache/catalina/util/SessionConfig.java0000644000175100017510000000521511720040447024243 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import javax.servlet.SessionCookieConfig; import org.apache.catalina.Context; public class SessionConfig { private static final String DEFAULT_SESSION_COOKIE_NAME = "JSESSIONID"; private static final String DEFAULT_SESSION_PARAMETER_NAME = "jsessionid"; /** * Determine the name to use for the session cookie for the provided * context. * @param context */ public static String getSessionCookieName(Context context) { String result = getConfiguredSessionCookieName(context); if (result == null) { result = DEFAULT_SESSION_COOKIE_NAME; } return result; } /** * Determine the name to use for the session cookie for the provided * context. * @param context */ public static String getSessionUriParamName(Context context) { String result = getConfiguredSessionCookieName(context); if (result == null) { result = DEFAULT_SESSION_PARAMETER_NAME; } return result; } private static String getConfiguredSessionCookieName(Context context) { // Priority is: // 1. Cookie name defined in context // 2. Cookie name configured for app // 3. Default defined by spec if (context != null) { String cookieName = context.getSessionCookieName(); if (cookieName != null && cookieName.length() > 0) { return cookieName; } SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig(); cookieName = scc.getName(); if (cookieName != null && cookieName.length() > 0) { return cookieName; } } return null; } private SessionConfig() { // Utility class. Hide default constructor. } } tomcat7-7.0.52/java/org/apache/catalina/util/MIME2Java.java0000644000175100017510000004472012271471332023114 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.Hashtable; import java.util.Locale; /** * MIME2Java is a convenience class which handles conversions between MIME charset names * and Java encoding names. *

    The supported XML encodings are the intersection of XML-supported code sets and those * supported in JDK 1.1. *

    MIME charset names are used on xmlEncoding parameters to methods such * as TXDocument#setEncoding and DTD#setEncoding. *

    Java encoding names are used on encoding parameters to * methods such as TXDocument#printWithFormat and DTD#printExternal. *

    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    *

    Common Name *

    *

    Use this name in XML files *

    *

    Name Type *

    *

    Xerces converts to this Java Encoder Name *

    8 bit Unicode *

    UTF-8 *

    *

    IANA *

    *

    UTF8 *

    ISO Latin 1 *

    ISO-8859-1 *

    *

    MIME *

    *

    ISO-8859-1 *

    ISO Latin 2 *

    ISO-8859-2 *

    *

    MIME *

    *

    ISO-8859-2 *

    ISO Latin 3 *

    ISO-8859-3 *

    *

    MIME *

    *

    ISO-8859-3 *

    ISO Latin 4 *

    ISO-8859-4 *

    *

    MIME *

    *

    ISO-8859-4 *

    ISO Latin Cyrillic *

    ISO-8859-5 *

    *

    MIME *

    *

    ISO-8859-5 *

    ISO Latin Arabic *

    ISO-8859-6 *

    *

    MIME *

    *

    ISO-8859-6 *

    ISO Latin Greek *

    ISO-8859-7 *

    *

    MIME *

    *

    ISO-8859-7 *

    ISO Latin Hebrew *

    ISO-8859-8 *

    *

    MIME *

    *

    ISO-8859-8 *

    ISO Latin 5 *

    ISO-8859-9 *

    *

    MIME *

    *

    ISO-8859-9 *

    EBCDIC: US *

    ebcdic-cp-us *

    *

    IANA *

    *

    cp037 *

    EBCDIC: Canada *

    ebcdic-cp-ca *

    *

    IANA *

    *

    cp037 *

    EBCDIC: Netherlands *

    ebcdic-cp-nl *

    *

    IANA *

    *

    cp037 *

    EBCDIC: Denmark *

    ebcdic-cp-dk *

    *

    IANA *

    *

    cp277 *

    EBCDIC: Norway *

    ebcdic-cp-no *

    *

    IANA *

    *

    cp277 *

    EBCDIC: Finland *

    ebcdic-cp-fi *

    *

    IANA *

    *

    cp278 *

    EBCDIC: Sweden *

    ebcdic-cp-se *

    *

    IANA *

    *

    cp278 *

    EBCDIC: Italy *

    ebcdic-cp-it *

    *

    IANA *

    *

    cp280 *

    EBCDIC: Spain, Latin America *

    ebcdic-cp-es *

    *

    IANA *

    *

    cp284 *

    EBCDIC: Great Britain *

    ebcdic-cp-gb *

    *

    IANA *

    *

    cp285 *

    EBCDIC: France *

    ebcdic-cp-fr *

    *

    IANA *

    *

    cp297 *

    EBCDIC: Arabic *

    ebcdic-cp-ar1 *

    *

    IANA *

    *

    cp420 *

    EBCDIC: Hebrew *

    ebcdic-cp-he *

    *

    IANA *

    *

    cp424 *

    EBCDIC: Switzerland *

    ebcdic-cp-ch *

    *

    IANA *

    *

    cp500 *

    EBCDIC: Roece *

    ebcdic-cp-roece *

    *

    IANA *

    *

    cp870 *

    EBCDIC: Yogoslavia *

    ebcdic-cp-yu *

    *

    IANA *

    *

    cp870 *

    EBCDIC: Iceland *

    ebcdic-cp-is *

    *

    IANA *

    *

    cp871 *

    EBCDIC: Urdu *

    ebcdic-cp-ar2 *

    *

    IANA *

    *

    cp918 *

    Chinese for PRC, mixed 1/2 byte *

    gb2312 *

    *

    MIME *

    *

    GB2312 *

    Extended Unix Code, packed for Japanese *

    euc-jp *

    *

    MIME *

    *

    eucjis *

    Japanese: iso-2022-jp *

    iso-2020-jp *

    *

    MIME *

    *

    JIS *

    Japanese: Shift JIS *

    Shift_JIS *

    *

    MIME *

    *

    SJIS *

    Chinese: Big5 *

    Big5 *

    *

    MIME *

    *

    Big5 *

    Extended Unix Code, packed for Korean *

    euc-kr *

    *

    MIME *

    *

    iso2022kr *

    Cyrillic *

    koi8-r *

    *

    MIME *

    *

    koi8-r *

    * * @author TAMURA Kent <kent@trl.ibm.co.jp> */ public class MIME2Java { private static Hashtable s_enchash; private static Hashtable s_revhash; static { s_enchash = new Hashtable(); // , s_enchash.put("UTF-8", "UTF8"); s_enchash.put("US-ASCII", "8859_1"); // ? s_enchash.put("ISO-8859-1", "8859_1"); s_enchash.put("ISO-8859-2", "8859_2"); s_enchash.put("ISO-8859-3", "8859_3"); s_enchash.put("ISO-8859-4", "8859_4"); s_enchash.put("ISO-8859-5", "8859_5"); s_enchash.put("ISO-8859-6", "8859_6"); s_enchash.put("ISO-8859-7", "8859_7"); s_enchash.put("ISO-8859-8", "8859_8"); s_enchash.put("ISO-8859-9", "8859_9"); s_enchash.put("ISO-2022-JP", "JIS"); s_enchash.put("SHIFT_JIS", "SJIS"); s_enchash.put("EUC-JP", "EUCJIS"); s_enchash.put("GB2312", "GB2312"); s_enchash.put("BIG5", "Big5"); s_enchash.put("EUC-KR", "KSC5601"); s_enchash.put("ISO-2022-KR", "ISO2022KR"); s_enchash.put("KOI8-R", "KOI8_R"); s_enchash.put("EBCDIC-CP-US", "CP037"); s_enchash.put("EBCDIC-CP-CA", "CP037"); s_enchash.put("EBCDIC-CP-NL", "CP037"); s_enchash.put("EBCDIC-CP-DK", "CP277"); s_enchash.put("EBCDIC-CP-NO", "CP277"); s_enchash.put("EBCDIC-CP-FI", "CP278"); s_enchash.put("EBCDIC-CP-SE", "CP278"); s_enchash.put("EBCDIC-CP-IT", "CP280"); s_enchash.put("EBCDIC-CP-ES", "CP284"); s_enchash.put("EBCDIC-CP-GB", "CP285"); s_enchash.put("EBCDIC-CP-FR", "CP297"); s_enchash.put("EBCDIC-CP-AR1", "CP420"); s_enchash.put("EBCDIC-CP-HE", "CP424"); s_enchash.put("EBCDIC-CP-CH", "CP500"); s_enchash.put("EBCDIC-CP-ROECE", "CP870"); s_enchash.put("EBCDIC-CP-YU", "CP870"); s_enchash.put("EBCDIC-CP-IS", "CP871"); s_enchash.put("EBCDIC-CP-AR2", "CP918"); // j:CNS11643 -> EUC-TW? // ISO-2022-CN? ISO-2022-CN-EXT? s_revhash = new Hashtable(); // , s_revhash.put("UTF8", "UTF-8"); //s_revhash.put("8859_1", "US-ASCII"); // ? s_revhash.put("8859_1", "ISO-8859-1"); s_revhash.put("8859_2", "ISO-8859-2"); s_revhash.put("8859_3", "ISO-8859-3"); s_revhash.put("8859_4", "ISO-8859-4"); s_revhash.put("8859_5", "ISO-8859-5"); s_revhash.put("8859_6", "ISO-8859-6"); s_revhash.put("8859_7", "ISO-8859-7"); s_revhash.put("8859_8", "ISO-8859-8"); s_revhash.put("8859_9", "ISO-8859-9"); s_revhash.put("JIS", "ISO-2022-JP"); s_revhash.put("SJIS", "Shift_JIS"); s_revhash.put("EUCJIS", "EUC-JP"); s_revhash.put("GB2312", "GB2312"); s_revhash.put("BIG5", "Big5"); s_revhash.put("KSC5601", "EUC-KR"); s_revhash.put("ISO2022KR", "ISO-2022-KR"); s_revhash.put("KOI8_R", "KOI8-R"); s_revhash.put("CP037", "EBCDIC-CP-US"); s_revhash.put("CP037", "EBCDIC-CP-CA"); s_revhash.put("CP037", "EBCDIC-CP-NL"); s_revhash.put("CP277", "EBCDIC-CP-DK"); s_revhash.put("CP277", "EBCDIC-CP-NO"); s_revhash.put("CP278", "EBCDIC-CP-FI"); s_revhash.put("CP278", "EBCDIC-CP-SE"); s_revhash.put("CP280", "EBCDIC-CP-IT"); s_revhash.put("CP284", "EBCDIC-CP-ES"); s_revhash.put("CP285", "EBCDIC-CP-GB"); s_revhash.put("CP297", "EBCDIC-CP-FR"); s_revhash.put("CP420", "EBCDIC-CP-AR1"); s_revhash.put("CP424", "EBCDIC-CP-HE"); s_revhash.put("CP500", "EBCDIC-CP-CH"); s_revhash.put("CP870", "EBCDIC-CP-ROECE"); s_revhash.put("CP870", "EBCDIC-CP-YU"); s_revhash.put("CP871", "EBCDIC-CP-IS"); s_revhash.put("CP918", "EBCDIC-CP-AR2"); } private MIME2Java() { } /** * Convert a MIME charset name, also known as an XML encoding name, to a Java encoding name. * @param mimeCharsetName Case insensitive MIME charset name: UTF-8, US-ASCII, ISO-8859-1, * ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, * ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-2022-JP, Shift_JIS, * EUC-JP, GB2312, Big5, EUC-KR, ISO-2022-KR, KOI8-R, * EBCDIC-CP-US, EBCDIC-CP-CA, EBCDIC-CP-NL, EBCDIC-CP-DK, * EBCDIC-CP-NO, EBCDIC-CP-FI, EBCDIC-CP-SE, EBCDIC-CP-IT, * EBCDIC-CP-ES, EBCDIC-CP-GB, EBCDIC-CP-FR, EBCDIC-CP-AR1, * EBCDIC-CP-HE, EBCDIC-CP-CH, EBCDIC-CP-ROECE, EBCDIC-CP-YU, * EBCDIC-CP-IS and EBCDIC-CP-AR2. * @return Java encoding name, or null if mimeCharsetName * is unknown. * @see #reverse */ public static String convert(String mimeCharsetName) { return s_enchash.get(mimeCharsetName.toUpperCase(Locale.ENGLISH)); } /** * Convert a Java encoding name to MIME charset name. * Available values of encoding are "UTF8", "8859_1", "8859_2", "8859_3", "8859_4", * "8859_5", "8859_6", "8859_7", "8859_8", "8859_9", "JIS", "SJIS", "EUCJIS", * "GB2312", "BIG5", "KSC5601", "ISO2022KR", "KOI8_R", "CP037", "CP277", "CP278", * "CP280", "CP284", "CP285", "CP297", "CP420", "CP424", "CP500", "CP870", "CP871" and "CP918". * @param encoding Case insensitive Java encoding name: UTF8, 8859_1, 8859_2, 8859_3, * 8859_4, 8859_5, 8859_6, 8859_7, 8859_8, 8859_9, JIS, SJIS, EUCJIS, * GB2312, BIG5, KSC5601, ISO2022KR, KOI8_R, CP037, CP277, CP278, * CP280, CP284, CP285, CP297, CP420, CP424, CP500, CP870, CP871 * and CP918. * @return MIME charset name, or null if encoding is unknown. * @see #convert */ public static String reverse(String encoding) { return s_revhash.get(encoding.toUpperCase(Locale.ENGLISH)); } } tomcat7-7.0.52/java/org/apache/catalina/util/LocalStrings_ja.properties0000644000175100017510000000407012271471332026024 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. parameterMap.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fParameterMap\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093 resourceSet.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fResourceSet\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093 hexUtil.bad=\u7121\u52b9\u306a16\u9032\u6570\u5024\u3067\u3059 hexUtil.odd=\u5947\u6570\u6841\u306e16\u9032\u6570\u5024\u3067\u3059 #Default Messages Utilized by the ExtensionValidator extensionValidator.web-application-manifest=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30de\u30cb\u30d5\u30a7\u30b9\u30c8 extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{2}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 extensionValidator.extension-validation-error=ExtensionValidator[{0}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{1}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 extensionValidator.failload=\u62e1\u5f35 {0} \u306e\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f SecurityUtil.doAsPrivilege=PrivilegedExceptionAction\u30d6\u30ed\u30c3\u30af\u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 sessionIdGenerator.random=\u30af\u30e9\u30b9 {0} \u306e\u4e71\u6570\u767a\u751f\u5668\u306e\u521d\u671f\u5316\u306e\u4f8b\u5916\u3067\u3059 tomcat7-7.0.52/java/org/apache/catalina/util/ServerInfo.java0000644000175100017510000000717012271471332023561 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.InputStream; import java.util.Properties; import org.apache.tomcat.util.ExceptionUtils; /** * Simple utility module to make it easy to plug in the server identifier * when integrating Tomcat. * * @author Craig R. McClanahan */ public class ServerInfo { // ------------------------------------------------------- Static Variables /** * The server information String with which we identify ourselves. */ private static String serverInfo = null; /** * The server built String. */ private static String serverBuilt = null; /** * The server's version number String. */ private static String serverNumber = null; static { try { InputStream is = ServerInfo.class.getResourceAsStream ("/org/apache/catalina/util/ServerInfo.properties"); Properties props = new Properties(); props.load(is); is.close(); serverInfo = props.getProperty("server.info"); serverBuilt = props.getProperty("server.built"); serverNumber = props.getProperty("server.number"); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } if (serverInfo == null) serverInfo = "Apache Tomcat 7.0.x-dev"; if (serverBuilt == null) serverBuilt = "unknown"; if (serverNumber == null) serverNumber = "7.0.x"; } // --------------------------------------------------------- Public Methods /** * Return the server identification for this version of Tomcat. */ public static String getServerInfo() { return (serverInfo); } /** * Return the server built time for this version of Tomcat. */ public static String getServerBuilt() { return (serverBuilt); } /** * Return the server's version number. */ public static String getServerNumber() { return (serverNumber); } public static void main(String args[]) { System.out.println("Server version: " + getServerInfo()); System.out.println("Server built: " + getServerBuilt()); System.out.println("Server number: " + getServerNumber()); System.out.println("OS Name: " + System.getProperty("os.name")); System.out.println("OS Version: " + System.getProperty("os.version")); System.out.println("Architecture: " + System.getProperty("os.arch")); System.out.println("JVM Version: " + System.getProperty("java.runtime.version")); System.out.println("JVM Vendor: " + System.getProperty("java.vm.vendor")); } } tomcat7-7.0.52/java/org/apache/catalina/util/SessionIdGenerator.java0000644000175100017510000002121511544734026025246 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; public class SessionIdGenerator { private static Log log = LogFactory.getLog(SessionIdGenerator.class); private static StringManager sm = StringManager.getManager("org.apache.catalina.util"); /** * Queue of random number generator objects to be used when creating session * identifiers. If the queue is empty when a random number generator is * required, a new random number generator object is created. This is * designed this way since random number generators use a sync to make them * thread-safe and the sync makes using a a single object slow(er). */ private Queue randoms = new ConcurrentLinkedQueue(); /** * The Java class name of the secure random number generator class to be * used when generating session identifiers. The random number generator * class must be self-seeding and have a zero-argument constructor. If not * specified, an instance of {@link SecureRandom} will be generated. */ private String secureRandomClass = null; /** * The name of the algorithm to use to create instances of * {@link SecureRandom} which are used to generate session IDs. If no * algorithm is specified, SHA1PRNG is used. To use the platform default * (which may be SHA1PRNG), specify the empty string. If an invalid * algorithm and/or provider is specified the {@link SecureRandom} instances * will be created using the defaults. If that fails, the {@link * SecureRandom} instances will be created using platform defaults. */ private String secureRandomAlgorithm = "SHA1PRNG"; /** * The name of the provider to use to create instances of * {@link SecureRandom} which are used to generate session IDs. If * no algorithm is specified the of SHA1PRNG default is used. If an invalid * algorithm and/or provider is specified the {@link SecureRandom} instances * will be created using the defaults. If that fails, the {@link * SecureRandom} instances will be created using platform defaults. */ private String secureRandomProvider = null; /** Node identifier when in a cluster. Defaults to the empty string. */ private String jvmRoute = ""; /** Number of bytes in a session ID. Defaults to 16. */ private int sessionIdLength = 16; /** * Specify a non-default @{link {@link SecureRandom} implementation to use. * * @param secureRandomClass The fully-qualified class name */ public void setSecureRandomClass(String secureRandomClass) { this.secureRandomClass = secureRandomClass; } /** * Specify a non-default algorithm to use to generate random numbers. * * @param secureRandomAlgorithm The name of the algorithm */ public void setSecureRandomAlgorithm(String secureRandomAlgorithm) { this.secureRandomAlgorithm = secureRandomAlgorithm; } /** * Specify a non-default provider to use to generate random numbers. * * @param secureRandomProvider The name of the provider */ public void setSecureRandomProvider(String secureRandomProvider) { this.secureRandomProvider = secureRandomProvider; } /** * Specify the node identifier associated with this node which will be * included in the generated session ID. * * @param jvmRoute The node identifier */ public void setJvmRoute(String jvmRoute) { this.jvmRoute = jvmRoute; } /** * Specify the number of bytes for a session ID * * @param sessionIdLength Number of bytes */ public void setSessionIdLength(int sessionIdLength) { this.sessionIdLength = sessionIdLength; } /** * Generate and return a new session identifier. */ public String generateSessionId() { byte random[] = new byte[16]; // Render the result as a String of hexadecimal digits StringBuilder buffer = new StringBuilder(); int resultLenBytes = 0; while (resultLenBytes < sessionIdLength) { getRandomBytes(random); for (int j = 0; j < random.length && resultLenBytes < sessionIdLength; j++) { byte b1 = (byte) ((random[j] & 0xf0) >> 4); byte b2 = (byte) (random[j] & 0x0f); if (b1 < 10) buffer.append((char) ('0' + b1)); else buffer.append((char) ('A' + (b1 - 10))); if (b2 < 10) buffer.append((char) ('0' + b2)); else buffer.append((char) ('A' + (b2 - 10))); resultLenBytes++; } } if (jvmRoute != null && jvmRoute.length() > 0) { buffer.append('.').append(jvmRoute); } return buffer.toString(); } private void getRandomBytes(byte bytes[]) { SecureRandom random = randoms.poll(); if (random == null) { random = createSecureRandom(); } random.nextBytes(bytes); randoms.add(random); } /** * Create a new random number generator instance we should use for * generating session identifiers. */ private SecureRandom createSecureRandom() { SecureRandom result = null; long t1 = System.currentTimeMillis(); if (secureRandomClass != null) { try { // Construct and seed a new random number generator Class clazz = Class.forName(secureRandomClass); result = (SecureRandom) clazz.newInstance(); } catch (Exception e) { log.error(sm.getString("sessionIdGenerator.random", secureRandomClass), e); } } if (result == null) { // No secureRandomClass or creation failed. Use SecureRandom. try { if (secureRandomProvider != null && secureRandomProvider.length() > 0) { result = SecureRandom.getInstance(secureRandomAlgorithm, secureRandomProvider); } else if (secureRandomAlgorithm != null && secureRandomAlgorithm.length() > 0) { result = SecureRandom.getInstance(secureRandomAlgorithm); } } catch (NoSuchAlgorithmException e) { log.error(sm.getString("sessionIdGenerator.randomAlgorithm", secureRandomAlgorithm), e); } catch (NoSuchProviderException e) { log.error(sm.getString("sessionIdGenerator.randomProvider", secureRandomProvider), e); } } if (result == null) { // Invalid provider / algorithm try { result = SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { log.error(sm.getString("sessionIdGenerator.randomAlgorithm", secureRandomAlgorithm), e); } } if (result == null) { // Nothing works - use platform default result = new SecureRandom(); } // Force seeding to take place result.nextInt(); long t2=System.currentTimeMillis(); if( (t2-t1) > 100 ) log.info(sm.getString("sessionIdGenerator.createRandom", result.getAlgorithm(), Long.valueOf(t2-t1))); return result; } } tomcat7-7.0.52/java/org/apache/catalina/util/LocalStrings_fr.properties0000644000175100017510000000320412271471332026037 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. parameterMap.locked=Aucune modification n''est authoris\u00e9e sur un ParameterMap verrouill\u00e9 resourceSet.locked=Aucune modification n''est authoris\u00e9e sur un ResourceSet verrouill\u00e9 hexUtil.bad=Mauvais digit hexadecimal hexUtil.odd=Nombre impair de digits hexadecimaux #Default Messages Utilized by the ExtensionValidator extensionValidator.web-application-manifest=Web Application Manifest extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: L''extension requise "{2}" est introuvable. extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Impossible de trouver {1} extension(s) requise(s). SecurityUtil.doAsPrivilege=Une exception s''est produite lors de l''execution du bloc PrivilegedExceptionAction. sessionIdGenerator.random=Exception durant l''initialisation de la classe du g\u00e9n\u00e9rateur de nombre al\u00e9atoire {0} tomcat7-7.0.52/java/org/apache/catalina/util/InstanceSupport.java0000644000175100017510000002533512271471332024643 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import javax.servlet.Filter; import javax.servlet.Servlet; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.catalina.InstanceEvent; import org.apache.catalina.InstanceListener; import org.apache.catalina.Wrapper; /** * Support class to assist in firing InstanceEvent notifications to * registered InstanceListeners. * * @author Craig R. McClanahan */ public final class InstanceSupport { // ----------------------------------------------------------- Constructors /** * Construct a new InstanceSupport object associated with the specified * Instance component. * * @param wrapper The component that will be the source * of events that we fire */ public InstanceSupport(Wrapper wrapper) { super(); this.wrapper = wrapper; } // ----------------------------------------------------- Instance Variables /** * The set of registered InstanceListeners for event notifications. */ private InstanceListener listeners[] = new InstanceListener[0]; private final Object listenersLock = new Object(); // Lock object for changes to listeners /** * The source component for instance events that we will fire. */ private Wrapper wrapper = null; // ------------------------------------------------------------- Properties /** * Return the Wrapper with which we are associated. */ public Wrapper getWrapper() { return (this.wrapper); } // --------------------------------------------------------- Public Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ public void addInstanceListener(InstanceListener listener) { synchronized (listenersLock) { InstanceListener results[] = new InstanceListener[listeners.length + 1]; for (int i = 0; i < listeners.length; i++) results[i] = listeners[i]; results[listeners.length] = listener; listeners = results; } } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param filter The relevant Filter for this event */ public void fireInstanceEvent(String type, Filter filter) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, filter, type); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param filter The relevant Filter for this event * @param exception Exception that occurred */ public void fireInstanceEvent(String type, Filter filter, Throwable exception) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, filter, type, exception); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param filter The relevant Filter for this event * @param request The servlet request we are processing * @param response The servlet response we are processing */ public void fireInstanceEvent(String type, Filter filter, ServletRequest request, ServletResponse response) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, filter, type, request, response); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param filter The relevant Filter for this event * @param request The servlet request we are processing * @param response The servlet response we are processing * @param exception Exception that occurred */ public void fireInstanceEvent(String type, Filter filter, ServletRequest request, ServletResponse response, Throwable exception) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, filter, type, request, response, exception); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param servlet The relevant Servlet for this event */ public void fireInstanceEvent(String type, Servlet servlet) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, servlet, type); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param servlet The relevant Servlet for this event * @param exception Exception that occurred */ public void fireInstanceEvent(String type, Servlet servlet, Throwable exception) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, servlet, type, exception); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param servlet The relevant Servlet for this event * @param request The servlet request we are processing * @param response The servlet response we are processing */ public void fireInstanceEvent(String type, Servlet servlet, ServletRequest request, ServletResponse response) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, servlet, type, request, response); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param servlet The relevant Servlet for this event * @param request The servlet request we are processing * @param response The servlet response we are processing * @param exception Exception that occurred */ public void fireInstanceEvent(String type, Servlet servlet, ServletRequest request, ServletResponse response, Throwable exception) { if (listeners.length == 0) return; InstanceEvent event = new InstanceEvent(wrapper, servlet, type, request, response, exception); InstanceListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].instanceEvent(event); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to remove */ public void removeInstanceListener(InstanceListener listener) { synchronized (listenersLock) { int n = -1; for (int i = 0; i < listeners.length; i++) { if (listeners[i] == listener) { n = i; break; } } if (n < 0) return; InstanceListener results[] = new InstanceListener[listeners.length - 1]; int j = 0; for (int i = 0; i < listeners.length; i++) { if (i != n) results[j++] = listeners[i]; } listeners = results; } } } tomcat7-7.0.52/java/org/apache/catalina/util/Extension.java0000644000175100017510000002250512271471332023452 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.StringTokenizer; /** * Utility class that represents either an available "Optional Package" * (formerly known as "Standard Extension") as described in the manifest * of a JAR file, or the requirement for such an optional package. It is * used to support the requirements of the Servlet Specification, version * 2.3, related to providing shared extensions to all webapps. *

    * In addition, static utility methods are available to scan a manifest * and return an array of either available or required optional modules * documented in that manifest. *

    * For more information about optional packages, see the document * Optional Package Versioning in the documentation bundle for your * Java2 Standard Edition package, in file * guide/extensions/versioning.html. * * @author Craig McClanahan * @author Justyna Horwat * @author Greg Murray */ public final class Extension { // ------------------------------------------------------------- Properties /** * The name of the optional package being made available, or required. */ private String extensionName = null; public String getExtensionName() { return (this.extensionName); } public void setExtensionName(String extensionName) { this.extensionName = extensionName; } /** * The URL from which the most recent version of this optional package * can be obtained if it is not already installed. */ private String implementationURL = null; public String getImplementationURL() { return (this.implementationURL); } public void setImplementationURL(String implementationURL) { this.implementationURL = implementationURL; } /** * The name of the company or organization that produced this * implementation of this optional package. */ private String implementationVendor = null; public String getImplementationVendor() { return (this.implementationVendor); } public void setImplementationVendor(String implementationVendor) { this.implementationVendor = implementationVendor; } /** * The unique identifier of the company that produced the optional * package contained in this JAR file. */ private String implementationVendorId = null; public String getImplementationVendorId() { return (this.implementationVendorId); } public void setImplementationVendorId(String implementationVendorId) { this.implementationVendorId = implementationVendorId; } /** * The version number (dotted decimal notation) for this implementation * of the optional package. */ private String implementationVersion = null; public String getImplementationVersion() { return (this.implementationVersion); } public void setImplementationVersion(String implementationVersion) { this.implementationVersion = implementationVersion; } /** * The name of the company or organization that originated the * specification to which this optional package conforms. */ private String specificationVendor = null; public String getSpecificationVendor() { return (this.specificationVendor); } public void setSpecificationVendor(String specificationVendor) { this.specificationVendor = specificationVendor; } /** * The version number (dotted decimal notation) of the specification * to which this optional package conforms. */ private String specificationVersion = null; public String getSpecificationVersion() { return (this.specificationVersion); } public void setSpecificationVersion(String specificationVersion) { this.specificationVersion = specificationVersion; } /** * fulfilled is true if all the required extension dependencies have been * satisfied */ private boolean fulfilled = false; public void setFulfilled(boolean fulfilled) { this.fulfilled = fulfilled; } public boolean isFulfilled() { return fulfilled; } // --------------------------------------------------------- Public Methods /** * Return true if the specified Extension * (which represents an optional package required by this application) * is satisfied by this Extension (which represents an * optional package that is already installed. Otherwise, return * false. * * @param required Extension of the required optional package */ public boolean isCompatibleWith(Extension required) { // Extension Name must match if (extensionName == null) return (false); if (!extensionName.equals(required.getExtensionName())) return (false); // If specified, available specification version must be >= required if (required.getSpecificationVersion() != null) { if (!isNewer(specificationVersion, required.getSpecificationVersion())) return (false); } // If specified, Implementation Vendor ID must match if (required.getImplementationVendorId() != null) { if (implementationVendorId == null) return (false); if (!implementationVendorId.equals(required .getImplementationVendorId())) return (false); } // If specified, Implementation version must be >= required if (required.getImplementationVersion() != null) { if (!isNewer(implementationVersion, required.getImplementationVersion())) return (false); } // This available optional package satisfies the requirements return (true); } /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("Extension["); sb.append(extensionName); if (implementationURL != null) { sb.append(", implementationURL="); sb.append(implementationURL); } if (implementationVendor != null) { sb.append(", implementationVendor="); sb.append(implementationVendor); } if (implementationVendorId != null) { sb.append(", implementationVendorId="); sb.append(implementationVendorId); } if (implementationVersion != null) { sb.append(", implementationVersion="); sb.append(implementationVersion); } if (specificationVendor != null) { sb.append(", specificationVendor="); sb.append(specificationVendor); } if (specificationVersion != null) { sb.append(", specificationVersion="); sb.append(specificationVersion); } sb.append("]"); return (sb.toString()); } // -------------------------------------------------------- Private Methods /** * Return true if the first version number is greater than * or equal to the second; otherwise return false. * * @param first First version number (dotted decimal) * @param second Second version number (dotted decimal) * * @exception NumberFormatException on a malformed version number */ private boolean isNewer(String first, String second) throws NumberFormatException { if ((first == null) || (second == null)) return (false); if (first.equals(second)) return (true); StringTokenizer fTok = new StringTokenizer(first, ".", true); StringTokenizer sTok = new StringTokenizer(second, ".", true); int fVersion = 0; int sVersion = 0; while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) { if (fTok.hasMoreTokens()) fVersion = Integer.parseInt(fTok.nextToken()); else fVersion = 0; if (sTok.hasMoreTokens()) sVersion = Integer.parseInt(sTok.nextToken()); else sVersion = 0; if (fVersion < sVersion) return (false); else if (fVersion > sVersion) return (true); if (fTok.hasMoreTokens()) // Swallow the periods fTok.nextToken(); if (sTok.hasMoreTokens()) sTok.nextToken(); } return (true); // Exact match } } tomcat7-7.0.52/java/org/apache/catalina/util/RequestUtil.java0000644000175100017510000003540612271471332023770 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Map; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.res.StringManager; /** * General purpose request parsing and encoding utility methods. * * @author Craig R. McClanahan * @author Tim Tye */ public final class RequestUtil { private static final Log log = LogFactory.getLog(RequestUtil.class); /** * The string resources for this package. */ private static final StringManager sm = StringManager.getManager("org.apache.catalina.util"); /** * Filter the specified message string for characters that are sensitive * in HTML. This avoids potential attacks caused by including JavaScript * codes in the request URL that is often reported in error messages. * * @param message The message string to be filtered */ public static String filter(String message) { if (message == null) return (null); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); } /** * Normalize a relative URI path that may have relative values ("/./", * "/../", and so on ) it it. WARNING - This method is * useful only for normalizing application-generated paths. It does not * try to perform security checks for malicious input. * * @param path Relative path to be normalized * * @deprecated Deprecated to resolve a circular package dependency and will * be removed in Tomcat 8.0.x. Use {@link * org.apache.tomcat.util.http.RequestUtil#normalize(String)} as * a replacement. */ @Deprecated public static String normalize(String path) { return org.apache.tomcat.util.http.RequestUtil.normalize(path); } /** * Normalize a relative URI path that may have relative values ("/./", * "/../", and so on ) it it. WARNING - This method is * useful only for normalizing application-generated paths. It does not * try to perform security checks for malicious input. * * @param path Relative path to be normalized * @param replaceBackSlash Should '\\' be replaced with '/' * * @deprecated Deprecated to resolve a circular package dependency and will * be removed in Tomcat 8.0.x. Use {@link * org.apache.tomcat.util.http.RequestUtil#normalize(String, * boolean)} as a replacement. */ @Deprecated public static String normalize(String path, boolean replaceBackSlash) { return org.apache.tomcat.util.http.RequestUtil.normalize(path, replaceBackSlash); } /** * Append request parameters from the specified String to the specified * Map. It is presumed that the specified Map is not accessed from any * other thread, so no synchronization is performed. *

    * IMPLEMENTATION NOTE: URL decoding is performed * individually on the parsed name and value elements, rather than on * the entire query string ahead of time, to properly deal with the case * where the name or value includes an encoded "=" or "&" character * that would otherwise be interpreted as a delimiter. * * @param map Map that accumulates the resulting parameters * @param data Input string containing request parameters * @param encoding The encoding to use; encoding must not be null. * If an unsupported encoding is specified the parameters will not be * parsed and the map will not be modified */ public static void parseParameters(Map map, String data, String encoding) { if ((data != null) && (data.length() > 0)) { // use the specified encoding to extract bytes out of the // given string so that the encoding is not lost. byte[] bytes = null; try { bytes = data.getBytes(B2CConverter.getCharset(encoding)); parseParameters(map, bytes, encoding); } catch (UnsupportedEncodingException uee) { if (log.isDebugEnabled()) { log.debug(sm.getString("requestUtil.parseParameters.uee", encoding), uee); } } } } /** * Decode and return the specified URL-encoded String. * When the byte array is converted to a string, the system default * character encoding is used... This may be different than some other * servers. It is assumed the string is not a query string. * * @param str The url-encoded string * * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String URLDecode(String str) { return URLDecode(str, null); } /** * Decode and return the specified URL-encoded String. It is assumed the * string is not a query string. * * @param str The url-encoded string * @param enc The encoding to use; if null, the default encoding is used. If * an unsupported encoding is specified null will be returned * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String URLDecode(String str, String enc) { return URLDecode(str, enc, false); } /** * Decode and return the specified URL-encoded String. * * @param str The url-encoded string * @param enc The encoding to use; if null, the default encoding is used. If * an unsupported encoding is specified null will be returned * @param isQuery Is this a query string being processed * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String URLDecode(String str, String enc, boolean isQuery) { if (str == null) return (null); // use the specified encoding to extract bytes out of the // given string so that the encoding is not lost. If an // encoding is not specified, let it use platform default byte[] bytes = null; try { if (enc == null) { bytes = str.getBytes(Charset.defaultCharset()); } else { bytes = str.getBytes(B2CConverter.getCharset(enc)); } } catch (UnsupportedEncodingException uee) { if (log.isDebugEnabled()) { log.debug(sm.getString("requestUtil.urlDecode.uee", enc), uee); } } return URLDecode(bytes, enc, isQuery); } /** * Decode and return the specified URL-encoded byte array. It is assumed * the string is not a query string. * * @param bytes The url-encoded byte array * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String URLDecode(byte[] bytes) { return URLDecode(bytes, null); } /** * Decode and return the specified URL-encoded byte array. It is assumed * the string is not a query string. * * @param bytes The url-encoded byte array * @param enc The encoding to use; if null, the default encoding is used * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static String URLDecode(byte[] bytes, String enc) { return URLDecode(bytes, enc, false); } /** * Decode and return the specified URL-encoded byte array. * * @param bytes The url-encoded byte array * @param enc The encoding to use; if null, the default encoding is used. If * an unsupported encoding is specified null will be returned * @param isQuery Is this a query string being processed * @exception IllegalArgumentException if a '%' character is not followed * by a valid 2-digit hexadecimal number */ public static String URLDecode(byte[] bytes, String enc, boolean isQuery) { if (bytes == null) return null; int len = bytes.length; int ix = 0; int ox = 0; while (ix < len) { byte b = bytes[ix++]; // Get byte to test if (b == '+' && isQuery) { b = (byte)' '; } else if (b == '%') { if (ix + 2 > len) { throw new IllegalArgumentException( sm.getString("requestUtil.urlDecode.missingDigit")); } b = (byte) ((convertHexDigit(bytes[ix++]) << 4) + convertHexDigit(bytes[ix++])); } bytes[ox++] = b; } if (enc != null) { try { return new String(bytes, 0, ox, B2CConverter.getCharset(enc)); } catch (UnsupportedEncodingException uee) { if (log.isDebugEnabled()) { log.debug(sm.getString("requestUtil.urlDecode.uee", enc), uee); } return null; } } return new String(bytes, 0, ox); } /** * Convert a byte character value to hexadecimal digit value. * * @param b the character value byte */ private static byte convertHexDigit( byte b ) { if ((b >= '0') && (b <= '9')) return (byte)(b - '0'); if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10); if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10); throw new IllegalArgumentException( sm.getString("requestUtil.convertHexDigit.notHex", Character.valueOf((char)b))); } /** * Put name and value pair in map. When name already exist, add value * to array of values. * * @param map The map to populate * @param name The parameter name * @param value The parameter value */ private static void putMapEntry( Map map, String name, String value) { String[] newValues = null; String[] oldValues = map.get(name); if (oldValues == null) { newValues = new String[1]; newValues[0] = value; } else { newValues = new String[oldValues.length + 1]; System.arraycopy(oldValues, 0, newValues, 0, oldValues.length); newValues[oldValues.length] = value; } map.put(name, newValues); } /** * Append request parameters from the specified String to the specified * Map. It is presumed that the specified Map is not accessed from any * other thread, so no synchronization is performed. *

    * IMPLEMENTATION NOTE: URL decoding is performed * individually on the parsed name and value elements, rather than on * the entire query string ahead of time, to properly deal with the case * where the name or value includes an encoded "=" or "&" character * that would otherwise be interpreted as a delimiter. * * NOTE: byte array data is modified by this method. Caller beware. * * @param map Map that accumulates the resulting parameters * @param data Input string containing request parameters * @param encoding The encoding to use; if null, the default encoding is * used * * @exception UnsupportedEncodingException if the requested encoding is not * supported. */ public static void parseParameters(Map map, byte[] data, String encoding) throws UnsupportedEncodingException { Charset charset = B2CConverter.getCharset(encoding); if (data != null && data.length > 0) { int ix = 0; int ox = 0; String key = null; String value = null; while (ix < data.length) { byte c = data[ix++]; switch ((char) c) { case '&': value = new String(data, 0, ox, charset); if (key != null) { putMapEntry(map, key, value); key = null; } ox = 0; break; case '=': if (key == null) { key = new String(data, 0, ox, charset); ox = 0; } else { data[ox++] = c; } break; case '+': data[ox++] = (byte)' '; break; case '%': data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4) + convertHexDigit(data[ix++])); break; default: data[ox++] = c; } } //The last value does not end in '&'. So save it now. if (key != null) { value = new String(data, 0, ox, charset); putMapEntry(map, key, value); } } } } tomcat7-7.0.52/java/org/apache/catalina/util/Introspection.java0000644000175100017510000001457612077735044024356 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.beans.Introspector; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; import org.apache.catalina.Container; import org.apache.catalina.Globals; import org.apache.juli.logging.Log; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Provides introspection utilities that either require knowledge of Tomcat * internals or are solely used by Tomcat internals. */ public class Introspection { private static StringManager sm = StringManager.getManager("org.apache.catalina.util"); /** * Extract the Java Bean property name from the setter name. * * Note: This method assumes that the method name has already been checked * for correctness. */ public static String getPropertyName(Method setter) { return Introspector.decapitalize(setter.getName().substring(3)); } /** * Determines if a method has a valid name and signature for a Java Bean * setter. * * @param method The method to test * * @return true if the method does have a valid name and * signature, else false */ public static boolean isValidSetter(Method method) { if (method.getName().startsWith("set") && method.getName().length() > 3 && method.getParameterTypes().length == 1 && method.getReturnType().getName().equals("void")) { return true; } return false; } /** * Determines if a method is a valid lifecycle callback method. * * @param method * The method to test * * @return true if the method is a valid lifecycle callback * method, else false */ public static boolean isValidLifecycleCallback(Method method) { if (method.getParameterTypes().length != 0 || Modifier.isStatic(method.getModifiers()) || method.getExceptionTypes().length > 0 || !method.getReturnType().getName().equals("void")) { return false; } return true; } /** * Obtain the declared fields for a class taking account of any security * manager that may be configured. */ public static Field[] getDeclaredFields(final Class clazz) { Field[] fields = null; if (Globals.IS_SECURITY_ENABLED) { fields = AccessController.doPrivileged( new PrivilegedAction(){ @Override public Field[] run(){ return clazz.getDeclaredFields(); } }); } else { fields = clazz.getDeclaredFields(); } return fields; } /** * Obtain the declared methods for a class taking account of any security * manager that may be configured. */ public static Method[] getDeclaredMethods(final Class clazz) { Method[] methods = null; if (Globals.IS_SECURITY_ENABLED) { methods = AccessController.doPrivileged( new PrivilegedAction(){ @Override public Method[] run(){ return clazz.getDeclaredMethods(); } }); } else { methods = clazz.getDeclaredMethods(); } return methods; } /** * Attempt to load a class using the given Container's class loader. If the * class cannot be loaded, a debug level log message will be written to the * Container's log and null will be returned. */ public static Class loadClass(Container container, String className) { ClassLoader cl = container.getLoader().getClassLoader(); Log log = container.getLogger(); Class clazz = null; try { clazz = cl.loadClass(className); } catch (ClassNotFoundException e) { log.debug(sm.getString("introspection.classLoadFailed"), e); } catch (NoClassDefFoundError e) { log.debug(sm.getString("introspection.classLoadFailed"), e); } catch (ClassFormatError e) { log.debug(sm.getString("introspection.classLoadFailed"), e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("introspection.classLoadFailed"), t); } return clazz; } /** * Converts the primitive type to its corresponding wrapper. * * @param clazz * Class that will be evaluated * @return if the parameter is a primitive type returns its wrapper; * otherwise returns the same class */ public static Class convertPrimitiveType(Class clazz) { if (clazz.equals(char.class)) { return Character.class; } else if (clazz.equals(int.class)) { return Integer.class; } else if (clazz.equals(boolean.class)) { return Boolean.class; } else if (clazz.equals(double.class)) { return Double.class; } else if (clazz.equals(byte.class)) { return Byte.class; } else if (clazz.equals(short.class)) { return Short.class; } else if (clazz.equals(long.class)) { return Long.class; } else if (clazz.equals(float.class)) { return Float.class; } else { return clazz; } } } tomcat7-7.0.52/java/org/apache/catalina/util/IOTools.java0000644000175100017510000000534212271471332023026 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; /** * Contains commonly needed I/O-related methods * * @author Dan Sandberg */ public class IOTools { protected static final int DEFAULT_BUFFER_SIZE=4*1024; //4k private IOTools() { //Ensure non-instantiability } /** * Read input from reader and write it to writer until there is no more * input from reader. * * @param reader the reader to read from. * @param writer the writer to write to. * @param buf the char array to use as a buffer */ public static void flow( Reader reader, Writer writer, char[] buf ) throws IOException { int numRead; while ( (numRead = reader.read(buf) ) >= 0) { writer.write(buf, 0, numRead); } } /** * @see #flow( Reader, Writer, char[] ) */ public static void flow( Reader reader, Writer writer ) throws IOException { char[] buf = new char[DEFAULT_BUFFER_SIZE]; flow( reader, writer, buf ); } /** * Read input from input stream and write it to output stream * until there is no more input from input stream. * * @param is input stream the input stream to read from. * @param os output stream the output stream to write to. * @param buf the byte array to use as a buffer */ public static void flow( InputStream is, OutputStream os, byte[] buf ) throws IOException { int numRead; while ( (numRead = is.read(buf) ) >= 0) { os.write(buf, 0, numRead); } } /** * @see #flow( java.io.InputStream, java.io.OutputStream, byte[] ) */ public static void flow( InputStream is, OutputStream os ) throws IOException { byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; flow( is, os, buf ); } } tomcat7-7.0.52/java/org/apache/catalina/util/ContextName.java0000644000175100017510000001315112263527300023716 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.util; import java.util.Locale; /** * Utility class to manage context names so there is one place where the * conversions between baseName, path and version take place. */ public final class ContextName { private static final String ROOT_NAME = "ROOT"; private static final String VERSION_MARKER = "##"; private static final String FWD_SLASH_REPLACEMENT = "#"; private final String baseName; private final String path; private final String version; private final String name; /** * Creates an instance from a context name, display name, base name, * directory name, WAR name or context.xml name. * * @param name The name to use as the basis for this object * * @deprecated Use {@link ContextName#ContextName(String, boolean)} */ @Deprecated public ContextName(String name) { this(name, true); } /** * Creates an instance from a context name, display name, base name, * directory name, WAR name or context.xml name. * * @param name The name to use as the basis for this object * @param stripFileExtension If a .war or .xml file extension is present * at the end of the provided name should it be * removed? */ public ContextName(String name, boolean stripFileExtension) { String tmp1 = name; // Convert Context names and display names to base names // Strip off any leading "/" if (tmp1.startsWith("/")) { tmp1 = tmp1.substring(1); } // Replace any remaining / tmp1 = tmp1.replaceAll("/", FWD_SLASH_REPLACEMENT); // Insert the ROOT name if required if (tmp1.startsWith(VERSION_MARKER) || "".equals(tmp1)) { tmp1 = ROOT_NAME + tmp1; } // Remove any file extensions if (stripFileExtension && (tmp1.toLowerCase(Locale.ENGLISH).endsWith(".war") || tmp1.toLowerCase(Locale.ENGLISH).endsWith(".xml"))) { tmp1 = tmp1.substring(0, tmp1.length() -4); } baseName = tmp1; String tmp2; // Extract version number int versionIndex = baseName.indexOf(VERSION_MARKER); if (versionIndex > -1) { version = baseName.substring(versionIndex + 2); tmp2 = baseName.substring(0, versionIndex); } else { version = ""; tmp2 = baseName; } if (ROOT_NAME.equals(tmp2)) { path = ""; } else { path = "/" + tmp2.replaceAll(FWD_SLASH_REPLACEMENT, "/"); } if (versionIndex > -1) { this.name = path + VERSION_MARKER + version; } else { this.name = path; } } /** * Construct an instance from a path and version. * * @param path Context path to use * @param version Context version to use */ public ContextName(String path, String version) { // Path should never be null, '/' or '/ROOT' if (path == null || "/".equals(path) || "/ROOT".equals(path)) { this.path = ""; } else { this.path = path; } // Version should never be null if (version == null) { this.version = ""; } else { this.version = version; } // Name is path + version if ("".equals(this.version)) { name = this.path; } else { name = this.path + VERSION_MARKER + this.version; } // Base name is converted path + version StringBuilder tmp = new StringBuilder(); if ("".equals(this.path)) { tmp.append(ROOT_NAME); } else { tmp.append(this.path.substring(1).replaceAll("/", FWD_SLASH_REPLACEMENT)); } if (this.version.length() > 0) { tmp.append(VERSION_MARKER); tmp.append(this.version); } this.baseName = tmp.toString(); } public String getBaseName() { return baseName; } public String getPath() { return path; } public String getVersion() { return version; } public String getName() { return name; } public String getDisplayName() { StringBuilder tmp = new StringBuilder(); if ("".equals(path)) { tmp.append('/'); } else { tmp.append(path); } if (!"".equals(version)) { tmp.append(VERSION_MARKER); tmp.append(version); } return tmp.toString(); } @Override public String toString() { return getDisplayName(); } } tomcat7-7.0.52/java/org/apache/catalina/Cluster.java0000644000175100017510000000771112271471332022144 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; /** * A Cluster works as a Cluster client/server for the local host * Different Cluster implementations can be used to support different * ways to communicate within the Cluster. A Cluster implementation is * responsible for setting up a way to communicate within the Cluster * and also supply "ClientApplications" with ClusterSender * used when sending information in the Cluster and * ClusterInfo used for receiving information in the Cluster. * * @author Bip Thelin * @author Remy Maucherat * @author Filip Hanik */ public interface Cluster { // ------------------------------------------------------------- Properties /** * Return descriptive information about this Cluster implementation and * the corresponding version number, in the format * <description>/<version>. */ public String getInfo(); /** * Return the name of the cluster that this Server is currently * configured to operate within. * * @return The name of the cluster associated with this server */ public String getClusterName(); /** * Set the name of the cluster to join, if no cluster with * this name is present create one. * * @param clusterName The clustername to join */ public void setClusterName(String clusterName); /** * Set the Container associated with our Cluster * * @param container The Container to use */ public void setContainer(Container container); /** * Get the Container associated with our Cluster * * @return The Container associated with our Cluster */ public Container getContainer(); /** * Set the protocol parameters. * * @param protocol The protocol used by the cluster * @deprecated */ @Deprecated public void setProtocol(String protocol); /** * Get the protocol used by the cluster. * * @return The protocol * @deprecated */ @Deprecated public String getProtocol(); // --------------------------------------------------------- Public Methods /** * Create a new manager which will use this cluster to replicate its * sessions. * * @param name Name (key) of the application with which the manager is * associated */ public Manager createManager(String name); /** * Register a manager with the cluster. If the cluster is not responsible * for creating a manager, then the container will at least notify the * cluster that this manager is participating in the cluster. * @param manager Manager */ public void registerManager(Manager manager); /** * Removes a manager from the cluster * @param manager Manager */ public void removeManager(Manager manager); // --------------------------------------------------------- Cluster Wide Deployments /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ public void backgroundProcess(); } tomcat7-7.0.52/java/org/apache/catalina/LifecycleEvent.java0000644000175100017510000000474712271471332023432 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina; import java.util.EventObject; /** * General event for notifying listeners of significant changes on a component * that implements the Lifecycle interface. In particular, this will be useful * on Containers, where these events replace the ContextInterceptor concept in * Tomcat 3.x. * * @author Craig R. McClanahan */ public final class LifecycleEvent extends EventObject { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /** * Construct a new LifecycleEvent with the specified parameters. * * @param lifecycle Component on which this event occurred * @param type Event type (required) * @param data Event data (if any) */ public LifecycleEvent(Lifecycle lifecycle, String type, Object data) { super(lifecycle); this.type = type; this.data = data; } // ----------------------------------------------------- Instance Variables /** * The event data associated with this event. */ private Object data = null; /** * The event type this instance represents. */ private String type = null; // ------------------------------------------------------------- Properties /** * Return the event data of this event. */ public Object getData() { return (this.data); } /** * Return the Lifecycle on which this event occurred. */ public Lifecycle getLifecycle() { return (Lifecycle) getSource(); } /** * Return the event type of this event. */ public String getType() { return (this.type); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/0000755000175100017510000000000012301126370021133 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/UniqueId.java0000644000175100017510000000444312271464231023535 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.io.Serializable; import org.apache.catalina.tribes.util.Arrays; /** *

    Title: Represents a globally unique Id

    * *

    Company:

    * * @author Filip Hanik * @version 1.0 */ public final class UniqueId implements Serializable{ private static final long serialVersionUID = 1L; protected byte[] id; public UniqueId() { } public UniqueId(byte[] id) { this.id = id; } public UniqueId(byte[] id, int offset, int length) { this.id = new byte[length]; System.arraycopy(id,offset,this.id,0,length); } @Override public int hashCode() { if ( id == null ) return 0; return Arrays.hashCode(id); } @Override public boolean equals(Object other) { boolean result = (other instanceof UniqueId); if ( result ) { UniqueId uid = (UniqueId)other; if ( this.id == null && uid.id == null ) result = true; else if ( this.id == null && uid.id != null ) result = false; else if ( this.id != null && uid.id == null ) result = false; else result = Arrays.equals(this.id,uid.id); }//end if return result; } public byte[] getBytes() { return id; } @Override public String toString() { StringBuilder buf = new StringBuilder("UniqueId"); buf.append(org.apache.catalina.tribes.util.Arrays.toString(id)); return buf.toString(); } }tomcat7-7.0.52/java/org/apache/catalina/tribes/Channel.java0000644000175100017510000004112112271464231023354 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.io.Serializable; /** * Channel interface
    * A channel is a representation of a group of nodes all participating in some sort of * communication with each other.
    * The channel is the main API class for Tribes, this is essentially the only class * that an application needs to be aware of. Through the channel the application can:
    * 1. send messages
    * 2. receive message (by registering a ChannelListener
    * 3. get all members of the group getMembers()
    * 4. receive notifications of members added and members disappeared by * registering a MembershipListener
    *
    * The channel has 5 major components:
    * 1. Data receiver, with a built in thread pool to receive messages from other peers
    * 2. Data sender, an implementation for sending data using NIO or java.io
    * 3. Membership listener,listens for membership broadcasts
    * 4. Membership broadcaster, broadcasts membership pings.
    * 5. Channel interceptors, the ability to manipulate messages as they are sent or arrive

    * The channel layout is: *
    
     *  ChannelListener_1..ChannelListener_N MembershipListener_1..MembershipListener_N [Application Layer]
     *            \          \                  /                   /
     *             \          \                /                   /
     *              \          \              /                   /
     *               \          \            /                   /
     *                \          \          /                   /
     *                 \          \        /                   /
     *                  ---------------------------------------
     *                                  |
     *                                  |
     *                               Channel
     *                                  |
     *                         ChannelInterceptor_1
     *                                  |                                               [Channel stack]
     *                         ChannelInterceptor_N
     *                                  |
     *                             Coordinator (implements MessageListener,MembershipListener,ChannelInterceptor)
     *                          --------------------
     *                         /        |           \
     *                        /         |            \
     *                       /          |             \
     *                      /           |              \
     *                     /            |               \
     *           MembershipService ChannelSender ChannelReceiver                        [IO layer]
     * 
    * * For example usage @see org.apache.catalina.tribes.group.GroupChannel * @author Filip Hanik */ public interface Channel { /** * Start and stop sequences can be controlled by these constants * This allows you to start separate components of the channel
    * DEFAULT - starts or stops all components in the channel * @see #start(int) * @see #stop(int) */ public static final int DEFAULT = 15; /** * Start and stop sequences can be controlled by these constants * This allows you to start separate components of the channel
    * SND_RX_SEQ - starts or stops the data receiver. Start means opening a server socket * in case of a TCP implementation * @see #start(int) * @see #stop(int) */ public static final int SND_RX_SEQ = 1; /** * Start and stop sequences can be controlled by these constants * This allows you to start separate components of the channel
    * SND_TX_SEQ - starts or stops the data sender. This should not open any sockets, * as sockets are opened on demand when a message is being sent * @see #start(int) * @see #stop(int) */ public static final int SND_TX_SEQ = 2; /** * Start and stop sequences can be controlled by these constants * This allows you to start separate components of the channel
    * MBR_RX_SEQ - starts or stops the membership listener. In a multicast implementation * this will open a datagram socket and join a group and listen for membership messages * members joining * @see #start(int) * @see #stop(int) */ public static final int MBR_RX_SEQ = 4; /** * Start and stop sequences can be controlled by these constants * This allows you to start separate components of the channel
    * MBR_TX_SEQ - starts or stops the membership broadcaster. In a multicast implementation * this will open a datagram socket and join a group and broadcast the local member information * @see #start(int) * @see #stop(int) */ public static final int MBR_TX_SEQ = 8; /** * Send options, when a message is sent, it can have an option flag * to trigger certain behavior. Most flags are used to trigger channel interceptors * as the message passes through the channel stack.
    * However, there are five default flags that every channel implementation must implement
    * SEND_OPTIONS_BYTE_MESSAGE - The message is a pure byte message and no marshaling or unmarshaling will * be performed.
    * * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_BYTE_MESSAGE = 0x0001; /** * Send options, when a message is sent, it can have an option flag * to trigger certain behavior. Most flags are used to trigger channel interceptors * as the message passes through the channel stack.
    * However, there are five default flags that every channel implementation must implement
    * SEND_OPTIONS_USE_ACK - Message is sent and an ACK is received when the message has been received by the recipient
    * If no ack is received, the message is not considered successful
    * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_USE_ACK = 0x0002; /** * Send options, when a message is sent, it can have an option flag * to trigger certain behavior. Most flags are used to trigger channel interceptors * as the message passes through the channel stack.
    * However, there are five default flags that every channel implementation must implement
    * SEND_OPTIONS_SYNCHRONIZED_ACK - Message is sent and an ACK is received when the message has been received and * processed by the recipient
    * If no ack is received, the message is not considered successful
    * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_SYNCHRONIZED_ACK = 0x0004; /** * Send options, when a message is sent, it can have an option flag * to trigger certain behavior. Most flags are used to trigger channel interceptors * as the message passes through the channel stack.
    * However, there are five default flags that every channel implementation must implement
    * SEND_OPTIONS_ASYNCHRONOUS - Message is sent and an ACK is received when the message has been received and * processed by the recipient
    * If no ack is received, the message is not considered successful
    * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_ASYNCHRONOUS = 0x0008; /** * Send options, when a message is sent, it can have an option flag * to trigger certain behavior. Most flags are used to trigger channel interceptors * as the message passes through the channel stack.
    * However, there are five default flags that every channel implementation must implement
    * SEND_OPTIONS_SECURE - Message is sent over an encrypted channel
    * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_SECURE = 0x0010; /** * Send options. When a message is sent with this flag on * the system sends the message using UDP instead of TCP * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_UDP = 0x0020; /** * Send options. When a message is sent with this flag on * the system sends a UDP message on the Multicast address instead of UDP or TCP to individual addresses * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_MULTICAST = 0x0040; /** * Send options, when a message is sent, it can have an option flag * to trigger certain behavior. Most flags are used to trigger channel interceptors * as the message passes through the channel stack.
    * However, there are five default flags that every channel implementation must implement
    * SEND_OPTIONS_DEFAULT - the default sending options, just a helper variable.
    * The default is int SEND_OPTIONS_DEFAULT = SEND_OPTIONS_USE_ACK;
    * @see #SEND_OPTIONS_USE_ACK * @see #send(Member[], Serializable , int) * @see #send(Member[], Serializable, int, ErrorHandler) */ public static final int SEND_OPTIONS_DEFAULT = SEND_OPTIONS_USE_ACK; /** * Adds an interceptor to the channel message chain. * @param interceptor ChannelInterceptor */ public void addInterceptor(ChannelInterceptor interceptor); /** * Starts up the channel. This can be called multiple times for individual services to start * The svc parameter can be the logical or value of any constants * @param svc int value of
    * DEFAULT - will start all services
    * MBR_RX_SEQ - starts the membership receiver
    * MBR_TX_SEQ - starts the membership broadcaster
    * SND_TX_SEQ - starts the replication transmitter
    * SND_RX_SEQ - starts the replication receiver
    * Note: In order for the membership broadcaster to * transmit the correct information, it has to be started after the replication receiver. * @throws ChannelException if a startup error occurs or the service is already started or an error occurs. */ public void start(int svc) throws ChannelException; /** * Shuts down the channel. This can be called multiple times for individual services to shutdown * The svc parameter can be the logical or value of any constants * @param svc int value of
    * DEFAULT - will shutdown all services
    * MBR_RX_SEQ - stops the membership receiver
    * MBR_TX_SEQ - stops the membership broadcaster
    * SND_TX_SEQ - stops the replication transmitter
    * SND_RX_SEQ - stops the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already stopped or an error occurs. */ public void stop(int svc) throws ChannelException; /** * Send a message to one or more members in the cluster * @param destination Member[] - the destinations, can not be null or zero length, the reason for that * is that a membership change can occur and at that time the application is uncertain what group the message * actually got sent to. * @param msg Serializable - the message to send, has to be serializable, or a ByteMessage to * send a pure byte array * @param options int - sender options, see class documentation for each interceptor that is configured in order to trigger interceptors * @return a unique Id that identifies the message that is sent * @see ByteMessage * @see #SEND_OPTIONS_USE_ACK * @see #SEND_OPTIONS_ASYNCHRONOUS * @see #SEND_OPTIONS_SYNCHRONIZED_ACK */ public UniqueId send(Member[] destination, Serializable msg, int options) throws ChannelException; /** * Send a message to one or more members in the cluster * @param destination Member[] - the destinations, null or zero length means all * @param msg ClusterMessage - the message to send * @param options int - sender options, see class documentation * @param handler ErrorHandler - handle errors through a callback, rather than throw it * @return a unique Id that identifies the message that is sent * @exception ChannelException - if a serialization error happens. */ public UniqueId send(Member[] destination, Serializable msg, int options, ErrorHandler handler) throws ChannelException; /** * Sends a heart beat through the interceptor stacks * Use this method to alert interceptors and other components to * clean up garbage, timed out messages etc.
    * If you application has a background thread, then you can save one thread, * by configuring your channel to not use an internal heartbeat thread * and invoking this method. * @see #setHeartbeat(boolean) */ public void heartbeat(); /** * Enables or disables internal heartbeat. * @param enable boolean - default value is implementation specific * @see #heartbeat() */ public void setHeartbeat(boolean enable); /** * Add a membership listener, will get notified when a new member joins, leaves or crashes *
    If the membership listener implements the Heartbeat interface * the heartbeat() method will be invoked when the heartbeat runs on the channel * @param listener MembershipListener * @see MembershipListener */ public void addMembershipListener(MembershipListener listener); /** * Add a channel listener, this is a callback object when messages are received *
    If the channel listener implements the Heartbeat interface * the heartbeat() method will be invoked when the heartbeat runs on the channel * @param listener ChannelListener * @see ChannelListener * @see Heartbeat */ public void addChannelListener(ChannelListener listener); /** * remove a membership listener, listeners are removed based on Object.hashCode and Object.equals * @param listener MembershipListener * @see MembershipListener */ public void removeMembershipListener(MembershipListener listener); /** * remove a channel listener, listeners are removed based on Object.hashCode and Object.equals * @param listener ChannelListener * @see ChannelListener */ public void removeChannelListener(ChannelListener listener); /** * Returns true if there are any members in the group, * this call is the same as getMembers().length>0 * @return boolean - true if there are any members automatically discovered */ public boolean hasMembers() ; /** * Get all current group members * @return all members or empty array, never null */ public Member[] getMembers() ; /** * Return the member that represents this node. This is also the data * that gets broadcasted through the membership broadcaster component * @param incAlive - optimization, true if you want it to calculate alive time * since the membership service started. * @return Member */ public Member getLocalMember(boolean incAlive); /** * Returns the member from the membership service with complete and * recent data. Some implementations might serialize and send * membership information along with a message, and instead of sending * complete membership details, only send the primary identifier for the member * but not the payload or other information. When such message is received * the application can retrieve the cached member through this call.
    * In most cases, this is not necessary. * @param mbr Member * @return Member */ public Member getMember(Member mbr); } tomcat7-7.0.52/java/org/apache/catalina/tribes/tipis/0000755000175100017510000000000012301126370022263 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java0000644000175100017510000002405412271464231026514 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.tipis; import java.io.Serializable; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.util.Arrays; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * A smart implementation of a stateful replicated map. uses primary/secondary backup strategy. * One node is always the primary and one node is always the backup. * This map is synchronized across a cluster, and only has one backup member.
    * A perfect usage for this map would be a session map for a session manager in a clustered environment.
    * The only way to modify this list is to use the put, putAll, remove methods. * entrySet, entrySetFull, keySet, keySetFull, returns all non modifiable sets.

    * If objects (values) in the map change without invoking put() or remove() * the data can be distributed using two different methods:
    * replicate(boolean) and replicate(Object, boolean)
    * These two methods are very important two understand. The map can work with two set of value objects:
    * 1. Serializable - the entire object gets serialized each time it is replicated
    * 2. ReplicatedMapEntry - this interface allows for a isDirty() flag and to replicate diffs if desired.
    * Implementing the ReplicatedMapEntry interface allows you to decide what objects * get replicated and how much data gets replicated each time.
    * If you implement a smart AOP mechanism to detect changes in underlying objects, you can replicate * only those changes by implementing the ReplicatedMapEntry interface, and return true when isDiffable() * is invoked.

    * * This map implementation doesn't have a background thread running to replicate changes. * If you do have changes without invoking put/remove then you need to invoke one of the following methods: *
      *
    • replicate(Object,boolean) - replicates only the object that belongs to the key
    • *
    • replicate(boolean) - Scans the entire map for changes and replicates data
    • *
    * the boolean value in the replicate method used to decide * whether to only replicate objects that implement the ReplicatedMapEntry interface * or to replicate all objects. If an object doesn't implement the ReplicatedMapEntry interface * each time the object gets replicated the entire object gets serialized, hence a call to replicate(true) * will replicate all objects in this map that are using this node as primary. * *

    REMBER TO CALL breakdown() or finalize() when you are done with the map to * avoid memory leaks.

    * TODO implement periodic sync/transfer thread * @author Filip Hanik * @version 1.0 */ public class LazyReplicatedMap extends AbstractReplicatedMap { private static final long serialVersionUID = 1L; private final Log log = LogFactory.getLog(LazyReplicatedMap.class); //------------------------------------------------------------------------------ // CONSTRUCTORS / DESTRUCTORS //------------------------------------------------------------------------------ /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel * @param initialCapacity int - the size of this map, see HashMap * @param loadFactor float - load factor, see HashMap */ public LazyReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, int initialCapacity, float loadFactor, ClassLoader[] cls) { super(owner,channel,timeout,mapContextName,initialCapacity,loadFactor, Channel.SEND_OPTIONS_DEFAULT,cls, true); } /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel * @param initialCapacity int - the size of this map, see HashMap */ public LazyReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, int initialCapacity, ClassLoader[] cls) { super(owner, channel,timeout,mapContextName,initialCapacity, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR, Channel.SEND_OPTIONS_DEFAULT, cls, true); } /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel */ public LazyReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls) { super(owner, channel,timeout,mapContextName, AbstractReplicatedMap.DEFAULT_INITIAL_CAPACITY,AbstractReplicatedMap.DEFAULT_LOAD_FACTOR,Channel.SEND_OPTIONS_DEFAULT, cls, true); } /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel * @param terminate boolean - Flag for whether to terminate this map that failed to start. */ public LazyReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls, boolean terminate) { super(owner, channel,timeout,mapContextName, AbstractReplicatedMap.DEFAULT_INITIAL_CAPACITY, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR,Channel.SEND_OPTIONS_DEFAULT, cls, terminate); } //------------------------------------------------------------------------------ // METHODS TO OVERRIDE //------------------------------------------------------------------------------ @Override protected int getStateMessageType() { return AbstractReplicatedMap.MapMessage.MSG_STATE; } /** * publish info about a map pair (key/value) to other nodes in the cluster * @param key Object * @param value Object * @return Member - the backup node * @throws ChannelException */ @Override protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException { if (! (key instanceof Serializable && value instanceof Serializable) ) return new Member[0]; Member[] members = getMapMembers(); int firstIdx = getNextBackupIndex(); int nextIdx = firstIdx; Member[] backup = new Member[0]; //there are no backups if ( members.length == 0 || firstIdx == -1 ) return backup; boolean success = false; do { //select a backup node Member next = members[nextIdx]; //increment for the next round of back up selection nextIdx = nextIdx + 1; if ( nextIdx >= members.length ) nextIdx = 0; if (next == null) { continue; } MapMessage msg = null; try { backup = wrap(next); //publish the backup data to one node msg = new MapMessage(getMapContextName(), MapMessage.MSG_BACKUP, false, (Serializable) key, (Serializable) value, null, channel.getLocalMember(false), backup); if ( log.isTraceEnabled() ) log.trace("Publishing backup data:"+msg+" to: "+next.getName()); UniqueId id = getChannel().send(backup, msg, getChannelSendOptions()); if ( log.isTraceEnabled() ) log.trace("Data published:"+msg+" msg Id:"+id); //we published out to a backup, mark the test success success = true; }catch ( ChannelException x ) { log.error("Unable to replicate backup key:"+key+" to backup:"+next+". Reason:"+x.getMessage(),x); } try { //publish the data out to all nodes Member[] proxies = excludeFromSet(backup, getMapMembers()); if (success && proxies.length > 0 ) { msg = new MapMessage(getMapContextName(), MapMessage.MSG_PROXY, false, (Serializable) key, null, null, channel.getLocalMember(false),backup); if ( log.isTraceEnabled() ) log.trace("Publishing proxy data:"+msg+" to: "+Arrays.toNameString(proxies)); getChannel().send(proxies, msg, getChannelSendOptions()); } }catch ( ChannelException x ) { //log the error, but proceed, this should only happen if a node went down, //and if the node went down, then it can't receive the message, the others //should still get it. log.error("Unable to replicate proxy key:"+key+" to backup:"+next+". Reason:"+x.getMessage(),x); } } while ( !success && (firstIdx!=nextIdx)); return backup; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java0000644000175100017510000016403012271464231027337 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.tipis; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.Serializable; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelException.FaultyMember; import org.apache.catalina.tribes.ChannelListener; import org.apache.catalina.tribes.Heartbeat; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; import org.apache.catalina.tribes.group.Response; import org.apache.catalina.tribes.group.RpcCallback; import org.apache.catalina.tribes.group.RpcChannel; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.membership.MemberImpl; import org.apache.catalina.tribes.util.Arrays; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * * @author Filip Hanik * @version 1.0 */ @SuppressWarnings("rawtypes") public abstract class AbstractReplicatedMap extends ConcurrentHashMap implements RpcCallback, ChannelListener, MembershipListener, Heartbeat { private static final long serialVersionUID = 1L; private final Log log = LogFactory.getLog(AbstractReplicatedMap.class); /** * The default initial capacity - MUST be a power of two. */ public static final int DEFAULT_INITIAL_CAPACITY = 16; /** * The load factor used when none specified in constructor. **/ public static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * Used to identify the map */ private static final Charset CHARSET_ISO_8859_1 = Charset.forName("ISO-8859-1"); //------------------------------------------------------------------------------ // INSTANCE VARIABLES //------------------------------------------------------------------------------ protected abstract int getStateMessageType(); /** * Timeout for RPC messages, how long we will wait for a reply */ protected transient long rpcTimeout = 5000; /** * Reference to the channel for sending messages */ protected transient Channel channel; /** * The RpcChannel to send RPC messages through */ protected transient RpcChannel rpcChannel; /** * The Map context name makes this map unique, this * allows us to have more than one map shared * through one channel */ protected transient byte[] mapContextName; /** * Has the state been transferred */ protected transient boolean stateTransferred = false; /** * Simple lock object for transfers */ protected transient Object stateMutex = new Object(); /** * A list of members in our map */ protected transient HashMap mapMembers = new HashMap(); /** * Our default send options */ protected transient int channelSendOptions = Channel.SEND_OPTIONS_DEFAULT; /** * The owner of this map, ala a SessionManager for example */ protected transient MapOwner mapOwner; /** * External class loaders if serialization and deserialization is to be performed successfully. */ protected transient ClassLoader[] externalLoaders; /** * The node we are currently backing up data to, this index will rotate * on a round robin basis */ protected transient int currentNode = 0; /** * Since the map keeps internal membership * this is the timeout for a ping message to be responded to * If a remote map doesn't respond within this timeframe, * its considered dead. */ protected transient long accessTimeout = 5000; /** * Readable string of the mapContextName value */ protected transient String mapname = ""; //------------------------------------------------------------------------------ // map owner interface //------------------------------------------------------------------------------ public static interface MapOwner { // a typo, should have been "objectMadePrimary" public void objectMadePrimay(Object key, Object value); } //------------------------------------------------------------------------------ // CONSTRUCTORS //------------------------------------------------------------------------------ /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel * @param initialCapacity int - the size of this map, see HashMap * @param loadFactor float - load factor, see HashMap * @param cls - a list of classloaders to be used for deserialization of objects. */ public AbstractReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, int initialCapacity, float loadFactor, int channelSendOptions, ClassLoader[] cls, boolean terminate) { super(initialCapacity, loadFactor, 15); init(owner, channel, mapContextName, timeout, channelSendOptions, cls, terminate); } /** * Helper methods, wraps a single member in an array * @param m Member * @return Member[] */ protected Member[] wrap(Member m) { if ( m == null ) return new Member[0]; else return new Member[] {m}; } /** * Initializes the map by creating the RPC channel, registering itself as a channel listener * This method is also responsible for initiating the state transfer * @param owner Object * @param channel Channel * @param mapContextName String * @param timeout long * @param channelSendOptions int * @param cls ClassLoader[] */ protected void init(MapOwner owner, Channel channel, String mapContextName, long timeout, int channelSendOptions,ClassLoader[] cls, boolean terminate) { long start = System.currentTimeMillis(); log.info("Initializing AbstractReplicatedMap with context name:"+mapContextName); this.mapOwner = owner; this.externalLoaders = cls; this.channelSendOptions = channelSendOptions; this.channel = channel; this.rpcTimeout = timeout; this.mapname = mapContextName; //unique context is more efficient if it is stored as bytes this.mapContextName = mapContextName.getBytes(CHARSET_ISO_8859_1); if ( log.isTraceEnabled() ) log.trace("Created Lazy Map with name:"+mapContextName+", bytes:"+Arrays.toString(this.mapContextName)); //create an rpc channel and add the map as a listener this.rpcChannel = new RpcChannel(this.mapContextName, channel, this); //add this map as a message listener this.channel.addChannelListener(this); //listen for membership notifications this.channel.addMembershipListener(this); try { //broadcast our map, this just notifies other members of our existence broadcast(MapMessage.MSG_INIT, true); //transfer state from another map transferState(); //state is transferred, we are ready for messaging broadcast(MapMessage.MSG_START, true); } catch (ChannelException x) { log.warn("Unable to send map start message."); if (terminate) { breakdown(); throw new RuntimeException("Unable to start replicated map.",x); } } long complete = System.currentTimeMillis() - start; if (log.isInfoEnabled()) log.info("AbstractReplicatedMap[" +mapContextName + "] initialization was completed in " + complete + " ms."); } /** * Sends a ping out to all the members in the cluster, not just map members * that this map is alive. * @param timeout long * @throws ChannelException */ protected void ping(long timeout) throws ChannelException { //send out a map membership message, only wait for the first reply MapMessage msg = new MapMessage(this.mapContextName, MapMessage.MSG_INIT, false, null, null, null, channel.getLocalMember(false), null); if ( channel.getMembers().length > 0 ) { try { //send a ping, wait for all nodes to reply Response[] resp = rpcChannel.send(channel.getMembers(), msg, RpcChannel.ALL_REPLY, (channelSendOptions), (int) accessTimeout); for (int i = 0; i < resp.length; i++) { memberAlive(resp[i].getSource()); } } catch (ChannelException ce) { // Handle known failed members FaultyMember[] faultyMembers = ce.getFaultyMembers(); for (FaultyMember faultyMember : faultyMembers) { memberDisappeared(faultyMember.getMember()); } throw ce; } } //update our map of members, expire some if we didn't receive a ping back synchronized (mapMembers) { Member[] members = mapMembers.keySet().toArray(new Member[mapMembers.size()]); long now = System.currentTimeMillis(); for (Member member : members) { long access = mapMembers.get(member); if ( (now - access) > timeout ) { memberDisappeared(member); } } }//synch } /** * We have received a member alive notification * @param member Member */ protected void memberAlive(Member member) { synchronized (mapMembers) { if (!mapMembers.containsKey(member)) { mapMemberAdded(member); } //end if mapMembers.put(member, new Long(System.currentTimeMillis())); } } /** * Helper method to broadcast a message to all members in a channel * @param msgtype int * @param rpc boolean * @throws ChannelException */ protected void broadcast(int msgtype, boolean rpc) throws ChannelException { Member[] members = channel.getMembers(); // No destination. if (members.length == 0 ) return; //send out a map membership message, only wait for the first reply MapMessage msg = new MapMessage(this.mapContextName, msgtype, false, null, null, null, channel.getLocalMember(false), null); if ( rpc) { Response[] resp = rpcChannel.send(members, msg, RpcChannel.FIRST_REPLY, (channelSendOptions), rpcTimeout); if (resp.length > 0) { for (int i = 0; i < resp.length; i++) { mapMemberAdded(resp[i].getSource()); messageReceived(resp[i].getMessage(), resp[i].getSource()); } } else { log.warn("broadcast received 0 replies, probably a timeout."); } } else { channel.send(channel.getMembers(),msg,channelSendOptions); } } public void breakdown() { finalize(); } @Override public void finalize() { if (this.rpcChannel != null) { this.rpcChannel.breakdown(); } try {broadcast(MapMessage.MSG_STOP,false); }catch ( Exception ignore){} //cleanup if (this.channel != null) { this.channel.removeChannelListener(this); this.channel.removeMembershipListener(this); } this.rpcChannel = null; this.channel = null; this.mapMembers.clear(); super.clear(); this.stateTransferred = false; this.externalLoaders = null; } @Override public int hashCode() { return Arrays.hashCode(this.mapContextName); } @Override public boolean equals(Object o) { if ( !(o instanceof AbstractReplicatedMap)) return false; if ( !(o.getClass().equals(this.getClass())) ) return false; AbstractReplicatedMap other = (AbstractReplicatedMap)o; return Arrays.equals(mapContextName,other.mapContextName); } //------------------------------------------------------------------------------ // GROUP COM INTERFACES //------------------------------------------------------------------------------ public Member[] getMapMembers(HashMap members) { synchronized (members) { Member[] result = new Member[members.size()]; members.keySet().toArray(result); return result; } } public Member[] getMapMembers() { return getMapMembers(this.mapMembers); } public Member[] getMapMembersExcl(Member[] exclude) { synchronized (mapMembers) { @SuppressWarnings("unchecked") // mapMembers has the correct type HashMap list = (HashMap)mapMembers.clone(); for (int i=0; i * @param complete - if set to true, the object is replicated to its backup * if set to false, only objects that implement ReplicatedMapEntry and the isDirty() returns true will * be replicated */ public void replicate(Object key, boolean complete) { if ( log.isTraceEnabled() ) log.trace("Replicate invoked on key:"+key); MapEntry entry = (MapEntry)super.get(key); if ( entry == null ) return; if ( !entry.isSerializable() ) return; if (entry.isPrimary() && entry.getBackupNodes()!= null && entry.getBackupNodes().length > 0) { //check to see if we need to replicate this object isDirty()||complete || isAccessReplicate() ReplicatedMapEntry rentry = null; if (entry.getValue() instanceof ReplicatedMapEntry) rentry = (ReplicatedMapEntry)entry.getValue(); boolean isDirty = rentry != null && rentry.isDirty(); boolean isAccess = rentry != null && rentry.isAccessReplicate(); boolean repl = complete || isDirty || isAccess; if (!repl) { if ( log.isTraceEnabled() ) log.trace("Not replicating:"+key+", no change made"); return; } //check to see if the message is diffable boolean diff = rentry != null && rentry.isDiffable(); MapMessage msg = null; if (diff && (isDirty || complete)) { try { rentry.lock(); //construct a diff message msg = new MapMessage(mapContextName, MapMessage.MSG_BACKUP, true, (Serializable) entry.getKey(), null, rentry.getDiff(), entry.getPrimary(), entry.getBackupNodes()); rentry.resetDiff(); } catch (IOException x) { log.error("Unable to diff object. Will replicate the entire object instead.", x); } finally { rentry.unlock(); } } if (msg == null && complete) { //construct a complete msg = new MapMessage(mapContextName, MapMessage.MSG_BACKUP, false, (Serializable) entry.getKey(), (Serializable) entry.getValue(), null, entry.getPrimary(),entry.getBackupNodes()); } if (msg == null) { //construct a access message msg = new MapMessage(mapContextName, MapMessage.MSG_ACCESS, false, (Serializable) entry.getKey(), null, null, entry.getPrimary(), entry.getBackupNodes()); } try { if ( channel!=null && entry.getBackupNodes()!= null && entry.getBackupNodes().length > 0 ) { if (rentry != null) rentry.setLastTimeReplicated(System.currentTimeMillis()); channel.send(entry.getBackupNodes(), msg, channelSendOptions); } } catch (ChannelException x) { log.error("Unable to replicate data.", x); } } //end if } /** * This can be invoked by a periodic thread to replicate out any changes. * For maps that don't store objects that implement ReplicatedMapEntry, this * method should be used infrequently to avoid large amounts of data transfer * @param complete boolean */ public void replicate(boolean complete) { @SuppressWarnings("unchecked") Iterator> i = super.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = i.next(); replicate(e.getKey(), complete); } //while } public void transferState() { try { Member[] members = getMapMembers(); Member backup = members.length > 0 ? (Member) members[0] : null; if (backup != null) { MapMessage msg = new MapMessage(mapContextName, getStateMessageType(), false, null, null, null, null, null); Response[] resp = rpcChannel.send(new Member[] {backup}, msg, RpcChannel.FIRST_REPLY, channelSendOptions, rpcTimeout); if (resp.length > 0) { synchronized (stateMutex) { msg = (MapMessage) resp[0].getMessage(); msg.deserialize(getExternalLoaders()); ArrayList list = (ArrayList) msg.getValue(); for (int i = 0; i < list.size(); i++) { messageReceived( (Serializable) list.get(i), resp[0].getSource()); } //for } } else { log.warn("Transfer state, 0 replies, probably a timeout."); } } } catch (ChannelException x) { log.error("Unable to transfer LazyReplicatedMap state.", x); } catch (IOException x) { log.error("Unable to transfer LazyReplicatedMap state.", x); } catch (ClassNotFoundException x) { log.error("Unable to transfer LazyReplicatedMap state.", x); } stateTransferred = true; } /** * TODO implement state transfer * @param msg Serializable * @return Serializable - null if no reply should be sent */ @Override public Serializable replyRequest(Serializable msg, final Member sender) { if (! (msg instanceof MapMessage))return null; MapMessage mapmsg = (MapMessage) msg; //map init request if (mapmsg.getMsgType() == MapMessage.MSG_INIT) { mapmsg.setPrimary(channel.getLocalMember(false)); return mapmsg; } //map start request if (mapmsg.getMsgType() == MapMessage.MSG_START) { mapmsg.setPrimary(channel.getLocalMember(false)); mapMemberAdded(sender); return mapmsg; } //backup request if (mapmsg.getMsgType() == MapMessage.MSG_RETRIEVE_BACKUP) { MapEntry entry = (MapEntry)super.get(mapmsg.getKey()); if (entry == null || (!entry.isSerializable()) )return null; mapmsg.setValue( (Serializable) entry.getValue()); return mapmsg; } //state transfer request if (mapmsg.getMsgType() == MapMessage.MSG_STATE || mapmsg.getMsgType() == MapMessage.MSG_STATE_COPY) { synchronized (stateMutex) { //make sure we dont do two things at the same time ArrayList list = new ArrayList(); @SuppressWarnings("unchecked") Iterator> i = super.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = i.next(); MapEntry entry = (MapEntry) super.get(e.getKey()); if ( entry != null && entry.isSerializable() ) { boolean copy = (mapmsg.getMsgType() == MapMessage.MSG_STATE_COPY); MapMessage me = new MapMessage(mapContextName, copy?MapMessage.MSG_COPY:MapMessage.MSG_PROXY, false, (Serializable) entry.getKey(), copy?(Serializable) entry.getValue():null, null, entry.getPrimary(),entry.getBackupNodes()); list.add(me); } } mapmsg.setValue(list); return mapmsg; } //synchronized } return null; } /** * If the reply has already been sent to the requesting thread, * the rpc callback can handle any data that comes in after the fact. * @param msg Serializable * @param sender Member */ @Override public void leftOver(Serializable msg, Member sender) { //left over membership messages if (! (msg instanceof MapMessage))return; MapMessage mapmsg = (MapMessage) msg; try { mapmsg.deserialize(getExternalLoaders()); if (mapmsg.getMsgType() == MapMessage.MSG_START) { mapMemberAdded(mapmsg.getPrimary()); } else if (mapmsg.getMsgType() == MapMessage.MSG_INIT) { memberAlive(mapmsg.getPrimary()); } } catch (IOException x ) { log.error("Unable to deserialize MapMessage.",x); } catch (ClassNotFoundException x ) { log.error("Unable to deserialize MapMessage.",x); } } @SuppressWarnings("unchecked") @Override public void messageReceived(Serializable msg, Member sender) { if (! (msg instanceof MapMessage)) return; MapMessage mapmsg = (MapMessage) msg; if ( log.isTraceEnabled() ) { log.trace("Map["+mapname+"] received message:"+mapmsg); } try { mapmsg.deserialize(getExternalLoaders()); } catch (IOException x) { log.error("Unable to deserialize MapMessage.", x); return; } catch (ClassNotFoundException x) { log.error("Unable to deserialize MapMessage.", x); return; } if ( log.isTraceEnabled() ) log.trace("Map message received from:"+sender.getName()+" msg:"+mapmsg); if (mapmsg.getMsgType() == MapMessage.MSG_START) { mapMemberAdded(mapmsg.getPrimary()); } if (mapmsg.getMsgType() == MapMessage.MSG_STOP) { memberDisappeared(mapmsg.getPrimary()); } if (mapmsg.getMsgType() == MapMessage.MSG_PROXY) { MapEntry entry = (MapEntry)super.get(mapmsg.getKey()); if ( entry==null ) { entry = new MapEntry(mapmsg.getKey(), mapmsg.getValue()); entry.setBackup(false); entry.setProxy(true); entry.setBackupNodes(mapmsg.getBackupNodes()); entry.setPrimary(mapmsg.getPrimary()); super.put(entry.getKey(), entry); } else { entry.setProxy(true); entry.setBackup(false); entry.setBackupNodes(mapmsg.getBackupNodes()); entry.setPrimary(mapmsg.getPrimary()); } } if (mapmsg.getMsgType() == MapMessage.MSG_REMOVE) { super.remove(mapmsg.getKey()); } if (mapmsg.getMsgType() == MapMessage.MSG_BACKUP || mapmsg.getMsgType() == MapMessage.MSG_COPY) { MapEntry entry = (MapEntry)super.get(mapmsg.getKey()); if (entry == null) { entry = new MapEntry(mapmsg.getKey(), mapmsg.getValue()); entry.setBackup(mapmsg.getMsgType() == MapMessage.MSG_BACKUP); entry.setProxy(false); entry.setBackupNodes(mapmsg.getBackupNodes()); entry.setPrimary(mapmsg.getPrimary()); if (mapmsg.getValue()!=null && mapmsg.getValue() instanceof ReplicatedMapEntry ) { ((ReplicatedMapEntry)mapmsg.getValue()).setOwner(getMapOwner()); } } else { entry.setBackup(mapmsg.getMsgType() == MapMessage.MSG_BACKUP); entry.setProxy(false); entry.setBackupNodes(mapmsg.getBackupNodes()); entry.setPrimary(mapmsg.getPrimary()); if (entry.getValue() instanceof ReplicatedMapEntry) { ReplicatedMapEntry diff = (ReplicatedMapEntry) entry.getValue(); if (mapmsg.isDiff()) { try { diff.lock(); diff.applyDiff(mapmsg.getDiffValue(), 0, mapmsg.getDiffValue().length); } catch (Exception x) { log.error("Unable to apply diff to key:" + entry.getKey(), x); } finally { diff.unlock(); } } else { if ( mapmsg.getValue()!=null ) entry.setValue(mapmsg.getValue()); ((ReplicatedMapEntry)entry.getValue()).setOwner(getMapOwner()); } //end if } else if (mapmsg.getValue() instanceof ReplicatedMapEntry) { ReplicatedMapEntry re = (ReplicatedMapEntry)mapmsg.getValue(); re.setOwner(getMapOwner()); entry.setValue(re); } else { if ( mapmsg.getValue()!=null ) entry.setValue(mapmsg.getValue()); } //end if } //end if super.put(entry.getKey(), entry); } //end if if (mapmsg.getMsgType() == MapMessage.MSG_ACCESS) { MapEntry entry = (MapEntry)super.get(mapmsg.getKey()); if (entry != null) { entry.setBackupNodes(mapmsg.getBackupNodes()); entry.setPrimary(mapmsg.getPrimary()); if (entry.getValue() instanceof ReplicatedMapEntry) { ((ReplicatedMapEntry) entry.getValue()).accessEntry(); } } } } @Override public boolean accept(Serializable msg, Member sender) { boolean result = false; if (msg instanceof MapMessage) { if ( log.isTraceEnabled() ) log.trace("Map["+mapname+"] accepting...."+msg); result = Arrays.equals(mapContextName, ( (MapMessage) msg).getMapId()); if ( log.isTraceEnabled() ) log.trace("Msg["+mapname+"] accepted["+result+"]...."+msg); } return result; } public void mapMemberAdded(Member member) { if ( member.equals(getChannel().getLocalMember(false)) ) return; boolean memberAdded = false; //select a backup node if we don't have one synchronized (mapMembers) { if (!mapMembers.containsKey(member) ) { mapMembers.put(member, new Long(System.currentTimeMillis())); memberAdded = true; } } if ( memberAdded ) { synchronized (stateMutex) { @SuppressWarnings("unchecked") Iterator> i = super.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = i.next(); MapEntry entry = (MapEntry) super.get(e.getKey()); if ( entry == null ) continue; if (entry.isPrimary() && (entry.getBackupNodes() == null || entry.getBackupNodes().length == 0)) { try { Member[] backup = publishEntryInfo(entry.getKey(), entry.getValue()); entry.setBackupNodes(backup); entry.setPrimary(channel.getLocalMember(false)); } catch (ChannelException x) { log.error("Unable to select backup node.", x); } //catch } //end if } //while } //synchronized }//end if } public boolean inSet(Member m, Member[] set) { if ( set == null ) return false; boolean result = false; for (int i=0; i result = new ArrayList(); for (int i=0; i> i = super.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = i.next(); MapEntry entry = (MapEntry) super.get(e.getKey()); if (entry==null) continue; if (entry.isPrimary() && inSet(member,entry.getBackupNodes())) { if (log.isDebugEnabled()) log.debug("[1] Primary choosing a new backup"); try { Member[] backup = publishEntryInfo(entry.getKey(), entry.getValue()); entry.setBackupNodes(backup); entry.setPrimary(channel.getLocalMember(false)); } catch (ChannelException x) { log.error("Unable to relocate[" + entry.getKey() + "] to a new backup node", x); } } else if (member.equals(entry.getPrimary())) { if (log.isDebugEnabled()) log.debug("[2] Primary disappeared"); entry.setPrimary(null); } //end if if ( entry.isProxy() && entry.getPrimary() == null && entry.getBackupNodes()!=null && entry.getBackupNodes().length == 1 && entry.getBackupNodes()[0].equals(member) ) { //remove proxies that have no backup nor primaries if (log.isDebugEnabled()) log.debug("[3] Removing orphaned proxy"); i.remove(); } else if ( entry.getPrimary() == null && entry.isBackup() && entry.getBackupNodes()!=null && entry.getBackupNodes().length == 1 && entry.getBackupNodes()[0].equals(channel.getLocalMember(false)) ) { try { if (log.isDebugEnabled()) log.debug("[4] Backup becoming primary"); entry.setPrimary(channel.getLocalMember(false)); entry.setBackup(false); entry.setProxy(false); Member[] backup = publishEntryInfo(entry.getKey(), entry.getValue()); entry.setBackupNodes(backup); if ( mapOwner!=null ) mapOwner.objectMadePrimay(entry.getKey(),entry.getValue()); } catch (ChannelException x) { log.error("Unable to relocate[" + entry.getKey() + "] to a new backup node", x); } } } //while long complete = System.currentTimeMillis() - start; if (log.isInfoEnabled()) log.info("Relocation of map entries was complete in " + complete + " ms."); } public int getNextBackupIndex() { int size = mapMembers.size(); if (mapMembers.size() == 0)return -1; int node = currentNode++; if (node >= size) { node = 0; currentNode = 0; } return node; } public Member getNextBackupNode() { Member[] members = getMapMembers(); int node = getNextBackupIndex(); if ( members.length == 0 || node==-1) return null; if ( node >= members.length ) node = 0; return members[node]; } protected abstract Member[] publishEntryInfo(Object key, Object value) throws ChannelException; @Override public void heartbeat() { try { ping(accessTimeout); }catch ( Exception x ) { log.error("Unable to send AbstractReplicatedMap.ping message",x); } } //------------------------------------------------------------------------------ // METHODS TO OVERRIDE //------------------------------------------------------------------------------ /** * Removes an object from this map, it will also remove it from * * @param key Object * @return Object */ @Override public Object remove(Object key) { return remove(key,true); } public Object remove(Object key, boolean notify) { MapEntry entry = (MapEntry)super.remove(key); try { if (getMapMembers().length > 0 && notify) { MapMessage msg = new MapMessage(getMapContextName(), MapMessage.MSG_REMOVE, false, (Serializable) key, null, null, null,null); getChannel().send(getMapMembers(), msg, getChannelSendOptions()); } } catch ( ChannelException x ) { log.error("Unable to replicate out data for a LazyReplicatedMap.remove operation",x); } return entry!=null?entry.getValue():null; } public MapEntry getInternal(Object key) { return (MapEntry)super.get(key); } @Override public Object get(Object key) { MapEntry entry = (MapEntry)super.get(key); if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" entry:"+entry); if ( entry == null ) return null; if ( !entry.isPrimary() ) { //if the message is not primary, we need to retrieve the latest value try { Member[] backup = null; MapMessage msg = null; if ( !entry.isBackup() ) { //make sure we don't retrieve from ourselves msg = new MapMessage(getMapContextName(), MapMessage.MSG_RETRIEVE_BACKUP, false, (Serializable) key, null, null, null,null); Response[] resp = getRpcChannel().send(entry.getBackupNodes(),msg, RpcChannel.FIRST_REPLY, Channel.SEND_OPTIONS_DEFAULT, getRpcTimeout()); if (resp == null || resp.length == 0) { //no responses log.warn("Unable to retrieve remote object for key:" + key); return null; } msg = (MapMessage) resp[0].getMessage(); msg.deserialize(getExternalLoaders()); backup = entry.getBackupNodes(); if ( entry.getValue() instanceof ReplicatedMapEntry ) { ReplicatedMapEntry val = (ReplicatedMapEntry)entry.getValue(); val.setOwner(getMapOwner()); } if ( msg.getValue()!=null ) entry.setValue(msg.getValue()); } if (entry.isBackup()) { //select a new backup node backup = publishEntryInfo(key, entry.getValue()); } else if ( entry.isProxy() ) { //invalidate the previous primary msg = new MapMessage(getMapContextName(),MapMessage.MSG_PROXY,false,(Serializable)key,null,null,channel.getLocalMember(false),backup); Member[] dest = getMapMembersExcl(backup); if ( dest!=null && dest.length >0) { getChannel().send(dest, msg, getChannelSendOptions()); } if ( entry.getValue() != null && entry.getValue() instanceof ReplicatedMapEntry ) { ReplicatedMapEntry val = (ReplicatedMapEntry)entry.getValue(); val.setOwner(getMapOwner()); } } entry.setPrimary(channel.getLocalMember(false)); entry.setBackupNodes(backup); entry.setBackup(false); entry.setProxy(false); if ( getMapOwner()!=null ) getMapOwner().objectMadePrimay(key, entry.getValue()); } catch (Exception x) { log.error("Unable to replicate out data for a LazyReplicatedMap.get operation", x); return null; } } if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" result:"+entry.getValue()); return entry.getValue(); } protected void printMap(String header) { try { System.out.println("\nDEBUG MAP:"+header); System.out.println("Map[" + new String(mapContextName, CHARSET_ISO_8859_1) + ", Map Size:" + super.size()); Member[] mbrs = getMapMembers(); for ( int i=0; i> i = super.entrySet().iterator(); int cnt = 0; while (i.hasNext()) { Map.Entry e = i.next(); System.out.println( (++cnt) + ". " + super.get(e.getKey())); } System.out.println("EndMap]\n\n"); }catch ( Exception ignore) { ignore.printStackTrace(); } } /** * Returns true if the key has an entry in the map. * The entry can be a proxy or a backup entry, invoking get(key) * will make this entry primary for the group * @param key Object * @return boolean */ @Override public boolean containsKey(Object key) { return super.containsKey(key); } @Override public Object put(Object key, Object value) { return put(key,value,true); } @SuppressWarnings("unchecked") public Object put(Object key, Object value, boolean notify) { MapEntry entry = new MapEntry(key,value); entry.setBackup(false); entry.setProxy(false); entry.setPrimary(channel.getLocalMember(false)); Object old = null; //make sure that any old values get removed if ( containsKey(key) ) old = remove(key); try { if ( notify ) { Member[] backup = publishEntryInfo(key, value); entry.setBackupNodes(backup); } } catch (ChannelException x) { log.error("Unable to replicate out data for a LazyReplicatedMap.put operation", x); } super.put(key,entry); return old; } /** * Copies all values from one map to this instance * @param m Map */ @Override public void putAll(Map m) { @SuppressWarnings("unchecked") Iterator> i = m.entrySet().iterator(); while ( i.hasNext() ) { Map.Entry entry = i.next(); put(entry.getKey(),entry.getValue()); } } @Override public void clear() { clear(true); } public void clear(boolean notify) { if ( notify ) { //only delete active keys Iterator keys = keySet().iterator(); while (keys.hasNext()) remove(keys.next()); } else { super.clear(); } } @Override public boolean containsValue(Object value) { if ( value == null ) { return super.containsValue(value); } else { @SuppressWarnings("unchecked") Iterator> i = super.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = i.next(); MapEntry entry = (MapEntry) super.get(e.getKey()); if (entry!=null && entry.isActive() && value.equals(entry.getValue())) return true; }//while return false; }//end if } @Override public Object clone() { throw new UnsupportedOperationException("This operation is not valid on a replicated map"); } /** * Returns the entire contents of the map * Map.Entry.getValue() will return a LazyReplicatedMap.MapEntry object containing all the information * about the object. * @return Set */ public Set entrySetFull() { return super.entrySet(); } public Set keySetFull() { return super.keySet(); } public int sizeFull() { return super.size(); } @Override public Set entrySet() { LinkedHashSet set = new LinkedHashSet(super.size()); @SuppressWarnings("unchecked") Iterator> i = super.entrySet().iterator(); while ( i.hasNext() ) { Map.Entry e = i.next(); Object key = e.getKey(); MapEntry entry = (MapEntry)super.get(key); if ( entry != null && entry.isActive() ) { set.add(new MapEntry(key, entry.getValue())); } } return Collections.unmodifiableSet(set); } @Override public Set keySet() { //todo implement //should only return keys where this is active. LinkedHashSet set = new LinkedHashSet(super.size()); @SuppressWarnings("unchecked") Iterator> i = super.entrySet().iterator(); while ( i.hasNext() ) { Map.Entry e = i.next(); Object key = e.getKey(); MapEntry entry = (MapEntry)super.get(key); if ( entry!=null && entry.isActive() ) set.add(key); } return Collections.unmodifiableSet(set); } @Override public int size() { //todo, implement a counter variable instead //only count active members in this node int counter = 0; @SuppressWarnings("unchecked") Iterator> it = super.entrySet().iterator(); while (it!=null && it.hasNext() ) { Map.Entry e = it.next(); if ( e != null ) { MapEntry entry = (MapEntry) super.get(e.getKey()); if (entry!=null && entry.isActive() && entry.getValue() != null) counter++; } } return counter; } @Override public boolean isEmpty() { return size()==0; } @Override public Collection values() { ArrayList values = new ArrayList(); @SuppressWarnings("unchecked") Iterator> i = super.entrySet().iterator(); while ( i.hasNext() ) { Map.Entry e = i.next(); MapEntry entry = (MapEntry)super.get(e.getKey()); if (entry!=null && entry.isActive() && entry.getValue()!=null) values.add(entry.getValue()); } return Collections.unmodifiableCollection(values); } //------------------------------------------------------------------------------ // Map Entry class //------------------------------------------------------------------------------ public static class MapEntry implements Map.Entry { private boolean backup; private boolean proxy; private Member[] backupNodes; private Member primary; private Object key; private Object value; public MapEntry(Object key, Object value) { setKey(key); setValue(value); } public boolean isKeySerializable() { return (key == null) || (key instanceof Serializable); } public boolean isValueSerializable() { return (value==null) || (value instanceof Serializable); } public boolean isSerializable() { return isKeySerializable() && isValueSerializable(); } public boolean isBackup() { return backup; } public void setBackup(boolean backup) { this.backup = backup; } public boolean isProxy() { return proxy; } public boolean isPrimary() { return (!proxy && !backup); } public boolean isActive() { return !proxy; } public void setProxy(boolean proxy) { this.proxy = proxy; } public boolean isDiffable() { return (value instanceof ReplicatedMapEntry) && ((ReplicatedMapEntry)value).isDiffable(); } public void setBackupNodes(Member[] nodes) { this.backupNodes = nodes; } public Member[] getBackupNodes() { return backupNodes; } public void setPrimary(Member m) { primary = m; } public Member getPrimary() { return primary; } @Override public Object getValue() { return value; } @Override public Object setValue(Object value) { Object old = this.value; this.value = value; return old; } @Override public Object getKey() { return key; } public Object setKey(Object key) { Object old = this.key; this.key = key; return old; } @Override public int hashCode() { return key.hashCode(); } @Override public boolean equals(Object o) { return key.equals(o); } /** * apply a diff, or an entire object * @param data byte[] * @param offset int * @param length int * @param diff boolean * @throws IOException * @throws ClassNotFoundException */ public void apply(byte[] data, int offset, int length, boolean diff) throws IOException, ClassNotFoundException { if (isDiffable() && diff) { ReplicatedMapEntry rentry = (ReplicatedMapEntry) value; try { rentry.lock(); rentry.applyDiff(data, offset, length); } finally { rentry.unlock(); } } else if (length == 0) { value = null; proxy = true; } else { value = XByteBuffer.deserialize(data, offset, length); } } @Override public String toString() { StringBuilder buf = new StringBuilder("MapEntry[key:"); buf.append(getKey()).append("; "); buf.append("value:").append(getValue()).append("; "); buf.append("primary:").append(isPrimary()).append("; "); buf.append("backup:").append(isBackup()).append("; "); buf.append("proxy:").append(isProxy()).append(";]"); return buf.toString(); } } //------------------------------------------------------------------------------ // map message to send to and from other maps //------------------------------------------------------------------------------ public static class MapMessage implements Serializable { private static final long serialVersionUID = 1L; public static final int MSG_BACKUP = 1; public static final int MSG_RETRIEVE_BACKUP = 2; public static final int MSG_PROXY = 3; public static final int MSG_REMOVE = 4; public static final int MSG_STATE = 5; public static final int MSG_START = 6; public static final int MSG_STOP = 7; public static final int MSG_INIT = 8; public static final int MSG_COPY = 9; public static final int MSG_STATE_COPY = 10; public static final int MSG_ACCESS = 11; private byte[] mapId; private int msgtype; private boolean diff; private transient Serializable key; private transient Serializable value; private byte[] valuedata; private byte[] keydata; private byte[] diffvalue; private Member[] nodes; private Member primary; @Override public String toString() { StringBuilder buf = new StringBuilder("MapMessage[context="); buf.append(new String(mapId)); buf.append("; type="); buf.append(getTypeDesc()); buf.append("; key="); buf.append(key); buf.append("; value="); buf.append(value); return buf.toString(); } public String getTypeDesc() { switch (msgtype) { case MSG_BACKUP: return "MSG_BACKUP"; case MSG_RETRIEVE_BACKUP: return "MSG_RETRIEVE_BACKUP"; case MSG_PROXY: return "MSG_PROXY"; case MSG_REMOVE: return "MSG_REMOVE"; case MSG_STATE: return "MSG_STATE"; case MSG_START: return "MSG_START"; case MSG_STOP: return "MSG_STOP"; case MSG_INIT: return "MSG_INIT"; case MSG_STATE_COPY: return "MSG_STATE_COPY"; case MSG_COPY: return "MSG_COPY"; case MSG_ACCESS: return "MSG_ACCESS"; default : return "UNKNOWN"; } } /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public MapMessage() {} public MapMessage(byte[] mapId,int msgtype, boolean diff, Serializable key, Serializable value, byte[] diffvalue, Member primary, Member[] nodes) { this.mapId = mapId; this.msgtype = msgtype; this.diff = diff; this.key = key; this.value = value; this.diffvalue = diffvalue; this.nodes = nodes; this.primary = primary; setValue(value); setKey(key); } public void deserialize(ClassLoader[] cls) throws IOException, ClassNotFoundException { key(cls); value(cls); } public int getMsgType() { return msgtype; } public boolean isDiff() { return diff; } public Serializable getKey() { try { return key(null); } catch ( Exception x ) { throw new RuntimeException("Deserialization error of the MapMessage.key", x); } } public Serializable key(ClassLoader[] cls) throws IOException, ClassNotFoundException { if ( key!=null ) return key; if ( keydata == null || keydata.length == 0 ) return null; key = XByteBuffer.deserialize(keydata,0,keydata.length,cls); keydata = null; return key; } public byte[] getKeyData() { return keydata; } public Serializable getValue() { try { return value(null); } catch ( Exception x ) { throw new RuntimeException("Deserialization error of the MapMessage.value", x); } } public Serializable value(ClassLoader[] cls) throws IOException, ClassNotFoundException { if ( value!=null ) return value; if ( valuedata == null || valuedata.length == 0 ) return null; value = XByteBuffer.deserialize(valuedata,0,valuedata.length,cls); valuedata = null; return value; } public byte[] getValueData() { return valuedata; } public byte[] getDiffValue() { return diffvalue; } public Member[] getBackupNodes() { return nodes; } public Member getPrimary() { return primary; } private void setPrimary(Member m) { primary = m; } public byte[] getMapId() { return mapId; } public void setValue(Serializable value) { try { if ( value != null ) valuedata = XByteBuffer.serialize(value); this.value = value; }catch ( IOException x ) { throw new RuntimeException(x); } } public void setKey(Serializable key) { try { if (key != null) keydata = XByteBuffer.serialize(key); this.key = key; } catch (IOException x) { throw new RuntimeException(x); } } /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated protected Member[] readMembers(ObjectInput in) throws IOException, ClassNotFoundException { int nodecount = in.readInt(); Member[] members = new Member[nodecount]; for ( int i=0; i 0) members[i] = MemberImpl.getMember(d); } return members; } /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated protected void writeMembers(ObjectOutput out,Member[] members) throws IOException { if ( members == null ) members = new Member[0]; out.writeInt(members.length); for (int i=0; i * The replication logic will call the methods in the following order:
    * * 1. if ( entry.isDirty() )
    * try { * 2. entry.lock();
    * 3. byte[] diff = entry.getDiff();
    * 4. entry.reset();
    * } finally {
    * 5. entry.unlock();
    * }
    * }
    *
    *
    *
    * When the data is deserialized the logic is called in the following order
    * * 1. ReplicatedMapEntry entry = (ReplicatedMapEntry)objectIn.readObject();
    * 2. if ( isBackup(entry)||isPrimary(entry) ) entry.setOwner(owner);
    *
    *
    * * * @author Filip Hanik * @version 1.0 */ public interface ReplicatedMapEntry extends Serializable { /** * Has the object changed since last replication * and is not in a locked state * @return boolean */ public boolean isDirty(); /** * If this returns true, the map will extract the diff using getDiff() * Otherwise it will serialize the entire object. * @return boolean */ public boolean isDiffable(); /** * Returns a diff and sets the dirty map to false * @return byte[] * @throws IOException */ public byte[] getDiff() throws IOException; /** * Applies a diff to an existing object. * @param diff byte[] * @param offset int * @param length int * @throws IOException */ public void applyDiff(byte[] diff, int offset, int length) throws IOException, ClassNotFoundException; /** * Resets the current diff state and resets the dirty flag */ public void resetDiff(); /** * Lock during serialization */ public void lock(); /** * Unlock after serialization */ public void unlock(); /** * This method is called after the object has been * created on a remote map. On this method, * the object can initialize itself for any data that wasn't * * @param owner Object */ public void setOwner(Object owner); /** * For accuracy checking, a serialized attribute can contain a version number * This number increases as modifications are made to the data. * The replicated map can use this to ensure accuracy on a periodic basis * @return long - the version number or -1 if the data is not versioned */ public long getVersion(); /** * Forces a certain version to a replicated map entry
    * @param version long */ public void setVersion(long version); /** * Return the last replicate time. */ public long getLastTimeReplicated(); /** * Set the last replicate time. * @param lastTimeReplicated */ public void setLastTimeReplicated(long lastTimeReplicated); /** * If this returns true, to replicate that an object has been accessed * @return boolean */ public boolean isAccessReplicate(); /** * Access to an existing object. */ public void accessEntry(); }tomcat7-7.0.52/java/org/apache/catalina/tribes/tipis/Streamable.java0000644000175100017510000000424212271464231025216 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.tipis; import java.io.IOException; /** * Example usage: *
     * byte[] data = new byte[1024];
     * Streamable st = ....;
     * while ( !st.eof() ) {
     *   int length = st.read(data,0,data.length);
     *   String s = new String(data,0,length);
     *   System.out.println(s);
     * }
     * 
    * @author Filip Hanik * @version 1.0 * * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public interface Streamable { /** * returns true if the stream has reached its end * @return boolean */ public boolean eof(); /** * write data into the byte array starting at offset, maximum bytes read are (data.length-offset) * @param data byte[] - the array to read data into * @param offset int - start position for writing data * @return int - the number of bytes written into the data buffer */ public int write(byte[] data, int offset, int length) throws IOException; /** * read data into the byte array starting at offset * @param data byte[] - the array to read data into * @param offset int - start position for writing data * @param length - the desired read length * @return int - the number of bytes read from the data buffer */ public int read(byte[] data, int offset, int length) throws IOException; }tomcat7-7.0.52/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java0000644000175100017510000001466012274173771025667 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.tipis; import java.io.Serializable; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.Member; /** * All-to-all replication for a hash map implementation. Each node in the cluster will carry an identical * copy of the map.

    * This map implementation doesn't have a background thread running to replicate changes. * If you do have changes without invoking put/remove then you need to invoke one of the following methods: *
      *
    • replicate(Object,boolean) - replicates only the object that belongs to the key
    • *
    • replicate(boolean) - Scans the entire map for changes and replicates data
    • *
    * the boolean value in the replicate method used to decide * whether to only replicate objects that implement the ReplicatedMapEntry interface * or to replicate all objects. If an object doesn't implement the ReplicatedMapEntry interface * each time the object gets replicated the entire object gets serialized, hence a call to replicate(true) * will replicate all objects in this map that are using this node as primary. * *

    REMEMBER TO CALL breakdown() or finalize() * when you are done with the map to avoid memory leaks.

    * TODO implement periodic sync/transfer thread
    * TODO memberDisappeared, should do nothing except change map membership * by default it relocates the primary objects * * @author Filip Hanik * @version 1.0 */ public class ReplicatedMap extends AbstractReplicatedMap { private static final long serialVersionUID = 1L; //-------------------------------------------------------------------------- // CONSTRUCTORS / DESTRUCTORS //-------------------------------------------------------------------------- /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel * @param initialCapacity int - the size of this map, see HashMap * @param loadFactor float - load factor, see HashMap */ public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, int initialCapacity,float loadFactor, ClassLoader[] cls) { super(owner,channel, timeout, mapContextName, initialCapacity, loadFactor, Channel.SEND_OPTIONS_DEFAULT, cls, true); } /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel * @param initialCapacity int - the size of this map, see HashMap */ public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, int initialCapacity, ClassLoader[] cls) { super(owner,channel, timeout, mapContextName, initialCapacity, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR,Channel.SEND_OPTIONS_DEFAULT, cls, true); } /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel */ public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls) { super(owner, channel, timeout, mapContextName,AbstractReplicatedMap.DEFAULT_INITIAL_CAPACITY, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR, Channel.SEND_OPTIONS_DEFAULT, cls, true); } /** * Creates a new map * @param channel The channel to use for communication * @param timeout long - timeout for RPC messags * @param mapContextName String - unique name for this map, to allow multiple maps per channel * @param terminate boolean - Flag for whether to terminate this map that failed to start. */ public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls, boolean terminate) { super(owner, channel, timeout, mapContextName,AbstractReplicatedMap.DEFAULT_INITIAL_CAPACITY, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR, Channel.SEND_OPTIONS_DEFAULT, cls, terminate); } //------------------------------------------------------------------------------ // METHODS TO OVERRIDE //------------------------------------------------------------------------------ @Override protected int getStateMessageType() { return AbstractReplicatedMap.MapMessage.MSG_STATE_COPY; } /** * publish info about a map pair (key/value) to other nodes in the cluster * @param key Object * @param value Object * @return Member - the backup node * @throws ChannelException */ @Override protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException { if (! (key instanceof Serializable && value instanceof Serializable) ) return new Member[0]; //select a backup node Member[] backup = getMapMembers(); if (backup == null || backup.length == 0) return null; //publish the data out to all nodes MapMessage msg = new MapMessage(getMapContextName(), MapMessage.MSG_COPY, false, (Serializable) key, (Serializable) value, null,channel.getLocalMember(false), backup); getChannel().send(getMapMembers(), msg, getChannelSendOptions()); return backup; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/MembershipListener.java0000644000175100017510000000305412271464231025610 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * The MembershipListener interface is used as a callback to the * membership service. It has two methods that will notify the listener * when a member has joined the group and when a member has disappeared (crashed) * * @author Filip Hanik */ public interface MembershipListener { /** * A member was added to the group * @param member Member - the member that was added */ public void memberAdded(Member member); /** * A member was removed from the group
    * If the member left voluntarily, the Member.getCommand will contain the Member.SHUTDOWN_PAYLOAD data * @param member Member * @see Member#SHUTDOWN_PAYLOAD */ public void memberDisappeared(Member member); }tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/0000755000175100017510000000000012301126370023266 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/membership/LocalStrings_es.properties0000644000175100017510000000153312271464231030510 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. cluster.mbean.register.already = \u00A1El MBean {0} ya est\u00E1 registrado\! tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/Membership.java0000644000175100017510000002425112271464231026237 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.membership; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.catalina.tribes.Member; /** * A membership implementation using simple multicast. * This is the representation of a multicast membership. * This class is responsible for maintaining a list of active cluster nodes in the cluster. * If a node fails to send out a heartbeat, the node will be dismissed. * * @author Filip Hanik * @author Peter Rossbach */ public class Membership implements Cloneable { protected static final MemberImpl[] EMPTY_MEMBERS = new MemberImpl[0]; private final Object membersLock = new Object(); /** * The name of this membership, has to be the same as the name for the local * member */ protected MemberImpl local; /** * A map of all the members in the cluster. */ protected HashMap map = new HashMap(); /** * A list of all the members in the cluster. */ protected MemberImpl[] members = EMPTY_MEMBERS; /** * sort members by alive time */ protected Comparator memberComparator = new MemberComparator(); @Override public Object clone() { synchronized (membersLock) { Membership clone = new Membership(local, memberComparator); @SuppressWarnings("unchecked") // map is correct type already final HashMap tmpclone = (HashMap) map.clone(); clone.map = tmpclone; clone.members = new MemberImpl[members.length]; System.arraycopy(members,0,clone.members,0,members.length); return clone; } } /** * Constructs a new membership * @param local - has to be the name of the local member. Used to filter the local member from the cluster membership * @param includeLocal - TBA */ public Membership(MemberImpl local, boolean includeLocal) { this.local = local; if ( includeLocal ) addMember(local); } public Membership(MemberImpl local) { this(local,false); } public Membership(MemberImpl local, Comparator comp) { this(local,comp,false); } public Membership(MemberImpl local, Comparator comp, boolean includeLocal) { this(local,includeLocal); this.memberComparator = comp; } /** * Reset the membership and start over fresh. * Ie, delete all the members and wait for them to ping again and join this membership */ public synchronized void reset() { map.clear(); members = EMPTY_MEMBERS ; } /** * Notify the membership that this member has announced itself. * * @param member - the member that just pinged us * @return - true if this member is new to the cluster, false otherwise.
    * - false if this member is the local member or updated. */ public synchronized boolean memberAlive(MemberImpl member) { boolean result = false; //ignore ourselves if ( member.equals(local) ) return result; //return true if the membership has changed MbrEntry entry = map.get(member); if ( entry == null ) { entry = addMember(member); result = true; } else { //update the member alive time MemberImpl updateMember = entry.getMember() ; if(updateMember.getMemberAliveTime() != member.getMemberAliveTime()) { //update fields that can change updateMember.setMemberAliveTime(member.getMemberAliveTime()); updateMember.setPayload(member.getPayload()); updateMember.setCommand(member.getCommand()); Arrays.sort(members, memberComparator); } } entry.accessed(); return result; } /** * Add a member to this component and sort array with memberComparator * @param member The member to add */ public synchronized MbrEntry addMember(MemberImpl member) { synchronized (membersLock) { MbrEntry entry = new MbrEntry(member); if (!map.containsKey(member) ) { map.put(member, entry); MemberImpl results[] = new MemberImpl[members.length + 1]; for (int i = 0; i < members.length; i++) results[i] = members[i]; results[members.length] = member; members = results; Arrays.sort(members, memberComparator); } return entry; } } /** * Remove a member from this component. * * @param member The member to remove */ public void removeMember(MemberImpl member) { map.remove(member); synchronized (membersLock) { int n = -1; for (int i = 0; i < members.length; i++) { if (members[i] == member || members[i].equals(member)) { n = i; break; } } if (n < 0) return; MemberImpl results[] = new MemberImpl[members.length - 1]; int j = 0; for (int i = 0; i < members.length; i++) { if (i != n) results[j++] = members[i]; } members = results; } } /** * Runs a refresh cycle and returns a list of members that has expired. * This also removes the members from the membership, in such a way that * getMembers() = getMembers() - expire() * @param maxtime - the max time a member can remain unannounced before it is considered dead. * @return the list of expired members */ public synchronized MemberImpl[] expire(long maxtime) { if(!hasMembers() ) return EMPTY_MEMBERS; ArrayList list = null; Iterator i = map.values().iterator(); while(i.hasNext()) { MbrEntry entry = i.next(); if( entry.hasExpired(maxtime) ) { if(list == null) // only need a list when members are expired (smaller gc) list = new java.util.ArrayList(); list.add(entry.getMember()); } } if(list != null) { MemberImpl[] result = new MemberImpl[list.size()]; list.toArray(result); for( int j=0; j 0 ; } public MemberImpl getMember(Member mbr) { if(hasMembers()) { MemberImpl result = null; for ( int i=0; i> i = map.entrySet().iterator(); int pos = 0; while ( i.hasNext() ) result[pos++] = i.next().getValue(); return result; } // --------------------------------------------- Inner Class private static class MemberComparator implements Comparator, Serializable { private static final long serialVersionUID = 1L; @Override public int compare(Member m1, Member m2) { //longer alive time, means sort first long result = m2.getMemberAliveTime() - m1.getMemberAliveTime(); if (result < 0) return -1; else if (result == 0) return 0; else return 1; } } /** * Inner class that represents a member entry */ protected static class MbrEntry { protected MemberImpl mbr; protected long lastHeardFrom; public MbrEntry(MemberImpl mbr) { this.mbr = mbr; } /** * Indicate that this member has been accessed. */ public void accessed(){ lastHeardFrom = System.currentTimeMillis(); } /** * Return the actual Member object */ public MemberImpl getMember() { return mbr; } /** * Check if this dude has expired * @param maxtime The time threshold */ public boolean hasExpired(long maxtime) { long delta = System.currentTimeMillis() - lastHeardFrom; return delta > maxtime; } } } tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/McastService.java0000644000175100017510000005324412271464231026540 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.membership; import java.io.IOException; import java.net.DatagramPacket; import java.util.Properties; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; import org.apache.catalina.tribes.MembershipService; import org.apache.catalina.tribes.MessageListener; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.util.Arrays; import org.apache.catalina.tribes.util.StringManager; import org.apache.catalina.tribes.util.UUIDGenerator; /** * A membership implementation using simple multicast. * This is the representation of a multicast membership service. * This class is responsible for maintaining a list of active cluster nodes in the cluster. * If a node fails to send out a heartbeat, the node will be dismissed. * * @author Filip Hanik */ public class McastService implements MembershipService,MembershipListener,MessageListener { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( McastService.class ); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The descriptive information about this implementation. */ private static final String info = "McastService/2.1"; /** * The implementation specific properties */ protected Properties properties = new Properties(); /** * A handle to the actual low level implementation */ protected McastServiceImpl impl; /** * A membership listener delegate (should be the cluster :) */ protected MembershipListener listener; /** * A message listener delegate for broadcasts */ protected MessageListener msglistener; /** * The local member */ protected MemberImpl localMember ; private int mcastSoTimeout; private int mcastTTL; protected byte[] payload; protected byte[] domain; /** * Create a membership service. */ public McastService() { //default values properties.setProperty("mcastPort","45564"); properties.setProperty("mcastAddress","228.0.0.4"); properties.setProperty("memberDropTime","3000"); properties.setProperty("mcastFrequency","500"); } /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /** * * @param properties *
    All are required
    * 1. mcastPort - the port to listen to
    * 2. mcastAddress - the mcast group address
    * 4. bindAddress - the bind address if any - only one that can be null
    * 5. memberDropTime - the time a member is gone before it is considered gone.
    * 6. mcastFrequency - the frequency of sending messages
    * 7. tcpListenPort - the port this member listens to
    * 8. tcpListenHost - the bind address of this member
    * @exception java.lang.IllegalArgumentException if a property is missing. */ @Override public void setProperties(Properties properties) { hasProperty(properties,"mcastPort"); hasProperty(properties,"mcastAddress"); hasProperty(properties,"memberDropTime"); hasProperty(properties,"mcastFrequency"); hasProperty(properties,"tcpListenPort"); hasProperty(properties,"tcpListenHost"); this.properties = properties; } /** * Return the properties, see setProperties */ @Override public Properties getProperties() { return properties; } /** * Return the local member name */ public String getLocalMemberName() { return localMember.toString() ; } /** * Return the local member */ @Override public Member getLocalMember(boolean alive) { if ( alive && localMember != null && impl != null) localMember.setMemberAliveTime(System.currentTimeMillis()-impl.getServiceStartTime()); return localMember; } /** * Sets the local member properties for broadcasting */ @Override public void setLocalMemberProperties(String listenHost, int listenPort, int securePort, int udpPort) { properties.setProperty("tcpListenHost",listenHost); properties.setProperty("tcpListenPort",String.valueOf(listenPort)); properties.setProperty("udpListenPort",String.valueOf(udpPort)); properties.setProperty("tcpSecurePort",String.valueOf(securePort)); try { if (localMember != null) { localMember.setHostname(listenHost); localMember.setPort(listenPort); } else { localMember = new MemberImpl(listenHost, listenPort, 0); localMember.setUniqueId(UUIDGenerator.randomUUID(true)); localMember.setPayload(getPayload()); localMember.setDomain(getDomain()); } localMember.setSecurePort(securePort); localMember.setUdpPort(udpPort); localMember.getData(true, true); }catch ( IOException x ) { throw new IllegalArgumentException(x); } } public void setAddress(String addr) { properties.setProperty("mcastAddress", addr); } /** * @deprecated use setAddress * @param addr String */ @Deprecated public void setMcastAddr(String addr) { setAddress(addr); } public String getAddress() { return properties.getProperty("mcastAddress"); } /** * @deprecated use getAddress * @return String */ @Deprecated public String getMcastAddr() { return getAddress(); } public void setMcastBindAddress(String bindaddr) { setBind(bindaddr); } public void setBind(String bindaddr) { properties.setProperty("mcastBindAddress", bindaddr); } /** * @deprecated use getBind * @return String */ @Deprecated public String getMcastBindAddress() { return getBind(); } public String getBind() { return properties.getProperty("mcastBindAddress"); } /** * @deprecated use setPort * @param port int */ @Deprecated public void setMcastPort(int port) { setPort(port); } public void setPort(int port) { properties.setProperty("mcastPort", String.valueOf(port)); } public void setRecoveryCounter(int recoveryCounter) { properties.setProperty("recoveryCounter", String.valueOf(recoveryCounter)); } public int getRecoveryCounter(){ String p = properties.getProperty("recoveryCounter"); if(p != null){ return new Integer(p).intValue(); } return -1; } public void setRecoveryEnabled(boolean recoveryEnabled) { properties.setProperty("recoveryEnabled", String.valueOf(recoveryEnabled)); } public boolean getRecoveryEnabled() { String p = properties.getProperty("recoveryEnabled"); if(p != null){ return Boolean.valueOf(p).booleanValue(); } return false; } public void setRecoverySleepTime(long recoverySleepTime) { properties.setProperty("recoverySleepTime", String.valueOf(recoverySleepTime)); } public long getRecoverySleepTime(){ String p = properties.getProperty("recoverySleepTime"); if(p != null){ return new Long(p).longValue(); } return -1; } public void setLocalLoopbackDisabled(boolean localLoopbackDisabled) { properties.setProperty("localLoopbackDisabled",String.valueOf(localLoopbackDisabled)); } public boolean getLocalLoopbackDisabled(boolean localLoopbackDisabled) { String p = properties.getProperty("localLoopbackDisabled"); if(p != null){ return Boolean.valueOf(p).booleanValue(); } return false; } /** * @deprecated use getPort() * @return int */ @Deprecated public int getMcastPort() { return getPort(); } public int getPort() { String p = properties.getProperty("mcastPort"); return new Integer(p).intValue(); } /** * @deprecated use setFrequency * @param time long */ @Deprecated public void setMcastFrequency(long time) { setFrequency(time); } public void setFrequency(long time) { properties.setProperty("mcastFrequency", String.valueOf(time)); } /** * @deprecated use getFrequency * @return long */ @Deprecated public long getMcastFrequency() { return getFrequency(); } public long getFrequency() { String p = properties.getProperty("mcastFrequency"); return new Long(p).longValue(); } public void setMcastDropTime(long time) { setDropTime(time); } public void setDropTime(long time) { properties.setProperty("memberDropTime", String.valueOf(time)); } /** * @deprecated use getDropTime * @return long */ @Deprecated public long getMcastDropTime() { return getDropTime(); } public long getDropTime() { String p = properties.getProperty("memberDropTime"); return new Long(p).longValue(); } /** * Check if a required property is available. * @param properties The set of properties * @param name The property to check for */ protected void hasProperty(Properties properties, String name){ if ( properties.getProperty(name)==null) throw new IllegalArgumentException("McastService:Required property \""+name+"\" is missing."); } /** * Start broadcasting and listening to membership pings * @throws java.lang.Exception if a IO error occurs */ @Override public void start() throws java.lang.Exception { start(MembershipService.MBR_RX); start(MembershipService.MBR_TX); } @Override public void start(int level) throws java.lang.Exception { hasProperty(properties,"mcastPort"); hasProperty(properties,"mcastAddress"); hasProperty(properties,"memberDropTime"); hasProperty(properties,"mcastFrequency"); hasProperty(properties,"tcpListenPort"); hasProperty(properties,"tcpListenHost"); hasProperty(properties,"tcpSecurePort"); hasProperty(properties,"udpListenPort"); if ( impl != null ) { impl.start(level); return; } String host = getProperties().getProperty("tcpListenHost"); int port = Integer.parseInt(getProperties().getProperty("tcpListenPort")); int securePort = Integer.parseInt(getProperties().getProperty("tcpSecurePort")); int udpPort = Integer.parseInt(getProperties().getProperty("udpListenPort")); if ( localMember == null ) { localMember = new MemberImpl(host, port, 100); localMember.setUniqueId(UUIDGenerator.randomUUID(true)); } else { localMember.setHostname(host); localMember.setPort(port); localMember.setMemberAliveTime(100); } localMember.setSecurePort(securePort); localMember.setUdpPort(udpPort); if ( this.payload != null ) localMember.setPayload(payload); if ( this.domain != null ) localMember.setDomain(domain); localMember.setServiceStartTime(System.currentTimeMillis()); java.net.InetAddress bind = null; if ( properties.getProperty("mcastBindAddress")!= null ) { bind = java.net.InetAddress.getByName(properties.getProperty("mcastBindAddress")); } int ttl = -1; int soTimeout = -1; if ( properties.getProperty("mcastTTL") != null ) { try { ttl = Integer.parseInt(properties.getProperty("mcastTTL")); } catch ( Exception x ) { log.error("Unable to parse mcastTTL="+properties.getProperty("mcastTTL"),x); } } if ( properties.getProperty("mcastSoTimeout") != null ) { try { soTimeout = Integer.parseInt(properties.getProperty("mcastSoTimeout")); } catch ( Exception x ) { log.error("Unable to parse mcastSoTimeout="+properties.getProperty("mcastSoTimeout"),x); } } impl = new McastServiceImpl(localMember,Long.parseLong(properties.getProperty("mcastFrequency")), Long.parseLong(properties.getProperty("memberDropTime")), Integer.parseInt(properties.getProperty("mcastPort")), bind, java.net.InetAddress.getByName(properties.getProperty("mcastAddress")), ttl, soTimeout, this, this, Boolean.valueOf(properties.getProperty("localLoopbackDisabled","false")).booleanValue()); String value = properties.getProperty("recoveryEnabled","true"); boolean recEnabled = Boolean.valueOf(value).booleanValue() ; impl.setRecoveryEnabled(recEnabled); int recCnt = Integer.parseInt(properties.getProperty("recoveryCounter","10")); impl.setRecoveryCounter(recCnt); long recSlpTime = Long.parseLong(properties.getProperty("recoverySleepTime","5000")); impl.setRecoverySleepTime(recSlpTime); impl.start(level); } /** * Stop broadcasting and listening to membership pings */ @Override public void stop(int svc) { try { if ( impl != null && impl.stop(svc) ) impl = null; } catch ( Exception x) { log.error("Unable to stop the mcast service, level:"+svc+".",x); } } /** * Return all the members by name */ @Override public String[] getMembersByName() { Member[] currentMembers = getMembers(); String [] membernames ; if(currentMembers != null) { membernames = new String[currentMembers.length]; for (int i = 0; i < currentMembers.length; i++) { membernames[i] = currentMembers[i].toString() ; } } else membernames = new String[0] ; return membernames ; } /** * Return the member by name */ @Override public Member findMemberByName(String name) { Member[] currentMembers = getMembers(); for (int i = 0; i < currentMembers.length; i++) { if (name.equals(currentMembers[i].toString())) return currentMembers[i]; } return null; } /** * has members? */ @Override public boolean hasMembers() { if ( impl == null || impl.membership == null ) return false; return impl.membership.hasMembers(); } @Override public Member getMember(Member mbr) { if ( impl == null || impl.membership == null ) return null; return impl.membership.getMember(mbr); } /** * Return all the members */ protected static final Member[]EMPTY_MEMBERS = new Member[0]; @Override public Member[] getMembers() { if ( impl == null || impl.membership == null ) return EMPTY_MEMBERS; return impl.membership.getMembers(); } /** * Add a membership listener, this version only supports one listener per service, * so calling this method twice will result in only the second listener being active. * @param listener The listener */ @Override public void setMembershipListener(MembershipListener listener) { this.listener = listener; } public void setMessageListener(MessageListener listener) { this.msglistener = listener; } public void removeMessageListener() { this.msglistener = null; } /** * Remove the membership listener */ @Override public void removeMembershipListener(){ listener = null; } @Override public void memberAdded(Member member) { if ( listener!=null ) listener.memberAdded(member); } /** * Callback from the impl when a new member has been received * @param member The member */ @Override public void memberDisappeared(Member member) { if ( listener!=null ) listener.memberDisappeared(member); } @Override public void messageReceived(ChannelMessage msg) { if (msglistener!=null && msglistener.accept(msg)) msglistener.messageReceived(msg); } @Override public boolean accept(ChannelMessage msg) { return true; } @Override public void broadcast(ChannelMessage message) throws ChannelException { if (impl==null || (impl.startLevel & Channel.MBR_TX_SEQ)!=Channel.MBR_TX_SEQ ) throw new ChannelException("Multicast send is not started or enabled."); byte[] data = XByteBuffer.createDataPackage((ChannelData)message); if (data.length>McastServiceImpl.MAX_PACKET_SIZE) { throw new ChannelException("Packet length["+data.length+"] exceeds max packet size of "+McastServiceImpl.MAX_PACKET_SIZE+" bytes."); } DatagramPacket packet = new DatagramPacket(data,0,data.length); try { impl.send(false, packet); } catch (Exception x) { throw new ChannelException(x); } } /** * @deprecated use getSoTimeout * @return int */ @Deprecated public int getMcastSoTimeout() { return getSoTimeout(); } public int getSoTimeout() { return mcastSoTimeout; } /** * @deprecated use setSoTimeout * @param mcastSoTimeout int */ @Deprecated public void setMcastSoTimeout(int mcastSoTimeout) { setSoTimeout(mcastSoTimeout); } public void setSoTimeout(int mcastSoTimeout) { this.mcastSoTimeout = mcastSoTimeout; properties.setProperty("mcastSoTimeout", String.valueOf(mcastSoTimeout)); } /** * @deprecated use getTtl * @return int */ @Deprecated public int getMcastTTL() { return getTtl(); } public int getTtl() { return mcastTTL; } public byte[] getPayload() { return payload; } public byte[] getDomain() { return domain; } /** * @deprecated use setTtl * @param mcastTTL int */ @Deprecated public void setMcastTTL(int mcastTTL) { setTtl(mcastTTL); } public void setTtl(int mcastTTL) { this.mcastTTL = mcastTTL; properties.setProperty("mcastTTL", String.valueOf(mcastTTL)); } @Override public void setPayload(byte[] payload) { this.payload = payload; if ( localMember != null ) { localMember.setPayload(payload); localMember.getData(true,true); try { if (impl != null) impl.send(false); }catch ( Exception x ) { log.error("Unable to send payload update.",x); } } } @Override public void setDomain(byte[] domain) { this.domain = domain; if ( localMember != null ) { localMember.setDomain(domain); localMember.getData(true,true); try { if (impl != null) impl.send(false); }catch ( Exception x ) { log.error("Unable to send domain update.",x); } } } public void setDomain(String domain) { if ( domain == null ) return; if ( domain.startsWith("{") ) setDomain(Arrays.fromString(domain)); else setDomain(Arrays.convert(domain)); } /** * Simple test program * @param args Command-line arguments * @throws Exception If an error occurs */ public static void main(String args[]) throws Exception { if(log.isInfoEnabled()) log.info("Usage McastService hostname tcpport"); McastService service = new McastService(); java.util.Properties p = new java.util.Properties(); p.setProperty("mcastPort","5555"); p.setProperty("mcastAddress","224.10.10.10"); p.setProperty("mcastClusterDomain","catalina"); p.setProperty("bindAddress","localhost"); p.setProperty("memberDropTime","3000"); p.setProperty("mcastFrequency","500"); p.setProperty("tcpListenPort","4000"); p.setProperty("tcpListenHost","127.0.0.1"); p.setProperty("tcpSecurePort","4100"); p.setProperty("udpListenPort","4200"); service.setProperties(p); service.start(); Thread.sleep(60*1000*60); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/MemberImpl.java0000644000175100017510000004644012271464231026201 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.membership; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Arrays; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.transport.SenderState; /** * A membership implementation using simple multicast. * This is the representation of a multicast member. * Carries the host, and port of the this or other cluster nodes. * * @author Filip Hanik */ public class MemberImpl implements Member, java.io.Externalizable { /** * Should a call to getName or getHostName try to do a DNS lookup? * default is false */ public static final boolean DO_DNS_LOOKUPS = Boolean.parseBoolean(System.getProperty("org.apache.catalina.tribes.dns_lookups","false")); /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public static final transient String TCP_LISTEN_PORT = "tcpListenPort"; /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public static final transient String TCP_LISTEN_HOST = "tcpListenHost"; /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public static final transient String MEMBER_NAME = "memberName"; public static final transient byte[] TRIBES_MBR_BEGIN = new byte[] {84, 82, 73, 66, 69, 83, 45, 66, 1, 0}; public static final transient byte[] TRIBES_MBR_END = new byte[] {84, 82, 73, 66, 69, 83, 45, 69, 1, 0}; /** * The listen host for this member */ protected byte[] host; protected transient String hostname; /** * The tcp listen port for this member */ protected int port; /** * The udp listen port for this member */ protected int udpPort = -1; /** * The tcp/SSL listen port for this member */ protected int securePort = -1; /** * Counter for how many broadcast messages have been sent from this member */ protected int msgCount = 0; /** * The number of milliseconds since this member was * created, is kept track of using the start time */ protected long memberAliveTime = 0; /** * For the local member only */ protected transient long serviceStartTime; /** * To avoid serialization over and over again, once the local dataPkg * has been set, we use that to transmit data */ protected transient byte[] dataPkg = null; /** * Unique session Id for this member */ protected byte[] uniqueId = new byte[16]; /** * Custom payload that an app framework can broadcast * Also used to transport stop command. */ protected byte[] payload = new byte[0]; /** * Command, so that the custom payload doesn't have to be used * This is for internal tribes use, such as SHUTDOWN_COMMAND */ protected byte[] command = new byte[0]; /** * Domain if we want to filter based on domain. */ protected byte[] domain = new byte[0]; /** * Empty constructor for serialization */ public MemberImpl() { } /** * Construct a new member object * @param host - the tcp listen host * @param port - the tcp listen port * @param aliveTime - the number of milliseconds since this member was created */ public MemberImpl(String host, int port, long aliveTime) throws IOException { setHostname(host); this.port = port; this.memberAliveTime=aliveTime; } public MemberImpl(String host, int port, long aliveTime, byte[] payload) throws IOException { this(host,port,aliveTime); setPayload(payload); } @Override public boolean isReady() { return SenderState.getSenderState(this).isReady(); } @Override public boolean isSuspect() { return SenderState.getSenderState(this).isSuspect(); } @Override public boolean isFailing() { return SenderState.getSenderState(this).isFailing(); } /** * Increment the message count. */ protected void inc() { msgCount++; } /** * Create a data package to send over the wire representing this member. * This is faster than serialization. * @return - the bytes for this member deserialized */ public byte[] getData() { return getData(true); } /** * Highly optimized version of serializing a member into a byte array * Returns a cached byte[] reference, do not modify this data * @param getalive boolean * @return byte[] */ public byte[] getData(boolean getalive) { return getData(getalive,false); } public int getDataLength() { return TRIBES_MBR_BEGIN.length+ //start pkg 4+ //data length 8+ //alive time 4+ //port 4+ //secure port 4+ //udp port 1+ //host length host.length+ //host 4+ //command length command.length+ //command 4+ //domain length domain.length+ //domain 16+ //unique id 4+ //payload length payload.length+ //payload TRIBES_MBR_END.length; //end pkg } /** * * @param getalive boolean - calculate memberAlive time * @param reset boolean - reset the cached data package, and create a new one * @return byte[] */ public byte[] getData(boolean getalive, boolean reset) { if ( reset ) dataPkg = null; //look in cache first if ( dataPkg!=null ) { if ( getalive ) { //you'd be surprised, but System.currentTimeMillis //shows up on the profiler long alive=System.currentTimeMillis()-getServiceStartTime(); XByteBuffer.toBytes(alive, dataPkg, TRIBES_MBR_BEGIN.length+4); } return dataPkg; } //package looks like //start package TRIBES_MBR_BEGIN.length //package length - 4 bytes //alive - 8 bytes //port - 4 bytes //secure port - 4 bytes //udp port - 4 bytes //host length - 1 byte //host - hl bytes //clen - 4 bytes //command - clen bytes //dlen - 4 bytes //domain - dlen bytes //uniqueId - 16 bytes //payload length - 4 bytes //payload plen bytes //end package TRIBES_MBR_END.length byte[] addr = host; long alive=System.currentTimeMillis()-getServiceStartTime(); byte hl = (byte)addr.length; byte[] data = new byte[getDataLength()]; int bodylength = (getDataLength() - TRIBES_MBR_BEGIN.length - TRIBES_MBR_END.length - 4); int pos = 0; //TRIBES_MBR_BEGIN System.arraycopy(TRIBES_MBR_BEGIN,0,data,pos,TRIBES_MBR_BEGIN.length); pos += TRIBES_MBR_BEGIN.length; //body length XByteBuffer.toBytes(bodylength,data,pos); pos += 4; //alive data XByteBuffer.toBytes(alive,data,pos); pos += 8; //port XByteBuffer.toBytes(port,data,pos); pos += 4; //secure port XByteBuffer.toBytes(securePort,data,pos); pos += 4; //udp port XByteBuffer.toBytes(udpPort,data,pos); pos += 4; //host length data[pos++] = hl; //host System.arraycopy(addr,0,data,pos,addr.length); pos+=addr.length; //clen - 4 bytes XByteBuffer.toBytes(command.length,data,pos); pos+=4; //command - clen bytes System.arraycopy(command,0,data,pos,command.length); pos+=command.length; //dlen - 4 bytes XByteBuffer.toBytes(domain.length,data,pos); pos+=4; //domain - dlen bytes System.arraycopy(domain,0,data,pos,domain.length); pos+=domain.length; //unique Id System.arraycopy(uniqueId,0,data,pos,uniqueId.length); pos+=uniqueId.length; //payload XByteBuffer.toBytes(payload.length,data,pos); pos+=4; System.arraycopy(payload,0,data,pos,payload.length); pos+=payload.length; //TRIBES_MBR_END System.arraycopy(TRIBES_MBR_END,0,data,pos,TRIBES_MBR_END.length); pos += TRIBES_MBR_END.length; //create local data dataPkg = data; return data; } /** * Deserializes a member from data sent over the wire * @param data - the bytes received * @return a member object. */ public static MemberImpl getMember(byte[] data, MemberImpl member) { return getMember(data,0,data.length,member); } public static MemberImpl getMember(byte[] data, int offset, int length, MemberImpl member) { //package looks like //start package TRIBES_MBR_BEGIN.length //package length - 4 bytes //alive - 8 bytes //port - 4 bytes //secure port - 4 bytes //udp port - 4 bytes //host length - 1 byte //host - hl bytes //clen - 4 bytes //command - clen bytes //dlen - 4 bytes //domain - dlen bytes //uniqueId - 16 bytes //payload length - 4 bytes //payload plen bytes //end package TRIBES_MBR_END.length int pos = offset; if (XByteBuffer.firstIndexOf(data,offset,TRIBES_MBR_BEGIN)!=pos) { throw new IllegalArgumentException("Invalid package, should start with:"+org.apache.catalina.tribes.util.Arrays.toString(TRIBES_MBR_BEGIN)); } if ( length < (TRIBES_MBR_BEGIN.length+4) ) { throw new ArrayIndexOutOfBoundsException("Member package to small to validate."); } pos += TRIBES_MBR_BEGIN.length; int bodylength = XByteBuffer.toInt(data,pos); pos += 4; if ( length < (bodylength+4+TRIBES_MBR_BEGIN.length+TRIBES_MBR_END.length) ) { throw new ArrayIndexOutOfBoundsException("Not enough bytes in member package."); } int endpos = pos+bodylength; if (XByteBuffer.firstIndexOf(data,endpos,TRIBES_MBR_END)!=endpos) { throw new IllegalArgumentException("Invalid package, should end with:"+org.apache.catalina.tribes.util.Arrays.toString(TRIBES_MBR_END)); } byte[] alived = new byte[8]; System.arraycopy(data, pos, alived, 0, 8); pos += 8; byte[] portd = new byte[4]; System.arraycopy(data, pos, portd, 0, 4); pos += 4; byte[] sportd = new byte[4]; System.arraycopy(data, pos, sportd, 0, 4); pos += 4; byte[] uportd = new byte[4]; System.arraycopy(data, pos, uportd, 0, 4); pos += 4; byte hl = data[pos++]; byte[] addr = new byte[hl]; System.arraycopy(data, pos, addr, 0, hl); pos += hl; int cl = XByteBuffer.toInt(data, pos); pos += 4; byte[] command = new byte[cl]; System.arraycopy(data, pos, command, 0, command.length); pos += command.length; int dl = XByteBuffer.toInt(data, pos); pos += 4; byte[] domain = new byte[dl]; System.arraycopy(data, pos, domain, 0, domain.length); pos += domain.length; byte[] uniqueId = new byte[16]; System.arraycopy(data, pos, uniqueId, 0, 16); pos += 16; int pl = XByteBuffer.toInt(data, pos); pos += 4; byte[] payload = new byte[pl]; System.arraycopy(data, pos, payload, 0, payload.length); pos += payload.length; member.setHost(addr); member.setPort(XByteBuffer.toInt(portd, 0)); member.setSecurePort(XByteBuffer.toInt(sportd, 0)); member.setUdpPort(XByteBuffer.toInt(uportd, 0)); member.setMemberAliveTime(XByteBuffer.toLong(alived, 0)); member.setUniqueId(uniqueId); member.payload = payload; member.domain = domain; member.command = command; member.dataPkg = new byte[length]; System.arraycopy(data, offset, member.dataPkg, 0, length); return member; } public static MemberImpl getMember(byte[] data) { return getMember(data,new MemberImpl()); } public static MemberImpl getMember(byte[] data, int offset, int length) { return getMember(data,offset,length,new MemberImpl()); } /** * Return the name of this object * @return a unique name to the cluster */ @Override public String getName() { return "tcp://"+getHostname()+":"+getPort(); } /** * Return the listen port of this member * @return - tcp listen port */ @Override public int getPort() { return this.port; } /** * Return the TCP listen host for this member * @return IP address or host name */ @Override public byte[] getHost() { return host; } public String getHostname() { if ( this.hostname != null ) return hostname; else { try { if (DO_DNS_LOOKUPS) this.hostname = java.net.InetAddress.getByAddress(host).getHostName(); else this.hostname = org.apache.catalina.tribes.util.Arrays.toString(host,0,host.length,true); return this.hostname; }catch ( IOException x ) { throw new RuntimeException("Unable to parse hostname.",x); } } } public int getMsgCount() { return this.msgCount; } /** * Contains information on how long this member has been online. * The result is the number of milli seconds this member has been * broadcasting its membership to the cluster. * @return nr of milliseconds since this member started. */ @Override public long getMemberAliveTime() { return memberAliveTime; } public long getServiceStartTime() { return serviceStartTime; } @Override public byte[] getUniqueId() { return uniqueId; } @Override public byte[] getPayload() { return payload; } @Override public byte[] getCommand() { return command; } @Override public byte[] getDomain() { return domain; } @Override public int getSecurePort() { return securePort; } @Override public int getUdpPort() { return udpPort; } public void setMemberAliveTime(long time) { memberAliveTime=time; } /** * String representation of this object */ @Override public String toString() { StringBuilder buf = new StringBuilder(getClass().getName()); buf.append("["); buf.append(getName()).append(","); buf.append(getHostname()).append(","); buf.append(port).append(", alive="); buf.append(memberAliveTime).append(", "); buf.append("securePort=").append(securePort).append(", "); buf.append("UDP Port=").append(udpPort).append(", "); buf.append("id=").append(bToS(this.uniqueId)).append(", "); buf.append("payload=").append(bToS(this.payload,8)).append(", "); buf.append("command=").append(bToS(this.command,8)).append(", "); buf.append("domain=").append(bToS(this.domain,8)).append(", "); buf.append("]"); return buf.toString(); } public static String bToS(byte[] data) { return bToS(data,data.length); } public static String bToS(byte[] data, int max) { StringBuilder buf = new StringBuilder(4*16); buf.append("{"); for (int i=0; data!=null && i McastServiceImpl.MAX_PACKET_SIZE ) { this.payload = oldpayload; throw new IllegalArgumentException("Payload is to large for tribes to handle."); } } public void setCommand(byte[] command) { this.command = command!=null?command:new byte[0]; getData(true,true); } public void setDomain(byte[] domain) { this.domain = domain!=null?domain:new byte[0]; getData(true,true); } public void setSecurePort(int securePort) { this.securePort = securePort; this.dataPkg = null; } public void setUdpPort(int port) { this.udpPort = port; this.dataPkg = null; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { int length = in.readInt(); byte[] message = new byte[length]; in.readFully(message); getMember(message,this); } @Override public void writeExternal(ObjectOutput out) throws IOException { byte[] data = this.getData(); out.writeInt(data.length); out.write(data); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/McastServiceImpl.java0000644000175100017510000006064112271464231027361 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.membership; import java.io.IOException; import java.net.BindException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.SocketTimeoutException; import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; import org.apache.catalina.tribes.MessageListener; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.util.ExecutorFactory; /** * A membership implementation using simple multicast. * This is the representation of a multicast membership service. * This class is responsible for maintaining a list of active cluster nodes in the cluster. * If a node fails to send out a heartbeat, the node will be dismissed. * This is the low level implementation that handles the multicasting sockets. * Need to fix this, could use java.nio and only need one thread to send and receive, or * just use a timeout on the receive * @author Filip Hanik */ public class McastServiceImpl { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( McastService.class ); protected static int MAX_PACKET_SIZE = 65535; /** * Internal flag used for the listen thread that listens to the multicasting socket. */ protected volatile boolean doRunSender = false; protected volatile boolean doRunReceiver = false; protected int startLevel = 0; /** * Socket that we intend to listen to */ protected MulticastSocket socket; /** * The local member that we intend to broad cast over and over again */ protected MemberImpl member; /** * The multicast address */ protected InetAddress address; /** * The multicast port */ protected int port; /** * The time it takes for a member to expire. */ protected long timeToExpiration; /** * How often to we send out a broadcast saying we are alive, must be smaller than timeToExpiration */ protected long sendFrequency; /** * Reuse the sendPacket, no need to create a new one everytime */ protected DatagramPacket sendPacket; /** * Reuse the receivePacket, no need to create a new one everytime */ protected DatagramPacket receivePacket; /** * The membership, used so that we calculate memberships when they arrive or don't arrive */ protected Membership membership; /** * The actual listener, for callback when stuff goes down */ protected MembershipListener service; /** * The actual listener for broadcast callbacks */ protected MessageListener msgservice; /** * Thread to listen for pings */ protected ReceiverThread receiver; /** * Thread to send pings */ protected SenderThread sender; /** * Time to live for the multicast packets that are being sent out */ protected int mcastTTL = -1; /** * Read timeout on the mcast socket */ protected int mcastSoTimeout = -1; /** * bind address */ protected InetAddress mcastBindAddress = null; /** * nr of times the system has to fail before a recovery is initiated */ protected int recoveryCounter = 10; /** * The time the recovery thread sleeps between recovery attempts */ protected long recoverySleepTime = 5000; /** * Add the ability to turn on/off recovery */ protected boolean recoveryEnabled = true; /** * Dont interrupt the sender/receiver thread, but pass off to an executor */ protected ExecutorService executor = ExecutorFactory.newThreadPool(0, 2, 2, TimeUnit.SECONDS); /** * disable/enable local loopback message */ protected boolean localLoopbackDisabled = false; /** * Create a new mcast service impl * @param member - the local member * @param sendFrequency - the time (ms) in between pings sent out * @param expireTime - the time (ms) for a member to expire * @param port - the mcast port * @param bind - the bind address (not sure this is used yet) * @param mcastAddress - the mcast address * @param service - the callback service * @param localLoopbackDisabled - disable loopbackMode * @throws IOException */ public McastServiceImpl( MemberImpl member, long sendFrequency, long expireTime, int port, InetAddress bind, InetAddress mcastAddress, int ttl, int soTimeout, MembershipListener service, MessageListener msgservice, boolean localLoopbackDisabled) throws IOException { this.member = member; this.address = mcastAddress; this.port = port; this.mcastSoTimeout = soTimeout; this.mcastTTL = ttl; this.mcastBindAddress = bind; this.timeToExpiration = expireTime; this.service = service; this.msgservice = msgservice; this.sendFrequency = sendFrequency; this.localLoopbackDisabled = localLoopbackDisabled; init(); } public void init() throws IOException { setupSocket(); sendPacket = new DatagramPacket(new byte[MAX_PACKET_SIZE],MAX_PACKET_SIZE); sendPacket.setAddress(address); sendPacket.setPort(port); receivePacket = new DatagramPacket(new byte[MAX_PACKET_SIZE],MAX_PACKET_SIZE); receivePacket.setAddress(address); receivePacket.setPort(port); member.setCommand(new byte[0]); member.getData(true, true); if ( membership == null ) membership = new Membership(member); } protected void setupSocket() throws IOException { if (mcastBindAddress != null) { try { log.info("Attempting to bind the multicast socket to "+address+":"+port); socket = new MulticastSocket(new InetSocketAddress(address,port)); } catch (BindException e) { /* * On some platforms (e.g. Linux) it is not possible to bind * to the multicast address. In this case only bind to the * port. */ log.info("Binding to multicast address, failed. Binding to port only."); socket = new MulticastSocket(port); } } else { socket = new MulticastSocket(port); } socket.setLoopbackMode(localLoopbackDisabled); //hint if we want disable loop back(local machine) messages if (mcastBindAddress != null) { if(log.isInfoEnabled()) log.info("Setting multihome multicast interface to:" +mcastBindAddress); socket.setInterface(mcastBindAddress); } //end if //force a so timeout so that we don't block forever if ( mcastSoTimeout <= 0 ) mcastSoTimeout = (int)sendFrequency; if(log.isInfoEnabled()) log.info("Setting cluster mcast soTimeout to "+mcastSoTimeout); socket.setSoTimeout(mcastSoTimeout); if ( mcastTTL >= 0 ) { if(log.isInfoEnabled()) log.info("Setting cluster mcast TTL to " + mcastTTL); socket.setTimeToLive(mcastTTL); } } /** * Start the service * @param level 1 starts the receiver, level 2 starts the sender * @throws IOException if the service fails to start * @throws IllegalStateException if the service is already started */ public synchronized void start(int level) throws IOException { boolean valid = false; if ( (level & Channel.MBR_RX_SEQ)==Channel.MBR_RX_SEQ ) { if ( receiver != null ) throw new IllegalStateException("McastService.receive already running."); try { if ( sender == null ) socket.joinGroup(address); }catch (IOException iox) { log.error("Unable to join multicast group, make sure your system has multicasting enabled."); throw iox; } doRunReceiver = true; receiver = new ReceiverThread(); receiver.setDaemon(true); receiver.start(); valid = true; } if ( (level & Channel.MBR_TX_SEQ)==Channel.MBR_TX_SEQ ) { if ( sender != null ) throw new IllegalStateException("McastService.send already running."); if ( receiver == null ) socket.joinGroup(address); //make sure at least one packet gets out there send(false); doRunSender = true; sender = new SenderThread(sendFrequency); sender.setDaemon(true); sender.start(); //we have started the receiver, but not yet waited for membership to establish valid = true; } if (!valid) { throw new IllegalArgumentException("Invalid start level. Only acceptable levels are Channel.MBR_RX_SEQ and Channel.MBR_TX_SEQ"); } //pause, once or twice waitForMembers(level); startLevel = (startLevel | level); } private void waitForMembers(int level) { long memberwait = sendFrequency*2; if(log.isInfoEnabled()) log.info("Sleeping for "+memberwait+" milliseconds to establish cluster membership, start level:"+level); try {Thread.sleep(memberwait);}catch (InterruptedException ignore){} if(log.isInfoEnabled()) log.info("Done sleeping, membership established, start level:"+level); } /** * Stops the service * @throws IOException if the service fails to disconnect from the sockets */ public synchronized boolean stop(int level) throws IOException { boolean valid = false; if ( (level & Channel.MBR_RX_SEQ)==Channel.MBR_RX_SEQ ) { valid = true; doRunReceiver = false; if ( receiver !=null ) receiver.interrupt(); receiver = null; } if ( (level & Channel.MBR_TX_SEQ)==Channel.MBR_TX_SEQ ) { valid = true; doRunSender = false; if ( sender != null )sender.interrupt(); sender = null; } if (!valid) { throw new IllegalArgumentException("Invalid stop level. Only acceptable levels are Channel.MBR_RX_SEQ and Channel.MBR_TX_SEQ"); } startLevel = (startLevel & (~level)); //we're shutting down, send a shutdown message and close the socket if ( startLevel == 0 ) { //send a stop message member.setCommand(Member.SHUTDOWN_PAYLOAD); member.getData(true, true); send(false); //leave mcast group try {socket.leaveGroup(address);}catch ( Exception ignore){} try {socket.close();}catch ( Exception ignore){} member.setServiceStartTime(-1); } return (startLevel == 0); } /** * Receive a datagram packet, locking wait * @throws IOException */ public void receive() throws IOException { boolean checkexpired = true; try { socket.receive(receivePacket); if(receivePacket.getLength() > MAX_PACKET_SIZE) { log.error("Multicast packet received was too long, dropping package:"+receivePacket.getLength()); } else { byte[] data = new byte[receivePacket.getLength()]; System.arraycopy(receivePacket.getData(), receivePacket.getOffset(), data, 0, data.length); if (XByteBuffer.firstIndexOf(data,0,MemberImpl.TRIBES_MBR_BEGIN)==0) { memberDataReceived(data); } else { memberBroadcastsReceived(data); } } } catch (SocketTimeoutException x ) { //do nothing, this is normal, we don't want to block forever //since the receive thread is the same thread //that does membership expiration } if (checkexpired) checkExpired(); } private void memberDataReceived(byte[] data) { final MemberImpl m = MemberImpl.getMember(data); if (log.isTraceEnabled()) log.trace("Mcast receive ping from member " + m); Runnable t = null; if (Arrays.equals(m.getCommand(), Member.SHUTDOWN_PAYLOAD)) { if (log.isDebugEnabled()) log.debug("Member has shutdown:" + m); membership.removeMember(m); t = new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); try { Thread.currentThread().setName("Membership-MemberDisappeared."); service.memberDisappeared(m); }finally { Thread.currentThread().setName(name); } } }; } else if (membership.memberAlive(m)) { if (log.isDebugEnabled()) log.debug("Mcast add member " + m); t = new Runnable() { @Override public void run() { String name = Thread.currentThread().getName(); try { Thread.currentThread().setName("Membership-MemberAdded."); service.memberAdded(m); }finally { Thread.currentThread().setName(name); } } }; } //end if if ( t != null ) { executor.execute(t); } } private void memberBroadcastsReceived(final byte[] b) { if (log.isTraceEnabled()) log.trace("Mcast received broadcasts."); XByteBuffer buffer = new XByteBuffer(b,true); if (buffer.countPackages(true)>0) { int count = buffer.countPackages(); final ChannelData[] data = new ChannelData[count]; for (int i=0; i=recoveryCounter ) { errorCounter=0; RecoveryThread.recover(McastServiceImpl.this); } } } } } } }//class ReceiverThread public class SenderThread extends Thread { long time; int errorCounter=0; public SenderThread(long time) { this.time = time; setName("Tribes-MembershipSender"); } @Override public void run() { while ( doRunSender ) { try { send(true); errorCounter = 0; } catch ( Exception x ) { if (errorCounter==0) log.warn("Unable to send mcast message.",x); else log.debug("Unable to send mcast message.",x); if ( (++errorCounter)>=recoveryCounter ) { errorCounter=0; RecoveryThread.recover(McastServiceImpl.this); } } try { Thread.sleep(time); } catch ( Exception ignore ) {} } } }//class SenderThread protected static class RecoveryThread extends Thread { static volatile boolean running = false; public static synchronized void recover(McastServiceImpl parent) { if (running) return; if (!parent.isRecoveryEnabled()) return; running = true; Thread t = new RecoveryThread(parent); t.setName("Tribes-MembershipRecovery"); t.setDaemon(true); t.start(); } McastServiceImpl parent = null; public RecoveryThread(McastServiceImpl parent) { this.parent = parent; } public boolean stopService() { try { parent.stop(Channel.MBR_RX_SEQ | Channel.MBR_TX_SEQ); return true; } catch (Exception x) { log.warn("Recovery thread failed to stop membership service.", x); return false; } } public boolean startService() { try { parent.init(); parent.start(Channel.MBR_RX_SEQ | Channel.MBR_TX_SEQ); return true; } catch (Exception x) { log.warn("Recovery thread failed to start membership service.", x); return false; } } @Override public void run() { boolean success = false; int attempt = 0; try { while (!success) { if(log.isInfoEnabled()) log.info("Tribes membership, running recovery thread, multicasting is not functional."); if (stopService() & startService()) { success = true; if(log.isInfoEnabled()) log.info("Membership recovery was successful."); } try { if (!success) { if(log.isInfoEnabled()) log.info("Recovery attempt "+(++attempt)+" failed, trying again in " +parent.recoverySleepTime+ " seconds"); Thread.sleep(parent.recoverySleepTime); } }catch (InterruptedException ignore) { } } }finally { running = false; } } } public void setRecoveryCounter(int recoveryCounter) { this.recoveryCounter = recoveryCounter; } public void setRecoveryEnabled(boolean recoveryEnabled) { this.recoveryEnabled = recoveryEnabled; } public void setRecoverySleepTime(long recoverySleepTime) { this.recoverySleepTime = recoverySleepTime; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/mbeans-descriptors.xml0000644000175100017510000001562512271464231027634 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/Constants.java0000644000175100017510000000253012271464231026114 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.membership; import org.apache.catalina.tribes.util.Arrays; /** * Manifest constants for the org.apache.catalina.tribes.membership * package. * * @author Peter Rossbach * @author Filip Hanik */ public class Constants { public static final String Package = "org.apache.catalina.tribes.membership"; public static void main(String[] args) throws Exception { System.out.println(Arrays.toString("TRIBES-B".getBytes())); System.out.println(Arrays.toString("TRIBES-E".getBytes())); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/LocalStrings.properties0000644000175100017510000000151312271464231030017 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. cluster.mbean.register.already=MBean {0} already registered! tomcat7-7.0.52/java/org/apache/catalina/tribes/membership/StaticMember.java0000644000175100017510000000514512271464231026524 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.membership; import java.io.IOException; import org.apache.catalina.tribes.util.Arrays; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public class StaticMember extends MemberImpl { public StaticMember() { super(); } public StaticMember(String host, int port, long aliveTime) throws IOException { super(host, port, aliveTime); } public StaticMember(String host, int port, long aliveTime, byte[] payload) throws IOException { super(host, port, aliveTime, payload); } /** * @param host String, either in byte array string format, like {214,116,1,3} * or as a regular hostname, 127.0.0.1 or tomcat01.mydomain.com */ public void setHost(String host) { if ( host == null ) return; if ( host.startsWith("{") ) setHost(Arrays.fromString(host)); else try { setHostname(host); }catch (IOException x) { throw new RuntimeException(x);} } /** * @param domain String, either in byte array string format, like {214,116,1,3} * or as a regular string value like 'mydomain'. The latter will be converted using ISO-8859-1 encoding */ public void setDomain(String domain) { if ( domain == null ) return; if ( domain.startsWith("{") ) setDomain(Arrays.fromString(domain)); else setDomain(Arrays.convert(domain)); } /** * @param id String, must be in byte array string format, like {214,116,1,3} and exactly 16 bytes long */ public void setUniqueId(String id) { byte[] uuid = Arrays.fromString(id); if ( uuid==null || uuid.length != 16 ) throw new RuntimeException("UUID must be exactly 16 bytes, not:"+id); setUniqueId(uuid); } }tomcat7-7.0.52/java/org/apache/catalina/tribes/ChannelListener.java0000644000175100017510000000451012271464231025063 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.io.Serializable; /** * *

    Title: ChannelListener

    * *

    Description: An interface to listens to incoming messages from a channel

    * When a message is received, the Channel will invoke the channel listener in a conditional sequence. * if ( listener.accept(msg,sender) ) listener.messageReceived(msg,sender);
    * A ChannelListener implementation MUST NOT return true on accept(Serializable, Member) * if it doesn't intend to process the message. The channel can this way track whether a message * was processed by an above application or if it was just received and forgot about, a feature required * to support message-response(RPC) calls
    * * @author Filip Hanik * @version 1.0 */ public interface ChannelListener { /** * Receive a message from the channel * @param msg Serializable * @param sender - the source of the message */ public void messageReceived(Serializable msg, Member sender); /** * Invoked by the channel to determine if the listener will process this message or not. * @param msg Serializable * @param sender Member * @return boolean */ public boolean accept(Serializable msg, Member sender); /** * * @param listener Object * @return boolean * @see Object#equals(Object) */ @Override public boolean equals(Object listener); /** * * @return int * @see Object#hashCode() */ @Override public int hashCode(); } tomcat7-7.0.52/java/org/apache/catalina/tribes/ByteMessage.java0000644000175100017510000000626212271464231024223 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * A byte message is not serialized and deserialized by the channel * instead it is sent as a byte array
    * By default Tribes uses java serialization when it receives an object * to be sent over the wire. Java serialization is not the most * efficient of serializing data, and Tribes might not even * have access to the correct class loaders to deserialize the object properly. *
    * The ByteMessage class is a class where the channel when it receives it will * not attempt to perform serialization, instead it will simply stream the getMessage() * bytes.
    * If you are using multiple applications on top of Tribes you should add some sort of header * so that you can decide with the ChannelListener.accept() whether this message was intended * for you. * @author Filip Hanik */ public class ByteMessage implements Externalizable { /** * Storage for the message to be sent */ private byte[] message; /** * Creates an empty byte message * Constructor also for deserialization */ public ByteMessage() { } /** * Creates a byte message wit h * @param data byte[] - the message contents */ public ByteMessage(byte[] data) { message = data; } /** * Returns the message contents of this byte message * @return byte[] - message contents, can be null */ public byte[] getMessage() { return message; } /** * Sets the message contents of this byte message * @param message byte[] */ public void setMessage(byte[] message) { this.message = message; } /** * @see java.io.Externalizable#readExternal * @param in ObjectInput * @throws IOException */ @Override public void readExternal(ObjectInput in ) throws IOException { int length = in.readInt(); message = new byte[length]; in.readFully(message); } /** * @see java.io.Externalizable#writeExternal * @param out ObjectOutput * @throws IOException */ @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(message!=null?message.length:0); if ( message!=null ) out.write(message,0,message.length); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/0000755000175100017510000000000012301126370023167 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/transport/LocalStrings_es.properties0000644000175100017510000000663112271464231030415 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. IDataSender.ack.eof = EOF alcanzado en puerto local [{0}\:{1,number,integer}] IDataSender.ack.receive = Obtenido ACK en puerto local [{0}\:{1,number,integer}] IDataSender.ack.missing = No puedo leer reconocimiento desde [{0}\:{1,number,integer}] en {2,number,integer} ms. Desconectando conector e intentando otra vez. IDataSender.ack.read = Car\u00E1cter de espera de lectura ack '{2}' [{0}\:{1,number,integer}] IDataSender.ack.start = Esperando por mensaje ACK [{0}\:{1,number,integer}] IDataSender.ack.wrong = Falta ACK correcto tras 10 bytes le\u00EDdos en puerto local [{0}\:{1,number,integer}] IDataSender.closeSocket = El remitente cerr\u00F3 el conector con [{0}\:{1,number,integer}] (contador de cierre {2,number,integer}) IDataSender.connect = Remitente conectado con [{0}\:{1,number,integer}] (contador de conexi\u00F3n {2,number,integer}) IDataSender.create = Crear remitente [{0}\:{1,number,integer}] IDataSender.disconnect = Remitente desconectado de [{0}\:{1,number,integer}] (contador de desconexi\u00F3n {2,number,integer}) IDataSender.message.disconnect = Mensaje transferido\: El remitente no se pude desconectar de [{0}\:{1,number,integer}] IDataSender.message.create = Mensaje transferido\: El remitente no puede crear conector en curso [{0}\:{1,number,integer}] IDataSender.openSocket = Remitente abri\u00F3 conector con [{0}\:{1,number,integer}] (contador de apertura {2,number,integer}) IDataSender.openSocket.failure = \u00A1No pude abrir conector de remitente [{0}\:{1,number,integer}]\! (contador de fallo de apertura {2,number,integer}) IDataSender.send.again = Enviar datos de nuevo a [{0}\:{1,number,integer}] IDataSender.send.crash = Enviar mensaje se rompi\u00F3 [{0}\:{1,number,integer}] tipo\=[{2}], id\=[{3}] IDataSender.send.message = Enviar mensaje a [{0}\:{1,number,integer}] id\=[{2}] medida\={3,number,integer} IDataSender.send.lost = Mensaje perdido\: [{0}\:{1,number,integer}] tipo\=[{2}], id\=[{3}] IDataSender.senderModes.Configured = Configurado un remitente de r\u00E9plica de datos para el modo {0} IDataSender.senderModes.Instantiate = No puedo instanciar remitente de r\u00E9plica de datos de clase {0} IDataSender.senderModes.Missing = No puedo configurar remitente de r\u00E9plica de datos para modo {0} IDataSender.senderModes.Resources = No puedo cargar lista de mapeo de remitente de r\u00E9plica de datos de clase {0} IDataSender.stats = Estados de Env\u00EDo desde [{0}\:{1,number,integer}], Nr de bytes enviado\={2,number,integer} sobre {3} \= {4,number,integer} bytes/requerimiento, tiempo de proceso {5,number,integer} mseg, tiempo medio de proceso {6,number,integer} mseg PooledSender.senderDisconnectFail = No pude desconectar al remitente tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/PooledSender.java0000644000175100017510000001564312271464231026435 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import java.io.IOException; import java.util.List; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.util.StringManager; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public abstract class PooledSender extends AbstractSender implements MultiPointSender { private static final Log log = LogFactory.getLog(PooledSender.class); protected static final StringManager sm = StringManager.getManager(Constants.Package); private SenderQueue queue = null; private int poolSize = 25; private long maxWait = 3000; public PooledSender() { queue = new SenderQueue(this,poolSize); } public abstract DataSender getNewDataSender(); public DataSender getSender() { return queue.getSender(getMaxWait()); } public void returnSender(DataSender sender) { sender.keepalive(); queue.returnSender(sender); } @Override public synchronized void connect() throws IOException { //do nothing, happens in the socket sender itself queue.open(); setConnected(true); } @Override public synchronized void disconnect() { queue.close(); setConnected(false); } public int getInPoolSize() { return queue.getInPoolSize(); } public int getInUsePoolSize() { return queue.getInUsePoolSize(); } public void setPoolSize(int poolSize) { this.poolSize = poolSize; queue.setLimit(poolSize); } public int getPoolSize() { return poolSize; } public long getMaxWait() { return maxWait; } public void setMaxWait(long maxWait) { this.maxWait = maxWait; } @Override public boolean keepalive() { //do nothing, the pool checks on every return return (queue==null)?false:queue.checkIdleKeepAlive(); } @Override public void add(Member member) { // no op, senders created upon demands } @Override public void remove(Member member) { //no op for now, should not cancel out any keys //can create serious sync issues //all TCP connections are cleared out through keepalive //and if remote node disappears } // ----------------------------------------------------- Inner Class private static class SenderQueue { private int limit = 25; PooledSender parent = null; private List notinuse = null; private List inuse = null; private boolean isOpen = true; public SenderQueue(PooledSender parent, int limit) { this.limit = limit; this.parent = parent; notinuse = new java.util.LinkedList(); inuse = new java.util.LinkedList(); } /** * @return Returns the limit. */ public int getLimit() { return limit; } /** * @param limit The limit to set. */ public void setLimit(int limit) { this.limit = limit; } public int getInUsePoolSize() { return inuse.size(); } public int getInPoolSize() { return notinuse.size(); } public synchronized boolean checkIdleKeepAlive() { DataSender[] list = new DataSender[notinuse.size()]; notinuse.toArray(list); boolean result = false; for (int i=0; i 0) { sender = notinuse.remove(0); } if (sender != null) { inuse.add(sender); return sender; }//end if long delta = System.currentTimeMillis() - start; if ( delta > timeout && timeout>0) return null; else { try { wait(Math.max(timeout - delta,1)); }catch (InterruptedException x){} }//end if } } public synchronized void returnSender(DataSender sender) { if ( !isOpen) { sender.disconnect(); return; } //to do inuse.remove(sender); //just in case the limit has changed if ( notinuse.size() < this.getLimit() ) notinuse.add(sender); else try { sender.disconnect(); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString( "PooledSender.senderDisconnectFail"), e); } } notify(); } public synchronized void close() { isOpen = false; Object[] unused = notinuse.toArray(); Object[] used = inuse.toArray(); for (int i = 0; i < unused.length; i++) { DataSender sender = (DataSender) unused[i]; sender.disconnect(); }//for for (int i = 0; i < used.length; i++) { DataSender sender = (DataSender) used[i]; sender.disconnect(); }//for notinuse.clear(); inuse.clear(); notify(); } public synchronized void open() { isOpen = true; notify(); } } }tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/bio/0000755000175100017510000000000012301126370023740 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/transport/bio/PooledMultiSender.java0000644000175100017510000000513412271464231030213 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.bio; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.transport.AbstractSender; import org.apache.catalina.tribes.transport.DataSender; import org.apache.catalina.tribes.transport.MultiPointSender; import org.apache.catalina.tribes.transport.PooledSender; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public class PooledMultiSender extends PooledSender { public PooledMultiSender() { // NO-OP } @Override public void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException { MultiPointSender sender = null; try { sender = (MultiPointSender)getSender(); if (sender == null) { ChannelException cx = new ChannelException("Unable to retrieve a data sender, time out("+getMaxWait()+" ms) error."); for (int i = 0; i < destination.length; i++) cx.addFaultyMember(destination[i], new NullPointerException("Unable to retrieve a sender from the sender pool")); throw cx; } else { sender.sendMessage(destination, msg); } sender.keepalive(); }finally { if ( sender != null ) returnSender(sender); } } /** * getNewDataSender * * @return DataSender * TODO Implement this org.apache.catalina.tribes.transport.PooledSender * method */ @Override public DataSender getNewDataSender() { MultipointBioSender sender = new MultipointBioSender(); AbstractSender.transferProperties(this,sender); return sender; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/bio/BioReplicationTask.java0000644000175100017510000001526612271464231030352 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.bio; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.io.BufferPool; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.ListenCallback; import org.apache.catalina.tribes.io.ObjectReader; import org.apache.catalina.tribes.transport.AbstractRxTask; import org.apache.catalina.tribes.transport.Constants; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * A worker thread class which can drain channels and echo-back the input. Each * instance is constructed with a reference to the owning thread pool object. * When started, the thread loops forever waiting to be awakened to service the * channel associated with a SelectionKey object. The worker is tasked by * calling its serviceChannel() method with a SelectionKey object. The * serviceChannel() method stores the key reference in the thread object then * calls notify() to wake it up. When the channel has been drained, the worker * thread returns itself to its parent pool. * * @author Filip Hanik */ public class BioReplicationTask extends AbstractRxTask { private static final Log log = LogFactory.getLog( BioReplicationTask.class ); protected Socket socket; protected ObjectReader reader; public BioReplicationTask (ListenCallback callback) { super(callback); } // loop forever waiting for work to do @Override public synchronized void run() { if ( socket == null ) return; try { drainSocket(); } catch ( Exception x ) { log.error("Unable to service bio socket", x); }finally { try { socket.close(); }catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Failed to close socket", e); } } try { reader.close(); }catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Failed to close reader", e); } } reader = null; socket = null; } // done, ready for more, return to pool if ( getTaskPool() != null ) getTaskPool().returnWorker (this); } public synchronized void serviceSocket(Socket socket, ObjectReader reader) { this.socket = socket; this.reader = reader; } protected void execute(ObjectReader reader) throws Exception{ int pkgcnt = reader.count(); if ( pkgcnt > 0 ) { ChannelMessage[] msgs = reader.execute(); for ( int i=0; i= 0 ) { int count = reader.append(buf,0,length,true); if ( count > 0 ) execute(reader); length = in.read(buf); } } /** * send a reply-acknowledgment (6,2,3) * @param command */ protected void sendAck(byte[] command) { try { OutputStream out = socket.getOutputStream(); out.write(command); out.flush(); if (log.isTraceEnabled()) { log.trace("ACK sent to " + socket.getPort()); } } catch ( java.io.IOException x ) { log.warn("Unable to send ACK back through channel, channel disconnected?: "+x.getMessage()); } } @Override public void close() { setDoRun(false); try { socket.close(); }catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Failed to close socket", e); } } try { reader.close(); }catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Failed to close reader", e); } } reader = null; socket = null; super.close(); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/bio/BioSender.java0000644000175100017510000002467512271464231026502 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.bio; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Arrays; import org.apache.catalina.tribes.RemoteProcessException; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.transport.AbstractSender; import org.apache.catalina.tribes.transport.Constants; import org.apache.catalina.tribes.transport.SenderState; import org.apache.catalina.tribes.util.StringManager; /** * Send cluster messages with only one socket. Ack and keep Alive Handling is * supported * * @author Peter Rossbach * @author Filip Hanik * @since 5.5.16 */ public class BioSender extends AbstractSender { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(BioSender.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ private static final String info = "DataSender/3.0"; /** * current sender socket */ private Socket socket = null; private OutputStream soOut = null; private InputStream soIn = null; protected XByteBuffer ackbuf = new XByteBuffer(Constants.ACK_COMMAND.length,true); // ------------------------------------------------------------- Constructor public BioSender() { // NO-OP } // ------------------------------------------------------------- Properties /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Connect other cluster member receiver * @see org.apache.catalina.tribes.transport.DataSender#connect() */ @Override public void connect() throws IOException { openSocket(); } /** * disconnect and close socket * * @see org.apache.catalina.tribes.transport.DataSender#disconnect() */ @Override public void disconnect() { boolean connect = isConnected(); closeSocket(); if (connect) { if (log.isDebugEnabled()) log.debug(sm.getString("IDataSender.disconnect", getAddress().getHostAddress(), new Integer(getPort()), new Long(0))); } } /** * Send message. */ public void sendMessage(byte[] data, boolean waitForAck) throws IOException { IOException exception = null; setAttempt(0); try { // first try with existing connection pushMessage(data,false,waitForAck); } catch (IOException x) { SenderState.getSenderState(getDestination()).setSuspect(); exception = x; if (log.isTraceEnabled()) log.trace(sm.getString("IDataSender.send.again", getAddress().getHostAddress(),new Integer(getPort())),x); while ( getAttempt() bioSenders = new HashMap(); @Override public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException { byte[] data = XByteBuffer.createDataPackage((ChannelData)msg); BioSender[] senders = setupForSend(destination); ChannelException cx = null; for ( int i=0; i Map.Entry[] entries = bioSenders.entrySet().toArray(new Map.Entry[bioSenders.size()]); for ( int i=0; iLinkObject implements an element * for a linked list, consisting of a general * data object and a pointer to the next element. * * @author Rainer Jung * @author Peter Rossbach * @author Filip Hanik */ public class LinkObject { private ChannelMessage msg; private LinkObject next; private byte[] key ; private Member[] destination; private InterceptorPayload payload; /** * Construct a new element from the data object. * Sets the pointer to null. * * @param msg the message * @param destination TBA * @param payload The data object. */ public LinkObject(ChannelMessage msg, Member[] destination, InterceptorPayload payload) { this.msg = msg; this.next = null; this.key = msg.getUniqueId(); this.payload = payload; this.destination = destination; } /** * Set the next element. * @param next The next element. */ public void append(LinkObject next) { this.next = next; } /** * Get the next element. * @return The next element. */ public LinkObject next() { return next; } public void setNext(LinkObject next) { this.next = next; } /** * Get the data object from the element. * @return The data object from the element. */ public ChannelMessage data() { return msg; } /** * Get the unique message id * @return the unique message id */ public byte[] getKey() { return key; } public ErrorHandler getHandler() { return payload!=null?payload.getErrorHandler():null; } public InterceptorPayload getPayload() { return payload; } public Member[] getDestination() { return destination; } } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootroottomcat7-7.0.52/java/org/apache/catalina/tribes/transport/bio/util/SingleRemoveSynchronizedAddLock.javatomcat7-7.0.52/java/org/apache/catalina/tribes/transport/bio/util/SingleRemoveSynchronizedAddLock.ja0000644000175100017510000001660412271464231033470 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.bio.util; /** * The class SingleRemoveSynchronizedAddLock implement locking for * accessing the queue by a single remove thread and multiple add threads. * * A thread is only allowed to be either the remove or * an add thread. * * The lock can either be owned by the remove thread * or by a single add thread. * * If the remove thread tries to get the lock, * but the queue is empty, it will block (poll) * until an add threads adds an entry to the queue and * releases the lock. * * If the remove thread and add threads compete for * the lock and an add thread releases the lock, then * the remove thread will get the lock first. * * The remove thread removes all entries in the queue * at once and processes them without further * polling the queue. * * The lock is not reentrant, in the sense, that all * threads must release an owned lock before competing * for the lock again! * * @author Rainer Jung * @author Peter Rossbach * @version 1.1 */ public class SingleRemoveSynchronizedAddLock { public SingleRemoveSynchronizedAddLock() { // NO-OP } public SingleRemoveSynchronizedAddLock(boolean dataAvailable) { this.dataAvailable=dataAvailable; } /** * Time in milliseconds after which threads * waiting for an add lock are woken up. * This is used as a safety measure in case * thread notification via the unlock methods * has a bug. */ private long addWaitTimeout = 10000L; /** * Time in milliseconds after which threads * waiting for a remove lock are woken up. * This is used as a safety measure in case * thread notification via the unlock methods * has a bug. */ private long removeWaitTimeout = 30000L; /** * The current remove thread. * It is set to the remove thread polling for entries. * It is reset to null when the remove thread * releases the lock and proceeds processing * the removed entries. */ private Thread remover = null; /** * A flag indicating, if an add thread owns the lock. */ private boolean addLocked = false; /** * A flag indicating, if the remove thread owns the lock. */ private boolean removeLocked = false; /** * A flag indicating, if the remove thread is allowed * to wait for the lock. The flag is set to false, when aborting. */ private boolean removeEnabled = true; /** * A flag indicating, if the remover needs polling. * It indicates, if the locked object has data available * to be removed. */ private boolean dataAvailable = false; /** * @return Value of addWaitTimeout */ public synchronized long getAddWaitTimeout() { return addWaitTimeout; } /** * Set value of addWaitTimeout */ public synchronized void setAddWaitTimeout(long timeout) { addWaitTimeout = timeout; } /** * @return Value of removeWaitTimeout */ public synchronized long getRemoveWaitTimeout() { return removeWaitTimeout; } /** * Set value of removeWaitTimeout */ public synchronized void setRemoveWaitTimeout(long timeout) { removeWaitTimeout = timeout; } /** * Check if the locked object has data available * i.e. the remover can stop poling and get the lock. * @return True iff the lock Object has data available. */ public synchronized boolean isDataAvailable() { return dataAvailable; } /** * Check if an add thread owns the lock. * @return True iff an add thread owns the lock. */ public synchronized boolean isAddLocked() { return addLocked; } /** * Check if the remove thread owns the lock. * @return True iff the remove thread owns the lock. */ public synchronized boolean isRemoveLocked() { return removeLocked; } /** * Check if the remove thread is polling. * @return True iff the remove thread is polling. */ public synchronized boolean isRemovePolling() { if ( remover != null ) { return true; } return false; } /** * Acquires the lock by an add thread and sets the add flag. * If any add thread or the remove thread already acquired the lock * this add thread will block until the lock is released. */ public synchronized void lockAdd() { if ( addLocked || removeLocked ) { do { try { wait(addWaitTimeout); } catch ( InterruptedException e ) { Thread.currentThread().interrupt(); } } while ( addLocked || removeLocked ); } addLocked=true; } /** * Acquires the lock by the remove thread and sets the remove flag. * If any add thread already acquired the lock or the queue is * empty, the remove thread will block until the lock is released * and the queue is not empty. */ public synchronized boolean lockRemove() { removeLocked=false; removeEnabled=true; if ( ( addLocked || ! dataAvailable ) && removeEnabled ) { remover=Thread.currentThread(); do { try { wait(removeWaitTimeout); } catch ( InterruptedException e ) { Thread.currentThread().interrupt(); } } while ( ( addLocked || ! dataAvailable ) && removeEnabled ); remover=null; } if ( removeEnabled ) { removeLocked=true; } return removeLocked; } /** * Releases the lock by an add thread and reset the remove flag. * If the reader thread is polling, notify it. */ public synchronized void unlockAdd(boolean dataAvailable) { addLocked=false; this.dataAvailable=dataAvailable; if ( ( remover != null ) && ( dataAvailable || ! removeEnabled ) ) { remover.interrupt(); } else { notifyAll(); } } /** * Releases the lock by the remove thread and reset the add flag. * Notify all waiting add threads, * that the lock has been released by the remove thread. */ public synchronized void unlockRemove() { removeLocked=false; dataAvailable=false; notifyAll(); } /** * Abort any polling remover thread */ public synchronized void abortRemove() { removeEnabled=false; if ( remover != null ) { remover.interrupt(); } } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/bio/util/FastQueue.java0000644000175100017510000002277712271464231027510 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.bio.util; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.InterceptorPayload; /** * A fast queue that remover thread lock the adder thread.
    Limit the queue * length when you have strange producer thread problems. * * FIXME add i18n support to log messages * @author Rainer Jung * @author Peter Rossbach */ public class FastQueue { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(FastQueue.class); /** * This is the actual queue */ private SingleRemoveSynchronizedAddLock lock = null; /** * First Object at queue (consumer message) */ private LinkObject first = null; /** * Last object in queue (producer Object) */ private LinkObject last = null; /** * Current Queue elements size */ private volatile int size = 0; /** * check lock to detect strange threadings things */ private volatile boolean checkLock = false; // Flags used to detect unexpected state private volatile boolean inAdd = false; private volatile boolean inRemove = false; private volatile boolean inMutex = false; /** * limit the queue length ( default is unlimited) */ private int maxQueueLength = 0; /** * addWaitTimeout for producer */ private long addWaitTimeout = 10000L; /** * removeWaitTimeout for consumer */ private long removeWaitTimeout = 30000L; /** * enabled the queue */ private volatile boolean enabled = true; /** * max queue size */ private int maxSize = 0; /** * Generate Queue SingleRemoveSynchronizedAddLock and set add and wait * Timeouts */ public FastQueue() { lock = new SingleRemoveSynchronizedAddLock(); lock.setAddWaitTimeout(addWaitTimeout); lock.setRemoveWaitTimeout(removeWaitTimeout); } /** * get current add wait timeout * * @return current wait timeout */ public long getAddWaitTimeout() { addWaitTimeout = lock.getAddWaitTimeout(); return addWaitTimeout; } /** * Set add wait timeout (default 10000 msec) * * @param timeout */ public void setAddWaitTimeout(long timeout) { addWaitTimeout = timeout; lock.setAddWaitTimeout(addWaitTimeout); } /** * get current remove wait timeout * * @return The timeout */ public long getRemoveWaitTimeout() { removeWaitTimeout = lock.getRemoveWaitTimeout(); return removeWaitTimeout; } /** * set remove wait timeout ( default 30000 msec) * * @param timeout */ public void setRemoveWaitTimeout(long timeout) { removeWaitTimeout = timeout; lock.setRemoveWaitTimeout(removeWaitTimeout); } public int getMaxQueueLength() { return maxQueueLength; } public void setMaxQueueLength(int length) { maxQueueLength = length; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enable) { enabled = enable; if (!enable) { lock.abortRemove(); last = first = null; } } /** * @return Returns the checkLock. */ public boolean isCheckLock() { return checkLock; } /** * @param checkLock The checkLock to set. */ public void setCheckLock(boolean checkLock) { this.checkLock = checkLock; } /** * @return The max size */ public int getMaxSize() { return maxSize; } /** * @param size */ public void setMaxSize(int size) { maxSize = size; } /** * unlock queue for next add */ public void unlockAdd() { lock.unlockAdd(size > 0 ? true : false); } /** * unlock queue for next remove */ public void unlockRemove() { lock.unlockRemove(); } /** * start queuing */ public void start() { setEnabled(true); } /** * start queuing */ public void stop() { setEnabled(false); } public int getSize() { return size; } public SingleRemoveSynchronizedAddLock getLock() { return lock; } /** * Add new data to the queue. * * FIXME extract some method */ public boolean add(ChannelMessage msg, Member[] destination, InterceptorPayload payload) { boolean ok = true; if (!enabled) { if (log.isInfoEnabled()) log.info("FastQueue.add: queue disabled, add aborted"); return false; } lock.lockAdd(); try { if (log.isTraceEnabled()) { log.trace("FastQueue.add: starting with size " + size); } if (checkLock) { if (inAdd) log.warn("FastQueue.add: Detected other add"); inAdd = true; if (inMutex) log.warn("FastQueue.add: Detected other mutex in add"); inMutex = true; } if ((maxQueueLength > 0) && (size >= maxQueueLength)) { ok = false; if (log.isTraceEnabled()) { log.trace("FastQueue.add: Could not add, since queue is full (" + size + ">=" + maxQueueLength + ")"); } } else { LinkObject element = new LinkObject(msg,destination, payload); if (size == 0) { first = last = element; size = 1; } else { if (last == null) { ok = false; log.error("FastQueue.add: Could not add, since last is null although size is "+ size + " (>0)"); } else { last.append(element); last = element; size++; } } } if (first == null) { log.error("FastQueue.add: first is null, size is " + size + " at end of add"); } if (last == null) { log.error("FastQueue.add: last is null, size is " + size+ " at end of add"); } if (checkLock) { if (!inMutex) log.warn("FastQueue.add: Cancelled by other mutex in add"); inMutex = false; if (!inAdd) log.warn("FastQueue.add: Cancelled by other add"); inAdd = false; } if (log.isTraceEnabled()) log.trace("FastQueue.add: add ending with size " + size); } finally { lock.unlockAdd(true); } return ok; } /** * Remove the complete queued object list. * FIXME extract some method */ public LinkObject remove() { LinkObject element; boolean gotLock; if (!enabled) { if (log.isInfoEnabled()) log.info("FastQueue.remove: queue disabled, remove aborted"); return null; } gotLock = lock.lockRemove(); try { if (!gotLock) { if (enabled) { if (log.isInfoEnabled()) log.info("FastQueue.remove: Remove aborted although queue enabled"); } else { if (log.isInfoEnabled()) log.info("FastQueue.remove: queue disabled, remove aborted"); } return null; } if (log.isTraceEnabled()) { log.trace("FastQueue.remove: remove starting with size " + size); } if (checkLock) { if (inRemove) log.warn("FastQueue.remove: Detected other remove"); inRemove = true; if (inMutex) log.warn("FastQueue.remove: Detected other mutex in remove"); inMutex = true; } element = first; first = last = null; size = 0; if (checkLock) { if (!inMutex) log.warn("FastQueue.remove: Cancelled by other mutex in remove"); inMutex = false; if (!inRemove) log.warn("FastQueue.remove: Cancelled by other remove"); inRemove = false; } if (log.isTraceEnabled()) { log.trace("FastQueue.remove: remove ending with size " + size); } } finally { lock.unlockRemove(); } return element; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/AbstractSender.java0000644000175100017510000002161412271464231026751 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import org.apache.catalina.tribes.Member; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public abstract class AbstractSender implements DataSender { private boolean connected = false; private int rxBufSize = 25188; private int txBufSize = 43800; private int udpRxBufSize = 25188; private int udpTxBufSize = 43800; private boolean directBuffer = false; private int keepAliveCount = -1; private int requestCount = 0; private long connectTime; private long keepAliveTime = -1; private long timeout = 3000; private Member destination; private InetAddress address; private int port; private int maxRetryAttempts = 1;//1 resends private int attempt; private boolean tcpNoDelay = true; private boolean soKeepAlive = false; private boolean ooBInline = true; private boolean soReuseAddress = true; private boolean soLingerOn = false; private int soLingerTime = 3; private int soTrafficClass = 0x04 | 0x08 | 0x010; private boolean throwOnFailedAck = true; private boolean udpBased = false; private int udpPort = -1; /** * transfers sender properties from one sender to another * @param from AbstractSender * @param to AbstractSender */ public static void transferProperties(AbstractSender from, AbstractSender to) { to.rxBufSize = from.rxBufSize; to.txBufSize = from.txBufSize; to.directBuffer = from.directBuffer; to.keepAliveCount = from.keepAliveCount; to.keepAliveTime = from.keepAliveTime; to.timeout = from.timeout; to.destination = from.destination; to.address = from.address; to.port = from.port; to.maxRetryAttempts = from.maxRetryAttempts; to.tcpNoDelay = from.tcpNoDelay; to.soKeepAlive = from.soKeepAlive; to.ooBInline = from.ooBInline; to.soReuseAddress = from.soReuseAddress; to.soLingerOn = from.soLingerOn; to.soLingerTime = from.soLingerTime; to.soTrafficClass = from.soTrafficClass; to.throwOnFailedAck = from.throwOnFailedAck; to.udpBased = from.udpBased; to.udpPort = from.udpPort; } public AbstractSender() { } /** * connect * * @throws IOException * TODO Implement this org.apache.catalina.tribes.transport.DataSender method */ @Override public abstract void connect() throws IOException; /** * disconnect * * TODO Implement this org.apache.catalina.tribes.transport.DataSender method */ @Override public abstract void disconnect(); /** * keepalive * * @return boolean * TODO Implement this org.apache.catalina.tribes.transport.DataSender method */ @Override public boolean keepalive() { boolean disconnect = false; if (isUdpBased()) disconnect = true; //always disconnect UDP, TODO optimize the keepalive handling else if ( keepAliveCount >= 0 && requestCount>keepAliveCount ) disconnect = true; else if ( keepAliveTime >= 0 && (System.currentTimeMillis()-connectTime)>keepAliveTime ) disconnect = true; if ( disconnect ) disconnect(); return disconnect; } protected void setConnected(boolean connected){ this.connected = connected; } @Override public boolean isConnected() { return connected; } @Override public long getConnectTime() { return connectTime; } public Member getDestination() { return destination; } public int getKeepAliveCount() { return keepAliveCount; } public long getKeepAliveTime() { return keepAliveTime; } @Override public int getRequestCount() { return requestCount; } public int getRxBufSize() { return rxBufSize; } public long getTimeout() { return timeout; } public int getTxBufSize() { return txBufSize; } public InetAddress getAddress() { return address; } public int getPort() { return port; } public int getMaxRetryAttempts() { return maxRetryAttempts; } public void setDirect(boolean direct) { setDirectBuffer(direct); } public void setDirectBuffer(boolean directBuffer) { this.directBuffer = directBuffer; } public boolean getDirect() { return getDirectBuffer(); } public boolean getDirectBuffer() { return this.directBuffer; } public int getAttempt() { return attempt; } public boolean getTcpNoDelay() { return tcpNoDelay; } public boolean getSoKeepAlive() { return soKeepAlive; } public boolean getOoBInline() { return ooBInline; } public boolean getSoReuseAddress() { return soReuseAddress; } public boolean getSoLingerOn() { return soLingerOn; } public int getSoLingerTime() { return soLingerTime; } public int getSoTrafficClass() { return soTrafficClass; } public boolean getThrowOnFailedAck() { return throwOnFailedAck; } @Override public void setKeepAliveCount(int keepAliveCount) { this.keepAliveCount = keepAliveCount; } @Override public void setKeepAliveTime(long keepAliveTime) { this.keepAliveTime = keepAliveTime; } public void setRequestCount(int requestCount) { this.requestCount = requestCount; } @Override public void setRxBufSize(int rxBufSize) { this.rxBufSize = rxBufSize; } @Override public void setTimeout(long timeout) { this.timeout = timeout; } @Override public void setTxBufSize(int txBufSize) { this.txBufSize = txBufSize; } public void setConnectTime(long connectTime) { this.connectTime = connectTime; } public void setMaxRetryAttempts(int maxRetryAttempts) { this.maxRetryAttempts = maxRetryAttempts; } public void setAttempt(int attempt) { this.attempt = attempt; } public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } public void setSoKeepAlive(boolean soKeepAlive) { this.soKeepAlive = soKeepAlive; } public void setOoBInline(boolean ooBInline) { this.ooBInline = ooBInline; } public void setSoReuseAddress(boolean soReuseAddress) { this.soReuseAddress = soReuseAddress; } public void setSoLingerOn(boolean soLingerOn) { this.soLingerOn = soLingerOn; } public void setSoLingerTime(int soLingerTime) { this.soLingerTime = soLingerTime; } public void setSoTrafficClass(int soTrafficClass) { this.soTrafficClass = soTrafficClass; } public void setThrowOnFailedAck(boolean throwOnFailedAck) { this.throwOnFailedAck = throwOnFailedAck; } public void setDestination(Member destination) throws UnknownHostException { this.destination = destination; this.address = InetAddress.getByAddress(destination.getHost()); this.port = destination.getPort(); this.udpPort = destination.getUdpPort(); } public void setPort(int port) { this.port = port; } public void setAddress(InetAddress address) { this.address = address; } public boolean isUdpBased() { return udpBased; } public void setUdpBased(boolean udpBased) { this.udpBased = udpBased; } public int getUdpPort() { return udpPort; } public void setUdpPort(int udpPort) { this.udpPort = udpPort; } public int getUdpRxBufSize() { return udpRxBufSize; } public void setUdpRxBufSize(int udpRxBufSize) { this.udpRxBufSize = udpRxBufSize; } public int getUdpTxBufSize() { return udpTxBufSize; } public void setUdpTxBufSize(int udpTxBufSize) { this.udpTxBufSize = udpTxBufSize; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/ReplicationTransmitter.java0000644000175100017510000001022112271464231030543 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.ChannelSender; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.transport.nio.PooledParallelSender; import org.apache.catalina.tribes.util.StringManager; /** * Transmit message to other cluster members * Actual senders are created based on the replicationMode * type * * @author Filip Hanik */ public class ReplicationTransmitter implements ChannelSender { /** * The descriptive information about this implementation. */ private static final String info = "ReplicationTransmitter/3.0"; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); public ReplicationTransmitter() { } private MultiPointSender transport = new PooledParallelSender(); /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } public MultiPointSender getTransport() { return transport; } public void setTransport(MultiPointSender transport) { this.transport = transport; } // ------------------------------------------------------------- public /** * Send data to one member * @see org.apache.catalina.tribes.ChannelSender#sendMessage(org.apache.catalina.tribes.ChannelMessage, org.apache.catalina.tribes.Member[]) */ @Override public void sendMessage(ChannelMessage message, Member[] destination) throws ChannelException { MultiPointSender sender = getTransport(); sender.sendMessage(destination,message); } /** * start the sender and register transmitter mbean * * @see org.apache.catalina.tribes.ChannelSender#start() */ @Override public void start() throws java.io.IOException { getTransport().connect(); } /** * stop the sender and deregister mbeans (transmitter, senders) * * @see org.apache.catalina.tribes.ChannelSender#stop() */ @Override public synchronized void stop() { getTransport().disconnect(); } /** * Call transmitter to check for sender socket status * * @see org.apache.catalina.ha.tcp.SimpleTcpCluster#backgroundProcess() */ @Override public void heartbeat() { if (getTransport()!=null) getTransport().keepalive(); } /** * add new cluster member and create sender ( s. replicationMode) transfer * current properties to sender * * @see org.apache.catalina.tribes.ChannelSender#add(org.apache.catalina.tribes.Member) */ @Override public synchronized void add(Member member) { getTransport().add(member); } /** * remove sender from transmitter. ( deregister mbean and disconnect sender ) * * @see org.apache.catalina.tribes.ChannelSender#remove(org.apache.catalina.tribes.Member) */ @Override public synchronized void remove(Member member) { getTransport().remove(member); } // ------------------------------------------------------------- protected } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/RxTaskPool.java0000644000175100017510000001132712271464231026113 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * @author not attributable * @version 1.0 */ public class RxTaskPool { /** * A very simple thread pool class. The pool size is set at * construction time and remains fixed. Threads are cycled * through a FIFO idle queue. */ List idle = new LinkedList(); List used = new LinkedList(); Object mutex = new Object(); boolean running = true; private int maxTasks; private int minTasks; private TaskCreator creator = null; public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxTasks = maxTasks; this.minTasks = minTasks; this.creator = creator; } protected void configureTask(AbstractRxTask task) { synchronized (task) { task.setTaskPool(this); // task.setName(task.getClass().getName() + "[" + inc() + "]"); // task.setDaemon(true); // task.setPriority(Thread.MAX_PRIORITY); // task.start(); } } /** * Find an idle worker thread, if any. Could return null. */ public AbstractRxTask getRxTask() { AbstractRxTask worker = null; synchronized (mutex) { while ( worker == null && running ) { if (idle.size() > 0) { try { worker = idle.remove(0); } catch (java.util.NoSuchElementException x) { //this means that there are no available workers worker = null; } } else if ( used.size() < this.maxTasks && creator != null) { worker = creator.createRxTask(); configureTask(worker); } else { try { mutex.wait(); } catch (java.lang.InterruptedException x) { Thread.currentThread().interrupt(); } } }//while if ( worker != null ) used.add(worker); } return (worker); } public int available() { return idle.size(); } /** * Called by the worker thread to return itself to the * idle pool. */ public void returnWorker (AbstractRxTask worker) { if ( running ) { synchronized (mutex) { used.remove(worker); //if ( idle.size() < minThreads && !idle.contains(worker)) idle.add(worker); if ( idle.size() < maxTasks && !idle.contains(worker)) idle.add(worker); //let max be the upper limit else { worker.setDoRun(false); synchronized (worker){worker.notify();} } mutex.notify(); } }else { worker.setDoRun(false); synchronized (worker){worker.notify();} } } public int getMaxThreads() { return maxTasks; } public int getMinThreads() { return minTasks; } public void stop() { running = false; synchronized (mutex) { Iterator i = idle.iterator(); while ( i.hasNext() ) { AbstractRxTask worker = i.next(); returnWorker(worker); i.remove(); } } } public void setMaxTasks(int maxThreads) { this.maxTasks = maxThreads; } public void setMinTasks(int minThreads) { this.minTasks = minThreads; } public TaskCreator getTaskCreator() { return this.creator; } public static interface TaskCreator { public AbstractRxTask createRxTask(); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/ReceiverBase.java0000644000175100017510000003663712271464231026417 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.ChannelReceiver; import org.apache.catalina.tribes.MessageListener; import org.apache.catalina.tribes.io.ListenCallback; import org.apache.catalina.tribes.util.ExecutorFactory; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public abstract class ReceiverBase implements ChannelReceiver, ListenCallback, RxTaskPool.TaskCreator { public static final int OPTION_DIRECT_BUFFER = 0x0004; private static final Log log = LogFactory.getLog(ReceiverBase.class); private static final Object bindLock = new Object(); private MessageListener listener; private String host = "auto"; private InetAddress bind; private int port = 4000; private int udpPort = -1; private int securePort = -1; private int rxBufSize = 43800; private int txBufSize = 25188; private int udpRxBufSize = 43800; private int udpTxBufSize = 25188; private volatile boolean listen = false; private RxTaskPool pool; private boolean direct = true; private long tcpSelectorTimeout = 5000; //how many times to search for an available socket private int autoBind = 100; private int maxThreads = 15; private int minThreads = 6; private int maxTasks = 100; private int minTasks = 10; private boolean tcpNoDelay = true; private boolean soKeepAlive = false; private boolean ooBInline = true; private boolean soReuseAddress = true; private boolean soLingerOn = true; private int soLingerTime = 3; private int soTrafficClass = 0x04 | 0x08 | 0x010; private int timeout = 3000; //3 seconds private boolean useBufferPool = true; private boolean daemon = true; private long maxIdleTime = 60000; private ExecutorService executor; public ReceiverBase() { } @Override public void start() throws IOException { if ( executor == null ) { //executor = new ThreadPoolExecutor(minThreads,maxThreads,60,TimeUnit.SECONDS,new LinkedBlockingQueue()); TaskThreadFactory tf = new TaskThreadFactory("Tribes-Task-Receiver-"); executor = ExecutorFactory.newThreadPool(minThreads, maxThreads, maxIdleTime, TimeUnit.MILLISECONDS, tf); } } @Override public void stop() { if ( executor != null ) executor.shutdownNow();//ignore left overs executor = null; } /** * getMessageListener * * @return MessageListener * TODO Implement this org.apache.catalina.tribes.ChannelReceiver method */ @Override public MessageListener getMessageListener() { return listener; } /** * * @return The port * TODO Implement this org.apache.catalina.tribes.ChannelReceiver method */ @Override public int getPort() { return port; } public int getRxBufSize() { return rxBufSize; } public int getTxBufSize() { return txBufSize; } /** * @deprecated use getMinThreads()/getMaxThreads() * @return int */ @Deprecated public int getTcpThreadCount() { return getMaxThreads(); } /** * setMessageListener * * @param listener MessageListener * TODO Implement this org.apache.catalina.tribes.ChannelReceiver method */ @Override public void setMessageListener(MessageListener listener) { this.listener = listener; } /** * @deprecated use setPort * @param tcpListenPort int */ @Deprecated public void setTcpListenPort(int tcpListenPort) { setPort(tcpListenPort); } /** * @deprecated use setAddress * @param tcpListenHost String */ @Deprecated public void setTcpListenAddress(String tcpListenHost) { setAddress(tcpListenHost); } public void setRxBufSize(int rxBufSize) { this.rxBufSize = rxBufSize; } public void setTxBufSize(int txBufSize) { this.txBufSize = txBufSize; } /** * @deprecated use setMaxThreads/setMinThreads * @param tcpThreadCount int */ @Deprecated public void setTcpThreadCount(int tcpThreadCount) { setMaxThreads(tcpThreadCount); setMinThreads(tcpThreadCount); } /** * @return Returns the bind. */ public InetAddress getBind() { if (bind == null) { try { if ("auto".equals(host)) { host = java.net.InetAddress.getLocalHost().getHostAddress(); } if (log.isDebugEnabled()) log.debug("Starting replication listener on address:"+ host); bind = java.net.InetAddress.getByName(host); } catch (IOException ioe) { log.error("Failed bind replication listener on address:"+ host, ioe); } } return bind; } /** * Attempts to bind using the provided port and if that fails attempts to * bind to each of the ports from portstart to (portstart + retries -1) * until either there are no more ports or the bind is successful. The * address to bind to is obtained via a call to {link {@link #getBind()}. * @param socket The socket to bind * @param portstart Starting port for bind attempts * @param retries Number of times to attempt to bind (port incremented * between attempts) * @throws IOException */ protected void bind(ServerSocket socket, int portstart, int retries) throws IOException { synchronized (bindLock) { InetSocketAddress addr = null; int port = portstart; while (retries > 0) { try { addr = new InetSocketAddress(getBind(), port); socket.bind(addr); setPort(port); log.info("Receiver Server Socket bound to:"+addr); retries = 0; } catch ( IOException x) { retries--; if ( retries <= 0 ) { log.info("Unable to bind server socket to:" + addr + " throwing error."); throw x; } port++; } } } } /** * Same as bind() except it does it for the UDP port * @param socket * @param portstart * @param retries * @return int * @throws IOException */ protected int bindUdp(DatagramSocket socket, int portstart, int retries) throws IOException { InetSocketAddress addr = null; while ( retries > 0 ) { try { addr = new InetSocketAddress(getBind(), portstart); socket.bind(addr); setUdpPort(portstart); log.info("UDP Receiver Server Socket bound to:"+addr); return 0; }catch ( IOException x) { retries--; if ( retries <= 0 ) { log.info("Unable to bind UDP socket to:"+addr+" throwing error."); throw x; } portstart++; try { Thread.sleep(25); } catch (InterruptedException ti) { Thread.currentThread().interrupt(); } retries = bindUdp(socket,portstart,retries); } } return retries; } @Override public void messageDataReceived(ChannelMessage data) { if ( this.listener != null ) { if ( listener.accept(data) ) listener.messageReceived(data); } } public int getWorkerThreadOptions() { int options = 0; if ( getDirect() ) options = options | OPTION_DIRECT_BUFFER; return options; } /** * @param bind The bind to set. */ public void setBind(java.net.InetAddress bind) { this.bind = bind; } /** * @deprecated use getPort * @return int */ @Deprecated public int getTcpListenPort() { return getPort(); } public boolean getDirect() { return direct; } public void setDirect(boolean direct) { this.direct = direct; } public String getAddress() { getBind(); return this.host; } @Override public String getHost() { return getAddress(); } public long getSelectorTimeout() { return tcpSelectorTimeout; } /** * @deprecated use getSelectorTimeout * @return long */ @Deprecated public long getTcpSelectorTimeout() { return getSelectorTimeout(); } public boolean doListen() { return listen; } public MessageListener getListener() { return listener; } public RxTaskPool getTaskPool() { return pool; } /** * @deprecated use getAddress * @return String */ @Deprecated public String getTcpListenAddress() { return getAddress(); } public int getAutoBind() { return autoBind; } public int getMaxThreads() { return maxThreads; } public int getMinThreads() { return minThreads; } public boolean getTcpNoDelay() { return tcpNoDelay; } public boolean getSoKeepAlive() { return soKeepAlive; } public boolean getOoBInline() { return ooBInline; } public boolean getSoLingerOn() { return soLingerOn; } public int getSoLingerTime() { return soLingerTime; } public boolean getSoReuseAddress() { return soReuseAddress; } public int getSoTrafficClass() { return soTrafficClass; } public int getTimeout() { return timeout; } public boolean getUseBufferPool() { return useBufferPool; } @Override public int getSecurePort() { return securePort; } public int getMinTasks() { return minTasks; } public int getMaxTasks() { return maxTasks; } public ExecutorService getExecutor() { return executor; } public boolean isListening() { return listen; } /** * @deprecated use setSelectorTimeout * @param selTimeout long */ @Deprecated public void setTcpSelectorTimeout(long selTimeout) { setSelectorTimeout(selTimeout); } public void setSelectorTimeout(long selTimeout) { tcpSelectorTimeout = selTimeout; } public void setListen(boolean doListen) { this.listen = doListen; } public void setAddress(String host) { this.host = host; } public void setHost(String host) { setAddress(host); } public void setListener(MessageListener listener) { this.listener = listener; } public void setPool(RxTaskPool pool) { this.pool = pool; } public void setPort(int port) { this.port = port; } public void setAutoBind(int autoBind) { this.autoBind = autoBind; if ( this.autoBind <= 0 ) this.autoBind = 1; } public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } public void setMinThreads(int minThreads) { this.minThreads = minThreads; } public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } public void setSoKeepAlive(boolean soKeepAlive) { this.soKeepAlive = soKeepAlive; } public void setOoBInline(boolean ooBInline) { this.ooBInline = ooBInline; } public void setSoLingerOn(boolean soLingerOn) { this.soLingerOn = soLingerOn; } public void setSoLingerTime(int soLingerTime) { this.soLingerTime = soLingerTime; } public void setSoReuseAddress(boolean soReuseAddress) { this.soReuseAddress = soReuseAddress; } public void setSoTrafficClass(int soTrafficClass) { this.soTrafficClass = soTrafficClass; } public void setTimeout(int timeout) { this.timeout = timeout; } public void setUseBufferPool(boolean useBufferPool) { this.useBufferPool = useBufferPool; } public void setSecurePort(int securePort) { this.securePort = securePort; } public void setMinTasks(int minTasks) { this.minTasks = minTasks; } public void setMaxTasks(int maxTasks) { this.maxTasks = maxTasks; } public void setExecutor(ExecutorService executor) { this.executor = executor; } @Override public void heartbeat() { //empty operation } @Override public int getUdpPort() { return udpPort; } public void setUdpPort(int udpPort) { this.udpPort = udpPort; } public int getUdpRxBufSize() { return udpRxBufSize; } public void setUdpRxBufSize(int udpRxBufSize) { this.udpRxBufSize = udpRxBufSize; } public int getUdpTxBufSize() { return udpTxBufSize; } public void setUdpTxBufSize(int udpTxBufSize) { this.udpTxBufSize = udpTxBufSize; } // ---------------------------------------------- ThreadFactory Inner Class class TaskThreadFactory implements ThreadFactory { final ThreadGroup group; final AtomicInteger threadNumber = new AtomicInteger(1); final String namePrefix; TaskThreadFactory(String namePrefix) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.namePrefix = namePrefix; } @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement()); t.setDaemon(daemon); t.setPriority(Thread.NORM_PRIORITY); return t; } } public boolean isDaemon() { return daemon; } public long getMaxIdleTime() { return maxIdleTime; } public void setDaemon(boolean daemon) { this.daemon = daemon; } public void setMaxIdleTime(long maxIdleTime) { this.maxIdleTime = maxIdleTime; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/DataSender.java0000644000175100017510000000271712271464231026062 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import java.io.IOException; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public interface DataSender { public void connect() throws IOException; public void disconnect(); public boolean isConnected(); public void setRxBufSize(int size); public void setTxBufSize(int size); public boolean keepalive(); public void setTimeout(long timeout); public void setKeepAliveCount(int maxRequests); public void setKeepAliveTime(long keepAliveTimeInMs); public int getRequestCount(); public long getConnectTime(); }tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/MultiPointSender.java0000644000175100017510000000254012271464231027307 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; /** * @author Filip Hanik * @since 5.5.16 */ public interface MultiPointSender extends DataSender { public void sendMessage(Member[] destination, ChannelMessage data) throws ChannelException; public void setMaxRetryAttempts(int attempts); public void setDirectBuffer(boolean directBuf); public void add(Member member); public void remove(Member member); } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/AbstractRxTask.java0000644000175100017510000000425012271464231026742 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import org.apache.catalina.tribes.io.ListenCallback; /** * @author Filip Hanik */ public abstract class AbstractRxTask implements Runnable { public static final int OPTION_DIRECT_BUFFER = ReceiverBase.OPTION_DIRECT_BUFFER; private ListenCallback callback; private RxTaskPool pool; private boolean doRun = true; private int options; protected boolean useBufferPool = true; public AbstractRxTask(ListenCallback callback) { this.callback = callback; } public void setTaskPool(RxTaskPool pool) { this.pool = pool; } public void setOptions(int options) { this.options = options; } public void setCallback(ListenCallback callback) { this.callback = callback; } public void setDoRun(boolean doRun) { this.doRun = doRun; } public RxTaskPool getTaskPool() { return pool; } public int getOptions() { return options; } public ListenCallback getCallback() { return callback; } public boolean isDoRun() { return doRun; } public void close() { doRun = false; notify(); } public void setUseBufferPool(boolean usebufpool) { useBufferPool = usebufpool; } public boolean getUseBufferPool() { return useBufferPool; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/nio/0000755000175100017510000000000012301126370023754 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/transport/nio/NioSender.java0000644000175100017510000003453012271464231026521 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.nio; import java.io.EOFException; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Arrays; import org.apache.catalina.tribes.RemoteProcessException; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.transport.AbstractSender; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * This class is NOT thread safe and should never be used with more than one thread at a time * * This is a state machine, handled by the process method * States are: * - NOT_CONNECTED -> connect() -> CONNECTED * - CONNECTED -> setMessage() -> READY TO WRITE * - READY_TO_WRITE -> write() -> READY TO WRITE | READY TO READ * - READY_TO_READ -> read() -> READY_TO_READ | TRANSFER_COMPLETE * - TRANSFER_COMPLETE -> CONNECTED * * @author Filip Hanik * @version 1.0 */ public class NioSender extends AbstractSender { private static final Log log = LogFactory.getLog(NioSender.class); protected Selector selector; protected SocketChannel socketChannel = null; protected DatagramChannel dataChannel = null; /* * STATE VARIABLES * */ protected ByteBuffer readbuf = null; protected ByteBuffer writebuf = null; protected byte[] current = null; protected XByteBuffer ackbuf = new XByteBuffer(128,true); protected int remaining = 0; protected boolean complete; protected boolean connecting = false; public NioSender() { super(); } /** * State machine to send data * @param key SelectionKey * @return boolean * @throws IOException */ public boolean process(SelectionKey key, boolean waitForAck) throws IOException { int ops = key.readyOps(); key.interestOps(key.interestOps() & ~ops); //in case disconnect has been called if ((!isConnected()) && (!connecting)) throw new IOException("Sender has been disconnected, can't selection key."); if ( !key.isValid() ) throw new IOException("Key is not valid, it must have been cancelled."); if ( key.isConnectable() ) { if ( socketChannel.finishConnect() ) { completeConnect(); if ( current != null ) key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); return false; } else { //wait for the connection to finish key.interestOps(key.interestOps() | SelectionKey.OP_CONNECT); return false; }//end if } else if ( key.isWritable() ) { boolean writecomplete = write(key); if ( writecomplete ) { //we are completed, should we read an ack? if ( waitForAck ) { //register to read the ack key.interestOps(key.interestOps() | SelectionKey.OP_READ); } else { //if not, we are ready, setMessage will reregister us for another write interest //do a health check, we have no way of verify a disconnected //socket since we don't register for OP_READ on waitForAck=false read(key);//this causes overhead setRequestCount(getRequestCount()+1); return true; } } else { //we are not complete, lets write some more key.interestOps(key.interestOps()|SelectionKey.OP_WRITE); }//end if } else if ( key.isReadable() ) { boolean readcomplete = read(key); if ( readcomplete ) { setRequestCount(getRequestCount()+1); return true; } else { key.interestOps(key.interestOps() | SelectionKey.OP_READ); }//end if } else { //unknown state, should never happen log.warn("Data is in unknown state. readyOps="+ops); throw new IOException("Data is in unknown state. readyOps="+ops); }//end if return false; } private void configureSocket() throws IOException { if (socketChannel!=null) { socketChannel.configureBlocking(false); socketChannel.socket().setSendBufferSize(getTxBufSize()); socketChannel.socket().setReceiveBufferSize(getRxBufSize()); socketChannel.socket().setSoTimeout((int)getTimeout()); socketChannel.socket().setSoLinger(getSoLingerOn(),getSoLingerOn()?getSoLingerTime():0); socketChannel.socket().setTcpNoDelay(getTcpNoDelay()); socketChannel.socket().setKeepAlive(getSoKeepAlive()); socketChannel.socket().setReuseAddress(getSoReuseAddress()); socketChannel.socket().setOOBInline(getOoBInline()); socketChannel.socket().setSoLinger(getSoLingerOn(),getSoLingerTime()); socketChannel.socket().setTrafficClass(getSoTrafficClass()); } else if (dataChannel!=null) { dataChannel.configureBlocking(false); dataChannel.socket().setSendBufferSize(getUdpTxBufSize()); dataChannel.socket().setReceiveBufferSize(getUdpRxBufSize()); dataChannel.socket().setSoTimeout((int)getTimeout()); dataChannel.socket().setReuseAddress(getSoReuseAddress()); dataChannel.socket().setTrafficClass(getSoTrafficClass()); } } private void completeConnect() { //we connected, register ourselves for writing setConnected(true); connecting = false; setRequestCount(0); setConnectTime(System.currentTimeMillis()); } protected boolean read(SelectionKey key) throws IOException { //if there is no message here, we are done if ( current == null ) return true; int read = isUdpBased()?dataChannel.read(readbuf) : socketChannel.read(readbuf); //end of stream if ( read == -1 ) throw new IOException("Unable to receive an ack message. EOF on socket channel has been reached."); //no data read else if ( read == 0 ) return false; readbuf.flip(); ackbuf.append(readbuf,read); readbuf.clear(); if (ackbuf.doesPackageExist() ) { byte[] ackcmd = ackbuf.extractDataPackage(true).getBytes(); boolean ack = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.ACK_DATA); boolean fack = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA); if ( fack && getThrowOnFailedAck() ) throw new RemoteProcessException("Received a failed ack:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA"); return ack || fack; } else { return false; } } protected boolean write(SelectionKey key) throws IOException { if ( (!isConnected()) || (this.socketChannel==null && this.dataChannel==null)) { throw new IOException("NioSender is not connected, this should not occur."); } if ( current != null ) { if ( remaining > 0 ) { //we have written everything, or we are starting a new package //protect against buffer overwrite int byteswritten = isUdpBased()?dataChannel.write(writebuf) : socketChannel.write(writebuf); if (byteswritten == -1 ) throw new EOFException(); remaining -= byteswritten; //if the entire message was written from the buffer //reset the position counter if ( remaining < 0 ) { remaining = 0; } } return (remaining==0); } //no message to send, we can consider that complete return true; } /** * connect - blocking in this operation * * @throws IOException * TODO Implement this org.apache.catalina.tribes.transport.IDataSender method */ @Override public synchronized void connect() throws IOException { if ( connecting || isConnected()) return; connecting = true; if ( isConnected() ) throw new IOException("NioSender is already in connected state."); if ( readbuf == null ) { readbuf = getReadBuffer(); } else { readbuf.clear(); } if ( writebuf == null ) { writebuf = getWriteBuffer(); } else { writebuf.clear(); } if (isUdpBased()) { InetSocketAddress daddr = new InetSocketAddress(getAddress(),getUdpPort()); if ( dataChannel != null ) throw new IOException("Datagram channel has already been established. Connection might be in progress."); dataChannel = DatagramChannel.open(); configureSocket(); dataChannel.connect(daddr); completeConnect(); dataChannel.register(getSelector(),SelectionKey.OP_WRITE, this); } else { InetSocketAddress addr = new InetSocketAddress(getAddress(),getPort()); if ( socketChannel != null ) throw new IOException("Socket channel has already been established. Connection might be in progress."); socketChannel = SocketChannel.open(); configureSocket(); if ( socketChannel.connect(addr) ) { completeConnect(); socketChannel.register(getSelector(), SelectionKey.OP_WRITE, this); } else { socketChannel.register(getSelector(), SelectionKey.OP_CONNECT, this); } } } /** * disconnect * * TODO Implement this org.apache.catalina.tribes.transport.IDataSender method */ @Override public void disconnect() { try { connecting = false; setConnected(false); if ( socketChannel != null ) { try { try {socketChannel.socket().close();}catch ( Exception x){} //error free close, all the way //try {socket.shutdownOutput();}catch ( Exception x){} //try {socket.shutdownInput();}catch ( Exception x){} //try {socket.close();}catch ( Exception x){} try {socketChannel.close();}catch ( Exception x){} }finally { socketChannel = null; } } if ( dataChannel != null ) { try { try {dataChannel.socket().close();}catch ( Exception x){} //error free close, all the way //try {socket.shutdownOutput();}catch ( Exception x){} //try {socket.shutdownInput();}catch ( Exception x){} //try {socket.close();}catch ( Exception x){} try {dataChannel.close();}catch ( Exception x){} }finally { dataChannel = null; } } } catch ( Exception x ) { log.error("Unable to disconnect NioSender. msg="+x.getMessage()); if ( log.isDebugEnabled() ) log.debug("Unable to disconnect NioSender. msg="+x.getMessage(),x); } finally { } } public void reset() { if ( isConnected() && readbuf == null) { readbuf = getReadBuffer(); } if ( readbuf != null ) readbuf.clear(); if ( writebuf != null ) writebuf.clear(); current = null; ackbuf.clear(); remaining = 0; complete = false; setAttempt(0); setUdpBased(false); } private ByteBuffer getReadBuffer() { return getBuffer(getRxBufSize()); } private ByteBuffer getWriteBuffer() { return getBuffer(getTxBufSize()); } private ByteBuffer getBuffer(int size) { return (getDirectBuffer()?ByteBuffer.allocateDirect(size):ByteBuffer.allocate(size)); } /** * sendMessage * * @param data ChannelMessage * @throws IOException * TODO Implement this org.apache.catalina.tribes.transport.IDataSender method */ public synchronized void setMessage(byte[] data) throws IOException { setMessage(data,0,data.length); } public synchronized void setMessage(byte[] data,int offset, int length) throws IOException { if ( data != null ) { current = data; remaining = length; ackbuf.clear(); if ( writebuf != null ) writebuf.clear(); else writebuf = getBuffer(length); if ( writebuf.capacity() < length ) writebuf = getBuffer(length); //TODO use ByteBuffer.wrap to avoid copying the data. writebuf.put(data,offset,length); //writebuf.rewind(); //set the limit so that we don't write non wanted data //writebuf.limit(length); writebuf.flip(); if (isConnected()) { if (isUdpBased()) dataChannel.register(getSelector(), SelectionKey.OP_WRITE, this); else socketChannel.register(getSelector(), SelectionKey.OP_WRITE, this); } } } public byte[] getMessage() { return current; } public boolean isComplete() { return complete; } public Selector getSelector() { return selector; } public void setSelector(Selector selector) { this.selector = selector; } public void setComplete(boolean complete) { this.complete = complete; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java0000644000175100017510000000601712271464231030672 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.nio; import java.io.IOException; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.transport.AbstractSender; import org.apache.catalina.tribes.transport.DataSender; import org.apache.catalina.tribes.transport.PooledSender; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public class PooledParallelSender extends PooledSender { protected boolean connected = true; public PooledParallelSender() { super(); } @Override public void sendMessage(Member[] destination, ChannelMessage message) throws ChannelException { if ( !connected ) throw new ChannelException("Sender not connected."); ParallelNioSender sender = (ParallelNioSender)getSender(); if (sender == null) { ChannelException cx = new ChannelException("Unable to retrieve a data sender, time out("+getMaxWait()+" ms) error."); for (int i = 0; i < destination.length; i++) cx.addFaultyMember(destination[i], new NullPointerException("Unable to retrieve a sender from the sender pool")); throw cx; } else { try { sender.sendMessage(destination, message); sender.keepalive(); } catch (ChannelException x) { sender.disconnect(); throw x; } finally { returnSender(sender); if (!connected) disconnect(); } } } @Override public DataSender getNewDataSender() { try { ParallelNioSender sender = new ParallelNioSender(); AbstractSender.transferProperties(this,sender); return sender; } catch ( IOException x ) { throw new RuntimeException("Unable to open NIO selector.",x); } } @Override public synchronized void disconnect() { this.connected = false; super.disconnect(); } @Override public synchronized void connect() throws IOException { this.connected = true; super.connect(); } }tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java0000644000175100017510000004402412271464231027044 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.nio; import java.io.IOException; import java.net.ServerSocket; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedSelectorException; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import org.apache.catalina.tribes.io.ObjectReader; import org.apache.catalina.tribes.transport.AbstractRxTask; import org.apache.catalina.tribes.transport.Constants; import org.apache.catalina.tribes.transport.ReceiverBase; import org.apache.catalina.tribes.transport.RxTaskPool; import org.apache.catalina.tribes.util.StringManager; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * @author Filip Hanik */ public class NioReceiver extends ReceiverBase implements Runnable { private static final Log log = LogFactory.getLog(NioReceiver.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * The descriptive information about this implementation. */ private static final String info = "NioReceiver/1.0"; private volatile boolean running = false; private AtomicReference selector = new AtomicReference(); private ServerSocketChannel serverChannel = null; private DatagramChannel datagramChannel = null; protected LinkedList events = new LinkedList(); // private Object interestOpsMutex = new Object(); public NioReceiver() { } /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } // public Object getInterestOpsMutex() { // return interestOpsMutex; // } @Override public void stop() { this.stopListening(); super.stop(); } /** * start cluster receiver * @throws IOException * @see org.apache.catalina.tribes.ChannelReceiver#start() */ @Override public void start() throws IOException { super.start(); try { setPool(new RxTaskPool(getMaxThreads(),getMinThreads(),this)); } catch (Exception x) { log.fatal("ThreadPool can initilzed. Listener not started", x); if ( x instanceof IOException ) throw (IOException)x; else throw new IOException(x.getMessage()); } try { getBind(); bind(); Thread t = new Thread(this, "NioReceiver"); t.setDaemon(true); t.start(); } catch (Exception x) { log.fatal("Unable to start cluster receiver", x); if ( x instanceof IOException ) throw (IOException)x; else throw new IOException(x.getMessage()); } } @Override public AbstractRxTask createRxTask() { NioReplicationTask thread = new NioReplicationTask(this,this); thread.setUseBufferPool(this.getUseBufferPool()); thread.setRxBufSize(getRxBufSize()); thread.setOptions(getWorkerThreadOptions()); return thread; } protected void bind() throws IOException { // allocate an unbound server socket channel serverChannel = ServerSocketChannel.open(); // Get the associated ServerSocket to bind it with ServerSocket serverSocket = serverChannel.socket(); // create a new Selector for use below synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 this.selector.set(Selector.open()); } // set the port the server channel will listen to //serverSocket.bind(new InetSocketAddress(getBind(), getTcpListenPort())); bind(serverSocket,getPort(),getAutoBind()); // set non-blocking mode for the listening socket serverChannel.configureBlocking(false); // register the ServerSocketChannel with the Selector serverChannel.register(this.selector.get(), SelectionKey.OP_ACCEPT); //set up the datagram channel if (this.getUdpPort()>0) { datagramChannel = DatagramChannel.open(); configureDatagraChannel(); //bind to the address to avoid security checks bindUdp(datagramChannel.socket(),getUdpPort(),getAutoBind()); } } private void configureDatagraChannel() throws IOException { datagramChannel.configureBlocking(false); datagramChannel.socket().setSendBufferSize(getUdpTxBufSize()); datagramChannel.socket().setReceiveBufferSize(getUdpRxBufSize()); datagramChannel.socket().setReuseAddress(getSoReuseAddress()); datagramChannel.socket().setSoTimeout(getTimeout()); datagramChannel.socket().setTrafficClass(getSoTrafficClass()); } public void addEvent(Runnable event) { Selector selector = this.selector.get(); if ( selector != null ) { synchronized (events) { events.add(event); } if ( log.isTraceEnabled() ) log.trace("Adding event to selector:"+event); if ( isListening() ) selector.wakeup(); } } public void events() { if ( events.size() == 0 ) return; synchronized (events) { Runnable r = null; while ( (events.size() > 0) && (r = events.removeFirst()) != null ) { try { if ( log.isTraceEnabled() ) log.trace("Processing event in selector:"+r); r.run(); } catch ( Exception x ) { log.error("",x); } } events.clear(); } } public static void cancelledKey(SelectionKey key) { ObjectReader reader = (ObjectReader)key.attachment(); if ( reader != null ) { reader.setCancelled(true); reader.finish(); } key.cancel(); key.attach(null); if (key.channel() instanceof SocketChannel) try { ((SocketChannel)key.channel()).socket().close(); } catch (IOException e) { if (log.isDebugEnabled()) log.debug("", e); } if (key.channel() instanceof DatagramChannel) try { ((DatagramChannel)key.channel()).socket().close(); } catch (Exception e) { if (log.isDebugEnabled()) log.debug("", e); } try { key.channel().close(); } catch (IOException e) { if (log.isDebugEnabled()) log.debug("", e); } } protected long lastCheck = System.currentTimeMillis(); protected void socketTimeouts() { long now = System.currentTimeMillis(); if ( (now-lastCheck) < getSelectorTimeout() ) return; //timeout Selector tmpsel = this.selector.get(); Set keys = (isListening()&&tmpsel!=null)?tmpsel.keys():null; if ( keys == null ) return; for (Iterator iter = keys.iterator(); iter.hasNext();) { SelectionKey key = iter.next(); try { // if (key.interestOps() == SelectionKey.OP_READ) { // //only timeout sockets that we are waiting for a read from // ObjectReader ka = (ObjectReader) key.attachment(); // long delta = now - ka.getLastAccess(); // if (delta > (long) getTimeout()) { // cancelledKey(key); // } // } // else if ( key.interestOps() == 0 ) { //check for keys that didn't make it in. ObjectReader ka = (ObjectReader) key.attachment(); if ( ka != null ) { long delta = now - ka.getLastAccess(); if (delta > getTimeout() && (!ka.isAccessed())) { if (log.isWarnEnabled()) log.warn("Channel key is registered, but has had no interest ops for the last "+getTimeout()+" ms. (cancelled:"+ka.isCancelled()+"):"+key+" last access:"+new java.sql.Timestamp(ka.getLastAccess())+" Possible cause: all threads used, perform thread dump"); ka.setLastAccess(now); //key.interestOps(SelectionKey.OP_READ); }//end if } else { cancelledKey(key); }//end if }//end if }catch ( CancelledKeyException ckx ) { cancelledKey(key); } } lastCheck = System.currentTimeMillis(); } /** * get data from channel and store in byte array * send it to cluster * @throws IOException * @throws java.nio.channels.ClosedChannelException */ protected void listen() throws Exception { if (doListen()) { log.warn("ServerSocketChannel already started"); return; } setListen(true); // Avoid NPEs if selector is set to null on stop. Selector selector = this.selector.get(); if (selector!=null && datagramChannel!=null) { ObjectReader oreader = new ObjectReader(MAX_UDP_SIZE); //max size for a datagram packet registerChannel(selector,datagramChannel,SelectionKey.OP_READ,oreader); } while (doListen() && selector != null) { // this may block for a long time, upon return the // selected set contains keys of the ready channels try { events(); socketTimeouts(); int n = selector.select(getSelectorTimeout()); if (n == 0) { //there is a good chance that we got here //because the TcpReplicationThread called //selector wakeup(). //if that happens, we must ensure that that //thread has enough time to call interestOps // synchronized (interestOpsMutex) { //if we got the lock, means there are no //keys trying to register for the //interestOps method // } continue; // nothing to do } // get an iterator over the set of selected keys Iterator it = selector.selectedKeys().iterator(); // look at each key in the selected set while (it!=null && it.hasNext()) { SelectionKey key = it.next(); // Is a new connection coming in? if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel channel = server.accept(); channel.socket().setReceiveBufferSize(getTxBufSize()); channel.socket().setSendBufferSize(getTxBufSize()); channel.socket().setTcpNoDelay(getTcpNoDelay()); channel.socket().setKeepAlive(getSoKeepAlive()); channel.socket().setOOBInline(getOoBInline()); channel.socket().setReuseAddress(getSoReuseAddress()); channel.socket().setSoLinger(getSoLingerOn(),getSoLingerTime()); channel.socket().setSoTimeout(getTimeout()); Object attach = new ObjectReader(channel); registerChannel(selector, channel, SelectionKey.OP_READ, attach); } // is there data to read on this channel? if (key.isReadable()) { readDataFromSocket(key); } else { key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE)); } // remove key from selected set, it's been handled it.remove(); } } catch (java.nio.channels.ClosedSelectorException cse) { // ignore is normal at shutdown or stop listen socket } catch (java.nio.channels.CancelledKeyException nx) { log.warn("Replication client disconnected, error when polling key. Ignoring client."); } catch (Throwable t) { if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } log.error("Unable to process request in NioReceiver", t); } } serverChannel.close(); if (datagramChannel!=null) { try { datagramChannel.close(); }catch (Exception iox) { if (log.isDebugEnabled()) log.debug("Unable to close datagram channel.",iox); } datagramChannel=null; } closeSelector(); } /** * Close Selector. * * @see org.apache.catalina.tribes.transport.ReceiverBase#stop() */ protected void stopListening() { setListen(false); Selector selector = this.selector.get(); if (selector != null) { try { // Unlock the thread if is is blocked waiting for input selector.wakeup(); // Wait for the receiver thread to finish int count = 0; while (running && count < 50) { Thread.sleep(100); count ++; } if (running) { log.warn(sm.getString("NioReceiver.stop.threadRunning")); } closeSelector(); } catch (Exception x) { log.error("Unable to close cluster receiver selector.", x); } finally { this.selector.set(null); } } } private void closeSelector() throws IOException { Selector selector = this.selector.getAndSet(null); if (selector==null) return; try { Iterator it = selector.keys().iterator(); // look at each key in the selected set while (it.hasNext()) { SelectionKey key = it.next(); key.channel().close(); key.attach(null); key.cancel(); } }catch ( IOException ignore ){ if (log.isWarnEnabled()) { log.warn("Unable to cleanup on selector close.",ignore); } }catch ( ClosedSelectorException ignore){} selector.close(); } // ---------------------------------------------------------- /** * Register the given channel with the given selector for * the given operations of interest */ protected void registerChannel(Selector selector, SelectableChannel channel, int ops, Object attach) throws Exception { if (channel == null)return; // could happen // set the new channel non-blocking channel.configureBlocking(false); // register it with the selector channel.register(selector, ops, attach); } /** * Start thread and listen */ @Override public void run() { running = true; try { listen(); } catch (Exception x) { log.error("Unable to run replication listener.", x); } finally { running = false; } } // ---------------------------------------------------------- /** * Sample data handler method for a channel with data ready to read. * @param key A SelectionKey object associated with a channel * determined by the selector to be ready for reading. If the * channel returns an EOF condition, it is closed here, which * automatically invalidates the associated key. The selector * will then de-register the channel on the next select call. */ protected void readDataFromSocket(SelectionKey key) throws Exception { NioReplicationTask task = (NioReplicationTask) getTaskPool().getRxTask(); if (task == null) { // No threads/tasks available, do nothing, the selection // loop will keep calling this method until a // thread becomes available, the thread pool itself has a waiting mechanism // so we will not wait here. if (log.isDebugEnabled()) log.debug("No TcpReplicationThread available"); } else { // invoking this wakes up the worker thread then returns //add task to thread pool task.serviceChannel(key); getExecutor().execute(task); } } } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/nio/NioReplicationTask.java0000644000175100017510000003356512271464231030404 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport.nio; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.DatagramChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.nio.channels.WritableByteChannel; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.ChannelReceiver; import org.apache.catalina.tribes.RemoteProcessException; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.io.BufferPool; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.ListenCallback; import org.apache.catalina.tribes.io.ObjectReader; import org.apache.catalina.tribes.transport.AbstractRxTask; import org.apache.catalina.tribes.transport.Constants; import org.apache.catalina.tribes.util.Logs; /** * A worker thread class which can drain channels and echo-back the input. Each * instance is constructed with a reference to the owning thread pool object. * When started, the thread loops forever waiting to be awakened to service the * channel associated with a SelectionKey object. The worker is tasked by * calling its serviceChannel() method with a SelectionKey object. The * serviceChannel() method stores the key reference in the thread object then * calls notify() to wake it up. When the channel has been drained, the worker * thread returns itself to its parent pool. * * @author Filip Hanik */ public class NioReplicationTask extends AbstractRxTask { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( NioReplicationTask.class ); private ByteBuffer buffer = null; private SelectionKey key; private int rxBufSize; private NioReceiver receiver; public NioReplicationTask (ListenCallback callback, NioReceiver receiver) { super(callback); this.receiver = receiver; } // loop forever waiting for work to do @Override public synchronized void run() { if ( buffer == null ) { int size = getRxBufSize(); if (key.channel() instanceof DatagramChannel) { size = ChannelReceiver.MAX_UDP_SIZE; } if ( (getOptions() & OPTION_DIRECT_BUFFER) == OPTION_DIRECT_BUFFER) { buffer = ByteBuffer.allocateDirect(size); } else { buffer = ByteBuffer.allocate(size); } } else { buffer.clear(); } if (key == null) { return; // just in case } if ( log.isTraceEnabled() ) log.trace("Servicing key:"+key); try { ObjectReader reader = (ObjectReader)key.attachment(); if ( reader == null ) { if ( log.isTraceEnabled() ) log.trace("No object reader, cancelling:"+key); cancelKey(key); } else { if ( log.isTraceEnabled() ) log.trace("Draining channel:"+key); drainChannel(key, reader); } } catch (Exception e) { //this is common, since the sockets on the other //end expire after a certain time. if ( e instanceof CancelledKeyException ) { //do nothing } else if ( e instanceof IOException ) { //dont spew out stack traces for IO exceptions unless debug is enabled. if (log.isDebugEnabled()) log.debug ("IOException in replication worker, unable to drain channel. Probable cause: Keep alive socket closed["+e.getMessage()+"].", e); else log.warn ("IOException in replication worker, unable to drain channel. Probable cause: Keep alive socket closed["+e.getMessage()+"]."); } else if ( log.isErrorEnabled() ) { //this is a real error, log it. log.error("Exception caught in TcpReplicationThread.drainChannel.",e); } cancelKey(key); } finally { } key = null; // done, ready for more, return to pool getTaskPool().returnWorker (this); } /** * Called to initiate a unit of work by this worker thread * on the provided SelectionKey object. This method is * synchronized, as is the run() method, so only one key * can be serviced at a given time. * Before waking the worker thread, and before returning * to the main selection loop, this key's interest set is * updated to remove OP_READ. This will cause the selector * to ignore read-readiness for this channel while the * worker thread is servicing it. */ public synchronized void serviceChannel (SelectionKey key) { if ( log.isTraceEnabled() ) log.trace("About to service key:"+key); ObjectReader reader = (ObjectReader)key.attachment(); if ( reader != null ) reader.setLastAccess(System.currentTimeMillis()); this.key = key; key.interestOps (key.interestOps() & (~SelectionKey.OP_READ)); key.interestOps (key.interestOps() & (~SelectionKey.OP_WRITE)); } /** * The actual code which drains the channel associated with * the given key. This method assumes the key has been * modified prior to invocation to turn off selection * interest in OP_READ. When this method completes it * re-enables OP_READ and calls wakeup() on the selector * so the selector will resume watching this channel. */ protected void drainChannel (final SelectionKey key, ObjectReader reader) throws Exception { reader.setLastAccess(System.currentTimeMillis()); reader.access(); ReadableByteChannel channel = (ReadableByteChannel) key.channel(); int count=-1; buffer.clear(); // make buffer empty SocketAddress saddr = null; if (channel instanceof SocketChannel) { // loop while data available, channel is non-blocking while ((count = channel.read (buffer)) > 0) { buffer.flip(); // make buffer readable if ( buffer.hasArray() ) reader.append(buffer.array(),0,count,false); else reader.append(buffer,count,false); buffer.clear(); // make buffer empty //do we have at least one package? if ( reader.hasPackage() ) break; } } else if (channel instanceof DatagramChannel) { DatagramChannel dchannel = (DatagramChannel)channel; saddr = dchannel.receive(buffer); buffer.flip(); // make buffer readable if ( buffer.hasArray() ) reader.append(buffer.array(),0,buffer.limit()-buffer.position(),false); else reader.append(buffer,buffer.limit()-buffer.position(),false); buffer.clear(); // make buffer empty //did we get a package count = reader.hasPackage()?1:-1; } int pkgcnt = reader.count(); if (count < 0 && pkgcnt == 0 ) { //end of stream, and no more packages to process remoteEof(key); return; } ChannelMessage[] msgs = pkgcnt == 0? ChannelData.EMPTY_DATA_ARRAY : reader.execute(); registerForRead(key,reader);//register to read new data, before we send it off to avoid dead locks for ( int i=0; iTitle:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public class ParallelNioSender extends AbstractSender implements MultiPointSender { private static final Log log = LogFactory.getLog(ParallelNioSender.class); protected long selectTimeout = 5000; //default 5 seconds, same as send timeout protected Selector selector; protected HashMap nioSenders = new HashMap(); public ParallelNioSender() throws IOException { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 selector = Selector.open(); } setConnected(true); } @Override public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException { long start = System.currentTimeMillis(); this.setUdpBased((msg.getOptions()&Channel.SEND_OPTIONS_UDP) == Channel.SEND_OPTIONS_UDP); byte[] data = XByteBuffer.createDataPackage((ChannelData)msg); NioSender[] senders = setupForSend(destination); connect(senders); setData(senders,data); int remaining = senders.length; ChannelException cx = null; try { //loop until complete, an error happens, or we timeout long delta = System.currentTimeMillis() - start; boolean waitForAck = (Channel.SEND_OPTIONS_USE_ACK & msg.getOptions()) == Channel.SEND_OPTIONS_USE_ACK; while ( (remaining>0) && (delta 0 ) { //timeout has occurred ChannelException cxtimeout = new ChannelException("Operation has timed out("+getTimeout()+" ms.)."); if ( cx==null ) cx = new ChannelException("Operation has timed out("+getTimeout()+" ms.)."); for (int i=0; i it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey sk = it.next(); it.remove(); int readyOps = sk.readyOps(); sk.interestOps(sk.interestOps() & ~readyOps); NioSender sender = (NioSender) sk.attachment(); try { if (sender.process(sk,waitForAck)) { completed++; sender.setComplete(true); if ( Logs.MESSAGES.isTraceEnabled() ) { Logs.MESSAGES.trace("ParallelNioSender - Sent msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " to "+sender.getDestination().getName()); } SenderState.getSenderState(sender.getDestination()).setReady(); }//end if } catch (Exception x) { if (log.isTraceEnabled()) { log.trace("Error while processing send to " + sender.getDestination().getName(), x); } SenderState state = SenderState.getSenderState(sender.getDestination()); int attempt = sender.getAttempt()+1; boolean retry = (sender.getAttempt() <= maxAttempts && maxAttempts>0); synchronized (state) { //sk.cancel(); if (state.isSuspect()) state.setFailing(); if (state.isReady()) { state.setSuspect(); if ( retry ) log.warn("Member send is failing for:" + sender.getDestination().getName() +" ; Setting to suspect and retrying."); else log.warn("Member send is failing for:" + sender.getDestination().getName() +" ; Setting to suspect.", x); } } if ( !isConnected() ) { log.warn("Not retrying send for:" + sender.getDestination().getName() + "; Sender is disconnected."); ChannelException cx = new ChannelException("Send failed, and sender is disconnected. Not retrying.",x); cx.addFaultyMember(sender.getDestination(),x); throw cx; } byte[] data = sender.getMessage(); if ( retry ) { try { sender.disconnect(); sender.connect(); sender.setAttempt(attempt); sender.setMessage(data); }catch ( Exception ignore){ state.setFailing(); } } else { ChannelException cx = new ChannelException("Send failed, attempt:"+sender.getAttempt()+" max:"+maxAttempts,x); cx.addFaultyMember(sender.getDestination(),x); throw cx; }//end if } } return completed; } private void connect(NioSender[] senders) throws ChannelException { ChannelException x = null; for (int i=0; i> i = nioSenders.entrySet().iterator(); i.hasNext();) { Map.Entry entry = i.next(); NioSender sender = entry.getValue(); if ( sender.keepalive() ) { //nioSenders.remove(entry.getKey()); i.remove(); result = true; } else { try { sender.read(null); }catch ( IOException x ) { sender.disconnect(); sender.reset(); //nioSenders.remove(entry.getKey()); i.remove(); result = true; }catch ( Exception x ) { log.warn("Error during keepalive test for sender:"+sender,x); } } } //clean up any cancelled keys if ( result ) try { selector.selectNow(); }catch (Exception e){/*Ignore*/} return result; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/SenderState.java0000644000175100017510000000554212271464231026270 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import java.util.HashMap; import org.apache.catalina.tribes.Member; /** * * @author Filip Hanik * @version 1.0 * @since 5.5.16 */ public class SenderState { public static final int READY = 0; public static final int SUSPECT = 1; public static final int FAILING = 2; protected static HashMap memberStates = new HashMap(); public static SenderState getSenderState(Member member) { return getSenderState(member,true); } public static SenderState getSenderState(Member member, boolean create) { SenderState state = memberStates.get(member); if ( state == null && create) { synchronized ( memberStates ) { state = memberStates.get(member); if ( state == null ) { state = new SenderState(); memberStates.put(member,state); } } } return state; } public static void removeSenderState(Member member) { synchronized ( memberStates ) { memberStates.remove(member); } } // ----------------------------------------------------- Instance Variables private int state = READY; // ----------------------------------------------------- Constructor private SenderState() { this(READY); } private SenderState(int state) { this.state = state; } /** * * @return boolean */ public boolean isSuspect() { return (state == SUSPECT) || (state == FAILING); } public void setSuspect() { state = SUSPECT; } public boolean isReady() { return state == READY; } public void setReady() { state = READY; } public boolean isFailing() { return state == FAILING; } public void setFailing() { state = FAILING; } // ----------------------------------------------------- Public Properties } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/Constants.java0000644000175100017510000000300612271464231026014 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.transport; import org.apache.catalina.tribes.io.XByteBuffer; /** * Manifest constants for the org.apache.catalina.tribes.transport * package. * @author Filip Hanik * @author Peter Rossbach */ public class Constants { public static final String Package = "org.apache.catalina.tribes.transport"; /* * Do not change any of these values! */ public static final byte[] ACK_DATA = new byte[] {6, 2, 3}; public static final byte[] FAIL_ACK_DATA = new byte[] {11, 0, 5}; public static final byte[] ACK_COMMAND = XByteBuffer.createDataPackage(ACK_DATA); public static final byte[] FAIL_ACK_COMMAND = XByteBuffer.createDataPackage(FAIL_ACK_DATA); } tomcat7-7.0.52/java/org/apache/catalina/tribes/transport/LocalStrings.properties0000644000175100017510000000625012271464231027723 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. IDataSender.ack.eof=EOF reached at local port [{0}:{1,number,integer}] IDataSender.ack.receive=Got ACK at local port [{0}:{1,number,integer}] IDataSender.ack.missing=Unable to read acknowledgement from [{0}:{1,number,integer}] in {2,number,integer} ms. Disconnecting socket, and trying again. IDataSender.ack.read=Read wait ack char '{2}' [{0}:{1,number,integer}] IDataSender.ack.start=Waiting for ACK message [{0}:{1,number,integer}] IDataSender.ack.wrong=Missing correct ACK after 10 bytes read at local port [{0}:{1,number,integer}] IDataSender.closeSocket=Sender close socket to [{0}:{1,number,integer}] (close count {2,number,integer}) IDataSender.connect=Sender connect to [{0}:{1,number,integer}] (connect count {2,number,integer}) IDataSender.create=Create sender [{0}:{1,number,integer}] IDataSender.disconnect=Sender disconnect from [{0}:{1,number,integer}] (disconnect count {2,number,integer}) IDataSender.message.disconnect=Message transfered: Sender can't disconnect from [{0}:{1,number,integer}] IDataSender.message.create=Message transfered: Sender can't create current socket [{0}:{1,number,integer}] IDataSender.openSocket=Sender open socket to [{0}:{1,number,integer}] (open count {2,number,integer}) IDataSender.openSocket.failure=Open sender socket [{0}:{1,number,integer}] failure! (open failure count {2,number,integer}) IDataSender.send.again=Send data again to [{0}:{1,number,integer}] IDataSender.send.crash=Send message crashed [{0}:{1,number,integer}] type=[{2}], id=[{3}] IDataSender.send.message=Send message to [{0}:{1,number,integer}] id=[{2}] size={3,number,integer} IDataSender.send.lost=Message lost: [{0}:{1,number,integer}] type=[{2}], id=[{3}] IDataSender.senderModes.Configured=Configured a data replication sender for mode {0} IDataSender.senderModes.Instantiate=Can't instantiate a data replication sender of class {0} IDataSender.senderModes.Missing=Can't configure a data replication sender for mode {0} IDataSender.senderModes.Resources=Can't load data replication sender mapping list IDataSender.stats=Send stats from [{0}:{1,number,integer}], Nr of bytes sent={2,number,integer} over {3} = {4,number,integer} bytes/request, processing time {5,number,integer} msec, avg processing time {6,number,integer} msec NioReceiver.stop.threadRunning=The NioReceiver thread did not stop in a timely manner. Errors may be observed when the selector is closed. PooledSender.senderDisconnectFail=Failed to disconnect sender tomcat7-7.0.52/java/org/apache/catalina/tribes/group/0000755000175100017510000000000012301126370022267 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/group/AbsoluteOrder.java0000644000175100017510000000770212271464231025721 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group; import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; import java.util.List; import org.apache.catalina.tribes.Member; /** *

    Title: Membership - Absolute Order

    * *

    Description: A simple, yet agreeable and efficient way of ordering members

    *

    * Ordering members can serve as a basis for electing a leader or coordinating efforts.
    * This is stinky simple, it works on the basis of the Member interface * and orders members in the following format: * *

      *
    1. IP comparison - byte by byte, lower byte higher rank
    2. *
    3. IPv4 addresses rank higher than IPv6, ie the lesser number of bytes, the higher rank
    4. *
    5. Port comparison - lower port, higher rank
    6. *
    7. UniqueId comparison- byte by byte, lower byte higher rank
    8. *
    * *

    * * @author Filip Hanik * @version 1.0 * @see org.apache.catalina.tribes.Member */ public class AbsoluteOrder { public static final AbsoluteComparator comp = new AbsoluteComparator(); protected AbsoluteOrder() { super(); } public static void absoluteOrder(Member[] members) { if ( members == null || members.length <= 1 ) return; Arrays.sort(members,comp); } public static void absoluteOrder(List members) { if ( members == null || members.size() <= 1 ) return; java.util.Collections.sort(members, comp); } public static class AbsoluteComparator implements Comparator, Serializable { private static final long serialVersionUID = 1L; @Override public int compare(Member m1, Member m2) { int result = compareIps(m1,m2); if ( result == 0 ) result = comparePorts(m1,m2); if ( result == 0 ) result = compareIds(m1,m2); return result; } public int compareIps(Member m1, Member m2) { return compareBytes(m1.getHost(),m2.getHost()); } public int comparePorts(Member m1, Member m2) { return compareInts(m1.getPort(),m2.getPort()); } public int compareIds(Member m1, Member m2) { return compareBytes(m1.getUniqueId(),m2.getUniqueId()); } protected int compareBytes(byte[] d1, byte[] d2) { int result = 0; if ( d1.length == d2.length ) { for (int i=0; (result==0) && (iTitle: A perfect failure detector

    * *

    Description: The TcpFailureDetector is a useful interceptor * that adds reliability to the membership layer.

    *

    * If the network is busy, or the system is busy so that the membership receiver thread * is not getting enough time to update its table, members can be "timed out" * This failure detector will intercept the memberDisappeared message(unless its a true shutdown message) * and connect to the member using TCP. *

    *

    * The TcpFailureDetector works in two ways.
    * 1. It intercepts memberDisappeared events * 2. It catches send errors *

    * * @author Filip Hanik * @version 1.0 */ public class TcpFailureDetector extends ChannelInterceptorBase { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( TcpFailureDetector.class ); protected static byte[] TCP_FAIL_DETECT = new byte[] { 79, -89, 115, 72, 121, -126, 67, -55, -97, 111, -119, -128, -95, 91, 7, 20, 125, -39, 82, 91, -21, -15, 67, -102, -73, 126, -66, -113, -127, 103, 30, -74, 55, 21, -66, -121, 69, 126, 76, -88, -65, 10, 77, 19, 83, 56, 21, 50, 85, -10, -108, -73, 58, -6, 64, 120, -111, 4, 125, -41, 114, -124, -64, -43}; @Deprecated protected boolean performConnectTest = true;//Unused - will be removed in Tomcat 8.0.x protected long connectTimeout = 1000;//1 second default protected boolean performSendTest = true; protected boolean performReadTest = false; protected long readTestTimeout = 5000;//5 seconds protected Membership membership = null; protected HashMap removeSuspects = new HashMap(); protected HashMap addSuspects = new HashMap(); protected int removeSuspectsTimeout = 300; // 5 minutes @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { try { super.sendMessage(destination, msg, payload); }catch ( ChannelException cx ) { FaultyMember[] mbrs = cx.getFaultyMembers(); for ( int i=0; i 0) { long timeNow = System.currentTimeMillis(); int timeIdle = (int) ((timeNow - removeSuspects.get(m).longValue()) / 1000L); if (timeIdle > removeSuspectsTimeout) { removeSuspects.remove(m); // remove suspect member } } } } //check add suspects members if they are alive now, //if they are, simply issue the memberAdded message keys = addSuspects.keySet().toArray(new MemberImpl[addSuspects.size()]); for (int i = 0; i < keys.length; i++) { MemberImpl m = keys[i]; if ( membership.getMember(m) == null && (memberAlive(m))) { membership.memberAlive(m); super.memberAdded(m); addSuspects.remove(m); if(log.isInfoEnabled()) log.info("Suspect member, confirmed alive.["+m+"]"); } //end if } } protected synchronized void setupMembership() { if ( membership == null ) { membership = new Membership((MemberImpl)super.getLocalMember(true)); } } protected boolean memberAlive(Member mbr) { return memberAlive(mbr,TCP_FAIL_DETECT,performSendTest,performReadTest,readTestTimeout,connectTimeout,getOptionFlag()); } protected static boolean memberAlive(Member mbr, byte[] msgData, boolean sendTest, boolean readTest, long readTimeout, long conTimeout, int optionFlag) { //could be a shutdown notification if ( Arrays.equals(mbr.getCommand(),Member.SHUTDOWN_PAYLOAD) ) return false; Socket socket = new Socket(); try { InetAddress ia = InetAddress.getByAddress(mbr.getHost()); InetSocketAddress addr = new InetSocketAddress(ia, mbr.getPort()); socket.setSoTimeout((int)readTimeout); socket.connect(addr, (int) conTimeout); if ( sendTest ) { ChannelData data = new ChannelData(true); data.setAddress(mbr); data.setMessage(new XByteBuffer(msgData,false)); data.setTimestamp(System.currentTimeMillis()); int options = optionFlag | Channel.SEND_OPTIONS_BYTE_MESSAGE; if ( readTest ) options = (options | Channel.SEND_OPTIONS_USE_ACK); else options = (options & (~Channel.SEND_OPTIONS_USE_ACK)); data.setOptions(options); byte[] message = XByteBuffer.createDataPackage(data); socket.getOutputStream().write(message); if ( readTest ) { int length = socket.getInputStream().read(message); return length > 0; } }//end if return true; } catch ( SocketTimeoutException sx) { //do nothing, we couldn't connect } catch ( ConnectException cx) { //do nothing, we couldn't connect }catch (Exception x ) { log.error("Unable to perform failure detection check, assuming member down.",x); } finally { try {socket.close(); } catch ( Exception ignore ){} } return false; } @Deprecated public boolean getPerformConnectTest() { return performConnectTest; } public long getReadTestTimeout() { return readTestTimeout; } public boolean getPerformSendTest() { return performSendTest; } public boolean getPerformReadTest() { return performReadTest; } public long getConnectTimeout() { return connectTimeout; } public int getRemoveSuspectsTimeout() { return removeSuspectsTimeout; } @Deprecated public void setPerformConnectTest(boolean performConnectTest) { this.performConnectTest = performConnectTest; } public void setPerformReadTest(boolean performReadTest) { this.performReadTest = performReadTest; } public void setPerformSendTest(boolean performSendTest) { this.performSendTest = performSendTest; } public void setReadTestTimeout(long readTestTimeout) { this.readTestTimeout = readTestTimeout; } public void setConnectTimeout(long connectTimeout) { this.connectTimeout = connectTimeout; } public void setRemoveSuspectsTimeout(int removeSuspectsTimeout) { this.removeSuspectsTimeout = removeSuspectsTimeout; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/MessageDispatch15Interceptor.java0000644000175100017510000000717212271464231033322 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.InterceptorPayload; import org.apache.catalina.tribes.transport.bio.util.LinkObject; import org.apache.catalina.tribes.util.ExecutorFactory; import org.apache.catalina.tribes.util.TcclThreadFactory; /** * * Same implementation as the MessageDispatchInterceptor * except it uses an atomic long for the currentSize calculation * and uses a thread pool for message sending. * * @author Filip Hanik * @version 1.0 */ public class MessageDispatch15Interceptor extends MessageDispatchInterceptor { protected AtomicLong currentSize = new AtomicLong(0); protected ExecutorService executor = null; protected int maxThreads = 10; protected int maxSpareThreads = 2; protected long keepAliveTime = 5000; @Override public long getCurrentSize() { return currentSize.get(); } @Override public long addAndGetCurrentSize(long inc) { return currentSize.addAndGet(inc); } @Override public long setAndGetCurrentSize(long value) { currentSize.set(value); return value; } @Override public boolean addToQueue(ChannelMessage msg, Member[] destination, InterceptorPayload payload) { final LinkObject obj = new LinkObject(msg,destination,payload); Runnable r = new Runnable() { @Override public void run() { sendAsyncData(obj); } }; executor.execute(r); return true; } @Override public LinkObject removeFromQueue() { return null; //not used, thread pool contains its own queue. } @Override public void startQueue() { if ( run ) return; executor = ExecutorFactory.newThreadPool(maxSpareThreads, maxThreads, keepAliveTime, TimeUnit.MILLISECONDS, new TcclThreadFactory("MessageDispatch15Interceptor.MessageDispatchThread")); run = true; } @Override public void stopQueue() { run = false; executor.shutdownNow(); setAndGetCurrentSize(0); } public long getKeepAliveTime() { return keepAliveTime; } public int getMaxSpareThreads() { return maxSpareThreads; } public int getMaxThreads() { return maxThreads; } public void setKeepAliveTime(long keepAliveTime) { this.keepAliveTime = keepAliveTime; } public void setMaxSpareThreads(int maxSpareThreads) { this.maxSpareThreads = maxSpareThreads; } public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/FragmentationInterceptor.java0000644000175100017510000002121012271464231032673 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.Arrays; import java.util.HashMap; import java.util.Set; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.group.InterceptorPayload; import org.apache.catalina.tribes.io.XByteBuffer; /** * * The fragmentation interceptor splits up large messages into smaller messages and assembles them on the other end. * This is very useful when you don't want large messages hogging the sending sockets * and smaller messages can make it through. * *
    Configuration Options
    * OrderInteceptor.expire= - how long do we keep the fragments in memory and wait for the rest to arrivedefault=60,000ms -> 60seconds * This setting is useful to avoid OutOfMemoryErrors
    * OrderInteceptor.maxSize= - message size in bytes default=1024*100 (around a tenth of a MB)
    * @author Filip Hanik * @version 1.0 */ public class FragmentationInterceptor extends ChannelInterceptorBase { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( FragmentationInterceptor.class ); protected HashMap fragpieces = new HashMap(); private int maxSize = 1024*100; private long expire = 1000 * 60; //one minute expiration protected boolean deepclone = true; @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { int size = msg.getMessage().getLength(); boolean frag = (size>maxSize) && okToProcess(msg.getOptions()); if ( frag ) { frag(destination, msg, payload); } else { msg.getMessage().append(frag); super.sendMessage(destination, msg, payload); } } @Override public void messageReceived(ChannelMessage msg) { boolean isFrag = XByteBuffer.toBoolean(msg.getMessage().getBytesDirect(),msg.getMessage().getLength()-1); msg.getMessage().trim(1); if ( isFrag ) { defrag(msg); } else { super.messageReceived(msg); } } public FragCollection getFragCollection(FragKey key, ChannelMessage msg) { FragCollection coll = fragpieces.get(key); if ( coll == null ) { synchronized (fragpieces) { coll = fragpieces.get(key); if ( coll == null ) { coll = new FragCollection(msg); fragpieces.put(key, coll); } } } return coll; } public void removeFragCollection(FragKey key) { fragpieces.remove(key); } public void defrag(ChannelMessage msg ) { FragKey key = new FragKey(msg.getUniqueId()); FragCollection coll = getFragCollection(key,msg); coll.addMessage((ChannelMessage)msg.deepclone()); if ( coll.complete() ) { removeFragCollection(key); ChannelMessage complete = coll.assemble(); super.messageReceived(complete); } } public void frag(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { int size = msg.getMessage().getLength(); int count = ((size / maxSize )+(size%maxSize==0?0:1)); ChannelMessage[] messages = new ChannelMessage[count]; int remaining = size; for ( int i=0; i set = fragpieces.keySet(); Object[] keys = set.toArray(); for ( int i=0; iexpire; } } public static class FragKey { private byte[] uniqueId; private long received = System.currentTimeMillis(); public FragKey(byte[] id ) { this.uniqueId = id; } @Override public int hashCode() { return XByteBuffer.toInt(uniqueId,0); } @Override public boolean equals(Object o ) { if ( o instanceof FragKey ) { return Arrays.equals(uniqueId,((FragKey)o).uniqueId); } else return false; } public boolean expired(long expire) { return (System.currentTimeMillis()-received)>expire; } } }tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java0000644000175100017510000001223412271464231032254 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.text.DecimalFormat; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.group.InterceptorPayload; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * * * @author Filip Hanik * @version 1.0 */ public class ThroughputInterceptor extends ChannelInterceptorBase { private static final Log log = LogFactory.getLog(ThroughputInterceptor.class); double mbTx = 0; double mbAppTx = 0; double mbRx = 0; double timeTx = 0; double lastCnt = 0; AtomicLong msgTxCnt = new AtomicLong(1); AtomicLong msgRxCnt = new AtomicLong(0); AtomicLong msgTxErr = new AtomicLong(0); int interval = 10000; AtomicInteger access = new AtomicInteger(0); long txStart = 0; long rxStart = 0; DecimalFormat df = new DecimalFormat("#0.00"); @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { if ( access.addAndGet(1) == 1 ) txStart = System.currentTimeMillis(); long bytes = XByteBuffer.getDataPackageLength(((ChannelData)msg).getDataPackageLength()); try { super.sendMessage(destination, msg, payload); }catch ( ChannelException x ) { msgTxErr.addAndGet(1); if ( access.get() == 1 ) access.addAndGet(-1); throw x; } mbTx += (bytes*destination.length)/(1024d*1024d); mbAppTx += bytes/(1024d*1024d); if ( access.addAndGet(-1) == 0 ) { long stop = System.currentTimeMillis(); timeTx += (stop - txStart) / 1000d; if ((msgTxCnt.get() / interval) >= lastCnt) { lastCnt++; report(timeTx); } } msgTxCnt.addAndGet(1); } @Override public void messageReceived(ChannelMessage msg) { if ( rxStart == 0 ) rxStart = System.currentTimeMillis(); long bytes = XByteBuffer.getDataPackageLength(((ChannelData)msg).getDataPackageLength()); mbRx += bytes/(1024d*1024d); msgRxCnt.addAndGet(1); if ( msgRxCnt.get() % interval == 0 ) report(timeTx); super.messageReceived(msg); } public void report(double timeTx) { StringBuilder buf = new StringBuilder("ThroughputInterceptor Report[\n\tTx Msg:"); buf.append(msgTxCnt).append(" messages\n\tSent:"); buf.append(df.format(mbTx)); buf.append(" MB (total)\n\tSent:"); buf.append(df.format(mbAppTx)); buf.append(" MB (application)\n\tTime:"); buf.append(df.format(timeTx)); buf.append(" seconds\n\tTx Speed:"); buf.append(df.format(mbTx/timeTx)); buf.append(" MB/sec (total)\n\tTxSpeed:"); buf.append(df.format(mbAppTx/timeTx)); buf.append(" MB/sec (application)\n\tError Msg:"); buf.append(msgTxErr).append("\n\tRx Msg:"); buf.append(msgRxCnt); buf.append(" messages\n\tRx Speed:"); buf.append(df.format(mbRx/((System.currentTimeMillis()-rxStart)/1000))); buf.append(" MB/sec (since 1st msg)\n\tReceived:"); buf.append(df.format(mbRx)).append(" MB]\n"); if ( log.isInfoEnabled() ) log.info(buf); } public void setInterval(int interval) { this.interval = interval; } public int getInterval() { return interval; } public double getLastCnt() { return lastCnt; } public double getMbAppTx() { return mbAppTx; } public double getMbRx() { return mbRx; } public double getMbTx() { return mbTx; } public AtomicLong getMsgRxCnt() { return msgRxCnt; } public AtomicLong getMsgTxCnt() { return msgTxCnt; } public AtomicLong getMsgTxErr() { return msgTxErr; } public long getRxStart() { return rxStart; } public double getTimeTx() { return timeTx; } public long getTxStart() { return txStart; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java0000644000175100017510000010666512271464231032307 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelInterceptor; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.group.AbsoluteOrder; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.group.InterceptorPayload; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.membership.MemberImpl; import org.apache.catalina.tribes.membership.Membership; import org.apache.catalina.tribes.util.Arrays; import org.apache.catalina.tribes.util.UUIDGenerator; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    Title: Auto merging leader election algorithm

    * *

    Description: Implementation of a simple coordinator algorithm that not only selects a coordinator, * it also merges groups automatically when members are discovered that werent part of the *

    *

    This algorithm is non blocking meaning it allows for transactions while the coordination phase is going on *

    *

    This implementation is based on a home brewed algorithm that uses the AbsoluteOrder of a membership * to pass a token ring of the current membership.
    * This is not the same as just using AbsoluteOrder! Consider the following scenario:
    * Nodes, A,B,C,D,E on a network, in that priority. AbsoluteOrder will only work if all * nodes are receiving pings from all the other nodes. * meaning, that node{i} receives pings from node{all}-node{i}
    * but the following could happen if a multicast problem occurs. * A has members {B,C,D}
    * B has members {A,C}
    * C has members {D,E}
    * D has members {A,B,C,E}
    * E has members {A,C,D}
    * Because the default Tribes membership implementation, relies on the multicast packets to * arrive at all nodes correctly, there is nothing guaranteeing that it will.
    *
    * To best explain how this algorithm works, lets take the above example: * For simplicity we assume that a send operation is O(1) for all nodes, although this algorithm will work * where messages overlap, as they all depend on absolute order
    * Scenario 1: A,B,C,D,E all come online at the same time * Eval phase, A thinks of itself as leader, B thinks of A as leader, * C thinks of itself as leader, D,E think of A as leader
    * Token phase:
    * (1) A sends out a message X{A-ldr, A-src, mbrs-A,B,C,D} to B where X is the id for the message(and the view)
    * (1) C sends out a message Y{C-ldr, C-src, mbrs-C,D,E} to D where Y is the id for the message(and the view)
    * (2) B receives X{A-ldr, A-src, mbrs-A,B,C,D}, sends X{A-ldr, A-src, mbrs-A,B,C,D} to C
    * (2) D receives Y{C-ldr, C-src, mbrs-C,D,E} D is aware of A,B, sends Y{A-ldr, C-src, mbrs-A,B,C,D,E} to E
    * (3) C receives X{A-ldr, A-src, mbrs-A,B,C,D}, sends X{A-ldr, A-src, mbrs-A,B,C,D,E} to D
    * (3) E receives Y{A-ldr, C-src, mbrs-A,B,C,D,E} sends Y{A-ldr, C-src, mbrs-A,B,C,D,E} to A
    * (4) D receives X{A-ldr, A-src, mbrs-A,B,C,D,E} sends sends X{A-ldr, A-src, mbrs-A,B,C,D,E} to A
    * (4) A receives Y{A-ldr, C-src, mbrs-A,B,C,D,E}, holds the message, add E to its list of members
    * (5) A receives X{A-ldr, A-src, mbrs-A,B,C,D,E}
    * At this point, the state looks like
    * A - {A-ldr, mbrs-A,B,C,D,E, id=X}
    * B - {A-ldr, mbrs-A,B,C,D, id=X}
    * C - {A-ldr, mbrs-A,B,C,D,E, id=X}
    * D - {A-ldr, mbrs-A,B,C,D,E, id=X}
    * E - {A-ldr, mbrs-A,B,C,D,E, id=Y}
    *
    * A message doesn't stop until it reaches its original sender, unless its dropped by a higher leader. * As you can see, E still thinks the viewId=Y, which is not correct. But at this point we have * arrived at the same membership and all nodes are informed of each other.
    * To synchronize the rest we simply perform the following check at A when A receives X:
    * Original X{A-ldr, A-src, mbrs-A,B,C,D} == Arrived X{A-ldr, A-src, mbrs-A,B,C,D,E}
    * Since the condition is false, A, will resend the token, and A sends X{A-ldr, A-src, mbrs-A,B,C,D,E} to B * When A receives X again, the token is complete.
    * Optionally, A can send a message X{A-ldr, A-src, mbrs-A,B,C,D,E confirmed} to A,B,C,D,E who then * install and accept the view. *

    *

    * Lets assume that C1 arrives, C1 has lower priority than C, but higher priority than D.
    * Lets also assume that C1 sees the following view {B,D,E}
    * C1 waits for a token to arrive. When the token arrives, the same scenario as above will happen.
    * In the scenario where C1 sees {D,E} and A,B,C can not see C1, no token will ever arrive.
    * In this case, C1 sends a Z{C1-ldr, C1-src, mbrs-C1,D,E} to D
    * D receives Z{C1-ldr, C1-src, mbrs-C1,D,E} and sends Z{A-ldr, C1-src, mbrs-A,B,C,C1,D,E} to E
    * E receives Z{A-ldr, C1-src, mbrs-A,B,C,C1,D,E} and sends it to A
    * A sends Z{A-ldr, A-src, mbrs-A,B,C,C1,D,E} to B and the chain continues until A receives the token again. * At that time A optionally sends out Z{A-ldr, A-src, mbrs-A,B,C,C1,D,E, confirmed} to A,B,C,C1,D,E *

    *

    To ensure that the view gets implemented at all nodes at the same time, * A will send out a VIEW_CONF message, this is the 'confirmed' message that is optional above. *

    Ideally, the interceptor below this one would be the TcpFailureDetector to ensure correct memberships

    * *

    The example above, of course can be simplified with a finite statemachine:
    * But I suck at writing state machines, my head gets all confused. One day I will document this algorithm though.
    * Maybe I'll do a state diagram :) *

    *

    State Diagrams

    * Initiate an election

    * Receive an election message

    * * @author Filip Hanik * @version 1.0 * * * */ public class NonBlockingCoordinator extends ChannelInterceptorBase { private static final Log log = LogFactory.getLog(NonBlockingCoordinator.class); /** * header for a coordination message */ protected static final byte[] COORD_HEADER = new byte[] {-86, 38, -34, -29, -98, 90, 65, 63, -81, -122, -6, -110, 99, -54, 13, 63}; /** * Coordination request */ protected static final byte[] COORD_REQUEST = new byte[] {104, -95, -92, -42, 114, -36, 71, -19, -79, 20, 122, 101, -1, -48, -49, 30}; /** * Coordination confirmation, for blocking installations */ protected static final byte[] COORD_CONF = new byte[] {67, 88, 107, -86, 69, 23, 76, -70, -91, -23, -87, -25, -125, 86, 75, 20}; /** * Alive message */ protected static final byte[] COORD_ALIVE = new byte[] {79, -121, -25, -15, -59, 5, 64, 94, -77, 113, -119, -88, 52, 114, -56, -46, -18, 102, 10, 34, -127, -9, 71, 115, -70, 72, -101, 88, 72, -124, 127, 111, 74, 76, -116, 50, 111, 103, 65, 3, -77, 51, -35, 0, 119, 117, 9, -26, 119, 50, -75, -105, -102, 36, 79, 37, -68, -84, -123, 15, -22, -109, 106, -55}; /** * Time to wait for coordination timeout */ protected long waitForCoordMsgTimeout = 15000; /** * Our current view */ protected Membership view = null; /** * Out current viewId */ protected UniqueId viewId; /** * Our nonblocking membership */ protected Membership membership = null; /** * indicates that we are running an election * and this is the one we are running */ protected UniqueId suggestedviewId; protected Membership suggestedView; protected boolean started = false; protected final int startsvc = 0xFFFF; protected Object electionMutex = new Object(); protected AtomicBoolean coordMsgReceived = new AtomicBoolean(false); public NonBlockingCoordinator() { super(); } //============================================================================================================ // COORDINATION HANDLING //============================================================================================================ public void startElection(boolean force) throws ChannelException { synchronized (electionMutex) { MemberImpl local = (MemberImpl)getLocalMember(false); MemberImpl[] others = membership.getMembers(); fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START_ELECT,this,"Election initated")); if ( others.length == 0 ) { this.viewId = new UniqueId(UUIDGenerator.randomUUID(false)); this.view = new Membership(local,AbsoluteOrder.comp, true); this.handleViewConf(this.createElectionMsg(local,others,local),local,view); return; //the only member, no need for an election } if ( suggestedviewId != null ) { if ( view != null && Arrays.diff(view,suggestedView,local).length == 0 && Arrays.diff(suggestedView,view,local).length == 0) { suggestedviewId = null; suggestedView = null; fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, running election matches view")); } else { fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, election running")); } return; //election already running, I'm not allowed to have two of them } if ( view != null && Arrays.diff(view,membership,local).length == 0 && Arrays.diff(membership,view,local).length == 0) { fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, view matches membership")); return; //already have this view installed } int prio = AbsoluteOrder.comp.compare(local,others[0]); MemberImpl leader = ( prio < 0 )?local:others[0];//am I the leader in my view? if ( local.equals(leader) || force ) { CoordinationMessage msg = createElectionMsg(local, others, leader); suggestedviewId = msg.getId(); suggestedView = new Membership(local,AbsoluteOrder.comp,true); Arrays.fill(suggestedView,msg.getMembers()); fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_PROCESS_ELECT,this,"Election, sending request")); sendElectionMsg(local,others[0],msg); } else { try { coordMsgReceived.set(false); fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_WAIT_FOR_MSG,this,"Election, waiting for request")); electionMutex.wait(waitForCoordMsgTimeout); }catch ( InterruptedException x ) { Thread.interrupted(); } if ( suggestedviewId == null && (!coordMsgReceived.get())) { //no message arrived, send the coord msg // fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_WAIT_FOR_MSG,this,"Election, waiting timed out.")); // startElection(true); fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, waiting timed out.")); } else { fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, received a message")); } }//end if } } private CoordinationMessage createElectionMsg(MemberImpl local, MemberImpl[] others, MemberImpl leader) { Membership m = new Membership(local,AbsoluteOrder.comp,true); Arrays.fill(m,others); MemberImpl[] mbrs = m.getMembers(); m.reset(); CoordinationMessage msg = new CoordinationMessage(leader, local, mbrs,new UniqueId(UUIDGenerator.randomUUID(true)), COORD_REQUEST); return msg; } protected void sendElectionMsg(MemberImpl local, MemberImpl next, CoordinationMessage msg) throws ChannelException { fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_SEND_MSG,this,"Sending election message to("+next.getName()+")")); super.sendMessage(new Member[] {next}, createData(msg, local), null); } protected void sendElectionMsgToNextInline(MemberImpl local, CoordinationMessage msg) throws ChannelException { int next = Arrays.nextIndex(local,msg.getMembers()); int current = next; msg.leader = msg.getMembers()[0]; boolean sent = false; while ( !sent && current >= 0 ) { try { sendElectionMsg(local, msg.getMembers()[current], msg); sent = true; }catch ( ChannelException x ) { log.warn("Unable to send election message to:"+msg.getMembers()[current]); current = Arrays.nextIndex(msg.getMembers()[current],msg.getMembers()); if ( current == next ) throw x; } } } public Member getNextInLine(MemberImpl local, MemberImpl[] others) { MemberImpl result = null; for ( int i=0; i 0); } /** * Returns coordinator if one is available * @return Member */ public Member getCoordinator() { return (view != null && view.hasMembers()) ? view.getMembers()[0] : null; } public Member[] getView() { return (view != null && view.hasMembers()) ? view.getMembers() : new Member[0]; } public UniqueId getViewId() { return viewId; } /** * Block in/out messages while a election is going on */ protected void halt() { } /** * Release lock for in/out messages election is completed */ protected void release() { } /** * Wait for an election to end */ protected void waitForRelease() { } //============================================================================================================ // OVERRIDDEN METHODS FROM CHANNEL INTERCEPTOR BASE //============================================================================================================ @Override public void start(int svc) throws ChannelException { if (membership == null) setupMembership(); if (started)return; fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START, this, "Before start")); super.start(startsvc); started = true; if (view == null) view = new Membership( (MemberImpl)super.getLocalMember(true), AbsoluteOrder.comp, true); fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START, this, "After start")); startElection(false); } @Override public void stop(int svc) throws ChannelException { try { halt(); synchronized (electionMutex) { if (!started)return; started = false; fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_STOP, this, "Before stop")); super.stop(startsvc); this.view = null; this.viewId = null; this.suggestedView = null; this.suggestedviewId = null; this.membership.reset(); fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_STOP, this, "After stop")); } }finally { release(); } } @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { waitForRelease(); super.sendMessage(destination, msg, payload); } @Override public void messageReceived(ChannelMessage msg) { if ( Arrays.contains(msg.getMessage().getBytesDirect(),0,COORD_ALIVE,0,COORD_ALIVE.length) ) { //ignore message, its an alive message fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MSG_ARRIVE,this,"Alive Message")); } else if ( Arrays.contains(msg.getMessage().getBytesDirect(),0,COORD_HEADER,0,COORD_HEADER.length) ) { try { CoordinationMessage cmsg = new CoordinationMessage(msg.getMessage()); Member[] cmbr = cmsg.getMembers(); fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MSG_ARRIVE,this,"Coord Msg Arrived("+Arrays.toNameString(cmbr)+")")); processCoordMessage(cmsg, msg.getAddress()); }catch ( ChannelException x ) { log.error("Error processing coordination message. Could be fatal.",x); } } else { super.messageReceived(msg); } } @Override public void memberAdded(Member member) { memberAdded(member,true); } public void memberAdded(Member member,boolean elect) { try { if ( membership == null ) setupMembership(); if ( membership.memberAlive((MemberImpl)member) ) super.memberAdded(member); try { fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MBR_ADD,this,"Member add("+member.getName()+")")); if (started && elect) startElection(false); }catch ( ChannelException x ) { log.error("Unable to start election when member was added.",x); } }finally { } } @Override public void memberDisappeared(Member member) { try { membership.removeMember((MemberImpl)member); super.memberDisappeared(member); try { fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MBR_DEL,this,"Member remove("+member.getName()+")")); if ( started && (isCoordinator() || isHighest()) ) startElection(true); //to do, if a member disappears, only the coordinator can start }catch ( ChannelException x ) { log.error("Unable to start election when member was removed.",x); } }finally { } } public boolean isHighest() { Member local = getLocalMember(false); if ( membership.getMembers().length == 0 ) return true; else return AbsoluteOrder.comp.compare(local,membership.getMembers()[0])<=0; } public boolean isCoordinator() { Member coord = getCoordinator(); return coord != null && getLocalMember(false).equals(coord); } @Override public void heartbeat() { try { MemberImpl local = (MemberImpl)getLocalMember(false); if ( view != null && (Arrays.diff(view,membership,local).length != 0 || Arrays.diff(membership,view,local).length != 0) ) { if ( isHighest() ) { fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START_ELECT, this, "Heartbeat found inconsistency, restart election")); startElection(true); } } } catch ( Exception x ){ log.error("Unable to perform heartbeat.",x); } finally { super.heartbeat(); } } /** * has members */ @Override public boolean hasMembers() { return membership.hasMembers(); } /** * Get all current cluster members * @return all members or empty array */ @Override public Member[] getMembers() { return membership.getMembers(); } /** * * @param mbr Member * @return Member */ @Override public Member getMember(Member mbr) { return membership.getMember(mbr); } /** * Return the member that represents this node. * * @return Member */ @Override public Member getLocalMember(boolean incAlive) { Member local = super.getLocalMember(incAlive); if ( view == null && (local != null)) setupMembership(); return local; } protected synchronized void setupMembership() { if ( membership == null ) { membership = new Membership((MemberImpl)super.getLocalMember(true),AbsoluteOrder.comp,false); } } //============================================================================================================ // HELPER CLASSES FOR COORDINATION //============================================================================================================ public static class CoordinationMessage { //X{A-ldr, A-src, mbrs-A,B,C,D} protected XByteBuffer buf; protected MemberImpl leader; protected MemberImpl source; protected MemberImpl[] view; protected UniqueId id; protected byte[] type; /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected long timestamp = System.currentTimeMillis(); public CoordinationMessage(XByteBuffer buf) { this.buf = buf; parse(); } public CoordinationMessage(MemberImpl leader, MemberImpl source, MemberImpl[] view, UniqueId id, byte[] type) { this.buf = new XByteBuffer(4096,false); this.leader = leader; this.source = source; this.view = view; this.id = id; this.type = type; this.write(); } public byte[] getHeader() { return NonBlockingCoordinator.COORD_HEADER; } public MemberImpl getLeader() { if ( leader == null ) parse(); return leader; } public MemberImpl getSource() { if ( source == null ) parse(); return source; } public UniqueId getId() { if ( id == null ) parse(); return id; } public MemberImpl[] getMembers() { if ( view == null ) parse(); return view; } public byte[] getType() { if (type == null ) parse(); return type; } public XByteBuffer getBuffer() { return this.buf; } public void parse() { //header int offset = 16; //leader int ldrLen = XByteBuffer.toInt(buf.getBytesDirect(),offset); offset += 4; byte[] ldr = new byte[ldrLen]; System.arraycopy(buf.getBytesDirect(),offset,ldr,0,ldrLen); leader = MemberImpl.getMember(ldr); offset += ldrLen; //source int srcLen = XByteBuffer.toInt(buf.getBytesDirect(),offset); offset += 4; byte[] src = new byte[srcLen]; System.arraycopy(buf.getBytesDirect(),offset,src,0,srcLen); source = MemberImpl.getMember(src); offset += srcLen; //view int mbrCount = XByteBuffer.toInt(buf.getBytesDirect(),offset); offset += 4; view = new MemberImpl[mbrCount]; for (int i=0; iChannel.SEND_OPTIONS_ASYNCHRONOUS * flag to be set, if it is, it will queue the message for delivery and immediately return to the sender. * * * * @author Filip Hanik * @version 1.0 */ public class MessageDispatchInterceptor extends ChannelInterceptorBase implements Runnable { private static final Log log = LogFactory.getLog(MessageDispatchInterceptor.class); protected long maxQueueSize = 1024*1024*64; //64MB protected FastQueue queue = new FastQueue(); protected volatile boolean run = false; protected Thread msgDispatchThread = null; protected long currentSize = 0; protected boolean useDeepClone = true; protected boolean alwaysSend = true; public MessageDispatchInterceptor() { setOptionFlag(Channel.SEND_OPTIONS_ASYNCHRONOUS); } @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { boolean async = (msg.getOptions() & Channel.SEND_OPTIONS_ASYNCHRONOUS) == Channel.SEND_OPTIONS_ASYNCHRONOUS; if ( async && run ) { if ( (getCurrentSize()+msg.getMessage().getLength()) > maxQueueSize ) { if ( alwaysSend ) { super.sendMessage(destination,msg,payload); return; } else { throw new ChannelException("Asynchronous queue is full, reached its limit of " + maxQueueSize +" bytes, current:" + getCurrentSize() + " bytes."); }//end if }//end if //add to queue if ( useDeepClone ) msg = (ChannelMessage)msg.deepclone(); if (!addToQueue(msg, destination, payload) ) { throw new ChannelException("Unable to add the message to the async queue, queue bug?"); } addAndGetCurrentSize(msg.getMessage().getLength()); } else { super.sendMessage(destination, msg, payload); } } public boolean addToQueue(ChannelMessage msg, Member[] destination, InterceptorPayload payload) { return queue.add(msg,destination,payload); } public LinkObject removeFromQueue() { return queue.remove(); } public void startQueue() { msgDispatchThread = new Thread(this); msgDispatchThread.setName("MessageDispatchInterceptor.MessageDispatchThread"); msgDispatchThread.setDaemon(true); msgDispatchThread.setPriority(Thread.MAX_PRIORITY); queue.setEnabled(true); run = true; msgDispatchThread.start(); } public void stopQueue() { run = false; msgDispatchThread.interrupt(); queue.setEnabled(false); setAndGetCurrentSize(0); } @Override public void setOptionFlag(int flag) { if ( flag != Channel.SEND_OPTIONS_ASYNCHRONOUS ) log.warn("Warning, you are overriding the asynchronous option flag, this will disable the Channel.SEND_OPTIONS_ASYNCHRONOUS that other apps might use."); super.setOptionFlag(flag); } public void setMaxQueueSize(long maxQueueSize) { this.maxQueueSize = maxQueueSize; } public void setUseDeepClone(boolean useDeepClone) { this.useDeepClone = useDeepClone; } public long getMaxQueueSize() { return maxQueueSize; } public boolean getUseDeepClone() { return useDeepClone; } public long getCurrentSize() { return currentSize; } public long addAndGetCurrentSize(long inc) { synchronized (this) { currentSize += inc; return currentSize; } } public long setAndGetCurrentSize(long value) { synchronized (this) { currentSize = value; return value; } } @Override public void start(int svc) throws ChannelException { //start the thread if (!run ) { synchronized (this) { if ( !run && ((svc & Channel.SND_TX_SEQ)==Channel.SND_TX_SEQ) ) {//only start with the sender startQueue(); }//end if }//sync }//end if super.start(svc); } @Override public void stop(int svc) throws ChannelException { //stop the thread if ( run ) { synchronized (this) { if ( run && ((svc & Channel.SND_TX_SEQ)==Channel.SND_TX_SEQ)) { stopQueue(); }//end if }//sync }//end if super.stop(svc); } @Override public void run() { while ( run ) { LinkObject link = removeFromQueue(); if ( link == null ) continue; //should not happen unless we exceed wait time while ( link != null && run ) { link = sendAsyncData(link); }//while }//while }//run protected LinkObject sendAsyncData(LinkObject link) { ChannelMessage msg = link.data(); Member[] destination = link.getDestination(); try { super.sendMessage(destination,msg,null); try { if ( link.getHandler() != null ) link.getHandler().handleCompletion(new UniqueId(msg.getUniqueId())); } catch ( Exception ex ) { log.error("Unable to report back completed message.",ex); } } catch ( Exception x ) { ChannelException cx = null; if ( x instanceof ChannelException ) cx = (ChannelException)x; else cx = new ChannelException(x); if ( log.isDebugEnabled() ) log.debug("Error while processing async message.",x); try { if (link.getHandler() != null) link.getHandler().handleError(cx, new UniqueId(msg.getUniqueId())); } catch ( Exception ex ) { log.error("Unable to report back error message.",ex); } } finally { addAndGetCurrentSize(-msg.getMessage().getLength()); link = link.next(); }//try return link; } public boolean isAlwaysSend() { return alwaysSend; } public void setAlwaysSend(boolean alwaysSend) { this.alwaysSend = alwaysSend; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/DomainFilterInterceptor.java0000644000175100017510000000754712271464231032473 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.Arrays; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.membership.MemberImpl; import org.apache.catalina.tribes.membership.Membership; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** *

    Title: Member domain filter interceptor

    * *

    Description: Filters membership based on domain. *

    * * @author Filip Hanik * @version 1.0 */ public class DomainFilterInterceptor extends ChannelInterceptorBase { private static final Log log = LogFactory.getLog(DomainFilterInterceptor.class); protected Membership membership = null; protected byte[] domain = new byte[0]; @Override public void messageReceived(ChannelMessage msg) { //should we filter incoming based on domain? super.messageReceived(msg); }//messageReceived @Override public void memberAdded(Member member) { if ( membership == null ) setupMembership(); boolean notify = false; synchronized (membership) { notify = Arrays.equals(domain,member.getDomain()); if ( notify ) notify = membership.memberAlive((MemberImpl)member); } if ( notify ) { super.memberAdded(member); } else { if(log.isInfoEnabled()) log.info("Member was refused to join cluster["+member+"]"); } } @Override public void memberDisappeared(Member member) { if ( membership == null ) setupMembership(); boolean notify = false; synchronized (membership) { notify = Arrays.equals(domain,member.getDomain()); membership.removeMember((MemberImpl)member); } if ( notify ) super.memberDisappeared(member); } @Override public boolean hasMembers() { if ( membership == null ) setupMembership(); return membership.hasMembers(); } @Override public Member[] getMembers() { if ( membership == null ) setupMembership(); return membership.getMembers(); } @Override public Member getMember(Member mbr) { if ( membership == null ) setupMembership(); return membership.getMember(mbr); } @Override public Member getLocalMember(boolean incAlive) { return super.getLocalMember(incAlive); } protected synchronized void setupMembership() { if ( membership == null ) { membership = new Membership((MemberImpl)super.getLocalMember(true)); } } public byte[] getDomain() { return domain; } public void setDomain(byte[] domain) { this.domain = domain; } public void setDomain(String domain) { if ( domain == null ) return; if (domain.startsWith("{")) setDomain(org.apache.catalina.tribes.util.Arrays.fromString(domain)); else setDomain(org.apache.catalina.tribes.util.Arrays.convert(domain)); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/GzipInterceptor.java0000644000175100017510000000702312271464231031014 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.group.InterceptorPayload; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * @author Filip Hanik * @version 1.0 */ public class GzipInterceptor extends ChannelInterceptorBase { private static final Log log = LogFactory.getLog(GzipInterceptor.class); public static final int DEFAULT_BUFFER_SIZE = 2048; @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { try { byte[] data = compress(msg.getMessage().getBytes()); msg.getMessage().trim(msg.getMessage().getLength()); msg.getMessage().append(data,0,data.length); getNext().sendMessage(destination, msg, payload); } catch ( IOException x ) { log.error("Unable to compress byte contents"); throw new ChannelException(x); } } @Override public void messageReceived(ChannelMessage msg) { try { byte[] data = decompress(msg.getMessage().getBytes()); msg.getMessage().trim(msg.getMessage().getLength()); msg.getMessage().append(data,0,data.length); getPrevious().messageReceived(msg); } catch ( IOException x ) { log.error("Unable to decompress byte contents",x); } } public static byte[] compress(byte[] data) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); GZIPOutputStream gout = new GZIPOutputStream(bout); gout.write(data); gout.flush(); gout.close(); return bout.toByteArray(); } /** * @param data Data to decompress * @return Decompressed data * @throws IOException */ public static byte[] decompress(byte[] data) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE); ByteArrayInputStream bin = new ByteArrayInputStream(data); GZIPInputStream gin = new GZIPInputStream(bin); byte[] tmp = new byte[DEFAULT_BUFFER_SIZE]; int length = gin.read(tmp); while (length > -1) { bout.write(tmp, 0, length); length = gin.read(tmp); } return bout.toByteArray(); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/OrderInterceptor.java0000644000175100017510000002670212271464231031163 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.group.InterceptorPayload; import org.apache.catalina.tribes.io.XByteBuffer; /** * * The order interceptor guarantees that messages are received in the same order they were * sent. * This interceptor works best with the ack=true setting.
    * There is no point in * using this with the replicationMode="fastasynchqueue" as this mode guarantees ordering.
    * If you are using the mode ack=false replicationMode=pooled, and have a lot of concurrent threads, * this interceptor can really slow you down, as many messages will be completely out of order * and the queue might become rather large. If this is the case, then you might want to set * the value OrderInterceptor.maxQueue = 25 (meaning that we will never keep more than 25 messages in our queue) *
    Configuration Options
    * OrderInteceptor.expire= - if a message arrives out of order, how long before we act on it default=3000ms
    * OrderInteceptor.maxQueue= - how much can the queue grow to ensure ordering. * This setting is useful to avoid OutOfMemoryErrorsdefault=Integer.MAX_VALUE
    * OrderInterceptor.forwardExpired= - this flag tells the interceptor what to * do when a message has expired or the queue has grown larger than the maxQueue value. * true means that the message is sent up the stack to the receiver that will receive and out of order message * false means, forget the message and reset the message counter. default=true * * * @author Filip Hanik * @version 1.1 */ public class OrderInterceptor extends ChannelInterceptorBase { private HashMap outcounter = new HashMap(); private HashMap incounter = new HashMap(); private HashMap incoming = new HashMap(); private long expire = 3000; private boolean forwardExpired = true; private int maxQueue = Integer.MAX_VALUE; final ReentrantReadWriteLock inLock = new ReentrantReadWriteLock(true); final ReentrantReadWriteLock outLock= new ReentrantReadWriteLock(true); @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { if ( !okToProcess(msg.getOptions()) ) { super.sendMessage(destination, msg, payload); return; } ChannelException cx = null; for (int i=0; i cnt.getCounter() ) cnt.setCounter(order.getMsgNr()); super.messageReceived(order.getMessage()); order.setMessage(null); order = order.next; } MessageOrder head = order; MessageOrder prev = null; tmp = order; //flag to empty out the queue when it larger than maxQueue boolean empty = order!=null?order.getCount()>=maxQueue:false; while ( tmp != null ) { //process expired messages or empty out the queue if ( tmp.isExpired(expire) || empty ) { //reset the head if ( tmp == head ) head = tmp.next; cnt.setCounter(tmp.getMsgNr()+1); if ( getForwardExpired() ) super.messageReceived(tmp.getMessage()); tmp.setMessage(null); tmp = tmp.next; if ( prev != null ) prev.next = tmp; result = true; } else { prev = tmp; tmp = tmp.next; } } if ( head == null ) incoming.remove(member); else incoming.put(member, head); return result; } @Override public void memberAdded(Member member) { //notify upwards super.memberAdded(member); } @Override public void memberDisappeared(Member member) { //reset counters - lock free incounter.remove(member); outcounter.remove(member); //clear the remaining queue processLeftOvers(member,true); //notify upwards super.memberDisappeared(member); } protected int incCounter(Member mbr) { Counter cnt = getOutCounter(mbr); return cnt.inc(); } protected Counter getInCounter(Member mbr) { Counter cnt = incounter.get(mbr); if ( cnt == null ) { cnt = new Counter(); cnt.inc(); //always start at 1 for incoming incounter.put(mbr,cnt); } return cnt; } protected Counter getOutCounter(Member mbr) { Counter cnt = outcounter.get(mbr); if ( cnt == null ) { cnt = new Counter(); outcounter.put(mbr,cnt); } return cnt; } protected static class Counter { private AtomicInteger value = new AtomicInteger(0); public int getCounter() { return value.get(); } public void setCounter(int counter) { this.value.set(counter); } public int inc() { return value.addAndGet(1); } } protected static class MessageOrder { private long received = System.currentTimeMillis(); private MessageOrder next; private int msgNr; private ChannelMessage msg = null; public MessageOrder(int msgNr,ChannelMessage msg) { this.msgNr = msgNr; this.msg = msg; } public boolean isExpired(long expireTime) { return (System.currentTimeMillis()-received) > expireTime; } public ChannelMessage getMessage() { return msg; } public void setMessage(ChannelMessage msg) { this.msg = msg; } public void setNext(MessageOrder order) { this.next = order; } public MessageOrder getNext() { return next; } public int getCount() { int counter = 1; MessageOrder tmp = next; while ( tmp != null ) { counter++; tmp = tmp.next; } return counter; } @SuppressWarnings("null") // prev cannot be null public static MessageOrder add(MessageOrder head, MessageOrder add) { if ( head == null ) return add; if ( add == null ) return head; if ( head == add ) return add; if ( head.getMsgNr() > add.getMsgNr() ) { add.next = head; return add; } MessageOrder iter = head; MessageOrder prev = null; while ( iter.getMsgNr() < add.getMsgNr() && (iter.next !=null ) ) { prev = iter; iter = iter.next; } if ( iter.getMsgNr() < add.getMsgNr() ) { //add after add.next = iter.next; iter.next = add; } else if (iter.getMsgNr() > add.getMsgNr()) { //add before prev.next = add; // prev cannot be null here, warning suppressed add.next = iter; } else { throw new ArithmeticException("Message added has the same counter, synchronization bug. Disable the order interceptor"); } return head; } public int getMsgNr() { return msgNr; } } public void setExpire(long expire) { this.expire = expire; } public void setForwardExpired(boolean forwardExpired) { this.forwardExpired = forwardExpired; } public void setMaxQueue(int maxQueue) { this.maxQueue = maxQueue; } public long getExpire() { return expire; } public boolean getForwardExpired() { return forwardExpired; } public int getMaxQueue() { return maxQueue; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/SimpleCoordinator.java0000644000175100017510000000656712271464231031335 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.Arrays; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.AbsoluteOrder; import org.apache.catalina.tribes.group.ChannelInterceptorBase; /** * A dinky coordinator, just uses a sorted version of the member array. * * @author rnewson * */ public class SimpleCoordinator extends ChannelInterceptorBase { private Member[] view; private AtomicBoolean membershipChanged = new AtomicBoolean(); private void membershipChanged() { membershipChanged.set(true); } @Override public void memberAdded(final Member member) { super.memberAdded(member); membershipChanged(); installViewWhenStable(); } @Override public void memberDisappeared(final Member member) { super.memberDisappeared(member); membershipChanged(); installViewWhenStable(); } /** * Override to receive view changes. * * @param view */ protected void viewChange(final Member[] view) { } @Override public void start(int svc) throws ChannelException { super.start(svc); installViewWhenStable(); } private void installViewWhenStable() { int stableCount = 0; while (stableCount < 10) { if (membershipChanged.compareAndSet(true, false)) { stableCount = 0; } else { stableCount++; } try { TimeUnit.MILLISECONDS.sleep(250); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); } } final Member[] members = getMembers(); final Member[] view = new Member[members.length+1]; System.arraycopy(members, 0, view, 0, members.length); view[members.length] = getLocalMember(false); Arrays.sort(view, AbsoluteOrder.comp); if (Arrays.equals(view, this.view)) { return; } this.view = view; viewChange(view); } @Override public void stop(int svc) throws ChannelException { super.stop(svc); } public Member[] getView() { return view; } public Member getCoordinator() { return view == null ? null : view[0]; } public boolean isCoordinator() { return view == null ? false : getLocalMember(false).equals( getCoordinator()); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/TwoPhaseCommitInterceptor.java0000644000175100017510000001416212271464231033010 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.HashMap; import java.util.Map; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.group.InterceptorPayload; import org.apache.catalina.tribes.util.Arrays; import org.apache.catalina.tribes.util.UUIDGenerator; /** *

    Title:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public class TwoPhaseCommitInterceptor extends ChannelInterceptorBase { private static final byte[] START_DATA = new byte[] {113, 1, -58, 2, -34, -60, 75, -78, -101, -12, 32, -29, 32, 111, -40, 4}; private static final byte[] END_DATA = new byte[] {54, -13, 90, 110, 47, -31, 75, -24, -81, -29, 36, 52, -58, 77, -110, 56}; private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(TwoPhaseCommitInterceptor.class); protected HashMap messages = new HashMap(); protected long expire = 1000 * 60; //one minute expiration protected boolean deepclone = true; @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { //todo, optimize, if destination.length==1, then we can do //msg.setOptions(msg.getOptions() & (~getOptionFlag()) //and just send one message if (okToProcess(msg.getOptions()) ) { super.sendMessage(destination, msg, null); ChannelMessage confirmation = null; if ( deepclone ) confirmation = (ChannelMessage)msg.deepclone(); else confirmation = (ChannelMessage)msg.clone(); confirmation.getMessage().reset(); UUIDGenerator.randomUUID(false,confirmation.getUniqueId(),0); confirmation.getMessage().append(START_DATA,0,START_DATA.length); confirmation.getMessage().append(msg.getUniqueId(),0,msg.getUniqueId().length); confirmation.getMessage().append(END_DATA,0,END_DATA.length); super.sendMessage(destination,confirmation,payload); } else { //turn off two phase commit //this wont work if the interceptor has 0 as a flag //since there is no flag to turn off //msg.setOptions(msg.getOptions() & (~getOptionFlag())); super.sendMessage(destination, msg, payload); } } @Override public void messageReceived(ChannelMessage msg) { if (okToProcess(msg.getOptions())) { if ( msg.getMessage().getLength() == (START_DATA.length+msg.getUniqueId().length+END_DATA.length) && Arrays.contains(msg.getMessage().getBytesDirect(),0,START_DATA,0,START_DATA.length) && Arrays.contains(msg.getMessage().getBytesDirect(),START_DATA.length+msg.getUniqueId().length,END_DATA,0,END_DATA.length) ) { UniqueId id = new UniqueId(msg.getMessage().getBytesDirect(),START_DATA.length,msg.getUniqueId().length); MapEntry original = messages.get(id); if ( original != null ) { super.messageReceived(original.msg); messages.remove(id); } else log.warn("Received a confirmation, but original message is missing. Id:"+Arrays.toString(id.getBytes())); } else { UniqueId id = new UniqueId(msg.getUniqueId()); MapEntry entry = new MapEntry((ChannelMessage)msg.deepclone(),id,System.currentTimeMillis()); messages.put(id,entry); } } else { super.messageReceived(msg); } } public boolean getDeepclone() { return deepclone; } public long getExpire() { return expire; } public void setDeepclone(boolean deepclone) { this.deepclone = deepclone; } public void setExpire(long expire) { this.expire = expire; } @Override public void heartbeat() { try { long now = System.currentTimeMillis(); @SuppressWarnings("unchecked") Map.Entry[] entries = messages.entrySet().toArray(new Map.Entry[messages.size()]); for (int i=0; i expiration; } } }tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java0000644000175100017510000001511312271464231031446 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelInterceptor; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.ChannelInterceptorBase; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * * Sends a ping to all members. * Configure this interceptor with the TcpFailureDetector below it, * and the TcpFailureDetector will act as the membership guide. * @author Filip Hanik * @version 1.0 */ public class TcpPingInterceptor extends ChannelInterceptorBase { private static final Log log = LogFactory.getLog(TcpPingInterceptor.class); protected static byte[] TCP_PING_DATA = new byte[] { 79, -89, 115, 72, 121, -33, 67, -55, -97, 111, -119, -128, -95, 91, 7, 20, 125, -39, 82, 91, -21, -33, 67, -102, -73, 126, -66, -113, -127, 103, 30, -74, 55, 21, -66, -121, 69, 33, 76, -88, -65, 10, 77, 19, 83, 56, 21, 50, 85, -10, -108, -73, 58, -33, 33, 120, -111, 4, 125, -41, 114, -124, -64, -43}; protected long interval = 1000; //1 second protected boolean useThread = false; protected boolean staticOnly = false; protected volatile boolean running = true; protected PingThread thread = null; protected static AtomicInteger cnt = new AtomicInteger(0); WeakReference failureDetector = null; WeakReference staticMembers = null; @Override public synchronized void start(int svc) throws ChannelException { super.start(svc); running = true; if ( thread == null && useThread) { thread = new PingThread(); thread.setDaemon(true); thread.setName("TcpPingInterceptor.PingThread-"+cnt.addAndGet(1)); thread.start(); } //acquire the interceptors to invoke on send ping events ChannelInterceptor next = getNext(); while ( next != null ) { if ( next instanceof TcpFailureDetector ) failureDetector = new WeakReference((TcpFailureDetector)next); if ( next instanceof StaticMembershipInterceptor ) staticMembers = new WeakReference((StaticMembershipInterceptor)next); next = next.getNext(); } } @Override public void stop(int svc) throws ChannelException { running = false; if ( thread != null ) { thread.interrupt(); thread = null; } super.stop(svc); } @Override public void heartbeat() { super.heartbeat(); if (!getUseThread()) sendPing(); } public long getInterval() { return interval; } public void setInterval(long interval) { this.interval = interval; } public void setUseThread(boolean useThread) { this.useThread = useThread; } public void setStaticOnly(boolean staticOnly) { this.staticOnly = staticOnly; } public boolean getUseThread() { return useThread; } public boolean getStaticOnly() { return staticOnly; } protected void sendPing() { TcpFailureDetector tcpFailureDetector = failureDetector != null ? failureDetector.get() : null; if (tcpFailureDetector != null) { // We have a reference to the failure detector // Piggy back on it tcpFailureDetector.checkMembers(true); } else { StaticMembershipInterceptor smi = staticOnly && staticMembers != null ? staticMembers.get() : null; if (smi != null) { sendPingMessage(smi.getMembers()); } else { sendPingMessage(getMembers()); } } } protected void sendPingMessage(Member[] members) { if ( members == null || members.length == 0 ) return; ChannelData data = new ChannelData(true);//generates a unique Id data.setAddress(getLocalMember(false)); data.setTimestamp(System.currentTimeMillis()); data.setOptions(getOptionFlag()); data.setMessage(new XByteBuffer(TCP_PING_DATA, false)); try { super.sendMessage(members, data, null); }catch (ChannelException x) { log.warn("Unable to send TCP ping.",x); } } @Override public void messageReceived(ChannelMessage msg) { //catch incoming boolean process = true; if ( okToProcess(msg.getOptions()) ) { //check to see if it is a ping message, if so, process = false process = ( (msg.getMessage().getLength() != TCP_PING_DATA.length) || (!Arrays.equals(TCP_PING_DATA,msg.getMessage().getBytes()) ) ); }//end if //ignore the message, it doesnt have the flag set if ( process ) super.messageReceived(msg); else if ( log.isDebugEnabled() ) log.debug("Received a TCP ping packet:"+msg); }//messageReceived protected class PingThread extends Thread { @Override public void run() { while (running) { try { sleep(interval); sendPing(); }catch ( InterruptedException ix ) { interrupted(); }catch ( Exception x ) { log.warn("Unable to send ping from TCP ping thread.",x); } } } } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/interceptors/StaticMembershipInterceptor.java0000644000175100017510000000767412271464231033362 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group.interceptors; import java.util.ArrayList; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.group.AbsoluteOrder; import org.apache.catalina.tribes.group.ChannelInterceptorBase; public class StaticMembershipInterceptor extends ChannelInterceptorBase { protected ArrayList members = new ArrayList(); protected Member localMember = null; public StaticMembershipInterceptor() { super(); } public void addStaticMember(Member member) { synchronized (members) { if (!members.contains(member)) members.add(member); } } public void removeStaticMember(Member member) { synchronized (members) { if (members.contains(member)) members.remove(member); } } public void setLocalMember(Member member) { this.localMember = member; } /** * has members */ @Override public boolean hasMembers() { return super.hasMembers() || (members.size()>0); } /** * Get all current cluster members * @return all members or empty array */ @Override public Member[] getMembers() { if ( members.size() == 0 ) return super.getMembers(); else { synchronized (members) { Member[] others = super.getMembers(); Member[] result = new Member[members.size() + others.length]; for (int i = 0; i < others.length; i++) result[i] = others[i]; for (int i = 0; i < members.size(); i++) result[i + others.length] = members.get(i); AbsoluteOrder.absoluteOrder(result); return result; }//sync }//end if } /** * * @param mbr Member * @return Member */ @Override public Member getMember(Member mbr) { if ( members.contains(mbr) ) return members.get(members.indexOf(mbr)); else return super.getMember(mbr); } /** * Return the member that represents this node. * * @return Member */ @Override public Member getLocalMember(boolean incAlive) { if (this.localMember != null ) return localMember; else return super.getLocalMember(incAlive); } /** * Send notifications upwards * @param svc int * @throws ChannelException */ @Override public void start(int svc) throws ChannelException { if ( (Channel.SND_RX_SEQ&svc)==Channel.SND_RX_SEQ ) super.start(Channel.SND_RX_SEQ); if ( (Channel.SND_TX_SEQ&svc)==Channel.SND_TX_SEQ ) super.start(Channel.SND_TX_SEQ); final Member[] mbrs = members.toArray(new Member[members.size()]); final ChannelInterceptorBase base = this; Thread t = new Thread() { @Override public void run() { for (int i=0; i * DEFAULT - will start all services
    * MBR_RX_SEQ - starts the membership receiver
    * MBR_TX_SEQ - starts the membership broadcaster
    * SND_TX_SEQ - starts the replication transmitter
    * SND_RX_SEQ - starts the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. */ @Override public void start(int svc) throws ChannelException { if ( getNext()!=null ) getNext().start(svc); } /** * Shuts down the channel. This can be called multiple times for individual services to shutdown * The svc parameter can be the logical or value of any constants * @param svc int value of
    * DEFAULT - will shutdown all services
    * MBR_RX_SEQ - stops the membership receiver
    * MBR_TX_SEQ - stops the membership broadcaster
    * SND_TX_SEQ - stops the replication transmitter
    * SND_RX_SEQ - stops the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. */ @Override public void stop(int svc) throws ChannelException { if (getNext() != null) getNext().stop(svc); } @Override public void fireInterceptorEvent(InterceptorEvent event) { //empty operation } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/ChannelCoordinator.java0000644000175100017510000003111412271464231026715 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.ChannelReceiver; import org.apache.catalina.tribes.ChannelSender; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipService; import org.apache.catalina.tribes.MessageListener; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.membership.McastService; import org.apache.catalina.tribes.transport.ReplicationTransmitter; import org.apache.catalina.tribes.transport.SenderState; import org.apache.catalina.tribes.transport.nio.NioReceiver; import org.apache.catalina.tribes.util.Arrays; import org.apache.catalina.tribes.util.Logs; /** * The channel coordinator object coordinates the membership service, * the sender and the receiver. * This is the last interceptor in the chain. * @author Filip Hanik */ public class ChannelCoordinator extends ChannelInterceptorBase implements MessageListener { private ChannelReceiver clusterReceiver = new NioReceiver(); private ChannelSender clusterSender = new ReplicationTransmitter(); private MembershipService membershipService = new McastService(); private int startLevel = 0; public ChannelCoordinator() { // Override default this.optionFlag = Channel.SEND_OPTIONS_BYTE_MESSAGE | Channel.SEND_OPTIONS_USE_ACK | Channel.SEND_OPTIONS_SYNCHRONIZED_ACK; } public ChannelCoordinator(ChannelReceiver receiver, ChannelSender sender, MembershipService service) { this(); this.setClusterReceiver(receiver); this.setClusterSender(sender); this.setMembershipService(service); } /** * Send a message to one or more members in the cluster * @param destination Member[] - the destinations, null or zero length means all * @param msg ClusterMessage - the message to send * @param payload TBA */ @Override public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException { if ( destination == null ) destination = membershipService.getMembers(); if ((msg.getOptions()&Channel.SEND_OPTIONS_MULTICAST) == Channel.SEND_OPTIONS_MULTICAST) { membershipService.broadcast(msg); } else { clusterSender.sendMessage(msg,destination); } if ( Logs.MESSAGES.isTraceEnabled() ) { Logs.MESSAGES.trace("ChannelCoordinator - Sent msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " to "+Arrays.toNameString(destination)); } } /** * Starts up the channel. This can be called multiple times for individual services to start * The svc parameter can be the logical or value of any constants * @param svc int value of
    * DEFAULT - will start all services
    * MBR_RX_SEQ - starts the membership receiver
    * MBR_TX_SEQ - starts the membership broadcaster
    * SND_TX_SEQ - starts the replication transmitter
    * SND_RX_SEQ - starts the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. */ @Override public void start(int svc) throws ChannelException { this.internalStart(svc); } /** * Shuts down the channel. This can be called multiple times for individual services to shutdown * The svc parameter can be the logical or value of any constants * @param svc int value of
    * DEFAULT - will shutdown all services
    * MBR_RX_SEQ - stops the membership receiver
    * MBR_TX_SEQ - stops the membership broadcaster
    * SND_TX_SEQ - stops the replication transmitter
    * SND_RX_SEQ - stops the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. */ @Override public void stop(int svc) throws ChannelException { this.internalStop(svc); } /** * Starts up the channel. This can be called multiple times for individual services to start * The svc parameter can be the logical or value of any constants * @param svc int value of
    * DEFAULT - will start all services
    * MBR_RX_SEQ - starts the membership receiver
    * MBR_TX_SEQ - starts the membership broadcaster
    * SND_TX_SEQ - starts the replication transmitter
    * SND_RX_SEQ - starts the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. */ protected synchronized void internalStart(int svc) throws ChannelException { try { boolean valid = false; //make sure we don't pass down any flags that are unrelated to the bottom layer svc = svc & Channel.DEFAULT; if (startLevel == Channel.DEFAULT) return; //we have already started up all components if (svc == 0 ) return;//nothing to start if (svc == (svc & startLevel)) throw new ChannelException("Channel already started for level:"+svc); //must start the receiver first so that we can coordinate the port it //listens to with the local membership settings if ( Channel.SND_RX_SEQ==(svc & Channel.SND_RX_SEQ) ) { clusterReceiver.setMessageListener(this); clusterReceiver.start(); //synchronize, big time FIXME membershipService.setLocalMemberProperties(getClusterReceiver().getHost(), getClusterReceiver().getPort(), getClusterReceiver().getSecurePort(), getClusterReceiver().getUdpPort()); valid = true; } if ( Channel.SND_TX_SEQ==(svc & Channel.SND_TX_SEQ) ) { clusterSender.start(); valid = true; } if ( Channel.MBR_RX_SEQ==(svc & Channel.MBR_RX_SEQ) ) { membershipService.setMembershipListener(this); if (membershipService instanceof McastService) { ((McastService)membershipService).setMessageListener(this); } membershipService.start(MembershipService.MBR_RX); valid = true; } if ( Channel.MBR_TX_SEQ==(svc & Channel.MBR_TX_SEQ) ) { membershipService.start(MembershipService.MBR_TX); valid = true; } if ( !valid) { throw new IllegalArgumentException("Invalid start level, valid levels are:SND_RX_SEQ,SND_TX_SEQ,MBR_TX_SEQ,MBR_RX_SEQ"); } startLevel = (startLevel | svc); }catch ( ChannelException cx ) { throw cx; }catch ( Exception x ) { throw new ChannelException(x); } } /** * Shuts down the channel. This can be called multiple times for individual services to shutdown * The svc parameter can be the logical or value of any constants * @param svc int value of
    * DEFAULT - will shutdown all services
    * MBR_RX_SEQ - starts the membership receiver
    * MBR_TX_SEQ - starts the membership broadcaster
    * SND_TX_SEQ - starts the replication transmitter
    * SND_RX_SEQ - starts the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. */ protected synchronized void internalStop(int svc) throws ChannelException { try { //make sure we don't pass down any flags that are unrelated to the bottom layer svc = svc & Channel.DEFAULT; if (startLevel == 0) return; //we have already stopped up all components if (svc == 0 ) return;//nothing to stop boolean valid = false; if ( Channel.SND_RX_SEQ==(svc & Channel.SND_RX_SEQ) ) { clusterReceiver.stop(); clusterReceiver.setMessageListener(null); valid = true; } if ( Channel.SND_TX_SEQ==(svc & Channel.SND_TX_SEQ) ) { clusterSender.stop(); valid = true; } if ( Channel.MBR_RX_SEQ==(svc & Channel.MBR_RX_SEQ) ) { membershipService.stop(MembershipService.MBR_RX); membershipService.setMembershipListener(null); valid = true; } if ( Channel.MBR_TX_SEQ==(svc & Channel.MBR_TX_SEQ) ) { valid = true; membershipService.stop(MembershipService.MBR_TX); } if ( !valid) { throw new IllegalArgumentException("Invalid start level, valid levels are:SND_RX_SEQ,SND_TX_SEQ,MBR_TX_SEQ,MBR_RX_SEQ"); } startLevel = (startLevel & (~svc)); }catch ( Exception x ) { throw new ChannelException(x); } finally { } } @Override public void memberAdded(Member member){ SenderState.getSenderState(member); super.memberAdded(member); } @Override public void memberDisappeared(Member member){ SenderState.removeSenderState(member); super.memberDisappeared(member); } @Override public void messageReceived(ChannelMessage msg) { if ( Logs.MESSAGES.isTraceEnabled() ) { Logs.MESSAGES.trace("ChannelCoordinator - Received msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " from "+msg.getAddress().getName()); } super.messageReceived(msg); } public ChannelReceiver getClusterReceiver() { return clusterReceiver; } public ChannelSender getClusterSender() { return clusterSender; } public MembershipService getMembershipService() { return membershipService; } public void setClusterReceiver(ChannelReceiver clusterReceiver) { if ( clusterReceiver != null ) { this.clusterReceiver = clusterReceiver; this.clusterReceiver.setMessageListener(this); } else { if (this.clusterReceiver!=null ) this.clusterReceiver.setMessageListener(null); this.clusterReceiver = null; } } public void setClusterSender(ChannelSender clusterSender) { this.clusterSender = clusterSender; } public void setMembershipService(MembershipService membershipService) { this.membershipService = membershipService; this.membershipService.setMembershipListener(this); } @Override public void heartbeat() { if ( clusterSender!=null ) clusterSender.heartbeat(); super.heartbeat(); } /** * has members */ @Override public boolean hasMembers() { return this.getMembershipService().hasMembers(); } /** * Get all current cluster members * @return all members or empty array */ @Override public Member[] getMembers() { return this.getMembershipService().getMembers(); } /** * * @param mbr Member * @return Member */ @Override public Member getMember(Member mbr){ return this.getMembershipService().getMember(mbr); } /** * Return the member that represents this node. * * @return Member */ @Override public Member getLocalMember(boolean incAlive) { return this.getMembershipService().getLocalMember(incAlive); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/GroupChannel.java0000644000175100017510000006367312271464231025545 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group; import java.io.Serializable; import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.apache.catalina.tribes.ByteMessage; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelInterceptor; import org.apache.catalina.tribes.ChannelListener; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.ChannelReceiver; import org.apache.catalina.tribes.ChannelSender; import org.apache.catalina.tribes.ErrorHandler; import org.apache.catalina.tribes.Heartbeat; import org.apache.catalina.tribes.ManagedChannel; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; import org.apache.catalina.tribes.MembershipService; import org.apache.catalina.tribes.RemoteProcessException; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor; import org.apache.catalina.tribes.io.BufferPool; import org.apache.catalina.tribes.io.ChannelData; import org.apache.catalina.tribes.io.XByteBuffer; import org.apache.catalina.tribes.util.Arrays; import org.apache.catalina.tribes.util.Logs; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * The default implementation of a Channel.
    * The GroupChannel manages the replication channel. It coordinates * message being sent and received with membership announcements. * The channel has an chain of interceptors that can modify the message or perform other logic.
    * It manages a complete group, both membership and replication. * @author Filip Hanik */ public class GroupChannel extends ChannelInterceptorBase implements ManagedChannel { private static final Log log = LogFactory.getLog(GroupChannel.class); /** * Flag to determine if the channel manages its own heartbeat * If set to true, the channel will start a local thread for the heart beat. */ protected boolean heartbeat = true; /** * If heartbeat == true then how often do we want this * heartbeat to run. default is one minute */ protected long heartbeatSleeptime = 5*1000;//every 5 seconds /** * Internal heartbeat thread */ protected HeartbeatThread hbthread = null; /** * The ChannelCoordinator coordinates the bottom layer components:
    * - MembershipService
    * - ChannelSender
    * - ChannelReceiver
    */ protected ChannelCoordinator coordinator = new ChannelCoordinator(); /** * The first interceptor in the interceptor stack. * The interceptors are chained in a linked list, so we only need a reference to the * first one */ protected ChannelInterceptor interceptors = null; /** * A list of membership listeners that subscribe to membership announcements */ protected List membershipListeners = new CopyOnWriteArrayList(); /** * A list of channel listeners that subscribe to incoming messages */ protected List channelListeners = new CopyOnWriteArrayList(); /** * If set to true, the GroupChannel will check to make sure that */ protected boolean optionCheck = false; /** * Creates a GroupChannel. This constructor will also * add the first interceptor in the GroupChannel.
    * The first interceptor is always the channel itself. */ public GroupChannel() { addInterceptor(this); } /** * Adds an interceptor to the stack for message processing
    * Interceptors are ordered in the way they are added.
    * channel.addInterceptor(A);
    * channel.addInterceptor(C);
    * channel.addInterceptor(B);
    * Will result in a interceptor stack like this:
    * A -> C -> B
    * The complete stack will look like this:
    * Channel -> A -> C -> B -> ChannelCoordinator
    * @param interceptor ChannelInterceptorBase */ @Override public void addInterceptor(ChannelInterceptor interceptor) { if ( interceptors == null ) { interceptors = interceptor; interceptors.setNext(coordinator); interceptors.setPrevious(null); coordinator.setPrevious(interceptors); } else { ChannelInterceptor last = interceptors; while ( last.getNext() != coordinator ) { last = last.getNext(); } last.setNext(interceptor); interceptor.setNext(coordinator); interceptor.setPrevious(last); coordinator.setPrevious(interceptor); } } /** * Sends a heartbeat through the interceptor stack.
    * Invoke this method from the application on a periodic basis if * you have turned off internal heartbeats channel.setHeartbeat(false) */ @Override public void heartbeat() { super.heartbeat(); Iterator i = membershipListeners.iterator(); while ( i.hasNext() ) { Object o = i.next(); if ( o instanceof Heartbeat ) ((Heartbeat)o).heartbeat(); } i = channelListeners.iterator(); while ( i.hasNext() ) { Object o = i.next(); if ( o instanceof Heartbeat ) ((Heartbeat)o).heartbeat(); } } /** * Send a message to the destinations specified * @param destination Member[] - destination.length > 0 * @param msg Serializable - the message to send * @param options int - sender options, options can trigger guarantee levels and different interceptors to * react to the message see class documentation for the Channel object.
    * @return UniqueId - the unique Id that was assigned to this message * @throws ChannelException - if an error occurs processing the message * @see org.apache.catalina.tribes.Channel */ @Override public UniqueId send(Member[] destination, Serializable msg, int options) throws ChannelException { return send(destination,msg,options,null); } /** * * @param destination Member[] - destination.length > 0 * @param msg Serializable - the message to send * @param options int - sender options, options can trigger guarantee levels and different interceptors to * react to the message see class documentation for the Channel object.
    * @param handler - callback object for error handling and completion notification, used when a message is * sent asynchronously using the Channel.SEND_OPTIONS_ASYNCHRONOUS flag enabled. * @return UniqueId - the unique Id that was assigned to this message * @throws ChannelException - if an error occurs processing the message * @see org.apache.catalina.tribes.Channel */ @Override public UniqueId send(Member[] destination, Serializable msg, int options, ErrorHandler handler) throws ChannelException { if ( msg == null ) throw new ChannelException("Cant send a NULL message"); XByteBuffer buffer = null; try { if ( destination == null || destination.length == 0) throw new ChannelException("No destination given"); ChannelData data = new ChannelData(true);//generates a unique Id data.setAddress(getLocalMember(false)); data.setTimestamp(System.currentTimeMillis()); byte[] b = null; if ( msg instanceof ByteMessage ){ b = ((ByteMessage)msg).getMessage(); options = options | SEND_OPTIONS_BYTE_MESSAGE; } else { b = XByteBuffer.serialize(msg); options = options & (~SEND_OPTIONS_BYTE_MESSAGE); } data.setOptions(options); //XByteBuffer buffer = new XByteBuffer(b.length+128,false); buffer = BufferPool.getBufferPool().getBuffer(b.length+128, false); buffer.append(b,0,b.length); data.setMessage(buffer); InterceptorPayload payload = null; if ( handler != null ) { payload = new InterceptorPayload(); payload.setErrorHandler(handler); } getFirstInterceptor().sendMessage(destination, data, payload); if ( Logs.MESSAGES.isTraceEnabled() ) { Logs.MESSAGES.trace("GroupChannel - Sent msg:" + new UniqueId(data.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " to "+Arrays.toNameString(destination)); Logs.MESSAGES.trace("GroupChannel - Send Message:" + new UniqueId(data.getUniqueId()) + " is " +msg); } return new UniqueId(data.getUniqueId()); }catch ( Exception x ) { if ( x instanceof ChannelException ) throw (ChannelException)x; throw new ChannelException(x); } finally { if ( buffer != null ) BufferPool.getBufferPool().returnBuffer(buffer); } } /** * Callback from the interceptor stack.
    * When a message is received from a remote node, this method will be invoked by * the previous interceptor.
    * This method can also be used to send a message to other components within the same application, * but its an extreme case, and you're probably better off doing that logic between the applications itself. * @param msg ChannelMessage */ @Override public void messageReceived(ChannelMessage msg) { if ( msg == null ) return; try { if ( Logs.MESSAGES.isTraceEnabled() ) { Logs.MESSAGES.trace("GroupChannel - Received msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " from "+msg.getAddress().getName()); } Serializable fwd = null; if ( (msg.getOptions() & SEND_OPTIONS_BYTE_MESSAGE) == SEND_OPTIONS_BYTE_MESSAGE ) { fwd = new ByteMessage(msg.getMessage().getBytes()); } else { try { fwd = XByteBuffer.deserialize(msg.getMessage().getBytesDirect(), 0, msg.getMessage().getLength()); }catch (Exception sx) { log.error("Unable to deserialize message:"+msg,sx); return; } } if ( Logs.MESSAGES.isTraceEnabled() ) { Logs.MESSAGES.trace("GroupChannel - Receive Message:" + new UniqueId(msg.getUniqueId()) + " is " +fwd); } //get the actual member with the correct alive time Member source = msg.getAddress(); boolean rx = false; boolean delivered = false; for ( int i=0; iNoRpcChannelReply message to a member
    * This method gets invoked by the channel if a RPC message comes in * and no channel listener accepts the message. This avoids timeout * @param msg RpcMessage * @param destination Member - the destination for the reply */ protected void sendNoRpcChannelReply(RpcMessage msg, Member destination) { try { //avoid circular loop if ( msg instanceof RpcMessage.NoRpcChannelReply) return; RpcMessage.NoRpcChannelReply reply = new RpcMessage.NoRpcChannelReply(msg.rpcId,msg.uuid); send(new Member[]{destination},reply,Channel.SEND_OPTIONS_ASYNCHRONOUS); } catch ( Exception x ) { log.error("Unable to find rpc channel, failed to send NoRpcChannelReply.",x); } } /** * memberAdded gets invoked by the interceptor below the channel * and the channel will broadcast it to the membership listeners * @param member Member - the new member */ @Override public void memberAdded(Member member) { //notify upwards for (int i=0; i clazz = null; try { clazz = Class.forName("org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor", true,GroupChannel.class.getClassLoader()); clazz.newInstance(); } catch ( Throwable x ) { clazz = MessageDispatchInterceptor.class; }//catch try { interceptor = (ChannelInterceptor) clazz.newInstance(); } catch (Exception x) { throw new ChannelException("Unable to add MessageDispatchInterceptor to interceptor chain.",x); } this.addInterceptor(interceptor); } } /** * Validates the option flags that each interceptor is using and reports * an error if two interceptor share the same flag. * @throws ChannelException */ protected void checkOptionFlags() throws ChannelException { StringBuilder conflicts = new StringBuilder(); ChannelInterceptor first = interceptors; while ( first != null ) { int flag = first.getOptionFlag(); if ( flag != 0 ) { ChannelInterceptor next = first.getNext(); while ( next != null ) { int nflag = next.getOptionFlag(); if (nflag!=0 && (((flag & nflag) == flag ) || ((flag & nflag) == nflag)) ) { conflicts.append("["); conflicts.append(first.getClass().getName()); conflicts.append(":"); conflicts.append(flag); conflicts.append(" == "); conflicts.append(next.getClass().getName()); conflicts.append(":"); conflicts.append(nflag); conflicts.append("] "); }//end if next = next.getNext(); }//while }//end if first = first.getNext(); }//while if ( conflicts.length() > 0 ) throw new ChannelException("Interceptor option flag conflict: "+conflicts.toString()); } /** * Starts the channel * @param svc int - what service to start * @throws ChannelException * @see org.apache.catalina.tribes.Channel#start(int) */ @Override public synchronized void start(int svc) throws ChannelException { setupDefaultStack(); if (optionCheck) checkOptionFlags(); super.start(svc); if ( hbthread == null && heartbeat ) { hbthread = new HeartbeatThread(this,heartbeatSleeptime); hbthread.start(); } } /** * Stops the channel * @param svc int * @throws ChannelException * @see org.apache.catalina.tribes.Channel#stop(int) */ @Override public synchronized void stop(int svc) throws ChannelException { if (hbthread != null) { hbthread.stopHeartbeat(); hbthread = null; } super.stop(svc); } /** * Returns the first interceptor of the stack. Useful for traversal. * @return ChannelInterceptor */ public ChannelInterceptor getFirstInterceptor() { if (interceptors != null) return interceptors; else return coordinator; } /** * Returns the channel receiver component * @return ChannelReceiver */ @Override public ChannelReceiver getChannelReceiver() { return coordinator.getClusterReceiver(); } /** * Returns the channel sender component * @return ChannelSender */ @Override public ChannelSender getChannelSender() { return coordinator.getClusterSender(); } /** * Returns the membership service component * @return MembershipService */ @Override public MembershipService getMembershipService() { return coordinator.getMembershipService(); } /** * Sets the channel receiver component * @param clusterReceiver ChannelReceiver */ @Override public void setChannelReceiver(ChannelReceiver clusterReceiver) { coordinator.setClusterReceiver(clusterReceiver); } /** * Sets the channel sender component * @param clusterSender ChannelSender */ @Override public void setChannelSender(ChannelSender clusterSender) { coordinator.setClusterSender(clusterSender); } /** * Sets the membership component * @param membershipService MembershipService */ @Override public void setMembershipService(MembershipService membershipService) { coordinator.setMembershipService(membershipService); } /** * Adds a membership listener to the channel.
    * Membership listeners are uniquely identified using the equals(Object) method * @param membershipListener MembershipListener */ @Override public void addMembershipListener(MembershipListener membershipListener) { if (!this.membershipListeners.contains(membershipListener) ) this.membershipListeners.add(membershipListener); } /** * Removes a membership listener from the channel.
    * Membership listeners are uniquely identified using the equals(Object) method * @param membershipListener MembershipListener */ @Override public void removeMembershipListener(MembershipListener membershipListener) { membershipListeners.remove(membershipListener); } /** * Adds a channel listener to the channel.
    * Channel listeners are uniquely identified using the equals(Object) method * @param channelListener ChannelListener */ @Override public void addChannelListener(ChannelListener channelListener) { if (!this.channelListeners.contains(channelListener) ) { this.channelListeners.add(channelListener); } else { throw new IllegalArgumentException("Listener already exists:"+channelListener+"["+channelListener.getClass().getName()+"]"); } } /** * * Removes a channel listener from the channel.
    * Channel listeners are uniquely identified using the equals(Object) method * @param channelListener ChannelListener */ @Override public void removeChannelListener(ChannelListener channelListener) { channelListeners.remove(channelListener); } /** * Returns an iterator of all the interceptors in this stack * @return Iterator */ @Override public Iterator getInterceptors() { return new InterceptorIterator(this.getNext(),this.coordinator); } /** * Enables/disables the option check
    * Setting this to true, will make the GroupChannel perform a conflict check * on the interceptors. If two interceptors are using the same option flag * and throw an error upon start. * @param optionCheck boolean */ public void setOptionCheck(boolean optionCheck) { this.optionCheck = optionCheck; } /** * Configure local heartbeat sleep time
    * Only used when getHeartbeat()==true * @param heartbeatSleeptime long - time in milliseconds to sleep between heartbeats */ public void setHeartbeatSleeptime(long heartbeatSleeptime) { this.heartbeatSleeptime = heartbeatSleeptime; } /** * Enables or disables local heartbeat. * if setHeartbeat(true) is invoked then the channel will start an internal * thread to invoke Channel.heartbeat() every getHeartbeatSleeptime milliseconds * @param heartbeat boolean */ @Override public void setHeartbeat(boolean heartbeat) { this.heartbeat = heartbeat; } /** * @see #setOptionCheck(boolean) * @return boolean */ public boolean getOptionCheck() { return optionCheck; } /** * @see #setHeartbeat(boolean) * @return boolean */ public boolean getHeartbeat() { return heartbeat; } /** * Returns the sleep time in milliseconds that the internal heartbeat will * sleep in between invocations of Channel.heartbeat() * @return long */ public long getHeartbeatSleeptime() { return heartbeatSleeptime; } /** * *

    Title: Interceptor Iterator

    * *

    Description: An iterator to loop through the interceptors in a channel

    * * @version 1.0 */ public static class InterceptorIterator implements Iterator { private ChannelInterceptor end; private ChannelInterceptor start; public InterceptorIterator(ChannelInterceptor start, ChannelInterceptor end) { this.end = end; this.start = start; } @Override public boolean hasNext() { return start!=null && start != end; } @Override public ChannelInterceptor next() { ChannelInterceptor result = null; if ( hasNext() ) { result = start; start = start.getNext(); } return result; } @Override public void remove() { //empty operation } } /** * *

    Title: Internal heartbeat thread

    * *

    Description: if Channel.getHeartbeat()==true then a thread of this class * is created

    * * @version 1.0 */ public static class HeartbeatThread extends Thread { private static final Log log = LogFactory.getLog(HeartbeatThread.class); protected static int counter = 1; protected static synchronized int inc() { return counter++; } protected volatile boolean doRun = true; protected GroupChannel channel; protected long sleepTime; public HeartbeatThread(GroupChannel channel, long sleepTime) { super(); this.setPriority(MIN_PRIORITY); setName("GroupChannel-Heartbeat-"+inc()); setDaemon(true); this.channel = channel; this.sleepTime = sleepTime; } public void stopHeartbeat() { doRun = false; interrupt(); } @Override public void run() { while (doRun) { try { Thread.sleep(sleepTime); channel.heartbeat(); } catch ( InterruptedException x ) { interrupted(); } catch ( Exception x ) { log.error("Unable to send heartbeat through Tribes interceptor stack. Will try to sleep again.",x); }//catch }//while }//run }//HeartbeatThread } tomcat7-7.0.52/java/org/apache/catalina/tribes/group/InterceptorPayload.java0000644000175100017510000000227512271464231026757 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group; import org.apache.catalina.tribes.ErrorHandler; /** * @author Filip Hanik * @version 1.0 */ public class InterceptorPayload { private ErrorHandler errorHandler; public ErrorHandler getErrorHandler() { return errorHandler; } public void setErrorHandler(ErrorHandler errorHandler) { this.errorHandler = errorHandler; } }tomcat7-7.0.52/java/org/apache/catalina/tribes/group/RpcChannel.java0000644000175100017510000002675212271464231025172 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.group; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.ChannelListener; import org.apache.catalina.tribes.ErrorHandler; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.util.UUIDGenerator; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * A channel to handle RPC messaging * @author Filip Hanik */ public class RpcChannel implements ChannelListener{ private static final Log log = LogFactory.getLog(RpcChannel.class); public static final int FIRST_REPLY = 1; public static final int MAJORITY_REPLY = 2; public static final int ALL_REPLY = 3; public static final int NO_REPLY = 4; private Channel channel; private RpcCallback callback; private byte[] rpcId; private int replyMessageOptions = 0; private HashMap responseMap = new HashMap(); /** * Create an RPC channel. You can have several RPC channels attached to a group * all separated out by the uniqueness * @param rpcId - the unique Id for this RPC group * @param channel Channel * @param callback RpcCallback */ public RpcChannel(byte[] rpcId, Channel channel, RpcCallback callback) { this.channel = channel; this.callback = callback; this.rpcId = rpcId; channel.addChannelListener(this); } /** * Send a message and wait for the response. * @param destination Member[] - the destination for the message, and the members you request a reply from * @param message Serializable - the message you are sending out * @param rpcOptions int - FIRST_REPLY, MAJORITY_REPLY or ALL_REPLY * @param channelOptions channel sender options * @param timeout long - timeout in milliseconds, if no reply is received within this time null is returned * @return Response[] - an array of response objects. * @throws ChannelException */ public Response[] send(Member[] destination, Serializable message, int rpcOptions, int channelOptions, long timeout) throws ChannelException { if ( destination==null || destination.length == 0 ) return new Response[0]; //avoid dead lock int sendOptions = channelOptions & ~Channel.SEND_OPTIONS_SYNCHRONIZED_ACK; RpcCollectorKey key = new RpcCollectorKey(UUIDGenerator.randomUUID(false)); RpcCollector collector = new RpcCollector(key,rpcOptions,destination.length); try { synchronized (collector) { if ( rpcOptions != NO_REPLY ) responseMap.put(key, collector); RpcMessage rmsg = new RpcMessage(rpcId, key.id, message); channel.send(destination, rmsg, sendOptions); if ( rpcOptions != NO_REPLY ) collector.wait(timeout); } } catch ( InterruptedException ix ) { Thread.currentThread().interrupt(); }finally { responseMap.remove(key); } return collector.getResponses(); } @Override public void messageReceived(Serializable msg, Member sender) { RpcMessage rmsg = (RpcMessage)msg; RpcCollectorKey key = new RpcCollectorKey(rmsg.uuid); if ( rmsg.reply ) { RpcCollector collector = responseMap.get(key); if (collector == null) { callback.leftOver(rmsg.message, sender); } else { synchronized (collector) { //make sure it hasn't been removed if ( responseMap.containsKey(key) ) { if ( (rmsg instanceof RpcMessage.NoRpcChannelReply) ) collector.destcnt--; else collector.addResponse(rmsg.message, sender); if (collector.isComplete()) collector.notifyAll(); } else { if (! (rmsg instanceof RpcMessage.NoRpcChannelReply) ) callback.leftOver(rmsg.message, sender); } }//synchronized }//end if } else{ boolean finished = false; final ExtendedRpcCallback excallback = (callback instanceof ExtendedRpcCallback)?((ExtendedRpcCallback)callback) : null; boolean asyncReply = ((replyMessageOptions & Channel.SEND_OPTIONS_ASYNCHRONOUS) == Channel.SEND_OPTIONS_ASYNCHRONOUS); Serializable reply = callback.replyRequest(rmsg.message,sender); ErrorHandler handler = null; final Serializable request = msg; final Serializable response = reply; final Member fsender = sender; if (excallback!=null && asyncReply) { handler = new ErrorHandler() { @Override public void handleError(ChannelException x, UniqueId id) { excallback.replyFailed(request, response, fsender, x); } @Override public void handleCompletion(UniqueId id) { excallback.replySucceeded(request, response, fsender); } }; } rmsg.reply = true; rmsg.message = reply; try { if (handler!=null) { channel.send(new Member[] {sender}, rmsg,replyMessageOptions & ~Channel.SEND_OPTIONS_SYNCHRONIZED_ACK, handler); } else { channel.send(new Member[] {sender}, rmsg,replyMessageOptions & ~Channel.SEND_OPTIONS_SYNCHRONIZED_ACK); } finished = true; }catch ( Exception x ) { if (excallback != null && !asyncReply) { excallback.replyFailed(rmsg.message, reply, sender, x); } else { log.error("Unable to send back reply in RpcChannel.",x); } } if (finished && excallback != null && !asyncReply) { excallback.replySucceeded(rmsg.message, reply, sender); } }//end if } public void breakdown() { channel.removeChannelListener(this); } @Override public void finalize() { breakdown(); } @Override public boolean accept(Serializable msg, Member sender) { if ( msg instanceof RpcMessage ) { RpcMessage rmsg = (RpcMessage)msg; return Arrays.equals(rmsg.rpcId,rpcId); }else return false; } public Channel getChannel() { return channel; } public RpcCallback getCallback() { return callback; } public byte[] getRpcId() { return rpcId; } public void setChannel(Channel channel) { this.channel = channel; } public void setCallback(RpcCallback callback) { this.callback = callback; } public void setRpcId(byte[] rpcId) { this.rpcId = rpcId; } public int getReplyMessageOptions() { return replyMessageOptions; } public void setReplyMessageOptions(int replyMessageOptions) { this.replyMessageOptions = replyMessageOptions; } /** * * Class that holds all response. * @author not attributable * @version 1.0 */ public static class RpcCollector { public ArrayList responses = new ArrayList(); public RpcCollectorKey key; public int options; public int destcnt; /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated public long timeout; /** * @deprecated Use {@link * RpcChannel.RpcCollector#RpcChannel.RpcCollector( * RpcChannel.RpcCollectorKey, int, int)} */ @Deprecated public RpcCollector(RpcCollectorKey key, int options, int destcnt, long timeout) { this.key = key; this.options = options; this.destcnt = destcnt; this.timeout = timeout; } public RpcCollector(RpcCollectorKey key, int options, int destcnt) { this(key, options, destcnt, 0); } public void addResponse(Serializable message, Member sender){ Response resp = new Response(sender,message); responses.add(resp); } public boolean isComplete() { if ( destcnt <= 0 ) return true; switch (options) { case ALL_REPLY: return destcnt == responses.size(); case MAJORITY_REPLY: { float perc = ((float)responses.size()) / ((float)destcnt); return perc >= 0.50f; } case FIRST_REPLY: return responses.size()>0; default: return false; } } @Override public int hashCode() { return key.hashCode(); } @Override public boolean equals(Object o) { if ( o instanceof RpcCollector ) { RpcCollector r = (RpcCollector)o; return r.key.equals(this.key); } else return false; } public Response[] getResponses() { return responses.toArray(new Response[responses.size()]); } } public static class RpcCollectorKey { byte[] id; public RpcCollectorKey(byte[] id) { this.id = id; } @Override public int hashCode() { return id[0]+id[1]+id[2]+id[3]; } @Override public boolean equals(Object o) { if ( o instanceof RpcCollectorKey ) { RpcCollectorKey r = (RpcCollectorKey)o; return Arrays.equals(id,r.id); } else return false; } } /** * @deprecated Unused - will be removed in Tomcat 8.0.x */ @Deprecated protected static String bToS(byte[] data) { StringBuilder buf = new StringBuilder(4*16); buf.append("{"); for (int i=0; data!=null && iTitle:

    * *

    Description:

    * *

    Company:

    * * @author not attributable * @version 1.0 */ public class RpcMessage implements Externalizable { protected Serializable message; protected byte[] uuid; protected byte[] rpcId; protected boolean reply = false; public RpcMessage() { //for serialization } public RpcMessage(byte[] rpcId, byte[] uuid, Serializable message) { this.rpcId = rpcId; this.uuid = uuid; this.message = message; } @Override public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException { reply = in.readBoolean(); int length = in.readInt(); uuid = new byte[length]; in.readFully(uuid); length = in.readInt(); rpcId = new byte[length]; in.readFully(rpcId); message = (Serializable)in.readObject(); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeBoolean(reply); out.writeInt(uuid.length); out.write(uuid, 0, uuid.length); out.writeInt(rpcId.length); out.write(rpcId, 0, rpcId.length); out.writeObject(message); } @Override public String toString() { StringBuilder buf = new StringBuilder("RpcMessage["); buf.append(super.toString()); buf.append("] rpcId="); buf.append(Arrays.toString(rpcId)); buf.append("; uuid="); buf.append(Arrays.toString(uuid)); buf.append("; msg="); buf.append(message); return buf.toString(); } public static class NoRpcChannelReply extends RpcMessage { public NoRpcChannelReply() { } public NoRpcChannelReply(byte[] rpcid, byte[] uuid) { super(rpcid,uuid,null); reply = true; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { reply = true; int length = in.readInt(); uuid = new byte[length]; in.readFully(uuid); length = in.readInt(); rpcId = new byte[length]; in.readFully(rpcId); } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(uuid.length); out.write(uuid, 0, uuid.length); out.writeInt(rpcId.length); out.write(rpcId, 0, rpcId.length); } } } tomcat7-7.0.52/java/org/apache/catalina/tribes/ChannelReceiver.java0000644000175100017510000000477312271464231025055 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * ChannelReceiver Interface
    * The ChannelReceiver interface is the data receiver component * at the bottom layer, the IO layer (for layers see the javadoc for the {@link Channel} interface). * This class may optionally implement a thread pool for parallel processing of incoming messages. * @author Filip Hanik */ public interface ChannelReceiver extends Heartbeat { public static final int MAX_UDP_SIZE = 65535; /** * Start listening for incoming messages on the host/port * @throws java.io.IOException */ public void start() throws java.io.IOException; /** * Stop listening for messages */ public void stop(); /** * String representation of the IPv4 or IPv6 address that this host is listening * to. * @return the host that this receiver is listening to */ public String getHost(); /** * Returns the listening port * @return port */ public int getPort(); /** * Returns the secure listening port * @return port, -1 if a secure port is not activated */ public int getSecurePort(); /** * Returns the UDP port * @return port, -1 if the UDP port is not activated. */ public int getUdpPort(); /** * Sets the message listener to receive notification of incoming * @param listener MessageListener * @see MessageListener */ public void setMessageListener(MessageListener listener); /** * Returns the message listener that is associated with this receiver * @return MessageListener * @see MessageListener */ public MessageListener getMessageListener(); } tomcat7-7.0.52/java/org/apache/catalina/tribes/package.html0000644000175100017510000000707412271464231023433 0ustar locutuslocutus Apache Tribes - The Tomcat Cluster Communication Module

    QuickStart

    
                //create a channel
                Channel myChannel = new GroupChannel();
    
                //create my listeners
                MyMessageListener msgListener = new MyMessageListener();
                MyMemberListener mbrListener = new MyMemberListener();
    
                //attach the listeners to the channel
                myChannel.addMembershipListener(mbrListener);
                myChannel.addChannelListener(msgListener);
    
                //start the channel
                myChannel.start(Channel.DEFAULT);
    
                //create a message to be sent, message must implement java.io.Serializable
                //for performance reasons you probably want them to implement java.io.Externalizable
                Serializable myMsg = new MyMessage();
    
                //retrieve my current members
                Member[] group = myChannel.getMembers();
    
                //send the message
                channel.send(group,myMsg,Channel.SEND_OPTIONS_DEFAULT);
    
        

    Interfaces for the Application Developer

    1. org.apache.catalina.tribes.Channel Main component to interact with to send messages
    2. org.apache.catalina.tribes.MembershipListener Listen to membership changes
    3. org.apache.catalina.tribes.ChannelListener Listen to data messages
    4. org.apache.catalina.tribes.Member Identifies a node, implementation specific, default is org.apache.catalina.tribes.membership.MemberImpl

    Interfaces for the Tribes Component Developer

    1. org.apache.catalina.tribes.Channel Main component to that the application interacts with
    2. org.apache.catalina.tribes.ChannelReceiver IO Component to receive messages over some network transport
    3. org.apache.catalina.tribes.ChannelSender IO Component to send messages over some network transport
    4. org.apache.catalina.tribes.MembershipService IO Component that handles membership discovery and
    5. org.apache.catalina.tribes.ChannelInterceptor interceptors between the Channel and the IO layer
    6. org.apache.catalina.tribes.ChannelMessage The message that is sent through the interceptor stack down to the IO layer
    7. org.apache.catalina.tribes.Member Identifies a node, implementation specific to the underlying IO logic
    tomcat7-7.0.52/java/org/apache/catalina/tribes/ChannelMessage.java0000644000175100017510000000634612271464231024673 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.io.Serializable; import org.apache.catalina.tribes.io.XByteBuffer; /** * Message that is passed through the interceptor stack after the * data serialized in the Channel object and then passed down to the * interceptor and eventually down to the ChannelSender component * @author Filip Hanik * */ public interface ChannelMessage extends Serializable { /** * Get the address that this message originated from. * Almost always Channel.getLocalMember(boolean)
    * This would be set to a different address * if the message was being relayed from a host other than the one * that originally sent it. * @return the source or reply-to address of this message */ public Member getAddress(); /** * Sets the source or reply-to address of this message * @param member Member */ public void setAddress(Member member); /** * Timestamp of when the message was created. * @return long timestamp in milliseconds */ public long getTimestamp(); /** * * Sets the timestamp of this message * @param timestamp The timestamp */ public void setTimestamp(long timestamp); /** * Each message must have a globally unique Id. * interceptors heavily depend on this id for message processing * @return byte */ public byte[] getUniqueId(); /** * The byte buffer that contains the actual message payload * @param buf XByteBuffer */ public void setMessage(XByteBuffer buf); /** * returns the byte buffer that contains the actual message payload * @return XByteBuffer */ public XByteBuffer getMessage(); /** * The message options is a 32 bit flag set * that triggers interceptors and message behavior. * @see Channel#send(Member[], Serializable, int) * @see ChannelInterceptor#getOptionFlag * @return int - the option bits set for this message */ public int getOptions(); /** * sets the option bits for this message * @param options int * @see #getOptions() */ public void setOptions(int options); /** * Shallow clone, what gets cloned depends on the implementation * @return ChannelMessage */ public Object clone(); /** * Deep clone, all fields MUST get cloned * @return ChannelMessage */ public Object deepclone(); } tomcat7-7.0.52/java/org/apache/catalina/tribes/Member.java0000644000175100017510000001021512271464231023213 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * The Member interface, defines a member in the group. * Each member can carry a set of properties, defined by the actual implementation.
    * A member is identified by the host/ip/uniqueId
    * The host is what interface the member is listening to, to receive data
    * The port is what port the member is listening to, to receive data
    * The uniqueId defines the session id for the member. This is an important feature * since a member that has crashed and the starts up again on the same port/host is * not guaranteed to be the same member, so no state transfers will ever be confused * @author Filip Hanik */ public interface Member { /** * When a member leaves the cluster, the payload of the memberDisappeared member * will be the following bytes. This indicates a soft shutdown, and not a crash */ public static final byte[] SHUTDOWN_PAYLOAD = new byte[] {66, 65, 66, 89, 45, 65, 76, 69, 88}; /** * Returns the name of this node, should be unique within the group. */ public String getName(); /** * Returns the listen host for the ChannelReceiver implementation * @return IPv4 or IPv6 representation of the host address this member listens to incoming data * @see ChannelReceiver */ public byte[] getHost(); /** * Returns the listen port for the ChannelReceiver implementation * @return the listen port for this member, -1 if its not listening on an insecure port * @see ChannelReceiver */ public int getPort(); /** * Returns the secure listen port for the ChannelReceiver implementation. * Returns -1 if its not listening to a secure port. * @return the listen port for this member, -1 if its not listening on a secure port * @see ChannelReceiver */ public int getSecurePort(); /** * Returns the UDP port that this member is listening to for UDP messages. * @return the listen UDP port for this member, -1 if its not listening on a UDP port */ public int getUdpPort(); /** * Contains information on how long this member has been online. * The result is the number of milli seconds this member has been * broadcasting its membership to the group. * @return nr of milliseconds since this member started. */ public long getMemberAliveTime(); /** * The current state of the member * @return boolean - true if the member is functioning correctly */ public boolean isReady(); /** * The current state of the member * @return boolean - true if the member is suspect, but the crash has not been confirmed */ public boolean isSuspect(); /** * * @return boolean - true if the member has been confirmed to malfunction */ public boolean isFailing(); /** * returns a UUID unique for this member over all sessions. * If the member crashes and restarts, the uniqueId will be different. * @return byte[] */ public byte[] getUniqueId(); /** * returns the payload associated with this member * @return byte[] */ public byte[] getPayload(); /** * returns the command associated with this member * @return byte[] */ public byte[] getCommand(); /** * Domain for this cluster * @return byte[] */ public byte[] getDomain(); } tomcat7-7.0.52/java/org/apache/catalina/tribes/ChannelSender.java0000644000175100017510000000515612271464231024525 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.io.IOException; /** * ChannelReceiver Interface
    * The ChannelSender interface is the data sender component * at the bottom layer, the IO layer (for layers see the javadoc for the {@link Channel} interface).
    * The channel sender must support "silent" members, ie, be able to send a message to a member * that is not in the membership, but is part of the destination parameter * @author Filip Hanik */ public interface ChannelSender extends Heartbeat { /** * Notify the sender of a member being added to the group.
    * Optional. This can be an empty implementation, that does nothing * @param member Member */ public void add(Member member); /** * Notification that a member has been removed or crashed. * Can be used to clean up open connections etc * @param member Member */ public void remove(Member member); /** * Start the channel sender * @throws IOException if preprocessing takes place and an error happens */ public void start() throws IOException; /** * Stop the channel sender */ public void stop(); /** * A channel heartbeat, use this method to clean up resources */ @Override public void heartbeat() ; /** * Send a message to one or more recipients. * @param message ChannelMessage - the message to be sent * @param destination Member[] - the destinations * @throws ChannelException - if an error happens, the ChannelSender MUST report * individual send failures on a per member basis, using ChannelException.addFaultyMember * @see ChannelException#addFaultyMember(Member,java.lang.Exception) */ public void sendMessage(ChannelMessage message, Member[] destination) throws ChannelException; } tomcat7-7.0.52/java/org/apache/catalina/tribes/Heartbeat.java0000644000175100017510000000225112271464231023704 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * Can be implemented by the ChannelListener and Membership listeners to receive heartbeat * notifications from the Channel * @author Filip Hanik * @version 1.0 * @see Channel * @see Channel#heartbeat() */ public interface Heartbeat { /** * Heartbeat invocation for resources cleanup etc */ public void heartbeat(); }tomcat7-7.0.52/java/org/apache/catalina/tribes/RemoteProcessException.java0000644000175100017510000000322512271464231026460 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** *

    Title: RemoteProcessException

    * *

    Description: Message thrown by a sender when USE_SYNC_ACK receives a FAIL_ACK_COMMAND.
    * This means that the message was received on the remote node but the processing of the message failed. * This message will be embedded in a ChannelException.FaultyMember *

    * @see ChannelException * @author Filip Hanik * @version 1.0 */ public class RemoteProcessException extends RuntimeException { private static final long serialVersionUID = 1L; public RemoteProcessException() { super(); } public RemoteProcessException(String message) { super(message); } public RemoteProcessException(String message, Throwable cause) { super(message, cause); } public RemoteProcessException(Throwable cause) { super(cause); } }tomcat7-7.0.52/java/org/apache/catalina/tribes/io/0000755000175100017510000000000012301126370021542 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/io/ReplicationStream.java0000644000175100017510000001334012271464231026042 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.io; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; /** * Custom subclass of ObjectInputStream that loads from the * class loader for this web application. This allows classes defined only * with the web application to be found correctly. * * @author Craig R. McClanahan * @author Bip Thelin * @author Filip Hanik */ public final class ReplicationStream extends ObjectInputStream { /** * The class loader we will use to resolve classes. */ private ClassLoader[] classLoaders = null; /** * Construct a new instance of CustomObjectInputStream * * @param stream The input stream we will read from * @param classLoaders The class loader array used to instantiate objects * * @exception IOException if an input/output error occurs */ public ReplicationStream(InputStream stream, ClassLoader[] classLoaders) throws IOException { super(stream); this.classLoaders = classLoaders; } /** * Load the local class equivalent of the specified stream class * description, by using the class loader assigned to this Context. * * @param classDesc Class description from the input stream * * @exception ClassNotFoundException if this class cannot be found * @exception IOException if an input/output error occurs */ @Override public Class resolveClass(ObjectStreamClass classDesc) throws ClassNotFoundException, IOException { String name = classDesc.getName(); try { return resolveClass(name); } catch (ClassNotFoundException e) { return super.resolveClass(classDesc); } } public Class resolveClass(String name) throws ClassNotFoundException, IOException { boolean tryRepFirst = name.startsWith("org.apache.catalina.tribes"); try { if (tryRepFirst) return findReplicationClass(name); else return findExternalClass(name); } catch (Exception x) { if (tryRepFirst) return findExternalClass(name); else return findReplicationClass(name); } } /** * ObjectInputStream.resolveProxyClass has some funky way of using * the incorrect class loader to resolve proxy classes, let's do it our way instead */ @Override protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { ClassLoader latestLoader; if (classLoaders != null && classLoaders.length > 0) { latestLoader = classLoaders[0]; } else { latestLoader = null; } ClassLoader nonPublicLoader = null; boolean hasNonPublicInterface = false; // define proxy in class loader of non-public interface(s), if any Class[] classObjs = new Class[interfaces.length]; for (int i = 0; i < interfaces.length; i++) { Class cl = this.resolveClass(interfaces[i]); if (latestLoader==null) latestLoader = cl.getClassLoader(); if ((cl.getModifiers() & Modifier.PUBLIC) == 0) { if (hasNonPublicInterface) { if (nonPublicLoader != cl.getClassLoader()) { throw new IllegalAccessError( "conflicting non-public interface class loaders"); } } else { nonPublicLoader = cl.getClassLoader(); hasNonPublicInterface = true; } } classObjs[i] = cl; } try { return Proxy.getProxyClass(hasNonPublicInterface ? nonPublicLoader : latestLoader, classObjs); } catch (IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } } public Class findReplicationClass(String name) throws ClassNotFoundException, IOException { Class clazz = Class.forName(name, false, getClass().getClassLoader()); return clazz; } public Class findExternalClass(String name) throws ClassNotFoundException { ClassNotFoundException cnfe = null; for (int i=0; i clazz = Class.forName(name, false, classLoaders[i]); return clazz; } catch ( ClassNotFoundException x ) { cnfe = x; } } if ( cnfe != null ) throw cnfe; else throw new ClassNotFoundException(name); } @Override public void close() throws IOException { this.classLoaders = null; super.close(); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/io/BufferPool15Impl.java0000644000175100017510000000414112271464231025447 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.io; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; /** * * @author Filip Hanik * @version 1.0 */ class BufferPool15Impl implements BufferPool.BufferPoolAPI { protected int maxSize; protected AtomicInteger size = new AtomicInteger(0); protected ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); @Override public void setMaxSize(int bytes) { this.maxSize = bytes; } @Override public XByteBuffer getBuffer(int minSize, boolean discard) { XByteBuffer buffer = queue.poll(); if ( buffer != null ) size.addAndGet(-buffer.getCapacity()); if ( buffer == null ) buffer = new XByteBuffer(minSize,discard); else if ( buffer.getCapacity() <= minSize ) buffer.expand(minSize); buffer.setDiscard(discard); buffer.reset(); return buffer; } @Override public void returnBuffer(XByteBuffer buffer) { if ( (size.get() + buffer.getCapacity()) <= maxSize ) { size.addAndGet(buffer.getCapacity()); queue.offer(buffer); } } @Override public void clear() { queue.clear(); size.set(0); } public int getMaxSize() { return maxSize; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/io/XByteBuffer.java0000644000175100017510000004730712274173771024625 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicInteger; /** * The XByteBuffer provides a dual functionality. * One, it stores message bytes and automatically extends the byte buffer if needed.
    * Two, it can encode and decode packages so that they can be defined and identified * as they come in on a socket. *
    * THIS CLASS IS NOT THREAD SAFE
    *
    * Transfer package: *
      *
    • START_DATA/b> - 7 bytes - FLT2002
    • *
    • SIZE - 4 bytes - size of the data package
    • *
    • DATA - should be as many bytes as the prev SIZE
    • *
    • END_DATA - 7 bytes - TLF2003
    • *
    * @author Filip Hanik */ public class XByteBuffer { private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( XByteBuffer.class ); /** * This is a package header, 7 bytes (FLT2002) */ private static final byte[] START_DATA = {70,76,84,50,48,48,50}; /** * This is the package footer, 7 bytes (TLF2003) */ private static final byte[] END_DATA = {84,76,70,50,48,48,51}; /** * Variable to hold the data */ protected byte[] buf = null; /** * Current length of data in the buffer */ protected int bufSize = 0; /** * Flag for discarding invalid packages * If this flag is set to true, and append(byte[],...) is called, * the data added will be inspected, and if it doesn't start with * START_DATA it will be thrown away. * */ protected boolean discard = true; /** * Constructs a new XByteBuffer.
    * TODO use a pool of byte[] for performance * @param size - the initial size of the byte buffer */ public XByteBuffer(int size, boolean discard) { buf = new byte[size]; this.discard = discard; } public XByteBuffer(byte[] data,boolean discard) { this(data,data.length+128,discard); } public XByteBuffer(byte[] data, int size,boolean discard) { int length = Math.max(data.length,size); buf = new byte[length]; System.arraycopy(data,0,buf,0,data.length); bufSize = data.length; this.discard = discard; } public int getLength() { return bufSize; } public void setLength(int size) { if ( size > buf.length ) throw new ArrayIndexOutOfBoundsException("Size is larger than existing buffer."); bufSize = size; } public void trim(int length) { if ( (bufSize - length) < 0 ) throw new ArrayIndexOutOfBoundsException("Can't trim more bytes than are available. length:"+bufSize+" trim:"+length); bufSize -= length; } public void reset() { bufSize = 0; } public byte[] getBytesDirect() { return this.buf; } /** * Returns the bytes in the buffer, in its exact length */ public byte[] getBytes() { byte[] b = new byte[bufSize]; System.arraycopy(buf,0,b,0,bufSize); return b; } /** * Resets the buffer */ public void clear() { bufSize = 0; } /** * Appends the data to the buffer. If the data is incorrectly formatted, ie, the data should always start with the * header, false will be returned and the data will be discarded. * @param b - bytes to be appended * @param len - the number of bytes to append. * @return true if the data was appended correctly. Returns false if the package is incorrect, ie missing header or something, or the length of data is 0 */ public boolean append(ByteBuffer b, int len) { int newcount = bufSize + len; if (newcount > buf.length) { expand(newcount); } b.get(buf,bufSize,len); bufSize = newcount; if ( discard ) { if (bufSize > START_DATA.length && (firstIndexOf(buf, 0, START_DATA) == -1)) { bufSize = 0; log.error("Discarded the package, invalid header"); return false; } } return true; } public boolean append(byte i) { int newcount = bufSize + 1; if (newcount > buf.length) { expand(newcount); } buf[bufSize] = i; bufSize = newcount; return true; } public boolean append(boolean i) { int newcount = bufSize + 1; if (newcount > buf.length) { expand(newcount); } XByteBuffer.toBytes(i,buf,bufSize); bufSize = newcount; return true; } public boolean append(long i) { int newcount = bufSize + 8; if (newcount > buf.length) { expand(newcount); } XByteBuffer.toBytes(i,buf,bufSize); bufSize = newcount; return true; } public boolean append(int i) { int newcount = bufSize + 4; if (newcount > buf.length) { expand(newcount); } XByteBuffer.toBytes(i,buf,bufSize); bufSize = newcount; return true; } public boolean append(byte[] b, int off, int len) { if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return false; } int newcount = bufSize + len; if (newcount > buf.length) { expand(newcount); } System.arraycopy(b, off, buf, bufSize, len); bufSize = newcount; if ( discard ) { if (bufSize > START_DATA.length && (firstIndexOf(buf, 0, START_DATA) == -1)) { bufSize = 0; log.error("Discarded the package, invalid header"); return false; } } return true; } public void expand(int newcount) { //don't change the allocation strategy byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)]; System.arraycopy(buf, 0, newbuf, 0, bufSize); buf = newbuf; } public int getCapacity() { return buf.length; } /** * Internal mechanism to make a check if a complete package exists * within the buffer * @return - true if a complete package (header,compress,size,data,footer) exists within the buffer */ public int countPackages() { return countPackages(false); } public int countPackages(boolean first) { int cnt = 0; int pos = START_DATA.length; int start = 0; while ( start < bufSize ) { //first check start header int index = XByteBuffer.firstIndexOf(buf,start,START_DATA); //if the header (START_DATA) isn't the first thing or //the buffer isn't even 14 bytes if ( index != start || ((bufSize-start)<14) ) break; //next 4 bytes are compress flag not needed for count packages //then get the size 4 bytes int size = toInt(buf, pos); //now the total buffer has to be long enough to hold //START_DATA.length+4+size+END_DATA.length pos = start + START_DATA.length + 4 + size; if ( (pos + END_DATA.length) > bufSize) break; //and finally check the footer of the package END_DATA int newpos = firstIndexOf(buf, pos, END_DATA); //mismatch, there is no package if (newpos != pos) break; //increase the packet count cnt++; //reset the values start = pos + END_DATA.length; pos = start + START_DATA.length; //we only want to verify that we have at least one package if ( first ) break; } return cnt; } /** * Method to check if a package exists in this byte buffer. * @return - true if a complete package (header,options,size,data,footer) exists within the buffer */ public boolean doesPackageExist() { return (countPackages(true)>0); } /** * Extracts the message bytes from a package. * If no package exists, a IllegalStateException will be thrown. * @param clearFromBuffer - if true, the package will be removed from the byte buffer * @return - returns the actual message bytes (header, compress,size and footer not included). */ public XByteBuffer extractDataPackage(boolean clearFromBuffer) { int psize = countPackages(true); if (psize == 0) { throw new java.lang.IllegalStateException("No package exists in XByteBuffer"); } int size = toInt(buf, START_DATA.length); XByteBuffer xbuf = BufferPool.getBufferPool().getBuffer(size,false); xbuf.setLength(size); System.arraycopy(buf, START_DATA.length + 4, xbuf.getBytesDirect(), 0, size); if (clearFromBuffer) { int totalsize = START_DATA.length + 4 + size + END_DATA.length; bufSize = bufSize - totalsize; System.arraycopy(buf, totalsize, buf, 0, bufSize); } return xbuf; } public ChannelData extractPackage(boolean clearFromBuffer) throws java.io.IOException { XByteBuffer xbuf = extractDataPackage(clearFromBuffer); ChannelData cdata = ChannelData.getDataFromPackage(xbuf); return cdata; } /** * Creates a complete data package * @param cdata - the message data to be contained within the package * @return - a full package (header,size,data,footer) */ public static byte[] createDataPackage(ChannelData cdata) { // return createDataPackage(cdata.getDataPackage()); //avoid one extra byte array creation int dlength = cdata.getDataPackageLength(); int length = getDataPackageLength(dlength); byte[] data = new byte[length]; int offset = 0; System.arraycopy(START_DATA, 0, data, offset, START_DATA.length); offset += START_DATA.length; toBytes(dlength,data, START_DATA.length); offset += 4; cdata.getDataPackage(data,offset); offset += dlength; System.arraycopy(END_DATA, 0, data, offset, END_DATA.length); offset += END_DATA.length; return data; } public static byte[] createDataPackage(byte[] data, int doff, int dlength, byte[] buffer, int bufoff) { if ( (buffer.length-bufoff) > getDataPackageLength(dlength) ) { throw new ArrayIndexOutOfBoundsException("Unable to create data package, buffer is too small."); } System.arraycopy(START_DATA, 0, buffer, bufoff, START_DATA.length); toBytes(data.length,buffer, bufoff+START_DATA.length); System.arraycopy(data, doff, buffer, bufoff+START_DATA.length + 4, dlength); System.arraycopy(END_DATA, 0, buffer, bufoff+START_DATA.length + 4 + data.length, END_DATA.length); return buffer; } public static int getDataPackageLength(int datalength) { int length = START_DATA.length + //header length 4 + //data length indicator datalength + //actual data length END_DATA.length; //footer length return length; } public static byte[] createDataPackage(byte[] data) { int length = getDataPackageLength(data.length); byte[] result = new byte[length]; return createDataPackage(data,0,data.length,result,0); } // public static void fillDataPackage(byte[] data, int doff, int dlength, XByteBuffer buf) { // int pkglen = getDataPackageLength(dlength); // if ( buf.getCapacity() < pkglen ) buf.expand(pkglen); // createDataPackage(data,doff,dlength,buf.getBytesDirect(),buf.getLength()); // } /** * Convert four bytes to an int * @param b - the byte array containing the four bytes * @param off - the offset * @return the integer value constructed from the four bytes * @exception java.lang.ArrayIndexOutOfBoundsException */ public static int toInt(byte[] b,int off){ return ( ( b[off+3]) & 0xFF) + ( ( ( b[off+2]) & 0xFF) << 8) + ( ( ( b[off+1]) & 0xFF) << 16) + ( ( ( b[off+0]) & 0xFF) << 24); } /** * Convert eight bytes to a long * @param b - the byte array containing the four bytes * @param off - the offset * @return the long value constructed from the eight bytes * @exception java.lang.ArrayIndexOutOfBoundsException */ public static long toLong(byte[] b,int off){ return ( ( (long) b[off+7]) & 0xFF) + ( ( ( (long) b[off+6]) & 0xFF) << 8) + ( ( ( (long) b[off+5]) & 0xFF) << 16) + ( ( ( (long) b[off+4]) & 0xFF) << 24) + ( ( ( (long) b[off+3]) & 0xFF) << 32) + ( ( ( (long) b[off+2]) & 0xFF) << 40) + ( ( ( (long) b[off+1]) & 0xFF) << 48) + ( ( ( (long) b[off+0]) & 0xFF) << 56); } /** * Converts a boolean to a 1-byte array * @param bool - the integer * @return - 1-byte array * @deprecated use toBytes(boolean,byte[],int) */ @Deprecated public static byte[] toBytes(boolean bool) { byte[] b = new byte[1] ; return toBytes(bool,b,0); } public static byte[] toBytes(boolean bool, byte[] data, int offset) { data[offset] = (byte)(bool?1:0); return data; } /** * Converts a byte array entry to boolean * @param b byte array * @param offset within byte array * @return true if byte array entry is non-zero, false otherwise */ public static boolean toBoolean(byte[] b, int offset) { return b[offset] != 0; } /** * Converts an integer to four bytes * @param n - the integer * @return - four bytes in an array * @deprecated use toBytes(int,byte[],int) */ @Deprecated public static byte[] toBytes(int n) { return toBytes(n,new byte[4],0); } public static byte[] toBytes(int n,byte[] b, int offset) { b[offset+3] = (byte) (n); n >>>= 8; b[offset+2] = (byte) (n); n >>>= 8; b[offset+1] = (byte) (n); n >>>= 8; b[offset+0] = (byte) (n); return b; } /** * Converts an long to eight bytes * @param n - the long * @return - eight bytes in an array * @deprecated use toBytes(long,byte[],int) */ @Deprecated public static byte[] toBytes(long n) { return toBytes(n,new byte[8],0); } public static byte[] toBytes(long n, byte[] b, int offset) { b[offset+7] = (byte) (n); n >>>= 8; b[offset+6] = (byte) (n); n >>>= 8; b[offset+5] = (byte) (n); n >>>= 8; b[offset+4] = (byte) (n); n >>>= 8; b[offset+3] = (byte) (n); n >>>= 8; b[offset+2] = (byte) (n); n >>>= 8; b[offset+1] = (byte) (n); n >>>= 8; b[offset+0] = (byte) (n); return b; } /** * Similar to a String.IndexOf, but uses pure bytes * @param src - the source bytes to be searched * @param srcOff - offset on the source buffer * @param find - the string to be found within src * @return - the index of the first matching byte. -1 if the find array is not found */ public static int firstIndexOf(byte[] src, int srcOff, byte[] find){ int result = -1; if (find.length > src.length) return result; if (find.length == 0 || src.length == 0) return result; if (srcOff >= src.length ) throw new java.lang.ArrayIndexOutOfBoundsException(); boolean found = false; int srclen = src.length; int findlen = find.length; byte first = find[0]; int pos = srcOff; while (!found) { //find the first byte while (pos < srclen){ if (first == src[pos]) break; pos++; } if (pos >= srclen) return -1; //we found the first character //match the rest of the bytes - they have to match if ( (srclen - pos) < findlen) return -1; //assume it does exist found = true; for (int i = 1; ( (i < findlen) && found); i++) found = found && (find[i] == src[pos + i]); if (found) result = pos; else if ( (srclen - pos) < findlen) return -1; //no more matches possible else pos++; } return result; } public static Serializable deserialize(byte[] data) throws IOException, ClassNotFoundException, ClassCastException { return deserialize(data,0,data.length); } public static Serializable deserialize(byte[] data, int offset, int length) throws IOException, ClassNotFoundException, ClassCastException { return deserialize(data,offset,length,null); } private static AtomicInteger invokecount = new AtomicInteger(0); public static Serializable deserialize(byte[] data, int offset, int length, ClassLoader[] cls) throws IOException, ClassNotFoundException, ClassCastException { invokecount.addAndGet(1); Object message = null; if ( cls == null ) cls = new ClassLoader[0]; if (data != null && length > 0) { InputStream instream = new ByteArrayInputStream(data,offset,length); ObjectInputStream stream = null; stream = (cls.length>0)? new ReplicationStream(instream,cls):new ObjectInputStream(instream); message = stream.readObject(); instream.close(); stream.close(); } if ( message == null ) { return null; } else if (message instanceof Serializable) return (Serializable) message; else { throw new ClassCastException("Message has the wrong class. It should implement Serializable, instead it is:"+message.getClass().getName()); } } /** * Serializes a message into cluster data * @param msg ClusterMessage * @return serialized content as byte[] array * @throws IOException */ public static byte[] serialize(Serializable msg) throws IOException { ByteArrayOutputStream outs = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(outs); out.writeObject(msg); out.flush(); byte[] data = outs.toByteArray(); return data; } public void setDiscard(boolean discard) { this.discard = discard; } public boolean getDiscard() { return discard; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/io/ListenCallback.java0000644000175100017510000000302012271464231025262 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.io; import org.apache.catalina.tribes.ChannelMessage; /** * Internal interface, similar to the MessageListener but used * at the IO base * The listen callback interface is used by the replication system * when data has been received. The interface does not care about * objects and marshalling and just passes the bytes straight through. * @author Filip Hanik */ public interface ListenCallback { /** * This method is invoked on the callback object to notify it that new data has * been received from one of the cluster nodes. * @param data - the message bytes received from the cluster/replication system */ public void messageDataReceived(ChannelMessage data); }tomcat7-7.0.52/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java0000644000175100017510000000356412271464231030056 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.io; import java.io.IOException; import java.io.OutputStream; /** * Byte array output stream that exposes the byte array directly * * @author not attributable * @version 1.0 */ public class DirectByteArrayOutputStream extends OutputStream { private XByteBuffer buffer; public DirectByteArrayOutputStream(int size) { buffer = new XByteBuffer(size,false); } /** * Writes the specified byte to this output stream. * * @param b the byte. * @throws IOException if an I/O error occurs. In particular, an * IOException may be thrown if the output stream has * been closed. * TODO Implement this java.io.OutputStream method */ @Override public void write(int b) throws IOException { buffer.append((byte)b); } public int size() { return buffer.getLength(); } public byte[] getArrayDirect() { return buffer.getBytesDirect(); } public byte[] getArray() { return buffer.getBytes(); } }tomcat7-7.0.52/java/org/apache/catalina/tribes/io/BufferPool.java0000644000175100017510000000621112271464231024457 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.io; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * * @author Filip Hanik * * @version 1.0 */ public class BufferPool { private static final Log log = LogFactory.getLog(BufferPool.class); public static final int DEFAULT_POOL_SIZE = 100*1024*1024; //100MB protected static volatile BufferPool instance = null; protected BufferPoolAPI pool = null; private BufferPool(BufferPoolAPI pool) { this.pool = pool; } public XByteBuffer getBuffer(int minSize, boolean discard) { if ( pool != null ) return pool.getBuffer(minSize, discard); else return new XByteBuffer(minSize,discard); } public void returnBuffer(XByteBuffer buffer) { if ( pool != null ) pool.returnBuffer(buffer); } public void clear() { if ( pool != null ) pool.clear(); } public static BufferPool getBufferPool() { if ( (instance == null) ) { synchronized (BufferPool.class) { if ( instance == null ) { BufferPoolAPI pool = null; Class clazz = null; try { // TODO Is this approach still required? clazz = Class.forName("org.apache.catalina.tribes.io.BufferPool15Impl"); pool = (BufferPoolAPI)clazz.newInstance(); } catch ( Throwable x ) { log.warn("Unable to initilize BufferPool, not pooling XByteBuffer objects:"+x.getMessage()); if ( log.isDebugEnabled() ) log.debug("Unable to initilize BufferPool, not pooling XByteBuffer objects:",x); } if (pool != null) { pool.setMaxSize(DEFAULT_POOL_SIZE); log.info("Created a buffer pool with max size:"+DEFAULT_POOL_SIZE+" bytes of type:"+(clazz!=null?clazz.getName():"null")); instance = new BufferPool(pool); } }//end if }//sync }//end if return instance; } public static interface BufferPoolAPI { public void setMaxSize(int bytes); public XByteBuffer getBuffer(int minSize, boolean discard); public void returnBuffer(XByteBuffer buffer); public void clear(); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/io/ChannelData.java0000644000175100017510000003063212271464231024562 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.io; import java.sql.Timestamp; import java.util.Arrays; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.membership.MemberImpl; import org.apache.catalina.tribes.util.UUIDGenerator; /** * The ChannelData object is used to transfer a message through the * channel interceptor stack and eventually out on a transport to be sent * to another node. While the message is being processed by the different * interceptors, the message data can be manipulated as each interceptor seems appropriate. * @author Peter Rossbach * @author Filip Hanik */ public class ChannelData implements ChannelMessage { private static final long serialVersionUID = 1L; public static final ChannelData[] EMPTY_DATA_ARRAY = new ChannelData[0]; public static volatile boolean USE_SECURE_RANDOM_FOR_UUID = false; /** * The options this message was sent with */ private int options = 0 ; /** * The message data, stored in a dynamic buffer */ private XByteBuffer message ; /** * The timestamp that goes with this message */ private long timestamp ; /** * A unique message id */ private byte[] uniqueId ; /** * The source or reply-to address for this message */ private Member address; /** * Creates an empty channel data with a new unique Id * @see #ChannelData(boolean) */ public ChannelData() { this(true); } /** * Create an empty channel data object * @param generateUUID boolean - if true, a unique Id will be generated */ public ChannelData(boolean generateUUID) { if ( generateUUID ) generateUUID(); } /** * Creates a new channel data object with data * @param uniqueId - unique message id * @param message - message data * @param timestamp - message timestamp */ public ChannelData(byte[] uniqueId, XByteBuffer message, long timestamp) { this.uniqueId = uniqueId; this.message = message; this.timestamp = timestamp; } /** * @return Returns the message byte buffer */ @Override public XByteBuffer getMessage() { return message; } /** * @param message The message to send. */ @Override public void setMessage(XByteBuffer message) { this.message = message; } /** * @return Returns the timestamp. */ @Override public long getTimestamp() { return timestamp; } /** * @param timestamp The timestamp to send */ @Override public void setTimestamp(long timestamp) { this.timestamp = timestamp; } /** * @return Returns the uniqueId. */ @Override public byte[] getUniqueId() { return uniqueId; } /** * @param uniqueId The uniqueId to send. */ public void setUniqueId(byte[] uniqueId) { this.uniqueId = uniqueId; } /** * @return returns the message options * see org.apache.catalina.tribes.Channel#sendMessage(org.apache.catalina.tribes.Member[], java.io.Serializable, int) * */ @Override public int getOptions() { return options; } /** * Sets the message options. * * @param options the message options */ @Override public void setOptions(int options) { this.options = options; } /** * Returns the source or reply-to address * @return Member */ @Override public Member getAddress() { return address; } /** * Sets the source or reply-to address * @param address Member */ @Override public void setAddress(Member address) { this.address = address; } /** * Generates a UUID and invokes setUniqueId */ public void generateUUID() { byte[] data = new byte[16]; UUIDGenerator.randomUUID(USE_SECURE_RANDOM_FOR_UUID,data,0); setUniqueId(data); } public int getDataPackageLength() { int length = 4 + //options 8 + //timestamp off=4 4 + //unique id length off=12 uniqueId.length+ //id data off=12+uniqueId.length 4 + //addr length off=12+uniqueId.length+4 ((MemberImpl)address).getDataLength()+ //member data off=12+uniqueId.length+4+add.length 4 + //message length off=12+uniqueId.length+4+add.length+4 message.getLength(); return length; } /** * Serializes the ChannelData object into a byte[] array * @return byte[] */ public byte[] getDataPackage() { int length = getDataPackageLength(); byte[] data = new byte[length]; int offset = 0; return getDataPackage(data,offset); } public byte[] getDataPackage(byte[] data, int offset) { byte[] addr = ((MemberImpl)address).getData(false); XByteBuffer.toBytes(options,data,offset); offset += 4; //options XByteBuffer.toBytes(timestamp,data,offset); offset += 8; //timestamp XByteBuffer.toBytes(uniqueId.length,data,offset); offset += 4; //uniqueId.length System.arraycopy(uniqueId,0,data,offset,uniqueId.length); offset += uniqueId.length; //uniqueId data XByteBuffer.toBytes(addr.length,data,offset); offset += 4; //addr.length System.arraycopy(addr,0,data,offset,addr.length); offset += addr.length; //addr data XByteBuffer.toBytes(message.getLength(),data,offset); offset += 4; //message.length System.arraycopy(message.getBytesDirect(),0,data,offset,message.getLength()); offset += message.getLength(); //message data return data; } /** * Deserializes a ChannelData object from a byte array * @param xbuf byte[] * @return ChannelData */ public static ChannelData getDataFromPackage(XByteBuffer xbuf) { ChannelData data = new ChannelData(false); int offset = 0; data.setOptions(XByteBuffer.toInt(xbuf.getBytesDirect(),offset)); offset += 4; //options data.setTimestamp(XByteBuffer.toLong(xbuf.getBytesDirect(),offset)); offset += 8; //timestamp data.uniqueId = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)]; offset += 4; //uniqueId length System.arraycopy(xbuf.getBytesDirect(),offset,data.uniqueId,0,data.uniqueId.length); offset += data.uniqueId.length; //uniqueId data //byte[] addr = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)]; int addrlen = XByteBuffer.toInt(xbuf.getBytesDirect(),offset); offset += 4; //addr length //System.arraycopy(xbuf.getBytesDirect(),offset,addr,0,addr.length); data.setAddress(MemberImpl.getMember(xbuf.getBytesDirect(),offset,addrlen)); //offset += addr.length; //addr data offset += addrlen; int xsize = XByteBuffer.toInt(xbuf.getBytesDirect(),offset); offset += 4; //xsize length System.arraycopy(xbuf.getBytesDirect(),offset,xbuf.getBytesDirect(),0,xsize); xbuf.setLength(xsize); data.message = xbuf; return data; } public static ChannelData getDataFromPackage(byte[] b) { ChannelData data = new ChannelData(false); int offset = 0; data.setOptions(XByteBuffer.toInt(b,offset)); offset += 4; //options data.setTimestamp(XByteBuffer.toLong(b,offset)); offset += 8; //timestamp data.uniqueId = new byte[XByteBuffer.toInt(b,offset)]; offset += 4; //uniqueId length System.arraycopy(b,offset,data.uniqueId,0,data.uniqueId.length); offset += data.uniqueId.length; //uniqueId data byte[] addr = new byte[XByteBuffer.toInt(b,offset)]; offset += 4; //addr length System.arraycopy(b,offset,addr,0,addr.length); data.setAddress(MemberImpl.getMember(addr)); offset += addr.length; //addr data int xsize = XByteBuffer.toInt(b,offset); //data.message = new XByteBuffer(new byte[xsize],false); data.message = BufferPool.getBufferPool().getBuffer(xsize,false); offset += 4; //message length System.arraycopy(b,offset,data.message.getBytesDirect(),0,xsize); data.message.append(b,offset,xsize); offset += xsize; //message data return data; } @Override public int hashCode() { return XByteBuffer.toInt(getUniqueId(),0); } /** * Compares to ChannelData objects, only compares on getUniqueId().equals(o.getUniqueId()) * @param o Object * @return boolean */ @Override public boolean equals(Object o) { if ( o instanceof ChannelData ) { return Arrays.equals(getUniqueId(),((ChannelData)o).getUniqueId()); } else return false; } /** * Create a shallow clone, only the data gets recreated * @return ClusterData */ @Override public Object clone() { // byte[] d = this.getDataPackage(); // return ClusterData.getDataFromPackage(d); ChannelData clone = new ChannelData(false); clone.options = this.options; clone.message = new XByteBuffer(this.message.getBytesDirect(),false); clone.timestamp = this.timestamp; clone.uniqueId = this.uniqueId; clone.address = this.address; return clone; } /** * Complete clone * @return ClusterData */ @Override public Object deepclone() { byte[] d = this.getDataPackage(); return ChannelData.getDataFromPackage(d); } /** * Utility method, returns true if the options flag indicates that an ack * is to be sent after the message has been received and processed * @param options int - the options for the message * @return boolean * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK */ public static boolean sendAckSync(int options) { return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) && ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) == Channel.SEND_OPTIONS_SYNCHRONIZED_ACK); } /** * Utility method, returns true if the options flag indicates that an ack * is to be sent after the message has been received but not yet processed * @param options int - the options for the message * @return boolean * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK */ public static boolean sendAckAsync(int options) { return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) && ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) != Channel.SEND_OPTIONS_SYNCHRONIZED_ACK); } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("ClusterData[src="); buf.append(getAddress()).append("; id="); buf.append(bToS(getUniqueId())).append("; sent="); buf.append(new Timestamp(this.getTimestamp()).toString()).append("]"); return buf.toString(); } public static String bToS(byte[] data) { StringBuilder buf = new StringBuilder(4*16); buf.append("{"); for (int i=0; data!=null && iXByteBuffer until a full package has been received. * This object uses an XByteBuffer which is an extendable object buffer that also allows * for message encoding and decoding. * * @author Filip Hanik */ public class ObjectReader { private static final Log log = LogFactory.getLog(ObjectReader.class); private XByteBuffer buffer; protected long lastAccess = System.currentTimeMillis(); protected boolean accessed = false; private boolean cancelled; public ObjectReader(int packetSize) { this.buffer = new XByteBuffer(packetSize, true); } /** * Creates an ObjectReader for a TCP NIO socket channel * @param channel - the channel to be read. */ public ObjectReader(SocketChannel channel) { this(channel.socket()); } /** * Creates an ObjectReader for a TCP socket * @param socket Socket */ public ObjectReader(Socket socket) { try{ this.buffer = new XByteBuffer(socket.getReceiveBufferSize(), true); }catch ( IOException x ) { //unable to get buffer size log.warn("Unable to retrieve the socket receiver buffer size, setting to default 43800 bytes."); this.buffer = new XByteBuffer(43800,true); } } public synchronized void access() { this.accessed = true; this.lastAccess = System.currentTimeMillis(); } public synchronized void finish() { this.accessed = false; this.lastAccess = System.currentTimeMillis(); } public boolean isAccessed() { return this.accessed; } /** * Append new bytes to buffer. * @see XByteBuffer#countPackages() * @param data new transfer buffer * @param len length in buffer * @param count whether to return the count * @return number of messages that was sent to callback (or -1 if count == false) * @throws java.io.IOException */ public int append(ByteBuffer data, int len, boolean count) throws java.io.IOException { buffer.append(data,len); int pkgCnt = -1; if ( count ) pkgCnt = buffer.countPackages(); return pkgCnt; } public int append(byte[] data,int off,int len, boolean count) throws java.io.IOException { buffer.append(data,off,len); int pkgCnt = -1; if ( count ) pkgCnt = buffer.countPackages(); return pkgCnt; } /** * Send buffer to cluster listener (callback). * Is message complete receiver send message to callback? * * @see org.apache.catalina.tribes.transport.ReceiverBase#messageDataReceived(ChannelMessage) * @see XByteBuffer#doesPackageExist() * @see XByteBuffer#extractPackage(boolean) * * @return number of received packages/messages * @throws java.io.IOException */ public ChannelMessage[] execute() throws java.io.IOException { int pkgCnt = buffer.countPackages(); ChannelMessage[] result = new ChannelMessage[pkgCnt]; for (int i=0; i0; } /** * Returns the number of packages that the reader has read * @return int */ public int count() { return buffer.countPackages(); } public void close() { this.buffer = null; } public long getLastAccess() { return lastAccess; } public boolean isCancelled() { return cancelled; } public void setLastAccess(long lastAccess) { this.lastAccess = lastAccess; } public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/MessageListener.java0000644000175100017510000000261112271464231025077 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * *

    Title: MessageListener

    * *

    Description: The listener to be registered with the ChannelReceiver, internal Tribes component

    * * @author Filip Hanik * @version 1.0 */ public interface MessageListener { /** * Receive a message from the IO components in the Channel stack * @param msg ChannelMessage */ public void messageReceived(ChannelMessage msg); public boolean accept(ChannelMessage msg); @Override public boolean equals(Object listener); @Override public int hashCode(); } tomcat7-7.0.52/java/org/apache/catalina/tribes/Constants.java0000644000175100017510000000217712271464231023770 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * Manifest constants for the org.apache.catalina.tribes * package. * * @author Bip Thelin * @author Filip Hanik * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public final class Constants { public static final String Package = "org.apache.catalina.tribes"; } tomcat7-7.0.52/java/org/apache/catalina/tribes/ChannelInterceptor.java0000644000175100017510000001635312271464231025604 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import org.apache.catalina.tribes.group.InterceptorPayload; /** * A ChannelInterceptor is an interceptor that intercepts * messages and membership messages in the channel stack. * This allows interceptors to modify the message or perform * other actions when a message is sent or received.
    * Interceptors are tied together in a linked list. * @see org.apache.catalina.tribes.group.ChannelInterceptorBase * @author Filip Hanik */ public interface ChannelInterceptor extends MembershipListener, Heartbeat { /** * An interceptor can react to a message based on a set bit on the * message options.
    * When a message is sent, the options can be retrieved from ChannelMessage.getOptions() * and if the bit is set, this interceptor will react to it.
    * A simple evaluation if an interceptor should react to the message would be:
    * boolean react = (getOptionFlag() == (getOptionFlag() & ChannelMessage.getOptions()));
    * The default option is 0, meaning there is no way for the application to trigger the * interceptor. The interceptor itself will decide.
    * @return int * @see ChannelMessage#getOptions() */ public int getOptionFlag(); /** * Sets the option flag * @param flag int * @see #getOptionFlag() */ public void setOptionFlag(int flag); /** * Set the next interceptor in the list of interceptors * @param next ChannelInterceptor */ public void setNext(ChannelInterceptor next) ; /** * Retrieve the next interceptor in the list * @return ChannelInterceptor - returns the next interceptor in the list or null if no more interceptors exist */ public ChannelInterceptor getNext(); /** * Set the previous interceptor in the list * @param previous ChannelInterceptor */ public void setPrevious(ChannelInterceptor previous); /** * Retrieve the previous interceptor in the list * @return ChannelInterceptor - returns the previous interceptor in the list or null if no more interceptors exist */ public ChannelInterceptor getPrevious(); /** * The sendMessage method is called when a message is being sent to one more destinations. * The interceptor can modify any of the parameters and then pass on the message down the stack by * invoking getNext().sendMessage(destination,msg,payload)
    * Alternatively the interceptor can stop the message from being sent by not invoking * getNext().sendMessage(destination,msg,payload)
    * If the message is to be sent asynchronous the application can be notified of completion and * errors by passing in an error handler attached to a payload object.
    * The ChannelMessage.getAddress contains Channel.getLocalMember, and can be overwritten * to simulate a message sent from another node.
    * @param destination Member[] - the destination for this message * @param msg ChannelMessage - the message to be sent * @param payload InterceptorPayload - the payload, carrying an error handler and future useful data, can be null * @throws ChannelException * @see ErrorHandler * @see InterceptorPayload */ public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException; /** * the messageReceived is invoked when a message is received. * ChannelMessage.getAddress() is the sender, or the reply-to address * if it has been overwritten. * @param data ChannelMessage */ public void messageReceived(ChannelMessage data); /** * The heartbeat() method gets invoked periodically * to allow interceptors to clean up resources, time out object and * perform actions that are unrelated to sending/receiving data. */ @Override public void heartbeat(); /** * Intercepts the Channel.hasMembers() method * @return boolean - if the channel has members in its membership group * @see Channel#hasMembers() */ public boolean hasMembers() ; /** * Intercepts the code>Channel.getMembers() method * @return Member[] * @see Channel#getMembers() */ public Member[] getMembers() ; /** * Intercepts the code>Channel.getLocalMember(boolean) method * @param incAliveTime boolean * @return Member * @see Channel#getLocalMember(boolean) */ public Member getLocalMember(boolean incAliveTime) ; /** * Intercepts the code>Channel.getMember(Member) method * @param mbr Member * @return Member - the actual member information, including stay alive * @see Channel#getMember(Member) */ public Member getMember(Member mbr); /** * Starts up the channel. This can be called multiple times for individual services to start * The svc parameter can be the logical or value of any constants * @param svc int value of
    * Channel.DEFAULT - will start all services
    * Channel.MBR_RX_SEQ - starts the membership receiver
    * Channel.MBR_TX_SEQ - starts the membership broadcaster
    * Channel.SND_TX_SEQ - starts the replication transmitter
    * Channel.SND_RX_SEQ - starts the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. * @see Channel */ public void start(int svc) throws ChannelException; /** * Shuts down the channel. This can be called multiple times for individual services to shutdown * The svc parameter can be the logical or value of any constants * @param svc int value of
    * Channel.DEFAULT - will shutdown all services
    * Channel.MBR_RX_SEQ - stops the membership receiver
    * Channel.MBR_TX_SEQ - stops the membership broadcaster
    * Channel.SND_TX_SEQ - stops the replication transmitter
    * Channel.SND_RX_SEQ - stops the replication receiver
    * @throws ChannelException if a startup error occurs or the service is already started. * @see Channel */ public void stop(int svc) throws ChannelException; public void fireInterceptorEvent(InterceptorEvent event); interface InterceptorEvent { int getEventType(); String getEventTypeDesc(); ChannelInterceptor getInterceptor(); } } tomcat7-7.0.52/java/org/apache/catalina/tribes/util/0000755000175100017510000000000012301126370022110 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/tribes/util/UUIDGenerator.java0000644000175100017510000000650412271464231025404 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.util; import java.security.SecureRandom; import java.util.Random; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * simple generation of a UUID * @author Filip Hanik * @version 1.0 */ public class UUIDGenerator { private static final Log log = LogFactory.getLog(UUIDGenerator.class); protected static final StringManager sm = StringManager.getManager("org.apache.catalina.tribes.util"); public static final int UUID_LENGTH = 16; public static final int UUID_VERSION = 4; public static final int BYTES_PER_INT = 4; public static final int BITS_PER_BYTE = 8; protected static SecureRandom secrand = null; protected static Random rand = new Random(); static { long start = System.currentTimeMillis(); secrand = new SecureRandom(); // seed the generator secrand.nextInt(); long time = System.currentTimeMillis() - start; if (time > 100) { log.info(sm.getString("uuidGenerator.createRandom", secrand.getAlgorithm(), Long.valueOf(time))); } } public static byte[] randomUUID(boolean secure) { byte[] result = new byte[UUID_LENGTH]; return randomUUID(secure,result,0); } public static byte[] randomUUID(boolean secure, byte[] into, int offset) { if ( (offset+UUID_LENGTH)>into.length ) throw new ArrayIndexOutOfBoundsException("Unable to fit "+UUID_LENGTH+" bytes into the array. length:"+into.length+" required length:"+(offset+UUID_LENGTH)); Random r = (secure&&(secrand!=null))?secrand:rand; nextBytes(into,offset,UUID_LENGTH,r); into[6+offset] &= 0x0F; into[6+offset] |= (UUID_VERSION << 4); into[8+offset] &= 0x3F; //0011 1111 into[8+offset] |= 0x80; //1000 0000 return into; } /** * Same as java.util.Random.nextBytes except this one we dont have to allocate a new byte array * @param into byte[] * @param offset int * @param length int * @param r Random */ public static void nextBytes(byte[] into, int offset, int length, Random r) { int numRequested = length; int numGot = 0, rnd = 0; while (true) { for (int i = 0; i < BYTES_PER_INT; i++) { if (numGot == numRequested) return; rnd = (i == 0 ? r.nextInt() : rnd >> BITS_PER_BYTE); into[offset+numGot] = (byte) rnd; numGot++; } } } }tomcat7-7.0.52/java/org/apache/catalina/tribes/util/TcclThreadFactory.java0000644000175100017510000000523712211066351026331 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.util; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * ThreadFactory implementation that creates threads with the thread context * class loader set to the class loader that loaded this factory. It is intended * to be used when tasks may be passed to executors when the web application * class loader is set as the thread context class loader, such as in async * session replication. */ public class TcclThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; public TcclThreadFactory() { this("pool-" + poolNumber.getAndIncrement() + "-thread-"); } public TcclThreadFactory(String namePrefix) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.namePrefix = namePrefix; } @Override public Thread newThread(Runnable r) { final Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement()); if (IS_SECURITY_ENABLED) { AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { t.setContextClassLoader(this.getClass().getClassLoader()); return null; } }); } else { t.setContextClassLoader(this.getClass().getClassLoader()); } return t; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/util/Arrays.java0000644000175100017510000001776512271464231024243 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes.util; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import org.apache.catalina.tribes.ChannelMessage; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.UniqueId; import org.apache.catalina.tribes.group.AbsoluteOrder; import org.apache.catalina.tribes.membership.MemberImpl; import org.apache.catalina.tribes.membership.Membership; /** * @author Filip Hanik * @version 1.0 */ public class Arrays { private static final Charset CHARSET_ISO_8859_1 = Charset.forName("ISO-8859-1"); public static boolean contains(byte[] source, int srcoffset, byte[] key, int keyoffset, int length) { if ( srcoffset < 0 || srcoffset >= source.length) throw new ArrayIndexOutOfBoundsException("srcoffset is out of bounds."); if ( keyoffset < 0 || keyoffset >= key.length) throw new ArrayIndexOutOfBoundsException("keyoffset is out of bounds."); if ( length > (key.length-keyoffset) ) throw new ArrayIndexOutOfBoundsException("not enough data elements in the key, length is out of bounds."); //we don't have enough data to validate it if ( length > (source.length-srcoffset) ) return false; boolean match = true; int pos = keyoffset; for ( int i=srcoffset; match && i 0 ) { int i = offset; if (unsigned) { buf.append(data[i++] & 0xff); for (; i < length; i++) { buf.append(", ").append(data[i] & 0xff); } } else { buf.append(data[i++]); for (; i < length; i++) { buf.append(", ").append(data[i]); } } } buf.append("}"); return buf.toString(); } public static String toString(Object[] data) { return toString(data,0,data!=null?data.length:0); } public static String toString(Object[] data, int offset, int length) { StringBuilder buf = new StringBuilder("{"); if ( data != null && length > 0 ) { buf.append(data[offset++]); for (int i = offset; i < length; i++) { buf.append(", ").append(data[i]); } } buf.append("}"); return buf.toString(); } public static String toNameString(Member[] data) { return toNameString(data,0,data!=null?data.length:0); } public static String toNameString(Member[] data, int offset, int length) { StringBuilder buf = new StringBuilder("{"); if ( data != null && length > 0 ) { buf.append(data[offset++].getName()); for (int i = offset; i < length; i++) { buf.append(", ").append(data[i].getName()); } } buf.append("}"); return buf.toString(); } public static int add(int[] data) { int result = 0; for (int i=0;i list = new ArrayList(java.util.Arrays.asList(m1)); for (int i=0; i result = new ArrayList(); MemberImpl[] comp = complete.getMembers(); for ( int i=0; i alist = java.util.Arrays.asList(all); ArrayList list = new ArrayList(alist); for (int i=0; i= members.length ) idx = ((members.length>0)?0:-1); //System.out.println("Next index:"+idx); //System.out.println("Member:"+member.getName()); //System.out.println("Members:"+toNameString(members)); return idx; } public static int hashCode(byte a[]) { if (a == null) return 0; int result = 1; for (int i=0; i workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public TribesThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override public void execute(Runnable command) { try { super.execute(command); } catch (RejectedExecutionException rx) { if (super.getQueue() instanceof TaskQueue) { TaskQueue queue = (TaskQueue)super.getQueue(); if (!queue.force(command)) { throw new RejectedExecutionException("Queue capacity is full."); } } } } } // ---------------------------------------------- TaskQueue Inner Class private static class TaskQueue extends LinkedBlockingQueue { private static final long serialVersionUID = 1L; ThreadPoolExecutor parent = null; public TaskQueue() { super(); } public TaskQueue(int initialCapacity) { super(initialCapacity); } public TaskQueue(Collection c) { super(c); } public void setParent(ThreadPoolExecutor tp) { parent = tp; } public boolean force(Runnable o) { if ( parent.isShutdown() ) throw new RejectedExecutionException("Executor not running, can't force a command into the queue"); return super.offer(o); //forces the item onto the queue, to be used if the task is rejected } @Override public boolean offer(Runnable o) { //we can't do any checks if (parent==null) return super.offer(o); //we are maxed out on threads, simply queue the object if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o); //we have idle threads, just add it to the queue //this is an approximation, so it could use some tuning if (parent.getActiveCount()<(parent.getPoolSize())) return super.offer(o); //if we have less threads than maximum force creation of a new thread if (parent.getPoolSize()The StringManager operates on a package basis. One StringManager * per package can be created and accessed via the getManager method * call. * *

    The StringManager will look for a ResourceBundle named by * the package name given plus the suffix of "LocalStrings". In * practice, this means that the localized information will be contained * in a LocalStrings.properties file located in the package * directory of the classpath. * *

    Please see the documentation for java.util.ResourceBundle for * more information. * * @author James Duncan Davidson [duncan@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Mel Martinez [mmartinez@g1440.com] * @see java.util.ResourceBundle */ public class StringManager { /** * The ResourceBundle for this StringManager. */ private ResourceBundle bundle; private Locale locale; /** * Creates a new StringManager for a given package. This is a * private method and all access to it is arbitrated by the * static getManager method call so that only one StringManager * per package will be created. * * @param packageName Name of package to create StringManager for. */ private StringManager(String packageName) { String bundleName = packageName + ".LocalStrings"; try { bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); } catch( MissingResourceException ex ) { // Try from the current loader (that's the case for trusted apps) // Should only be required if using a TC5 style classloader structure // where common != shared != server ClassLoader cl = Thread.currentThread().getContextClassLoader(); if( cl != null ) { try { bundle = ResourceBundle.getBundle( bundleName, Locale.getDefault(), cl); } catch(MissingResourceException ex2) { // Ignore } } } // Get the actual locale, which may be different from the requested one if (bundle != null) { locale = bundle.getLocale(); } } /** Get a string from the underlying resource bundle or return null if the String is not found. @param key to desired resource String @return resource String matching key from underlying bundle or null if not found. @throws IllegalArgumentException if key is null. */ public String getString(String key) { if(key == null){ String msg = "key may not have a null value"; throw new IllegalArgumentException(msg); } String str = null; try { str = bundle.getString(key); } catch(MissingResourceException mre) { //bad: shouldn't mask an exception the following way: // str = "[cannot find message associated with key '" + key + "' due to " + mre + "]"; // because it hides the fact that the String was missing // from the calling code. //good: could just throw the exception (or wrap it in another) // but that would probably cause much havoc on existing // code. //better: consistent with container pattern to // simply return null. Calling code can then do // a null check. str = null; } return str; } /** * Get a string from the underlying resource bundle and format * it with the given set of arguments. * * @param key * @param args */ public String getString(final String key, final Object... args) { String value = getString(key); if (value == null) { value = key; } MessageFormat mf = new MessageFormat(value); mf.setLocale(locale); return mf.format(args, new StringBuffer(), null).toString(); } // -------------------------------------------------------------- // STATIC SUPPORT METHODS // -------------------------------------------------------------- private static Hashtable managers = new Hashtable(); /** * Get the StringManager for a particular package. If a manager for * a package already exists, it will be reused, else a new * StringManager will be created and returned. * * @param packageName The package name */ public static final synchronized StringManager getManager(String packageName) { StringManager mgr = managers.get(packageName); if (mgr == null) { mgr = new StringManager(packageName); managers.put(packageName, mgr); } return mgr; } } tomcat7-7.0.52/java/org/apache/catalina/tribes/MembershipService.java0000644000175100017510000001063712271464231025430 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * MembershipService Interface
    * The MembershipService interface is the membership component * at the bottom layer, the IO layer (for layers see the javadoc for the {@link Channel} interface).
    * @author Filip Hanik */ public interface MembershipService { public static final int MBR_RX = Channel.MBR_RX_SEQ; public static final int MBR_TX = Channel.MBR_TX_SEQ; /** * Sets the properties for the membership service. This must be called before * the start() method is called. * The properties are implementation specific. * @param properties - to be used to configure the membership service. */ public void setProperties(java.util.Properties properties); /** * Returns the properties for the configuration used. */ public java.util.Properties getProperties(); /** * Starts the membership service. If a membership listeners is added * the listener will start to receive membership events. * Performs a start level 1 and 2 * @throws java.lang.Exception if the service fails to start. */ public void start() throws java.lang.Exception; /** * Starts the membership service. If a membership listeners is added * the listener will start to receive membership events. * @param level - level MBR_RX starts listening for members, level MBR_TX * starts broad casting the server * @throws java.lang.Exception if the service fails to start. * @throws java.lang.IllegalArgumentException if the level is incorrect. */ public void start(int level) throws java.lang.Exception; /** * Starts the membership service. If a membership listeners is added * the listener will start to receive membership events. * @param level - level MBR_RX stops listening for members, level MBR_TX * stops broad casting the server * @throws java.lang.IllegalArgumentException if the level is incorrect. */ public void stop(int level); /** * @return true if the the group contains members */ public boolean hasMembers(); /** * * @param mbr Member * @return Member */ public Member getMember(Member mbr); /** * Returns a list of all the members in the cluster. */ public Member[] getMembers(); /** * Returns the member object that defines this member */ public Member getLocalMember(boolean incAliveTime); /** * Return all members by name */ public String[] getMembersByName() ; /** * Return the member by name */ public Member findMemberByName(String name) ; /** * Sets the local member properties for broadcasting */ public void setLocalMemberProperties(String listenHost, int listenPort, int securePort, int udpPort); /** * Sets the membership listener, only one listener can be added. * If you call this method twice, the last listener will be used. * @param listener The listener */ public void setMembershipListener(MembershipListener listener); /** * removes the membership listener. */ public void removeMembershipListener(); /** * Set a payload to be broadcasted with each membership * broadcast. * @param payload byte[] */ public void setPayload(byte[] payload); public void setDomain(byte[] domain); /** * Broadcasts a message to all members * @param message * @throws ChannelException */ public void broadcast(ChannelMessage message) throws ChannelException; } tomcat7-7.0.52/java/org/apache/catalina/tribes/ErrorHandler.java0000644000175100017510000000332512271464231024377 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; /** * The ErrorHandler class is used when sending messages * that are sent asynchronously and the application still needs to get * confirmation when the message was sent successfully or when a message errored out. * @author Filip Hanik * @version 1.0 */ public interface ErrorHandler { /** * Invoked if the message is dispatched asynch, and an error occurs * @param x ChannelException - the error that happened * @param id - the unique id for the message * @see Channel#send(Member[], java.io.Serializable, int, ErrorHandler) */ public void handleError(ChannelException x, UniqueId id); /** * Invoked when the message has been sent successfully. * @param id - the unique id for the message * @see Channel#send(Member[], java.io.Serializable, int, ErrorHandler) */ public void handleCompletion(UniqueId id); }tomcat7-7.0.52/java/org/apache/catalina/tribes/ManagedChannel.java0000644000175100017510000000445612271464231024643 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.util.Iterator; /** * Channel interface * A managed channel interface gives you access to the components of the channels * such as senders, receivers, interceptors etc for configurations purposes * @author Filip Hanik */ public interface ManagedChannel extends Channel { /** * Sets the channel sender * @param sender ChannelSender * @see ChannelSender */ public void setChannelSender(ChannelSender sender); /** * Sets the channel receiver * @param receiver ChannelReceiver * @see ChannelReceiver */ public void setChannelReceiver(ChannelReceiver receiver); /** * Sets the membership service * @param service MembershipService * @see MembershipService */ public void setMembershipService(MembershipService service); /** * returns the channel sender * @return ChannelSender * @see ChannelSender */ public ChannelSender getChannelSender(); /** * returns the channel receiver * @return ChannelReceiver * @see ChannelReceiver */ public ChannelReceiver getChannelReceiver(); /** * Returns the membership service * @return MembershipService * @see MembershipService */ public MembershipService getMembershipService(); /** * Returns the interceptor stack * @return Iterator * @see Channel#addInterceptor(ChannelInterceptor) */ public Iterator getInterceptors(); } tomcat7-7.0.52/java/org/apache/catalina/tribes/ChannelException.java0000644000175100017510000001323712271464231025242 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.tribes; import java.util.ArrayList; /** * Channel Exception
    * A channel exception is thrown when an internal error happens * somewhere in the channel.
    * When a global error happens, the cause can be retrieved using getCause()

    * If an application is sending a message and some of the recipients fail to receive it, * the application can retrieve what recipients failed by using the getFaultyMembers() * method. This way, an application will always know if a message was delivered successfully or not. * @author Filip Hanik */ public class ChannelException extends Exception { private static final long serialVersionUID = 1L; /** * Empty list to avoid reinstatiating lists */ protected static final FaultyMember[] EMPTY_LIST = new FaultyMember[0]; /* * Holds a list of faulty members */ private ArrayList faultyMembers=null; /** * Constructor, creates a ChannelException * @see java.lang.Exception#Exception() */ public ChannelException() { super(); } /** * Constructor, creates a ChannelException with an error message * @see java.lang.Exception#Exception(String) */ public ChannelException(String message) { super(message); } /** * Constructor, creates a ChannelException with an error message and a cause * @param message String * @param cause Throwable * @see java.lang.Exception#Exception(String,Throwable) */ public ChannelException(String message, Throwable cause) { super(message, cause); } /** * Constructor, creates a ChannelException with a cause * @param cause Throwable * @see java.lang.Exception#Exception(Throwable) */ public ChannelException(Throwable cause) { super(cause); } /** * Returns the message for this exception * @return String * @see java.lang.Exception#getMessage() */ @Override public String getMessage() { StringBuilder buf = new StringBuilder(super.getMessage()); if (faultyMembers==null || faultyMembers.size() == 0 ) { buf.append("; No faulty members identified."); } else { buf.append("; Faulty members:"); for ( int i=0; i(); if ( !faultyMembers.contains(mbr) ) return faultyMembers.add(mbr); else return false; } /** * Returns an array of members that failed and the reason they failed. * @return FaultyMember[] */ public FaultyMember[] getFaultyMembers() { if ( this.faultyMembers==null ) return EMPTY_LIST; return faultyMembers.toArray(new FaultyMember[faultyMembers.size()]); } /** * *

    Title: FaultyMember class

    * *

    Description: Represent a failure to a specific member when a message was sent * to more than one member

    * * @author Filip Hanik * @version 1.0 */ public static class FaultyMember { protected Exception cause; protected Member member; public FaultyMember(Member mbr, Exception x) { this.member = mbr; this.cause = x; } public Member getMember() { return member; } public Exception getCause() { return cause; } @Override public String toString() { return "FaultyMember:"+member.toString(); } @Override public int hashCode() { return (member!=null)?member.hashCode():0; } @Override public boolean equals(Object o) { if (member==null || (!(o instanceof FaultyMember)) || (((FaultyMember)o).member==null)) return false; return member.equals(((FaultyMember)o).member); } } } tomcat7-7.0.52/java/org/apache/catalina/core/0000755000175100017510000000000012301126370020573 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/core/LocalStrings_es.properties0000644000175100017510000006066412271471332026027 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationContext.addFilter.ise = No se pueden a\u00F1adir filtros al contexto {0} ya que \u00E9ste ha sido inicializado applicationContext.addListener.iae.cnfe = No puedo crear una instancia del tipo [{0}] applicationContext.addListener.iae.wrongType = El tipo especificado [{0}] no es uno de los tipos de escuchador esperados applicationContext.addListener.iae.sclNotAllowed = Una vez que el primer ServletContextListener ha sido llamado, no se pueden a\u00F1adir m\u00E1s ServletContextListeners. applicationContext.addListener.ise = No se pueden a\u00F1adir escuchadores al contexto {0}, una vez que ha sido inicializado. applicationContext.addRole.ise = No se pueden a\u00F1adir roles al contexto {0}, una vez que ha sido inicializado. applicationContext.addServlet.ise = No se pueden a\u00F1adir servlets al contexto {0}, una vez que ha sido inicializado. applicationContext.attributeEvent = Excepci\u00F3n lanzada por escuchador de eventos de atributos applicationContext.mapping.error = Error durante mapeo applicationContext.requestDispatcher.iae = La Trayectoria {0} no comienza con car\u00E1cter "/" applicationContext.resourcePaths.iae = La Trayectoria {0} no comienza con car\u00E1cter "/" applicationContext.role.iae = Un rol individual que se ha de declarar para el contexto [{0}] no puede ser nulo o cadena vac\u00EDa applicationContext.roles.iae = Un arreglo de roles que se ha de declarar para el contexto [{0}] no puede ser nulo o cadena vac\u00EDa applicationContext.setAttribute.namenull = El nombre no puede ser nulo applicationContext.addSessionCookieConfig.ise = No se puede poner la configuraci\u00F3n de Cookie de Sesi\u00F3n para el contexto {0}, una vez que \u00E9ste ha sido inicializado. applicationContext.setSessionTracking.ise = No se pueden poner los modos de seguimiento de sesi\u00F3n para el contexto {0} mientras el contexto se est\u00E1 ejecutando. applicationContext.setSessionTracking.iae.invalid = El modo de seguimiento de sesi\u00F3n {0} requerido para el contexto {1} no est\u00E1 soportado por este contexto applicationContext.setSessionTracking.iae.ssl = Los modos de seguimiento de sesi\u00F3n requeridos para el contexto {0}, incluy\u00F3 SSL y al menos otro modo. SSL no se puede configurar con otros modos. applicationContext.lookup.error = No pude localizar el recurso [{0}] en el contexto [{1}] applicationDispatcher.allocateException = Excepci\u00F3n de reserva de espacio para servlet {0} applicationDispatcher.deallocateException = Excepci\u00F3n de recuperaci\u00F3n de espacio para servlet {0} applicationDispatcher.forward.ise = No puedo reenviar despu\u00E9s de que la respuesta se haya llevado a cabo. applicationDispatcher.forward.throw = El recurso reenviado lanz\u00F3 un excepci\u00F3n applicationDispatcher.include.throw = El recurso inclu\u00EDdo lanz\u00F3 una excepci\u00F3n applicationDispatcher.isUnavailable = El Servlet {0} no est\u00E1 disponible en este momento applicationDispatcher.serviceException = El Servlet.service() para servlet {0} lanz\u00F3 una excepci\u00F3n applicationDispatcher.specViolation.request = SevletRequest original o ServletRequest original arropado no pas\u00F3 a RequestDispatcher en violaci\u00F3n de SRV.8.2 y SRV.14.2.5.1 applicationDispatcher.specViolation.response = SevletResponse original o ServletResponse original arropado no pas\u00F3 a RequestDispatcher en violaci\u00F3n de SRV.8.2 y SRV.14.2.5.1 applicationFilterConfig.jmxRegisterFail = Ha fallado el registro JMX para el filtro del tipo [{0}] y nombre [{1}] applicationFilterConfig.jmxUnregister = Se ha completado el desregistro JMX para el filtro del tipo [{0}] y nombre [{1}] applicationFilterConfig.jmxUnregisterFail = Ha fallado el desregistro JMX para el filtro del tipo [{0}] y nombre [{1}] applicationFilterRegistration.nullInitParam = No puedo poner el par\u00E1metro de inicializaci\u00F3n para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}] applicationFilterRegistration.nullInitParams = No puedo poner los par\u00E1metros de inicializaci\u00F3n para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}] applicationRequest.badParent = No puedo localizar la implementaci\u00F3n de Requerimiento padre applicationRequest.badRequest = El requerimiento no es un javax.servlet.ServletRequestWrapper applicationResponse.badParent = No puedo localizar implementaci\u00F3n de Respuesta padre applicationResponse.badResponse = La Respuesta no es un javax.servlet.ServletResponseWrapper applicationServletRegistration.setServletSecurity.iae = Se ha especificado restricci\u00F3n Null para el servlet [{0}] desplegado en el contexto con el nombre [{1}] applicationServletRegistration.setServletSecurity.ise = No se pueden a\u00F1adir restricciones de seguridad al servlet [{0}] desplegado en el contexto con el nombre [{1}] ya que el contexto ya ha sido inicializado. aprListener.aprInit = La biblioteca nativa de Apache Tomcat basada en ARP que permite un rendimiento \u00F3ptimo en entornos de desarrollo no ha sido hallada en java.library.path\: {0} aprListener.tcnInvalid = Se encuentra instalada una versi\u00F3n incompatible {0} de la biblioteca nativa APR de Apache Tomcat, mientras que Tomcat necesita la versi\u00F3n {1} aprListener.tcnVersion = Se encuentra instalada una versi\u00F3n muy vieja {0} de la biblioteca nativa APR de Apache Tomcat, mientras que Tomcat recomienda una versi\u00F3n mayor de {1} aprListener.aprDestroy = No pude apagar la biblioteca nativa de Apache Tomcat aprListener.sslInit = No pude inicializar el SSLEngine (Motor SSL) aprListener.tcnValid = Cargada la biblioteca nativa APR de Apache Tomcat {0} con la versin APR {1}. aprListener.flags = Capacidades APR\: IPv6 [{0}], enviar fichero [{1}], aceptar filtros [{2}], aleatorio [{3}]. aprListener.initializedOpenSSL=OpenSSL inicializado correctamente ({0}) asyncContextImpl.requestEnded = El requerimiento asociado con AsyncContext ya ha completado su procesamiento. containerBase.alreadyStarted = Ya ha sido arrancado el Contenedor {0} containerBase.notConfigured = No se ha configurado V\u00E1lvula b\u00E1sica containerBase.notStarted = No se ha arrancado el Contenedor {0} containerBase.backgroundProcess.cluster = Excepci\u00F3n al procesar cl\u00FAster {0} de proceso en segundo plano containerBase.backgroundProcess.loader = Excepci\u00F3n al procesar cargador {0} de proceso en segundo plano containerBase.backgroundProcess.manager = Excepci\u00F3n al procesar gestor {0} de proceso en segundo plano containerBase.backgroundProcess.realm = Excepci\u00F3n al procesar reino {0} de proceso en segundo plano containerBase.backgroundProcess.valve = Excepci\u00F3n al procesar v\u00E1lvula {0} de proceso en segundo plano fastEngineMapper.alreadyStarted = Ya se ha arrancado el FastEngineMapper {0} fastEngineMapper.notStarted = No se ha arrancado a\u00FAn el FastEngineMapper {0} filterChain.filter = La ejecuci\u00F3n del Filtro lanz\u00F3 una excepci\u00F3n filterChain.servlet = La ejecuci\u00F3n del Servlet lanz\u00F3 una excepci\u00F3n httpContextMapper.container = Este Contenedor no es un StandardContext httpEngineMapper.container = Este Contenedor no es un StandardEngine httpHostMapper.container = Esta Contenedor no es una StandardHost interceptorValve.alreadyStarted = Ya ha sido arrancada la InterceptorValve interceptorValve.notStarted = A\u00FAn no ha sido arrancada la InterceptorValve jreLeakListener.keepAliveFail = No pude disparar la creaci\u00F3n de la clase sun.net.www.http.HttpClient durante el arranque de Tomcat para prevenir posibles fallos de memoria. Esto es lo esperado en JVMs no Sun. jreLeakListener.gcDaemonFail = No pude disparar la creaci\u00F3n del hilo Daemon GC durante el arranque de Tomcat para prevenir posibles fallos de memoria. Esto es lo esperado en JVMs no Sun. jreLeakListener.jarUrlConnCacheFail = No pude desactivar la cach\u00E9 de conexi\u00F3n URL de Jar por defecto jreLeakListener.xmlParseFail = Error mientras intentaba prevenir fallos de memoria durante el an\u00E1lisis XML jreLeakListener.authPolicyFail = Error mientras intentaba prevenir fallos de memoria en javax.security.auth.Policy class jreLeakListener.ldapPoolManagerFail = No pude disparar la creaci\u00F3n de la clase com.sun.jndi.ldap.LdapPoolManager durante el arranque de Tomcat para prevenir posibles fallos de memoria. Esto es lo que se espera si las JVMs no son Sun. naming.wsdlFailed = No pude hallar fichero wsdl\: {0} naming.bindFailed = No pude cambiar (bind) objeto\: {0} naming.jmxRegistrationFailed = No pude registrar en JMX\: {0} naming.unbindFailed = No pude descambiar (unbind) objecto\: {0} naming.invalidEnvEntryType = La entrada de Entorno {0} tiene un tipo inv\u00E1lido naming.invalidEnvEntryValue = La entrada de Entorno {0} tiene un valor inv\u00E1lido naming.namingContextCreationFailed = Fall\u00F3 la creaci\u00F3n del contexto de nombres (naming)\: {0} standardContext.invalidWrapperClass = {0} no es una subclase de StandardWrapper standardContext.alreadyStarted = Ya se ha arrancado el Contexto standardContext.applicationListener = Error configurando escuchador de aplicaci\u00F3n de clase {0} standardContext.applicationSkipped = Se ha saltado la instalaci\u00F3n de escuchadores de aplicaci\u00F3n debido a error(es) previo(s) standardContext.badRequest = Trayectoria de requerimiento inv\u00E1lida ({0}). standardContext.cluster.noManager = No se ha hallado el gestor. Revisando si hay que usar el gestor de cl\u00FAster. Cl\u00FAster configurado\: [{0}], Aplicaci\u00F3n distribu\u00EDble\: [{1}] standardContext.crlfinurl = El modelo URL "{0}" contiene un CR o LR y por ello nunca coincidir\u00E1. standardContext.duplicateListener = El escuchador "{0}" ya est\u00E1 configurado para este contexto. La definici\u00F3n duplicada ha sido ignorada. standardContext.errorPage.error = La localizaci\u00F3n de la p\u00E1gina de error 0} debe de comenzar con ''/'' standardContext.errorPage.required = ErrorPage no puede ser nulo standardContext.errorPage.warning = AVISO\: La localizaci\u00F3n de la p\u00E1gina de error {0} debe de comenzar con ''/'' en Servlet 2.4 standardContext.filterMap.either = El mapeo de filtro debe de especificar o un o un standardContext.filterMap.name = El mapeo de filtro especifica un nombre desconocido de filtro {0} standardContext.filterMap.pattern = {0} inv\u00E1lido en mapeo de filtro standardContext.filterStart = Excepci\u00F3n arrancando filtro {0} standardContext.filterStartFailed = No pude arrancar Filtros de aplicaci\u00F3n con \u00E9xito standardContext.requestListener.requestInit = Una excepci\u00F3n durante el env\u00EDo de requerimiento ha iniciado un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0} standardContext.requestListener.requestDestroy = Una excepci\u00F3n durante el env\u00EDo de requerimiento ha destru\u00EDdo un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0} standardContext.requestListenerStartFailed = No pude arrancar v\u00E1lvula de escuchador de requerimiento con exito standardContext.requestListenerConfig.added = A\u00F1adida V\u00E1lvula de escuchador de requerimiento standardContext.requestListenerConfig.error = Excepci\u00F3n a\u00F1adiendo V\u00E1lvula de escuchador de requerimiento\: {0} standardContext.isUnavailable = Esta aplicaci\u00F3n no est\u00E1 disponible en este momento standardContext.listenerStart = Excepci\u00F3n enviando evento inicializado de contexto a instancia de escuchador de clase {0} standardContext.listenerStartFailed = No pude arrancar Escuchadores de aplicaci\u00F3n con \u00E9xito standardContext.listenerStop = Excepci\u00F3n enviando evento de contexto destru\u00EDdo a instancia de escuchador de clase {0} standardContext.loginConfig.errorPage = La P\u00E1gina de error de Formulario {0} debe de comenzar con ''/' standardContext.loginConfig.errorWarning = AVISO\: La p\u00E1gina de error de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4 standardContext.loginConfig.loginPage = La p\u00E1gina de login de Formulario {0} debe de comenzar con ''/' standardContext.loginConfig.loginWarning = AVISO\: La p\u00E1gina de login de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4 standardContext.loginConfig.required = LoginConfig no puede ser nula standardContext.manager = Configurado un gestor de la clase [{0}] standardContext.mappingError = Error de configuraci\u00F3n de MAPEO para URI relativa {0} standardContext.namingResource.init.fail = No pude inicializar recursos de nuevo nombre standardContext.namingResource.destroy.fail = No pude destruir recursos de viejo nombre standardContext.noResourceJar = Los JARs de recurso no est\u00E1n soportados. El JAR hallado en [{0}] no se utilizar\u00E1 para proveer de contenido est\u00E1tico para el contexto con nombre [{1}] standardContext.notFound = El recurso requerido ({0}) no se encuentra disponible standardContext.notReloadable = Est\u00E1 desactivada la recarga en este Contexto standardContext.notStarted = A\u00FAn no se ha arrancado el Contexto [{0}] standardContext.notWrapper = El Hijo de un Contexto debe de ser un Arropador (Wrapper) standardContext.parameter.duplicate = Duplicado par\u00E1metro de inicializaci\u00F3n de contexto [{0}] standardContext.parameter.required = Es necesario poner nombre de par\u00E1metro y valor de par\u00E1metro standardContext.pathInvalid = Una ruta de contexto debe de ser o una cadena vac\u00EDa o comenzar con "/". La ruta [{0}] no cumple con estos criterios y ha sido cambiada por [{1}] standardContext.reloadingCompleted = Se ha completado la recarga de este Contexto standardContext.reloadingFailed = Fall\u00F3 la recarga de este Contexto debido a errores previos standardContext.reloadingStarted = Ha comenzado la recarga de Contexto [{0}] standardContext.resourcesStart = Error arrancando Recursos est\u00E1ticos standardContext.securityConstraint.mixHttpMethod = No est\u00E1 permitido mezclar y ien la misma colecci\u00F3n de recursos web standardContext.securityConstraint.pattern = {0} inv\u00E1lida en restricci\u00F3n de seguridad standardContext.servletMap.name = El mapeo de Servlet especifica un nombre de servlet desconocido {0} standardContext.servletMap.pattern = {0} inv\u00E1lida en mapeo de servlet standardContext.startCleanup = Excepci\u00F3n durante la limpieza tras no poder arrancar standardContext.startFailed = Fall\u00F3 en arranque del Contexto [{0}] debido a errores previos standardContext.startingContext = Excepci\u00F3n arrancando Contexto con nombre [{0}] standardContext.startingLoader = Excepci\u00F3n arrancando Cargador standardContext.startingManager = Excepci\u00F3n arrancando Gestor standardContext.startingWrapper = Excepci\u00F3n arrancando Arropador (Wrapper) para servlet {0} standardContext.stoppingContext = Excepci\u00F3n parando Context [{0}] standardContext.stoppingLoader = Excepci\u00F3n parando Cargador standardContext.stoppingManager = Excepci\u00F3n parando Gestor standardContext.stoppingWrapper = Excepci\u00F3n parando Arropador (Wrapper) para servlet {0} standardContext.urlDecode = No puedo decodificar URL de trayectoria de requerimiento {0} standardContext.urlPattern.patternWarning = AVISO\: el patr\u00F3n URL {0} debe de comenzar con ''/'' en Servlet 2.4 standardContext.urlValidate = No puedo validar trayectoria de requerimiento de URL decodificada {0} standardContext.workPath = Excepci\u00F3n obteniendo ruta de trabajo para el contexto [{0}] standardContext.workCreateException = No pude determinar directorio absoluto de trabajo a partir del directorio [{0}] y CATALINA_HOME [{1}] para el contexto [{2}] standardContext.workCreateFail = No pude crear el directorio de trabajo [{0}] para el contexto [{1}] standardContextValve.acknowledgeException = No pude reconocer el requerimiento con una respuesta 100 (Continuar) standardEngine.alreadyStarted = Ya ha sido arrancado el Motor standardEngine.jvmRouteFail = No pude poner el atributo jvmRoute del Motor para la propiedad del sistema standardEngine.mappingError = Error de configuraci\u00F3n de MAPEO para nombre de servidor {0} standardEngine.noHost = No hay M\u00E1quina que coincida con nombre de servidor {0} standardEngine.noHostHeader = Requerimiento HTTP/1.1 sin M\u00E1quina\: cabecera standardEngine.notHost = El Hijo de un Motor debe de ser un M\u00E1quina standardEngine.notParent = El Motor no puede tener un Contenedor padre standardEngine.notStarted = A\u00FAn no se ha arrancado el Motor standardEngine.unfoundHost = M\u00E1quina virtual {0} no hallada standardEngine.unknownHost = No se ha especificado m\u00E1quina servidora en este requerimiento standardEngine.unregister.mbeans.failed = Error al destruir (destroy()) para fichero mbean {0} standardHost.accessBase = No puedo acceder a directorio base de documento {0} standardHost.alreadyStarted = Ya ha sido arrancada la M\u00E1quina standardHost.appBase = No existe el directorio base de aplicaci\u00F3n {0} standardHost.clientAbort = El Cliente Remoto Abort\u00F3 el Requerimiento, IOException\: {0} standardHost.configRequired = Es necesario poner la URL a archivo de configuraci\u00F3n standardHost.configNotAllowed = No se permite el uso del archivo de configuraci\u00F3n standardHost.installBase = S\u00F3lo se pueden instalar aplicaciones web en el directorio de aplicaciones web de M\u00E1quina standardHost.installing = Instalando aplicaciones web en trayectoria de contexto {0} desde URL {1} standardHost.installingWAR = Instalando aplicaci\u00F3n web desde URL {0} standardHost.installingXML = Procesando URL de archivo de configuraci\u00F3n de Contexto {0} standardHost.installError = Error desplegando aplicaci\u00F3n en trayectoria de contexto {0} standardHost.invalidErrorReportValveClass = No pude cargar clase especifiada de v\u00E1lvula de informe de error\: {0} standardHost.docBase = Ya existe el directorio base de documento {0} standardHost.mappingError = Error de configuraci\u00F3n de MAPEO para URI de requerimiento {0} standardHost.noContext = No se ha configurado Contexto para procesar este requerimiento standardHost.noHost = No se ha configurado M\u00E1quina para procesar este requerimiento standardHost.notContext = El Hijo de una M\u00E1quina debe de ser un Contexto standardHost.notStarted = A\u00FAn no se ha arrancado la M\u00E1quina standardHost.nullName = Es necesario poner el nombre de M\u00E1quina standardHost.pathFormat = Trayectoria de contexto inv\u00E1lida\: {0} standardHost.pathMatch = La trayectoria de Contexto {0} debe de coincidir con el nombre de directorio o de archivo WAR\: {1} standardHost.pathMissing = La trayectoria de Contexto {0} no est\u00E1 en uso en este momento standardHost.pathRequired = Es necesario poner la trayectoria de Contexto standardHost.pathUsed = Ya est\u00E1 en uso la trayectoria de Contexto {0} standardHost.removing = Quitando aplicaci\u00F3n web en trayectoria de contexto {0} standardHost.removeError = Error quitando aplicaci\u00F3n en trayectoria de contexto {0} standardHost.start = Arrancando aplicaci\u00F3n web en trayectoria de contexto {0} standardHost.stop = Parando aplicaci\u00F3n web en trayectoria de contexto {0} standardHost.unfoundContext = No puedo hallar contexto para URI de requerimiento {0} standardHost.warRequired = Es necesario poner la URL a archivo de aplicaci\u00F3n web standardHost.warURL = URL inv\u00E1lida para archivo de aplicaci\u00F3n web\: {0} standardServer.onameFail = El nombre MBean especificado para el Servidor [{0}] no es v\u00E1lido standardServer.shutdownViaPort = Se ha recibido un comando de apagado a trav\u00E9s del puerto de apagado. Parando la instancia del Servidor. standardService.connector.initFailed = No pude inicializar el conector [{0}] standardService.connector.destroyFailed = No pude destruir el conector [{0}] standardService.connector.pauseFailed = No pude pausar el conector [{0}] standardService.connector.startFailed = No pude arrancar el conector [{0}] standardService.connector.stopFailed = No pude parar el conector [{0}] standardService.initialize.failed = Servicio inicializando en {0} fall\u00F3 standardService.onameFail = El nombre MBean especificado para el Servicio [{0}] no es v\u00E1lido standardService.register.failed = Error registrando servicio en dominio {0} standardService.start.name = Arrancando servicio {0} standardService.stop.name = Parando servicio {0} standardThreadExecutor.onameFail = El nombre MBean especificado para el Ejecutor de Hilos [{0}] no es v\u00E1lido standardWrapper.allocate = Error reservando espacio para una instancia de servlet standardWrapper.allocateException = Excepci\u00F3n de reserva de espacio para servlet {0} standardWrapper.containerServlet = Cargando servlet de contenedor {0} standardWrapper.createFilters = Excepci\u00F3n de creaci\u00F3n de filtros para servlet {0} standardWrapper.deallocateException = Excepci\u00F3n de recuperaci\u00F3n de espacio para servlet {0} standardWrapper.destroyException = Servlet.destroy() para servlet {0} lanz\u00F3 excepci\u00F3n standardWrapper.exception0 = Informe de Excepci\u00F3n de Tomcat standardWrapper.exception1 = Ha tenido lugar una Excepci\u00F3n de Servlet standardWrapper.exception2 = Informe de Excepci\u00F3n\: standardWrapper.exception3 = Causa Ra\u00EDz\: standardWrapper.initException = Servlet.init() para servlet {0} lanz\u00F3 excepci\u00F3n standardWrapper.instantiate = Error instanciando clase de servlet {0} standardWrapper.isUnavailable = El Servlet {0} no est\u00E1 disponible en este momento standardWrapper.jasperLoader = Usando cargador de clases (classloader) de Jasper para servlet {0} standardWrapper.jspFile.format = El archivo JSP {0} no comienza con car\u00E1cter ''/'' standardWrapper.loadException = El Servlet {0} lanz\u00F3 excepci\u00F3n de load() standardWrapper.missingClass = El Arropador (Wrapper) no puede hallar clase de servlet {0} o una clase de la que depende standardWrapper.missingLoader = El Arropador (Wrapper) no puede hallar Cargador para servlet {0} standardWrapper.notChild = El contenedor de Arropador (Wrapper) no puede tener contenedores hijo standardWrapper.notClass = No se ha especificado clase de servlet para servlet {0} standardWrapper.notContext = El contenedor padre para un Arropador (Wrapper) debe de ser un Contexto standardWrapper.notFound = No est\u00E1 disponible el Servlet {0} standardWrapper.notServlet = La Clase {0} no es un Servlet standardWrapper.releaseFilters = Excepci\u00F3n de Liberaci\u00F3n de filtros para servlet {0} standardWrapper.serviceException = Servlet.service() para servlet {0} lanz\u00F3 excepci\u00F3n standardWrapper.serviceExceptionRoot = El Servlet.service() para el servlet [{0}] en el contexto con ruta [{1}] lanz\u00F3 la excepci\u00F3n [{2}] con causa ra\u00EDz standardWrapper.statusHeader = HTTP Estado {0} - {1} standardWrapper.statusTitle = Informe de Error de Tomcat standardWrapper.unavailable = Marcando el servlet {0} como no disponible standardWrapper.unloadException = El Servlet {0} lanz\u00F3 excepci\u00F3n unload() standardWrapper.unloading = No puedo reservar espacio para servlet {0} porque est\u00E1 siendo descargado standardWrapper.waiting = Esperando por {0} instancia(s) para recuperar su espacio reservado threadLocalLeakPreventionListener.lifecycleEvent.error = Excepci\u00F3n procesando evento de ciclo de vida {0} threadLocalLeakPreventionListener.containerEvent.error = Excepci\u00F3n procesando evento de contenedor {0} defaultInstanceManager.restrictedServletsResource = No se ha hallado el fichero de propiedades restringidas de servlets defaultInstanceManager.privilegedServlet = El Servlet de clase {0} es privilegiado y no puede ser cargado mediante esta aplicaci\u00F3n defaultInstanceManager.restrictedFiltersResource = No se ha hallado el fichero de propiedades restringidas de filtros defaultInstanceManager.privilegedFilter = El filtro de clase {0} es privilegiado y no puede ser cargado mediante esta apliaci\u00F3n web defaultInstanceManager.restrictedListenersResources = No se ha hallado el fichero de propiedades restringidas de escuchadores tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationContextFacade.java0000644000175100017510000007016012271471332026345 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Enumeration; import java.util.EventListener; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.servlet.descriptor.JspConfigDescriptor; import org.apache.catalina.Globals; import org.apache.catalina.security.SecurityUtil; import org.apache.tomcat.util.ExceptionUtils; /** * Facade object which masks the internal ApplicationContext * object from the web application. * * @author Remy Maucherat * @author Jean-Francois Arcand */ public class ApplicationContextFacade implements ServletContext { // ---------------------------------------------------------- Attributes /** * Cache Class object used for reflection. */ private HashMap[]> classCache; /** * Cache method object. */ private HashMap objectCache; // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class, associated with the specified * Context instance. * * @param context The associated Context instance */ public ApplicationContextFacade(ApplicationContext context) { super(); this.context = context; classCache = new HashMap[]>(); objectCache = new HashMap(); initClassCache(); } private void initClassCache(){ Class[] clazz = new Class[]{String.class}; classCache.put("getContext", clazz); classCache.put("getMimeType", clazz); classCache.put("getResourcePaths", clazz); classCache.put("getResource", clazz); classCache.put("getResourceAsStream", clazz); classCache.put("getRequestDispatcher", clazz); classCache.put("getNamedDispatcher", clazz); classCache.put("getServlet", clazz); classCache.put("setInitParameter", new Class[]{String.class, String.class}); classCache.put("createServlet", new Class[]{Class.class}); classCache.put("addServlet", new Class[]{String.class, String.class}); classCache.put("createFilter", new Class[]{Class.class}); classCache.put("addFilter", new Class[]{String.class, String.class}); classCache.put("createListener", new Class[]{Class.class}); classCache.put("addListener", clazz); classCache.put("getFilterRegistration", clazz); classCache.put("getServletRegistration", clazz); classCache.put("getInitParameter", clazz); classCache.put("setAttribute", new Class[]{String.class, Object.class}); classCache.put("removeAttribute", clazz); classCache.put("getRealPath", clazz); classCache.put("getAttribute", clazz); classCache.put("log", clazz); classCache.put("setSessionTrackingModes", new Class[]{Set.class} ); } // ----------------------------------------------------- Instance Variables /** * Wrapped application context. */ private ApplicationContext context = null; // ------------------------------------------------- ServletContext Methods @Override public ServletContext getContext(String uripath) { ServletContext theContext = null; if (SecurityUtil.isPackageProtectionEnabled()) { theContext = (ServletContext) doPrivileged("getContext", new Object[]{uripath}); } else { theContext = context.getContext(uripath); } if ((theContext != null) && (theContext instanceof ApplicationContext)){ theContext = ((ApplicationContext)theContext).getFacade(); } return (theContext); } @Override public int getMajorVersion() { return context.getMajorVersion(); } @Override public int getMinorVersion() { return context.getMinorVersion(); } @Override public String getMimeType(String file) { if (SecurityUtil.isPackageProtectionEnabled()) { return (String)doPrivileged("getMimeType", new Object[]{file}); } else { return context.getMimeType(file); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public Set getResourcePaths(String path) { if (SecurityUtil.isPackageProtectionEnabled()){ return (Set)doPrivileged("getResourcePaths", new Object[]{path}); } else { return context.getResourcePaths(path); } } @Override public URL getResource(String path) throws MalformedURLException { if (Globals.IS_SECURITY_ENABLED) { try { return (URL) invokeMethod(context, "getResource", new Object[]{path}); } catch(Throwable t) { ExceptionUtils.handleThrowable(t); if (t instanceof MalformedURLException){ throw (MalformedURLException)t; } return null; } } else { return context.getResource(path); } } @Override public InputStream getResourceAsStream(String path) { if (SecurityUtil.isPackageProtectionEnabled()) { return (InputStream) doPrivileged("getResourceAsStream", new Object[]{path}); } else { return context.getResourceAsStream(path); } } @Override public RequestDispatcher getRequestDispatcher(final String path) { if (SecurityUtil.isPackageProtectionEnabled()) { return (RequestDispatcher) doPrivileged("getRequestDispatcher", new Object[]{path}); } else { return context.getRequestDispatcher(path); } } @Override public RequestDispatcher getNamedDispatcher(String name) { if (SecurityUtil.isPackageProtectionEnabled()) { return (RequestDispatcher) doPrivileged("getNamedDispatcher", new Object[]{name}); } else { return context.getNamedDispatcher(name); } } /** * @deprecated As of Java Servlet API 2.1, with no direct replacement. */ @Override @Deprecated public Servlet getServlet(String name) throws ServletException { if (SecurityUtil.isPackageProtectionEnabled()) { try { return (Servlet) invokeMethod(context, "getServlet", new Object[]{name}); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (t instanceof ServletException) { throw (ServletException) t; } return null; } } else { return context.getServlet(name); } } /** * @deprecated As of Java Servlet API 2.1, with no direct replacement. */ @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type @Deprecated public Enumeration getServlets() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Enumeration) doPrivileged("getServlets", null); } else { return context.getServlets(); } } /** * @deprecated As of Java Servlet API 2.1, with no direct replacement. */ @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type @Deprecated public Enumeration getServletNames() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Enumeration) doPrivileged("getServletNames", null); } else { return context.getServletNames(); } } @Override public void log(String msg) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("log", new Object[]{msg} ); } else { context.log(msg); } } /** * @deprecated As of Java Servlet API 2.1, use * log(String, Throwable) instead */ @Override @Deprecated public void log(Exception exception, String msg) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("log", new Class[]{Exception.class, String.class}, new Object[]{exception,msg}); } else { context.log(exception, msg); } } @Override public void log(String message, Throwable throwable) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("log", new Class[]{String.class, Throwable.class}, new Object[]{message, throwable}); } else { context.log(message, throwable); } } @Override public String getRealPath(String path) { if (SecurityUtil.isPackageProtectionEnabled()) { return (String) doPrivileged("getRealPath", new Object[]{path}); } else { return context.getRealPath(path); } } @Override public String getServerInfo() { if (SecurityUtil.isPackageProtectionEnabled()) { return (String) doPrivileged("getServerInfo", null); } else { return context.getServerInfo(); } } @Override public String getInitParameter(String name) { if (SecurityUtil.isPackageProtectionEnabled()) { return (String) doPrivileged("getInitParameter", new Object[]{name}); } else { return context.getInitParameter(name); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public Enumeration getInitParameterNames() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Enumeration) doPrivileged( "getInitParameterNames", null); } else { return context.getInitParameterNames(); } } @Override public Object getAttribute(String name) { if (SecurityUtil.isPackageProtectionEnabled()) { return doPrivileged("getAttribute", new Object[]{name}); } else { return context.getAttribute(name); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public Enumeration getAttributeNames() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Enumeration) doPrivileged( "getAttributeNames", null); } else { return context.getAttributeNames(); } } @Override public void setAttribute(String name, Object object) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("setAttribute", new Object[]{name,object}); } else { context.setAttribute(name, object); } } @Override public void removeAttribute(String name) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("removeAttribute", new Object[]{name}); } else { context.removeAttribute(name); } } @Override public String getServletContextName() { if (SecurityUtil.isPackageProtectionEnabled()) { return (String) doPrivileged("getServletContextName", null); } else { return context.getServletContextName(); } } @Override public String getContextPath() { if (SecurityUtil.isPackageProtectionEnabled()) { return (String) doPrivileged("getContextPath", null); } else { return context.getContextPath(); } } @Override public FilterRegistration.Dynamic addFilter(String filterName, String className) { if (SecurityUtil.isPackageProtectionEnabled()) { return (FilterRegistration.Dynamic) doPrivileged( "addFilter", new Object[]{filterName, className}); } else { return context.addFilter(filterName, className); } } @Override public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { if (SecurityUtil.isPackageProtectionEnabled()) { return (FilterRegistration.Dynamic) doPrivileged("addFilter", new Class[]{String.class, Filter.class}, new Object[]{filterName, filter}); } else { return context.addFilter(filterName, filter); } } @Override public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { if (SecurityUtil.isPackageProtectionEnabled()) { return (FilterRegistration.Dynamic) doPrivileged("addFilter", new Class[]{String.class, Class.class}, new Object[]{filterName, filterClass}); } else { return context.addFilter(filterName, filterClass); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public T createFilter(Class c) throws ServletException { if (SecurityUtil.isPackageProtectionEnabled()) { try { return (T) invokeMethod(context, "createFilter", new Object[]{c}); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (t instanceof ServletException) { throw (ServletException) t; } return null; } } else { return context.createFilter(c); } } @Override public FilterRegistration getFilterRegistration(String filterName) { if (SecurityUtil.isPackageProtectionEnabled()) { return (FilterRegistration) doPrivileged( "getFilterRegistration", new Object[]{filterName}); } else { return context.getFilterRegistration(filterName); } } @Override public ServletRegistration.Dynamic addServlet(String servletName, String className) { if (SecurityUtil.isPackageProtectionEnabled()) { return (ServletRegistration.Dynamic) doPrivileged( "addServlet", new Object[]{servletName, className}); } else { return context.addServlet(servletName, className); } } @Override public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { if (SecurityUtil.isPackageProtectionEnabled()) { return (ServletRegistration.Dynamic) doPrivileged("addServlet", new Class[]{String.class, Servlet.class}, new Object[]{servletName, servlet}); } else { return context.addServlet(servletName, servlet); } } @Override public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { if (SecurityUtil.isPackageProtectionEnabled()) { return (ServletRegistration.Dynamic) doPrivileged("addServlet", new Class[]{String.class, Class.class}, new Object[]{servletName, servletClass}); } else { return context.addServlet(servletName, servletClass); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public T createServlet(Class c) throws ServletException { if (SecurityUtil.isPackageProtectionEnabled()) { try { return (T) invokeMethod(context, "createServlet", new Object[]{c}); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (t instanceof ServletException) { throw (ServletException) t; } return null; } } else { return context.createServlet(c); } } @Override public ServletRegistration getServletRegistration(String servletName) { if (SecurityUtil.isPackageProtectionEnabled()) { return (ServletRegistration) doPrivileged( "getServletRegistration", new Object[]{servletName}); } else { return context.getServletRegistration(servletName); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public Set getDefaultSessionTrackingModes() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Set) doPrivileged("getDefaultSessionTrackingModes", null); } else { return context.getDefaultSessionTrackingModes(); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public Set getEffectiveSessionTrackingModes() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Set) doPrivileged("getEffectiveSessionTrackingModes", null); } else { return context.getEffectiveSessionTrackingModes(); } } @Override public SessionCookieConfig getSessionCookieConfig() { if (SecurityUtil.isPackageProtectionEnabled()) { return (SessionCookieConfig) doPrivileged("getSessionCookieConfig", null); } else { return context.getSessionCookieConfig(); } } @Override public void setSessionTrackingModes( Set sessionTrackingModes) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("setSessionTrackingModes", new Object[]{sessionTrackingModes}); } else { context.setSessionTrackingModes(sessionTrackingModes); } } @Override public boolean setInitParameter(String name, String value) { if (SecurityUtil.isPackageProtectionEnabled()) { return ((Boolean) doPrivileged("setInitParameter", new Object[]{name, value})).booleanValue(); } else { return context.setInitParameter(name, value); } } @Override public void addListener(Class listenerClass) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("addListener", new Class[]{Class.class}, new Object[]{listenerClass}); } else { context.addListener(listenerClass); } } @Override public void addListener(String className) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("addListener", new Object[]{className}); } else { context.addListener(className); } } @Override public void addListener(T t) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("addListener", new Class[]{EventListener.class}, new Object[]{t}); } else { context.addListener(t); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public T createListener(Class c) throws ServletException { if (SecurityUtil.isPackageProtectionEnabled()) { try { return (T) invokeMethod(context, "createListener", new Object[]{c}); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (t instanceof ServletException) { throw (ServletException) t; } return null; } } else { return context.createListener(c); } } @Override public void declareRoles(String... roleNames) { if (SecurityUtil.isPackageProtectionEnabled()) { doPrivileged("declareRoles", new Object[]{roleNames}); } else { context.declareRoles(roleNames); } } @Override public ClassLoader getClassLoader() { if (SecurityUtil.isPackageProtectionEnabled()) { return (ClassLoader) doPrivileged("getClassLoader", null); } else { return context.getClassLoader(); } } @Override public int getEffectiveMajorVersion() { if (SecurityUtil.isPackageProtectionEnabled()) { return ((Integer) doPrivileged("getEffectiveMajorVersion", null)).intValue(); } else { return context.getEffectiveMajorVersion(); } } @Override public int getEffectiveMinorVersion() { if (SecurityUtil.isPackageProtectionEnabled()) { return ((Integer) doPrivileged("getEffectiveMinorVersion", null)).intValue(); } else { return context.getEffectiveMinorVersion(); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public Map getFilterRegistrations() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Map) doPrivileged( "getFilterRegistrations", null); } else { return context.getFilterRegistrations(); } } @Override public JspConfigDescriptor getJspConfigDescriptor() { if (SecurityUtil.isPackageProtectionEnabled()) { return (JspConfigDescriptor) doPrivileged("getJspConfigDescriptor", null); } else { return context.getJspConfigDescriptor(); } } @Override @SuppressWarnings("unchecked") // doPrivileged() returns the correct type public Map getServletRegistrations() { if (SecurityUtil.isPackageProtectionEnabled()) { return (Map) doPrivileged( "getServletRegistrations", null); } else { return context.getServletRegistrations(); } } /** * Use reflection to invoke the requested method. Cache the method object * to speed up the process * @param methodName The method to call. * @param params The arguments passed to the called method. */ private Object doPrivileged(final String methodName, final Object[] params) { try{ return invokeMethod(context, methodName, params); }catch(Throwable t){ ExceptionUtils.handleThrowable(t); throw new RuntimeException(t.getMessage(), t); } } /** * Use reflection to invoke the requested method. Cache the method object * to speed up the process * @param appContext The AppliationContext object on which the method * will be invoked * @param methodName The method to call. * @param params The arguments passed to the called method. */ private Object invokeMethod(ApplicationContext appContext, final String methodName, Object[] params) throws Throwable{ try{ Method method = objectCache.get(methodName); if (method == null){ method = appContext.getClass() .getMethod(methodName, classCache.get(methodName)); objectCache.put(methodName, method); } return executeMethod(method,appContext,params); } catch (Exception ex){ handleException(ex); return null; } finally { params = null; } } /** * Use reflection to invoke the requested method. Cache the method object * to speed up the process * @param methodName The method to invoke. * @param clazz The class where the method is. * @param params The arguments passed to the called method. */ private Object doPrivileged(final String methodName, final Class[] clazz, Object[] params) { try{ Method method = context.getClass().getMethod(methodName, clazz); return executeMethod(method,context,params); } catch (Exception ex){ try { handleException(ex); } catch (Throwable t){ ExceptionUtils.handleThrowable(t); throw new RuntimeException(t.getMessage()); } return null; } finally { params = null; } } /** * Executes the method of the specified ApplicationContext * @param method The method object to be invoked. * @param context The AppliationContext object on which the method * will be invoked * @param params The arguments passed to the called method. */ private Object executeMethod(final Method method, final ApplicationContext context, final Object[] params) throws PrivilegedActionException, IllegalAccessException, InvocationTargetException { if (SecurityUtil.isPackageProtectionEnabled()){ return AccessController.doPrivileged(new PrivilegedExceptionAction(){ @Override public Object run() throws IllegalAccessException, InvocationTargetException{ return method.invoke(context, params); } }); } else { return method.invoke(context, params); } } /** * * Throw the real exception. * @param ex The current exception */ private void handleException(Exception ex) throws Throwable { Throwable realException; if (ex instanceof PrivilegedActionException) { ex = ((PrivilegedActionException) ex).getException(); } if (ex instanceof InvocationTargetException) { realException = ex.getCause(); if (realException == null) { realException = ex; } } else { realException = ex; } throw realException; } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardHost.java0000644000175100017510000005262612271471332024056 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Valve; import org.apache.catalina.loader.WebappClassLoader; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.valves.ValveBase; import org.apache.tomcat.util.ExceptionUtils; /** * Standard implementation of the Host interface. Each * child container must be a Context implementation to process the * requests directed to a particular web application. * * @author Craig R. McClanahan * @author Remy Maucherat */ public class StandardHost extends ContainerBase implements Host { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( StandardHost.class ); // ----------------------------------------------------------- Constructors /** * Create a new StandardHost component with the default basic Valve. */ public StandardHost() { super(); pipeline.setBasic(new StandardHostValve()); } // ----------------------------------------------------- Instance Variables /** * The set of aliases for this Host. */ private String[] aliases = new String[0]; private final Object aliasesLock = new Object(); /** * The application root for this Host. */ private String appBase = "webapps"; /** * The XML root for this Host. */ private String xmlBase = null; /** * The auto deploy flag for this Host. */ private boolean autoDeploy = true; /** * The Java class name of the default context configuration class * for deployed web applications. */ private String configClass = "org.apache.catalina.startup.ContextConfig"; /** * The Java class name of the default Context implementation class for * deployed web applications. */ private String contextClass = "org.apache.catalina.core.StandardContext"; /** * The deploy on startup flag for this Host. */ private boolean deployOnStartup = true; /** * deploy Context XML config files property. */ private boolean deployXML = !Globals.IS_SECURITY_ENABLED; /** * Should XML files be copied to * $CATALINA_BASE/conf/<engine>/<host> by default when * a web application is deployed? */ private boolean copyXML = false; /** * The Java class name of the default error reporter implementation class * for deployed web applications. */ private String errorReportValveClass = "org.apache.catalina.valves.ErrorReportValve"; /** * The descriptive information string for this implementation. */ private static final String info = "org.apache.catalina.core.StandardHost/1.0"; /** * Unpack WARs property. */ private boolean unpackWARs = true; /** * Work Directory base for applications. */ private String workDir = null; /** * Should we create directories upon startup for appBase and xmlBase */ private boolean createDirs = true; /** * Track the class loaders for the child web applications so memory leaks * can be detected. */ private Map childClassLoaders = new WeakHashMap(); /** * Any file or directory in {@link #appBase} that this pattern matches will * be ignored by the automatic deployment process (both * {@link #deployOnStartup} and {@link #autoDeploy}). */ private Pattern deployIgnore = null; private boolean undeployOldVersions = false; // ------------------------------------------------------------- Properties @Override public boolean getUndeployOldVersions() { return undeployOldVersions; } @Override public void setUndeployOldVersions(boolean undeployOldVersions) { this.undeployOldVersions = undeployOldVersions; } @Override public ExecutorService getStartStopExecutor() { return startStopExecutor; } /** * Return the application root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. */ @Override public String getAppBase() { return (this.appBase); } /** * Set the application root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. * * @param appBase The new application root */ @Override public void setAppBase(String appBase) { String oldAppBase = this.appBase; this.appBase = appBase; support.firePropertyChange("appBase", oldAppBase, this.appBase); } /** * Return the XML root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. * If null, defaults to * ${catalina.base}/conf/<engine name>/<host name> directory */ @Override public String getXmlBase() { return (this.xmlBase); } /** * Set the Xml root for this Host. This can be an absolute * pathname, a relative pathname, or a URL. * If null, defaults to * ${catalina.base}/conf/<engine name>/<host name> directory * * @param xmlBase The new XML root */ @Override public void setXmlBase(String xmlBase) { String oldXmlBase = this.xmlBase; this.xmlBase = xmlBase; support.firePropertyChange("xmlBase", oldXmlBase, this.xmlBase); } /** * Returns true if the Host will attempt to create directories for appBase and xmlBase * unless they already exist. */ @Override public boolean getCreateDirs() { return createDirs; } /** * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup * @param createDirs */ @Override public void setCreateDirs(boolean createDirs) { this.createDirs = createDirs; } /** * Return the value of the auto deploy flag. If true, it indicates that * this host's child webapps will be dynamically deployed. */ @Override public boolean getAutoDeploy() { return (this.autoDeploy); } /** * Set the auto deploy flag value for this host. * * @param autoDeploy The new auto deploy flag */ @Override public void setAutoDeploy(boolean autoDeploy) { boolean oldAutoDeploy = this.autoDeploy; this.autoDeploy = autoDeploy; support.firePropertyChange("autoDeploy", oldAutoDeploy, this.autoDeploy); } /** * Return the Java class name of the context configuration class * for new web applications. */ @Override public String getConfigClass() { return (this.configClass); } /** * Set the Java class name of the context configuration class * for new web applications. * * @param configClass The new context configuration class */ @Override public void setConfigClass(String configClass) { String oldConfigClass = this.configClass; this.configClass = configClass; support.firePropertyChange("configClass", oldConfigClass, this.configClass); } /** * Return the Java class name of the Context implementation class * for new web applications. */ public String getContextClass() { return (this.contextClass); } /** * Set the Java class name of the Context implementation class * for new web applications. * * @param contextClass The new context implementation class */ public void setContextClass(String contextClass) { String oldContextClass = this.contextClass; this.contextClass = contextClass; support.firePropertyChange("contextClass", oldContextClass, this.contextClass); } /** * Return the value of the deploy on startup flag. If true, it indicates * that this host's child webapps should be discovered and automatically * deployed at startup time. */ @Override public boolean getDeployOnStartup() { return (this.deployOnStartup); } /** * Set the deploy on startup flag value for this host. * * @param deployOnStartup The new deploy on startup flag */ @Override public void setDeployOnStartup(boolean deployOnStartup) { boolean oldDeployOnStartup = this.deployOnStartup; this.deployOnStartup = deployOnStartup; support.firePropertyChange("deployOnStartup", oldDeployOnStartup, this.deployOnStartup); } /** * Deploy XML Context config files flag accessor. */ public boolean isDeployXML() { return (deployXML); } /** * Deploy XML Context config files flag mutator. */ public void setDeployXML(boolean deployXML) { this.deployXML = deployXML; } /** * Return the copy XML config file flag for this component. */ public boolean isCopyXML() { return (this.copyXML); } /** * Set the copy XML config file flag for this component. * * @param copyXML The new copy XML flag */ public void setCopyXML(boolean copyXML) { this.copyXML= copyXML; } /** * Return the Java class name of the error report valve class * for new web applications. */ public String getErrorReportValveClass() { return (this.errorReportValveClass); } /** * Set the Java class name of the error report valve class * for new web applications. * * @param errorReportValveClass The new error report valve class */ public void setErrorReportValveClass(String errorReportValveClass) { String oldErrorReportValveClassClass = this.errorReportValveClass; this.errorReportValveClass = errorReportValveClass; support.firePropertyChange("errorReportValveClass", oldErrorReportValveClassClass, this.errorReportValveClass); } /** * Return the canonical, fully qualified, name of the virtual host * this Container represents. */ @Override public String getName() { return (name); } /** * Set the canonical, fully qualified, name of the virtual host * this Container represents. * * @param name Virtual host name * * @exception IllegalArgumentException if name is null */ @Override public void setName(String name) { if (name == null) throw new IllegalArgumentException (sm.getString("standardHost.nullName")); name = name.toLowerCase(Locale.ENGLISH); // Internally all names are lower case String oldName = this.name; this.name = name; support.firePropertyChange("name", oldName, this.name); } /** * Unpack WARs flag accessor. */ public boolean isUnpackWARs() { return (unpackWARs); } /** * Unpack WARs flag mutator. */ public void setUnpackWARs(boolean unpackWARs) { this.unpackWARs = unpackWARs; } /** * Host work directory base. */ public String getWorkDir() { return (workDir); } /** * Host work directory base. */ public void setWorkDir(String workDir) { this.workDir = workDir; } /** * Return the regular expression that defines the files and directories in * the host's {@link #appBase} that will be ignored by the automatic * deployment process. */ @Override public String getDeployIgnore() { if (deployIgnore == null) { return null; } return this.deployIgnore.toString(); } /** * Return the compiled regular expression that defines the files and * directories in the host's {@link #appBase} that will be ignored by the * automatic deployment process. */ @Override public Pattern getDeployIgnorePattern() { return this.deployIgnore; } /** * Set the regular expression that defines the files and directories in * the host's {@link #appBase} that will be ignored by the automatic * deployment process. */ @Override public void setDeployIgnore(String deployIgnore) { String oldDeployIgnore; if (this.deployIgnore == null) { oldDeployIgnore = null; } else { oldDeployIgnore = this.deployIgnore.toString(); } if (deployIgnore == null) { this.deployIgnore = null; } else { this.deployIgnore = Pattern.compile(deployIgnore); } support.firePropertyChange("deployIgnore", oldDeployIgnore, deployIgnore); } // --------------------------------------------------------- Public Methods /** * Add an alias name that should be mapped to this same Host. * * @param alias The alias to be added */ @Override public void addAlias(String alias) { alias = alias.toLowerCase(Locale.ENGLISH); synchronized (aliasesLock) { // Skip duplicate aliases for (int i = 0; i < aliases.length; i++) { if (aliases[i].equals(alias)) return; } // Add this alias to the list String newAliases[] = new String[aliases.length + 1]; for (int i = 0; i < aliases.length; i++) newAliases[i] = aliases[i]; newAliases[aliases.length] = alias; aliases = newAliases; } // Inform interested listeners fireContainerEvent(ADD_ALIAS_EVENT, alias); } /** * Add a child Container, only if the proposed child is an implementation * of Context. * * @param child Child container to be added */ @Override public void addChild(Container child) { child.addLifecycleListener(new MemoryLeakTrackingListener()); if (!(child instanceof Context)) throw new IllegalArgumentException (sm.getString("standardHost.notContext")); super.addChild(child); } /** * Used to ensure the regardless of {@link Context} implementation, a record * is kept of the class loader used every time a context starts. */ private class MemoryLeakTrackingListener implements LifecycleListener { @Override public void lifecycleEvent(LifecycleEvent event) { if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) { if (event.getSource() instanceof Context) { Context context = ((Context) event.getSource()); childClassLoaders.put(context.getLoader().getClassLoader(), context.getServletContext().getContextPath()); } } } } /** * Attempt to identify the contexts that have a class loader memory leak. * This is usually triggered on context reload. Note: This method attempts * to force a full garbage collection. This should be used with extreme * caution on a production system. */ public String[] findReloadedContextMemoryLeaks() { System.gc(); List result = new ArrayList(); for (Map.Entry entry : childClassLoaders.entrySet()) { ClassLoader cl = entry.getKey(); if (cl instanceof WebappClassLoader) { if (!((WebappClassLoader) cl).isStarted()) { result.add(entry.getValue()); } } } return result.toArray(new String[result.size()]); } /** * Return the set of alias names for this Host. If none are defined, * a zero length array is returned. */ @Override public String[] findAliases() { synchronized (aliasesLock) { return (this.aliases); } } /** * Return descriptive information about this Container implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Remove the specified alias name from the aliases for this Host. * * @param alias Alias name to be removed */ @Override public void removeAlias(String alias) { alias = alias.toLowerCase(Locale.ENGLISH); synchronized (aliasesLock) { // Make sure this alias is currently present int n = -1; for (int i = 0; i < aliases.length; i++) { if (aliases[i].equals(alias)) { n = i; break; } } if (n < 0) return; // Remove the specified alias int j = 0; String results[] = new String[aliases.length - 1]; for (int i = 0; i < aliases.length; i++) { if (i != n) results[j++] = aliases[i]; } aliases = results; } // Inform interested listeners fireContainerEvent(REMOVE_ALIAS_EVENT, alias); } /** * Return a String representation of this component. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); if (getParent() != null) { sb.append(getParent().toString()); sb.append("."); } sb.append("StandardHost["); sb.append(getName()); sb.append("]"); return (sb.toString()); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Set error report valve String errorValve = getErrorReportValveClass(); if ((errorValve != null) && (!errorValve.equals(""))) { try { boolean found = false; Valve[] valves = getPipeline().getValves(); for (Valve valve : valves) { if (errorValve.equals(valve.getClass().getName())) { found = true; break; } } if(!found) { Valve valve = (Valve) Class.forName(errorValve).newInstance(); getPipeline().addValve(valve); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString( "standardHost.invalidErrorReportValveClass", errorValve), t); } } super.startInternal(); } // -------------------- JMX -------------------- /** * Return the MBean Names of the Valves associated with this Host * * @exception Exception if an MBean cannot be created or registered */ public String [] getValveNames() throws Exception { Valve [] valves = this.getPipeline().getValves(); String [] mbeanNames = new String[valves.length]; for (int i = 0; i < valves.length; i++) { if( valves[i] == null ) continue; if( ((ValveBase)valves[i]).getObjectName() == null ) continue; mbeanNames[i] = ((ValveBase)valves[i]).getObjectName().toString(); } return mbeanNames; } public String[] getAliases() { synchronized (aliasesLock) { return aliases; } } @Override protected String getObjectNameKeyProperties() { StringBuilder keyProperties = new StringBuilder("type=Host"); keyProperties.append(MBeanUtils.getContainerKeyProperties(this)); return keyProperties.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/core/RestrictedServlets.properties0000644000175100017510000000164612271471332026567 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. org.apache.catalina.ssi.SSIServlet=restricted org.apache.catalina.servlets.CGIServlet=restricted org.apache.catalina.manager.JMXProxyServlet=restricted tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationFilterFactory.java0000644000175100017510000003121712271471332026412 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import javax.servlet.DispatcherType; import javax.servlet.Servlet; import javax.servlet.ServletRequest; import org.apache.catalina.Globals; import org.apache.catalina.Wrapper; import org.apache.catalina.comet.CometFilter; import org.apache.catalina.connector.Request; import org.apache.catalina.deploy.FilterMap; import org.apache.tomcat.util.ExceptionUtils; /** * Factory for the creation and caching of Filters and creation * of Filter Chains. * * @author Greg Murray * @author Remy Maucherat */ public final class ApplicationFilterFactory { // -------------------------------------------------------------- Constants /** * @deprecated Use {@link Globals#DISPATCHER_TYPE_ATTR} */ @Deprecated public static final String DISPATCHER_TYPE_ATTR = Globals.DISPATCHER_TYPE_ATTR; /** * @deprecated Use {@link Globals#DISPATCHER_REQUEST_PATH_ATTR} */ @Deprecated public static final String DISPATCHER_REQUEST_PATH_ATTR = Globals.DISPATCHER_REQUEST_PATH_ATTR; private static ApplicationFilterFactory factory = null; // ----------------------------------------------------------- Constructors private ApplicationFilterFactory() { // Prevent instantiation outside of the getInstanceMethod(). } // --------------------------------------------------------- Public Methods /** * Return the factory instance. */ public static ApplicationFilterFactory getInstance() { if (factory == null) { factory = new ApplicationFilterFactory(); } return factory; } /** * Construct and return a FilterChain implementation that will wrap the * execution of the specified servlet instance. If we should not execute * a filter chain at all, return null. * * @param request The servlet request we are processing * @param servlet The servlet instance to be wrapped */ public ApplicationFilterChain createFilterChain (ServletRequest request, Wrapper wrapper, Servlet servlet) { // get the dispatcher type DispatcherType dispatcher = null; if (request.getAttribute(Globals.DISPATCHER_TYPE_ATTR) != null) { dispatcher = (DispatcherType) request.getAttribute( Globals.DISPATCHER_TYPE_ATTR); } String requestPath = null; Object attribute = request.getAttribute( Globals.DISPATCHER_REQUEST_PATH_ATTR); if (attribute != null){ requestPath = attribute.toString(); } // If there is no servlet to execute, return null if (servlet == null) return (null); boolean comet = false; // Create and initialize a filter chain object ApplicationFilterChain filterChain = null; if (request instanceof Request) { Request req = (Request) request; comet = req.isComet(); if (Globals.IS_SECURITY_ENABLED) { // Security: Do not recycle filterChain = new ApplicationFilterChain(); if (comet) { req.setFilterChain(filterChain); } } else { filterChain = (ApplicationFilterChain) req.getFilterChain(); if (filterChain == null) { filterChain = new ApplicationFilterChain(); req.setFilterChain(filterChain); } } } else { // Request dispatcher in use filterChain = new ApplicationFilterChain(); } filterChain.setServlet(servlet); filterChain.setSupport (((StandardWrapper)wrapper).getInstanceSupport()); // Acquire the filter mappings for this Context StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done if ((filterMaps == null) || (filterMaps.length == 0)) return (filterChain); // Acquire the information we will need to match filter mappings String servletName = wrapper.getName(); // Add the relevant path-mapped filters to this filter chain for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersURL(filterMaps[i], requestPath)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } boolean isCometFilter = false; if (comet) { try { isCometFilter = filterConfig.getFilter() instanceof CometFilter; } catch (Exception e) { // Note: The try catch is there because getFilter has a lot of // declared exceptions. However, the filter is allocated much // earlier Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); } if (isCometFilter) { filterChain.addFilter(filterConfig); } } else { filterChain.addFilter(filterConfig); } } // Add filters that match on servlet name second for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersServlet(filterMaps[i], servletName)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } boolean isCometFilter = false; if (comet) { try { isCometFilter = filterConfig.getFilter() instanceof CometFilter; } catch (Exception e) { // Note: The try catch is there because getFilter has a lot of // declared exceptions. However, the filter is allocated much // earlier } if (isCometFilter) { filterChain.addFilter(filterConfig); } } else { filterChain.addFilter(filterConfig); } } // Return the completed filter chain return (filterChain); } // -------------------------------------------------------- Private Methods /** * Return true if the context-relative request path * matches the requirements of the specified filter mapping; * otherwise, return false. * * @param filterMap Filter mapping being checked * @param requestPath Context-relative request path of this request */ private boolean matchFiltersURL(FilterMap filterMap, String requestPath) { // Check the specific "*" special URL pattern, which also matches // named dispatches if (filterMap.getMatchAllUrlPatterns()) return (true); if (requestPath == null) return (false); // Match on context relative request path String[] testPaths = filterMap.getURLPatterns(); for (int i = 0; i < testPaths.length; i++) { if (matchFiltersURL(testPaths[i], requestPath)) { return (true); } } // No match return (false); } /** * Return true if the context-relative request path * matches the requirements of the specified filter mapping; * otherwise, return false. * * @param testPath URL mapping being checked * @param requestPath Context-relative request path of this request */ private boolean matchFiltersURL(String testPath, String requestPath) { if (testPath == null) return (false); // Case 1 - Exact Match if (testPath.equals(requestPath)) return (true); // Case 2 - Path Match ("/.../*") if (testPath.equals("/*")) return (true); if (testPath.endsWith("/*")) { if (testPath.regionMatches(0, requestPath, 0, testPath.length() - 2)) { if (requestPath.length() == (testPath.length() - 2)) { return (true); } else if ('/' == requestPath.charAt(testPath.length() - 2)) { return (true); } } return (false); } // Case 3 - Extension Match if (testPath.startsWith("*.")) { int slash = requestPath.lastIndexOf('/'); int period = requestPath.lastIndexOf('.'); if ((slash >= 0) && (period > slash) && (period != requestPath.length() - 1) && ((requestPath.length() - period) == (testPath.length() - 1))) { return (testPath.regionMatches(2, requestPath, period + 1, testPath.length() - 2)); } } // Case 4 - "Default" Match return (false); // NOTE - Not relevant for selecting filters } /** * Return true if the specified servlet name matches * the requirements of the specified filter mapping; otherwise * return false. * * @param filterMap Filter mapping being checked * @param servletName Servlet name being checked */ private boolean matchFiltersServlet(FilterMap filterMap, String servletName) { if (servletName == null) { return (false); } // Check the specific "*" special servlet name else if (filterMap.getMatchAllServletNames()) { return (true); } else { String[] servletNames = filterMap.getServletNames(); for (int i = 0; i < servletNames.length; i++) { if (servletName.equals(servletNames[i])) { return (true); } } return false; } } /** * Convenience method which returns true if the dispatcher type * matches the dispatcher types specified in the FilterMap */ private boolean matchDispatcher(FilterMap filterMap, DispatcherType type) { switch (type) { case FORWARD : { if ((filterMap.getDispatcherMapping() & FilterMap.FORWARD) > 0) { return true; } break; } case INCLUDE : { if ((filterMap.getDispatcherMapping() & FilterMap.INCLUDE) > 0) { return true; } break; } case REQUEST : { if ((filterMap.getDispatcherMapping() & FilterMap.REQUEST) > 0) { return true; } break; } case ERROR : { if ((filterMap.getDispatcherMapping() & FilterMap.ERROR) > 0) { return true; } break; } case ASYNC : { if ((filterMap.getDispatcherMapping() & FilterMap.ASYNC) > 0) { return true; } break; } } return false; } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardThreadExecutor.java0000644000175100017510000002220212271471332026052 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import org.apache.catalina.Executor; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.tomcat.util.threads.ResizableExecutor; import org.apache.tomcat.util.threads.TaskQueue; import org.apache.tomcat.util.threads.TaskThreadFactory; import org.apache.tomcat.util.threads.ThreadPoolExecutor; public class StandardThreadExecutor extends LifecycleMBeanBase implements Executor, ResizableExecutor { // ---------------------------------------------- Properties /** * Default thread priority */ protected int threadPriority = Thread.NORM_PRIORITY; /** * Run threads in daemon or non-daemon state */ protected boolean daemon = true; /** * Default name prefix for the thread name */ protected String namePrefix = "tomcat-exec-"; /** * max number of threads */ protected int maxThreads = 200; /** * min number of threads */ protected int minSpareThreads = 25; /** * idle time in milliseconds */ protected int maxIdleTime = 60000; /** * The executor we use for this component */ protected ThreadPoolExecutor executor = null; /** * the name of this thread pool */ protected String name; /** * prestart threads? */ protected boolean prestartminSpareThreads = false; /** * The maximum number of elements that can queue up before we reject them */ protected int maxQueueSize = Integer.MAX_VALUE; /** * After a context is stopped, threads in the pool are renewed. To avoid * renewing all threads at the same time, this delay is observed between 2 * threads being renewed. */ protected long threadRenewalDelay = org.apache.tomcat.util.threads.Constants.DEFAULT_THREAD_RENEWAL_DELAY; private TaskQueue taskqueue = null; // ---------------------------------------------- Constructors public StandardThreadExecutor() { //empty constructor for the digester } // ---------------------------------------------- Public Methods @Override protected void initInternal() throws LifecycleException { super.initInternal(); } /** * Start the component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { taskqueue = new TaskQueue(maxQueueSize); TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority()); executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf); if (prestartminSpareThreads) { executor.prestartAllCoreThreads(); } taskqueue.setParent(executor); setState(LifecycleState.STARTING); } /** * Stop the component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); if ( executor != null ) executor.shutdownNow(); executor = null; taskqueue = null; } @Override protected void destroyInternal() throws LifecycleException { super.destroyInternal(); } @Override public void execute(Runnable command, long timeout, TimeUnit unit) { if ( executor != null ) { executor.execute(command,timeout,unit); } else { throw new IllegalStateException("StandardThreadExecutor not started."); } } @Override public void execute(Runnable command) { if ( executor != null ) { try { executor.execute(command); } catch (RejectedExecutionException rx) { //there could have been contention around the queue if ( !( (TaskQueue) executor.getQueue()).force(command) ) throw new RejectedExecutionException("Work queue full."); } } else throw new IllegalStateException("StandardThreadPool not started."); } public void contextStopping() { if (executor != null) { executor.contextStopping(); } } public int getThreadPriority() { return threadPriority; } public boolean isDaemon() { return daemon; } public String getNamePrefix() { return namePrefix; } public int getMaxIdleTime() { return maxIdleTime; } @Override public int getMaxThreads() { return maxThreads; } public int getMinSpareThreads() { return minSpareThreads; } @Override public String getName() { return name; } public boolean isPrestartminSpareThreads() { return prestartminSpareThreads; } public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } public void setDaemon(boolean daemon) { this.daemon = daemon; } public void setNamePrefix(String namePrefix) { this.namePrefix = namePrefix; } public void setMaxIdleTime(int maxIdleTime) { this.maxIdleTime = maxIdleTime; if (executor != null) { executor.setKeepAliveTime(maxIdleTime, TimeUnit.MILLISECONDS); } } public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; if (executor != null) { executor.setMaximumPoolSize(maxThreads); } } public void setMinSpareThreads(int minSpareThreads) { this.minSpareThreads = minSpareThreads; if (executor != null) { executor.setCorePoolSize(minSpareThreads); } } public void setPrestartminSpareThreads(boolean prestartminSpareThreads) { this.prestartminSpareThreads = prestartminSpareThreads; } public void setName(String name) { this.name = name; } public void setMaxQueueSize(int size) { this.maxQueueSize = size; } public int getMaxQueueSize() { return maxQueueSize; } public long getThreadRenewalDelay() { return threadRenewalDelay; } public void setThreadRenewalDelay(long threadRenewalDelay) { this.threadRenewalDelay = threadRenewalDelay; if (executor != null) { executor.setThreadRenewalDelay(threadRenewalDelay); } } // Statistics from the thread pool @Override public int getActiveCount() { return (executor != null) ? executor.getActiveCount() : 0; } public long getCompletedTaskCount() { return (executor != null) ? executor.getCompletedTaskCount() : 0; } public int getCorePoolSize() { return (executor != null) ? executor.getCorePoolSize() : 0; } public int getLargestPoolSize() { return (executor != null) ? executor.getLargestPoolSize() : 0; } @Override public int getPoolSize() { return (executor != null) ? executor.getPoolSize() : 0; } public int getQueueSize() { return (executor != null) ? executor.getQueue().size() : -1; } @Override public boolean resizePool(int corePoolSize, int maximumPoolSize) { if (executor == null) return false; executor.setCorePoolSize(corePoolSize); executor.setMaximumPoolSize(maximumPoolSize); return true; } @Override public boolean resizeQueue(int capacity) { return false; } @Override protected String getDomainInternal() { // No way to navigate to Engine. Needs to have domain set. return null; } @Override protected String getObjectNameKeyProperties() { StringBuilder name = new StringBuilder("type=Executor,name="); name.append(getName()); return name.toString(); } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationFilterConfig.java0000644000175100017510000003170612271471332026213 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.management.ObjectName; import javax.naming.NamingException; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.security.SecurityUtil; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.log.SystemLogHandler; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.modeler.Util; import org.apache.tomcat.util.res.StringManager; /** * Implementation of a javax.servlet.FilterConfig useful in * managing the filter instances instantiated when a web application * is first started. * * @author Craig R. McClanahan */ public final class ApplicationFilterConfig implements FilterConfig, Serializable { private static final long serialVersionUID = 1L; protected static final StringManager sm = StringManager.getManager(Constants.Package); private static final org.apache.juli.logging.Log log = LogFactory.getLog(ApplicationFilterConfig.class); /** * Empty String collection to serve as the basis for empty enumerations. */ private static final List emptyString = Collections.emptyList(); // ----------------------------------------------------------- Constructors /** * Construct a new ApplicationFilterConfig for the specified filter * definition. * * @param context The context with which we are associated * @param filterDef Filter definition for which a FilterConfig is to be * constructed * * @exception ClassCastException if the specified class does not implement * the javax.servlet.Filter interface * @exception ClassNotFoundException if the filter class cannot be found * @exception IllegalAccessException if the filter class cannot be * publicly instantiated * @exception InstantiationException if an exception occurs while * instantiating the filter object * @exception ServletException if thrown by the filter's init() method * @throws NamingException * @throws InvocationTargetException */ ApplicationFilterConfig(Context context, FilterDef filterDef) throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException { super(); this.context = context; this.filterDef = filterDef; // Allocate a new filter instance if necessary if (filterDef.getFilter() == null) { getFilter(); } else { this.filter = filterDef.getFilter(); getInstanceManager().newInstance(filter); initFilter(); } } // ----------------------------------------------------- Instance Variables /** * The Context with which we are associated. */ private transient Context context = null; /** * The application Filter we are configured for. */ private transient Filter filter = null; /** * The FilterDef that defines our associated Filter. */ private final FilterDef filterDef; /** * the InstanceManager used to create and destroy filter instances. */ private transient InstanceManager instanceManager; /** * JMX registration name */ private ObjectName oname; // --------------------------------------------------- FilterConfig Methods /** * Return the name of the filter we are configuring. */ @Override public String getFilterName() { return (filterDef.getFilterName()); } /** * Return the class of the filter we are configuring. */ public String getFilterClass() { return filterDef.getFilterClass(); } /** * Return a String containing the value of the named * initialization parameter, or null if the parameter * does not exist. * * @param name Name of the requested initialization parameter */ @Override public String getInitParameter(String name) { Map map = filterDef.getParameterMap(); if (map == null) { return (null); } return map.get(name); } /** * Return an Enumeration of the names of the initialization * parameters for this Filter. */ @Override public Enumeration getInitParameterNames() { Map map = filterDef.getParameterMap(); if (map == null) { return Collections.enumeration(emptyString); } return Collections.enumeration(map.keySet()); } /** * Return the ServletContext of our associated web application. */ @Override public ServletContext getServletContext() { return this.context.getServletContext(); } /** * Return a String representation of this object. */ @Override public String toString() { StringBuilder sb = new StringBuilder("ApplicationFilterConfig["); sb.append("name="); sb.append(filterDef.getFilterName()); sb.append(", filterClass="); sb.append(filterDef.getFilterClass()); sb.append("]"); return (sb.toString()); } // --------------------------------------------------------- Public Methods public Map getFilterInitParameterMap() { return Collections.unmodifiableMap(filterDef.getParameterMap()); } // -------------------------------------------------------- Package Methods /** * Return the application Filter we are configured for. * * @exception ClassCastException if the specified class does not implement * the javax.servlet.Filter interface * @exception ClassNotFoundException if the filter class cannot be found * @exception IllegalAccessException if the filter class cannot be * publicly instantiated * @exception InstantiationException if an exception occurs while * instantiating the filter object * @exception ServletException if thrown by the filter's init() method * @throws NamingException * @throws InvocationTargetException */ Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException { // Return the existing filter instance, if any if (this.filter != null) return (this.filter); // Identify the class loader we will be using String filterClass = filterDef.getFilterClass(); this.filter = (Filter) getInstanceManager().newInstance(filterClass); initFilter(); return (this.filter); } private void initFilter() throws ServletException { if (context instanceof StandardContext && context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); filter.init(this); } finally { String capturedlog = SystemLogHandler.stopCapture(); if (capturedlog != null && capturedlog.length() > 0) { getServletContext().log(capturedlog); } } } else { filter.init(this); } // Expose filter via JMX registerJMX(); } /** * Return the filter definition we are configured for. */ FilterDef getFilterDef() { return (this.filterDef); } /** * Release the Filter instance associated with this FilterConfig, * if there is one. */ void release() { unregisterJMX(); if (this.filter != null) { try { if (Globals.IS_SECURITY_ENABLED) { try { SecurityUtil.doAsPrivilege("destroy", filter); } finally { SecurityUtil.remove(filter); } } else { filter.destroy(); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); context.getLogger().error(sm.getString( "applicationFilterConfig.release", filterDef.getFilterName(), filterDef.getFilterClass()), t); } if (!context.getIgnoreAnnotations()) { try { ((StandardContext) context).getInstanceManager().destroyInstance(this.filter); } catch (Exception e) { Throwable t = ExceptionUtils .unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); context.getLogger().error("ApplicationFilterConfig.preDestroy", t); } } } this.filter = null; } // -------------------------------------------------------- Private Methods private InstanceManager getInstanceManager() { if (instanceManager == null) { if (context instanceof StandardContext) { instanceManager = ((StandardContext)context).getInstanceManager(); } else { instanceManager = new DefaultInstanceManager(null, new HashMap>(), context, getClass().getClassLoader()); } } return instanceManager; } private void registerJMX() { String parentName = context.getName(); if (!parentName.startsWith("/")) { parentName = "/" + parentName; } String hostName = context.getParent().getName(); hostName = (hostName == null) ? "DEFAULT" : hostName; // domain == engine name String domain = context.getParent().getParent().getName(); String webMod = "//" + hostName + parentName; String onameStr = null; String filterName = filterDef.getFilterName(); if (Util.objectNameValueNeedsQuote(filterName)) { filterName = ObjectName.quote(filterName); } if (context instanceof StandardContext) { StandardContext standardContext = (StandardContext) context; onameStr = domain + ":j2eeType=Filter,name=" + filterName + ",WebModule=" + webMod + ",J2EEApplication=" + standardContext.getJ2EEApplication() + ",J2EEServer=" + standardContext.getJ2EEServer(); } else { onameStr = domain + ":j2eeType=Filter,name=" + filterName + ",WebModule=" + webMod; } try { oname = new ObjectName(onameStr); Registry.getRegistry(null, null).registerComponent(this, oname, null); } catch (Exception ex) { log.info(sm.getString("applicationFilterConfig.jmxRegisterFail", getFilterClass(), getFilterName()), ex); } } private void unregisterJMX() { // unregister this component if (oname != null) { try { Registry.getRegistry(null, null).unregisterComponent(oname); if (log.isDebugEnabled()) log.debug(sm.getString( "applicationFilterConfig.jmxUnregister", getFilterClass(), getFilterName())); } catch(Exception ex) { log.error(sm.getString( "applicationFilterConfig.jmxUnregisterFail", getFilterClass(), getFilterName()), ex); } } } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationResponse.java0000644000175100017510000001161412271471332025432 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.Locale; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; /** * Wrapper around a javax.servlet.ServletResponse * that transforms an application response object (which might be the original * one passed to a servlet, or might be based on the 2.3 * javax.servlet.ServletResponseWrapper class) * back into an internal org.apache.catalina.Response. *

    * WARNING: Due to Java's lack of support for multiple * inheritance, all of the logic in ApplicationResponse is * duplicated in ApplicationHttpResponse. Make sure that you * keep these two classes in synchronization when making changes! * * @author Craig R. McClanahan */ class ApplicationResponse extends ServletResponseWrapper { // ----------------------------------------------------------- Constructors /** * Construct a new wrapped response around the specified servlet response. * * @param response The servlet response being wrapped */ @Deprecated public ApplicationResponse(ServletResponse response) { this(response, false); } /** * Construct a new wrapped response around the specified servlet response. * * @param response The servlet response being wrapped * @param included true if this response is being processed * by a RequestDispatcher.include() call */ public ApplicationResponse(ServletResponse response, boolean included) { super(response); setIncluded(included); } // ----------------------------------------------------- Instance Variables /** * Is this wrapped response the subject of an include() * call? */ protected boolean included = false; // ------------------------------------------------ ServletResponse Methods /** * Disallow reset() calls on a included response. * * @exception IllegalStateException if the response has already * been committed */ @Override public void reset() { // If already committed, the wrapped response will throw ISE if (!included || getResponse().isCommitted()) getResponse().reset(); } /** * Disallow setContentLength() calls on an included response. * * @param len The new content length */ @Override public void setContentLength(int len) { if (!included) getResponse().setContentLength(len); } /** * Disallow setContentType() calls on an included response. * * @param type The new content type */ @Override public void setContentType(String type) { if (!included) getResponse().setContentType(type); } /** * Ignore setLocale() calls on an included response. * * @param loc The new locale */ @Override public void setLocale(Locale loc) { if (!included) getResponse().setLocale(loc); } /** * Ignore setBufferSize() calls on an included response. * * @param size The buffer size */ @Override public void setBufferSize(int size) { if (!included) getResponse().setBufferSize(size); } // ----------------------------------------- ServletResponseWrapper Methods /** * Set the response that we are wrapping. * * @param response The new wrapped response */ @Override public void setResponse(ServletResponse response) { super.setResponse(response); } // -------------------------------------------------------- Package Methods /** * Return the included flag for this response. */ @Deprecated boolean isIncluded() { return (this.included); } /** * Set the included flag for this response. * * @param included The new included flag */ void setIncluded(boolean included) { this.included = included; } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationContext.java0000644000175100017510000015260612274431005025263 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.Enumeration; import java.util.EventListener; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.naming.Binding; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.LifecycleState; import org.apache.catalina.Service; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Connector; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.util.ResourceSet; import org.apache.catalina.util.ServerInfo; import org.apache.naming.resources.DirContextURLStreamHandler; import org.apache.naming.resources.Resource; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.RequestUtil; import org.apache.tomcat.util.http.mapper.MappingData; import org.apache.tomcat.util.res.StringManager; /** * Standard implementation of ServletContext that represents * a web application's execution environment. An instance of this class is * associated with each instance of StandardContext. * * @author Craig R. McClanahan * @author Remy Maucherat */ public class ApplicationContext implements ServletContext { protected static final boolean STRICT_SERVLET_COMPLIANCE; protected static final boolean GET_RESOURCE_REQUIRE_SLASH; static { STRICT_SERVLET_COMPLIANCE = Globals.STRICT_SERVLET_COMPLIANCE; String requireSlash = System.getProperty( "org.apache.catalina.core.ApplicationContext.GET_RESOURCE_REQUIRE_SLASH"); if (requireSlash == null) { GET_RESOURCE_REQUIRE_SLASH = STRICT_SERVLET_COMPLIANCE; } else { GET_RESOURCE_REQUIRE_SLASH = Boolean.valueOf(requireSlash).booleanValue(); } } // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class, associated with the specified * Context instance. * * @param context The associated Context instance */ public ApplicationContext(StandardContext context) { super(); this.context = context; this.sessionCookieConfig = new ApplicationSessionCookieConfig(context); // Populate session tracking modes populateSessionTrackingModes(); } // ----------------------------------------------------- Instance Variables /** * The context attributes for this context. */ protected Map attributes = new ConcurrentHashMap(); /** * List of read only attributes for this context. */ private Map readOnlyAttributes = new ConcurrentHashMap(); /** * The Context instance with which we are associated. */ private StandardContext context = null; /** * Empty String collection to serve as the basis for empty enumerations. */ private static final List emptyString = Collections.emptyList(); /** * Empty Servlet collection to serve as the basis for empty enumerations. */ private static final List emptyServlet = Collections.emptyList(); /** * The facade around this object. */ private ServletContext facade = new ApplicationContextFacade(this); /** * The merged context initialization parameters for this Context. */ private final ConcurrentHashMap parameters = new ConcurrentHashMap(); /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * Thread local data used during request dispatch. */ private ThreadLocal dispatchData = new ThreadLocal(); /** * Session Cookie config */ private SessionCookieConfig sessionCookieConfig; /** * Session tracking modes */ private Set sessionTrackingModes = null; private Set defaultSessionTrackingModes = null; private Set supportedSessionTrackingModes = null; /** * Flag that indicates if a new {@link ServletContextListener} may be added * to the application. Once the first {@link ServletContextListener} is * called, no more may be added. */ private boolean newServletContextListenerAllowed = true; // --------------------------------------------------------- Public Methods /** * Return the resources object that is mapped to a specified path. * The path must begin with a "/" and is interpreted as relative to the * current context root. */ @Deprecated public DirContext getResources() { return context.getResources(); } // ------------------------------------------------- ServletContext Methods /** * Return the value of the specified context attribute, if any; * otherwise return null. * * @param name Name of the context attribute to return */ @Override public Object getAttribute(String name) { return (attributes.get(name)); } /** * Return an enumeration of the names of the context attributes * associated with this context. */ @Override public Enumeration getAttributeNames() { Set names = new HashSet(); names.addAll(attributes.keySet()); return Collections.enumeration(names); } /** * Return a ServletContext object that corresponds to a * specified URI on the server. This method allows servlets to gain * access to the context for various parts of the server, and as needed * obtain RequestDispatcher objects or resources from the * context. The given path must be absolute (beginning with a "/"), * and is interpreted based on our virtual host's document root. * * @param uri Absolute URI of a resource on the server */ @Override public ServletContext getContext(String uri) { // Validate the format of the specified argument if ((uri == null) || (!uri.startsWith("/"))) return (null); Context child = null; try { Host host = (Host) context.getParent(); String mapuri = uri; while (true) { child = (Context) host.findChild(mapuri); if (child != null) break; int slash = mapuri.lastIndexOf('/'); if (slash < 0) break; mapuri = mapuri.substring(0, slash); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); return (null); } if (child == null) return (null); if (context.getCrossContext()) { // If crossContext is enabled, can always return the context return child.getServletContext(); } else if (child == context) { // Can still return the current context return context.getServletContext(); } else { // Nothing to return return (null); } } /** * Return the main path associated with this context. */ @Override public String getContextPath() { return context.getPath(); } /** * Return the value of the specified initialization parameter, or * null if this parameter does not exist. * * @param name Name of the initialization parameter to retrieve */ @Override public String getInitParameter(final String name) { // Special handling for XML settings as the context setting must // always override anything that might have been set by an application. if (Globals.JASPER_XML_VALIDATION_TLD_INIT_PARAM.equals(name) && context.getTldValidation()) { return "true"; } if (Globals.JASPER_XML_BLOCK_EXTERNAL_INIT_PARAM.equals(name)) { if (!context.getXmlBlockExternal()) { // System admin has explicitly changed the default return "false"; } } return parameters.get(name); } /** * Return the names of the context's initialization parameters, or an * empty enumeration if the context has no initialization parameters. */ @Override public Enumeration getInitParameterNames() { Set names = new HashSet(); names.addAll(parameters.keySet()); // Special handling for XML settings as these attributes will always be // available if they have been set on the context if (context.getTldValidation()) { names.add(Globals.JASPER_XML_VALIDATION_TLD_INIT_PARAM); } if (!context.getXmlBlockExternal()) { names.add(Globals.JASPER_XML_BLOCK_EXTERNAL_INIT_PARAM); } return Collections.enumeration(names); } /** * Return the major version of the Java Servlet API that we implement. */ @Override public int getMajorVersion() { return (Constants.MAJOR_VERSION); } /** * Return the minor version of the Java Servlet API that we implement. */ @Override public int getMinorVersion() { return (Constants.MINOR_VERSION); } /** * Return the MIME type of the specified file, or null if * the MIME type cannot be determined. * * @param file Filename for which to identify a MIME type */ @Override public String getMimeType(String file) { if (file == null) return (null); int period = file.lastIndexOf("."); if (period < 0) return (null); String extension = file.substring(period + 1); if (extension.length() < 1) return (null); return (context.findMimeMapping(extension)); } /** * Return a RequestDispatcher object that acts as a * wrapper for the named servlet. * * @param name Name of the servlet for which a dispatcher is requested */ @Override public RequestDispatcher getNamedDispatcher(String name) { // Validate the name argument if (name == null) return (null); // Create and return a corresponding request dispatcher Wrapper wrapper = (Wrapper) context.findChild(name); if (wrapper == null) return (null); return new ApplicationDispatcher(wrapper, null, null, null, null, name); } /** * Return the real path for a given virtual path, if possible; otherwise * return null. * * @param path The path to the desired resource */ @Override public String getRealPath(String path) { return context.getRealPath(path); } /** * Return a RequestDispatcher instance that acts as a * wrapper for the resource at the given path. The path must begin * with a "/" and is interpreted as relative to the current context root. * * @param path The path to the desired resource. */ @Override public RequestDispatcher getRequestDispatcher(String path) { // Validate the path argument if (path == null) return (null); if (!path.startsWith("/")) throw new IllegalArgumentException (sm.getString ("applicationContext.requestDispatcher.iae", path)); // Get query string String queryString = null; String normalizedPath = path; int pos = normalizedPath.indexOf('?'); if (pos >= 0) { queryString = normalizedPath.substring(pos + 1); normalizedPath = normalizedPath.substring(0, pos); } normalizedPath = RequestUtil.normalize(normalizedPath); if (normalizedPath == null) return (null); pos = normalizedPath.length(); // Use the thread local URI and mapping data DispatchData dd = dispatchData.get(); if (dd == null) { dd = new DispatchData(); dispatchData.set(dd); } MessageBytes uriMB = dd.uriMB; uriMB.recycle(); // Use the thread local mapping data MappingData mappingData = dd.mappingData; // Map the URI CharChunk uriCC = uriMB.getCharChunk(); try { uriCC.append(context.getPath(), 0, context.getPath().length()); /* * Ignore any trailing path params (separated by ';') for mapping * purposes */ int semicolon = normalizedPath.indexOf(';'); if (pos >= 0 && semicolon > pos) { semicolon = -1; } uriCC.append(normalizedPath, 0, semicolon > 0 ? semicolon : pos); context.getMapper().map(uriMB, mappingData); if (mappingData.wrapper == null) { return (null); } /* * Append any trailing path params (separated by ';') that were * ignored for mapping purposes, so that they're reflected in the * RequestDispatcher's requestURI */ if (semicolon > 0) { uriCC.append(normalizedPath, semicolon, pos - semicolon); } } catch (Exception e) { // Should never happen log(sm.getString("applicationContext.mapping.error"), e); return (null); } Wrapper wrapper = (Wrapper) mappingData.wrapper; String wrapperPath = mappingData.wrapperPath.toString(); String pathInfo = mappingData.pathInfo.toString(); mappingData.recycle(); // Construct a RequestDispatcher to process this request return new ApplicationDispatcher (wrapper, uriCC.toString(), wrapperPath, pathInfo, queryString, null); } /** * Return the URL to the resource that is mapped to a specified path. * The path must begin with a "/" and is interpreted as relative to the * current context root. * * @param path The path to the desired resource * * @exception MalformedURLException if the path is not given * in the correct form */ @Override public URL getResource(String path) throws MalformedURLException { if (path == null || !path.startsWith("/") && GET_RESOURCE_REQUIRE_SLASH) throw new MalformedURLException(sm.getString( "applicationContext.requestDispatcher.iae", path)); String normPath = RequestUtil.normalize(path); if (normPath == null) return (null); DirContext resources = context.getResources(); if (resources != null) { String fullPath = context.getPath() + normPath; String hostName = context.getParent().getName(); try { resources.lookup(normPath); URI uri = new URI("jndi", null, "", -1, getJNDIUri(hostName, fullPath), null, null); return new URL(null, uri.toString(), new DirContextURLStreamHandler(resources)); } catch (NamingException e) { // Ignore } catch (Exception e) { // Unexpected log(sm.getString("applicationContext.lookup.error", path, getContextPath()), e); } } return (null); } /** * Return the requested resource as an InputStream. The * path must be specified according to the rules described under * getResource. If no such resource can be identified, * return null. * * @param path The path to the desired resource. */ @Override public InputStream getResourceAsStream(String path) { if (path == null) return (null); if (!path.startsWith("/") && GET_RESOURCE_REQUIRE_SLASH) return null; String normalizedPath = RequestUtil.normalize(path); if (normalizedPath == null) return (null); DirContext resources = context.getResources(); if (resources != null) { try { Object resource = resources.lookup(normalizedPath); if (resource instanceof Resource) return (((Resource) resource).streamContent()); } catch (NamingException e) { // Ignore } catch (Exception e) { // Unexpected log(sm.getString("applicationContext.lookup.error", path, getContextPath()), e); } } return (null); } /** * Return a Set containing the resource paths of resources member of the * specified collection. Each path will be a String starting with * a "/" character. The returned set is immutable. * * @param path Collection path */ @Override public Set getResourcePaths(String path) { // Validate the path argument if (path == null) { return null; } if (!path.startsWith("/")) { throw new IllegalArgumentException (sm.getString("applicationContext.resourcePaths.iae", path)); } String normalizedPath = RequestUtil.normalize(path); if (normalizedPath == null) return (null); DirContext resources = context.getResources(); if (resources != null) { return (getResourcePathsInternal(resources, normalizedPath)); } return (null); } /** * Internal implementation of getResourcesPath() logic. * * @param resources Directory context to search * @param path Collection path */ private Set getResourcePathsInternal(DirContext resources, String path) { ResourceSet set = new ResourceSet(); try { listCollectionPaths(set, resources, path); } catch (NamingException e) { return (null); } set.setLocked(true); return (set); } /** * Return the name and version of the servlet container. */ @Override public String getServerInfo() { return (ServerInfo.getServerInfo()); } /** * @deprecated As of Java Servlet API 2.1, with no direct replacement. */ @Override @Deprecated public Servlet getServlet(String name) { return (null); } /** * Return the display name of this web application. */ @Override public String getServletContextName() { return (context.getDisplayName()); } /** * @deprecated As of Java Servlet API 2.1, with no direct replacement. */ @Override @Deprecated public Enumeration getServletNames() { return Collections.enumeration(emptyString); } /** * @deprecated As of Java Servlet API 2.1, with no direct replacement. */ @Override @Deprecated public Enumeration getServlets() { return Collections.enumeration(emptyServlet); } /** * Writes the specified message to a servlet log file. * * @param message Message to be written */ @Override public void log(String message) { context.getLogger().info(message); } /** * Writes the specified exception and message to a servlet log file. * * @param exception Exception to be reported * @param message Message to be written * * @deprecated As of Java Servlet API 2.1, use * log(String, Throwable) instead */ @Override @Deprecated public void log(Exception exception, String message) { context.getLogger().error(message, exception); } /** * Writes the specified message and exception to a servlet log file. * * @param message Message to be written * @param throwable Exception to be reported */ @Override public void log(String message, Throwable throwable) { context.getLogger().error(message, throwable); } /** * Remove the context attribute with the specified name, if any. * * @param name Name of the context attribute to be removed */ @Override public void removeAttribute(String name) { Object value = null; // Remove the specified attribute // Check for read only attribute if (readOnlyAttributes.containsKey(name)){ return; } value = attributes.remove(name); if (value == null) { return; } // Notify interested application event listeners Object listeners[] = context.getApplicationEventListeners(); if ((listeners == null) || (listeners.length == 0)) return; ServletContextAttributeEvent event = new ServletContextAttributeEvent(context.getServletContext(), name, value); for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof ServletContextAttributeListener)) continue; ServletContextAttributeListener listener = (ServletContextAttributeListener) listeners[i]; try { context.fireContainerEvent("beforeContextAttributeRemoved", listener); listener.attributeRemoved(event); context.fireContainerEvent("afterContextAttributeRemoved", listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); context.fireContainerEvent("afterContextAttributeRemoved", listener); // FIXME - should we do anything besides log these? log(sm.getString("applicationContext.attributeEvent"), t); } } } /** * Bind the specified value with the specified context attribute name, * replacing any existing value for that name. * * @param name Attribute name to be bound * @param value New attribute value to be bound */ @Override public void setAttribute(String name, Object value) { // Name cannot be null if (name == null) throw new IllegalArgumentException (sm.getString("applicationContext.setAttribute.namenull")); // Null value is the same as removeAttribute() if (value == null) { removeAttribute(name); return; } Object oldValue = null; boolean replaced = false; // Add or replace the specified attribute // Check for read only attribute if (readOnlyAttributes.containsKey(name)) return; oldValue = attributes.get(name); if (oldValue != null) replaced = true; attributes.put(name, value); // Notify interested application event listeners Object listeners[] = context.getApplicationEventListeners(); if ((listeners == null) || (listeners.length == 0)) return; ServletContextAttributeEvent event = null; if (replaced) event = new ServletContextAttributeEvent(context.getServletContext(), name, oldValue); else event = new ServletContextAttributeEvent(context.getServletContext(), name, value); for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof ServletContextAttributeListener)) continue; ServletContextAttributeListener listener = (ServletContextAttributeListener) listeners[i]; try { if (replaced) { context.fireContainerEvent ("beforeContextAttributeReplaced", listener); listener.attributeReplaced(event); context.fireContainerEvent("afterContextAttributeReplaced", listener); } else { context.fireContainerEvent("beforeContextAttributeAdded", listener); listener.attributeAdded(event); context.fireContainerEvent("afterContextAttributeAdded", listener); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (replaced) context.fireContainerEvent("afterContextAttributeReplaced", listener); else context.fireContainerEvent("afterContextAttributeAdded", listener); // FIXME - should we do anything besides log these? log(sm.getString("applicationContext.attributeEvent"), t); } } } /** * Add filter to context. * @param filterName Name of filter to add * @param filterClass Name of filter class * @return null if the filter has already been fully defined, * else a {@link javax.servlet.FilterRegistration.Dynamic} object * that can be used to further configure the filter * @throws IllegalStateException if the context has already been initialised * @throws UnsupportedOperationException - if this context was passed to the * {@link ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)} * method of a {@link ServletContextListener} that was not declared * in web.xml, a web-fragment or annotated with * {@link javax.servlet.annotation.WebListener}. */ @Override public FilterRegistration.Dynamic addFilter(String filterName, String filterClass) throws IllegalStateException { return addFilter(filterName, filterClass, null); } /** * Add filter to context. * @param filterName Name of filter to add * @param filter Filter to add * @return null if the filter has already been fully defined, * else a {@link javax.servlet.FilterRegistration.Dynamic} object * that can be used to further configure the filter * @throws IllegalStateException if the context has already been initialised * @throws UnsupportedOperationException - if this context was passed to the * {@link ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)} * method of a {@link ServletContextListener} that was not declared * in web.xml, a web-fragment or annotated with * {@link javax.servlet.annotation.WebListener}. */ @Override public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) throws IllegalStateException { return addFilter(filterName, null, filter); } /** * Add filter to context. * @param filterName Name of filter to add * @param filterClass Class of filter to add * @return null if the filter has already been fully defined, * else a {@link javax.servlet.FilterRegistration.Dynamic} object * that can be used to further configure the filter * @throws IllegalStateException if the context has already been initialised * @throws UnsupportedOperationException - if this context was passed to the * {@link ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)} * method of a {@link ServletContextListener} that was not declared * in web.xml, a web-fragment or annotated with * {@link javax.servlet.annotation.WebListener}. */ @Override public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) throws IllegalStateException { return addFilter(filterName, filterClass.getName(), null); } private FilterRegistration.Dynamic addFilter(String filterName, String filterClass, Filter filter) throws IllegalStateException { if (filterName == null || filterName.equals("")) { throw new IllegalArgumentException(sm.getString( "applicationContext.invalidFilterName", filterName)); } if (!context.getState().equals(LifecycleState.STARTING_PREP)) { //TODO Spec breaking enhancement to ignore this restriction throw new IllegalStateException( sm.getString("applicationContext.addFilter.ise", getContextPath())); } FilterDef filterDef = context.findFilterDef(filterName); // Assume a 'complete' FilterRegistration is one that has a class and // a name if (filterDef == null) { filterDef = new FilterDef(); filterDef.setFilterName(filterName); context.addFilterDef(filterDef); } else { if (filterDef.getFilterName() != null && filterDef.getFilterClass() != null) { return null; } } if (filter == null) { filterDef.setFilterClass(filterClass); } else { filterDef.setFilterClass(filter.getClass().getName()); filterDef.setFilter(filter); } return new ApplicationFilterRegistration(filterDef, context); } @Override public T createFilter(Class c) throws ServletException { try { @SuppressWarnings("unchecked") T filter = (T) context.getInstanceManager().newInstance(c.getName()); return filter; } catch (IllegalAccessException e) { throw new ServletException(e); } catch (InvocationTargetException e) { ExceptionUtils.handleThrowable(e.getCause()); throw new ServletException(e); } catch (NamingException e) { throw new ServletException(e); } catch (InstantiationException e) { throw new ServletException(e); } catch (ClassNotFoundException e) { throw new ServletException(e); } } @Override public FilterRegistration getFilterRegistration(String filterName) { FilterDef filterDef = context.findFilterDef(filterName); if (filterDef == null) { return null; } return new ApplicationFilterRegistration(filterDef, context); } /** * Add servlet to context. * @param servletName Name of servlet to add * @param servletClass Name of servlet class * @return null if the servlet has already been fully defined, * else a {@link javax.servlet.ServletRegistration.Dynamic} object * that can be used to further configure the servlet * @throws IllegalStateException if the context has already been initialised * @throws UnsupportedOperationException - if this context was passed to the * {@link ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)} * method of a {@link ServletContextListener} that was not declared * in web.xml, a web-fragment or annotated with * {@link javax.servlet.annotation.WebListener}. */ @Override public ServletRegistration.Dynamic addServlet(String servletName, String servletClass) throws IllegalStateException { return addServlet(servletName, servletClass, null); } /** * Add servlet to context. * @param servletName Name of servlet to add * @param servlet Servlet instance to add * @return null if the servlet has already been fully defined, * else a {@link javax.servlet.ServletRegistration.Dynamic} object * that can be used to further configure the servlet * @throws IllegalStateException if the context has already been initialised * @throws UnsupportedOperationException - if this context was passed to the * {@link ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)} * method of a {@link ServletContextListener} that was not declared * in web.xml, a web-fragment or annotated with * {@link javax.servlet.annotation.WebListener}. */ @Override public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) throws IllegalStateException { return addServlet(servletName, null, servlet); } /** * Add servlet to context. * @param servletName Name of servlet to add * @param servletClass Class of servlet to add * @return null if the servlet has already been fully defined, * else a {@link javax.servlet.ServletRegistration.Dynamic} object * that can be used to further configure the servlet * @throws IllegalStateException if the context has already been initialised * @throws UnsupportedOperationException - if this context was passed to the * {@link ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)} * method of a {@link ServletContextListener} that was not declared * in web.xml, a web-fragment or annotated with * {@link javax.servlet.annotation.WebListener}. */ @Override public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) throws IllegalStateException { return addServlet(servletName, servletClass.getName(), null); } private ServletRegistration.Dynamic addServlet(String servletName, String servletClass, Servlet servlet) throws IllegalStateException { if (servletName == null || servletName.equals("")) { throw new IllegalArgumentException(sm.getString( "applicationContext.invalidServletName", servletName)); } if (!context.getState().equals(LifecycleState.STARTING_PREP)) { //TODO Spec breaking enhancement to ignore this restriction throw new IllegalStateException( sm.getString("applicationContext.addServlet.ise", getContextPath())); } Wrapper wrapper = (Wrapper) context.findChild(servletName); // Assume a 'complete' ServletRegistration is one that has a class and // a name if (wrapper == null) { wrapper = context.createWrapper(); wrapper.setName(servletName); context.addChild(wrapper); } else { if (wrapper.getName() != null && wrapper.getServletClass() != null) { if (wrapper.isOverridable()) { wrapper.setOverridable(false); } else { return null; } } } if (servlet == null) { wrapper.setServletClass(servletClass); } else { wrapper.setServletClass(servlet.getClass().getName()); wrapper.setServlet(servlet); } return context.dynamicServletAdded(wrapper); } @Override public T createServlet(Class c) throws ServletException { try { @SuppressWarnings("unchecked") T servlet = (T) context.getInstanceManager().newInstance(c.getName()); context.dynamicServletCreated(servlet); return servlet; } catch (IllegalAccessException e) { throw new ServletException(e); } catch (InvocationTargetException e) { ExceptionUtils.handleThrowable(e.getCause()); throw new ServletException(e); } catch (NamingException e) { throw new ServletException(e); } catch (InstantiationException e) { throw new ServletException(e); } catch (ClassNotFoundException e) { throw new ServletException(e); } } @Override public ServletRegistration getServletRegistration(String servletName) { Wrapper wrapper = (Wrapper) context.findChild(servletName); if (wrapper == null) { return null; } return new ApplicationServletRegistration(wrapper, context); } /** * By default {@link SessionTrackingMode#URL} is always supported, {@link * SessionTrackingMode#COOKIE} is supported unless the cookies * attribute has been set to false for the context and {@link * SessionTrackingMode#SSL} is supported if at least one of the connectors * used by this context has the attribute secure set to * true. */ @Override public Set getDefaultSessionTrackingModes() { return defaultSessionTrackingModes; } private void populateSessionTrackingModes() { // URL re-writing is always enabled by default defaultSessionTrackingModes = EnumSet.of(SessionTrackingMode.URL); supportedSessionTrackingModes = EnumSet.of(SessionTrackingMode.URL); if (context.getCookies()) { defaultSessionTrackingModes.add(SessionTrackingMode.COOKIE); supportedSessionTrackingModes.add(SessionTrackingMode.COOKIE); } // SSL not enabled by default as it can only used on its own // Context > Host > Engine > Service Service s = ((Engine) context.getParent().getParent()).getService(); Connector[] connectors = s.findConnectors(); // Need at least one SSL enabled connector to use the SSL session ID. for (Connector connector : connectors) { if (Boolean.TRUE.equals(connector.getAttribute("SSLEnabled"))) { supportedSessionTrackingModes.add(SessionTrackingMode.SSL); break; } } } /** * Return the supplied value if one was previously set, else return the * defaults. */ @Override public Set getEffectiveSessionTrackingModes() { if (sessionTrackingModes != null) { return sessionTrackingModes; } return defaultSessionTrackingModes; } @Override public SessionCookieConfig getSessionCookieConfig() { return sessionCookieConfig; } /** * @throws IllegalStateException if the context has already been initialised * @throws IllegalArgumentException If SSL is requested in combination with * anything else or if an unsupported * tracking mode is requested */ @Override public void setSessionTrackingModes( Set sessionTrackingModes) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException( sm.getString("applicationContext.setSessionTracking.ise", getContextPath())); } // Check that only supported tracking modes have been requested for (SessionTrackingMode sessionTrackingMode : sessionTrackingModes) { if (!supportedSessionTrackingModes.contains(sessionTrackingMode)) { throw new IllegalArgumentException(sm.getString( "applicationContext.setSessionTracking.iae.invalid", sessionTrackingMode.toString(), getContextPath())); } } // Check SSL has not be configured with anything else if (sessionTrackingModes.contains(SessionTrackingMode.SSL)) { if (sessionTrackingModes.size() > 1) { throw new IllegalArgumentException(sm.getString( "applicationContext.setSessionTracking.iae.ssl", getContextPath())); } } this.sessionTrackingModes = sessionTrackingModes; } @Override public boolean setInitParameter(String name, String value) { return parameters.putIfAbsent(name, value) == null; } @Override public void addListener(Class listenerClass) { EventListener listener; try { listener = createListener(listenerClass); } catch (ServletException e) { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.init", listenerClass.getName()), e); } addListener(listener); } @Override public void addListener(String className) { try { Object obj = context.getInstanceManager().newInstance(className); if (!(obj instanceof EventListener)) { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.wrongType", className)); } EventListener listener = (EventListener) obj; addListener(listener); } catch (IllegalAccessException e) { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.cnfe", className), e); } catch (InvocationTargetException e) { ExceptionUtils.handleThrowable(e.getCause()); throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.cnfe", className), e); } catch (NamingException e) { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.cnfe", className), e); } catch (InstantiationException e) { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.cnfe", className), e); } catch (ClassNotFoundException e) { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.cnfe", className), e); } } @Override public void addListener(T t) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException( sm.getString("applicationContext.addListener.ise", getContextPath())); } boolean match = false; if (t instanceof ServletContextAttributeListener || t instanceof ServletRequestListener || t instanceof ServletRequestAttributeListener || t instanceof HttpSessionAttributeListener) { context.addApplicationEventListener(t); match = true; } if (t instanceof HttpSessionListener || (t instanceof ServletContextListener && newServletContextListenerAllowed)) { // Add listener directly to the list of instances rather than to // the list of class names. context.addApplicationLifecycleListener(t); match = true; } if (match) return; if (t instanceof ServletContextListener) { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.sclNotAllowed", t.getClass().getName())); } else { throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.wrongType", t.getClass().getName())); } } @Override public T createListener(Class c) throws ServletException { try { @SuppressWarnings("unchecked") T listener = (T) context.getInstanceManager().newInstance(c); if (listener instanceof ServletContextListener || listener instanceof ServletContextAttributeListener || listener instanceof ServletRequestListener || listener instanceof ServletRequestAttributeListener || listener instanceof HttpSessionListener || listener instanceof HttpSessionAttributeListener) { return listener; } throw new IllegalArgumentException(sm.getString( "applicationContext.addListener.iae.wrongType", listener.getClass().getName())); } catch (IllegalAccessException e) { throw new ServletException(e); } catch (InvocationTargetException e) { ExceptionUtils.handleThrowable(e.getCause()); throw new ServletException(e); } catch (NamingException e) { throw new ServletException(e); } catch (InstantiationException e) { throw new ServletException(e); } } @Override public void declareRoles(String... roleNames) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { //TODO Spec breaking enhancement to ignore this restriction throw new IllegalStateException( sm.getString("applicationContext.addRole.ise", getContextPath())); } if (roleNames == null) { throw new IllegalArgumentException( sm.getString("applicationContext.roles.iae", getContextPath())); } for (String role : roleNames) { if (role == null || "".equals(role)) { throw new IllegalArgumentException( sm.getString("applicationContext.role.iae", getContextPath())); } context.addSecurityRole(role); } } @Override public ClassLoader getClassLoader() { ClassLoader result = context.getLoader().getClassLoader(); if (Globals.IS_SECURITY_ENABLED) { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); ClassLoader parent = result; while (parent != null) { if (parent == tccl) { break; } parent = parent.getParent(); } if (parent == null) { System.getSecurityManager().checkPermission( new RuntimePermission("getClassLoader")); } } return result; } @Override public int getEffectiveMajorVersion() { return context.getEffectiveMajorVersion(); } @Override public int getEffectiveMinorVersion() { return context.getEffectiveMinorVersion(); } @Override public Map getFilterRegistrations() { Map result = new HashMap(); FilterDef[] filterDefs = context.findFilterDefs(); for (FilterDef filterDef : filterDefs) { result.put(filterDef.getFilterName(), new ApplicationFilterRegistration(filterDef, context)); } return result; } @Override public JspConfigDescriptor getJspConfigDescriptor() { JspConfigDescriptor jspConfigDescriptor = context .getJspConfigDescriptor(); if (jspConfigDescriptor.getJspPropertyGroups().isEmpty() && jspConfigDescriptor.getTaglibs().isEmpty()) { return null; } else { return jspConfigDescriptor; } } @Override public Map getServletRegistrations() { Map result = new HashMap(); Container[] wrappers = context.findChildren(); for (Container wrapper : wrappers) { result.put(((Wrapper) wrapper).getName(), new ApplicationServletRegistration( (Wrapper) wrapper, context)); } return result; } // -------------------------------------------------------- Package Methods protected StandardContext getContext() { return this.context; } @Deprecated protected Map getReadonlyAttributes() { return this.readOnlyAttributes; } /** * Clear all application-created attributes. */ protected void clearAttributes() { // Create list of attributes to be removed ArrayList list = new ArrayList(); Iterator iter = attributes.keySet().iterator(); while (iter.hasNext()) { list.add(iter.next()); } // Remove application originated attributes // (read only attributes will be left in place) Iterator keys = list.iterator(); while (keys.hasNext()) { String key = keys.next(); removeAttribute(key); } } /** * Return the facade associated with this ApplicationContext. */ protected ServletContext getFacade() { return (this.facade); } /** * Set an attribute as read only. */ void setAttributeReadOnly(String name) { if (attributes.containsKey(name)) readOnlyAttributes.put(name, name); } protected void setNewServletContextListenerAllowed(boolean allowed) { this.newServletContextListenerAllowed = allowed; } /** * List resource paths (recursively), and store all of them in the given * Set. */ private static void listCollectionPaths(Set set, DirContext resources, String path) throws NamingException { Enumeration childPaths = resources.listBindings(path); while (childPaths.hasMoreElements()) { Binding binding = childPaths.nextElement(); String name = binding.getName(); StringBuilder childPath = new StringBuilder(path); if (!"/".equals(path) && !path.endsWith("/")) childPath.append("/"); childPath.append(name); Object object = binding.getObject(); if (object instanceof DirContext) { childPath.append("/"); } set.add(childPath.toString()); } } /** * Get full path, based on the host name and the context path. */ private static String getJNDIUri(String hostName, String path) { String result; if (path.startsWith("/")) { result = "/" + hostName + path; } else { result = "/" + hostName + "/" + path; } return result; } /** * Internal class used as thread-local storage when doing path * mapping during dispatch. */ private static final class DispatchData { public MessageBytes uriMB; public MappingData mappingData; public DispatchData() { uriMB = MessageBytes.newInstance(); CharChunk uriCC = uriMB.getCharChunk(); uriCC.setLimit(-1); mappingData = new MappingData(); } } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardContextValve.java0000644000175100017510000001202512271471332025550 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Container; import org.apache.catalina.Wrapper; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.valves.ValveBase; import org.apache.tomcat.util.buf.MessageBytes; /** * Valve that implements the default basic behavior for the * StandardContext container implementation. *

    * USAGE CONSTRAINT: This implementation is likely to be useful only * when processing HTTP requests. * * @author Craig R. McClanahan */ final class StandardContextValve extends ValveBase { public StandardContextValve() { super(true); } /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.core.StandardContextValve/1.0"; /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } /** * Cast to a StandardContext right away, as it will be needed later. * * @see org.apache.catalina.Contained#setContainer(org.apache.catalina.Container) */ @Override public void setContainer(Container container) { super.setContainer(container); } /** * Select the appropriate child Wrapper to process this request, * based on the specified request URI. If no matching Wrapper can * be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public final void invoke(Request request, Response response) throws IOException, ServletException { // Disallow any direct access to resources under WEB-INF or META-INF MessageBytes requestPathMB = request.getRequestPathMB(); if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/META-INF")) || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // Select the Wrapper to be used for this Request Wrapper wrapper = request.getWrapper(); if (wrapper == null || wrapper.isUnavailable()) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // Acknowledge the request try { response.sendAcknowledgement(); } catch (IOException ioe) { container.getLogger().error(sm.getString( "standardContextValve.acknowledgeException"), ioe); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } if (request.isAsyncSupported()) { request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported()); } wrapper.getPipeline().getFirst().invoke(request, response); } /** * Select the appropriate child Wrapper to process this request, * based on the specified request URI. If no matching Wrapper can * be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * @param event * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public final void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Select the Wrapper to be used for this Request Wrapper wrapper = request.getWrapper(); wrapper.getPipeline().getFirst().event(request, response, event); } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardHostValve.java0000644000175100017510000004603512271471332025051 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Wrapper; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.connector.ClientAbortException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.deploy.ErrorPage; import org.apache.catalina.valves.ValveBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Valve that implements the default basic behavior for the * StandardHost container implementation. *

    * USAGE CONSTRAINT: This implementation is likely to be useful only * when processing HTTP requests. * * @author Craig R. McClanahan * @author Remy Maucherat */ final class StandardHostValve extends ValveBase { private static final Log log = LogFactory.getLog(StandardHostValve.class); protected static final boolean STRICT_SERVLET_COMPLIANCE; protected static final boolean ACCESS_SESSION; static { STRICT_SERVLET_COMPLIANCE = Globals.STRICT_SERVLET_COMPLIANCE; String accessSession = System.getProperty( "org.apache.catalina.core.StandardHostValve.ACCESS_SESSION"); if (accessSession == null) { ACCESS_SESSION = STRICT_SERVLET_COMPLIANCE; } else { ACCESS_SESSION = Boolean.valueOf(accessSession).booleanValue(); } } //------------------------------------------------------ Constructor public StandardHostValve() { super(true); } // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.core.StandardHostValve/1.0"; /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Select the appropriate child Context to process this request, * based on the specified request URI. If no matching Context can * be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public final void invoke(Request request, Response response) throws IOException, ServletException { // Select the Context to be used for this Request Context context = request.getContext(); if (context == null) { response.sendError (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, sm.getString("standardHost.noContext")); return; } // Bind the context CL to the current thread if( context.getLoader() != null ) { // Not started - it should check for availability first // This should eventually move to Engine, it's generic. if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( context.getLoader().getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); } } if (request.isAsyncSupported()) { request.setAsyncSupported(context.getPipeline().isAsyncSupported()); } // Don't fire listeners during async processing // If a request init listener throws an exception, the request is // aborted boolean asyncAtStart = request.isAsync(); // An async error page may dispatch to another resource. This flag helps // ensure an infinite error handling loop is not entered boolean errorAtStart = response.isError(); if (asyncAtStart || context.fireRequestInitEvent(request)) { // Ask this Context to process this request try { context.getPipeline().getFirst().invoke(request, response); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (errorAtStart) { container.getLogger().error("Exception Processing " + request.getRequestURI(), t); } else { request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); throwable(request, response, t); } } // If the request was async at the start and an error occurred then // the async error handling will kick-in and that will fire the // request destroyed event *after* the error handling has taken // place if (!(request.isAsync() || (asyncAtStart && request.getAttribute( RequestDispatcher.ERROR_EXCEPTION) != null))) { // Protect against NPEs if context was destroyed during a // long running request. if (context.getState().isAvailable()) { if (!errorAtStart) { // Error page processing response.setSuspended(false); Throwable t = (Throwable) request.getAttribute( RequestDispatcher.ERROR_EXCEPTION); if (t != null) { throwable(request, response, t); } else { status(request, response); } } context.fireRequestDestroyEvent(request); } } } // Access a session (if present) to update last accessed time, based on a // strict interpretation of the specification if (ACCESS_SESSION) { request.getSession(false); } // Restore the context classloader if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( StandardHostValve.class.getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader (StandardHostValve.class.getClassLoader()); } } /** * Process Comet event. * * @param request Request to be processed * @param response Response to be produced * @param event the event * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public final void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Select the Context to be used for this Request Context context = request.getContext(); // Bind the context CL to the current thread if( context.getLoader() != null ) { // Not started - it should check for availability first // This should eventually move to Engine, it's generic. Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); } // Ask this Context to process this request context.getPipeline().getFirst().event(request, response, event); // Error page processing response.setSuspended(false); Throwable t = (Throwable) request.getAttribute( RequestDispatcher.ERROR_EXCEPTION); if (t != null) { throwable(request, response, t); } else { status(request, response); } // Access a session (if present) to update last accessed time, based on a // strict interpretation of the specification if (ACCESS_SESSION) { request.getSession(false); } // Restore the context classloader Thread.currentThread().setContextClassLoader (StandardHostValve.class.getClassLoader()); } // -------------------------------------------------------- Private Methods /** * Handle the HTTP status code (and corresponding message) generated * while processing the specified Request to produce the specified * Response. Any exceptions that occur during generation of the error * report are logged and swallowed. * * @param request The request being processed * @param response The response being generated */ private void status(Request request, Response response) { int statusCode = response.getStatus(); // Handle a custom error page for this status code Context context = request.getContext(); if (context == null) return; /* Only look for error pages when isError() is set. * isError() is set when response.sendError() is invoked. This * allows custom error pages without relying on default from * web.xml. */ if (!response.isError()) return; ErrorPage errorPage = context.findErrorPage(statusCode); if (errorPage == null) { // Look for a default error page errorPage = context.findErrorPage(0); } if (errorPage != null) { response.setAppCommitted(false); request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, Integer.valueOf(statusCode)); String message = response.getMessage(); if (message == null) message = ""; request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation()); request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR); Wrapper wrapper = request.getWrapper(); if (wrapper != null) request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName()); request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); if (custom(request, response, errorPage)) { try { response.flushBuffer(); } catch (ClientAbortException e) { // Ignore } catch (IOException e) { container.getLogger().warn("Exception Processing " + errorPage, e); } } } } /** * Handle the specified Throwable encountered while processing * the specified Request to produce the specified Response. Any * exceptions that occur during generation of the exception report are * logged and swallowed. * * @param request The request being processed * @param response The response being generated * @param throwable The exception that occurred (which possibly wraps * a root cause exception */ protected void throwable(Request request, Response response, Throwable throwable) { Context context = request.getContext(); if (context == null) return; Throwable realError = throwable; if (realError instanceof ServletException) { realError = ((ServletException) realError).getRootCause(); if (realError == null) { realError = throwable; } } // If this is an aborted request from a client just log it and return if (realError instanceof ClientAbortException ) { if (log.isDebugEnabled()) { log.debug (sm.getString("standardHost.clientAbort", realError.getCause().getMessage())); } return; } ErrorPage errorPage = findErrorPage(context, throwable); if ((errorPage == null) && (realError != throwable)) { errorPage = findErrorPage(context, realError); } if (errorPage != null) { response.setAppCommitted(false); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation()); request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR); request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); request.setAttribute(RequestDispatcher.ERROR_MESSAGE, throwable.getMessage()); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, realError); Wrapper wrapper = request.getWrapper(); if (wrapper != null) request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, wrapper.getName()); request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, realError.getClass()); if (custom(request, response, errorPage)) { try { response.flushBuffer(); } catch (IOException e) { container.getLogger().warn("Exception Processing " + errorPage, e); } } } else { // A custom error-page has not been defined for the exception // that was thrown during request processing. Check if an // error-page for error code 500 was specified and if so, // send that page back as the response. response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // The response is an error response.setError(); status(request, response); } } /** * Handle an HTTP status code or Java exception by forwarding control * to the location included in the specified errorPage object. It is * assumed that the caller has already recorded any request attributes * that are to be forwarded to this page. Return true if * we successfully utilized the specified error page location, or * false if the default error report should be rendered. * * @param request The request being processed * @param response The response being generated * @param errorPage The errorPage directive we are obeying */ private boolean custom(Request request, Response response, ErrorPage errorPage) { if (container.getLogger().isDebugEnabled()) container.getLogger().debug("Processing " + errorPage); try { // Forward control to the specified location ServletContext servletContext = request.getContext().getServletContext(); RequestDispatcher rd = servletContext.getRequestDispatcher(errorPage.getLocation()); if (response.isCommitted()) { // Response is committed - including the error page is the // best we can do rd.include(request.getRequest(), response.getResponse()); } else { // Reset the response (keeping the real error code and message) response.resetBuffer(true); response.setContentLength(-1); rd.forward(request.getRequest(), response.getResponse()); // If we forward, the response is suspended again response.setSuspended(false); } // Indicate that we have successfully processed this custom page return (true); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // Report our failure to process this custom page container.getLogger().error("Exception Processing " + errorPage, t); return (false); } } /** * Find and return the ErrorPage instance for the specified exception's * class, or an ErrorPage instance for the closest superclass for which * there is such a definition. If no associated ErrorPage instance is * found, return null. * * @param context The Context in which to search * @param exception The exception for which to find an ErrorPage */ private static ErrorPage findErrorPage (Context context, Throwable exception) { if (exception == null) return (null); Class clazz = exception.getClass(); String name = clazz.getName(); while (!Object.class.equals(clazz)) { ErrorPage errorPage = context.findErrorPage(name); if (errorPage != null) return (errorPage); clazz = clazz.getSuperclass(); if (clazz == null) break; name = clazz.getName(); } return (null); } private static class PrivilegedSetTccl implements PrivilegedAction { private ClassLoader cl; PrivilegedSetTccl(ClassLoader cl) { this.cl = cl; } @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); return null; } } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationPart.java0000644000175100017510000001251612271471332024544 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Map; import javax.servlet.http.Part; import org.apache.tomcat.util.http.fileupload.FileItem; import org.apache.tomcat.util.http.fileupload.ParameterParser; import org.apache.tomcat.util.http.fileupload.disk.DiskFileItem; /** * Adaptor to allow {@link FileItem} objects generated by the package renamed * commons-upload to be used by the Servlet 3.0 upload API that expects * {@link Part}s. */ public class ApplicationPart implements Part { private final FileItem fileItem; private final File location; public ApplicationPart(FileItem fileItem, File location) { this.fileItem = fileItem; this.location = location; } @Override public void delete() throws IOException { fileItem.delete(); } @Override public String getContentType() { return fileItem.getContentType(); } @Override public String getHeader(String name) { if (fileItem instanceof DiskFileItem) { return ((DiskFileItem) fileItem).getHeaders().getHeader(name); } return null; } @Override public Collection getHeaderNames() { if (fileItem instanceof DiskFileItem) { HashSet headerNames = new HashSet(); Iterator iter = ((DiskFileItem) fileItem).getHeaders().getHeaderNames(); while (iter.hasNext()) { headerNames.add(iter.next()); } return headerNames; } return Collections.emptyList(); } @Override public Collection getHeaders(String name) { if (fileItem instanceof DiskFileItem) { HashSet headers = new HashSet(); Iterator iter = ((DiskFileItem) fileItem).getHeaders().getHeaders(name); while (iter.hasNext()) { headers.add(iter.next()); } return headers; } return Collections.emptyList(); } @Override public InputStream getInputStream() throws IOException { return fileItem.getInputStream(); } @Override public String getName() { return fileItem.getFieldName(); } @Override public long getSize() { return fileItem.getSize(); } @Override public void write(String fileName) throws IOException { File file = new File(fileName); if (!file.isAbsolute()) { file = new File(location, fileName); } try { fileItem.write(file); } catch (Exception e) { throw new IOException(e); } } public String getString(String encoding) throws UnsupportedEncodingException { return fileItem.getString(encoding); } /** * Calls {@link #getSubmittedFileName()}. * * @deprecated Use {@link #getSubmittedFileName()} from Servlet 3.1 instead. * This method will be removed in Tomcat 8. */ @Deprecated public String getFilename() { return getSubmittedFileName(); } /** * Adapted from FileUploadBase.getFileName(). Method name chosen to be * consistent with Servlet 3.1. */ public String getSubmittedFileName() { String fileName = null; String cd = getHeader("Content-Disposition"); if (cd != null) { String cdl = cd.toLowerCase(Locale.ENGLISH); if (cdl.startsWith("form-data") || cdl.startsWith("attachment")) { ParameterParser paramParser = new ParameterParser(); paramParser.setLowerCaseNames(true); // Parameter parser can handle null input Map params = paramParser.parse(cd, ';'); if (params.containsKey("filename")) { fileName = params.get("filename"); if (fileName != null) { fileName = fileName.trim(); } else { // Even if there is no value, the parameter is present, // so we return an empty file name rather than no file // name. fileName = ""; } } } } return fileName; } } tomcat7-7.0.52/java/org/apache/catalina/core/NamingContextListener.java0000644000175100017510000012502712271471332025740 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.StringTokenizer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.naming.NameAlreadyBoundException; import javax.naming.NamingException; import javax.naming.Reference; import javax.naming.StringRefAddr; import org.apache.catalina.Container; import org.apache.catalina.ContainerEvent; import org.apache.catalina.ContainerListener; import org.apache.catalina.Context; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Server; import org.apache.catalina.deploy.ContextEjb; import org.apache.catalina.deploy.ContextEnvironment; import org.apache.catalina.deploy.ContextHandler; import org.apache.catalina.deploy.ContextLocalEjb; import org.apache.catalina.deploy.ContextResource; import org.apache.catalina.deploy.ContextResourceEnvRef; import org.apache.catalina.deploy.ContextResourceLink; import org.apache.catalina.deploy.ContextService; import org.apache.catalina.deploy.ContextTransaction; import org.apache.catalina.deploy.NamingResources; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.naming.ContextAccessController; import org.apache.naming.ContextBindings; import org.apache.naming.EjbRef; import org.apache.naming.HandlerRef; import org.apache.naming.NamingContext; import org.apache.naming.ResourceEnvRef; import org.apache.naming.ResourceLinkRef; import org.apache.naming.ResourceRef; import org.apache.naming.ServiceRef; import org.apache.naming.TransactionRef; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; /** * Helper class used to initialize and populate the JNDI context associated * with each context and server. * * @author Remy Maucherat */ public class NamingContextListener implements LifecycleListener, ContainerListener, PropertyChangeListener { private static final Log log = LogFactory.getLog(NamingContextListener.class); // ----------------------------------------------------- Instance Variables protected Log logger = log; /** * Name of the associated naming context. */ protected String name = "/"; /** * Associated container. */ protected Object container = null; /** * Initialized flag. */ protected boolean initialized = false; /** * Associated naming resources. */ protected NamingResources namingResources = null; /** * Associated JNDI context. */ protected NamingContext namingContext = null; /** * Comp context. */ protected javax.naming.Context compCtx = null; /** * Env context. */ protected javax.naming.Context envCtx = null; /** * Objectnames hashtable. */ protected HashMap objectNames = new HashMap(); /** * Determines if an attempt to write to a read-only context results in an * exception or if the request is ignored. */ private boolean exceptionOnFailedWrite = true; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------------------------------------- Properties /** * Returns whether or not an attempt to modify the JNDI context will trigger * an exception or if the request will be ignored. */ public boolean getExceptionOnFailedWrite() { return exceptionOnFailedWrite; } /** * Controls whether or not an attempt to modify the JNDI context will * trigger an exception or if the request will be ignored. * * @param exceptionOnFailedWrite The new value */ public void setExceptionOnFailedWrite(boolean exceptionOnFailedWrite) { this.exceptionOnFailedWrite = exceptionOnFailedWrite; } /** * Return the "name" property. */ public String getName() { return (this.name); } /** * Set the "name" property. * * @param name The new name */ public void setName(String name) { this.name = name; } /** * Return the comp context. */ @Deprecated public javax.naming.Context getCompContext() { return this.compCtx; } /** * Return the env context. */ public javax.naming.Context getEnvContext() { return this.envCtx; } /** * Return the associated naming context. */ @Deprecated public NamingContext getNamingContext() { return (this.namingContext); } // ---------------------------------------------- LifecycleListener Methods /** * Acknowledge the occurrence of the specified event. * * @param event LifecycleEvent that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { container = event.getLifecycle(); if (container instanceof Context) { namingResources = ((Context) container).getNamingResources(); logger = log; } else if (container instanceof Server) { namingResources = ((Server) container).getGlobalNamingResources(); } else { return; } if (Lifecycle.CONFIGURE_START_EVENT.equals(event.getType())) { if (initialized) return; Hashtable contextEnv = new Hashtable(); try { namingContext = new NamingContext(contextEnv, getName()); } catch (NamingException e) { // Never happens } ContextAccessController.setSecurityToken(getName(), container); ContextBindings.bindContext(container, namingContext, container); if( log.isDebugEnabled() ) { log.debug("Bound " + container ); } // Configure write when read-only behaviour namingContext.setExceptionOnFailedWrite( getExceptionOnFailedWrite()); // Setting the context in read/write mode ContextAccessController.setWritable(getName(), container); try { createNamingContext(); } catch (NamingException e) { logger.error (sm.getString("naming.namingContextCreationFailed", e)); } namingResources.addPropertyChangeListener(this); // Binding the naming context to the class loader if (container instanceof Context) { // Setting the context in read only mode ContextAccessController.setReadOnly(getName()); try { ContextBindings.bindClassLoader (container, container, ((Container) container).getLoader().getClassLoader()); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } } if (container instanceof Server) { org.apache.naming.factory.ResourceLinkFactory.setGlobalContext (namingContext); try { ContextBindings.bindClassLoader (container, container, this.getClass().getClassLoader()); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } if (container instanceof StandardServer) { ((StandardServer) container).setGlobalNamingContext (namingContext); } } initialized = true; } else if (Lifecycle.CONFIGURE_STOP_EVENT.equals(event.getType())) { if (!initialized) return; // Setting the context in read/write mode ContextAccessController.setWritable(getName(), container); ContextBindings.unbindContext(container, container); if (container instanceof Context) { ContextBindings.unbindClassLoader (container, container, ((Container) container).getLoader().getClassLoader()); } if (container instanceof Server) { namingResources.removePropertyChangeListener(this); ContextBindings.unbindClassLoader (container, container, this.getClass().getClassLoader()); } ContextAccessController.unsetSecurityToken(getName(), container); // unregister mbeans. Collection names = objectNames.values(); for (ObjectName objectName : names) { Registry.getRegistry(null, null).unregisterComponent(objectName); } objectNames.clear(); namingContext = null; envCtx = null; compCtx = null; initialized = false; } } // ---------------------------------------------- ContainerListener Methods /** * Acknowledge the occurrence of the specified event. * Note: Will never be called when the listener is associated to a Server, * since it is not a Container. * * @param event ContainerEvent that has occurred */ @Override public void containerEvent(ContainerEvent event) { if (!initialized) return; // Setting the context in read/write mode ContextAccessController.setWritable(getName(), container); String type = event.getType(); if (type.equals("addEjb")) { String ejbName = (String) event.getData(); if (ejbName != null) { ContextEjb ejb = namingResources.findEjb(ejbName); addEjb(ejb); } } else if (type.equals("addEnvironment")) { String environmentName = (String) event.getData(); if (environmentName != null) { ContextEnvironment env = namingResources.findEnvironment(environmentName); addEnvironment(env); } } else if (type.equals("addLocalEjb")) { String localEjbName = (String) event.getData(); if (localEjbName != null) { ContextLocalEjb localEjb = namingResources.findLocalEjb(localEjbName); addLocalEjb(localEjb); } } else if (type.equals("addResource")) { String resourceName = (String) event.getData(); if (resourceName != null) { ContextResource resource = namingResources.findResource(resourceName); addResource(resource); } } else if (type.equals("addResourceLink")) { String resourceLinkName = (String) event.getData(); if (resourceLinkName != null) { ContextResourceLink resourceLink = namingResources.findResourceLink(resourceLinkName); addResourceLink(resourceLink); } } else if (type.equals("addResourceEnvRef")) { String resourceEnvRefName = (String) event.getData(); if (resourceEnvRefName != null) { ContextResourceEnvRef resourceEnvRef = namingResources.findResourceEnvRef(resourceEnvRefName); addResourceEnvRef(resourceEnvRef); } } else if (type.equals("addService")) { String serviceName = (String) event.getData(); if (serviceName != null) { ContextService service = namingResources.findService(serviceName); addService(service); } } else if (type.equals("removeEjb")) { String ejbName = (String) event.getData(); if (ejbName != null) { removeEjb(ejbName); } } else if (type.equals("removeEnvironment")) { String environmentName = (String) event.getData(); if (environmentName != null) { removeEnvironment(environmentName); } } else if (type.equals("removeLocalEjb")) { String localEjbName = (String) event.getData(); if (localEjbName != null) { removeLocalEjb(localEjbName); } } else if (type.equals("removeResource")) { String resourceName = (String) event.getData(); if (resourceName != null) { removeResource(resourceName); } } else if (type.equals("removeResourceLink")) { String resourceLinkName = (String) event.getData(); if (resourceLinkName != null) { removeResourceLink(resourceLinkName); } } else if (type.equals("removeResourceEnvRef")) { String resourceEnvRefName = (String) event.getData(); if (resourceEnvRefName != null) { removeResourceEnvRef(resourceEnvRefName); } } else if (type.equals("removeService")) { String serviceName = (String) event.getData(); if (serviceName != null) { removeService(serviceName); } } // Setting the context in read only mode ContextAccessController.setReadOnly(getName()); } // ----------------------------------------- PropertyChangeListener Methods /** * Process property change events. * * @param event The property change event that has occurred */ @Override public void propertyChange(PropertyChangeEvent event) { if (!initialized) return; Object source = event.getSource(); if (source == namingResources) { // Setting the context in read/write mode ContextAccessController.setWritable(getName(), container); processGlobalResourcesChange(event.getPropertyName(), event.getOldValue(), event.getNewValue()); // Setting the context in read only mode ContextAccessController.setReadOnly(getName()); } } // -------------------------------------------------------- Private Methods /** * Process a property change on the naming resources, by making the * corresponding addition or removal to the associated JNDI context. * * @param name Property name of the change to be processed * @param oldValue The old value (or null if adding) * @param newValue The new value (or null if removing) */ private void processGlobalResourcesChange(String name, Object oldValue, Object newValue) { if (name.equals("ejb")) { if (oldValue != null) { ContextEjb ejb = (ContextEjb) oldValue; if (ejb.getName() != null) { removeEjb(ejb.getName()); } } if (newValue != null) { ContextEjb ejb = (ContextEjb) newValue; if (ejb.getName() != null) { addEjb(ejb); } } } else if (name.equals("environment")) { if (oldValue != null) { ContextEnvironment env = (ContextEnvironment) oldValue; if (env.getName() != null) { removeEnvironment(env.getName()); } } if (newValue != null) { ContextEnvironment env = (ContextEnvironment) newValue; if (env.getName() != null) { addEnvironment(env); } } } else if (name.equals("localEjb")) { if (oldValue != null) { ContextLocalEjb ejb = (ContextLocalEjb) oldValue; if (ejb.getName() != null) { removeLocalEjb(ejb.getName()); } } if (newValue != null) { ContextLocalEjb ejb = (ContextLocalEjb) newValue; if (ejb.getName() != null) { addLocalEjb(ejb); } } } else if (name.equals("resource")) { if (oldValue != null) { ContextResource resource = (ContextResource) oldValue; if (resource.getName() != null) { removeResource(resource.getName()); } } if (newValue != null) { ContextResource resource = (ContextResource) newValue; if (resource.getName() != null) { addResource(resource); } } } else if (name.equals("resourceEnvRef")) { if (oldValue != null) { ContextResourceEnvRef resourceEnvRef = (ContextResourceEnvRef) oldValue; if (resourceEnvRef.getName() != null) { removeResourceEnvRef(resourceEnvRef.getName()); } } if (newValue != null) { ContextResourceEnvRef resourceEnvRef = (ContextResourceEnvRef) newValue; if (resourceEnvRef.getName() != null) { addResourceEnvRef(resourceEnvRef); } } } else if (name.equals("resourceLink")) { if (oldValue != null) { ContextResourceLink rl = (ContextResourceLink) oldValue; if (rl.getName() != null) { removeResourceLink(rl.getName()); } } if (newValue != null) { ContextResourceLink rl = (ContextResourceLink) newValue; if (rl.getName() != null) { addResourceLink(rl); } } } else if (name.equals("service")) { if (oldValue != null) { ContextService service = (ContextService) oldValue; if (service.getName() != null) { removeService(service.getName()); } } if (newValue != null) { ContextService service = (ContextService) newValue; if (service.getName() != null) { addService(service); } } } } /** * Create and initialize the JNDI naming context. */ private void createNamingContext() throws NamingException { // Creating the comp subcontext if (container instanceof Server) { compCtx = namingContext; envCtx = namingContext; } else { compCtx = namingContext.createSubcontext("comp"); envCtx = compCtx.createSubcontext("env"); } int i; if (log.isDebugEnabled()) log.debug("Creating JNDI naming context"); if (namingResources == null) { namingResources = new NamingResources(); namingResources.setContainer(container); } // Resource links ContextResourceLink[] resourceLinks = namingResources.findResourceLinks(); for (i = 0; i < resourceLinks.length; i++) { addResourceLink(resourceLinks[i]); } // Resources ContextResource[] resources = namingResources.findResources(); for (i = 0; i < resources.length; i++) { addResource(resources[i]); } // Resources Env ContextResourceEnvRef[] resourceEnvRefs = namingResources.findResourceEnvRefs(); for (i = 0; i < resourceEnvRefs.length; i++) { addResourceEnvRef(resourceEnvRefs[i]); } // Environment entries ContextEnvironment[] contextEnvironments = namingResources.findEnvironments(); for (i = 0; i < contextEnvironments.length; i++) { addEnvironment(contextEnvironments[i]); } // EJB references ContextEjb[] ejbs = namingResources.findEjbs(); for (i = 0; i < ejbs.length; i++) { addEjb(ejbs[i]); } // WebServices references ContextService[] services = namingResources.findServices(); for (i = 0; i < services.length; i++) { addService(services[i]); } // Binding a User Transaction reference if (container instanceof Context) { try { Reference ref = new TransactionRef(); compCtx.bind("UserTransaction", ref); ContextTransaction transaction = namingResources.getTransaction(); if (transaction != null) { Iterator params = transaction.listProperties(); while (params.hasNext()) { String paramName = params.next(); String paramValue = (String) transaction.getProperty(paramName); StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); ref.add(refAddr); } } } catch (NameAlreadyBoundException e) { // Ignore because UserTransaction was obviously // added via ResourceLink } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } } // Binding the resources directory context if (container instanceof Context) { try { compCtx.bind("Resources", ((Container) container).getResources()); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } } } /** * Create an ObjectName for this * ContextResource object. * * @param resource The resource * @return ObjectName The object name * @exception MalformedObjectNameException if a name cannot be created */ protected ObjectName createObjectName(ContextResource resource) throws MalformedObjectNameException { String domain = null; if (container instanceof StandardServer) { domain = ((StandardServer) container).getDomain(); } else if (container instanceof ContainerBase) { domain = ((ContainerBase) container).getDomain(); } if (domain == null) { domain = "Catalina"; } ObjectName name = null; String quotedResourceName = ObjectName.quote(resource.getName()); if (container instanceof Server) { name = new ObjectName(domain + ":type=DataSource" + ",class=" + resource.getType() + ",name=" + quotedResourceName); } else if (container instanceof Context) { String contextName = ((Context)container).getName(); if (!contextName.startsWith("/")) contextName = "/" + contextName; Host host = (Host) ((Context)container).getParent(); name = new ObjectName(domain + ":type=DataSource" + ",context=" + contextName + ",host=" + host.getName() + ",class=" + resource.getType() + ",name=" + quotedResourceName); } return (name); } /** * Set the specified EJBs in the naming context. */ public void addEjb(ContextEjb ejb) { // Create a reference to the EJB. Reference ref = new EjbRef (ejb.getType(), ejb.getHome(), ejb.getRemote(), ejb.getLink()); // Adding the additional parameters, if any Iterator params = ejb.listProperties(); while (params.hasNext()) { String paramName = params.next(); String paramValue = (String) ejb.getProperty(paramName); StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); ref.add(refAddr); } try { createSubcontexts(envCtx, ejb.getName()); envCtx.bind(ejb.getName(), ref); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } } /** * Set the specified environment entries in the naming context. */ public void addEnvironment(ContextEnvironment env) { Object value = null; // Instantiating a new instance of the correct object type, and // initializing it. String type = env.getType(); try { if (type.equals("java.lang.String")) { value = env.getValue(); } else if (type.equals("java.lang.Byte")) { if (env.getValue() == null) { value = Byte.valueOf((byte) 0); } else { value = Byte.decode(env.getValue()); } } else if (type.equals("java.lang.Short")) { if (env.getValue() == null) { value = Short.valueOf((short) 0); } else { value = Short.decode(env.getValue()); } } else if (type.equals("java.lang.Integer")) { if (env.getValue() == null) { value = Integer.valueOf(0); } else { value = Integer.decode(env.getValue()); } } else if (type.equals("java.lang.Long")) { if (env.getValue() == null) { value = Long.valueOf(0); } else { value = Long.decode(env.getValue()); } } else if (type.equals("java.lang.Boolean")) { value = Boolean.valueOf(env.getValue()); } else if (type.equals("java.lang.Double")) { if (env.getValue() == null) { value = Double.valueOf(0); } else { value = Double.valueOf(env.getValue()); } } else if (type.equals("java.lang.Float")) { if (env.getValue() == null) { value = Float.valueOf(0); } else { value = Float.valueOf(env.getValue()); } } else if (type.equals("java.lang.Character")) { if (env.getValue() == null) { value = Character.valueOf((char) 0); } else { if (env.getValue().length() == 1) { value = Character.valueOf(env.getValue().charAt(0)); } else { throw new IllegalArgumentException(); } } } else { value = constructEnvEntry(env.getType(), env.getValue()); if (value == null) { logger.error(sm.getString( "naming.invalidEnvEntryType", env.getName())); } } } catch (NumberFormatException e) { logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName())); } catch (IllegalArgumentException e) { logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName())); } // Binding the object to the appropriate name if (value != null) { try { if (logger.isDebugEnabled()) logger.debug(" Adding environment entry " + env.getName()); createSubcontexts(envCtx, env.getName()); envCtx.bind(env.getName(), value); } catch (NamingException e) { logger.error(sm.getString("naming.invalidEnvEntryValue", e)); } } } private Object constructEnvEntry(String type, String value) { try { Class clazz = Class.forName(type); Constructor c = null; try { c = clazz.getConstructor(String.class); return c.newInstance(value); } catch (NoSuchMethodException e) { // Ignore } if (value.length() != 1) { return null; } try { c = clazz.getConstructor(char.class); return c.newInstance(Character.valueOf(value.charAt(0))); } catch (NoSuchMethodException e) { // Ignore } } catch (Exception e) { // Ignore } return null; } /** * Set the specified local EJBs in the naming context. */ public void addLocalEjb( @SuppressWarnings("unused") ContextLocalEjb localEjb) { // NO-OP } /** * Set the specified web service in the naming context. */ public void addService(ContextService service) { if (service.getWsdlfile() != null) { URL wsdlURL = null; try { wsdlURL = new URL(service.getWsdlfile()); } catch (MalformedURLException e) { // Ignore and carry on } if (wsdlURL == null) { try { wsdlURL = ((Context) container). getServletContext(). getResource(service.getWsdlfile()); } catch (MalformedURLException e) { // Ignore and carry on } } if (wsdlURL == null) { try { wsdlURL = ((Context) container). getServletContext(). getResource("/" + service.getWsdlfile()); logger.debug(" Changing service ref wsdl file for /" + service.getWsdlfile()); } catch (MalformedURLException e) { logger.error(sm.getString("naming.wsdlFailed", e)); } } if (wsdlURL == null) service.setWsdlfile(null); else service.setWsdlfile(wsdlURL.toString()); } if (service.getJaxrpcmappingfile() != null) { URL jaxrpcURL = null; try { jaxrpcURL = new URL(service.getJaxrpcmappingfile()); } catch (MalformedURLException e) { // Ignore and carry on } if (jaxrpcURL == null) { try { jaxrpcURL = ((Context) container). getServletContext(). getResource(service.getJaxrpcmappingfile()); } catch (MalformedURLException e) { // Ignore and carry on } } if (jaxrpcURL == null) { try { jaxrpcURL = ((Context) container). getServletContext(). getResource("/" + service.getJaxrpcmappingfile()); logger.debug(" Changing service ref jaxrpc file for /" + service.getJaxrpcmappingfile()); } catch (MalformedURLException e) { logger.error(sm.getString("naming.wsdlFailed", e)); } } if (jaxrpcURL == null) service.setJaxrpcmappingfile(null); else service.setJaxrpcmappingfile(jaxrpcURL.toString()); } // Create a reference to the resource. Reference ref = new ServiceRef (service.getName(), service.getType(), service.getServiceqname(), service.getWsdlfile(), service.getJaxrpcmappingfile()); // Adding the additional port-component-ref, if any Iterator portcomponent = service.getServiceendpoints(); while (portcomponent.hasNext()) { String serviceendpoint = portcomponent.next(); StringRefAddr refAddr = new StringRefAddr(ServiceRef.SERVICEENDPOINTINTERFACE, serviceendpoint); ref.add(refAddr); String portlink = service.getPortlink(serviceendpoint); refAddr = new StringRefAddr(ServiceRef.PORTCOMPONENTLINK, portlink); ref.add(refAddr); } // Adding the additional parameters, if any Iterator handlers = service.getHandlers(); while (handlers.hasNext()) { String handlername = handlers.next(); ContextHandler handler = service.getHandler(handlername); HandlerRef handlerRef = new HandlerRef(handlername, handler.getHandlerclass()); Iterator localParts = handler.getLocalparts(); while (localParts.hasNext()) { String localPart = localParts.next(); String namespaceURI = handler.getNamespaceuri(localPart); handlerRef.add(new StringRefAddr(HandlerRef.HANDLER_LOCALPART, localPart)); handlerRef.add(new StringRefAddr(HandlerRef.HANDLER_NAMESPACE, namespaceURI)); } Iterator params = handler.listProperties(); while (params.hasNext()) { String paramName = params.next(); String paramValue = (String) handler.getProperty(paramName); handlerRef.add(new StringRefAddr(HandlerRef.HANDLER_PARAMNAME, paramName)); handlerRef.add(new StringRefAddr(HandlerRef.HANDLER_PARAMVALUE, paramValue)); } for (int i = 0; i < handler.getSoapRolesSize(); i++) { handlerRef.add(new StringRefAddr(HandlerRef.HANDLER_SOAPROLE, handler.getSoapRole(i))); } for (int i = 0; i < handler.getPortNamesSize(); i++) { handlerRef.add(new StringRefAddr(HandlerRef.HANDLER_PORTNAME, handler.getPortName(i))); } ((ServiceRef) ref).addHandler(handlerRef); } try { if (logger.isDebugEnabled()) { logger.debug(" Adding service ref " + service.getName() + " " + ref); } createSubcontexts(envCtx, service.getName()); envCtx.bind(service.getName(), ref); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } } /** * Set the specified resources in the naming context. */ public void addResource(ContextResource resource) { // Create a reference to the resource. Reference ref = new ResourceRef (resource.getType(), resource.getDescription(), resource.getScope(), resource.getAuth(), resource.getSingleton()); // Adding the additional parameters, if any Iterator params = resource.listProperties(); while (params.hasNext()) { String paramName = params.next(); String paramValue = (String) resource.getProperty(paramName); StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); ref.add(refAddr); } try { if (logger.isDebugEnabled()) { logger.debug(" Adding resource ref " + resource.getName() + " " + ref); } createSubcontexts(envCtx, resource.getName()); envCtx.bind(resource.getName(), ref); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } if ("javax.sql.DataSource".equals(ref.getClassName()) && resource.getSingleton()) { try { ObjectName on = createObjectName(resource); Object actualResource = envCtx.lookup(resource.getName()); Registry.getRegistry(null, null).registerComponent(actualResource, on, null); objectNames.put(resource.getName(), on); } catch (Exception e) { logger.warn(sm.getString("naming.jmxRegistrationFailed", e)); } } } /** * Set the specified resources in the naming context. */ public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) { // Create a reference to the resource env. Reference ref = new ResourceEnvRef(resourceEnvRef.getType()); // Adding the additional parameters, if any Iterator params = resourceEnvRef.listProperties(); while (params.hasNext()) { String paramName = params.next(); String paramValue = (String) resourceEnvRef.getProperty(paramName); StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); ref.add(refAddr); } try { if (logger.isDebugEnabled()) log.debug(" Adding resource env ref " + resourceEnvRef.getName()); createSubcontexts(envCtx, resourceEnvRef.getName()); envCtx.bind(resourceEnvRef.getName(), ref); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } } /** * Set the specified resource link in the naming context. */ public void addResourceLink(ContextResourceLink resourceLink) { // Create a reference to the resource. Reference ref = new ResourceLinkRef (resourceLink.getType(), resourceLink.getGlobal(), resourceLink.getFactory(), null); Iterator i = resourceLink.listProperties(); while (i.hasNext()) { String key = i.next().toString(); Object val = resourceLink.getProperty(key); if (val!=null) { StringRefAddr refAddr = new StringRefAddr(key, val.toString()); ref.add(refAddr); } } javax.naming.Context ctx = "UserTransaction".equals(resourceLink.getName()) ? compCtx : envCtx; try { if (logger.isDebugEnabled()) log.debug(" Adding resource link " + resourceLink.getName()); createSubcontexts(envCtx, resourceLink.getName()); ctx.bind(resourceLink.getName(), ref); } catch (NamingException e) { logger.error(sm.getString("naming.bindFailed", e)); } } /** * Set the specified EJBs in the naming context. */ public void removeEjb(String name) { try { envCtx.unbind(name); } catch (NamingException e) { logger.error(sm.getString("naming.unbindFailed", e)); } } /** * Set the specified environment entries in the naming context. */ public void removeEnvironment(String name) { try { envCtx.unbind(name); } catch (NamingException e) { logger.error(sm.getString("naming.unbindFailed", e)); } } /** * Set the specified local EJBs in the naming context. */ public void removeLocalEjb(String name) { try { envCtx.unbind(name); } catch (NamingException e) { logger.error(sm.getString("naming.unbindFailed", e)); } } /** * Set the specified web services in the naming context. */ public void removeService(String name) { try { envCtx.unbind(name); } catch (NamingException e) { logger.error(sm.getString("naming.unbindFailed", e)); } } /** * Set the specified resources in the naming context. */ public void removeResource(String name) { try { envCtx.unbind(name); } catch (NamingException e) { logger.error(sm.getString("naming.unbindFailed", e)); } ObjectName on = objectNames.get(name); if (on != null) { Registry.getRegistry(null, null).unregisterComponent(on); } } /** * Set the specified resources in the naming context. */ public void removeResourceEnvRef(String name) { try { envCtx.unbind(name); } catch (NamingException e) { logger.error(sm.getString("naming.unbindFailed", e)); } } /** * Set the specified resources in the naming context. */ public void removeResourceLink(String name) { try { envCtx.unbind(name); } catch (NamingException e) { logger.error(sm.getString("naming.unbindFailed", e)); } } /** * Create all intermediate subcontexts. */ private void createSubcontexts(javax.naming.Context ctx, String name) throws NamingException { javax.naming.Context currentContext = ctx; StringTokenizer tokenizer = new StringTokenizer(name, "/"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if ((!token.equals("")) && (tokenizer.hasMoreTokens())) { try { currentContext = currentContext.createSubcontext(token); } catch (NamingException e) { // Silent catch. Probably an object is already bound in // the context. currentContext = (javax.naming.Context) currentContext.lookup(token); } } } } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardWrapperValve.java0000644000175100017510000005406612271471332025557 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometProcessor; import org.apache.catalina.connector.ClientAbortException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.valves.ValveBase; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.log.SystemLogHandler; import org.apache.tomcat.util.res.StringManager; /** * Valve that implements the default basic behavior for the * StandardWrapper container implementation. * * @author Craig R. McClanahan */ final class StandardWrapperValve extends ValveBase { //------------------------------------------------------ Constructor public StandardWrapperValve() { super(true); } // ----------------------------------------------------- Instance Variables // Some JMX statistics. This valve is associated with a StandardWrapper. // We expose the StandardWrapper as JMX ( j2eeType=Servlet ). The fields // are here for performance. private volatile long processingTime; private volatile long maxTime; private volatile long minTime = Long.MAX_VALUE; private volatile int requestCount; private volatile int errorCount; /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); // --------------------------------------------------------- Public Methods /** * Invoke the servlet we are managing, respecting the rules regarding * servlet lifecycle and SingleThreadModel support. * * @param request Request to be processed * @param response Response to be produced * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public final void invoke(Request request, Response response) throws IOException, ServletException { // Initialize local variables we may need boolean unavailable = false; Throwable throwable = null; // This should be a Request attribute... long t1=System.currentTimeMillis(); requestCount++; StandardWrapper wrapper = (StandardWrapper) getContainer(); Servlet servlet = null; Context context = (Context) wrapper.getParent(); // Check for the application being marked unavailable if (!context.getState().isAvailable()) { response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardContext.isUnavailable")); unavailable = true; } // Check for the servlet being marked unavailable if (!unavailable && wrapper.isUnavailable()) { container.getLogger().info(sm.getString("standardWrapper.isUnavailable", wrapper.getName())); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardWrapper.isUnavailable", wrapper.getName())); } else if (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("standardWrapper.notFound", wrapper.getName())); } unavailable = true; } // Allocate a servlet instance to process this request try { if (!unavailable) { servlet = wrapper.allocate(); } } catch (UnavailableException e) { container.getLogger().error( sm.getString("standardWrapper.allocateException", wrapper.getName()), e); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardWrapper.isUnavailable", wrapper.getName())); } else if (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("standardWrapper.notFound", wrapper.getName())); } } catch (ServletException e) { container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), StandardWrapper.getRootCause(e)); throwable = e; exception(request, response, e); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), e); throwable = e; exception(request, response, e); servlet = null; } // Identify if the request is Comet related now that the servlet has been allocated boolean comet = false; if (servlet instanceof CometProcessor && request.getAttribute( Globals.COMET_SUPPORTED_ATTR) == Boolean.TRUE) { comet = true; request.setComet(true); } MessageBytes requestPathMB = request.getRequestPathMB(); DispatcherType dispatcherType = DispatcherType.REQUEST; if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC; request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, requestPathMB); // Create the filter chain for this request ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet); // Reset comet flag value after creating the filter chain request.setComet(false); // Call the filter chain for this request // NOTE: This also calls the servlet's service() method try { if ((servlet != null) && (filterChain != null)) { // Swallow output if needed if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); if (request.isAsyncDispatching()) { //TODO SERVLET3 - async ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { filterChain.doFilterEvent(request.getEvent()); request.setComet(true); } else { filterChain.doFilter(request.getRequest(), response.getResponse()); } } finally { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { context.getLogger().info(log); } } } else { if (request.isAsyncDispatching()) { //TODO SERVLET3 - async ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch(); } else if (comet) { request.setComet(true); filterChain.doFilterEvent(request.getEvent()); } else { filterChain.doFilter (request.getRequest(), response.getResponse()); } } } } catch (ClientAbortException e) { throwable = e; exception(request, response, e); } catch (IOException e) { container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); throwable = e; exception(request, response, e); } catch (UnavailableException e) { container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); // throwable = e; // exception(request, response, e); wrapper.unavailable(e); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardWrapper.isUnavailable", wrapper.getName())); } else if (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("standardWrapper.notFound", wrapper.getName())); } // Do not save exception in 'throwable', because we // do not want to do exception(request, response, e) processing } catch (ServletException e) { Throwable rootCause = StandardWrapper.getRootCause(e); if (!(rootCause instanceof ClientAbortException)) { container.getLogger().error(sm.getString( "standardWrapper.serviceExceptionRoot", wrapper.getName(), context.getName(), e.getMessage()), rootCause); } throwable = e; exception(request, response, e); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); throwable = e; exception(request, response, e); } // Release the filter chain (if any) for this request if (filterChain != null) { if (request.isComet()) { // If this is a Comet request, then the same chain will be used for the // processing of all subsequent events. filterChain.reuse(); } else { filterChain.release(); } } // Deallocate the allocated servlet instance try { if (servlet != null) { wrapper.deallocate(servlet); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.deallocateException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, e); } } // If this servlet has been marked permanently unavailable, // unload it and release this instance try { if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) { wrapper.unload(); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.unloadException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, e); } } long t2=System.currentTimeMillis(); long time=t2-t1; processingTime += time; if( time > maxTime) maxTime=time; if( time < minTime) minTime=time; } /** * Process a Comet event. The main differences here are to not use sendError * (the response is committed), to avoid creating a new filter chain * (which would work but be pointless), and a few very minor tweaks. * * @param request The servlet request to be processed * @param response The servlet response to be created * * @exception IOException if an input/output error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet * @exception ServletException if a servlet error occurs, or is thrown * by a subsequently invoked Valve, Filter, or Servlet */ @Override public void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Initialize local variables we may need Throwable throwable = null; // This should be a Request attribute... long t1=System.currentTimeMillis(); // FIXME: Add a flag to count the total amount of events processed ? requestCount++; StandardWrapper wrapper = (StandardWrapper) getContainer(); if (wrapper == null) { // Context has been shutdown. Nothing to do here. return; } Servlet servlet = null; Context context = (Context) wrapper.getParent(); // Check for the application being marked unavailable boolean unavailable = !context.getState().isAvailable() || wrapper.isUnavailable(); // Allocate a servlet instance to process this request try { if (!unavailable) { servlet = wrapper.allocate(); } } catch (UnavailableException e) { // The response is already committed, so it's not possible to do anything } catch (ServletException e) { container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), StandardWrapper.getRootCause(e)); throwable = e; exception(request, response, e); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), e); throwable = e; exception(request, response, e); servlet = null; } MessageBytes requestPathMB = request.getRequestPathMB(); request.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.REQUEST); request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, requestPathMB); // Get the current (unchanged) filter chain for this request ApplicationFilterChain filterChain = (ApplicationFilterChain) request.getFilterChain(); // Call the filter chain for this request // NOTE: This also calls the servlet's event() method try { if ((servlet != null) && (filterChain != null)) { // Swallow output if needed if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); filterChain.doFilterEvent(request.getEvent()); } finally { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { context.getLogger().info(log); } } } else { filterChain.doFilterEvent(request.getEvent()); } } } catch (ClientAbortException e) { throwable = e; exception(request, response, e); } catch (IOException e) { container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); throwable = e; exception(request, response, e); } catch (UnavailableException e) { container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); // Do not save exception in 'throwable', because we // do not want to do exception(request, response, e) processing } catch (ServletException e) { Throwable rootCause = StandardWrapper.getRootCause(e); if (!(rootCause instanceof ClientAbortException)) { container.getLogger().error(sm.getString( "standardWrapper.serviceExceptionRoot", wrapper.getName(), context.getName(), e.getMessage()), rootCause); } throwable = e; exception(request, response, e); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString( "standardWrapper.serviceException", wrapper.getName(), context.getName()), e); throwable = e; exception(request, response, e); } // Release the filter chain (if any) for this request if (filterChain != null) { filterChain.reuse(); } // Deallocate the allocated servlet instance try { if (servlet != null) { wrapper.deallocate(servlet); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.deallocateException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, e); } } // If this servlet has been marked permanently unavailable, // unload it and release this instance try { if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) { wrapper.unload(); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.unloadException", wrapper.getName()), e); if (throwable == null) { throwable = e; exception(request, response, e); } } long t2=System.currentTimeMillis(); long time=t2-t1; processingTime += time; if( time > maxTime) maxTime=time; if( time < minTime) minTime=time; } // -------------------------------------------------------- Private Methods /** * Handle the specified ServletException encountered while processing * the specified Request to produce the specified Response. Any * exceptions that occur during generation of the exception report are * logged and swallowed. * * @param request The request being processed * @param response The response being generated * @param exception The exception that occurred (which possibly wraps * a root cause exception */ private void exception(Request request, Response response, Throwable exception) { request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, exception); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } public long getProcessingTime() { return processingTime; } /** * Deprecated unused */ @Deprecated public void setProcessingTime(long processingTime) { this.processingTime = processingTime; } public long getMaxTime() { return maxTime; } /** * Deprecated unused */ @Deprecated public void setMaxTime(long maxTime) { this.maxTime = maxTime; } public long getMinTime() { return minTime; } /** * Deprecated unused */ @Deprecated public void setMinTime(long minTime) { this.minTime = minTime; } public int getRequestCount() { return requestCount; } /** * Deprecated unused */ @Deprecated public void setRequestCount(int requestCount) { this.requestCount = requestCount; } public int getErrorCount() { return errorCount; } public void incrementErrorCount() { errorCount++; } /** * Deprecated unused */ @Deprecated public void setErrorCount(int errorCount) { this.errorCount = errorCount; } @Override protected void initInternal() throws LifecycleException { // NOOP - Don't register this Valve in JMX } } tomcat7-7.0.52/java/org/apache/catalina/core/ThreadLocalLeakPreventionListener.java0000644000175100017510000002033112271471332030203 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.concurrent.Executor; import org.apache.catalina.Container; import org.apache.catalina.ContainerEvent; import org.apache.catalina.ContainerListener; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.connector.Connector; import org.apache.coyote.ProtocolHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.threads.ThreadPoolExecutor; /** *

    * A {@link LifecycleListener} that triggers the renewal of threads in Executor * pools when a {@link Context} is being stopped to avoid thread-local related * memory leaks. *

    *

    * Note : active threads will be renewed one by one when they come back to the * pool after executing their task, see * {@link org.apache.tomcat.util.threads.ThreadPoolExecutor}.afterExecute(). *

    * * This listener must be declared in server.xml to be active. * */ public class ThreadLocalLeakPreventionListener implements LifecycleListener, ContainerListener { private static final Log log = LogFactory.getLog(ThreadLocalLeakPreventionListener.class); private volatile boolean serverStopping = false; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Listens for {@link LifecycleEvent} for the start of the {@link Server} to * initialize itself and then for after_stop events of each {@link Context}. */ @Override public void lifecycleEvent(LifecycleEvent event) { try { Lifecycle lifecycle = event.getLifecycle(); if (Lifecycle.AFTER_START_EVENT.equals(event.getType()) && lifecycle instanceof Server) { // when the server starts, we register ourself as listener for // all context // as well as container event listener so that we know when new // Context are deployed Server server = (Server) lifecycle; registerListenersForServer(server); } if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType()) && lifecycle instanceof Server) { // Server is shutting down, so thread pools will be shut down so // there is no need to clean the threads serverStopping = true; } if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType()) && lifecycle instanceof Context) { stopIdleThreads((Context) lifecycle); } } catch (Exception e) { String msg = sm.getString( "threadLocalLeakPreventionListener.lifecycleEvent.error", event); log.error(msg, e); } } @Override public void containerEvent(ContainerEvent event) { try { String type = event.getType(); if (Container.ADD_CHILD_EVENT.equals(type)) { processContainerAddChild(event.getContainer(), (Container) event.getData()); } else if (Container.REMOVE_CHILD_EVENT.equals(type)) { processContainerRemoveChild(event.getContainer(), (Container) event.getData()); } } catch (Exception e) { String msg = sm.getString( "threadLocalLeakPreventionListener.containerEvent.error", event); log.error(msg, e); } } private void registerListenersForServer(Server server) { for (Service service : server.findServices()) { Engine engine = (Engine) service.getContainer(); engine.addContainerListener(this); registerListenersForEngine(engine); } } private void registerListenersForEngine(Engine engine) { for (Container hostContainer : engine.findChildren()) { Host host = (Host) hostContainer; host.addContainerListener(this); registerListenersForHost(host); } } private void registerListenersForHost(Host host) { for (Container contextContainer : host.findChildren()) { Context context = (Context) contextContainer; registerContextListener(context); } } private void registerContextListener(Context context) { context.addLifecycleListener(this); } protected void processContainerAddChild(Container parent, Container child) { if (log.isDebugEnabled()) log.debug("Process addChild[parent=" + parent + ",child=" + child + "]"); if (child instanceof Context) { registerContextListener((Context) child); } else if (child instanceof Engine) { registerListenersForEngine((Engine) child); } else if (child instanceof Host) { registerListenersForHost((Host) child); } } protected void processContainerRemoveChild(Container parent, Container child) { if (log.isDebugEnabled()) log.debug("Process removeChild[parent=" + parent + ",child=" + child + "]"); if (child instanceof Context) { Context context = (Context) child; context.removeLifecycleListener(this); } else if (child instanceof Host || child instanceof Engine) { child.removeContainerListener(this); } } /** * Updates each ThreadPoolExecutor with the current time, which is the time * when a context is being stopped. * * @param context * the context being stopped, used to discover all the Connectors * of its parent Service. */ private void stopIdleThreads(Context context) { if (serverStopping) return; if (context instanceof StandardContext && !((StandardContext) context).getRenewThreadsWhenStoppingContext()) { log.debug("Not renewing threads when the context is stopping, " + "it is configured not to do it."); return; } Engine engine = (Engine) context.getParent().getParent(); Service service = engine.getService(); Connector[] connectors = service.findConnectors(); if (connectors != null) { for (Connector connector : connectors) { ProtocolHandler handler = connector.getProtocolHandler(); Executor executor = null; if (handler != null) { executor = handler.getExecutor(); } if (executor instanceof ThreadPoolExecutor) { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; threadPoolExecutor.contextStopping(); } else if (executor instanceof StandardThreadExecutor) { StandardThreadExecutor stdThreadExecutor = (StandardThreadExecutor) executor; stdThreadExecutor.contextStopping(); } } } } } tomcat7-7.0.52/java/org/apache/catalina/core/RestrictedListeners.properties0000644000175100017510000000141512271471332026722 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. tomcat7-7.0.52/java/org/apache/catalina/core/AprLifecycleListener.java0000644000175100017510000002724212271471332025524 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.Library; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Implementation of LifecycleListener that will init and * and destroy APR. * * @author Remy Maucherat * @author Filip Hanik * @since 4.1 */ public class AprLifecycleListener implements LifecycleListener { private static final Log log = LogFactory.getLog(AprLifecycleListener.class); private static boolean instanceCreated = false; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ---------------------------------------------- Constants protected static final int TCN_REQUIRED_MAJOR = 1; protected static final int TCN_REQUIRED_MINOR = 1; protected static final int TCN_REQUIRED_PATCH = 29; protected static final int TCN_RECOMMENDED_MINOR = 1; protected static final int TCN_RECOMMENDED_PV = 29; // ---------------------------------------------- Properties protected static String SSLEngine = "on"; //default on protected static String FIPSMode = "off"; // default off, valid only when SSLEngine="on" protected static String SSLRandomSeed = "builtin"; protected static boolean sslInitialized = false; protected static boolean aprInitialized = false; @Deprecated protected static boolean sslAvailable = false; protected static boolean aprAvailable = false; protected static boolean fipsModeActive = false; protected static final Object lock = new Object(); public static boolean isAprAvailable() { //https://issues.apache.org/bugzilla/show_bug.cgi?id=48613 if (instanceCreated) { synchronized (lock) { init(); } } return aprAvailable; } public AprLifecycleListener() { instanceCreated = true; } // ---------------------------------------------- LifecycleListener Methods /** * Primary entry point for startup and shutdown events. * * @param event The event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) { synchronized (lock) { init(); if (aprAvailable) { try { initializeSSL(); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.error(sm.getString("aprListener.sslInit"), t); } } // Failure to initialize FIPS mode is fatal if ("on".equalsIgnoreCase(FIPSMode) && !isFIPSModeActive()) { Error e = new Error( sm.getString("aprListener.initializeFIPSFailed")); // Log here, because thrown error might be not logged log.fatal(e.getMessage(), e); throw e; } } } else if (Lifecycle.AFTER_DESTROY_EVENT.equals(event.getType())) { synchronized (lock) { if (!aprAvailable) { return; } try { terminateAPR(); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.info(sm.getString("aprListener.aprDestroy")); } } } } private static void terminateAPR() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { String methodName = "terminate"; Method method = Class.forName("org.apache.tomcat.jni.Library") .getMethod(methodName, (Class [])null); method.invoke(null, (Object []) null); aprAvailable = false; aprInitialized = false; sslInitialized = false; // Well we cleaned the pool in terminate. sslAvailable = false; // Well we cleaned the pool in terminate. fipsModeActive = false; } private static void init() { int major = 0; int minor = 0; int patch = 0; int apver = 0; int rqver = TCN_REQUIRED_MAJOR * 1000 + TCN_REQUIRED_MINOR * 100 + TCN_REQUIRED_PATCH; int rcver = TCN_REQUIRED_MAJOR * 1000 + TCN_RECOMMENDED_MINOR * 100 + TCN_RECOMMENDED_PV; if (aprInitialized) { return; } aprInitialized = true; try { String methodName = "initialize"; Class paramTypes[] = new Class[1]; paramTypes[0] = String.class; Object paramValues[] = new Object[1]; paramValues[0] = null; Class clazz = Class.forName("org.apache.tomcat.jni.Library"); Method method = clazz.getMethod(methodName, paramTypes); method.invoke(null, paramValues); major = clazz.getField("TCN_MAJOR_VERSION").getInt(null); minor = clazz.getField("TCN_MINOR_VERSION").getInt(null); patch = clazz.getField("TCN_PATCH_VERSION").getInt(null); apver = major * 1000 + minor * 100 + patch; } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.info(sm.getString("aprListener.aprInit", System.getProperty("java.library.path"))); return; } if (apver < rqver) { log.error(sm.getString("aprListener.tcnInvalid", major + "." + minor + "." + patch, TCN_REQUIRED_MAJOR + "." + TCN_REQUIRED_MINOR + "." + TCN_REQUIRED_PATCH)); try { // Terminate the APR in case the version // is below required. terminateAPR(); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); } return; } if (apver < rcver) { log.info(sm.getString("aprListener.tcnVersion", major + "." + minor + "." + patch, TCN_REQUIRED_MAJOR + "." + TCN_RECOMMENDED_MINOR + "." + TCN_RECOMMENDED_PV)); } log.info(sm.getString("aprListener.tcnValid", major + "." + minor + "." + patch, Library.APR_MAJOR_VERSION + "." + Library.APR_MINOR_VERSION + "." + Library.APR_PATCH_VERSION)); // Log APR flags log.info(sm.getString("aprListener.flags", Boolean.valueOf(Library.APR_HAVE_IPV6), Boolean.valueOf(Library.APR_HAS_SENDFILE), Boolean.valueOf(Library.APR_HAS_SO_ACCEPTFILTER), Boolean.valueOf(Library.APR_HAS_RANDOM))); aprAvailable = true; } private static void initializeSSL() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { if ("off".equalsIgnoreCase(SSLEngine)) { return; } if (sslInitialized) { //only once per VM return; } sslInitialized = true; String methodName = "randSet"; Class paramTypes[] = new Class[1]; paramTypes[0] = String.class; Object paramValues[] = new Object[1]; paramValues[0] = SSLRandomSeed; Class clazz = Class.forName("org.apache.tomcat.jni.SSL"); Method method = clazz.getMethod(methodName, paramTypes); method.invoke(null, paramValues); methodName = "initialize"; paramValues[0] = "on".equalsIgnoreCase(SSLEngine)?null:SSLEngine; method = clazz.getMethod(methodName, paramTypes); method.invoke(null, paramValues); if("on".equalsIgnoreCase(FIPSMode)) { log.info(sm.getString("aprListener.initializingFIPS")); int result = SSL.fipsModeSet(1); // success is defined as return value = 1 if(1 == result) { fipsModeActive = true; log.info(sm.getString("aprListener.initializeFIPSSuccess")); } else { // This case should be handled by the native method, // but we'll make absolutely sure, here. String message = sm.getString("aprListener.initializeFIPSFailed"); log.error(message); throw new IllegalStateException(message); } } log.info(sm.getString("aprListener.initializedOpenSSL", SSL.versionString())); sslAvailable = true; } public String getSSLEngine() { return SSLEngine; } public void setSSLEngine(String SSLEngine) { if (!SSLEngine.equals(AprLifecycleListener.SSLEngine)) { // Ensure that the SSLEngine is consistent with that used for SSL init if (sslInitialized) { throw new IllegalStateException( sm.getString("aprListener.tooLateForSSLEngine")); } AprLifecycleListener.SSLEngine = SSLEngine; } } public String getSSLRandomSeed() { return SSLRandomSeed; } public void setSSLRandomSeed(String SSLRandomSeed) { if (!SSLRandomSeed.equals(AprLifecycleListener.SSLRandomSeed)) { // Ensure that the random seed is consistent with that used for SSL init if (sslInitialized) { throw new IllegalStateException( sm.getString("aprListener.tooLateForSSLRandomSeed")); } AprLifecycleListener.SSLRandomSeed = SSLRandomSeed; } } public String getFIPSMode() { return FIPSMode; } public void setFIPSMode(String FIPSMode) { if (!FIPSMode.equals(AprLifecycleListener.FIPSMode)) { // Ensure that the FIPS mode is consistent with that used for SSL init if (sslInitialized) { throw new IllegalStateException( sm.getString("aprListener.tooLateForFIPSMode")); } AprLifecycleListener.FIPSMode = FIPSMode; } } public boolean isFIPSModeActive() { return fipsModeActive; } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationFilterRegistration.java0000644000175100017510000001512412271471332027454 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.Collection; import java.util.EnumSet; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.servlet.DispatcherType; import javax.servlet.FilterRegistration; import org.apache.catalina.Context; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.util.ParameterMap; import org.apache.tomcat.util.res.StringManager; public class ApplicationFilterRegistration implements FilterRegistration.Dynamic { /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); private FilterDef filterDef; private Context context; public ApplicationFilterRegistration(FilterDef filterDef, Context context) { this.filterDef = filterDef; this.context = context; } @Override public void addMappingForServletNames( EnumSet dispatcherTypes, boolean isMatchAfter, String... servletNames) { FilterMap filterMap = new FilterMap(); filterMap.setFilterName(filterDef.getFilterName()); if (dispatcherTypes != null) { for (DispatcherType dispatcherType : dispatcherTypes) { filterMap.setDispatcher(dispatcherType.name()); } } if (servletNames != null) { for (String servletName : servletNames) { filterMap.addServletName(servletName); } if (isMatchAfter) { context.addFilterMap(filterMap); } else { context.addFilterMapBefore(filterMap); } } // else error? } @Override public void addMappingForUrlPatterns( EnumSet dispatcherTypes, boolean isMatchAfter, String... urlPatterns) { FilterMap filterMap = new FilterMap(); filterMap.setFilterName(filterDef.getFilterName()); if (dispatcherTypes != null) { for (DispatcherType dispatcherType : dispatcherTypes) { filterMap.setDispatcher(dispatcherType.name()); } } if (urlPatterns != null) { for (String urlPattern : urlPatterns) { filterMap.addURLPattern(urlPattern); } if (isMatchAfter) { context.addFilterMap(filterMap); } else { context.addFilterMapBefore(filterMap); } } // else error? } @Override public Collection getServletNameMappings() { Collection result = new HashSet(); FilterMap[] filterMaps = context.findFilterMaps(); for (FilterMap filterMap : filterMaps) { if (filterMap.getFilterName().equals(filterDef.getFilterName())) { for (String servletName : filterMap.getServletNames()) { result.add(servletName); } } } return result; } @Override public Collection getUrlPatternMappings() { Collection result = new HashSet(); FilterMap[] filterMaps = context.findFilterMaps(); for (FilterMap filterMap : filterMaps) { if (filterMap.getFilterName().equals(filterDef.getFilterName())) { for (String urlPattern : filterMap.getURLPatterns()) { result.add(urlPattern); } } } return result; } @Override public String getClassName() { return filterDef.getFilterClass(); } @Override public String getInitParameter(String name) { return filterDef.getParameterMap().get(name); } @Override public Map getInitParameters() { ParameterMap result = new ParameterMap(); result.putAll(filterDef.getParameterMap()); result.setLocked(true); return result; } @Override public String getName() { return filterDef.getFilterName(); } @Override public boolean setInitParameter(String name, String value) { if (name == null || value == null) { throw new IllegalArgumentException( sm.getString("applicationFilterRegistration.nullInitParam", name, value)); } if (getInitParameter(name) != null) { return false; } filterDef.addInitParameter(name, value); return true; } @Override public Set setInitParameters(Map initParameters) { Set conflicts = new HashSet(); for (Map.Entry entry : initParameters.entrySet()) { if (entry.getKey() == null || entry.getValue() == null) { throw new IllegalArgumentException(sm.getString( "applicationFilterRegistration.nullInitParams", entry.getKey(), entry.getValue())); } if (getInitParameter(entry.getKey()) != null) { conflicts.add(entry.getKey()); } } // Have to add in a separate loop since spec requires no updates at all // if there is an issue for (Map.Entry entry : initParameters.entrySet()) { setInitParameter(entry.getKey(), entry.getValue()); } return conflicts; } @Override public void setAsyncSupported(boolean asyncSupported) { filterDef.setAsyncSupported(Boolean.valueOf(asyncSupported).toString()); } } tomcat7-7.0.52/java/org/apache/catalina/core/ContainerBase.java0000644000175100017510000013753712271471332024202 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.management.ObjectName; import javax.naming.directory.DirContext; import javax.servlet.ServletException; import org.apache.catalina.AccessLog; import org.apache.catalina.Cluster; import org.apache.catalina.Container; import org.apache.catalina.ContainerEvent; import org.apache.catalina.ContainerListener; import org.apache.catalina.Globals; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Loader; import org.apache.catalina.Manager; import org.apache.catalina.Pipeline; import org.apache.catalina.Realm; import org.apache.catalina.Valve; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.naming.resources.ProxyDirContext; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Abstract implementation of the Container interface, providing common * functionality required by nearly every implementation. Classes extending * this base class must implement getInfo(), and may implement * a replacement for invoke(). *

    * All subclasses of this abstract base class will include support for a * Pipeline object that defines the processing to be performed for each request * received by the invoke() method of this class, utilizing the * "Chain of Responsibility" design pattern. A subclass should encapsulate its * own processing functionality as a Valve, and configure this * Valve into the pipeline by calling setBasic(). *

    * This implementation fires property change events, per the JavaBeans design * pattern, for changes in singleton properties. In addition, it fires the * following ContainerEvent events to listeners who register * themselves with addContainerListener(): * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    TypeDataDescription
    addChildContainerChild container added to this Container.
    addValveValveValve added to this Container.
    removeChildContainerChild container removed from this Container.
    removeValveValveValve removed from this Container.
    startnullContainer was started.
    stopnullContainer was stopped.
    * Subclasses that fire additional events should document them in the * class comments of the implementation class. * * TODO: Review synchronisation around background processing. See bug 47024. * * @author Craig R. McClanahan */ public abstract class ContainerBase extends LifecycleMBeanBase implements Container { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( ContainerBase.class ); /** * Perform addChild with the permissions of this class. * addChild can be called with the XML parser on the stack, * this allows the XML parser to have fewer privileges than * Tomcat. */ protected class PrivilegedAddChild implements PrivilegedAction { private Container child; PrivilegedAddChild(Container child) { this.child = child; } @Override public Void run() { addChildInternal(child); return null; } } // ----------------------------------------------------- Instance Variables /** * The child Containers belonging to this Container, keyed by name. */ protected HashMap children = new HashMap(); /** * The processor delay for this component. */ protected int backgroundProcessorDelay = -1; /** * The container event listeners for this Container. Implemented as a * CopyOnWriteArrayList since listeners may invoke methods to add/remove * themselves or other listeners and with a ReadWriteLock that would trigger * a deadlock. */ protected List listeners = new CopyOnWriteArrayList(); /** * The Loader implementation with which this Container is associated. */ protected Loader loader = null; /** * The Logger implementation with which this Container is associated. */ protected Log logger = null; /** * Associated logger name. */ protected String logName = null; /** * The Manager implementation with which this Container is associated. */ protected Manager manager = null; /** * The cluster with which this Container is associated. */ protected Cluster cluster = null; /** * The human-readable name of this Container. */ protected String name = null; /** * The parent Container to which this Container is a child. */ protected Container parent = null; /** * The parent class loader to be configured when we install a Loader. */ protected ClassLoader parentClassLoader = null; /** * The Pipeline object with which this Container is associated. */ protected Pipeline pipeline = new StandardPipeline(this); /** * The Realm with which this Container is associated. */ private volatile Realm realm = null; /** * Lock used to control access to the Realm. */ private final ReadWriteLock realmLock = new ReentrantReadWriteLock(); /** * The resources DirContext object with which this Container is associated. */ protected DirContext resources = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Will children be started automatically when they are added. */ protected boolean startChildren = true; /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); /** * The background thread. */ private Thread thread = null; /** * The background thread completion semaphore. */ private volatile boolean threadDone = false; /** * The access log to use for requests normally handled by this container * that have been handled earlier in the processing chain. */ protected volatile AccessLog accessLog = null; private volatile boolean accessLogScanComplete = false; /** * The number of threads available to process start and stop events for any * children associated with this container. */ private int startStopThreads = 1; protected ThreadPoolExecutor startStopExecutor; // ------------------------------------------------------------- Properties @Override public int getStartStopThreads() { return startStopThreads; } /** * Handles the special values. */ private int getStartStopThreadsInternal() { int result = getStartStopThreads(); // Positive values are unchanged if (result > 0) { return result; } // Zero == Runtime.getRuntime().availableProcessors() // -ve == Runtime.getRuntime().availableProcessors() + value // These two are the same result = Runtime.getRuntime().availableProcessors() + result; if (result < 1) { result = 1; } return result; } @Override public void setStartStopThreads(int startStopThreads) { this.startStopThreads = startStopThreads; // Use local copies to ensure thread safety ThreadPoolExecutor executor = startStopExecutor; if (executor != null) { int newThreads = getStartStopThreadsInternal(); executor.setMaximumPoolSize(newThreads); executor.setCorePoolSize(newThreads); } } /** * Get the delay between the invocation of the backgroundProcess method on * this container and its children. Child containers will not be invoked * if their delay value is not negative (which would mean they are using * their own thread). Setting this to a positive value will cause * a thread to be spawn. After waiting the specified amount of time, * the thread will invoke the executePeriodic method on this container * and all its children. */ @Override public int getBackgroundProcessorDelay() { return backgroundProcessorDelay; } /** * Set the delay between the invocation of the execute method on this * container and its children. * * @param delay The delay in seconds between the invocation of * backgroundProcess methods */ @Override public void setBackgroundProcessorDelay(int delay) { backgroundProcessorDelay = delay; } /** * Return descriptive information about this Container implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return this.getClass().getName(); } /** * Return the Loader with which this Container is associated. If there is * no associated Loader, return the Loader associated with our parent * Container (if any); otherwise, return null. */ @Override public Loader getLoader() { if (loader != null) return (loader); if (parent != null) return (parent.getLoader()); return (null); } /** * Set the Loader with which this Container is associated. * * @param loader The newly associated loader */ @Override public synchronized void setLoader(Loader loader) { // Change components if necessary Loader oldLoader = this.loader; if (oldLoader == loader) return; this.loader = loader; // Stop the old component if necessary if (getState().isAvailable() && (oldLoader != null) && (oldLoader instanceof Lifecycle)) { try { ((Lifecycle) oldLoader).stop(); } catch (LifecycleException e) { log.error("ContainerBase.setLoader: stop: ", e); } } // Start the new component if necessary if (loader != null) loader.setContainer(this); if (getState().isAvailable() && (loader != null) && (loader instanceof Lifecycle)) { try { ((Lifecycle) loader).start(); } catch (LifecycleException e) { log.error("ContainerBase.setLoader: start: ", e); } } // Report this property change to interested listeners support.firePropertyChange("loader", oldLoader, this.loader); } /** * Return the Logger for this Container. */ @Override public Log getLogger() { if (logger != null) return (logger); logger = LogFactory.getLog(logName()); return (logger); } /** * Return the Manager with which this Container is associated. If there is * no associated Manager, return the Manager associated with our parent * Container (if any); otherwise return null. */ @Override public Manager getManager() { if (manager != null) return (manager); if (parent != null) return (parent.getManager()); return (null); } /** * Set the Manager with which this Container is associated. * * @param manager The newly associated Manager */ @Override public synchronized void setManager(Manager manager) { // Change components if necessary Manager oldManager = this.manager; if (oldManager == manager) return; this.manager = manager; // Stop the old component if necessary if (getState().isAvailable() && (oldManager != null) && (oldManager instanceof Lifecycle)) { try { ((Lifecycle) oldManager).stop(); } catch (LifecycleException e) { log.error("ContainerBase.setManager: stop: ", e); } } // Start the new component if necessary if (manager != null) manager.setContainer(this); if (getState().isAvailable() && (manager != null) && (manager instanceof Lifecycle)) { try { ((Lifecycle) manager).start(); } catch (LifecycleException e) { log.error("ContainerBase.setManager: start: ", e); } } // Report this property change to interested listeners support.firePropertyChange("manager", oldManager, this.manager); } /** * Return an object which may be utilized for mapping to this component. */ @Deprecated @Override public Object getMappingObject() { return this; } /** * Return the Cluster with which this Container is associated. If there is * no associated Cluster, return the Cluster associated with our parent * Container (if any); otherwise return null. */ @Override public Cluster getCluster() { if (cluster != null) return (cluster); if (parent != null) return (parent.getCluster()); return (null); } /** * Set the Cluster with which this Container is associated. * * @param cluster The newly associated Cluster */ @Override public synchronized void setCluster(Cluster cluster) { // Change components if necessary Cluster oldCluster = this.cluster; if (oldCluster == cluster) return; this.cluster = cluster; // Stop the old component if necessary if (getState().isAvailable() && (oldCluster != null) && (oldCluster instanceof Lifecycle)) { try { ((Lifecycle) oldCluster).stop(); } catch (LifecycleException e) { log.error("ContainerBase.setCluster: stop: ", e); } } // Start the new component if necessary if (cluster != null) cluster.setContainer(this); if (getState().isAvailable() && (cluster != null) && (cluster instanceof Lifecycle)) { try { ((Lifecycle) cluster).start(); } catch (LifecycleException e) { log.error("ContainerBase.setCluster: start: ", e); } } // Report this property change to interested listeners support.firePropertyChange("cluster", oldCluster, this.cluster); } /** * Return a name string (suitable for use by humans) that describes this * Container. Within the set of child containers belonging to a particular * parent, Container names must be unique. */ @Override public String getName() { return (name); } /** * Set a name string (suitable for use by humans) that describes this * Container. Within the set of child containers belonging to a particular * parent, Container names must be unique. * * @param name New name of this container * * @exception IllegalStateException if this Container has already been * added to the children of a parent Container (after which the name * may not be changed) */ @Override public void setName(String name) { String oldName = this.name; this.name = name; support.firePropertyChange("name", oldName, this.name); } /** * Return if children of this container will be started automatically when * they are added to this container. */ public boolean getStartChildren() { return (startChildren); } /** * Set if children of this container will be started automatically when * they are added to this container. * * @param startChildren New value of the startChildren flag */ public void setStartChildren(boolean startChildren) { boolean oldStartChildren = this.startChildren; this.startChildren = startChildren; support.firePropertyChange("startChildren", oldStartChildren, this.startChildren); } /** * Return the Container for which this Container is a child, if there is * one. If there is no defined parent, return null. */ @Override public Container getParent() { return (parent); } /** * Set the parent Container to which this Container is being added as a * child. This Container may refuse to become attached to the specified * Container by throwing an exception. * * @param container Container to which this Container is being added * as a child * * @exception IllegalArgumentException if this Container refuses to become * attached to the specified Container */ @Override public void setParent(Container container) { Container oldParent = this.parent; this.parent = container; support.firePropertyChange("parent", oldParent, this.parent); } /** * Return the parent class loader (if any) for this web application. * This call is meaningful only after a Loader has * been configured. */ @Override public ClassLoader getParentClassLoader() { if (parentClassLoader != null) return (parentClassLoader); if (parent != null) { return (parent.getParentClassLoader()); } return (ClassLoader.getSystemClassLoader()); } /** * Set the parent class loader (if any) for this web application. * This call is meaningful only before a Loader has * been configured, and the specified value (if non-null) should be * passed as an argument to the class loader constructor. * * * @param parent The new parent class loader */ @Override public void setParentClassLoader(ClassLoader parent) { ClassLoader oldParentClassLoader = this.parentClassLoader; this.parentClassLoader = parent; support.firePropertyChange("parentClassLoader", oldParentClassLoader, this.parentClassLoader); } /** * Return the Pipeline object that manages the Valves associated with * this Container. */ @Override public Pipeline getPipeline() { return (this.pipeline); } /** * Return the Realm with which this Container is associated. If there is * no associated Realm, return the Realm associated with our parent * Container (if any); otherwise return null. */ @Override public Realm getRealm() { Lock l = realmLock.readLock(); try { l.lock(); if (realm != null) return (realm); if (parent != null) return (parent.getRealm()); return null; } finally { l.unlock(); } } protected Realm getRealmInternal() { Lock l = realmLock.readLock(); try { l.lock(); return realm; } finally { l.unlock(); } } /** * Set the Realm with which this Container is associated. * * @param realm The newly associated Realm */ @Override public void setRealm(Realm realm) { Lock l = realmLock.writeLock(); try { l.lock(); // Change components if necessary Realm oldRealm = this.realm; if (oldRealm == realm) return; this.realm = realm; // Stop the old component if necessary if (getState().isAvailable() && (oldRealm != null) && (oldRealm instanceof Lifecycle)) { try { ((Lifecycle) oldRealm).stop(); } catch (LifecycleException e) { log.error("ContainerBase.setRealm: stop: ", e); } } // Start the new component if necessary if (realm != null) realm.setContainer(this); if (getState().isAvailable() && (realm != null) && (realm instanceof Lifecycle)) { try { ((Lifecycle) realm).start(); } catch (LifecycleException e) { log.error("ContainerBase.setRealm: start: ", e); } } // Report this property change to interested listeners support.firePropertyChange("realm", oldRealm, this.realm); } finally { l.unlock(); } } /** * Return the resources DirContext object with which this Container is * associated. If there is no associated resources object, return the * resources associated with our parent Container (if any); otherwise * return null. */ @Override public DirContext getResources() { if (resources != null) return (resources); if (parent != null) return (parent.getResources()); return (null); } /** * Set the resources DirContext object with which this Container is * associated. * * @param resources The newly associated DirContext */ @Override public synchronized void setResources(DirContext resources) { // Called from StandardContext.setResources() // <- StandardContext.start() // <- ContainerBase.addChildInternal() // Change components if necessary DirContext oldResources = this.resources; if (oldResources == resources) return; Hashtable env = new Hashtable(); if (getParent() != null) env.put(ProxyDirContext.HOST, getParent().getName()); env.put(ProxyDirContext.CONTEXT, getName()); this.resources = new ProxyDirContext(env, resources); // Report this property change to interested listeners support.firePropertyChange("resources", oldResources, this.resources); } // ------------------------------------------------------ Container Methods /** * Add a new child Container to those associated with this Container, * if supported. Prior to adding this Container to the set of children, * the child's setParent() method must be called, with this * Container as an argument. This method may thrown an * IllegalArgumentException if this Container chooses not * to be attached to the specified Container, in which case it is not added * * @param child New child Container to be added * * @exception IllegalArgumentException if this exception is thrown by * the setParent() method of the child Container * @exception IllegalArgumentException if the new child does not have * a name unique from that of existing children of this Container * @exception IllegalStateException if this Container does not support * child Containers */ @Override public void addChild(Container child) { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction dp = new PrivilegedAddChild(child); AccessController.doPrivileged(dp); } else { addChildInternal(child); } } private void addChildInternal(Container child) { if( log.isDebugEnabled() ) log.debug("Add child " + child + " " + this); synchronized(children) { if (children.get(child.getName()) != null) throw new IllegalArgumentException("addChild: Child name '" + child.getName() + "' is not unique"); child.setParent(this); // May throw IAE children.put(child.getName(), child); } // Start child // Don't do this inside sync block - start can be a slow process and // locking the children object can cause problems elsewhere if ((getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState())) && startChildren) { try { child.start(); } catch (LifecycleException e) { log.error("ContainerBase.addChild: start: ", e); throw new IllegalStateException ("ContainerBase.addChild: start: " + e); } } fireContainerEvent(ADD_CHILD_EVENT, child); } /** * Add a container event listener to this component. * * @param listener The listener to add */ @Override public void addContainerListener(ContainerListener listener) { listeners.add(listener); } /** * Add a property change listener to this component. * * @param listener The listener to add */ @Override public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } /** * Return the child Container, associated with this Container, with * the specified name (if any); otherwise, return null * * @param name Name of the child Container to be retrieved */ @Override public Container findChild(String name) { if (name == null) return (null); synchronized (children) { return children.get(name); } } /** * Return the set of children Containers associated with this Container. * If this Container has no children, a zero-length array is returned. */ @Override public Container[] findChildren() { synchronized (children) { Container results[] = new Container[children.size()]; return children.values().toArray(results); } } /** * Return the set of container listeners associated with this Container. * If this Container has no registered container listeners, a zero-length * array is returned. */ @Override public ContainerListener[] findContainerListeners() { ContainerListener[] results = new ContainerListener[0]; return listeners.toArray(results); } /** * Process the specified Request, to produce the corresponding Response, * by invoking the first Valve in our pipeline (if any), or the basic * Valve otherwise. * * @param request Request to be processed * @param response Response to be produced * * @exception IllegalStateException if neither a pipeline or a basic * Valve have been configured for this Container * @exception IOException if an input/output error occurred while * processing * @exception ServletException if a ServletException was thrown * while processing this request */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { pipeline.getFirst().invoke(request, response); } /** * Remove an existing child Container from association with this parent * Container. * * @param child Existing child Container to be removed */ @Override public void removeChild(Container child) { if (child == null) { return; } synchronized(children) { if (children.get(child.getName()) == null) return; children.remove(child.getName()); } try { if (child.getState().isAvailable()) { child.stop(); } } catch (LifecycleException e) { log.error("ContainerBase.removeChild: stop: ", e); } fireContainerEvent(REMOVE_CHILD_EVENT, child); try { // child.destroy() may have already been called which would have // triggered this call. If that is the case, no need to destroy the // child again. if (!LifecycleState.DESTROYING.equals(child.getState())) { child.destroy(); } } catch (LifecycleException e) { log.error("ContainerBase.removeChild: destroy: ", e); } } /** * Remove a container event listener from this component. * * @param listener The listener to remove */ @Override public void removeContainerListener(ContainerListener listener) { listeners.remove(listener); } /** * Remove a property change listener from this component. * * @param listener The listener to remove */ @Override public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } @Override protected void initInternal() throws LifecycleException { BlockingQueue startStopQueue = new LinkedBlockingQueue(); startStopExecutor = new ThreadPoolExecutor( getStartStopThreadsInternal(), getStartStopThreadsInternal(), 10, TimeUnit.SECONDS, startStopQueue, new StartStopThreadFactory(getName() + "-startStop-")); startStopExecutor.allowCoreThreadTimeOut(true); super.initInternal(); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Start our subordinate components, if any if ((loader != null) && (loader instanceof Lifecycle)) ((Lifecycle) loader).start(); logger = null; getLogger(); if ((manager != null) && (manager instanceof Lifecycle)) ((Lifecycle) manager).start(); if ((cluster != null) && (cluster instanceof Lifecycle)) ((Lifecycle) cluster).start(); Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); if ((resources != null) && (resources instanceof Lifecycle)) ((Lifecycle) resources).start(); // Start our child containers, if any Container children[] = findChildren(); List> results = new ArrayList>(); for (int i = 0; i < children.length; i++) { results.add(startStopExecutor.submit(new StartChild(children[i]))); } boolean fail = false; for (Future result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString("containerBase.threadedStartFailed"), e); fail = true; } } if (fail) { throw new LifecycleException( sm.getString("containerBase.threadedStartFailed")); } // Start the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start(); setState(LifecycleState.STARTING); // Start our thread threadStart(); } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { // Stop our thread threadStop(); setState(LifecycleState.STOPPING); // Stop the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle && ((Lifecycle) pipeline).getState().isAvailable()) { ((Lifecycle) pipeline).stop(); } // Stop our child containers, if any Container children[] = findChildren(); List> results = new ArrayList>(); for (int i = 0; i < children.length; i++) { results.add(startStopExecutor.submit(new StopChild(children[i]))); } boolean fail = false; for (Future result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString("containerBase.threadedStopFailed"), e); fail = true; } } if (fail) { throw new LifecycleException( sm.getString("containerBase.threadedStopFailed")); } // Stop our subordinate components, if any if ((resources != null) && (resources instanceof Lifecycle)) { ((Lifecycle) resources).stop(); } Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) { ((Lifecycle) realm).stop(); } if ((cluster != null) && (cluster instanceof Lifecycle)) { ((Lifecycle) cluster).stop(); } if ((manager != null) && (manager instanceof Lifecycle) && ((Lifecycle) manager).getState().isAvailable() ) { ((Lifecycle) manager).stop(); } if ((loader != null) && (loader instanceof Lifecycle)) { ((Lifecycle) loader).stop(); } } @Override protected void destroyInternal() throws LifecycleException { if ((manager != null) && (manager instanceof Lifecycle)) { ((Lifecycle) manager).destroy(); } Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) { ((Lifecycle) realm).destroy(); } if ((cluster != null) && (cluster instanceof Lifecycle)) { ((Lifecycle) cluster).destroy(); } if ((loader != null) && (loader instanceof Lifecycle)) { ((Lifecycle) loader).destroy(); } // Stop the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).destroy(); } // Remove children now this container is being destroyed for (Container child : findChildren()) { removeChild(child); } // Required if the child is destroyed directly. if (parent != null) { parent.removeChild(this); } // If init fails, this may be null if (startStopExecutor != null) { startStopExecutor.shutdownNow(); } super.destroyInternal(); } /** * Check this container for an access log and if none is found, look to the * parent. If there is no parent and still none is found, use the NoOp * access log. */ @Override public void logAccess(Request request, Response response, long time, boolean useDefault) { boolean logged = false; if (getAccessLog() != null) { getAccessLog().log(request, response, time); logged = true; } if (getParent() != null) { // No need to use default logger once request/response has been logged // once getParent().logAccess(request, response, time, (useDefault && !logged)); } } @Override public AccessLog getAccessLog() { if (accessLogScanComplete) { return accessLog; } AccessLogAdapter adapter = null; Valve valves[] = getPipeline().getValves(); for (Valve valve : valves) { if (valve instanceof AccessLog) { if (adapter == null) { adapter = new AccessLogAdapter((AccessLog) valve); } else { adapter.add((AccessLog) valve); } } } if (adapter != null) { accessLog = adapter; } accessLogScanComplete = true; return accessLog; } // ------------------------------------------------------- Pipeline Methods /** * Convenience method, intended for use by the digester to simplify the * process of adding Valves to containers. See * {@link Pipeline#addValve(Valve)} for full details. Components other than * the digester should use {@link #getPipeline()}.{@link #addValve(Valve)} in case a * future implementation provides an alternative method for the digester to * use. * * @param valve Valve to be added * * @exception IllegalArgumentException if this Container refused to * accept the specified Valve * @exception IllegalArgumentException if the specified Valve refuses to be * associated with this Container * @exception IllegalStateException if the specified Valve is already * associated with a different Container */ public synchronized void addValve(Valve valve) { pipeline.addValve(valve); } /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ @Override public void backgroundProcess() { if (!getState().isAvailable()) return; if (cluster != null) { try { cluster.backgroundProcess(); } catch (Exception e) { log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e); } } if (loader != null) { try { loader.backgroundProcess(); } catch (Exception e) { log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e); } } if (manager != null) { try { manager.backgroundProcess(); } catch (Exception e) { log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e); } } Realm realm = getRealmInternal(); if (realm != null) { try { realm.backgroundProcess(); } catch (Exception e) { log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e); } } Valve current = pipeline.getFirst(); while (current != null) { try { current.backgroundProcess(); } catch (Exception e) { log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e); } current = current.getNext(); } fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); } // ------------------------------------------------------ Protected Methods /** * Notify all container event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param data Event data */ @Override public void fireContainerEvent(String type, Object data) { if (listeners.size() < 1) return; ContainerEvent event = new ContainerEvent(this, type, data); // Note for each uses an iterator internally so this is safe for (ContainerListener listener : listeners) { listener.containerEvent(event); } } /** * Return the abbreviated name of this container for logging messages */ protected String logName() { if (logName != null) { return logName; } String loggerName = null; Container current = this; while (current != null) { String name = current.getName(); if ((name == null) || (name.equals(""))) { name = "/"; } else if (name.startsWith("##")) { name = "/" + name; } loggerName = "[" + name + "]" + ((loggerName != null) ? ("." + loggerName) : ""); current = current.getParent(); } logName = ContainerBase.class.getName() + "." + loggerName; return logName; } // -------------------- JMX and Registration -------------------- @Override protected String getDomainInternal() { return MBeanUtils.getDomain(this); } public ObjectName[] getChildren() { ObjectName result[]=new ObjectName[children.size()]; Iterator it=children.values().iterator(); int i=0; while( it.hasNext() ) { Object next=it.next(); if( next instanceof ContainerBase ) { result[i++]=((ContainerBase)next).getObjectName(); } } return result; } // -------------------- Background Thread -------------------- /** * Start the background thread that will periodically check for * session timeouts. */ protected void threadStart() { if (thread != null) return; if (backgroundProcessorDelay <= 0) return; threadDone = false; String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; thread = new Thread(new ContainerBackgroundProcessor(), threadName); thread.setDaemon(true); thread.start(); } /** * Stop the background thread that is periodically checking for * session timeouts. */ protected void threadStop() { if (thread == null) return; threadDone = true; thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { // Ignore } thread = null; } // -------------------------------------- ContainerExecuteDelay Inner Class /** * Private thread class to invoke the backgroundProcess method * of this container and its children after a fixed delay. */ protected class ContainerBackgroundProcessor implements Runnable { @Override public void run() { while (!threadDone) { try { Thread.sleep(backgroundProcessorDelay * 1000L); } catch (InterruptedException e) { // Ignore } if (!threadDone) { Container parent = (Container) getMappingObject(); ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (parent.getLoader() != null) { cl = parent.getLoader().getClassLoader(); } processChildren(parent, cl); } } } protected void processChildren(Container container, ClassLoader cl) { try { if (container.getLoader() != null) { Thread.currentThread().setContextClassLoader (container.getLoader().getClassLoader()); } container.backgroundProcess(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("Exception invoking periodic operation: ", t); } finally { Thread.currentThread().setContextClassLoader(cl); } Container[] children = container.findChildren(); for (int i = 0; i < children.length; i++) { if (children[i].getBackgroundProcessorDelay() <= 0) { processChildren(children[i], cl); } } } } // ----------------------------- Inner classes used with start/stop Executor private static class StartChild implements Callable { private Container child; public StartChild(Container child) { this.child = child; } @Override public Void call() throws LifecycleException { child.start(); return null; } } private static class StopChild implements Callable { private Container child; public StopChild(Container child) { this.child = child; } @Override public Void call() throws LifecycleException { if (child.getState().isAvailable()) { child.stop(); } return null; } } private static class StartStopThreadFactory implements ThreadFactory { private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; public StartStopThreadFactory(String namePrefix) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.namePrefix = namePrefix; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(group, r, namePrefix + threadNumber.getAndIncrement()); thread.setDaemon(true); return thread; } } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationSessionCookieConfig.java0000644000175100017510000002001712271471332027534 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import javax.servlet.SessionCookieConfig; import javax.servlet.http.Cookie; import org.apache.catalina.Context; import org.apache.catalina.LifecycleState; import org.apache.catalina.util.SessionConfig; import org.apache.tomcat.util.res.StringManager; public class ApplicationSessionCookieConfig implements SessionCookieConfig { /** * The string manager for this package. */ private static final StringManager sm = StringManager .getManager(Constants.Package); private boolean httpOnly; private boolean secure; private int maxAge = -1; private String comment; private String domain; private String name; private String path; private StandardContext context; public ApplicationSessionCookieConfig(StandardContext context) { this.context = context; } @Override public String getComment() { return comment; } @Override public String getDomain() { return domain; } @Override public int getMaxAge() { return maxAge; } @Override public String getName() { return name; } @Override public String getPath() { return path; } @Override public boolean isHttpOnly() { return httpOnly; } @Override public boolean isSecure() { return secure; } @Override public void setComment(String comment) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationSessionCookieConfig.ise", "comment", context.getPath())); } this.comment = comment; } @Override public void setDomain(String domain) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationSessionCookieConfig.ise", "domain name", context.getPath())); } this.domain = domain; } @Override public void setHttpOnly(boolean httpOnly) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationSessionCookieConfig.ise", "HttpOnly", context.getPath())); } this.httpOnly = httpOnly; } @Override public void setMaxAge(int maxAge) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationSessionCookieConfig.ise", "max age", context.getPath())); } this.maxAge = maxAge; } @Override public void setName(String name) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationSessionCookieConfig.ise", "name", context.getPath())); } this.name = name; } @Override public void setPath(String path) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationSessionCookieConfig.ise", "path", context.getPath())); } this.path = path; } @Override public void setSecure(boolean secure) { if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationSessionCookieConfig.ise", "secure", context.getPath())); } this.secure = secure; } /** * Creates a new session cookie for the given session ID * * @param context The Context for the web application * @param sessionId The ID of the session for which the cookie will be * created * @param secure Should session cookie be configured as secure */ public static Cookie createSessionCookie(Context context, String sessionId, boolean secure) { SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig(); // NOTE: The priority order for session cookie configuration is: // 1. Context level configuration // 2. Values from SessionCookieConfig // 3. Defaults Cookie cookie = new Cookie( SessionConfig.getSessionCookieName(context), sessionId); // Just apply the defaults. cookie.setMaxAge(scc.getMaxAge()); cookie.setComment(scc.getComment()); if (context.getSessionCookieDomain() == null) { // Avoid possible NPE if (scc.getDomain() != null) { cookie.setDomain(scc.getDomain()); } } else { cookie.setDomain(context.getSessionCookieDomain()); } // Always set secure if the request is secure if (scc.isSecure() || secure) { cookie.setSecure(true); } // Always set httpOnly if the context is configured for that if (scc.isHttpOnly() || context.getUseHttpOnly()) { cookie.setHttpOnly(true); } String contextPath = context.getSessionCookiePath(); if (contextPath == null || contextPath.length() == 0) { contextPath = scc.getPath(); } if (contextPath == null || contextPath.length() == 0) { contextPath = context.getEncodedPath(); } if (context.getSessionCookiePathUsesTrailingSlash()) { // Handle special case of ROOT context where cookies require a path of // '/' but the servlet spec uses an empty string // Also ensure the cookies for a context with a path of /foo don't get // sent for requests with a path of /foobar if (!contextPath.endsWith("/")) { contextPath = contextPath + "/"; } } else { // Only handle special case of ROOT context where cookies require a // path of '/' but the servlet spec uses an empty string if (contextPath.length() == 0) { contextPath = "/"; } } cookie.setPath(contextPath); return cookie; } /** * Determine the name to use for the session cookie for the provided * context. * @param context * * @deprecated Replaced by * {@link SessionConfig#getSessionCookieName(Context)}. This * will be removed in Tomcat 8.0.x. */ @Deprecated public static String getSessionCookieName(Context context) { return SessionConfig.getSessionCookieName(context); } /** * Determine the name to use for the session cookie for the provided * context. * @param context * * @deprecated Replaced by * {@link SessionConfig#getSessionUriParamName(Context)}. This * will be removed in Tomcat 8.0.x. */ @Deprecated public static String getSessionUriParamName(Context context) { return SessionConfig.getSessionUriParamName(context); } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardService.java0000644000175100017510000004307612271471332024540 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import javax.management.ObjectName; import org.apache.catalina.Container; import org.apache.catalina.Engine; import org.apache.catalina.Executor; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.connector.Connector; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Standard implementation of the Service interface. The * associated Container is generally an instance of Engine, but this is * not required. * * @author Craig R. McClanahan */ public class StandardService extends LifecycleMBeanBase implements Service { private static final Log log = LogFactory.getLog(StandardService.class); // ----------------------------------------------------- Instance Variables /** * Descriptive information about this component implementation. */ private static final String info = "org.apache.catalina.core.StandardService/1.0"; /** * The name of this service. */ private String name = null; /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The Server that owns this Service, if any. */ private Server server = null; /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); /** * The set of Connectors associated with this Service. */ protected Connector connectors[] = new Connector[0]; /** * */ protected ArrayList executors = new ArrayList(); /** * The Container associated with this Service. (In the case of the * org.apache.catalina.startup.Embedded subclass, this holds the most * recently added Engine.) */ protected Container container = null; private ClassLoader parentClassLoader = null; // ------------------------------------------------------------- Properties /** * Return the Container that handles requests for all * Connectors associated with this Service. */ @Override public Container getContainer() { return (this.container); } /** * Set the Container that handles requests for all * Connectors associated with this Service. * * @param container The new Container */ @Override public void setContainer(Container container) { Container oldContainer = this.container; if ((oldContainer != null) && (oldContainer instanceof Engine)) ((Engine) oldContainer).setService(null); this.container = container; if ((this.container != null) && (this.container instanceof Engine)) ((Engine) this.container).setService(this); if (getState().isAvailable() && (this.container != null)) { try { this.container.start(); } catch (LifecycleException e) { // Ignore } } if (getState().isAvailable() && (oldContainer != null)) { try { oldContainer.stop(); } catch (LifecycleException e) { // Ignore } } // Report this property change to interested listeners support.firePropertyChange("container", oldContainer, this.container); } /** * Return descriptive information about this Service implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return the name of this Service. */ @Override public String getName() { return (this.name); } /** * Set the name of this Service. * * @param name The new service name */ @Override public void setName(String name) { this.name = name; } /** * Return the Server with which we are associated (if any). */ @Override public Server getServer() { return (this.server); } /** * Set the Server with which we are associated (if any). * * @param server The server that owns this Service */ @Override public void setServer(Server server) { this.server = server; } // --------------------------------------------------------- Public Methods /** * Add a new Connector to the set of defined Connectors, and associate it * with this Service's Container. * * @param connector The Connector to be added */ @Override public void addConnector(Connector connector) { synchronized (connectors) { connector.setService(this); Connector results[] = new Connector[connectors.length + 1]; System.arraycopy(connectors, 0, results, 0, connectors.length); results[connectors.length] = connector; connectors = results; if (getState().isAvailable()) { try { connector.start(); } catch (LifecycleException e) { log.error(sm.getString( "standardService.connector.startFailed", connector), e); } } // Report this property change to interested listeners support.firePropertyChange("connector", null, connector); } } public ObjectName[] getConnectorNames() { ObjectName results[] = new ObjectName[connectors.length]; for (int i=0; iStandardWrapper object. * * @author Remy Maucharat */ public final class StandardWrapperFacade implements ServletConfig { // ----------------------------------------------------------- Constructors /** * Create a new facade around a StandardWrapper. */ public StandardWrapperFacade(StandardWrapper config) { super(); this.config = config; } // ----------------------------------------------------- Instance Variables /** * Wrapped config. */ private ServletConfig config = null; /** * Wrapped context (facade). */ private ServletContext context = null; // -------------------------------------------------- ServletConfig Methods @Override public String getServletName() { return config.getServletName(); } @Override public ServletContext getServletContext() { if (context == null) { context = config.getServletContext(); if ((context != null) && (context instanceof ApplicationContext)) context = ((ApplicationContext) context).getFacade(); } return (context); } @Override public String getInitParameter(String name) { return config.getInitParameter(name); } @Override public Enumeration getInitParameterNames() { return config.getInitParameterNames(); } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardContext.java0000644000175100017510000063655012274431005024565 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.EventListener; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicLong; import javax.management.ListenerNotFoundException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationEmitter; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.FilterRegistration; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.ServletRegistration.Dynamic; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.ServletSecurityElement; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; import org.apache.catalina.Authenticator; import org.apache.catalina.Container; import org.apache.catalina.ContainerListener; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.InstanceListener; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.LifecycleState; import org.apache.catalina.Loader; import org.apache.catalina.Manager; import org.apache.catalina.Pipeline; import org.apache.catalina.Realm; import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.catalina.deploy.ApplicationListener; import org.apache.catalina.deploy.ApplicationParameter; import org.apache.catalina.deploy.ErrorPage; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.deploy.Injectable; import org.apache.catalina.deploy.InjectionTarget; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.deploy.MessageDestination; import org.apache.catalina.deploy.MessageDestinationRef; import org.apache.catalina.deploy.NamingResources; import org.apache.catalina.deploy.SecurityCollection; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.session.StandardManager; import org.apache.catalina.startup.TldConfig; import org.apache.catalina.util.CharsetMapper; import org.apache.catalina.util.ContextName; import org.apache.catalina.util.ExtensionValidator; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.URLEncoder; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.naming.ContextBindings; import org.apache.naming.resources.BaseDirContext; import org.apache.naming.resources.DirContextURLStreamHandler; import org.apache.naming.resources.FileDirContext; import org.apache.naming.resources.ProxyDirContext; import org.apache.naming.resources.WARDirContext; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.JarScanner; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.descriptor.XmlIdentifiers; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.scan.StandardJarScanner; /** * Standard implementation of the Context interface. Each * child container must be a Wrapper implementation to process the * requests directed to a particular servlet. * * @author Craig R. McClanahan * @author Remy Maucherat */ public class StandardContext extends ContainerBase implements Context, NotificationEmitter { private static final Log log = LogFactory.getLog(StandardContext.class); // ----------------------------------------------------------- Constructors /** * Create a new StandardContext component with the default basic Valve. */ public StandardContext() { super(); pipeline.setBasic(new StandardContextValve()); broadcaster = new NotificationBroadcasterSupport(); // Set defaults if (!Globals.STRICT_SERVLET_COMPLIANCE) { // Strict servlet compliance requires all extension mapped servlets // to be checked against welcome files resourceOnlyServlets.add("jsp"); } } // ----------------------------------------------------- Class Variables /** * The descriptive information string for this implementation. */ private static final String info = "org.apache.catalina.core.StandardContext/1.0"; /** * Array containing the safe characters set. */ protected static URLEncoder urlEncoder; /** * GMT timezone - all HTTP dates are on GMT */ static { urlEncoder = new URLEncoder(); urlEncoder.addSafeCharacter('~'); urlEncoder.addSafeCharacter('-'); urlEncoder.addSafeCharacter('_'); urlEncoder.addSafeCharacter('.'); urlEncoder.addSafeCharacter('*'); urlEncoder.addSafeCharacter('/'); } // ----------------------------------------------------- Instance Variables /** * Allow multipart/form-data requests to be parsed even when the * target servlet doesn't specify @MultipartConfig or have a * <multipart-config> element. */ protected boolean allowCasualMultipartParsing = false; /** * Control whether remaining request data will be read * (swallowed) even if the request violates a data size constraint. */ private boolean swallowAbortedUploads = true; /** * The alternate deployment descriptor name. */ private String altDDName = null; /** * Lifecycle provider. */ private InstanceManager instanceManager = null; /** * Associated host name. */ private String hostName; /** * The antiJARLocking flag for this Context. */ private boolean antiJARLocking = false; /** * The antiResourceLocking flag for this Context. */ private boolean antiResourceLocking = false; /** * The set of application listener class names configured for this * application, in the order they were encountered in the resulting merged * web.xml file. */ private ApplicationListener applicationListeners[] = new ApplicationListener[0]; private final Object applicationListenersLock = new Object(); /** * The set of instantiated application event listener objects. Note that * SCIs and other code may use the pluggability APIs to add listener * instances directly to this list before the application starts. */ private Object applicationEventListenersObjects[] = new Object[0]; /** * The set of instantiated application lifecycle listener objects. Note that * SCIs and other code may use the pluggability APIs to add listener * instances directly to this list before the application starts. */ private Object applicationLifecycleListenersObjects[] = new Object[0]; /** * The ordered set of ServletContainerInitializers for this web application. */ private Map>> initializers = new LinkedHashMap>>(); /** * The set of application parameters defined for this application. */ private ApplicationParameter applicationParameters[] = new ApplicationParameter[0]; private final Object applicationParametersLock = new Object(); /** * The broadcaster that sends j2ee notifications. */ private NotificationBroadcasterSupport broadcaster = null; /** * The Locale to character set mapper for this application. */ private CharsetMapper charsetMapper = null; /** * The Java class name of the CharsetMapper class to be created. */ private String charsetMapperClass = "org.apache.catalina.util.CharsetMapper"; /** * The URL of the XML descriptor for this context. */ private URL configFile = null; /** * The "correctly configured" flag for this Context. */ private boolean configured = false; /** * The security constraints for this web application. */ private volatile SecurityConstraint constraints[] = new SecurityConstraint[0]; private final Object constraintsLock = new Object(); /** * The ServletContext implementation associated with this Context. */ protected ApplicationContext context = null; /** * Compiler classpath to use. */ private String compilerClasspath = null; /** * Should we attempt to use cookies for session id communication? */ private boolean cookies = true; /** * Should we allow the ServletContext.getContext() method * to access the context of other web applications in this server? */ private boolean crossContext = false; /** * Encoded path. */ private String encodedPath = null; /** * Unencoded path for this web application. */ private String path = null; /** * The "follow standard delegation model" flag that will be used to * configure our ClassLoader. */ private boolean delegate = false; /** * The display name of this web application. */ private String displayName = null; /** * Override the default context xml location. */ private String defaultContextXml; /** * Override the default web xml location. */ private String defaultWebXml; /** * The distributable flag for this web application. */ private boolean distributable = false; /** * The document root for this web application. */ private String docBase = null; /** * The exception pages for this web application, keyed by fully qualified * class name of the Java exception. */ private HashMap exceptionPages = new HashMap(); /** * The set of filter configurations (and associated filter instances) we * have initialized, keyed by filter name. */ private HashMap filterConfigs = new HashMap(); /** * The set of filter definitions for this application, keyed by * filter name. */ private HashMap filterDefs = new HashMap(); /** * The set of filter mappings for this application, in the order * they were defined in the deployment descriptor with additional mappings * added via the {@link ServletContext} possibly both before and after those * defined in the deployment descriptor. */ private final ContextFilterMaps filterMaps = new ContextFilterMaps(); /** * Ignore annotations. */ private boolean ignoreAnnotations = false; /** * The set of classnames of InstanceListeners that will be added * to each newly created Wrapper by createWrapper(). */ private String instanceListeners[] = new String[0]; private final Object instanceListenersLock = new Object(); /** * The login configuration descriptor for this web application. */ private LoginConfig loginConfig = null; /** * The mapper associated with this context. */ private org.apache.tomcat.util.http.mapper.Mapper mapper = new org.apache.tomcat.util.http.mapper.Mapper(); /** * The naming context listener for this web application. */ private NamingContextListener namingContextListener = null; /** * The naming resources for this web application. */ private NamingResources namingResources = null; /** * The message destinations for this web application. */ private HashMap messageDestinations = new HashMap(); /** * The MIME mappings for this web application, keyed by extension. */ private HashMap mimeMappings = new HashMap(); /** * Special case: error page for status 200. */ private ErrorPage okErrorPage = null; /** * The context initialization parameters for this web application, * keyed by name. */ private HashMap parameters = new HashMap(); /** * The request processing pause flag (while reloading occurs) */ private boolean paused = false; /** * The public identifier of the DTD for the web application deployment * descriptor version we are currently parsing. This is used to support * relaxed validation rules when processing version 2.2 web.xml files. */ private String publicId = null; /** * The reloadable flag for this web application. */ private boolean reloadable = false; /** * Unpack WAR property. */ private boolean unpackWAR = true; /** * Context level override for default {@link StandardHost#isCopyXML()}. */ private boolean copyXML = false; /** * The default context override flag for this web application. */ private boolean override = false; /** * The original document root for this web application. */ private String originalDocBase = null; /** * The privileged flag for this web application. */ private boolean privileged = false; /** * Should the next call to addWelcomeFile() cause replacement * of any existing welcome files? This will be set before processing the * web application's deployment descriptor, so that application specified * choices replace, rather than append to, those defined * in the global descriptor. */ private boolean replaceWelcomeFiles = false; /** * The security role mappings for this application, keyed by role * name (as used within the application). */ private HashMap roleMappings = new HashMap(); /** * The security roles for this application, keyed by role name. */ private String securityRoles[] = new String[0]; private final Object securityRolesLock = new Object(); /** * The servlet mappings for this web application, keyed by * matching pattern. */ private HashMap servletMappings = new HashMap(); private final Object servletMappingsLock = new Object(); /** * The session timeout (in minutes) for this web application. */ private int sessionTimeout = 30; /** * The notification sequence number. */ private AtomicLong sequenceNumber = new AtomicLong(0); /** * The status code error pages for this web application, keyed by * HTTP status code (as an Integer). Note status code zero is used for the * default error page. */ private HashMap statusPages = new HashMap(); /** * Set flag to true to cause the system.out and system.err to be redirected * to the logger when executing a servlet. */ private boolean swallowOutput = false; /** * Amount of ms that the container will wait for servlets to unload. */ private long unloadDelay = 2000; /** * The watched resources for this application. */ private String watchedResources[] = new String[0]; private final Object watchedResourcesLock = new Object(); /** * The welcome files for this application. */ private String welcomeFiles[] = new String[0]; private final Object welcomeFilesLock = new Object(); /** * The set of classnames of LifecycleListeners that will be added * to each newly created Wrapper by createWrapper(). */ private String wrapperLifecycles[] = new String[0]; private final Object wrapperLifecyclesLock = new Object(); /** * The set of classnames of ContainerListeners that will be added * to each newly created Wrapper by createWrapper(). */ private String wrapperListeners[] = new String[0]; private final Object wrapperListenersLock = new Object(); /** * The pathname to the work directory for this context (relative to * the server's home if not absolute). */ private String workDir = null; /** * Java class name of the Wrapper class implementation we use. */ private String wrapperClassName = StandardWrapper.class.getName(); private Class wrapperClass = null; /** * JNDI use flag. */ private boolean useNaming = true; /** * Filesystem based flag. */ private boolean filesystemBased = false; /** * Name of the associated naming context. */ private String namingContextName = null; /** * Caching allowed flag. */ private boolean cachingAllowed = true; /** * Allow linking. */ protected boolean allowLinking = false; /** * Cache max size in KB. */ protected int cacheMaxSize = 10240; // 10 MB /** * Attribute used to turn on/off the use of external entities. */ private boolean xmlBlockExternal = true; /** * Cache object max size in KB. */ protected int cacheObjectMaxSize = 512; // 512K /** * Cache TTL in ms. */ protected int cacheTTL = 5000; /** * List of resource aliases. */ private String aliases = null; /** * Non proxied resources. */ private DirContext webappResources = null; private long startupTime; private long startTime; private long tldScanTime; /** * Name of the engine. If null, the domain is used. */ private String j2EEApplication="none"; private String j2EEServer="none"; /** * Attribute value used to turn on/off XML validation for web.xml and * web-fragment.xml files. */ private boolean webXmlValidation = Globals.STRICT_SERVLET_COMPLIANCE; /** * Attribute value used to turn on/off XML namespace validation */ private boolean webXmlNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE; /** * Attribute value used to turn on/off TLD processing */ private boolean processTlds = true; /** * Attribute value used to turn on/off XML validation */ private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE; /** * Should we save the configuration. */ private boolean saveConfig = true; /** * The name to use for session cookies. null indicates that * the name is controlled by the application. */ private String sessionCookieName; /** * The flag that indicates that session cookies should use HttpOnly */ private boolean useHttpOnly = true; /** * The domain to use for session cookies. null indicates that * the domain is controlled by the application. */ private String sessionCookieDomain; /** * The path to use for session cookies. null indicates that * the path is controlled by the application. */ private String sessionCookiePath; /** * Is a / added to the end of the session cookie path to ensure browsers, * particularly IE, don't send a session cookie for context /foo with * requests intended for context /foobar. */ private boolean sessionCookiePathUsesTrailingSlash = true; /** * The Jar scanner to use to search for Jars that might contain * configuration information such as TLDs or web-fragment.xml files. */ private JarScanner jarScanner = null; /** * Should Tomcat attempt to null out any static or final fields from loaded * classes when a web application is stopped as a work around for apparent * garbage collection bugs and application coding errors? There have been * some issues reported with log4j when this option is true. Applications * without memory leaks using recent JVMs should operate correctly with this * option set to false. If not specified, the default value of * false will be used. */ private boolean clearReferencesStatic = false; /** * Should Tomcat attempt to terminate threads that have been started by the * web application? Stopping threads is performed via the deprecated (for * good reason) Thread.stop() method and is likely to result in * instability. As such, enabling this should be viewed as an option of last * resort in a development environment and is not recommended in a * production environment. If not specified, the default value of * false will be used. */ private boolean clearReferencesStopThreads = false; /** * Should Tomcat attempt to terminate any {@link java.util.TimerThread}s * that have been started by the web application? If not specified, the * default value of false will be used. */ private boolean clearReferencesStopTimerThreads = false; /** * If an HttpClient keep-alive timer thread has been started by this web * application and is still running, should Tomcat change the context class * loader from the current {@link WebappClassLoader} to * {@link WebappClassLoader#parent} to prevent a memory leak? Note that the * keep-alive timer thread will stop on its own once the keep-alives all * expire however, on a busy system that might not happen for some time. */ private boolean clearReferencesHttpClientKeepAliveThread = true; /** * Should Tomcat renew the threads of the thread pool when the application * is stopped to avoid memory leaks because of uncleaned ThreadLocal * variables. This also requires that the threadRenewalDelay property of the * StandardThreadExecutor of ThreadPoolExecutor be set to a positive value. */ private boolean renewThreadsWhenStoppingContext = true; /** * Should the effective web.xml be logged when the context starts? */ private boolean logEffectiveWebXml = false; private int effectiveMajorVersion = 3; private int effectiveMinorVersion = 0; private JspConfigDescriptor jspConfigDescriptor = new ApplicationJspConfigDescriptor(); private Set resourceOnlyServlets = new HashSet(); private String webappVersion = ""; private boolean addWebinfClassesResources = false; private boolean fireRequestListenersOnForwards = false; /** * Servlets created via {@link ApplicationContext#createServlet(Class)} for * tracking purposes. */ private Set createdServlets = new HashSet(); private boolean preemptiveAuthentication = false; private boolean sendRedirectBody = false; private boolean jndiExceptionOnFailedWrite = true; private Map postConstructMethods = new HashMap(); private Map preDestroyMethods = new HashMap(); private String containerSciFilter; // ----------------------------------------------------- Context Properties @Override public void setContainerSciFilter(String containerSciFilter) { this.containerSciFilter = containerSciFilter; } @Override public String getContainerSciFilter() { return containerSciFilter; } @Override public boolean getSendRedirectBody() { return sendRedirectBody; } @Override public void setSendRedirectBody(boolean sendRedirectBody) { this.sendRedirectBody = sendRedirectBody; } @Override public boolean getPreemptiveAuthentication() { return preemptiveAuthentication; } @Override public void setPreemptiveAuthentication(boolean preemptiveAuthentication) { this.preemptiveAuthentication = preemptiveAuthentication; } @Override public void setFireRequestListenersOnForwards(boolean enable) { fireRequestListenersOnForwards = enable; } @Override public boolean getFireRequestListenersOnForwards() { return fireRequestListenersOnForwards; } public void setAddWebinfClassesResources( boolean addWebinfClassesResources) { this.addWebinfClassesResources = addWebinfClassesResources; } public boolean getAddWebinfClassesResources() { return addWebinfClassesResources; } @Override public void setWebappVersion(String webappVersion) { if (null == webappVersion) { this.webappVersion = ""; } else { this.webappVersion = webappVersion; } } @Override public String getWebappVersion() { return webappVersion; } @Override public String getBaseName() { return new ContextName(path, webappVersion).getBaseName(); } @Override public String getResourceOnlyServlets() { StringBuilder result = new StringBuilder(); boolean first = true; for (String servletName : resourceOnlyServlets) { if (!first) { result.append(','); } result.append(servletName); } return result.toString(); } @Override public void setResourceOnlyServlets(String resourceOnlyServlets) { this.resourceOnlyServlets.clear(); if (resourceOnlyServlets == null) { return; } for (String servletName : resourceOnlyServlets.split(",")) { servletName = servletName.trim(); if (servletName.length()>0) { this.resourceOnlyServlets.add(servletName); } } } @Override public boolean isResourceOnlyServlet(String servletName) { return resourceOnlyServlets.contains(servletName); } @Override public int getEffectiveMajorVersion() { return effectiveMajorVersion; } @Override public void setEffectiveMajorVersion(int effectiveMajorVersion) { this.effectiveMajorVersion = effectiveMajorVersion; } @Override public int getEffectiveMinorVersion() { return effectiveMinorVersion; } @Override public void setEffectiveMinorVersion(int effectiveMinorVersion) { this.effectiveMinorVersion = effectiveMinorVersion; } @Override public void setLogEffectiveWebXml(boolean logEffectiveWebXml) { this.logEffectiveWebXml = logEffectiveWebXml; } @Override public boolean getLogEffectiveWebXml() { return logEffectiveWebXml; } @Override public Authenticator getAuthenticator() { if (this instanceof Authenticator) return (Authenticator) this; Pipeline pipeline = getPipeline(); if (pipeline != null) { Valve basic = pipeline.getBasic(); if ((basic != null) && (basic instanceof Authenticator)) return (Authenticator) basic; Valve valves[] = pipeline.getValves(); for (int i = 0; i < valves.length; i++) { if (valves[i] instanceof Authenticator) return (Authenticator) valves[i]; } } return null; } @Override public JarScanner getJarScanner() { if (jarScanner == null) { jarScanner = new StandardJarScanner(); } return jarScanner; } @Override public void setJarScanner(JarScanner jarScanner) { this.jarScanner = jarScanner; } @Override public InstanceManager getInstanceManager() { return instanceManager; } @Override public void setInstanceManager(InstanceManager instanceManager) { this.instanceManager = instanceManager; } @Override public String getEncodedPath() { return encodedPath; } /** * Is caching allowed ? */ public boolean isCachingAllowed() { return cachingAllowed; } /** * Set caching allowed flag. */ public void setCachingAllowed(boolean cachingAllowed) { this.cachingAllowed = cachingAllowed; } /** * Set allow linking. */ public void setAllowLinking(boolean allowLinking) { this.allowLinking = allowLinking; } /** * Is linking allowed. */ public boolean isAllowLinking() { return allowLinking; } /** * Set to true to allow requests mapped to servlets that * do not explicitly declare @MultipartConfig or have * <multipart-config> specified in web.xml to parse * multipart/form-data requests. * * @param allowCasualMultipartParsing true to allow such * casual parsing, false otherwise. */ @Override public void setAllowCasualMultipartParsing( boolean allowCasualMultipartParsing) { this.allowCasualMultipartParsing = allowCasualMultipartParsing; } /** * Returns true if requests mapped to servlets without * "multipart config" to parse multipart/form-data requests anyway. * * @return true if requests mapped to servlets without * "multipart config" to parse multipart/form-data requests, * false otherwise. */ @Override public boolean getAllowCasualMultipartParsing() { return this.allowCasualMultipartParsing; } /** * Set to false to disable request data swallowing * after an upload was aborted due to size constraints. * * @param swallowAbortedUploads false to disable * swallowing, true otherwise (default). */ @Override public void setSwallowAbortedUploads(boolean swallowAbortedUploads) { this.swallowAbortedUploads = swallowAbortedUploads; } /** * Returns true if remaining request data will be read * (swallowed) even the request violates a data size constraint. * * @return true if data will be swallowed (default), * false otherwise. */ @Override public boolean getSwallowAbortedUploads() { return this.swallowAbortedUploads; } /** * Set cache TTL. */ public void setCacheTTL(int cacheTTL) { this.cacheTTL = cacheTTL; } /** * Get cache TTL. */ public int getCacheTTL() { return cacheTTL; } /** * Return the maximum size of the cache in KB. */ public int getCacheMaxSize() { return cacheMaxSize; } /** * Set the maximum size of the cache in KB. */ public void setCacheMaxSize(int cacheMaxSize) { this.cacheMaxSize = cacheMaxSize; } /** * Return the maximum size of objects to be cached in KB. */ public int getCacheObjectMaxSize() { return cacheObjectMaxSize; } /** * Set the maximum size of objects to be placed the cache in KB. */ public void setCacheObjectMaxSize(int cacheObjectMaxSize) { this.cacheObjectMaxSize = cacheObjectMaxSize; } /** * Return the list of resource aliases. */ public String getAliases() { return this.aliases; } /** * Add a URL for a JAR that contains static resources in a * META-INF/resources directory that should be included in the static * resources for this context. */ @Override public void addResourceJarUrl(URL url) { if (webappResources instanceof BaseDirContext) { ((BaseDirContext) webappResources).addResourcesJar(url); } else { log.error(sm.getString("standardContext.noResourceJar", url, getName())); } } /** * Add a URL for a JAR that contains static resources in a * META-INF/resources directory that should be included in the static * resources for this context. */ public void addResourcesDirContext(DirContext altDirContext) { if (webappResources instanceof BaseDirContext) { ((BaseDirContext) webappResources).addAltDirContext(altDirContext); } else { log.error(sm.getString("standardContext.noResourceJar", altDirContext, getName())); } } /** * Set the current alias configuration. The list of aliases should be of the * form "/aliasPath1=docBase1,/aliasPath2=docBase2" where aliasPathN must * include a leading '/' and docBaseN must be an absolute path to either a * .war file or a directory. */ public void setAliases(String aliases) { this.aliases = aliases; } /** * Add a ServletContainerInitializer instance to this web application. * * @param sci The instance to add * @param classes The classes in which the initializer expressed an * interest */ @Override public void addServletContainerInitializer( ServletContainerInitializer sci, Set> classes) { initializers.put(sci, classes); } /** * Return the "follow standard delegation model" flag used to configure * our ClassLoader. */ public boolean getDelegate() { return (this.delegate); } /** * Set the "follow standard delegation model" flag used to configure * our ClassLoader. * * @param delegate The new flag */ public void setDelegate(boolean delegate) { boolean oldDelegate = this.delegate; this.delegate = delegate; support.firePropertyChange("delegate", oldDelegate, this.delegate); } /** * Returns true if the internal naming support is used. */ public boolean isUseNaming() { return (useNaming); } /** * Enables or disables naming. */ public void setUseNaming(boolean useNaming) { this.useNaming = useNaming; } /** * Returns true if the resources associated with this context are * filesystem based. */ @Deprecated public boolean isFilesystemBased() { return (filesystemBased); } /** * Return the set of initialized application event listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @exception IllegalStateException if this method is called before * this application has started, or after it has been stopped */ @Override public Object[] getApplicationEventListeners() { return (applicationEventListenersObjects); } /** * Store the set of initialized application event listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @param listeners The set of instantiated listener objects. */ @Override public void setApplicationEventListeners(Object listeners[]) { applicationEventListenersObjects = listeners; } /** * Add a listener to the end of the list of initialized application event * listeners. */ public void addApplicationEventListener(Object listener) { int len = applicationEventListenersObjects.length; Object[] newListeners = Arrays.copyOf(applicationEventListenersObjects, len + 1); newListeners[len] = listener; applicationEventListenersObjects = newListeners; } /** * Return the set of initialized application lifecycle listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @exception IllegalStateException if this method is called before * this application has started, or after it has been stopped */ @Override public Object[] getApplicationLifecycleListeners() { return (applicationLifecycleListenersObjects); } /** * Store the set of initialized application lifecycle listener objects, * in the order they were specified in the web application deployment * descriptor, for this application. * * @param listeners The set of instantiated listener objects. */ @Override public void setApplicationLifecycleListeners(Object listeners[]) { applicationLifecycleListenersObjects = listeners; } /** * Add a listener to the end of the list of initialized application * lifecycle listeners. */ public void addApplicationLifecycleListener(Object listener) { int len = applicationLifecycleListenersObjects.length; Object[] newListeners = Arrays.copyOf( applicationLifecycleListenersObjects, len + 1); newListeners[len] = listener; applicationLifecycleListenersObjects = newListeners; } /** * Return the antiJARLocking flag for this Context. */ public boolean getAntiJARLocking() { return (this.antiJARLocking); } /** * Return the antiResourceLocking flag for this Context. */ public boolean getAntiResourceLocking() { return (this.antiResourceLocking); } /** * Set the antiJARLocking feature for this Context. * * @param antiJARLocking The new flag value */ public void setAntiJARLocking(boolean antiJARLocking) { boolean oldAntiJARLocking = this.antiJARLocking; this.antiJARLocking = antiJARLocking; support.firePropertyChange("antiJARLocking", oldAntiJARLocking, this.antiJARLocking); } /** * Set the antiResourceLocking feature for this Context. * * @param antiResourceLocking The new flag value */ public void setAntiResourceLocking(boolean antiResourceLocking) { boolean oldAntiResourceLocking = this.antiResourceLocking; this.antiResourceLocking = antiResourceLocking; support.firePropertyChange("antiResourceLocking", oldAntiResourceLocking, this.antiResourceLocking); } /** * Return the application available flag for this Context. */ @Override public boolean getAvailable() { // TODO Remove this method entirely return getState().isAvailable(); } /** * Return the Locale to character set mapper for this Context. */ @Override public CharsetMapper getCharsetMapper() { // Create a mapper the first time it is requested if (this.charsetMapper == null) { try { Class clazz = Class.forName(charsetMapperClass); this.charsetMapper = (CharsetMapper) clazz.newInstance(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); this.charsetMapper = new CharsetMapper(); } } return (this.charsetMapper); } /** * Set the Locale to character set mapper for this Context. * * @param mapper The new mapper */ @Override public void setCharsetMapper(CharsetMapper mapper) { CharsetMapper oldCharsetMapper = this.charsetMapper; this.charsetMapper = mapper; if( mapper != null ) this.charsetMapperClass= mapper.getClass().getName(); support.firePropertyChange("charsetMapper", oldCharsetMapper, this.charsetMapper); } @Override public String getCharset(Locale locale) { return getCharsetMapper().getCharset(locale); } /** * Return the URL of the XML descriptor for this context. */ @Override public URL getConfigFile() { return (this.configFile); } /** * Set the URL of the XML descriptor for this context. * * @param configFile The URL of the XML descriptor for this context. */ @Override public void setConfigFile(URL configFile) { this.configFile = configFile; } /** * Return the "correctly configured" flag for this Context. */ @Override public boolean getConfigured() { return (this.configured); } /** * Set the "correctly configured" flag for this Context. This can be * set to false by startup listeners that detect a fatal configuration * error to avoid the application from being made available. * * @param configured The new correctly configured flag */ @Override public void setConfigured(boolean configured) { boolean oldConfigured = this.configured; this.configured = configured; support.firePropertyChange("configured", oldConfigured, this.configured); } /** * Return the "use cookies for session ids" flag. */ @Override public boolean getCookies() { return (this.cookies); } /** * Set the "use cookies for session ids" flag. * * @param cookies The new flag */ @Override public void setCookies(boolean cookies) { boolean oldCookies = this.cookies; this.cookies = cookies; support.firePropertyChange("cookies", oldCookies, this.cookies); } /** * Gets the name to use for session cookies. Overrides any setting that * may be specified by the application. * * @return The value of the default session cookie name or null if not * specified */ @Override public String getSessionCookieName() { return sessionCookieName; } /** * Sets the name to use for session cookies. Overrides any setting that * may be specified by the application. * * @param sessionCookieName The name to use */ @Override public void setSessionCookieName(String sessionCookieName) { String oldSessionCookieName = this.sessionCookieName; this.sessionCookieName = sessionCookieName; support.firePropertyChange("sessionCookieName", oldSessionCookieName, sessionCookieName); } /** * Gets the value of the use HttpOnly cookies for session cookies flag. * * @return true if the HttpOnly flag should be set on session * cookies */ @Override public boolean getUseHttpOnly() { return useHttpOnly; } /** * Sets the use HttpOnly cookies for session cookies flag. * * @param useHttpOnly Set to true to use HttpOnly cookies * for session cookies */ @Override public void setUseHttpOnly(boolean useHttpOnly) { boolean oldUseHttpOnly = this.useHttpOnly; this.useHttpOnly = useHttpOnly; support.firePropertyChange("useHttpOnly", oldUseHttpOnly, this.useHttpOnly); } /** * Gets the domain to use for session cookies. Overrides any setting that * may be specified by the application. * * @return The value of the default session cookie domain or null if not * specified */ @Override public String getSessionCookieDomain() { return sessionCookieDomain; } /** * Sets the domain to use for session cookies. Overrides any setting that * may be specified by the application. * * @param sessionCookieDomain The domain to use */ @Override public void setSessionCookieDomain(String sessionCookieDomain) { String oldSessionCookieDomain = this.sessionCookieDomain; this.sessionCookieDomain = sessionCookieDomain; support.firePropertyChange("sessionCookieDomain", oldSessionCookieDomain, sessionCookieDomain); } /** * Gets the path to use for session cookies. Overrides any setting that * may be specified by the application. * * @return The value of the default session cookie path or null if not * specified */ @Override public String getSessionCookiePath() { return sessionCookiePath; } /** * Sets the path to use for session cookies. Overrides any setting that * may be specified by the application. * * @param sessionCookiePath The path to use */ @Override public void setSessionCookiePath(String sessionCookiePath) { String oldSessionCookiePath = this.sessionCookiePath; this.sessionCookiePath = sessionCookiePath; support.firePropertyChange("sessionCookiePath", oldSessionCookiePath, sessionCookiePath); } @Override public boolean getSessionCookiePathUsesTrailingSlash() { return sessionCookiePathUsesTrailingSlash; } @Override public void setSessionCookiePathUsesTrailingSlash( boolean sessionCookiePathUsesTrailingSlash) { this.sessionCookiePathUsesTrailingSlash = sessionCookiePathUsesTrailingSlash; } /** * Return the "allow crossing servlet contexts" flag. */ @Override public boolean getCrossContext() { return (this.crossContext); } /** * Set the "allow crossing servlet contexts" flag. * * @param crossContext The new cross contexts flag */ @Override public void setCrossContext(boolean crossContext) { boolean oldCrossContext = this.crossContext; this.crossContext = crossContext; support.firePropertyChange("crossContext", oldCrossContext, this.crossContext); } public String getDefaultContextXml() { return defaultContextXml; } /** * Set the location of the default context xml that will be used. * If not absolute, it'll be made relative to the engine's base dir * ( which defaults to catalina.base system property ). * * @param defaultContextXml The default web xml */ public void setDefaultContextXml(String defaultContextXml) { this.defaultContextXml = defaultContextXml; } public String getDefaultWebXml() { return defaultWebXml; } /** * Set the location of the default web xml that will be used. * If not absolute, it'll be made relative to the engine's base dir * ( which defaults to catalina.base system property ). * * @param defaultWebXml The default web xml */ public void setDefaultWebXml(String defaultWebXml) { this.defaultWebXml = defaultWebXml; } /** * Gets the time (in milliseconds) it took to start this context. * * @return Time (in milliseconds) it took to start this context. */ public long getStartupTime() { return startupTime; } public void setStartupTime(long startupTime) { this.startupTime = startupTime; } public long getTldScanTime() { return tldScanTime; } public void setTldScanTime(long tldScanTime) { this.tldScanTime = tldScanTime; } /** * Return the display name of this web application. */ @Override public String getDisplayName() { return (this.displayName); } /** * Return the alternate Deployment Descriptor name. */ @Override public String getAltDDName(){ return altDDName; } /** * Set an alternate Deployment Descriptor name. */ @Override public void setAltDDName(String altDDName) { this.altDDName = altDDName; if (context != null) { context.setAttribute(Globals.ALT_DD_ATTR,altDDName); } } /** * Return the compiler classpath. */ @Deprecated public String getCompilerClasspath(){ return compilerClasspath; } /** * Set the compiler classpath. */ @Deprecated public void setCompilerClasspath(String compilerClasspath) { this.compilerClasspath = compilerClasspath; } /** * Set the display name of this web application. * * @param displayName The new display name */ @Override public void setDisplayName(String displayName) { String oldDisplayName = this.displayName; this.displayName = displayName; support.firePropertyChange("displayName", oldDisplayName, this.displayName); } /** * Return the distributable flag for this web application. */ @Override public boolean getDistributable() { return (this.distributable); } /** * Set the distributable flag for this web application. * * @param distributable The new distributable flag */ @Override public void setDistributable(boolean distributable) { boolean oldDistributable = this.distributable; this.distributable = distributable; support.firePropertyChange("distributable", oldDistributable, this.distributable); // Bugzilla 32866 if(getManager() != null) { if(log.isDebugEnabled()) { log.debug("Propagating distributable=" + distributable + " to manager"); } getManager().setDistributable(distributable); } } /** * Return the document root for this Context. This can be an absolute * pathname, a relative pathname, or a URL. */ @Override public String getDocBase() { return (this.docBase); } /** * Set the document root for this Context. This can be an absolute * pathname, a relative pathname, or a URL. * * @param docBase The new document root */ @Override public void setDocBase(String docBase) { this.docBase = docBase; } /** * Return descriptive information about this Container implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } public String getJ2EEApplication() { return j2EEApplication; } public void setJ2EEApplication(String j2EEApplication) { this.j2EEApplication = j2EEApplication; } public String getJ2EEServer() { return j2EEServer; } public void setJ2EEServer(String j2EEServer) { this.j2EEServer = j2EEServer; } /** * Set the Loader with which this Context is associated. * * @param loader The newly associated loader */ @Override public synchronized void setLoader(Loader loader) { super.setLoader(loader); } /** * Return the boolean on the annotations parsing. */ @Override public boolean getIgnoreAnnotations() { return this.ignoreAnnotations; } /** * Set the boolean on the annotations parsing for this web * application. * * @param ignoreAnnotations The boolean on the annotations parsing */ @Override public void setIgnoreAnnotations(boolean ignoreAnnotations) { boolean oldIgnoreAnnotations = this.ignoreAnnotations; this.ignoreAnnotations = ignoreAnnotations; support.firePropertyChange("ignoreAnnotations", oldIgnoreAnnotations, this.ignoreAnnotations); } /** * Return the login configuration descriptor for this web application. */ @Override public LoginConfig getLoginConfig() { return (this.loginConfig); } /** * Set the login configuration descriptor for this web application. * * @param config The new login configuration */ @Override public void setLoginConfig(LoginConfig config) { // Validate the incoming property value if (config == null) throw new IllegalArgumentException (sm.getString("standardContext.loginConfig.required")); String loginPage = config.getLoginPage(); if ((loginPage != null) && !loginPage.startsWith("/")) { if (isServlet22()) { if(log.isDebugEnabled()) log.debug(sm.getString("standardContext.loginConfig.loginWarning", loginPage)); config.setLoginPage("/" + loginPage); } else { throw new IllegalArgumentException (sm.getString("standardContext.loginConfig.loginPage", loginPage)); } } String errorPage = config.getErrorPage(); if ((errorPage != null) && !errorPage.startsWith("/")) { if (isServlet22()) { if(log.isDebugEnabled()) log.debug(sm.getString("standardContext.loginConfig.errorWarning", errorPage)); config.setErrorPage("/" + errorPage); } else { throw new IllegalArgumentException (sm.getString("standardContext.loginConfig.errorPage", errorPage)); } } // Process the property setting change LoginConfig oldLoginConfig = this.loginConfig; this.loginConfig = config; support.firePropertyChange("loginConfig", oldLoginConfig, this.loginConfig); } /** * Get the mapper associated with the context. */ @Override public org.apache.tomcat.util.http.mapper.Mapper getMapper() { return (mapper); } /** * Return the naming resources associated with this web application. */ @Override public NamingResources getNamingResources() { if (namingResources == null) { setNamingResources(new NamingResources()); } return (namingResources); } /** * Set the naming resources for this web application. * * @param namingResources The new naming resources */ @Override public void setNamingResources(NamingResources namingResources) { // Process the property setting change NamingResources oldNamingResources = this.namingResources; this.namingResources = namingResources; if (namingResources != null) { namingResources.setContainer(this); } support.firePropertyChange("namingResources", oldNamingResources, this.namingResources); if (getState() == LifecycleState.NEW || getState() == LifecycleState.INITIALIZING || getState() == LifecycleState.INITIALIZED) { // NEW will occur if Context is defined in server.xml // At this point getObjectKeyPropertiesNameOnly() will trigger an // NPE. // INITIALIZED will occur if the Context is defined in a context.xml // file // If started now, a second start will be attempted when the context // starts // In both cases, return and let context init the namingResources // when it starts return; } if (oldNamingResources != null) { try { oldNamingResources.stop(); oldNamingResources.destroy(); } catch (LifecycleException e) { log.warn("standardContext.namingResource.destroy.fail", e); } } if (namingResources != null) { try { namingResources.init(); namingResources.start(); } catch (LifecycleException e) { log.warn("standardContext.namingResource.init.fail", e); } } } /** * Return the context path for this Context. */ @Override public String getPath() { return (path); } /** * Set the context path for this Context. * * @param path The new context path */ @Override public void setPath(String path) { if (path == null || (!path.equals("") && !path.startsWith("/"))) { this.path = "/" + path; log.warn(sm.getString( "standardContext.pathInvalid", path, this.path)); } else { this.path = path; } encodedPath = urlEncoder.encode(this.path); if (getName() == null) { setName(this.path); } } /** * Return the public identifier of the deployment descriptor DTD that is * currently being parsed. */ @Override public String getPublicId() { return (this.publicId); } /** * Set the public identifier of the deployment descriptor DTD that is * currently being parsed. * * @param publicId The public identifier */ @Override public void setPublicId(String publicId) { if (log.isDebugEnabled()) log.debug("Setting deployment descriptor public ID to '" + publicId + "'"); String oldPublicId = this.publicId; this.publicId = publicId; support.firePropertyChange("publicId", oldPublicId, publicId); } /** * Return the reloadable flag for this web application. */ @Override public boolean getReloadable() { return (this.reloadable); } /** * Return the default context override flag for this web application. */ @Override public boolean getOverride() { return (this.override); } /** * Return the original document root for this Context. This can be an absolute * pathname, a relative pathname, or a URL. * Is only set as deployment has change docRoot! */ public String getOriginalDocBase() { return (this.originalDocBase); } /** * Set the original document root for this Context. This can be an absolute * pathname, a relative pathname, or a URL. * * @param docBase The original document root */ public void setOriginalDocBase(String docBase) { this.originalDocBase = docBase; } /** * Return the parent class loader (if any) for this web application. * This call is meaningful only after a Loader has * been configured. */ @Override public ClassLoader getParentClassLoader() { if (parentClassLoader != null) return (parentClassLoader); if (getPrivileged()) { return this.getClass().getClassLoader(); } else if (parent != null) { return (parent.getParentClassLoader()); } return (ClassLoader.getSystemClassLoader()); } /** * Return the privileged flag for this web application. */ @Override public boolean getPrivileged() { return (this.privileged); } /** * Set the privileged flag for this web application. * * @param privileged The new privileged flag */ @Override public void setPrivileged(boolean privileged) { boolean oldPrivileged = this.privileged; this.privileged = privileged; support.firePropertyChange("privileged", oldPrivileged, this.privileged); } /** * Set the reloadable flag for this web application. * * @param reloadable The new reloadable flag */ @Override public void setReloadable(boolean reloadable) { boolean oldReloadable = this.reloadable; this.reloadable = reloadable; support.firePropertyChange("reloadable", oldReloadable, this.reloadable); } /** * Set the default context override flag for this web application. * * @param override The new override flag */ @Override public void setOverride(boolean override) { boolean oldOverride = this.override; this.override = override; support.firePropertyChange("override", oldOverride, this.override); } /** * Return the "replace welcome files" property. */ @Deprecated public boolean isReplaceWelcomeFiles() { return (this.replaceWelcomeFiles); } /** * Set the "replace welcome files" property. * * @param replaceWelcomeFiles The new property value */ public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) { boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles; this.replaceWelcomeFiles = replaceWelcomeFiles; support.firePropertyChange("replaceWelcomeFiles", oldReplaceWelcomeFiles, this.replaceWelcomeFiles); } /** * Return the servlet context for which this Context is a facade. */ @Override public ServletContext getServletContext() { if (context == null) { context = new ApplicationContext(this); if (altDDName != null) context.setAttribute(Globals.ALT_DD_ATTR,altDDName); } return (context.getFacade()); } /** * Return the default session timeout (in minutes) for this * web application. */ @Override public int getSessionTimeout() { return (this.sessionTimeout); } /** * Set the default session timeout (in minutes) for this * web application. * * @param timeout The new default session timeout */ @Override public void setSessionTimeout(int timeout) { int oldSessionTimeout = this.sessionTimeout; /* * SRV.13.4 ("Deployment Descriptor"): * If the timeout is 0 or less, the container ensures the default * behaviour of sessions is never to time out. */ this.sessionTimeout = (timeout == 0) ? -1 : timeout; support.firePropertyChange("sessionTimeout", oldSessionTimeout, this.sessionTimeout); } /** * Return the value of the swallowOutput flag. */ @Override public boolean getSwallowOutput() { return (this.swallowOutput); } /** * Set the value of the swallowOutput flag. If set to true, the system.out * and system.err will be redirected to the logger during a servlet * execution. * * @param swallowOutput The new value */ @Override public void setSwallowOutput(boolean swallowOutput) { boolean oldSwallowOutput = this.swallowOutput; this.swallowOutput = swallowOutput; support.firePropertyChange("swallowOutput", oldSwallowOutput, this.swallowOutput); } /** * Return the value of the unloadDelay flag. */ public long getUnloadDelay() { return (this.unloadDelay); } /** * Set the value of the unloadDelay flag, which represents the amount * of ms that the container will wait when unloading servlets. * Setting this to a small value may cause more requests to fail * to complete when stopping a web application. * * @param unloadDelay The new value */ public void setUnloadDelay(long unloadDelay) { long oldUnloadDelay = this.unloadDelay; this.unloadDelay = unloadDelay; support.firePropertyChange("unloadDelay", Long.valueOf(oldUnloadDelay), Long.valueOf(this.unloadDelay)); } /** * Unpack WAR flag accessor. */ public boolean getUnpackWAR() { return (unpackWAR); } /** * Unpack WAR flag mutator. */ public void setUnpackWAR(boolean unpackWAR) { this.unpackWAR = unpackWAR; } public boolean getCopyXML() { return copyXML; } public void setCopyXML(boolean copyXML) { this.copyXML = copyXML; } /** * Return the Java class name of the Wrapper implementation used * for servlets registered in this Context. */ @Override public String getWrapperClass() { return (this.wrapperClassName); } /** * Set the Java class name of the Wrapper implementation used * for servlets registered in this Context. * * @param wrapperClassName The new wrapper class name * * @throws IllegalArgumentException if the specified wrapper class * cannot be found or is not a subclass of StandardWrapper */ @Override public void setWrapperClass(String wrapperClassName) { this.wrapperClassName = wrapperClassName; try { wrapperClass = Class.forName(wrapperClassName); if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) { throw new IllegalArgumentException( sm.getString("standardContext.invalidWrapperClass", wrapperClassName)); } } catch (ClassNotFoundException cnfe) { throw new IllegalArgumentException(cnfe.getMessage()); } } /** * Set the resources DirContext object with which this Container is * associated. * * @param resources The newly associated DirContext */ @Override public synchronized void setResources(DirContext resources) { if (getState().isAvailable()) { throw new IllegalStateException (sm.getString("standardContext.resources.started")); } DirContext oldResources = this.webappResources; if (oldResources == resources) return; if (resources instanceof BaseDirContext) { // Caching ((BaseDirContext) resources).setCached(isCachingAllowed()); ((BaseDirContext) resources).setCacheTTL(getCacheTTL()); ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize()); ((BaseDirContext) resources).setCacheObjectMaxSize( getCacheObjectMaxSize()); // Alias support ((BaseDirContext) resources).setAliases(getAliases()); } if (resources instanceof FileDirContext) { filesystemBased = true; ((FileDirContext) resources).setAllowLinking(isAllowLinking()); } this.webappResources = resources; // The proxied resources will be refreshed on start this.resources = null; support.firePropertyChange("resources", oldResources, this.webappResources); } @Override public JspConfigDescriptor getJspConfigDescriptor() { return jspConfigDescriptor; } // ------------------------------------------------------ Public Properties /** * Returns whether or not an attempt to modify the JNDI context will trigger * an exception or if the request will be ignored. */ public boolean getJndiExceptionOnFailedWrite() { return jndiExceptionOnFailedWrite; } /** * Controls whether or not an attempt to modify the JNDI context will * trigger an exception or if the request will be ignored. * * @param jndiExceptionOnFailedWrite */ public void setJndiExceptionOnFailedWrite( boolean jndiExceptionOnFailedWrite) { this.jndiExceptionOnFailedWrite = jndiExceptionOnFailedWrite; } /** * Return the Locale to character set mapper class for this Context. */ public String getCharsetMapperClass() { return (this.charsetMapperClass); } /** * Set the Locale to character set mapper class for this Context. * * @param mapper The new mapper class */ public void setCharsetMapperClass(String mapper) { String oldCharsetMapperClass = this.charsetMapperClass; this.charsetMapperClass = mapper; support.firePropertyChange("charsetMapperClass", oldCharsetMapperClass, this.charsetMapperClass); } /** Get the absolute path to the work dir. * To avoid duplication. * * @return The work path */ public String getWorkPath() { if (getWorkDir() == null) { return null; } File workDir = new File(getWorkDir()); if (!workDir.isAbsolute()) { File catalinaHome = engineBase(); String catalinaHomePath = null; try { catalinaHomePath = catalinaHome.getCanonicalPath(); workDir = new File(catalinaHomePath, getWorkDir()); } catch (IOException e) { log.warn(sm.getString("standardContext.workPath", getName()), e); } } return workDir.getAbsolutePath(); } /** * Return the work directory for this Context. */ public String getWorkDir() { return (this.workDir); } /** * Set the work directory for this Context. * * @param workDir The new work directory */ public void setWorkDir(String workDir) { this.workDir = workDir; if (getState().isAvailable()) { postWorkDirectory(); } } /** * Save config ? */ @Deprecated public boolean isSaveConfig() { return saveConfig; } /** * Set save config flag. */ @Deprecated public void setSaveConfig(boolean saveConfig) { this.saveConfig = saveConfig; } /** * Return the clearReferencesStatic flag for this Context. */ public boolean getClearReferencesStatic() { return (this.clearReferencesStatic); } /** * Set the clearReferencesStatic feature for this Context. * * @param clearReferencesStatic The new flag value */ public void setClearReferencesStatic(boolean clearReferencesStatic) { boolean oldClearReferencesStatic = this.clearReferencesStatic; this.clearReferencesStatic = clearReferencesStatic; support.firePropertyChange("clearReferencesStatic", oldClearReferencesStatic, this.clearReferencesStatic); } /** * Return the clearReferencesStopThreads flag for this Context. */ public boolean getClearReferencesStopThreads() { return (this.clearReferencesStopThreads); } /** * Set the clearReferencesStopThreads feature for this Context. * * @param clearReferencesStopThreads The new flag value */ public void setClearReferencesStopThreads( boolean clearReferencesStopThreads) { boolean oldClearReferencesStopThreads = this.clearReferencesStopThreads; this.clearReferencesStopThreads = clearReferencesStopThreads; support.firePropertyChange("clearReferencesStopThreads", oldClearReferencesStopThreads, this.clearReferencesStopThreads); } /** * Return the clearReferencesStopTimerThreads flag for this Context. */ public boolean getClearReferencesStopTimerThreads() { return (this.clearReferencesStopTimerThreads); } /** * Set the clearReferencesStopTimerThreads feature for this Context. * * @param clearReferencesStopTimerThreads The new flag value */ public void setClearReferencesStopTimerThreads( boolean clearReferencesStopTimerThreads) { boolean oldClearReferencesStopTimerThreads = this.clearReferencesStopTimerThreads; this.clearReferencesStopTimerThreads = clearReferencesStopTimerThreads; support.firePropertyChange("clearReferencesStopTimerThreads", oldClearReferencesStopTimerThreads, this.clearReferencesStopTimerThreads); } /** * Return the clearReferencesHttpClientKeepAliveThread flag for this * Context. */ public boolean getClearReferencesHttpClientKeepAliveThread() { return (this.clearReferencesHttpClientKeepAliveThread); } /** * Set the clearReferencesHttpClientKeepAliveThread feature for this * Context. * * @param clearReferencesHttpClientKeepAliveThread The new flag value */ public void setClearReferencesHttpClientKeepAliveThread( boolean clearReferencesHttpClientKeepAliveThread) { this.clearReferencesHttpClientKeepAliveThread = clearReferencesHttpClientKeepAliveThread; } public boolean getRenewThreadsWhenStoppingContext() { return this.renewThreadsWhenStoppingContext; } public void setRenewThreadsWhenStoppingContext( boolean renewThreadsWhenStoppingContext) { boolean oldRenewThreadsWhenStoppingContext = this.renewThreadsWhenStoppingContext; this.renewThreadsWhenStoppingContext = renewThreadsWhenStoppingContext; support.firePropertyChange("renewThreadsWhenStoppingContext", oldRenewThreadsWhenStoppingContext, this.renewThreadsWhenStoppingContext); } // -------------------------------------------------------- Context Methods @Override public void addApplicationListener(String listener) { addApplicationListener(new ApplicationListener(listener, false)); } /** * Add a new Listener class name to the set of Listeners * configured for this application. * * @param listener Java class name of a listener class */ @Override public void addApplicationListener(ApplicationListener listener) { synchronized (applicationListenersLock) { ApplicationListener results[] = new ApplicationListener[applicationListeners.length + 1]; for (int i = 0; i < applicationListeners.length; i++) { if (listener.equals(applicationListeners[i])) { log.info(sm.getString( "standardContext.duplicateListener",listener)); return; } results[i] = applicationListeners[i]; } results[applicationListeners.length] = listener; applicationListeners = results; } fireContainerEvent("addApplicationListener", listener); // FIXME - add instance if already started? } /** * Add a new application parameter for this application. * * @param parameter The new application parameter */ @Override public void addApplicationParameter(ApplicationParameter parameter) { synchronized (applicationParametersLock) { String newName = parameter.getName(); for (ApplicationParameter p : applicationParameters) { if (newName.equals(p.getName()) && !p.getOverride()) return; } ApplicationParameter results[] = Arrays.copyOf( applicationParameters, applicationParameters.length + 1); results[applicationParameters.length] = parameter; applicationParameters = results; } fireContainerEvent("addApplicationParameter", parameter); } /** * Add a child Container, only if the proposed child is an implementation * of Wrapper. * * @param child Child container to be added * * @exception IllegalArgumentException if the proposed container is * not an implementation of Wrapper */ @Override public void addChild(Container child) { // Global JspServlet Wrapper oldJspServlet = null; if (!(child instanceof Wrapper)) { throw new IllegalArgumentException (sm.getString("standardContext.notWrapper")); } boolean isJspServlet = "jsp".equals(child.getName()); // Allow webapp to override JspServlet inherited from global web.xml. if (isJspServlet) { oldJspServlet = (Wrapper) findChild("jsp"); if (oldJspServlet != null) { removeChild(oldJspServlet); } } super.addChild(child); if (isJspServlet && oldJspServlet != null) { /* * The webapp-specific JspServlet inherits all the mappings * specified in the global web.xml, and may add additional ones. */ String[] jspMappings = oldJspServlet.findMappings(); for (int i=0; jspMappings!=null && i 0 && collections[i].findOmittedMethods().length > 0) { throw new IllegalArgumentException(sm.getString( "standardContext.securityConstraint.mixHttpMethod")); } } // Add this constraint to the set for our web application synchronized (constraintsLock) { SecurityConstraint results[] = new SecurityConstraint[constraints.length + 1]; for (int i = 0; i < constraints.length; i++) results[i] = constraints[i]; results[constraints.length] = constraint; constraints = results; } } /** * Add an error page for the specified error or Java exception. * * @param errorPage The error page definition to be added */ @Override public void addErrorPage(ErrorPage errorPage) { // Validate the input parameters if (errorPage == null) throw new IllegalArgumentException (sm.getString("standardContext.errorPage.required")); String location = errorPage.getLocation(); if ((location != null) && !location.startsWith("/")) { if (isServlet22()) { if(log.isDebugEnabled()) log.debug(sm.getString("standardContext.errorPage.warning", location)); errorPage.setLocation("/" + location); } else { throw new IllegalArgumentException (sm.getString("standardContext.errorPage.error", location)); } } // Add the specified error page to our internal collections String exceptionType = errorPage.getExceptionType(); if (exceptionType != null) { synchronized (exceptionPages) { exceptionPages.put(exceptionType, errorPage); } } else { synchronized (statusPages) { if (errorPage.getErrorCode() == 200) { this.okErrorPage = errorPage; } statusPages.put(Integer.valueOf(errorPage.getErrorCode()), errorPage); } } fireContainerEvent("addErrorPage", errorPage); } /** * Add a filter definition to this Context. * * @param filterDef The filter definition to be added */ @Override public void addFilterDef(FilterDef filterDef) { synchronized (filterDefs) { filterDefs.put(filterDef.getFilterName(), filterDef); } fireContainerEvent("addFilterDef", filterDef); } /** * Add a filter mapping to this Context at the end of the current set * of filter mappings. * * @param filterMap The filter mapping to be added * * @exception IllegalArgumentException if the specified filter name * does not match an existing filter definition, or the filter mapping * is malformed */ @Override public void addFilterMap(FilterMap filterMap) { validateFilterMap(filterMap); // Add this filter mapping to our registered set filterMaps.add(filterMap); fireContainerEvent("addFilterMap", filterMap); } /** * Add a filter mapping to this Context before the mappings defined in the * deployment descriptor but after any other mappings added via this method. * * @param filterMap The filter mapping to be added * * @exception IllegalArgumentException if the specified filter name * does not match an existing filter definition, or the filter mapping * is malformed */ @Override public void addFilterMapBefore(FilterMap filterMap) { validateFilterMap(filterMap); // Add this filter mapping to our registered set filterMaps.addBefore(filterMap); fireContainerEvent("addFilterMap", filterMap); } /** * Validate the supplied FilterMap. */ private void validateFilterMap(FilterMap filterMap) { // Validate the proposed filter mapping String filterName = filterMap.getFilterName(); String[] servletNames = filterMap.getServletNames(); String[] urlPatterns = filterMap.getURLPatterns(); if (findFilterDef(filterName) == null) throw new IllegalArgumentException (sm.getString("standardContext.filterMap.name", filterName)); if (!filterMap.getMatchAllServletNames() && !filterMap.getMatchAllUrlPatterns() && (servletNames.length == 0) && (urlPatterns.length == 0)) throw new IllegalArgumentException (sm.getString("standardContext.filterMap.either")); // FIXME: Older spec revisions may still check this /* if ((servletNames.length != 0) && (urlPatterns.length != 0)) throw new IllegalArgumentException (sm.getString("standardContext.filterMap.either")); */ for (int i = 0; i < urlPatterns.length; i++) { if (!validateURLPattern(urlPatterns[i])) { throw new IllegalArgumentException (sm.getString("standardContext.filterMap.pattern", urlPatterns[i])); } } } /** * Add the classname of an InstanceListener to be added to each * Wrapper appended to this Context. * * @param listener Java class name of an InstanceListener class */ @Override public void addInstanceListener(String listener) { synchronized (instanceListenersLock) { String results[] =new String[instanceListeners.length + 1]; for (int i = 0; i < instanceListeners.length; i++) results[i] = instanceListeners[i]; results[instanceListeners.length] = listener; instanceListeners = results; } fireContainerEvent("addInstanceListener", listener); } /** * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4) * * @param locale locale to map an encoding for * @param encoding encoding to be used for a give locale */ @Override public void addLocaleEncodingMappingParameter(String locale, String encoding){ getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding); } /** * Add a message destination for this web application. * * @param md New message destination */ public void addMessageDestination(MessageDestination md) { synchronized (messageDestinations) { messageDestinations.put(md.getName(), md); } fireContainerEvent("addMessageDestination", md.getName()); } /** * Add a message destination reference for this web application. * * @param mdr New message destination reference */ public void addMessageDestinationRef (MessageDestinationRef mdr) { namingResources.addMessageDestinationRef(mdr); fireContainerEvent("addMessageDestinationRef", mdr.getName()); } /** * Add a new MIME mapping, replacing any existing mapping for * the specified extension. * * @param extension Filename extension being mapped * @param mimeType Corresponding MIME type */ @Override public void addMimeMapping(String extension, String mimeType) { synchronized (mimeMappings) { mimeMappings.put(extension, mimeType); } fireContainerEvent("addMimeMapping", extension); } /** * Add a new context initialization parameter. * * @param name Name of the new parameter * @param value Value of the new parameter * * @exception IllegalArgumentException if the name or value is missing, * or if this context initialization parameter has already been * registered */ @Override public void addParameter(String name, String value) { // Validate the proposed context initialization parameter if ((name == null) || (value == null)) throw new IllegalArgumentException (sm.getString("standardContext.parameter.required")); if (parameters.get(name) != null) throw new IllegalArgumentException (sm.getString("standardContext.parameter.duplicate", name)); // Add this parameter to our defined set synchronized (parameters) { parameters.put(name, value); } fireContainerEvent("addParameter", name); } /** * Add a security role reference for this web application. * * @param role Security role used in the application * @param link Actual security role to check for */ @Override public void addRoleMapping(String role, String link) { synchronized (roleMappings) { roleMappings.put(role, link); } fireContainerEvent("addRoleMapping", role); } /** * Add a new security role for this web application. * * @param role New security role */ @Override public void addSecurityRole(String role) { synchronized (securityRolesLock) { String results[] =new String[securityRoles.length + 1]; for (int i = 0; i < securityRoles.length; i++) results[i] = securityRoles[i]; results[securityRoles.length] = role; securityRoles = results; } fireContainerEvent("addSecurityRole", role); } /** * Add a new servlet mapping, replacing any existing mapping for * the specified pattern. * * @param pattern URL pattern to be mapped * @param name Name of the corresponding servlet to execute * * @exception IllegalArgumentException if the specified servlet name * is not known to this Context */ @Override public void addServletMapping(String pattern, String name) { addServletMapping(pattern, name, false); } /** * Add a new servlet mapping, replacing any existing mapping for * the specified pattern. * * @param pattern URL pattern to be mapped * @param name Name of the corresponding servlet to execute * @param jspWildCard true if name identifies the JspServlet * and pattern contains a wildcard; false otherwise * * @exception IllegalArgumentException if the specified servlet name * is not known to this Context */ @Override public void addServletMapping(String pattern, String name, boolean jspWildCard) { // Validate the proposed mapping if (findChild(name) == null) throw new IllegalArgumentException (sm.getString("standardContext.servletMap.name", name)); String decodedPattern = adjustURLPattern(RequestUtil.URLDecode(pattern)); if (!validateURLPattern(decodedPattern)) throw new IllegalArgumentException (sm.getString("standardContext.servletMap.pattern", decodedPattern)); // Add this mapping to our registered set synchronized (servletMappingsLock) { String name2 = servletMappings.get(decodedPattern); if (name2 != null) { // Don't allow more than one servlet on the same pattern Wrapper wrapper = (Wrapper) findChild(name2); wrapper.removeMapping(decodedPattern); mapper.removeWrapper(decodedPattern); } servletMappings.put(decodedPattern, name); } Wrapper wrapper = (Wrapper) findChild(name); wrapper.addMapping(decodedPattern); // Update context mapper mapper.addWrapper(decodedPattern, wrapper, jspWildCard, resourceOnlyServlets.contains(name)); fireContainerEvent("addServletMapping", decodedPattern); } /** * Add a new watched resource to the set recognized by this Context. * * @param name New watched resource file name */ @Override public void addWatchedResource(String name) { synchronized (watchedResourcesLock) { String results[] = new String[watchedResources.length + 1]; for (int i = 0; i < watchedResources.length; i++) results[i] = watchedResources[i]; results[watchedResources.length] = name; watchedResources = results; } fireContainerEvent("addWatchedResource", name); } /** * Add a new welcome file to the set recognized by this Context. * * @param name New welcome file name */ @Override public void addWelcomeFile(String name) { synchronized (welcomeFilesLock) { // Welcome files from the application deployment descriptor // completely replace those from the default conf/web.xml file if (replaceWelcomeFiles) { fireContainerEvent(CLEAR_WELCOME_FILES_EVENT, null); welcomeFiles = new String[0]; setReplaceWelcomeFiles(false); } String results[] =new String[welcomeFiles.length + 1]; for (int i = 0; i < welcomeFiles.length; i++) results[i] = welcomeFiles[i]; results[welcomeFiles.length] = name; welcomeFiles = results; } if(this.getState().equals(LifecycleState.STARTED)) fireContainerEvent(ADD_WELCOME_FILE_EVENT, name); } /** * Add the classname of a LifecycleListener to be added to each * Wrapper appended to this Context. * * @param listener Java class name of a LifecycleListener class */ @Override public void addWrapperLifecycle(String listener) { synchronized (wrapperLifecyclesLock) { String results[] =new String[wrapperLifecycles.length + 1]; for (int i = 0; i < wrapperLifecycles.length; i++) results[i] = wrapperLifecycles[i]; results[wrapperLifecycles.length] = listener; wrapperLifecycles = results; } fireContainerEvent("addWrapperLifecycle", listener); } /** * Add the classname of a ContainerListener to be added to each * Wrapper appended to this Context. * * @param listener Java class name of a ContainerListener class */ @Override public void addWrapperListener(String listener) { synchronized (wrapperListenersLock) { String results[] =new String[wrapperListeners.length + 1]; for (int i = 0; i < wrapperListeners.length; i++) results[i] = wrapperListeners[i]; results[wrapperListeners.length] = listener; wrapperListeners = results; } fireContainerEvent("addWrapperListener", listener); } /** * Factory method to create and return a new Wrapper instance, of * the Java implementation class appropriate for this Context * implementation. The constructor of the instantiated Wrapper * will have been called, but no properties will have been set. */ @Override public Wrapper createWrapper() { Wrapper wrapper = null; if (wrapperClass != null) { try { wrapper = (Wrapper) wrapperClass.newInstance(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("createWrapper", t); return (null); } } else { wrapper = new StandardWrapper(); } synchronized (instanceListenersLock) { for (int i = 0; i < instanceListeners.length; i++) { try { Class clazz = Class.forName(instanceListeners[i]); InstanceListener listener = (InstanceListener) clazz.newInstance(); wrapper.addInstanceListener(listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("createWrapper", t); return (null); } } } synchronized (wrapperLifecyclesLock) { for (int i = 0; i < wrapperLifecycles.length; i++) { try { Class clazz = Class.forName(wrapperLifecycles[i]); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); wrapper.addLifecycleListener(listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("createWrapper", t); return (null); } } } synchronized (wrapperListenersLock) { for (int i = 0; i < wrapperListeners.length; i++) { try { Class clazz = Class.forName(wrapperListeners[i]); ContainerListener listener = (ContainerListener) clazz.newInstance(); wrapper.addContainerListener(listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("createWrapper", t); return (null); } } } return (wrapper); } /** * Return the set of application listener class names configured * for this application. */ @Override public String[] findApplicationListeners() { ArrayList list = new ArrayList(applicationListeners.length); for (ApplicationListener applicationListener: applicationListeners) { list.add(applicationListener.getClassName()); } return list.toArray(new String[list.size()]); } /** * Return the set of application parameters for this application. */ @Override public ApplicationParameter[] findApplicationParameters() { synchronized (applicationParametersLock) { return (applicationParameters); } } /** * Return the security constraints for this web application. * If there are none, a zero-length array is returned. */ @Override public SecurityConstraint[] findConstraints() { return (constraints); } /** * Return the error page entry for the specified HTTP error code, * if any; otherwise return null. * * @param errorCode Error code to look up */ @Override public ErrorPage findErrorPage(int errorCode) { if (errorCode == 200) { return (okErrorPage); } else { return (statusPages.get(Integer.valueOf(errorCode))); } } /** * Return the error page entry for the specified Java exception type, * if any; otherwise return null. * * @param exceptionType Exception type to look up */ @Override public ErrorPage findErrorPage(String exceptionType) { synchronized (exceptionPages) { return (exceptionPages.get(exceptionType)); } } /** * Return the set of defined error pages for all specified error codes * and exception types. */ @Override public ErrorPage[] findErrorPages() { synchronized(exceptionPages) { synchronized(statusPages) { ErrorPage results1[] = new ErrorPage[exceptionPages.size()]; results1 = exceptionPages.values().toArray(results1); ErrorPage results2[] = new ErrorPage[statusPages.size()]; results2 = statusPages.values().toArray(results2); ErrorPage results[] = new ErrorPage[results1.length + results2.length]; for (int i = 0; i < results1.length; i++) results[i] = results1[i]; for (int i = results1.length; i < results.length; i++) results[i] = results2[i - results1.length]; return (results); } } } /** * Return the filter definition for the specified filter name, if any; * otherwise return null. * * @param filterName Filter name to look up */ @Override public FilterDef findFilterDef(String filterName) { synchronized (filterDefs) { return (filterDefs.get(filterName)); } } /** * Return the set of defined filters for this Context. */ @Override public FilterDef[] findFilterDefs() { synchronized (filterDefs) { FilterDef results[] = new FilterDef[filterDefs.size()]; return (filterDefs.values().toArray(results)); } } /** * Return the set of filter mappings for this Context. */ @Override public FilterMap[] findFilterMaps() { return filterMaps.asArray(); } /** * Return the set of InstanceListener classes that will be added to * newly created Wrappers automatically. */ @Override public String[] findInstanceListeners() { synchronized (instanceListenersLock) { return (instanceListeners); } } /** * FIXME: Fooling introspection ... */ @Deprecated public Context findMappingObject() { return (Context) getMappingObject(); } /** * Return the message destination with the specified name, if any; * otherwise, return null. * * @param name Name of the desired message destination */ public MessageDestination findMessageDestination(String name) { synchronized (messageDestinations) { return (messageDestinations.get(name)); } } /** * Return the set of defined message destinations for this web * application. If none have been defined, a zero-length array * is returned. */ public MessageDestination[] findMessageDestinations() { synchronized (messageDestinations) { MessageDestination results[] = new MessageDestination[messageDestinations.size()]; return (messageDestinations.values().toArray(results)); } } /** * Return the message destination ref with the specified name, if any; * otherwise, return null. * * @param name Name of the desired message destination ref */ public MessageDestinationRef findMessageDestinationRef(String name) { return namingResources.findMessageDestinationRef(name); } /** * Return the set of defined message destination refs for this web * application. If none have been defined, a zero-length array * is returned. */ public MessageDestinationRef[] findMessageDestinationRefs() { return namingResources.findMessageDestinationRefs(); } /** * Return the MIME type to which the specified extension is mapped, * if any; otherwise return null. * * @param extension Extension to map to a MIME type */ @Override public String findMimeMapping(String extension) { return (mimeMappings.get(extension)); } /** * Return the extensions for which MIME mappings are defined. If there * are none, a zero-length array is returned. */ @Override public String[] findMimeMappings() { synchronized (mimeMappings) { String results[] = new String[mimeMappings.size()]; return (mimeMappings.keySet().toArray(results)); } } /** * Return the value for the specified context initialization * parameter name, if any; otherwise return null. * * @param name Name of the parameter to return */ @Override public String findParameter(String name) { synchronized (parameters) { return (parameters.get(name)); } } /** * Return the names of all defined context initialization parameters * for this Context. If no parameters are defined, a zero-length * array is returned. */ @Override public String[] findParameters() { synchronized (parameters) { String results[] = new String[parameters.size()]; return (parameters.keySet().toArray(results)); } } /** * For the given security role (as used by an application), return the * corresponding role name (as defined by the underlying Realm) if there * is one. Otherwise, return the specified role unchanged. * * @param role Security role to map */ @Override public String findRoleMapping(String role) { String realRole = null; synchronized (roleMappings) { realRole = roleMappings.get(role); } if (realRole != null) return (realRole); else return (role); } /** * Return true if the specified security role is defined * for this application; otherwise return false. * * @param role Security role to verify */ @Override public boolean findSecurityRole(String role) { synchronized (securityRolesLock) { for (int i = 0; i < securityRoles.length; i++) { if (role.equals(securityRoles[i])) return (true); } } return (false); } /** * Return the security roles defined for this application. If none * have been defined, a zero-length array is returned. */ @Override public String[] findSecurityRoles() { synchronized (securityRolesLock) { return (securityRoles); } } /** * Return the servlet name mapped by the specified pattern (if any); * otherwise return null. * * @param pattern Pattern for which a mapping is requested */ @Override public String findServletMapping(String pattern) { synchronized (servletMappingsLock) { return (servletMappings.get(pattern)); } } /** * Return the patterns of all defined servlet mappings for this * Context. If no mappings are defined, a zero-length array is returned. */ @Override public String[] findServletMappings() { synchronized (servletMappingsLock) { String results[] = new String[servletMappings.size()]; return (servletMappings.keySet().toArray(results)); } } /** * Return the context-relative URI of the error page for the specified * HTTP status code, if any; otherwise return null. * * @param status HTTP status code to look up */ @Override public String findStatusPage(int status) { ErrorPage errorPage = statusPages.get(Integer.valueOf(status)); if (errorPage!=null) { return errorPage.getLocation(); } return null; } /** * Return the set of HTTP status codes for which error pages have * been specified. If none are specified, a zero-length array * is returned. */ @Override public int[] findStatusPages() { synchronized (statusPages) { int results[] = new int[statusPages.size()]; Iterator elements = statusPages.keySet().iterator(); int i = 0; while (elements.hasNext()) results[i++] = elements.next().intValue(); return (results); } } /** * Return true if the specified welcome file is defined * for this Context; otherwise return false. * * @param name Welcome file to verify */ @Override public boolean findWelcomeFile(String name) { synchronized (welcomeFilesLock) { for (int i = 0; i < welcomeFiles.length; i++) { if (name.equals(welcomeFiles[i])) return (true); } } return (false); } /** * Return the set of watched resources for this Context. If none are * defined, a zero length array will be returned. */ @Override public String[] findWatchedResources() { synchronized (watchedResourcesLock) { return watchedResources; } } /** * Return the set of welcome files defined for this Context. If none are * defined, a zero-length array is returned. */ @Override public String[] findWelcomeFiles() { synchronized (welcomeFilesLock) { return (welcomeFiles); } } /** * Return the set of LifecycleListener classes that will be added to * newly created Wrappers automatically. */ @Override public String[] findWrapperLifecycles() { synchronized (wrapperLifecyclesLock) { return (wrapperLifecycles); } } /** * Return the set of ContainerListener classes that will be added to * newly created Wrappers automatically. */ @Override public String[] findWrapperListeners() { synchronized (wrapperListenersLock) { return (wrapperListeners); } } /** * Reload this web application, if reloading is supported. *

    * IMPLEMENTATION NOTE: This method is designed to deal with * reloads required by changes to classes in the underlying repositories * of our class loader and changes to the web.xml file. It does not handle * changes to any context.xml file. If the context.xml has changed, you * should stop this Context and create (and start) a new Context instance * instead. Note that there is additional code in * CoyoteAdapter#postParseRequest() to handle mapping requests * to paused Contexts. * * @exception IllegalStateException if the reloadable * property is set to false. */ @Override public synchronized void reload() { // Validate our current component state if (!getState().isAvailable()) throw new IllegalStateException (sm.getString("standardContext.notStarted", getName())); if(log.isInfoEnabled()) log.info(sm.getString("standardContext.reloadingStarted", getName())); // Stop accepting requests temporarily. setPaused(true); try { stop(); } catch (LifecycleException e) { log.error( sm.getString("standardContext.stoppingContext", getName()), e); } try { start(); } catch (LifecycleException e) { log.error( sm.getString("standardContext.startingContext", getName()), e); } setPaused(false); if(log.isInfoEnabled()) log.info(sm.getString("standardContext.reloadingCompleted", getName())); } /** * Remove the specified application listener class from the set of * listeners for this application. * * @param listener Java class name of the listener to be removed */ @Override public void removeApplicationListener(String listener) { synchronized (applicationListenersLock) { // Make sure this welcome file is currently present int n = -1; for (int i = 0; i < applicationListeners.length; i++) { if (applicationListeners[i].getClassName().equals(listener)) { n = i; break; } } if (n < 0) return; // Remove the specified constraint int j = 0; ApplicationListener results[] = new ApplicationListener[applicationListeners.length - 1]; for (int i = 0; i < applicationListeners.length; i++) { if (i != n) results[j++] = applicationListeners[i]; } applicationListeners = results; } // Inform interested listeners fireContainerEvent("removeApplicationListener", listener); // FIXME - behavior if already started? } /** * Remove the application parameter with the specified name from * the set for this application. * * @param name Name of the application parameter to remove */ @Override public void removeApplicationParameter(String name) { synchronized (applicationParametersLock) { // Make sure this parameter is currently present int n = -1; for (int i = 0; i < applicationParameters.length; i++) { if (name.equals(applicationParameters[i].getName())) { n = i; break; } } if (n < 0) return; // Remove the specified parameter int j = 0; ApplicationParameter results[] = new ApplicationParameter[applicationParameters.length - 1]; for (int i = 0; i < applicationParameters.length; i++) { if (i != n) results[j++] = applicationParameters[i]; } applicationParameters = results; } // Inform interested listeners fireContainerEvent("removeApplicationParameter", name); } /** * Add a child Container, only if the proposed child is an implementation * of Wrapper. * * @param child Child container to be added * * @exception IllegalArgumentException if the proposed container is * not an implementation of Wrapper */ @Override public void removeChild(Container child) { if (!(child instanceof Wrapper)) { throw new IllegalArgumentException (sm.getString("standardContext.notWrapper")); } super.removeChild(child); } /** * Remove the specified security constraint from this web application. * * @param constraint Constraint to be removed */ @Override public void removeConstraint(SecurityConstraint constraint) { synchronized (constraintsLock) { // Make sure this constraint is currently present int n = -1; for (int i = 0; i < constraints.length; i++) { if (constraints[i].equals(constraint)) { n = i; break; } } if (n < 0) return; // Remove the specified constraint int j = 0; SecurityConstraint results[] = new SecurityConstraint[constraints.length - 1]; for (int i = 0; i < constraints.length; i++) { if (i != n) results[j++] = constraints[i]; } constraints = results; } // Inform interested listeners fireContainerEvent("removeConstraint", constraint); } /** * Remove the error page for the specified error code or * Java language exception, if it exists; otherwise, no action is taken. * * @param errorPage The error page definition to be removed */ @Override public void removeErrorPage(ErrorPage errorPage) { String exceptionType = errorPage.getExceptionType(); if (exceptionType != null) { synchronized (exceptionPages) { exceptionPages.remove(exceptionType); } } else { synchronized (statusPages) { if (errorPage.getErrorCode() == 200) { this.okErrorPage = null; } statusPages.remove(Integer.valueOf(errorPage.getErrorCode())); } } fireContainerEvent("removeErrorPage", errorPage); } /** * Remove the specified filter definition from this Context, if it exists; * otherwise, no action is taken. * * @param filterDef Filter definition to be removed */ @Override public void removeFilterDef(FilterDef filterDef) { synchronized (filterDefs) { filterDefs.remove(filterDef.getFilterName()); } fireContainerEvent("removeFilterDef", filterDef); } /** * Remove a filter mapping from this Context. * * @param filterMap The filter mapping to be removed */ @Override public void removeFilterMap(FilterMap filterMap) { filterMaps.remove(filterMap); // Inform interested listeners fireContainerEvent("removeFilterMap", filterMap); } /** * Remove a class name from the set of InstanceListener classes that * will be added to newly created Wrappers. * * @param listener Class name of an InstanceListener class to be removed */ @Override public void removeInstanceListener(String listener) { synchronized (instanceListenersLock) { // Make sure this welcome file is currently present int n = -1; for (int i = 0; i < instanceListeners.length; i++) { if (instanceListeners[i].equals(listener)) { n = i; break; } } if (n < 0) return; // Remove the specified constraint int j = 0; String results[] = new String[instanceListeners.length - 1]; for (int i = 0; i < instanceListeners.length; i++) { if (i != n) results[j++] = instanceListeners[i]; } instanceListeners = results; } // Inform interested listeners fireContainerEvent("removeInstanceListener", listener); } /** * Remove any message destination with the specified name. * * @param name Name of the message destination to remove */ public void removeMessageDestination(String name) { synchronized (messageDestinations) { messageDestinations.remove(name); } fireContainerEvent("removeMessageDestination", name); } /** * Remove any message destination ref with the specified name. * * @param name Name of the message destination ref to remove */ public void removeMessageDestinationRef(String name) { namingResources.removeMessageDestinationRef(name); fireContainerEvent("removeMessageDestinationRef", name); } /** * Remove the MIME mapping for the specified extension, if it exists; * otherwise, no action is taken. * * @param extension Extension to remove the mapping for */ @Override public void removeMimeMapping(String extension) { synchronized (mimeMappings) { mimeMappings.remove(extension); } fireContainerEvent("removeMimeMapping", extension); } /** * Remove the context initialization parameter with the specified * name, if it exists; otherwise, no action is taken. * * @param name Name of the parameter to remove */ @Override public void removeParameter(String name) { synchronized (parameters) { parameters.remove(name); } fireContainerEvent("removeParameter", name); } /** * Remove any security role reference for the specified name * * @param role Security role (as used in the application) to remove */ @Override public void removeRoleMapping(String role) { synchronized (roleMappings) { roleMappings.remove(role); } fireContainerEvent("removeRoleMapping", role); } /** * Remove any security role with the specified name. * * @param role Security role to remove */ @Override public void removeSecurityRole(String role) { synchronized (securityRolesLock) { // Make sure this security role is currently present int n = -1; for (int i = 0; i < securityRoles.length; i++) { if (role.equals(securityRoles[i])) { n = i; break; } } if (n < 0) return; // Remove the specified security role int j = 0; String results[] = new String[securityRoles.length - 1]; for (int i = 0; i < securityRoles.length; i++) { if (i != n) results[j++] = securityRoles[i]; } securityRoles = results; } // Inform interested listeners fireContainerEvent("removeSecurityRole", role); } /** * Remove any servlet mapping for the specified pattern, if it exists; * otherwise, no action is taken. * * @param pattern URL pattern of the mapping to remove */ @Override public void removeServletMapping(String pattern) { String name = null; synchronized (servletMappingsLock) { name = servletMappings.remove(pattern); } Wrapper wrapper = (Wrapper) findChild(name); if( wrapper != null ) { wrapper.removeMapping(pattern); } mapper.removeWrapper(pattern); fireContainerEvent("removeServletMapping", pattern); } /** * Remove the specified watched resource name from the list associated * with this Context. * * @param name Name of the watched resource to be removed */ @Override public void removeWatchedResource(String name) { synchronized (watchedResourcesLock) { // Make sure this watched resource is currently present int n = -1; for (int i = 0; i < watchedResources.length; i++) { if (watchedResources[i].equals(name)) { n = i; break; } } if (n < 0) return; // Remove the specified watched resource int j = 0; String results[] = new String[watchedResources.length - 1]; for (int i = 0; i < watchedResources.length; i++) { if (i != n) results[j++] = watchedResources[i]; } watchedResources = results; } fireContainerEvent("removeWatchedResource", name); } /** * Remove the specified welcome file name from the list recognized * by this Context. * * @param name Name of the welcome file to be removed */ @Override public void removeWelcomeFile(String name) { synchronized (welcomeFilesLock) { // Make sure this welcome file is currently present int n = -1; for (int i = 0; i < welcomeFiles.length; i++) { if (welcomeFiles[i].equals(name)) { n = i; break; } } if (n < 0) return; // Remove the specified constraint int j = 0; String results[] = new String[welcomeFiles.length - 1]; for (int i = 0; i < welcomeFiles.length; i++) { if (i != n) results[j++] = welcomeFiles[i]; } welcomeFiles = results; } // Inform interested listeners if(this.getState().equals(LifecycleState.STARTED)) fireContainerEvent(REMOVE_WELCOME_FILE_EVENT, name); } /** * Remove a class name from the set of LifecycleListener classes that * will be added to newly created Wrappers. * * @param listener Class name of a LifecycleListener class to be removed */ @Override public void removeWrapperLifecycle(String listener) { synchronized (wrapperLifecyclesLock) { // Make sure this welcome file is currently present int n = -1; for (int i = 0; i < wrapperLifecycles.length; i++) { if (wrapperLifecycles[i].equals(listener)) { n = i; break; } } if (n < 0) return; // Remove the specified constraint int j = 0; String results[] = new String[wrapperLifecycles.length - 1]; for (int i = 0; i < wrapperLifecycles.length; i++) { if (i != n) results[j++] = wrapperLifecycles[i]; } wrapperLifecycles = results; } // Inform interested listeners fireContainerEvent("removeWrapperLifecycle", listener); } /** * Remove a class name from the set of ContainerListener classes that * will be added to newly created Wrappers. * * @param listener Class name of a ContainerListener class to be removed */ @Override public void removeWrapperListener(String listener) { synchronized (wrapperListenersLock) { // Make sure this welcome file is currently present int n = -1; for (int i = 0; i < wrapperListeners.length; i++) { if (wrapperListeners[i].equals(listener)) { n = i; break; } } if (n < 0) return; // Remove the specified constraint int j = 0; String results[] = new String[wrapperListeners.length - 1]; for (int i = 0; i < wrapperListeners.length; i++) { if (i != n) results[j++] = wrapperListeners[i]; } wrapperListeners = results; } // Inform interested listeners fireContainerEvent("removeWrapperListener", listener); } /** * Gets the cumulative processing times of all servlets in this * StandardContext. * * @return Cumulative processing times of all servlets in this * StandardContext */ public long getProcessingTime() { long result = 0; Container[] children = findChildren(); if (children != null) { for( int i=0; i< children.length; i++ ) { result += ((StandardWrapper)children[i]).getProcessingTime(); } } return result; } /** * Gets the maximum processing time of all servlets in this * StandardContext. * * @return Maximum processing time of all servlets in this * StandardContext */ public long getMaxTime() { long result = 0; long time; Container[] children = findChildren(); if (children != null) { for( int i=0; i< children.length; i++ ) { time = ((StandardWrapper)children[i]).getMaxTime(); if (time > result) result = time; } } return result; } /** * Gets the minimum processing time of all servlets in this * StandardContext. * * @return Minimum processing time of all servlets in this * StandardContext */ public long getMinTime() { long result = -1; long time; Container[] children = findChildren(); if (children != null) { for( int i=0; i< children.length; i++ ) { time = ((StandardWrapper)children[i]).getMinTime(); if (result < 0 || time < result) result = time; } } return result; } /** * Gets the cumulative request count of all servlets in this * StandardContext. * * @return Cumulative request count of all servlets in this * StandardContext */ public int getRequestCount() { int result = 0; Container[] children = findChildren(); if (children != null) { for( int i=0; i< children.length; i++ ) { result += ((StandardWrapper)children[i]).getRequestCount(); } } return result; } /** * Gets the cumulative error count of all servlets in this * StandardContext. * * @return Cumulative error count of all servlets in this * StandardContext */ public int getErrorCount() { int result = 0; Container[] children = findChildren(); if (children != null) { for( int i=0; i< children.length; i++ ) { result += ((StandardWrapper)children[i]).getErrorCount(); } } return result; } /** * Return the real path for a given virtual path, if possible; otherwise * return null. * * @param path The path to the desired resource */ @Override public String getRealPath(String path) { if (webappResources instanceof BaseDirContext) { return ((BaseDirContext) webappResources).getRealPath(path); } return null; } /** * hook to register that we need to scan for security annotations. * @param wrapper The wrapper for the Servlet that was added */ public ServletRegistration.Dynamic dynamicServletAdded(Wrapper wrapper) { Servlet s = wrapper.getServlet(); if (s != null && createdServlets.contains(s)) { // Mark the wrapper to indicate annotations need to be scanned wrapper.setServletSecurityAnnotationScanRequired(true); } return new ApplicationServletRegistration(wrapper, this); } /** * hook to track which registrations need annotation scanning * @param servlet */ public void dynamicServletCreated(Servlet servlet) { createdServlets.add(servlet); } /** * A helper class to manage the filter mappings in a Context. */ private static final class ContextFilterMaps { private final Object lock = new Object(); /** * The set of filter mappings for this application, in the order they * were defined in the deployment descriptor with additional mappings * added via the {@link ServletContext} possibly both before and after * those defined in the deployment descriptor. */ private FilterMap[] array = new FilterMap[0]; /** * Filter mappings added via {@link ServletContext} may have to be * inserted before the mappings in the deployment descriptor but must be * inserted in the order the {@link ServletContext} methods are called. * This isn't an issue for the mappings added after the deployment * descriptor - they are just added to the end - but correctly the * adding mappings before the deployment descriptor mappings requires * knowing where the last 'before' mapping was added. */ private int insertPoint = 0; /** * Return the set of filter mappings. */ public FilterMap[] asArray() { synchronized (lock) { return array; } } /** * Add a filter mapping at the end of the current set of filter * mappings. * * @param filterMap * The filter mapping to be added */ public void add(FilterMap filterMap) { synchronized (lock) { FilterMap results[] = Arrays.copyOf(array, array.length + 1); results[array.length] = filterMap; array = results; } } /** * Add a filter mapping before the mappings defined in the deployment * descriptor but after any other mappings added via this method. * * @param filterMap * The filter mapping to be added */ public void addBefore(FilterMap filterMap) { synchronized (lock) { FilterMap results[] = new FilterMap[array.length + 1]; System.arraycopy(array, 0, results, 0, insertPoint); System.arraycopy(array, insertPoint, results, insertPoint + 1, array.length - insertPoint); results[insertPoint] = filterMap; array = results; insertPoint++; } } /** * Remove a filter mapping. * * @param filterMap The filter mapping to be removed */ public void remove(FilterMap filterMap) { synchronized (lock) { // Make sure this filter mapping is currently present int n = -1; for (int i = 0; i < array.length; i++) { if (array[i] == filterMap) { n = i; break; } } if (n < 0) return; // Remove the specified filter mapping FilterMap results[] = new FilterMap[array.length - 1]; System.arraycopy(array, 0, results, 0, n); System.arraycopy(array, n + 1, results, n, (array.length - 1) - n); array = results; if (n < insertPoint) { insertPoint--; } } } } // --------------------------------------------------------- Public Methods /** * Configure and initialize the set of filters for this Context. * Return true if all filter initialization completed * successfully, or false otherwise. */ public boolean filterStart() { if (getLogger().isDebugEnabled()) getLogger().debug("Starting filters"); // Instantiate and record a FilterConfig for each defined filter boolean ok = true; synchronized (filterConfigs) { filterConfigs.clear(); Iterator names = filterDefs.keySet().iterator(); while (names.hasNext()) { String name = names.next(); if (getLogger().isDebugEnabled()) getLogger().debug(" Starting filter '" + name + "'"); ApplicationFilterConfig filterConfig = null; try { filterConfig = new ApplicationFilterConfig(this, filterDefs.get(name)); filterConfigs.put(name, filterConfig); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); getLogger().error (sm.getString("standardContext.filterStart", name), t); ok = false; } } } return (ok); } /** * Finalize and release the set of filters for this Context. * Return true if all filter finalization completed * successfully, or false otherwise. */ public boolean filterStop() { if (getLogger().isDebugEnabled()) getLogger().debug("Stopping filters"); // Release all Filter and FilterConfig instances synchronized (filterConfigs) { Iterator names = filterConfigs.keySet().iterator(); while (names.hasNext()) { String name = names.next(); if (getLogger().isDebugEnabled()) getLogger().debug(" Stopping filter '" + name + "'"); ApplicationFilterConfig filterConfig = filterConfigs.get(name); filterConfig.release(); } filterConfigs.clear(); } return (true); } /** * Find and return the initialized FilterConfig for the * specified filter name, if any; otherwise return null. * * @param name Name of the desired filter */ public FilterConfig findFilterConfig(String name) { return (filterConfigs.get(name)); } /** * Configure the set of instantiated application event listeners * for this Context. Return true if all listeners wre * initialized successfully, or false otherwise. */ public boolean listenerStart() { if (log.isDebugEnabled()) log.debug("Configuring application event listeners"); // Instantiate the required listeners ApplicationListener listeners[] = applicationListeners; Object results[] = new Object[listeners.length]; boolean ok = true; Set noPluggabilityListeners = new HashSet(); for (int i = 0; i < results.length; i++) { if (getLogger().isDebugEnabled()) getLogger().debug(" Configuring event listener class '" + listeners[i] + "'"); try { ApplicationListener listener = listeners[i]; results[i] = instanceManager.newInstance( listener.getClassName()); if (listener.isPluggabilityBlocked()) { noPluggabilityListeners.add(results[i]); } } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); getLogger().error (sm.getString("standardContext.applicationListener", listeners[i].getClassName()), t); ok = false; } } if (!ok) { getLogger().error(sm.getString("standardContext.applicationSkipped")); return (false); } // Sort listeners in two arrays ArrayList eventListeners = new ArrayList(); ArrayList lifecycleListeners = new ArrayList(); for (int i = 0; i < results.length; i++) { if ((results[i] instanceof ServletContextAttributeListener) || (results[i] instanceof ServletRequestAttributeListener) || (results[i] instanceof ServletRequestListener) || (results[i] instanceof HttpSessionAttributeListener)) { eventListeners.add(results[i]); } if ((results[i] instanceof ServletContextListener) || (results[i] instanceof HttpSessionListener)) { lifecycleListeners.add(results[i]); } } // Listener instances may have been added directly to this Context by // ServletContextInitializers and other code via the pluggability APIs. // Put them these listeners after the ones defined in web.xml and/or // annotations then overwrite the list of instances with the new, full // list. for (Object eventListener: getApplicationEventListeners()) { eventListeners.add(eventListener); } setApplicationEventListeners(eventListeners.toArray()); for (Object lifecycleListener: getApplicationLifecycleListeners()) { lifecycleListeners.add(lifecycleListener); if (lifecycleListener instanceof ServletContextListener) { noPluggabilityListeners.add(lifecycleListener); } } setApplicationLifecycleListeners(lifecycleListeners.toArray()); // Send application start events if (getLogger().isDebugEnabled()) getLogger().debug("Sending application start events"); // Ensure context is not null getServletContext(); context.setNewServletContextListenerAllowed(false); Object instances[] = getApplicationLifecycleListeners(); if (instances == null || instances.length == 0) { return ok; } ServletContextEvent event = new ServletContextEvent(getServletContext()); ServletContextEvent tldEvent = null; if (noPluggabilityListeners.size() > 0) { tldEvent = new ServletContextEvent(new NoPluggabilityServletContext( getServletContext())); } for (int i = 0; i < instances.length; i++) { if (instances[i] == null) continue; if (!(instances[i] instanceof ServletContextListener)) continue; ServletContextListener listener = (ServletContextListener) instances[i]; try { fireContainerEvent("beforeContextInitialized", listener); if (noPluggabilityListeners.contains(listener)) { listener.contextInitialized(tldEvent); } else { listener.contextInitialized(event); } fireContainerEvent("afterContextInitialized", listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); fireContainerEvent("afterContextInitialized", listener); getLogger().error (sm.getString("standardContext.listenerStart", instances[i].getClass().getName()), t); ok = false; } } return (ok); } /** * Send an application stop event to all interested listeners. * Return true if all events were sent successfully, * or false otherwise. */ public boolean listenerStop() { if (log.isDebugEnabled()) log.debug("Sending application stop events"); boolean ok = true; Object listeners[] = getApplicationLifecycleListeners(); if (listeners != null) { ServletContextEvent event = new ServletContextEvent(getServletContext()); for (int i = 0; i < listeners.length; i++) { int j = (listeners.length - 1) - i; if (listeners[j] == null) continue; if (listeners[j] instanceof ServletContextListener) { ServletContextListener listener = (ServletContextListener) listeners[j]; try { fireContainerEvent("beforeContextDestroyed", listener); listener.contextDestroyed(event); fireContainerEvent("afterContextDestroyed", listener); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); fireContainerEvent("afterContextDestroyed", listener); getLogger().error (sm.getString("standardContext.listenerStop", listeners[j].getClass().getName()), t); ok = false; } } try { getInstanceManager().destroyInstance(listeners[j]); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); getLogger().error (sm.getString("standardContext.listenerStop", listeners[j].getClass().getName()), t); ok = false; } } } // Annotation processing listeners = getApplicationEventListeners(); if (listeners != null) { for (int i = 0; i < listeners.length; i++) { int j = (listeners.length - 1) - i; if (listeners[j] == null) continue; try { getInstanceManager().destroyInstance(listeners[j]); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); getLogger().error (sm.getString("standardContext.listenerStop", listeners[j].getClass().getName()), t); ok = false; } } } setApplicationEventListeners(null); setApplicationLifecycleListeners(null); return (ok); } /** * Allocate resources, including proxy. * Return true if initialization was successfull, * or false otherwise. */ public boolean resourcesStart() { boolean ok = true; Hashtable env = new Hashtable(); if (getParent() != null) env.put(ProxyDirContext.HOST, getParent().getName()); env.put(ProxyDirContext.CONTEXT, getName()); try { ProxyDirContext proxyDirContext = new ProxyDirContext(env, webappResources); if (webappResources instanceof FileDirContext) { filesystemBased = true; ((FileDirContext) webappResources).setAllowLinking (isAllowLinking()); } if (webappResources instanceof BaseDirContext) { ((BaseDirContext) webappResources).setDocBase(getBasePath()); ((BaseDirContext) webappResources).setCached (isCachingAllowed()); ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL()); ((BaseDirContext) webappResources).setCacheMaxSize (getCacheMaxSize()); ((BaseDirContext) webappResources).allocate(); // Alias support ((BaseDirContext) webappResources).setAliases(getAliases()); if (effectiveMajorVersion >=3 && addWebinfClassesResources) { try { DirContext webInfCtx = (DirContext) webappResources.lookup( "/WEB-INF/classes"); // Do the lookup to make sure it exists webInfCtx.lookup("META-INF/resources"); ((BaseDirContext) webappResources).addAltDirContext( webInfCtx); } catch (NamingException e) { // Doesn't exist - ignore and carry on } } } // Register the cache in JMX if (isCachingAllowed()) { String contextName = getName(); if (!contextName.startsWith("/")) { contextName = "/" + contextName; } ObjectName resourcesName = new ObjectName(this.getDomain() + ":type=Cache,host=" + getHostname() + ",context=" + contextName); Registry.getRegistry(null, null).registerComponent (proxyDirContext.getCache(), resourcesName, null); } this.resources = proxyDirContext; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("standardContext.resourcesStart"), t); ok = false; } return (ok); } /** * Deallocate resources and destroy proxy. */ public boolean resourcesStop() { boolean ok = true; try { if (resources != null) { if (resources instanceof Lifecycle) { ((Lifecycle) resources).stop(); } if (webappResources instanceof BaseDirContext) { ((BaseDirContext) webappResources).release(); } // Unregister the cache in JMX if (isCachingAllowed()) { String contextName = getName(); if (!contextName.startsWith("/")) { contextName = "/" + contextName; } ObjectName resourcesName = new ObjectName(this.getDomain() + ":type=Cache,host=" + getHostname() + ",context=" + contextName); Registry.getRegistry(null, null) .unregisterComponent(resourcesName); } } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("standardContext.resourcesStop"), t); ok = false; } this.resources = null; return (ok); } /** * Load and initialize all servlets marked "load on startup" in the * web application deployment descriptor. * * @param children Array of wrappers for all currently defined * servlets (including those not declared load on startup) */ public void loadOnStartup(Container children[]) { // Collect "load on startup" servlets that need to be initialized TreeMap> map = new TreeMap>(); for (int i = 0; i < children.length; i++) { Wrapper wrapper = (Wrapper) children[i]; int loadOnStartup = wrapper.getLoadOnStartup(); if (loadOnStartup < 0) continue; Integer key = Integer.valueOf(loadOnStartup); ArrayList list = map.get(key); if (list == null) { list = new ArrayList(); map.put(key, list); } list.add(wrapper); } // Load the collected "load on startup" servlets for (ArrayList list : map.values()) { for (Wrapper wrapper : list) { try { wrapper.load(); } catch (ServletException e) { getLogger().error(sm.getString("standardWrapper.loadException", getName()), StandardWrapper.getRootCause(e)); // NOTE: load errors (including a servlet that throws // UnavailableException from tht init() method) are NOT // fatal to application startup } } } } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { if(log.isDebugEnabled()) log.debug("Starting " + getBaseName()); // Send j2ee.state.starting notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.starting", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } setConfigured(false); boolean ok = true; // Currently this is effectively a NO-OP but needs to be called to // ensure the NamingResources follows the correct lifecycle if (namingResources != null) { namingResources.start(); } // Add missing components as necessary if (webappResources == null) { // (1) Required by Loader if (log.isDebugEnabled()) log.debug("Configuring default Resources"); try { if ((getDocBase() != null) && (getDocBase().endsWith(".war")) && (!(new File(getBasePath())).isDirectory())) setResources(new WARDirContext()); else setResources(new FileDirContext()); } catch (IllegalArgumentException e) { log.error("Error initializing resources: " + e.getMessage()); ok = false; } } if (ok) { if (!resourcesStart()) { throw new LifecycleException("Error in resourceStart()"); } } if (getLoader() == null) { WebappLoader webappLoader = new WebappLoader(getParentClassLoader()); webappLoader.setDelegate(getDelegate()); setLoader(webappLoader); } // Initialize character set mapper getCharsetMapper(); // Post work directory postWorkDirectory(); // Validate required extensions boolean dependencyCheck = true; try { dependencyCheck = ExtensionValidator.validateApplication (getResources(), this); } catch (IOException ioe) { log.error("Error in dependencyCheck", ioe); dependencyCheck = false; } if (!dependencyCheck) { // do not make application available if depency check fails ok = false; } // Reading the "catalina.useNaming" environment variable String useNamingProperty = System.getProperty("catalina.useNaming"); if ((useNamingProperty != null) && (useNamingProperty.equals("false"))) { useNaming = false; } if (ok && isUseNaming()) { if (getNamingContextListener() == null) { NamingContextListener ncl = new NamingContextListener(); ncl.setName(getNamingContextName()); ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite()); addLifecycleListener(ncl); setNamingContextListener(ncl); } } // Standard container startup if (log.isDebugEnabled()) log.debug("Processing standard container startup"); // Binding thread ClassLoader oldCCL = bindThread(); try { if (ok) { // Start our subordinate components, if any if ((loader != null) && (loader instanceof Lifecycle)) ((Lifecycle) loader).start(); // since the loader just started, the webapp classloader is now // created. // By calling unbindThread and bindThread in a row, we setup the // current Thread CCL to be the webapp classloader unbindThread(oldCCL); oldCCL = bindThread(); // Initialize logger again. Other components might have used it // too early, so it should be reset. logger = null; getLogger(); if ((cluster != null) && (cluster instanceof Lifecycle)) ((Lifecycle) cluster).start(); Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); if ((resources != null) && (resources instanceof Lifecycle)) ((Lifecycle) resources).start(); // Notify our interested LifecycleListeners fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); // Start our child containers, if not already started for (Container child : findChildren()) { if (!child.getState().isAvailable()) { child.start(); } } // Start the Valves in our pipeline (including the basic), // if any if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).start(); } // Acquire clustered manager Manager contextManager = null; if (manager == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("standardContext.cluster.noManager", Boolean.valueOf((getCluster() != null)), Boolean.valueOf(distributable))); } if ( (getCluster() != null) && distributable) { try { contextManager = getCluster().createManager(getName()); } catch (Exception ex) { log.error("standardContext.clusterFail", ex); ok = false; } } else { contextManager = new StandardManager(); } } // Configure default manager if none was specified if (contextManager != null) { if (log.isDebugEnabled()) { log.debug(sm.getString("standardContext.manager", contextManager.getClass().getName())); } setManager(contextManager); } if (manager!=null && (getCluster() != null) && distributable) { //let the cluster know that there is a context that is distributable //and that it has its own manager getCluster().registerManager(manager); } } } finally { // Unbinding thread unbindThread(oldCCL); } if (!getConfigured()) { log.error( "Error getConfigured"); ok = false; } // We put the resources into the servlet context if (ok) getServletContext().setAttribute (Globals.RESOURCES_ATTR, getResources()); // Initialize associated mapper mapper.setContext(getPath(), welcomeFiles, resources); // Binding thread oldCCL = bindThread(); if (ok ) { if (getInstanceManager() == null) { javax.naming.Context context = null; if (isUseNaming() && getNamingContextListener() != null) { context = getNamingContextListener().getEnvContext(); } Map> injectionMap = buildInjectionMap( getIgnoreAnnotations() ? new NamingResources(): getNamingResources()); setInstanceManager(new DefaultInstanceManager(context, injectionMap, this, this.getClass().getClassLoader())); getServletContext().setAttribute( InstanceManager.class.getName(), getInstanceManager()); } } try { // Create context attributes that will be required if (ok) { getServletContext().setAttribute( JarScanner.class.getName(), getJarScanner()); } // Set up the context init params mergeParameters(); // Call ServletContainerInitializers for (Map.Entry>> entry : initializers.entrySet()) { try { entry.getKey().onStartup(entry.getValue(), getServletContext()); } catch (ServletException e) { log.error(sm.getString("standardContext.sciFail"), e); ok = false; break; } } // Configure and call application event listeners if (ok) { if (!listenerStart()) { log.error( "Error listenerStart"); ok = false; } } try { // Start manager if ((manager != null) && (manager instanceof Lifecycle)) { ((Lifecycle) getManager()).start(); } } catch(Exception e) { log.error("Error manager.start()", e); ok = false; } // Configure and call application filters if (ok) { if (!filterStart()) { log.error("Error filterStart"); ok = false; } } // Load and initialize all "load on startup" servlets if (ok) { loadOnStartup(findChildren()); } // Start ContainerBackgroundProcessor thread super.threadStart(); } finally { // Unbinding thread unbindThread(oldCCL); } // Set available status depending upon startup success if (ok) { if (log.isDebugEnabled()) log.debug("Starting completed"); } else { log.error(sm.getString("standardContext.startFailed", getName())); } startTime=System.currentTimeMillis(); // Send j2ee.state.running notification if (ok && (this.getObjectName() != null)) { Notification notification = new Notification("j2ee.state.running", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } // Close all JARs right away to avoid always opening a peak number // of files on startup if (getLoader() instanceof WebappLoader) { ((WebappLoader) getLoader()).closeJARs(true); } // Reinitializing if something went wrong if (!ok) { setState(LifecycleState.FAILED); } else { setState(LifecycleState.STARTING); } } private Map> buildInjectionMap(NamingResources namingResources) { Map> injectionMap = new HashMap>(); for (Injectable resource: namingResources.findLocalEjbs()) { addInjectionTarget(resource, injectionMap); } for (Injectable resource: namingResources.findEjbs()) { addInjectionTarget(resource, injectionMap); } for (Injectable resource: namingResources.findEnvironments()) { addInjectionTarget(resource, injectionMap); } for (Injectable resource: namingResources.findMessageDestinationRefs()) { addInjectionTarget(resource, injectionMap); } for (Injectable resource: namingResources.findResourceEnvRefs()) { addInjectionTarget(resource, injectionMap); } for (Injectable resource: namingResources.findResources()) { addInjectionTarget(resource, injectionMap); } for (Injectable resource: namingResources.findServices()) { addInjectionTarget(resource, injectionMap); } return injectionMap; } private void addInjectionTarget(Injectable resource, Map> injectionMap) { List injectionTargets = resource.getInjectionTargets(); if (injectionTargets != null && injectionTargets.size() > 0) { String jndiName = resource.getName(); for (InjectionTarget injectionTarget: injectionTargets) { String clazz = injectionTarget.getTargetClass(); Map injections = injectionMap.get(clazz); if (injections == null) { injections = new HashMap(); injectionMap.put(clazz, injections); } injections.put(injectionTarget.getTargetName(), jndiName); } } } /** * Merge the context initialization parameters specified in the application * deployment descriptor with the application parameters described in the * server configuration, respecting the override property of * the application parameters appropriately. */ private void mergeParameters() { Map mergedParams = new HashMap(); String names[] = findParameters(); for (int i = 0; i < names.length; i++) { mergedParams.put(names[i], findParameter(names[i])); } ApplicationParameter params[] = findApplicationParameters(); for (int i = 0; i < params.length; i++) { if (params[i].getOverride()) { if (mergedParams.get(params[i].getName()) == null) { mergedParams.put(params[i].getName(), params[i].getValue()); } } else { mergedParams.put(params[i].getName(), params[i].getValue()); } } ServletContext sc = getServletContext(); for (Map.Entry entry : mergedParams.entrySet()) { sc.setInitParameter(entry.getKey(), entry.getValue()); } } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { // Send j2ee.state.stopping notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.stopping", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } setState(LifecycleState.STOPPING); // Binding thread ClassLoader oldCCL = bindThread(); try { // Stop our child containers, if any final Container[] children = findChildren(); ClassLoader old = bindThread(); try { // Stop ContainerBackgroundProcessor thread threadStop(); for (int i = 0; i < children.length; i++) { children[i].stop(); } // Stop our filters filterStop(); if (manager != null && manager instanceof Lifecycle && ((Lifecycle) manager).getState().isAvailable()) { ((Lifecycle) manager).stop(); } // Stop our application listeners listenerStop(); } finally{ unbindThread(old); } // Finalize our character set mapper setCharsetMapper(null); // Normal container shutdown processing if (log.isDebugEnabled()) log.debug("Processing standard container shutdown"); // JNDI resources are unbound in CONFIGURE_STOP_EVENT so stop // naming resoucres before they are unbound since NamingResoucres // does a JNDI lookup to retrieve the resource. This needs to be // after the application has finished with the resource if (namingResources != null) { namingResources.stop(); } fireLifecycleEvent(Lifecycle.CONFIGURE_STOP_EVENT, null); // Stop the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle && ((Lifecycle) pipeline).getState().isAvailable()) { ((Lifecycle) pipeline).stop(); } // Clear all application-originated servlet context attributes if (context != null) context.clearAttributes(); // Stop resources resourcesStop(); Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) { ((Lifecycle) realm).stop(); } if ((cluster != null) && (cluster instanceof Lifecycle)) { ((Lifecycle) cluster).stop(); } if ((loader != null) && (loader instanceof Lifecycle)) { ((Lifecycle) loader).stop(); } } finally { // Unbinding thread unbindThread(oldCCL); } // Send j2ee.state.stopped notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.stopped", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } // Reset application context context = null; // This object will no longer be visible or used. try { resetContext(); } catch( Exception ex ) { log.error( "Error reseting context " + this + " " + ex, ex ); } //reset the instance manager instanceManager = null; if (log.isDebugEnabled()) log.debug("Stopping complete"); } /** Destroy needs to clean up the context completely. * * The problem is that undoing all the config in start() and restoring * a 'fresh' state is impossible. After stop()/destroy()/init()/start() * we should have the same state as if a fresh start was done - i.e * read modified web.xml, etc. This can only be done by completely * removing the context object and remapping a new one, or by cleaning * up everything. * * XXX Should this be done in stop() ? * */ @Override protected void destroyInternal() throws LifecycleException { // If in state NEW when destroy is called, the object name will never // have been set so the notification can't be created if (getObjectName() != null) { // Send j2ee.object.deleted notification Notification notification = new Notification("j2ee.object.deleted", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } if (namingResources != null) { namingResources.destroy(); } synchronized (instanceListenersLock) { instanceListeners = new String[0]; } super.destroyInternal(); } private void resetContext() throws Exception { // Restore the original state ( pre reading web.xml in start ) // If you extend this - override this method and make sure to clean up // Don't reset anything that is read from a element since // elements are read at initialisation will not be read // again for this object for (Container child : findChildren()) { removeChild(child); } startupTime = 0; startTime = 0; tldScanTime = 0; // Bugzilla 32867 distributable = false; applicationListeners = new ApplicationListener[0]; applicationEventListenersObjects = new Object[0]; applicationLifecycleListenersObjects = new Object[0]; jspConfigDescriptor = new ApplicationJspConfigDescriptor(); initializers.clear(); createdServlets.clear(); postConstructMethods.clear(); preDestroyMethods.clear(); if(log.isDebugEnabled()) log.debug("resetContext " + getObjectName()); } /** * Return a String representation of this component. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); if (getParent() != null) { sb.append(getParent().toString()); sb.append("."); } sb.append("StandardContext["); sb.append(getName()); sb.append("]"); return (sb.toString()); } // ------------------------------------------------------ Protected Methods /** * Adjust the URL pattern to begin with a leading slash, if appropriate * (i.e. we are running a servlet 2.2 application). Otherwise, return * the specified URL pattern unchanged. * * @param urlPattern The URL pattern to be adjusted (if needed) * and returned */ protected String adjustURLPattern(String urlPattern) { if (urlPattern == null) return (urlPattern); if (urlPattern.startsWith("/") || urlPattern.startsWith("*.")) return (urlPattern); if (!isServlet22()) return (urlPattern); if(log.isDebugEnabled()) log.debug(sm.getString("standardContext.urlPattern.patternWarning", urlPattern)); return ("/" + urlPattern); } /** * Are we processing a version 2.2 deployment descriptor? */ @Override public boolean isServlet22() { return XmlIdentifiers.WEB_22_PUBLIC.equals(publicId); } @Override public Set addServletSecurity( ApplicationServletRegistration registration, ServletSecurityElement servletSecurityElement) { Set conflicts = new HashSet(); Collection urlPatterns = registration.getMappings(); for (String urlPattern : urlPatterns) { boolean foundConflict = false; SecurityConstraint[] securityConstraints = findConstraints(); for (SecurityConstraint securityConstraint : securityConstraints) { SecurityCollection[] collections = securityConstraint.findCollections(); for (SecurityCollection collection : collections) { if (collection.findPattern(urlPattern)) { // First pattern found will indicate if there is a // conflict since for any given pattern all matching // constraints will be from either the descriptor or // not. It is not permitted to have a mixture if (collection.isFromDescriptor()) { // Skip this pattern foundConflict = true; conflicts.add(urlPattern); } else { // Need to overwrite constraint for this pattern // so remove every pattern found // TODO spec 13.4.2 appears to say only the // conflicting pattern is overwritten, not the // entire security constraint. removeConstraint(securityConstraint); } } if (foundConflict) { break; } } if (foundConflict) { break; } } // TODO spec 13.4.2 appears to say that non-conflicting patterns are // still used. // TODO you can't calculate the eventual security constraint now, // you have to wait until the context is started, since application // code can add url patterns after calling setSecurity. if (!foundConflict) { SecurityConstraint[] newSecurityConstraints = SecurityConstraint.createConstraints( servletSecurityElement, urlPattern); for (SecurityConstraint securityConstraint : newSecurityConstraints) { addConstraint(securityConstraint); } } } return conflicts; } /** * Return a File object representing the base directory for the * entire servlet container (i.e. the Engine container if present). */ protected File engineBase() { String base=System.getProperty(Globals.CATALINA_BASE_PROP); if( base == null ) { StandardEngine eng=(StandardEngine)this.getParent().getParent(); base=eng.getBaseDir(); } return (new File(base)); } /** * Bind current thread, both for CL purposes and for JNDI ENC support * during : startup, shutdown and realoading of the context. * * @return the previous context class loader */ protected ClassLoader bindThread() { ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); if (getResources() == null) return oldContextClassLoader; if (getLoader() != null && getLoader().getClassLoader() != null) { Thread.currentThread().setContextClassLoader (getLoader().getClassLoader()); } DirContextURLStreamHandler.bindThread(getResources()); if (isUseNaming()) { try { ContextBindings.bindThread(this, this); } catch (NamingException e) { // Silent catch, as this is a normal case during the early // startup stages } } return oldContextClassLoader; } /** * Unbind thread. */ protected void unbindThread(ClassLoader oldContextClassLoader) { if (isUseNaming()) { ContextBindings.unbindThread(this, this); } DirContextURLStreamHandler.unbindThread(); Thread.currentThread().setContextClassLoader(oldContextClassLoader); } /** * Get base path. */ protected String getBasePath() { String docBase = null; Container container = this; while (container != null) { if (container instanceof Host) break; container = container.getParent(); } File file = new File(getDocBase()); if (!file.isAbsolute()) { if (container == null) { docBase = (new File(engineBase(), getDocBase())).getPath(); } else { // Use the "appBase" property of this container String appBase = ((Host) container).getAppBase(); file = new File(appBase); if (!file.isAbsolute()) file = new File(engineBase(), appBase); docBase = (new File(file, getDocBase())).getPath(); } } else { docBase = file.getPath(); } return docBase; } /** * Get app base. */ protected String getAppBase() { String appBase = null; Container container = this; while (container != null) { if (container instanceof Host) break; container = container.getParent(); } if (container != null) { appBase = ((Host) container).getAppBase(); } return appBase; } /** * Get naming context full name. */ private String getNamingContextName() { if (namingContextName == null) { Container parent = getParent(); if (parent == null) { namingContextName = getName(); } else { Stack stk = new Stack(); StringBuilder buff = new StringBuilder(); while (parent != null) { stk.push(parent.getName()); parent = parent.getParent(); } while (!stk.empty()) { buff.append("/" + stk.pop()); } buff.append(getName()); namingContextName = buff.toString(); } } return namingContextName; } /** * Naming context listener accessor. */ public NamingContextListener getNamingContextListener() { return namingContextListener; } /** * Naming context listener setter. */ public void setNamingContextListener(NamingContextListener namingContextListener) { this.namingContextListener = namingContextListener; } /** * Return the request processing paused flag for this Context. */ @Override public boolean getPaused() { return (this.paused); } /** * @deprecated Unused. Will be removed in Tomcat 8.0.x. */ @Deprecated public String getHostname() { Container parentHost = getParent(); if (parentHost != null) { hostName = parentHost.getName(); } if ((hostName == null) || (hostName.length() < 1)) hostName = "_"; return hostName; } @Override public boolean fireRequestInitEvent(ServletRequest request) { Object instances[] = getApplicationEventListeners(); if ((instances != null) && (instances.length > 0)) { ServletRequestEvent event = new ServletRequestEvent(getServletContext(), request); for (int i = 0; i < instances.length; i++) { if (instances[i] == null) continue; if (!(instances[i] instanceof ServletRequestListener)) continue; ServletRequestListener listener = (ServletRequestListener) instances[i]; try { listener.requestInitialized(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLogger().error(sm.getString( "standardContext.requestListener.requestInit", instances[i].getClass().getName()), t); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); return false; } } } return true; } @Override public boolean fireRequestDestroyEvent(ServletRequest request) { Object instances[] = getApplicationEventListeners(); if ((instances != null) && (instances.length > 0)) { ServletRequestEvent event = new ServletRequestEvent(getServletContext(), request); for (int i = 0; i < instances.length; i++) { int j = (instances.length -1) -i; if (instances[j] == null) continue; if (!(instances[j] instanceof ServletRequestListener)) continue; ServletRequestListener listener = (ServletRequestListener) instances[j]; try { listener.requestDestroyed(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLogger().error(sm.getString( "standardContext.requestListener.requestInit", instances[j].getClass().getName()), t); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); return false; } } } return true; } @Override public void addPostConstructMethod(String clazz, String method) { if (clazz == null || method == null) throw new IllegalArgumentException( sm.getString("standardContext.postconstruct.required")); if (postConstructMethods.get(clazz) != null) throw new IllegalArgumentException(sm.getString( "standardContext.postconstruct.duplicate", clazz)); postConstructMethods.put(clazz, method); fireContainerEvent("addPostConstructMethod", clazz); } @Override public void removePostConstructMethod(String clazz) { postConstructMethods.remove(clazz); fireContainerEvent("removePostConstructMethod", clazz); } @Override public void addPreDestroyMethod(String clazz, String method) { if (clazz == null || method == null) throw new IllegalArgumentException( sm.getString("standardContext.predestroy.required")); if (preDestroyMethods.get(clazz) != null) throw new IllegalArgumentException(sm.getString( "standardContext.predestroy.duplicate", clazz)); preDestroyMethods.put(clazz, method); fireContainerEvent("addPreDestroyMethod", clazz); } @Override public void removePreDestroyMethod(String clazz) { preDestroyMethods.remove(clazz); fireContainerEvent("removePreDestroyMethod", clazz); } @Override public String findPostConstructMethod(String clazz) { return postConstructMethods.get(clazz); } @Override public String findPreDestroyMethod(String clazz) { return preDestroyMethods.get(clazz); } @Override public Map findPostConstructMethods() { return postConstructMethods; } @Override public Map findPreDestroyMethods() { return preDestroyMethods; } /** * Set the appropriate context attribute for our work directory. */ private void postWorkDirectory() { // Acquire (or calculate) the work directory path String workDir = getWorkDir(); if (workDir == null || workDir.length() == 0) { // Retrieve our parent (normally a host) name String hostName = null; String engineName = null; String hostWorkDir = null; Container parentHost = getParent(); if (parentHost != null) { hostName = parentHost.getName(); if (parentHost instanceof StandardHost) { hostWorkDir = ((StandardHost)parentHost).getWorkDir(); } Container parentEngine = parentHost.getParent(); if (parentEngine != null) { engineName = parentEngine.getName(); } } if ((hostName == null) || (hostName.length() < 1)) hostName = "_"; if ((engineName == null) || (engineName.length() < 1)) engineName = "_"; String temp = getName(); if (temp.startsWith("/")) temp = temp.substring(1); temp = temp.replace('/', '_'); temp = temp.replace('\\', '_'); if (temp.length() < 1) temp = "_"; if (hostWorkDir != null ) { workDir = hostWorkDir + File.separator + temp; } else { workDir = "work" + File.separator + engineName + File.separator + hostName + File.separator + temp; } setWorkDir(workDir); } // Create this directory if necessary File dir = new File(workDir); if (!dir.isAbsolute()) { File catalinaHome = engineBase(); String catalinaHomePath = null; try { catalinaHomePath = catalinaHome.getCanonicalPath(); dir = new File(catalinaHomePath, workDir); } catch (IOException e) { log.warn(sm.getString("standardContext.workCreateException", workDir, catalinaHomePath, getName()), e); } } if (!dir.mkdirs() && !dir.isDirectory()) { log.warn(sm.getString("standardContext.workCreateFail", dir, getName())); } // Set the appropriate servlet context attribute if (context == null) { getServletContext(); } context.setAttribute(ServletContext.TEMPDIR, dir); context.setAttributeReadOnly(ServletContext.TEMPDIR); } /** * Set the request processing paused flag for this Context. * * @param paused The new request processing paused flag */ private void setPaused(boolean paused) { this.paused = paused; } /** * Validate the syntax of a proposed <url-pattern> * for conformance with specification requirements. * * @param urlPattern URL pattern to be validated */ private boolean validateURLPattern(String urlPattern) { if (urlPattern == null) return (false); if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) { return (false); } if (urlPattern.equals("")) { return true; } if (urlPattern.startsWith("*.")) { if (urlPattern.indexOf('/') < 0) { checkUnusualURLPattern(urlPattern); return (true); } else return (false); } if ( (urlPattern.startsWith("/")) && (urlPattern.indexOf("*.") < 0)) { checkUnusualURLPattern(urlPattern); return (true); } else return (false); } /** * Check for unusual but valid <url-pattern>s. * See Bugzilla 34805, 43079 & 43080 */ private void checkUnusualURLPattern(String urlPattern) { if (log.isInfoEnabled()) { if(urlPattern.endsWith("*") && (urlPattern.length() < 2 || urlPattern.charAt(urlPattern.length()-2) != '/')) { log.info("Suspicious url pattern: \"" + urlPattern + "\"" + " in context [" + getName() + "] - see" + " section SRV.11.2 of the Servlet specification" ); } } } // ------------------------------------------------------------- Operations /** * JSR77 deploymentDescriptor attribute * * @return string deployment descriptor */ public String getDeploymentDescriptor() { InputStream stream = null; ServletContext servletContext = getServletContext(); if (servletContext != null) { stream = servletContext.getResourceAsStream( org.apache.catalina.startup.Constants.ApplicationWebXml); } if (stream == null) { return ""; } StringBuilder sb = new StringBuilder(); BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(stream)); String strRead = ""; while (strRead != null) { sb.append(strRead); strRead = br.readLine(); } } catch (IOException e) { return ""; } finally { if (br != null) { try { br.close(); } catch (IOException ioe) {/*Ignore*/} } } return sb.toString(); } /** * JSR77 servlets attribute * * @return list of all servlets ( we know about ) */ public String[] getServlets() { String[] result = null; Container[] children = findChildren(); if (children != null) { result = new String[children.length]; for( int i=0; i< children.length; i++ ) { result[i] = children[i].getObjectName().toString(); } } return result; } @Override protected String getObjectNameKeyProperties() { StringBuilder keyProperties = new StringBuilder("j2eeType=WebModule,"); keyProperties.append(getObjectKeyPropertiesNameOnly()); keyProperties.append(",J2EEApplication="); keyProperties.append(getJ2EEApplication()); keyProperties.append(",J2EEServer="); keyProperties.append(getJ2EEServer()); return keyProperties.toString(); } private String getObjectKeyPropertiesNameOnly() { StringBuilder result = new StringBuilder("name=//"); String hostname = getParent().getName(); if (hostname == null) { result.append("DEFAULT"); } else { result.append(hostname); } String contextName = getName(); if (!contextName.startsWith("/")) { result.append('/'); } result.append(contextName); return result.toString(); } @Override protected void initInternal() throws LifecycleException { super.initInternal(); if (processTlds) { this.addLifecycleListener(new TldConfig()); } // Register the naming resources if (namingResources != null) { namingResources.init(); } // Send j2ee.object.created notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.object.created", this.getObjectName(), sequenceNumber.getAndIncrement()); broadcaster.sendNotification(notification); } } /* Remove a JMX notficationListener * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) */ @Override public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object object) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener,filter,object); } private MBeanNotificationInfo[] notificationInfo; /* Get JMX Broadcaster Info * @TODO use StringManager for international support! * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! * @see javax.management.NotificationBroadcaster#getNotificationInfo() */ @Override public MBeanNotificationInfo[] getNotificationInfo() { // FIXME: i18n if(notificationInfo == null) { notificationInfo = new MBeanNotificationInfo[]{ new MBeanNotificationInfo(new String[] { "j2ee.object.created"}, Notification.class.getName(), "web application is created" ), new MBeanNotificationInfo(new String[] { "j2ee.state.starting"}, Notification.class.getName(), "change web application is starting" ), new MBeanNotificationInfo(new String[] { "j2ee.state.running"}, Notification.class.getName(), "web application is running" ), new MBeanNotificationInfo(new String[] { "j2ee.state.stopping"}, Notification.class.getName(), "web application start to stopped" ), new MBeanNotificationInfo(new String[] { "j2ee.object.stopped"}, Notification.class.getName(), "web application is stopped" ), new MBeanNotificationInfo(new String[] { "j2ee.object.deleted"}, Notification.class.getName(), "web application is deleted" ) }; } return notificationInfo; } /* Add a JMX-NotificationListener * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) */ @Override public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object object) throws IllegalArgumentException { broadcaster.addNotificationListener(listener,filter,object); } /** * Remove a JMX-NotificationListener * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) */ @Override public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener); } // ------------------------------------------------------------- Attributes /** * Return the naming resources associated with this web application. */ @Deprecated public javax.naming.directory.DirContext getStaticResources() { return getResources(); } /** * Return the naming resources associated with this web application. * FIXME: Fooling introspection ... */ @Deprecated public javax.naming.directory.DirContext findStaticResources() { return getResources(); } /** * Return the naming resources associated with this web application. */ public String[] getWelcomeFiles() { return findWelcomeFiles(); } @Override public boolean getXmlNamespaceAware(){ return webXmlNamespaceAware; } @Override public void setXmlNamespaceAware(boolean webXmlNamespaceAware){ this.webXmlNamespaceAware = webXmlNamespaceAware; } @Override public void setXmlValidation(boolean webXmlValidation){ this.webXmlValidation = webXmlValidation; } @Override public boolean getXmlValidation(){ return webXmlValidation; } @Override public boolean getTldNamespaceAware(){ return true; } @Override public void setTldNamespaceAware(boolean tldNamespaceAware){ // NO-OP; } @Override public void setXmlBlockExternal(boolean xmlBlockExternal) { this.xmlBlockExternal = xmlBlockExternal; } @Override public boolean getXmlBlockExternal() { return xmlBlockExternal; } @Override public void setTldValidation(boolean tldValidation){ this.tldValidation = tldValidation; } @Override public boolean getTldValidation(){ return tldValidation; } /** * Sets the process TLDs attribute. * * @param newProcessTlds The new value */ public void setProcessTlds(boolean newProcessTlds) { processTlds = newProcessTlds; } /** * Returns the processTlds attribute value. */ public boolean getProcessTlds() { return processTlds; } /** * Support for "stateManageable" JSR77 */ public boolean isStateManageable() { return true; } @Deprecated public void startRecursive() throws LifecycleException { // nothing to start recursive, the servlets will be started by load-on-startup start(); } /** * The J2EE Server ObjectName this module is deployed on. */ private String server = null; /** * The Java virtual machines on which this module is running. */ private String[] javaVMs = null; public String getServer() { return server; } public String setServer(String server) { return this.server=server; } public String[] getJavaVMs() { return javaVMs; } public String[] setJavaVMs(String[] javaVMs) { return this.javaVMs = javaVMs; } /** * Gets the time this context was started. * * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this * context was started */ public long getStartTime() { return startTime; } @Deprecated public boolean isEventProvider() { return false; } @Deprecated public boolean isStatisticsProvider() { return false; } private static class NoPluggabilityServletContext implements ServletContext { private final ServletContext sc; public NoPluggabilityServletContext(ServletContext sc) { this.sc = sc; } @Override public String getContextPath() { return sc.getContextPath(); } @Override public ServletContext getContext(String uripath) { return sc.getContext(uripath); } @Override public int getMajorVersion() { return sc.getMajorVersion(); } @Override public int getMinorVersion() { return sc.getMinorVersion(); } @Override public int getEffectiveMajorVersion() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public int getEffectiveMinorVersion() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public String getMimeType(String file) { return sc.getMimeType(file); } @Override public Set getResourcePaths(String path) { return sc.getResourcePaths(path); } @Override public URL getResource(String path) throws MalformedURLException { return sc.getResource(path); } @Override public InputStream getResourceAsStream(String path) { return sc.getResourceAsStream(path); } @Override public RequestDispatcher getRequestDispatcher(String path) { return sc.getRequestDispatcher(path); } @Override public RequestDispatcher getNamedDispatcher(String name) { return sc.getNamedDispatcher(name); } @Override @Deprecated public Servlet getServlet(String name) throws ServletException { return sc.getServlet(name); } @Override @Deprecated public Enumeration getServlets() { return sc.getServlets(); } @Override @Deprecated public Enumeration getServletNames() { return sc.getServletNames(); } @Override public void log(String msg) { sc.log(msg); } @Override @Deprecated public void log(Exception exception, String msg) { sc.log(exception, msg); } @Override public void log(String message, Throwable throwable) { sc.log(message, throwable); } @Override public String getRealPath(String path) { return sc.getRealPath(path); } @Override public String getServerInfo() { return sc.getServerInfo(); } @Override public String getInitParameter(String name) { return sc.getInitParameter(name); } @Override public Enumeration getInitParameterNames() { return sc.getInitParameterNames(); } @Override public boolean setInitParameter(String name, String value) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public Object getAttribute(String name) { return sc.getAttribute(name); } @Override public Enumeration getAttributeNames() { return sc.getAttributeNames(); } @Override public void setAttribute(String name, Object object) { sc.setAttribute(name, object); } @Override public void removeAttribute(String name) { sc.removeAttribute(name); } @Override public String getServletContextName() { return sc.getServletContextName(); } @Override public Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public Dynamic addServlet(String servletName, Servlet servlet) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public Dynamic addServlet(String servletName, Class servletClass) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public T createServlet(Class c) throws ServletException { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public ServletRegistration getServletRegistration(String servletName) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public Map getServletRegistrations() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public javax.servlet.FilterRegistration.Dynamic addFilter( String filterName, String className) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public javax.servlet.FilterRegistration.Dynamic addFilter( String filterName, Filter filter) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public javax.servlet.FilterRegistration.Dynamic addFilter( String filterName, Class filterClass) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public T createFilter(Class c) throws ServletException { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public FilterRegistration getFilterRegistration(String filterName) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public Map getFilterRegistrations() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public SessionCookieConfig getSessionCookieConfig() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public void setSessionTrackingModes( Set sessionTrackingModes) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public Set getDefaultSessionTrackingModes() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public Set getEffectiveSessionTrackingModes() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public void addListener(String className) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public void addListener(T t) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public void addListener(Class listenerClass) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public T createListener(Class c) throws ServletException { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public JspConfigDescriptor getJspConfigDescriptor() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public ClassLoader getClassLoader() { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } @Override public void declareRoles(String... roleNames) { throw new UnsupportedOperationException( sm.getString("noPluggabilityServletContext.notAllowed")); } } } tomcat7-7.0.52/java/org/apache/catalina/core/JasperListener.java0000644000175100017510000000473112271471332024404 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * This listener is designed to initialize Jasper before any web applications are * started. * * @author Remy Maucherat * @since 4.1 */ public class JasperListener implements LifecycleListener { private static final Log log = LogFactory.getLog(JasperListener.class); /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ---------------------------------------------- LifecycleListener Methods /** * Primary entry point for startup and shutdown events. * * @param event The event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) { try { // Set JSP factory Class.forName("org.apache.jasper.compiler.JspRuntimeContext", true, this.getClass().getClassLoader()); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // Should not occur, obviously log.warn("Couldn't initialize Jasper", t); } // Another possibility is to do directly: // JspFactory.setDefaultFactory(new JspFactoryImpl()); } } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationHttpResponse.java0000644000175100017510000002340712271471332026275 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import java.util.Locale; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; /** * Wrapper around a javax.servlet.http.HttpServletResponse * that transforms an application response object (which might be the original * one passed to a servlet, or might be based on the 2.3 * javax.servlet.http.HttpServletResponseWrapper class) * back into an internal org.apache.catalina.HttpResponse. *

    * WARNING: Due to Java's lack of support for multiple * inheritance, all of the logic in ApplicationResponse is * duplicated in ApplicationHttpResponse. Make sure that you * keep these two classes in synchronization when making changes! * * @author Craig R. McClanahan */ class ApplicationHttpResponse extends HttpServletResponseWrapper { // ----------------------------------------------------------- Constructors /** * Construct a new wrapped response around the specified servlet response. * * @param response The servlet response being wrapped */ @Deprecated public ApplicationHttpResponse(HttpServletResponse response) { this(response, false); } /** * Construct a new wrapped response around the specified servlet response. * * @param response The servlet response being wrapped * @param included true if this response is being processed * by a RequestDispatcher.include() call */ public ApplicationHttpResponse(HttpServletResponse response, boolean included) { super(response); setIncluded(included); } // ----------------------------------------------------- Instance Variables /** * Is this wrapped response the subject of an include() * call? */ protected boolean included = false; /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.core.ApplicationHttpResponse/1.0"; // ------------------------------------------------ ServletResponse Methods /** * Disallow reset() calls on a included response. * * @exception IllegalStateException if the response has already * been committed */ @Override public void reset() { // If already committed, the wrapped response will throw ISE if (!included || getResponse().isCommitted()) getResponse().reset(); } /** * Disallow setContentLength() calls on an included response. * * @param len The new content length */ @Override public void setContentLength(int len) { if (!included) getResponse().setContentLength(len); } /** * Disallow setContentType() calls on an included response. * * @param type The new content type */ @Override public void setContentType(String type) { if (!included) getResponse().setContentType(type); } /** * Disallow setLocale() calls on an included response. * * @param loc The new locale */ @Override public void setLocale(Locale loc) { if (!included) getResponse().setLocale(loc); } /** * Ignore setBufferSize() calls on an included response. * * @param size The buffer size */ @Override public void setBufferSize(int size) { if (!included) getResponse().setBufferSize(size); } // -------------------------------------------- HttpServletResponse Methods /** * Disallow addCookie() calls on an included response. * * @param cookie The new cookie */ @Override public void addCookie(Cookie cookie) { if (!included) ((HttpServletResponse) getResponse()).addCookie(cookie); } /** * Disallow addDateHeader() calls on an included response. * * @param name The new header name * @param value The new header value */ @Override public void addDateHeader(String name, long value) { if (!included) ((HttpServletResponse) getResponse()).addDateHeader(name, value); } /** * Disallow addHeader() calls on an included response. * * @param name The new header name * @param value The new header value */ @Override public void addHeader(String name, String value) { if (!included) ((HttpServletResponse) getResponse()).addHeader(name, value); } /** * Disallow addIntHeader() calls on an included response. * * @param name The new header name * @param value The new header value */ @Override public void addIntHeader(String name, int value) { if (!included) ((HttpServletResponse) getResponse()).addIntHeader(name, value); } /** * Disallow sendError() calls on an included response. * * @param sc The new status code * * @exception IOException if an input/output error occurs */ @Override public void sendError(int sc) throws IOException { if (!included) ((HttpServletResponse) getResponse()).sendError(sc); } /** * Disallow sendError() calls on an included response. * * @param sc The new status code * @param msg The new message * * @exception IOException if an input/output error occurs */ @Override public void sendError(int sc, String msg) throws IOException { if (!included) ((HttpServletResponse) getResponse()).sendError(sc, msg); } /** * Disallow sendRedirect() calls on an included response. * * @param location The new location * * @exception IOException if an input/output error occurs */ @Override public void sendRedirect(String location) throws IOException { if (!included) ((HttpServletResponse) getResponse()).sendRedirect(location); } /** * Disallow setDateHeader() calls on an included response. * * @param name The new header name * @param value The new header value */ @Override public void setDateHeader(String name, long value) { if (!included) ((HttpServletResponse) getResponse()).setDateHeader(name, value); } /** * Disallow setHeader() calls on an included response. * * @param name The new header name * @param value The new header value */ @Override public void setHeader(String name, String value) { if (!included) ((HttpServletResponse) getResponse()).setHeader(name, value); } /** * Disallow setIntHeader() calls on an included response. * * @param name The new header name * @param value The new header value */ @Override public void setIntHeader(String name, int value) { if (!included) ((HttpServletResponse) getResponse()).setIntHeader(name, value); } /** * Disallow setStatus() calls on an included response. * * @param sc The new status code */ @Override public void setStatus(int sc) { if (!included) ((HttpServletResponse) getResponse()).setStatus(sc); } /** * Disallow setStatus() calls on an included response. * * @param sc The new status code * @param msg The new message * @deprecated As of version 2.1, due to ambiguous meaning of the message * parameter. To set a status code use * setStatus(int), to send an error with a * description use sendError(int, String). */ @Deprecated @Override public void setStatus(int sc, String msg) { if (!included) ((HttpServletResponse) getResponse()).setStatus(sc, msg); } // -------------------------------------------------------- Package Methods /** * Return descriptive information about this implementation. */ public String getInfo() { return (info); } /** * Return the included flag for this response. */ @Deprecated boolean isIncluded() { return (this.included); } /** * Set the included flag for this response. * * @param included The new included flag */ void setIncluded(boolean included) { this.included = included; } /** * Set the response that we are wrapping. * * @param response The new wrapped response */ void setResponse(HttpServletResponse response) { super.setResponse(response); } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationDispatcher.java0000644000175100017510000011737512271471332025735 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import java.io.PrintWriter; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.AsyncDispatcher; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.InstanceEvent; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.ClientAbortException; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.connector.Response; import org.apache.catalina.connector.ResponseFacade; import org.apache.catalina.util.InstanceSupport; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Standard implementation of RequestDispatcher that allows a * request to be forwarded to a different resource to create the ultimate * response, or to include the output of another resource in the response * from this resource. This implementation allows application level servlets * to wrap the request and/or response objects that are passed on to the * called resource, as long as the wrapping classes extend * javax.servlet.ServletRequestWrapper and * javax.servlet.ServletResponseWrapper. * * @author Craig R. McClanahan */ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher { protected static final boolean STRICT_SERVLET_COMPLIANCE; protected static final boolean WRAP_SAME_OBJECT; static { STRICT_SERVLET_COMPLIANCE = Globals.STRICT_SERVLET_COMPLIANCE; String wrapSameObject = System.getProperty( "org.apache.catalina.core.ApplicationDispatcher.WRAP_SAME_OBJECT"); if (wrapSameObject == null) { WRAP_SAME_OBJECT = STRICT_SERVLET_COMPLIANCE; } else { WRAP_SAME_OBJECT = Boolean.valueOf(wrapSameObject).booleanValue(); } } protected class PrivilegedForward implements PrivilegedExceptionAction { private ServletRequest request; private ServletResponse response; PrivilegedForward(ServletRequest request, ServletResponse response) { this.request = request; this.response = response; } @Override public Void run() throws java.lang.Exception { doForward(request,response); return null; } } protected class PrivilegedInclude implements PrivilegedExceptionAction { private ServletRequest request; private ServletResponse response; PrivilegedInclude(ServletRequest request, ServletResponse response) { this.request = request; this.response = response; } @Override public Void run() throws ServletException, IOException { doInclude(request, response); return null; } } protected class PrivilegedDispatch implements PrivilegedExceptionAction { private final ServletRequest request; private final ServletResponse response; PrivilegedDispatch(ServletRequest request, ServletResponse response) { this.request = request; this.response = response; } @Override public Void run() throws ServletException, IOException { doDispatch(request, response); return null; } } /** * Used to pass state when the request dispatcher is used. Using instance * variables causes threading issues and state is too complex to pass and * return single ServletRequest or ServletResponse objects. */ private static class State { State(ServletRequest request, ServletResponse response, boolean including) { this.outerRequest = request; this.outerResponse = response; this.including = including; } /** * The outermost request that will be passed on to the invoked servlet. */ ServletRequest outerRequest = null; /** * The outermost response that will be passed on to the invoked servlet. */ ServletResponse outerResponse = null; /** * The request wrapper we have created and installed (if any). */ ServletRequest wrapRequest = null; /** * The response wrapper we have created and installed (if any). */ ServletResponse wrapResponse = null; /** * Are we performing an include() instead of a forward()? */ boolean including = false; /** * Outermost HttpServletRequest in the chain */ HttpServletRequest hrequest = null; /** * Outermost HttpServletResponse in the chain */ HttpServletResponse hresponse = null; } // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class, configured according to the * specified parameters. If both servletPath and pathInfo are * null, it will be assumed that this RequestDispatcher * was acquired by name, rather than by path. * * @param wrapper The Wrapper associated with the resource that will * be forwarded to or included (required) * @param requestURI The request URI to this resource (if any) * @param servletPath The revised servlet path to this resource (if any) * @param pathInfo The revised extra path information to this resource * (if any) * @param queryString Query string parameters included with this request * (if any) * @param name Servlet name (if a named dispatcher was created) * else null */ public ApplicationDispatcher (Wrapper wrapper, String requestURI, String servletPath, String pathInfo, String queryString, String name) { super(); // Save all of our configuration parameters this.wrapper = wrapper; this.context = (Context) wrapper.getParent(); this.requestURI = requestURI; this.servletPath = servletPath; this.pathInfo = pathInfo; this.queryString = queryString; this.name = name; if (wrapper instanceof StandardWrapper) this.support = ((StandardWrapper) wrapper).getInstanceSupport(); else this.support = new InstanceSupport(wrapper); } // ----------------------------------------------------- Instance Variables /** * The Context this RequestDispatcher is associated with. */ private Context context = null; /** * Descriptive information about this implementation. */ private static final String info = "org.apache.catalina.core.ApplicationDispatcher/1.0"; /** * The servlet name for a named dispatcher. */ private String name = null; /** * The extra path information for this RequestDispatcher. */ private String pathInfo = null; /** * The query string parameters for this RequestDispatcher. */ private String queryString = null; /** * The request URI for this RequestDispatcher. */ private String requestURI = null; /** * The servlet path for this RequestDispatcher. */ private String servletPath = null; /** * The StringManager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The InstanceSupport instance associated with our Wrapper (used to * send "before dispatch" and "after dispatch" events. */ private InstanceSupport support = null; /** * The Wrapper associated with the resource that will be forwarded to * or included. */ private Wrapper wrapper = null; // ------------------------------------------------------------- Properties /** * Return the descriptive information about this implementation. */ public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Forward this request and response to another resource for processing. * Any runtime exception, IOException, or ServletException thrown by the * called servlet will be propagated to the caller. * * @param request The servlet request to be forwarded * @param response The servlet response to be forwarded * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ @Override public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { if (Globals.IS_SECURITY_ENABLED) { try { PrivilegedForward dp = new PrivilegedForward(request,response); AccessController.doPrivileged(dp); } catch (PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; throw (IOException) e; } } else { doForward(request,response); } } private void doForward(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Reset any output that has been buffered, but keep headers/cookies if (response.isCommitted()) { throw new IllegalStateException (sm.getString("applicationDispatcher.forward.ise")); } try { response.resetBuffer(); } catch (IllegalStateException e) { throw e; } // Set up to handle the specified request and response State state = new State(request, response, false); if (WRAP_SAME_OBJECT) { // Check SRV.8.2 / SRV.14.2.5.1 compliance checkSameObjects(request, response); } wrapResponse(state); // Handle an HTTP named dispatcher forward if ((servletPath == null) && (pathInfo == null)) { ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(state); HttpServletRequest hrequest = state.hrequest; wrequest.setRequestURI(hrequest.getRequestURI()); wrequest.setContextPath(hrequest.getContextPath()); wrequest.setServletPath(hrequest.getServletPath()); wrequest.setPathInfo(hrequest.getPathInfo()); wrequest.setQueryString(hrequest.getQueryString()); processRequest(request,response,state); } // Handle an HTTP path-based forward else { ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(state); String contextPath = context.getPath(); HttpServletRequest hrequest = state.hrequest; if (hrequest.getAttribute( RequestDispatcher.FORWARD_REQUEST_URI) == null) { wrequest.setAttribute(RequestDispatcher.FORWARD_REQUEST_URI, hrequest.getRequestURI()); wrequest.setAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH, hrequest.getContextPath()); wrequest.setAttribute(RequestDispatcher.FORWARD_SERVLET_PATH, hrequest.getServletPath()); wrequest.setAttribute(RequestDispatcher.FORWARD_PATH_INFO, hrequest.getPathInfo()); wrequest.setAttribute(RequestDispatcher.FORWARD_QUERY_STRING, hrequest.getQueryString()); } wrequest.setContextPath(contextPath); wrequest.setRequestURI(requestURI); wrequest.setServletPath(servletPath); wrequest.setPathInfo(pathInfo); if (queryString != null) { wrequest.setQueryString(queryString); wrequest.setQueryParams(queryString); } processRequest(request,response,state); } if (request.getAsyncContext() != null) { // An async request was started during the forward, don't close the // response as it may be written to during the async handling return; } // This is not a real close in order to support error processing if (wrapper.getLogger().isDebugEnabled() ) wrapper.getLogger().debug(" Disabling the response for futher output"); if (response instanceof ResponseFacade) { ((ResponseFacade) response).finish(); } else { // Servlet SRV.6.2.2. The Request/Response may have been wrapped // and may no longer be instance of RequestFacade if (wrapper.getLogger().isDebugEnabled()){ wrapper.getLogger().debug( " The Response is vehiculed using a wrapper: " + response.getClass().getName() ); } // Close anyway try { PrintWriter writer = response.getWriter(); writer.close(); } catch (IllegalStateException e) { try { ServletOutputStream stream = response.getOutputStream(); stream.close(); } catch (IllegalStateException f) { // Ignore } catch (IOException f) { // Ignore } } catch (IOException e) { // Ignore } } } /** * Prepare the request based on the filter configuration. * @param request The servlet request we are processing * @param response The servlet response we are creating * @param state The RD state * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ private void processRequest(ServletRequest request, ServletResponse response, State state) throws IOException, ServletException { DispatcherType disInt = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); if (disInt != null) { boolean doInvoke = true; if (context.getFireRequestListenersOnForwards() && !context.fireRequestInitEvent(request)) { doInvoke = false; } if (doInvoke) { if (disInt != DispatcherType.ERROR) { state.outerRequest.setAttribute( Globals.DISPATCHER_REQUEST_PATH_ATTR, getCombinedPath()); state.outerRequest.setAttribute( Globals.DISPATCHER_TYPE_ATTR, DispatcherType.FORWARD); invoke(state.outerRequest, response, state); } else { invoke(state.outerRequest, response, state); } if (context.getFireRequestListenersOnForwards()) { context.fireRequestDestroyEvent(request); } } } } /** * Combine the servletPath and the pathInfo. If pathInfo is * null it is ignored. If servletPath is null then * null is returned. * @return The combined path with pathInfo appended to servletInfo */ private String getCombinedPath() { if (servletPath == null) { return null; } if (pathInfo == null) { return servletPath; } return servletPath + pathInfo; } /** * Include the response from another resource in the current response. * Any runtime exception, IOException, or ServletException thrown by the * called servlet will be propagated to the caller. * * @param request The servlet request that is including this one * @param response The servlet response to be appended to * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ @Override public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { if (Globals.IS_SECURITY_ENABLED) { try { PrivilegedInclude dp = new PrivilegedInclude(request,response); AccessController.doPrivileged(dp); } catch (PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; throw (IOException) e; } } else { doInclude(request, response); } } private void doInclude(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Set up to handle the specified request and response State state = new State(request, response, true); if (WRAP_SAME_OBJECT) { // Check SRV.8.2 / SRV.14.2.5.1 compliance checkSameObjects(request, response); } // Create a wrapped response to use for this request wrapResponse(state); // Handle an HTTP named dispatcher include if (name != null) { ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(state); wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name); if (servletPath != null) wrequest.setServletPath(servletPath); wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.INCLUDE); wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, getCombinedPath()); invoke(state.outerRequest, state.outerResponse, state); } // Handle an HTTP path based include else { ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(state); String contextPath = context.getPath(); if (requestURI != null) wrequest.setAttribute(RequestDispatcher.INCLUDE_REQUEST_URI, requestURI); if (contextPath != null) wrequest.setAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH, contextPath); if (servletPath != null) wrequest.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, servletPath); if (pathInfo != null) wrequest.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, pathInfo); if (queryString != null) { wrequest.setAttribute(RequestDispatcher.INCLUDE_QUERY_STRING, queryString); wrequest.setQueryParams(queryString); } wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.INCLUDE); wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, getCombinedPath()); invoke(state.outerRequest, state.outerResponse, state); } } @Override public void dispatch(ServletRequest request, ServletResponse response) throws ServletException, IOException { if (Globals.IS_SECURITY_ENABLED) { try { PrivilegedDispatch dp = new PrivilegedDispatch(request,response); AccessController.doPrivileged(dp); } catch (PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; throw (IOException) e; } } else { doDispatch(request, response); } } private void doDispatch(ServletRequest request, ServletResponse response) throws ServletException, IOException { // Set up to handle the specified request and response State state = new State(request, response, false); // Create a wrapped response to use for this request wrapResponse(state); ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(state); if (queryString != null) { wrequest.setQueryParams(queryString); } wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.ASYNC); wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, getCombinedPath()); wrequest.setContextPath(context.getPath()); wrequest.setRequestURI(requestURI); wrequest.setServletPath(servletPath); wrequest.setPathInfo(pathInfo); if (queryString != null) { wrequest.setQueryString(queryString); wrequest.setQueryParams(queryString); } invoke(state.outerRequest, state.outerResponse, state); } // -------------------------------------------------------- Private Methods /** * Ask the resource represented by this RequestDispatcher to process * the associated request, and create (or append to) the associated * response. *

    * IMPLEMENTATION NOTE: This implementation assumes * that no filters are applied to a forwarded or included resource, * because they were already done for the original request. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ private void invoke(ServletRequest request, ServletResponse response, State state) throws IOException, ServletException { // Checking to see if the context classloader is the current context // classloader. If it's not, we're saving it, and setting the context // classloader to the Context classloader ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); ClassLoader contextClassLoader = context.getLoader().getClassLoader(); if (oldCCL != contextClassLoader) { Thread.currentThread().setContextClassLoader(contextClassLoader); } else { oldCCL = null; } // Initialize local variables we may need HttpServletResponse hresponse = state.hresponse; Servlet servlet = null; IOException ioException = null; ServletException servletException = null; RuntimeException runtimeException = null; boolean unavailable = false; // Check for the servlet being marked unavailable if (wrapper.isUnavailable()) { wrapper.getLogger().warn( sm.getString("applicationDispatcher.isUnavailable", wrapper.getName())); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) hresponse.setDateHeader("Retry-After", available); hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm .getString("applicationDispatcher.isUnavailable", wrapper .getName())); unavailable = true; } // Allocate a servlet instance to process this request try { if (!unavailable) { servlet = wrapper.allocate(); } } catch (ServletException e) { wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), StandardWrapper.getRootCause(e)); servletException = e; } catch (Throwable e) { ExceptionUtils.handleThrowable(e); wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), e); servletException = new ServletException (sm.getString("applicationDispatcher.allocateException", wrapper.getName()), e); servlet = null; } // Get the FilterChain Here ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper,servlet); // Call the service() method for the allocated servlet instance try { support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT, servlet, request, response); // for includes/forwards if ((servlet != null) && (filterChain != null)) { filterChain.doFilter(request, response); } // Servlet Service Method is called by the FilterChain support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); } catch (ClientAbortException e) { support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); ioException = e; } catch (IOException e) { support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e); ioException = e; } catch (UnavailableException e) { support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e); servletException = e; wrapper.unavailable(e); } catch (ServletException e) { support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); Throwable rootCause = StandardWrapper.getRootCause(e); if (!(rootCause instanceof ClientAbortException)) { wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), rootCause); } servletException = e; } catch (RuntimeException e) { support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, servlet, request, response); wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e); runtimeException = e; } // Release the filter chain (if any) for this request try { if (filterChain != null) filterChain.release(); } catch (Throwable e) { ExceptionUtils.handleThrowable(e); wrapper.getLogger().error(sm.getString("standardWrapper.releaseFilters", wrapper.getName()), e); // FIXME: Exception handling needs to be similar to what is in the StandardWrapperValue } // Deallocate the allocated servlet instance try { if (servlet != null) { wrapper.deallocate(servlet); } } catch (ServletException e) { wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e); servletException = e; } catch (Throwable e) { ExceptionUtils.handleThrowable(e); wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e); servletException = new ServletException (sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e); } // Reset the old context class loader if (oldCCL != null) Thread.currentThread().setContextClassLoader(oldCCL); // Unwrap request/response if needed // See Bugzilla 30949 unwrapRequest(state); unwrapResponse(state); // Recycle request if necessary (also BZ 30949) recycleRequestWrapper(state); // Rethrow an exception if one was thrown by the invoked servlet if (ioException != null) throw ioException; if (servletException != null) throw servletException; if (runtimeException != null) throw runtimeException; } /** * Unwrap the request if we have wrapped it. */ private void unwrapRequest(State state) { if (state.wrapRequest == null) return; if (state.outerRequest.isAsyncStarted()) { if (!state.outerRequest.getAsyncContext().hasOriginalRequestAndResponse()) { return; } } ServletRequest previous = null; ServletRequest current = state.outerRequest; while (current != null) { // If we run into the container request we are done if ((current instanceof Request) || (current instanceof RequestFacade)) break; // Remove the current request if it is our wrapper if (current == state.wrapRequest) { ServletRequest next = ((ServletRequestWrapper) current).getRequest(); if (previous == null) state.outerRequest = next; else ((ServletRequestWrapper) previous).setRequest(next); break; } // Advance to the next request in the chain previous = current; current = ((ServletRequestWrapper) current).getRequest(); } } /** * Unwrap the response if we have wrapped it. */ private void unwrapResponse(State state) { if (state.wrapResponse == null) return; if (state.outerRequest.isAsyncStarted()) { if (!state.outerRequest.getAsyncContext().hasOriginalRequestAndResponse()) { return; } } ServletResponse previous = null; ServletResponse current = state.outerResponse; while (current != null) { // If we run into the container response we are done if ((current instanceof Response) || (current instanceof ResponseFacade)) break; // Remove the current response if it is our wrapper if (current == state.wrapResponse) { ServletResponse next = ((ServletResponseWrapper) current).getResponse(); if (previous == null) state.outerResponse = next; else ((ServletResponseWrapper) previous).setResponse(next); break; } // Advance to the next response in the chain previous = current; current = ((ServletResponseWrapper) current).getResponse(); } } /** * Create and return a request wrapper that has been inserted in the * appropriate spot in the request chain. */ private ServletRequest wrapRequest(State state) { // Locate the request we should insert in front of ServletRequest previous = null; ServletRequest current = state.outerRequest; while (current != null) { if(state.hrequest == null && (current instanceof HttpServletRequest)) state.hrequest = (HttpServletRequest)current; if (!(current instanceof ServletRequestWrapper)) break; if (current instanceof ApplicationHttpRequest) break; if (current instanceof ApplicationRequest) break; previous = current; current = ((ServletRequestWrapper) current).getRequest(); } // Instantiate a new wrapper at this point and insert it in the chain ServletRequest wrapper = null; if ((current instanceof ApplicationHttpRequest) || (current instanceof Request) || (current instanceof HttpServletRequest)) { // Compute a crossContext flag HttpServletRequest hcurrent = (HttpServletRequest) current; boolean crossContext = false; if ((state.outerRequest instanceof ApplicationHttpRequest) || (state.outerRequest instanceof Request) || (state.outerRequest instanceof HttpServletRequest)) { HttpServletRequest houterRequest = (HttpServletRequest) state.outerRequest; Object contextPath = houterRequest.getAttribute( RequestDispatcher.INCLUDE_CONTEXT_PATH); if (contextPath == null) { // Forward contextPath = houterRequest.getContextPath(); } crossContext = !(context.getPath().equals(contextPath)); } wrapper = new ApplicationHttpRequest (hcurrent, context, crossContext); } else { wrapper = new ApplicationRequest(current); } if (previous == null) state.outerRequest = wrapper; else ((ServletRequestWrapper) previous).setRequest(wrapper); state.wrapRequest = wrapper; return (wrapper); } /** * Create and return a response wrapper that has been inserted in the * appropriate spot in the response chain. */ private ServletResponse wrapResponse(State state) { // Locate the response we should insert in front of ServletResponse previous = null; ServletResponse current = state.outerResponse; while (current != null) { if(state.hresponse == null && (current instanceof HttpServletResponse)) { state.hresponse = (HttpServletResponse)current; if(!state.including) // Forward only needs hresponse return null; } if (!(current instanceof ServletResponseWrapper)) break; if (current instanceof ApplicationHttpResponse) break; if (current instanceof ApplicationResponse) break; previous = current; current = ((ServletResponseWrapper) current).getResponse(); } // Instantiate a new wrapper at this point and insert it in the chain ServletResponse wrapper = null; if ((current instanceof ApplicationHttpResponse) || (current instanceof Response) || (current instanceof HttpServletResponse)) wrapper = new ApplicationHttpResponse((HttpServletResponse) current, state.including); else wrapper = new ApplicationResponse(current, state.including); if (previous == null) state.outerResponse = wrapper; else ((ServletResponseWrapper) previous).setResponse(wrapper); state.wrapResponse = wrapper; return (wrapper); } private void checkSameObjects(ServletRequest appRequest, ServletResponse appResponse) throws ServletException { ServletRequest originalRequest = ApplicationFilterChain.getLastServicedRequest(); ServletResponse originalResponse = ApplicationFilterChain.getLastServicedResponse(); // Some forwards, eg from valves will not set original values if (originalRequest == null || originalResponse == null) { return; } boolean same = false; ServletRequest dispatchedRequest = appRequest; //find the request that was passed into the service method while (originalRequest instanceof ServletRequestWrapper && ((ServletRequestWrapper) originalRequest).getRequest()!=null ) { originalRequest = ((ServletRequestWrapper) originalRequest).getRequest(); } //compare with the dispatched request while (!same) { if (originalRequest.equals(dispatchedRequest)) { same = true; } if (!same && dispatchedRequest instanceof ServletRequestWrapper) { dispatchedRequest = ((ServletRequestWrapper) dispatchedRequest).getRequest(); } else { break; } } if (!same) { throw new ServletException(sm.getString( "applicationDispatcher.specViolation.request")); } same = false; ServletResponse dispatchedResponse = appResponse; //find the response that was passed into the service method while (originalResponse instanceof ServletResponseWrapper && ((ServletResponseWrapper) originalResponse).getResponse() != null ) { originalResponse = ((ServletResponseWrapper) originalResponse).getResponse(); } //compare with the dispatched response while (!same) { if (originalResponse.equals(dispatchedResponse)) { same = true; } if (!same && dispatchedResponse instanceof ServletResponseWrapper) { dispatchedResponse = ((ServletResponseWrapper) dispatchedResponse).getResponse(); } else { break; } } if (!same) { throw new ServletException(sm.getString( "applicationDispatcher.specViolation.response")); } } private void recycleRequestWrapper(State state) { if (state.wrapRequest instanceof ApplicationHttpRequest) { ((ApplicationHttpRequest) state.wrapRequest).recycle(); } } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationJspConfigDescriptor.java0000644000175100017510000000313112271471332027550 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.descriptor.JspPropertyGroupDescriptor; import javax.servlet.descriptor.TaglibDescriptor; public class ApplicationJspConfigDescriptor implements JspConfigDescriptor { private Collection jspPropertyGroups = new LinkedHashSet(); private Collection taglibs = new HashSet(); @Override public Collection getJspPropertyGroups() { return jspPropertyGroups; } @Override public Collection getTaglibs() { return taglibs; } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationRequest.java0000644000175100017510000001336712271471332025273 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import javax.servlet.RequestDispatcher; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; /** * Wrapper around a javax.servlet.ServletRequest * that transforms an application request object (which might be the original * one passed to a servlet, or might be based on the 2.3 * javax.servlet.ServletRequestWrapper class) * back into an internal org.apache.catalina.Request. *

    * WARNING: Due to Java's lack of support for multiple * inheritance, all of the logic in ApplicationRequest is * duplicated in ApplicationHttpRequest. Make sure that you * keep these two classes in synchronization when making changes! * * @author Craig R. McClanahan */ class ApplicationRequest extends ServletRequestWrapper { // ------------------------------------------------------- Static Variables /** * The set of attribute names that are special for request dispatchers. */ protected static final String specials[] = { RequestDispatcher.INCLUDE_REQUEST_URI, RequestDispatcher.INCLUDE_CONTEXT_PATH, RequestDispatcher.INCLUDE_SERVLET_PATH, RequestDispatcher.INCLUDE_PATH_INFO, RequestDispatcher.INCLUDE_QUERY_STRING, RequestDispatcher.FORWARD_REQUEST_URI, RequestDispatcher.FORWARD_CONTEXT_PATH, RequestDispatcher.FORWARD_SERVLET_PATH, RequestDispatcher.FORWARD_PATH_INFO, RequestDispatcher.FORWARD_QUERY_STRING }; // ----------------------------------------------------------- Constructors /** * Construct a new wrapped request around the specified servlet request. * * @param request The servlet request being wrapped */ public ApplicationRequest(ServletRequest request) { super(request); setRequest(request); } // ----------------------------------------------------- Instance Variables /** * The request attributes for this request. This is initialized from the * wrapped request, but updates are allowed. */ protected HashMap attributes = new HashMap(); // ------------------------------------------------- ServletRequest Methods /** * Override the getAttribute() method of the wrapped request. * * @param name Name of the attribute to retrieve */ @Override public Object getAttribute(String name) { synchronized (attributes) { return (attributes.get(name)); } } /** * Override the getAttributeNames() method of the wrapped * request. */ @Override public Enumeration getAttributeNames() { synchronized (attributes) { return Collections.enumeration(attributes.keySet()); } } /** * Override the removeAttribute() method of the * wrapped request. * * @param name Name of the attribute to remove */ @Override public void removeAttribute(String name) { synchronized (attributes) { attributes.remove(name); if (!isSpecial(name)) getRequest().removeAttribute(name); } } /** * Override the setAttribute() method of the * wrapped request. * * @param name Name of the attribute to set * @param value Value of the attribute to set */ @Override public void setAttribute(String name, Object value) { synchronized (attributes) { attributes.put(name, value); if (!isSpecial(name)) getRequest().setAttribute(name, value); } } // ------------------------------------------ ServletRequestWrapper Methods /** * Set the request that we are wrapping. * * @param request The new wrapped request */ @Override public void setRequest(ServletRequest request) { super.setRequest(request); // Initialize the attributes for this request synchronized (attributes) { attributes.clear(); Enumeration names = request.getAttributeNames(); while (names.hasMoreElements()) { String name = names.nextElement(); Object value = request.getAttribute(name); attributes.put(name, value); } } } // ------------------------------------------------------ Protected Methods /** * Is this attribute name one of the special ones that is added only for * included servlets? * * @param name Attribute name to be tested */ protected boolean isSpecial(String name) { for (int i = 0; i < specials.length; i++) { if (specials[i].equals(name)) return (true); } return (false); } } tomcat7-7.0.52/java/org/apache/catalina/core/DefaultInstanceManager.java0000644000175100017510000010237612271471332026022 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.beans.Introspector; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.WeakHashMap; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import javax.ejb.EJB; import javax.naming.Context; import javax.naming.NamingException; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceUnit; import javax.servlet.Filter; import javax.servlet.Servlet; import javax.xml.ws.WebServiceRef; import org.apache.catalina.ContainerServlet; import org.apache.catalina.Globals; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.util.Introspection; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; public class DefaultInstanceManager implements InstanceManager { // Used when there are no annotations in a class private static final AnnotationCacheEntry[] ANNOTATIONS_EMPTY = new AnnotationCacheEntry[0]; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); private final Context context; private final Map> injectionMap; protected final ClassLoader classLoader; protected final ClassLoader containerClassLoader; protected boolean privileged; protected boolean ignoreAnnotations; private final Properties restrictedFilters = new Properties(); private final Properties restrictedListeners = new Properties(); private final Properties restrictedServlets = new Properties(); private final Map, AnnotationCacheEntry[]> annotationCache = new WeakHashMap, AnnotationCacheEntry[]>(); private final Map postConstructMethods; private final Map preDestroyMethods; public DefaultInstanceManager(Context context, Map> injectionMap, org.apache.catalina.Context catalinaContext, ClassLoader containerClassLoader) { classLoader = catalinaContext.getLoader().getClassLoader(); privileged = catalinaContext.getPrivileged(); this.containerClassLoader = containerClassLoader; ignoreAnnotations = catalinaContext.getIgnoreAnnotations(); StringManager sm = StringManager.getManager(Constants.Package); try { InputStream is = this.getClass().getClassLoader().getResourceAsStream ("org/apache/catalina/core/RestrictedServlets.properties"); if (is != null) { restrictedServlets.load(is); } else { catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedServletsResource")); } } catch (IOException e) { catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedServletsResource"), e); } try { InputStream is = this.getClass().getClassLoader().getResourceAsStream ("org/apache/catalina/core/RestrictedListeners.properties"); if (is != null) { restrictedListeners.load(is); } else { catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedListenersResources")); } } catch (IOException e) { catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedListenersResources"), e); } try { InputStream is = this.getClass().getClassLoader().getResourceAsStream ("org/apache/catalina/core/RestrictedFilters.properties"); if (is != null) { restrictedFilters.load(is); } else { catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedFiltersResource")); } } catch (IOException e) { catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedServletsResources"), e); } this.context = context; this.injectionMap = injectionMap; this.postConstructMethods = catalinaContext.findPostConstructMethods(); this.preDestroyMethods = catalinaContext.findPreDestroyMethods(); } @Override public Object newInstance(Class clazz) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException { return newInstance(clazz.newInstance(), clazz); } @Override public Object newInstance(String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { Class clazz = loadClassMaybePrivileged(className, classLoader); return newInstance(clazz.newInstance(), clazz); } @Override public Object newInstance(final String className, final ClassLoader classLoader) throws IllegalAccessException, NamingException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class clazz = classLoader.loadClass(className); return newInstance(clazz.newInstance(), clazz); } @Override public void newInstance(Object o) throws IllegalAccessException, InvocationTargetException, NamingException { newInstance(o, o.getClass()); } private Object newInstance(Object instance, Class clazz) throws IllegalAccessException, InvocationTargetException, NamingException { if (!ignoreAnnotations) { Map injections = assembleInjectionsFromClassHierarchy(clazz); populateAnnotationsCache(clazz, injections); processAnnotations(instance, injections); postConstruct(instance, clazz); } return instance; } private Map assembleInjectionsFromClassHierarchy(Class clazz) { Map injections = new HashMap(); Map currentInjections = null; while (clazz != null) { currentInjections = this.injectionMap.get(clazz.getName()); if (currentInjections != null) { injections.putAll(currentInjections); } clazz = clazz.getSuperclass(); } return injections; } @Override public void destroyInstance(Object instance) throws IllegalAccessException, InvocationTargetException { if (!ignoreAnnotations) { preDestroy(instance, instance.getClass()); } } /** * Call postConstruct method on the specified instance recursively from deepest superclass to actual class. * * @param instance object to call postconstruct methods on * @param clazz (super) class to examine for postConstruct annotation. * @throws IllegalAccessException if postConstruct method is inaccessible. * @throws java.lang.reflect.InvocationTargetException * if call fails */ protected void postConstruct(Object instance, final Class clazz) throws IllegalAccessException, InvocationTargetException { if (context == null) { // No resource injection return; } Class superClass = clazz.getSuperclass(); if (superClass != Object.class) { postConstruct(instance, superClass); } // At the end the postconstruct annotated // method is invoked AnnotationCacheEntry[] annotations; synchronized (annotationCache) { annotations = annotationCache.get(clazz); } for (AnnotationCacheEntry entry : annotations) { if (entry.getType() == AnnotationCacheEntryType.POST_CONSTRUCT) { Method postConstruct = getMethod(clazz, entry); synchronized (postConstruct) { boolean accessibility = postConstruct.isAccessible(); postConstruct.setAccessible(true); postConstruct.invoke(instance); postConstruct.setAccessible(accessibility); } } } } /** * Call preDestroy method on the specified instance recursively from deepest superclass to actual class. * * @param instance object to call preDestroy methods on * @param clazz (super) class to examine for preDestroy annotation. * @throws IllegalAccessException if preDestroy method is inaccessible. * @throws java.lang.reflect.InvocationTargetException * if call fails */ protected void preDestroy(Object instance, final Class clazz) throws IllegalAccessException, InvocationTargetException { Class superClass = clazz.getSuperclass(); if (superClass != Object.class) { preDestroy(instance, superClass); } // At the end the postconstruct annotated // method is invoked AnnotationCacheEntry[] annotations = null; synchronized (annotationCache) { annotations = annotationCache.get(clazz); } if (annotations == null) { // instance not created through the instance manager return; } for (AnnotationCacheEntry entry : annotations) { if (entry.getType() == AnnotationCacheEntryType.PRE_DESTROY) { Method preDestroy = getMethod(clazz, entry); synchronized (preDestroy) { boolean accessibility = preDestroy.isAccessible(); preDestroy.setAccessible(true); preDestroy.invoke(instance); preDestroy.setAccessible(accessibility); } } } } /** * Make sure that the annotations cache has been populated for the provided * class. * * @param clazz clazz to populate annotations for * @param injections map of injections for this class from xml deployment * descriptor * @throws IllegalAccessException if injection target is inaccessible * @throws javax.naming.NamingException if value cannot be looked up in jndi * @throws java.lang.reflect.InvocationTargetException * if injection fails */ protected void populateAnnotationsCache(Class clazz, Map injections) throws IllegalAccessException, InvocationTargetException, NamingException { List annotations = null; while (clazz != null) { AnnotationCacheEntry[] annotationsArray = null; synchronized (annotationCache) { annotationsArray = annotationCache.get(clazz); } if (annotationsArray == null) { if (annotations == null) { annotations = new ArrayList(); } else { annotations.clear(); } if (context != null) { // Initialize fields annotations for resource injection if // JNDI is enabled Field[] fields = Introspection.getDeclaredFields(clazz); for (Field field : fields) { if (injections != null && injections.containsKey(field.getName())) { annotations.add(new AnnotationCacheEntry( field.getName(), null, injections.get(field.getName()), AnnotationCacheEntryType.FIELD)); } else if (field.isAnnotationPresent(Resource.class)) { Resource annotation = field.getAnnotation(Resource.class); annotations.add(new AnnotationCacheEntry( field.getName(), null, annotation.name(), AnnotationCacheEntryType.FIELD)); } else if (field.isAnnotationPresent(EJB.class)) { EJB annotation = field.getAnnotation(EJB.class); annotations.add(new AnnotationCacheEntry( field.getName(), null, annotation.name(), AnnotationCacheEntryType.FIELD)); } else if (field.isAnnotationPresent(WebServiceRef.class)) { WebServiceRef annotation = field.getAnnotation(WebServiceRef.class); annotations.add(new AnnotationCacheEntry( field.getName(), null, annotation.name(), AnnotationCacheEntryType.FIELD)); } else if (field.isAnnotationPresent(PersistenceContext.class)) { PersistenceContext annotation = field.getAnnotation(PersistenceContext.class); annotations.add(new AnnotationCacheEntry( field.getName(), null, annotation.name(), AnnotationCacheEntryType.FIELD)); } else if (field.isAnnotationPresent(PersistenceUnit.class)) { PersistenceUnit annotation = field.getAnnotation(PersistenceUnit.class); annotations.add(new AnnotationCacheEntry( field.getName(), null, annotation.name(), AnnotationCacheEntryType.FIELD)); } } } // Initialize methods annotations Method[] methods = Introspection.getDeclaredMethods(clazz); Method postConstruct = null; String postConstructFromXml = postConstructMethods.get(clazz.getName()); Method preDestroy = null; String preDestroyFromXml = preDestroyMethods.get(clazz.getName()); for (Method method : methods) { if (context != null) { // Resource injection only if JNDI is enabled if (injections != null && Introspection.isValidSetter(method)) { String fieldName = Introspection.getPropertyName(method); if (injections.containsKey(fieldName)) { annotations.add(new AnnotationCacheEntry( method.getName(), method.getParameterTypes(), injections.get(fieldName), AnnotationCacheEntryType.SETTER)); continue; } } if (method.isAnnotationPresent(Resource.class)) { Resource annotation = method.getAnnotation(Resource.class); annotations.add(new AnnotationCacheEntry( method.getName(), method.getParameterTypes(), annotation.name(), AnnotationCacheEntryType.SETTER)); } else if (method.isAnnotationPresent(EJB.class)) { EJB annotation = method.getAnnotation(EJB.class); annotations.add(new AnnotationCacheEntry( method.getName(), method.getParameterTypes(), annotation.name(), AnnotationCacheEntryType.SETTER)); } else if (method.isAnnotationPresent(WebServiceRef.class)) { WebServiceRef annotation = method.getAnnotation(WebServiceRef.class); annotations.add(new AnnotationCacheEntry( method.getName(), method.getParameterTypes(), annotation.name(), AnnotationCacheEntryType.SETTER)); } else if (method.isAnnotationPresent(PersistenceContext.class)) { PersistenceContext annotation = method.getAnnotation(PersistenceContext.class); annotations.add(new AnnotationCacheEntry( method.getName(), method.getParameterTypes(), annotation.name(), AnnotationCacheEntryType.SETTER)); } else if (method.isAnnotationPresent(PersistenceUnit.class)) { PersistenceUnit annotation = method.getAnnotation(PersistenceUnit.class); annotations.add(new AnnotationCacheEntry( method.getName(), method.getParameterTypes(), annotation.name(), AnnotationCacheEntryType.SETTER)); } } postConstruct = findPostConstruct(postConstruct, postConstructFromXml, method); preDestroy = findPreDestroy(preDestroy, preDestroyFromXml, method); } if (postConstruct != null) { annotations.add(new AnnotationCacheEntry( postConstruct.getName(), postConstruct.getParameterTypes(), null, AnnotationCacheEntryType.POST_CONSTRUCT)); } else if (postConstructFromXml != null) { throw new IllegalArgumentException("Post construct method " + postConstructFromXml + " for class " + clazz.getName() + " is declared in deployment descriptor but cannot be found."); } if (preDestroy != null) { annotations.add(new AnnotationCacheEntry( preDestroy.getName(), preDestroy.getParameterTypes(), null, AnnotationCacheEntryType.PRE_DESTROY)); } else if (preDestroyFromXml != null) { throw new IllegalArgumentException("Pre destroy method " + preDestroyFromXml + " for class " + clazz.getName() + " is declared in deployment descriptor but cannot be found."); } if (annotations.isEmpty()) { // Use common object to save memory annotationsArray = ANNOTATIONS_EMPTY; } else { annotationsArray = annotations.toArray( new AnnotationCacheEntry[annotations.size()]); } synchronized (annotationCache) { annotationCache.put(clazz, annotationsArray); } } clazz = clazz.getSuperclass(); } } /** * Inject resources in specified instance. * * @param instance instance to inject into * @param injections map of injections for this class from xml deployment descriptor * @throws IllegalAccessException if injection target is inaccessible * @throws javax.naming.NamingException if value cannot be looked up in jndi * @throws java.lang.reflect.InvocationTargetException * if injection fails */ protected void processAnnotations(Object instance, Map injections) throws IllegalAccessException, InvocationTargetException, NamingException { if (context == null) { // No resource injection return; } Class clazz = instance.getClass(); while (clazz != null) { AnnotationCacheEntry[] annotations; synchronized (annotationCache) { annotations = annotationCache.get(clazz); } for (AnnotationCacheEntry entry : annotations) { if (entry.getType() == AnnotationCacheEntryType.SETTER) { lookupMethodResource(context, instance, getMethod(clazz, entry), entry.getName(), clazz); } else if (entry.getType() == AnnotationCacheEntryType.FIELD) { lookupFieldResource(context, instance, getField(clazz, entry), entry.getName(), clazz); } } clazz = clazz.getSuperclass(); } } /** * Makes cache size available to unit tests. */ protected int getAnnotationCacheSize() { synchronized (annotationCache) { return annotationCache.size(); } } protected Class loadClassMaybePrivileged(final String className, final ClassLoader classLoader) throws ClassNotFoundException { Class clazz; if (SecurityUtil.isPackageProtectionEnabled()) { try { clazz = AccessController.doPrivileged(new PrivilegedExceptionAction>() { @Override public Class run() throws Exception { return loadClass(className, classLoader); } }); } catch (PrivilegedActionException e) { Throwable t = e.getCause(); if (t instanceof ClassNotFoundException) { throw (ClassNotFoundException) t; } throw new RuntimeException(t); } } else { clazz = loadClass(className, classLoader); } checkAccess(clazz); return clazz; } protected Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { if (className.startsWith("org.apache.catalina")) { return containerClassLoader.loadClass(className); } try { Class clazz = containerClassLoader.loadClass(className); if (ContainerServlet.class.isAssignableFrom(clazz)) { return clazz; } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } return classLoader.loadClass(className); } private void checkAccess(Class clazz) { if (privileged) { return; } if (Filter.class.isAssignableFrom(clazz)) { checkAccess(clazz, restrictedFilters); } else if (Servlet.class.isAssignableFrom(clazz)) { if (ContainerServlet.class.isAssignableFrom(clazz)) { throw new SecurityException("Restricted (ContainerServlet) " + clazz); } checkAccess(clazz, restrictedServlets); } else { checkAccess(clazz, restrictedListeners); } } private void checkAccess(Class clazz, Properties restricted) { while (clazz != null) { if ("restricted".equals(restricted.getProperty(clazz.getName()))) { throw new SecurityException("Restricted " + clazz); } clazz = clazz.getSuperclass(); } } /** * Inject resources in specified field. * * @param context jndi context to extract value from * @param instance object to inject into * @param field field target for injection * @param name jndi name value is bound under * @param clazz class annotation is defined in * @throws IllegalAccessException if field is inaccessible * @throws javax.naming.NamingException if value is not accessible in naming context */ protected static void lookupFieldResource(Context context, Object instance, Field field, String name, Class clazz) throws NamingException, IllegalAccessException { Object lookedupResource; boolean accessibility; String normalizedName = normalize(name); if ((normalizedName != null) && (normalizedName.length() > 0)) { lookedupResource = context.lookup(normalizedName); } else { lookedupResource = context.lookup(clazz.getName() + "/" + field.getName()); } synchronized (field) { accessibility = field.isAccessible(); field.setAccessible(true); field.set(instance, lookedupResource); field.setAccessible(accessibility); } } /** * Inject resources in specified method. * * @param context jndi context to extract value from * @param instance object to inject into * @param method field target for injection * @param name jndi name value is bound under * @param clazz class annotation is defined in * @throws IllegalAccessException if method is inaccessible * @throws javax.naming.NamingException if value is not accessible in naming context * @throws java.lang.reflect.InvocationTargetException * if setter call fails */ protected static void lookupMethodResource(Context context, Object instance, Method method, String name, Class clazz) throws NamingException, IllegalAccessException, InvocationTargetException { if (!Introspection.isValidSetter(method)) { throw new IllegalArgumentException( sm.getString("defaultInstanceManager.invalidInjection")); } Object lookedupResource; boolean accessibility; String normalizedName = normalize(name); if ((normalizedName != null) && (normalizedName.length() > 0)) { lookedupResource = context.lookup(normalizedName); } else { lookedupResource = context.lookup( clazz.getName() + "/" + Introspection.getPropertyName(method)); } synchronized (method) { accessibility = method.isAccessible(); method.setAccessible(true); method.invoke(instance, lookedupResource); method.setAccessible(accessibility); } } @Deprecated public static String getName(Method setter) { // Note: method signature has already been checked for correctness. // The method name always starts with "set". return Introspector.decapitalize(setter.getName().substring(3)); } private static String normalize(String jndiName){ if(jndiName != null && jndiName.startsWith("java:comp/env/")){ return jndiName.substring(14); } return jndiName; } private static Method getMethod(final Class clazz, final AnnotationCacheEntry entry) { Method result = null; if (Globals.IS_SECURITY_ENABLED) { result = AccessController.doPrivileged( new PrivilegedAction() { @Override public Method run() { Method result = null; try { result = clazz.getDeclaredMethod( entry.getAccessibleObjectName(), entry.getParamTypes()); } catch (NoSuchMethodException e) { // Should never happen. On that basis don't log // it. } return result; } }); } else { try { result = clazz.getDeclaredMethod( entry.getAccessibleObjectName(), entry.getParamTypes()); } catch (NoSuchMethodException e) { // Should never happen. On that basis don't log it. } } return result; } private static Field getField(final Class clazz, final AnnotationCacheEntry entry) { Field result = null; if (Globals.IS_SECURITY_ENABLED) { result = AccessController.doPrivileged( new PrivilegedAction() { @Override public Field run() { Field result = null; try { result = clazz.getDeclaredField( entry.getAccessibleObjectName()); } catch (NoSuchFieldException e) { // Should never happen. On that basis don't log // it. } return result; } }); } else { try { result = clazz.getDeclaredField( entry.getAccessibleObjectName()); } catch (NoSuchFieldException e) { // Should never happen. On that basis don't log it. } } return result; } private static Method findPostConstruct(Method currentPostConstruct, String postConstructFromXml, Method method) { return findLifecycleCallback(currentPostConstruct, postConstructFromXml, method, PostConstruct.class); } private static Method findPreDestroy(Method currentPreDestroy, String preDestroyFromXml, Method method) { return findLifecycleCallback(currentPreDestroy, preDestroyFromXml, method, PreDestroy.class); } private static Method findLifecycleCallback(Method currentMethod, String methodNameFromXml, Method method, Class annotation) { Method result = currentMethod; if (methodNameFromXml != null) { if (method.getName().equals(methodNameFromXml)) { if (!Introspection.isValidLifecycleCallback(method)) { throw new IllegalArgumentException( "Invalid " + annotation.getName() + " annotation"); } result = method; } } else { if (method.isAnnotationPresent(annotation)) { if (currentMethod != null || !Introspection.isValidLifecycleCallback(method)) { throw new IllegalArgumentException( "Invalid " + annotation.getName() + " annotation"); } result = method; } } return result; } private static final class AnnotationCacheEntry { private final String accessibleObjectName; private final Class[] paramTypes; private final String name; private final AnnotationCacheEntryType type; public AnnotationCacheEntry(String accessibleObjectName, Class[] paramTypes, String name, AnnotationCacheEntryType type) { this.accessibleObjectName = accessibleObjectName; this.paramTypes = paramTypes; this.name = name; this.type = type; } public String getAccessibleObjectName() { return accessibleObjectName; } public Class[] getParamTypes() { return paramTypes; } public String getName() { return name; } public AnnotationCacheEntryType getType() { return type; } } private static enum AnnotationCacheEntryType { FIELD, SETTER, POST_CONSTRUCT, PRE_DESTROY } } tomcat7-7.0.52/java/org/apache/catalina/core/mbeans-descriptors.xml0000644000175100017510000022212312271471332025132 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/core/Constants.java0000644000175100017510000000215612271471332023425 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; public class Constants { public static final String Package = "org.apache.catalina.core"; public static final int MAJOR_VERSION = 3; public static final int MINOR_VERSION = 0; public static final String JSP_SERVLET_CLASS = "org.apache.jasper.servlet.JspServlet"; } tomcat7-7.0.52/java/org/apache/catalina/core/LocalStrings.properties0000644000175100017510000005520512271471332025333 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationContext.addFilter.ise=Filters can not be added to context {0} as the context has been initialised applicationContext.addListener.iae.cnfe=Unable to create an instance of type [{0}] applicationContext.addListener.iae.wrongType=The type specified [{0}] is not one of the expected listener types applicationContext.addListener.iae.sclNotAllowed=Once the first ServletContextListener has been called, no more ServletContextListeners may be added. applicationContext.addListener.ise=Listeners can not be added to context {0} as the context has been initialised applicationContext.addRole.ise=Roles can not be added to context {0} as the context has been initialised applicationContext.addServlet.ise=Servlets can not be added to context {0} as the context has been initialised applicationContext.attributeEvent=Exception thrown by attributes event listener applicationContext.invalidFilterName=Unable to add filter definition due to invalid filter name [{0}]. applicationContext.invalidServletName=Unable to add servlet definition due to invalid servlet name [{0}]. applicationContext.mapping.error=Error during mapping applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character applicationContext.role.iae=An individual role to declare for context [{0}] may not be null nor the empty string applicationContext.roles.iae=Array of roles to declare for context [{0}] cannot be null applicationContext.setAttribute.namenull=Name cannot be null applicationContext.addSessionCookieConfig.ise=Session Cookie configuration cannot be set for context {0} as the context has been initialised applicationContext.setSessionTracking.ise=The session tracking modes for context {0} cannot be set whilst the context is running applicationContext.setSessionTracking.iae.invalid=The session tracking mode {0} requested for context {1} is not supported by that context applicationContext.setSessionTracking.iae.ssl=The session tracking modes requested for context {0} included SSL and at least one other mode. SSL may not be configured with other modes. applicationContext.lookup.error=Failed to locate resource [{0}] in context [{1}] applicationDispatcher.allocateException=Allocate exception for servlet {0} applicationDispatcher.deallocateException=Deallocate exception for servlet {0} applicationDispatcher.forward.ise=Cannot forward after response has been committed applicationDispatcher.forward.throw=Forwarded resource threw an exception applicationDispatcher.include.throw=Included resource threw an exception applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception applicationDispatcher.specViolation.request=Original SevletRequest or wrapped original ServletRequest not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1 applicationDispatcher.specViolation.response=Original SevletResponse or wrapped original ServletResponse not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1 applicationFilterConfig.jmxRegisterFail=JMX registration failed for filter of type [{0}] and name [{1}] applicationFilterConfig.jmxUnregister=JMX de-registration complete for filter of type [{0}] and name [{1}] applicationFilterConfig.jmxUnregisterFail=JMX de-registration failed for filter of type [{0}] and name [{1}] applicationFilterConfig.release=Failed to destroy the filter named [{0}] of type [{1}] applicationFilterRegistration.nullInitParam=Unable to set initialisation parameter for filter due to null name and/or value. Name [{0}], Value [{1}] applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}] applicationRequest.badParent=Cannot locate parent Request implementation applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper applicationResponse.badParent=Cannot locate parent Response implementation applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper applicationServletRegistration.setServletSecurity.iae=Null constraint specified for servlet [{0}] deployed to context with name [{1}] applicationServletRegistration.setServletSecurity.ise=Security constraints can't be added to servlet [{0}] deployed to context with name [{1}] as the context has already been initialised applicationSessionCookieConfig.ise=Property {0} can not be added to SessionCookieConfig for context {1} as the context has been initialised aprListener.aprInit=The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0} aprListener.tcnInvalid=An incompatible version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat requires version {1} aprListener.tcnVersion=An older version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of {1} aprListener.aprDestroy=Failed shutdown of APR based Apache Tomcat Native library aprListener.sslInit=Failed to initialize the SSLEngine. aprListener.tcnValid=Loaded APR based Apache Tomcat Native library {0} using APR version {1}. aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}]. aprListener.initializingFIPS=Initializing FIPS mode... aprListener.initializeFIPSSuccess=Successfully entered FIPS mode aprListener.initializeFIPSFailed=Failed to enter FIPS mode aprListener.tooLateForSSLEngine=Cannot setSSLEngine: SSL has already been initialized aprListener.tooLateForSSLRandomSeed=Cannot setSSLRandomSeed: SSL has already been initialized aprListener.tooLateForFIPSMode=Cannot setFIPSMode: SSL has already been initialized aprListener.initializedOpenSSL=OpenSSL successfully initialized ({0}) asyncContextImpl.requestEnded=The request associated with the AsyncContext has already completed processing. asyncContextImpl.noAsyncDispatcher=The dispatcher returned from the ServletContext does not support asynchronous dispatching asyncContextImpl.dispatchingStarted=Asynchronous dispatch operation has already been called. Additional asynchronous dispatch operation within the same asynchronous cycle is not allowed. containerBase.threadedStartFailed=A child container failed during start containerBase.threadedStopFailed=A child container failed during stop containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process containerBase.backgroundProcess.loader=Exception processing loader {0} background process containerBase.backgroundProcess.manager=Exception processing manager {0} background process containerBase.backgroundProcess.realm=Exception processing realm {0} background process containerBase.backgroundProcess.valve=Exception processing valve {0} background process defaultInstanceManager.invalidInjection=Invalid method resource injection annotation fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started filterChain.filter=Filter execution threw an exception filterChain.servlet=Servlet execution threw an exception httpContextMapper.container=This container is not a StandardContext httpEngineMapper.container=This container is not a StandardEngine httpHostMapper.container=This container is not a StandardHost interceptorValve.alreadyStarted=InterceptorValve has already been started interceptorValve.notStarted=InterceptorValve has not yet been started jreLeakListener.keepAliveFail=Failed to trigger creation of the sun.net.www.http.HttpClient class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. jreLeakListener.gcDaemonFail=Failed to trigger creation of the GC Daemon thread during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. jreLeakListener.jarUrlConnCacheFail=Failed to disable Jar URL connection caching by default jreLeakListener.xmlParseFail=Error whilst attempting to prevent memory leaks during XML parsing jreLeakListener.authPolicyFail=Error whilst attempting to prevent memory leak in javax.security.auth.Policy class jreLeakListener.ldapPoolManagerFail=Failed to trigger creation of the com.sun.jndi.ldap.LdapPoolManager class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. jreLeakListener.classToInitializeFail=Failed to load class {0} during Tomcat start to prevent possible memory leaks. naming.wsdlFailed=Failed to find wsdl file: {0} naming.bindFailed=Failed to bind object: {0} naming.jmxRegistrationFailed=Failed to register in JMX: {0} naming.unbindFailed=Failed to unbind object: {0} naming.invalidEnvEntryType=Environment entry {0} has an invalid type naming.invalidEnvEntryValue=Environment entry {0} has an invalid value naming.namingContextCreationFailed=Creation of the naming context failed: {0} noPluggabilityServletContext.notAllowed=Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with @WebListener standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper standardContext.alreadyStarted=Context has already been started standardContext.applicationListener=Error configuring application listener of class {0} standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s) standardContext.badRequest=Invalid request path ({0}). standardContext.cluster.noManager=No manager found. Checking if cluster manager should be used. Cluster configured: [{0}], Application distributable: [{1}] standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched. standardContext.duplicateListener=The listener "{0}" is already configured for this context. The duplicate definition has been ignored. standardContext.errorPage.error=Error page location {0} must start with a ''/'' standardContext.errorPage.required=ErrorPage cannot be null standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4 standardContext.filterMap.either=Filter mapping must specify either a or a standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0} standardContext.filterMap.pattern=Invalid {0} in filter mapping standardContext.filterStart=Exception starting filter {0} standardContext.filterStartFailed=Failed to start application Filters successfully standardContext.requestListener.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0} standardContext.requestListener.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0} standardContext.requestListenerStartFailed=Failed to start request listener valve successfully standardContext.requestListenerConfig.added=Added request listener Valve standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0} standardContext.isUnavailable=This application is not currently available standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0} standardContext.listenerStartFailed=Failed to start application Listeners successfully standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0} standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/' standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4 standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/' standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4 standardContext.loginConfig.required=LoginConfig cannot be null standardContext.manager=Configured a manager of class [{0}] standardContext.mappingError=MAPPING configuration error for relative URI {0} standardContext.namingResource.init.fail=Failed to init new naming resources standardContext.namingResource.destroy.fail=Failed to destroy old naming resources standardContext.noResourceJar=Resource JARs are not supported. The JAR found at [{0}] will not be used to provide static content for context with name [{1}] standardContext.notFound=The requested resource ({0}) is not available. standardContext.notReloadable=Reloading is disabled on this Context standardContext.notStarted=Context with name [{0}] has not yet been started standardContext.notWrapper=Child of a Context must be a Wrapper standardContext.parameter.duplicate=Duplicate context initialization parameter {0} standardContext.parameter.required=Both parameter name and parameter value are required standardContext.pathInvalid=A context path must either be an empty string or start with a ''/''. The path [{0}] does not meet these criteria and has been changed to [{1}] standardContext.postconstruct.duplicate=Duplicate post construct method definition for class {0} standardContext.postconstruct.required=Both fully qualified class name and method name are required standardContext.predestroy.duplicate=Duplicate pre destroy method definition for class {0} standardContext.predestroy.required=Both fully qualified class name and method name are required standardContext.reloadingCompleted=Reloading Context with name [{0}] is completed standardContext.reloadingFailed=Reloading this Context failed due to previous errors standardContext.reloadingStarted=Reloading Context with name [{0}] has started standardContext.resourcesStart=Error starting static Resources standardContext.sciFail=Error during ServletContainerInitializer processing standardContext.securityConstraint.mixHttpMethod=It is not permitted to mix and in the same web resource collection standardContext.securityConstraint.pattern=Invalid {0} in security constraint standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0} standardContext.servletMap.pattern=Invalid {0} in servlet mapping standardContext.startCleanup=Exception during cleanup after start failed standardContext.startFailed=Context [{0}] startup failed due to previous errors standardContext.startingContext=Exception starting Context with name [{0}] standardContext.startingLoader=Exception starting Loader standardContext.startingManager=Exception starting Manager standardContext.startingWrapper=Exception starting Wrapper for servlet {0} standardContext.stoppingContext=Exception stopping Context with name [{0}] standardContext.stoppingLoader=Exception stopping Loader standardContext.stoppingManager=Exception stopping Manager standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0} standardContext.urlDecode=Cannot URL decode request path {0} standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4 standardContext.urlValidate=Cannot validate URL decoded request path {0} standardContext.workPath=Exception obtaining work path for context [{0}] standardContext.workCreateException=Failed to determine absolute work directory from directory [{0}] and CATALINA_HOME [{1}] for context [{2}] standardContext.workCreateFail=Failed to create work directory [{0}] for context [{1}] standardContextValve.acknowledgeException=Failed to acknowledge request with a 100 (Continue) response standardEngine.alreadyStarted=Engine has already been started standardEngine.jvmRouteFail=Failed to set Engine's jvmRoute attribute from system property standardEngine.mappingError=MAPPING configuration error for server name {0} standardEngine.noHost=No Host matches server name {0} standardEngine.noHostHeader=HTTP/1.1 request with no Host: header standardEngine.notHost=Child of an Engine must be a Host standardEngine.notParent=Engine cannot have a parent Container standardEngine.notStarted=Engine has not yet been started standardEngine.unfoundHost=Virtual host {0} not found standardEngine.unknownHost=No server host specified in this request standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0} standardHost.accessBase=Cannot access document base directory {0} standardHost.alreadyStarted=Host has already been started standardHost.appBase=Application base directory {0} does not exist standardHost.clientAbort=Remote Client Aborted Request, IOException: {0} standardHost.configRequired=URL to configuration file is required standardHost.configNotAllowed=Use of configuration file is not allowed standardHost.installBase=Only web applications in the Host web application directory can be installed standardHost.installing=Installing web application at context path {0} from URL {1} standardHost.installingWAR=Installing web application from URL {0} standardHost.installingXML=Processing Context configuration file URL {0} standardHost.installError=Error deploying application at context path {0} standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0} standardHost.docBase=Document base directory {0} already exists standardHost.mappingError=MAPPING configuration error for request URI {0} standardHost.noContext=No Context configured to process this request standardHost.noHost=No Host configured to process this request standardHost.notContext=Child of a Host must be a Context standardHost.notStarted=Host has not yet been started standardHost.nullName=Host name is required standardHost.pathFormat=Invalid context path: {0} standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1} standardHost.pathMissing=Context path {0} is not currently in use standardHost.pathRequired=Context path is required standardHost.pathUsed=Context path {0} is already in use standardHost.removing=Removing web application at context path {0} standardHost.removeError=Error removing application at context path {0} standardHost.start=Starting web application at context path {0} standardHost.stop=Stopping web application at context path {0} standardHost.unfoundContext=Cannot find context for request URI {0} standardHost.warRequired=URL to web application archive is required standardHost.warURL=Invalid URL for web application archive: {0} standardServer.onameFail=MBean name specified for Server [{0}] is not valid standardServer.shutdownViaPort=A valid shutdown command was received via the shutdown port. Stopping the Server instance. standardService.connector.initFailed=Failed to initialize connector [{0}] standardService.connector.destroyFailed=Failed to destroy connector [{0}] standardService.connector.pauseFailed=Failed to pause connector [{0}] standardService.connector.startFailed=Failed to start connector [{0}] standardService.connector.stopFailed=Failed to stop connector [{0}] standardService.initialize.failed=Service initializing at {0} failed standardService.onameFail=MBean name specified for Service [{0}] is not valid standardService.register.failed=Error registering Service at domain {0} standardService.start.name=Starting service {0} standardService.stop.name=Stopping service {0} standardThreadExecutor.onameFail=MBean name specified for Thread Executor [{0}] is not valid standardWrapper.allocate=Error allocating a servlet instance standardWrapper.allocateException=Allocate exception for servlet {0} standardWrapper.containerServlet=Loading container servlet {0} standardWrapper.createFilters=Create filters exception for servlet {0} standardWrapper.deallocateException=Deallocate exception for servlet {0} standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception standardWrapper.exception0=Tomcat Exception Report standardWrapper.exception1=A Servlet Exception Has Occurred standardWrapper.exception2=Exception Report: standardWrapper.exception3=Root Cause: standardWrapper.initException=Servlet.init() for servlet {0} threw exception standardWrapper.instantiate=Error instantiating servlet class {0} standardWrapper.isUnavailable=Servlet {0} is currently unavailable standardWrapper.jasperLoader=Using Jasper classloader for servlet {0} standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character standardWrapper.loadException=Servlet {0} threw load() exception standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0} standardWrapper.notChild=Wrapper container may not have child containers standardWrapper.notClass=No servlet class has been specified for servlet {0} standardWrapper.notContext=Parent container of a Wrapper must be a Context standardWrapper.notFound=Servlet {0} is not available standardWrapper.notServlet=Class {0} is not a Servlet standardWrapper.releaseFilters=Release filters exception for servlet {0} standardWrapper.serviceException=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception standardWrapper.serviceExceptionRoot=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception [{2}] with root cause standardWrapper.statusHeader=HTTP Status {0} - {1} standardWrapper.statusTitle=Tomcat Error Report standardWrapper.unavailable=Marking servlet {0} as unavailable standardWrapper.unloadException=Servlet {0} threw unload() exception standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated for Servlet [{1}] threadLocalLeakPreventionListener.lifecycleEvent.error=Exception processing lifecycle event {0} threadLocalLeakPreventionListener.containerEvent.error=Exception processing container event {0} defaultInstanceManager.restrictedServletsResource=Restricted servlets property file not found defaultInstanceManager.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application defaultInstanceManager.restrictedFiltersResource=Restricted filters property file not found defaultInstanceManager.privilegedFilter=Filter of class {0} is privileged and cannot be loaded by this web application defaultInstanceManager.restrictedListenersResources="Restricted listeners property file not found tomcat7-7.0.52/java/org/apache/catalina/core/StandardWrapper.java0000644000175100017510000017112112271471332024551 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.PrintStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Stack; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.management.ListenerNotFoundException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationEmitter; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.servlet.MultipartConfigElement; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.ServletSecurityElement; import javax.servlet.SingleThreadModel; import javax.servlet.UnavailableException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.ServletSecurity; import org.apache.catalina.Container; import org.apache.catalina.ContainerServlet; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.InstanceEvent; import org.apache.catalina.InstanceListener; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Wrapper; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.util.InstanceSupport; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.PeriodicEventListener; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.log.SystemLogHandler; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.modeler.Util; /** * Standard implementation of the Wrapper interface that represents * an individual servlet definition. No child Containers are allowed, and * the parent Container must be a Context. * * @author Craig R. McClanahan * @author Remy Maucherat */ @SuppressWarnings("deprecation") // SingleThreadModel public class StandardWrapper extends ContainerBase implements ServletConfig, Wrapper, NotificationEmitter { private static final Log log = LogFactory.getLog( StandardWrapper.class ); protected static final String[] DEFAULT_SERVLET_METHODS = new String[] { "GET", "HEAD", "POST" }; // ----------------------------------------------------------- Constructors /** * Create a new StandardWrapper component with the default basic Valve. */ public StandardWrapper() { super(); swValve=new StandardWrapperValve(); pipeline.setBasic(swValve); broadcaster = new NotificationBroadcasterSupport(); } // ----------------------------------------------------- Instance Variables /** * The date and time at which this servlet will become available (in * milliseconds since the epoch), or zero if the servlet is available. * If this value equals Long.MAX_VALUE, the unavailability of this * servlet is considered permanent. */ protected long available = 0L; /** * The broadcaster that sends j2ee notifications. */ protected NotificationBroadcasterSupport broadcaster = null; /** * The count of allocations that are currently active (even if they * are for the same instance, as will be true on a non-STM servlet). */ protected AtomicInteger countAllocated = new AtomicInteger(0); /** * The facade associated with this wrapper. */ protected StandardWrapperFacade facade = new StandardWrapperFacade(this); /** * The descriptive information string for this implementation. */ protected static final String info = "org.apache.catalina.core.StandardWrapper/1.0"; /** * The (single) possibly uninitialized instance of this servlet. */ protected volatile Servlet instance = null; /** * Flag that indicates if this instance has been initialized */ protected volatile boolean instanceInitialized = false; /** * The support object for our instance listeners. */ protected InstanceSupport instanceSupport = new InstanceSupport(this); /** * The load-on-startup order value (negative value means load on * first call) for this servlet. */ protected int loadOnStartup = -1; /** * Mappings associated with the wrapper. */ protected ArrayList mappings = new ArrayList(); /** * The initialization parameters for this servlet, keyed by * parameter name. */ protected HashMap parameters = new HashMap(); /** * The security role references for this servlet, keyed by role name * used in the servlet. The corresponding value is the role name of * the web application itself. */ protected HashMap references = new HashMap(); /** * The run-as identity for this servlet. */ protected String runAs = null; /** * The notification sequence number. */ protected long sequenceNumber = 0; /** * The fully qualified servlet class name for this servlet. */ protected String servletClass = null; /** * Does this servlet implement the SingleThreadModel interface? */ protected volatile boolean singleThreadModel = false; /** * Are we unloading our servlet instance at the moment? */ protected boolean unloading = false; /** * Maximum number of STM instances. */ protected int maxInstances = 20; /** * Number of instances currently loaded for a STM servlet. */ protected int nInstances = 0; /** * Stack containing the STM instances. */ protected Stack instancePool = null; /** * Wait time for servlet unload in ms. */ protected long unloadDelay = 2000; /** * True if this StandardWrapper is for the JspServlet */ protected boolean isJspServlet; /** * The ObjectName of the JSP monitoring mbean */ protected ObjectName jspMonitorON; /** * Should we swallow System.out */ protected boolean swallowOutput = false; // To support jmx attributes protected StandardWrapperValve swValve; protected long loadTime=0; protected int classLoadTime=0; /** * Multipart config */ protected MultipartConfigElement multipartConfigElement = null; /** * Async support */ protected boolean asyncSupported = false; /** * Enabled */ protected boolean enabled = true; protected volatile boolean servletSecurityAnnotationScanRequired = false; private boolean overridable = false; /** * Static class array used when the SecurityManager is turned on and * Servlet.init is invoked. */ protected static Class[] classType = new Class[]{ServletConfig.class}; /** * Static class array used when the SecurityManager is turned on and * Servlet.service is invoked. */ @Deprecated protected static Class[] classTypeUsedInService = new Class[]{ ServletRequest.class, ServletResponse.class}; private final ReentrantReadWriteLock parametersLock = new ReentrantReadWriteLock(); private final ReentrantReadWriteLock mappingsLock = new ReentrantReadWriteLock(); private final ReentrantReadWriteLock referencesLock = new ReentrantReadWriteLock(); // ------------------------------------------------------------- Properties @Override public boolean isOverridable() { return overridable; } @Override public void setOverridable(boolean overridable) { this.overridable = overridable; } /** * Return the available date/time for this servlet, in milliseconds since * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean * that unavailability is permanent and any request for this servlet will return * an SC_NOT_FOUND error. If this date/time is in the future, any request for * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero, * the servlet is currently available. */ @Override public long getAvailable() { return (this.available); } /** * Set the available date/time for this servlet, in milliseconds since the * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean * that unavailability is permanent and any request for this servlet will return * an SC_NOT_FOUND error. If this date/time is in the future, any request for * this servlet will return an SC_SERVICE_UNAVAILABLE error. * * @param available The new available date/time */ @Override public void setAvailable(long available) { long oldAvailable = this.available; if (available > System.currentTimeMillis()) this.available = available; else this.available = 0L; support.firePropertyChange("available", Long.valueOf(oldAvailable), Long.valueOf(this.available)); } /** * Return the number of active allocations of this servlet, even if they * are all for the same instance (as will be true for servlets that do * not implement SingleThreadModel. */ public int getCountAllocated() { return (this.countAllocated.get()); } /** * Return descriptive information about this Container implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Return the InstanceSupport object for this Wrapper instance. */ public InstanceSupport getInstanceSupport() { return (this.instanceSupport); } /** * Return the load-on-startup order value (negative value means * load on first call). */ @Override public int getLoadOnStartup() { if (isJspServlet && loadOnStartup < 0) { /* * JspServlet must always be preloaded, because its instance is * used during registerJMX (when registering the JSP * monitoring mbean) */ return Integer.MAX_VALUE; } else { return (this.loadOnStartup); } } /** * Set the load-on-startup order value (negative value means * load on first call). * * @param value New load-on-startup value */ @Override public void setLoadOnStartup(int value) { int oldLoadOnStartup = this.loadOnStartup; this.loadOnStartup = value; support.firePropertyChange("loadOnStartup", Integer.valueOf(oldLoadOnStartup), Integer.valueOf(this.loadOnStartup)); } /** * Set the load-on-startup order value from a (possibly null) string. * Per the specification, any missing or non-numeric value is converted * to a zero, so that this servlet will still be loaded at startup * time, but in an arbitrary order. * * @param value New load-on-startup value */ public void setLoadOnStartupString(String value) { try { setLoadOnStartup(Integer.parseInt(value)); } catch (NumberFormatException e) { setLoadOnStartup(0); } } public String getLoadOnStartupString() { return Integer.toString( getLoadOnStartup()); } /** * Return maximum number of instances that will be allocated when a single * thread model servlet is used. */ public int getMaxInstances() { return (this.maxInstances); } /** * Set the maximum number of instances that will be allocated when a single * thread model servlet is used. * * @param maxInstances New value of maxInstances */ public void setMaxInstances(int maxInstances) { int oldMaxInstances = this.maxInstances; this.maxInstances = maxInstances; support.firePropertyChange("maxInstances", oldMaxInstances, this.maxInstances); } /** * Set the parent Container of this Wrapper, but only if it is a Context. * * @param container Proposed parent Container */ @Override public void setParent(Container container) { if ((container != null) && !(container instanceof Context)) throw new IllegalArgumentException (sm.getString("standardWrapper.notContext")); if (container instanceof StandardContext) { swallowOutput = ((StandardContext)container).getSwallowOutput(); unloadDelay = ((StandardContext)container).getUnloadDelay(); } super.setParent(container); } /** * Return the run-as identity for this servlet. */ @Override public String getRunAs() { return (this.runAs); } /** * Set the run-as identity for this servlet. * * @param runAs New run-as identity value */ @Override public void setRunAs(String runAs) { String oldRunAs = this.runAs; this.runAs = runAs; support.firePropertyChange("runAs", oldRunAs, this.runAs); } /** * Return the fully qualified servlet class name for this servlet. */ @Override public String getServletClass() { return (this.servletClass); } /** * Set the fully qualified servlet class name for this servlet. * * @param servletClass Servlet class name */ @Override public void setServletClass(String servletClass) { String oldServletClass = this.servletClass; this.servletClass = servletClass; support.firePropertyChange("servletClass", oldServletClass, this.servletClass); if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) { isJspServlet = true; } } /** * Set the name of this servlet. This is an alias for the normal * Container.setName() method, and complements the * getServletName() method required by the * ServletConfig interface. * * @param name The new name of this servlet */ public void setServletName(String name) { setName(name); } /** * Return true if the servlet class represented by this * component implements the SingleThreadModel interface. */ public boolean isSingleThreadModel() { // Short-cuts // If singleThreadModel is true, must have already checked this // If instance != null, must have already loaded if (singleThreadModel || instance != null) { return singleThreadModel; } // The logic to determine this safely is more complex than one might // expect. allocate() already has the necessary logic so re-use it. // Make sure the Servlet is loaded with the right class loader ClassLoader old = Thread.currentThread().getContextClassLoader(); ClassLoader webappClassLoader = ((Context) getParent()).getLoader().getClassLoader(); try { Thread.currentThread().setContextClassLoader(webappClassLoader); Servlet s = allocate(); deallocate(s); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } finally { Thread.currentThread().setContextClassLoader(old); } return singleThreadModel; } /** * Is this servlet currently unavailable? */ @Override public boolean isUnavailable() { if (!isEnabled()) return true; else if (available == 0L) return false; else if (available <= System.currentTimeMillis()) { available = 0L; return false; } else return true; } /** * Gets the names of the methods supported by the underlying servlet. * * This is the same set of methods included in the Allow response header * in response to an OPTIONS request method processed by the underlying * servlet. * * @return Array of names of the methods supported by the underlying * servlet */ @Override public String[] getServletMethods() throws ServletException { instance = loadServlet(); Class servletClazz = instance.getClass(); if (!javax.servlet.http.HttpServlet.class.isAssignableFrom( servletClazz)) { return DEFAULT_SERVLET_METHODS; } HashSet allow = new HashSet(); allow.add("TRACE"); allow.add("OPTIONS"); Method[] methods = getAllDeclaredMethods(servletClazz); for (int i=0; methods != null && iservice() method called. If the servlet class does * not implement SingleThreadModel, the (only) initialized * instance may be returned immediately. If the servlet class implements * SingleThreadModel, the Wrapper implementation must ensure * that this instance is not allocated again until it is deallocated by a * call to deallocate(). * * @exception ServletException if the servlet init() method threw * an exception * @exception ServletException if a loading error occurs */ @Override public Servlet allocate() throws ServletException { // If we are currently unloading this servlet, throw an exception if (unloading) throw new ServletException (sm.getString("standardWrapper.unloading", getName())); boolean newInstance = false; // If not SingleThreadedModel, return the same instance every time if (!singleThreadModel) { // Load and initialize our instance if necessary if (instance == null) { synchronized (this) { if (instance == null) { try { if (log.isDebugEnabled()) log.debug("Allocating non-STM instance"); instance = loadServlet(); if (!singleThreadModel) { // For non-STM, increment here to prevent a race // condition with unload. Bug 43683, test case // #3 newInstance = true; countAllocated.incrementAndGet(); } } catch (ServletException e) { throw e; } catch (Throwable e) { ExceptionUtils.handleThrowable(e); throw new ServletException (sm.getString("standardWrapper.allocate"), e); } } } } if (!instanceInitialized) { initServlet(instance); } if (singleThreadModel) { if (newInstance) { // Have to do this outside of the sync above to prevent a // possible deadlock synchronized (instancePool) { instancePool.push(instance); nInstances++; } } } else { if (log.isTraceEnabled()) log.trace(" Returning non-STM instance"); // For new instances, count will have been incremented at the // time of creation if (!newInstance) { countAllocated.incrementAndGet(); } return (instance); } } synchronized (instancePool) { while (countAllocated.get() >= nInstances) { // Allocate a new instance if possible, or else wait if (nInstances < maxInstances) { try { instancePool.push(loadServlet()); nInstances++; } catch (ServletException e) { throw e; } catch (Throwable e) { ExceptionUtils.handleThrowable(e); throw new ServletException (sm.getString("standardWrapper.allocate"), e); } } else { try { instancePool.wait(); } catch (InterruptedException e) { // Ignore } } } if (log.isTraceEnabled()) log.trace(" Returning allocated STM instance"); countAllocated.incrementAndGet(); return instancePool.pop(); } } /** * Return this previously allocated servlet to the pool of available * instances. If this servlet class does not implement SingleThreadModel, * no action is actually required. * * @param servlet The servlet to be returned * * @exception ServletException if a deallocation error occurs */ @Override public void deallocate(Servlet servlet) throws ServletException { // If not SingleThreadModel, no action is required if (!singleThreadModel) { countAllocated.decrementAndGet(); return; } // Unlock and free this instance synchronized (instancePool) { countAllocated.decrementAndGet(); instancePool.push(servlet); instancePool.notify(); } } /** * Return the value for the specified initialization parameter name, * if any; otherwise return null. * * @param name Name of the requested initialization parameter */ @Override public String findInitParameter(String name) { try { parametersLock.readLock().lock(); return parameters.get(name); } finally { parametersLock.readLock().unlock(); } } /** * Return the names of all defined initialization parameters for this * servlet. */ @Override public String[] findInitParameters() { try { parametersLock.readLock().lock(); String results[] = new String[parameters.size()]; return parameters.keySet().toArray(results); } finally { parametersLock.readLock().unlock(); } } /** * Return the mappings associated with this wrapper. */ @Override public String[] findMappings() { try { mappingsLock.readLock().lock(); return mappings.toArray(new String[mappings.size()]); } finally { mappingsLock.readLock().unlock(); } } /** * Return the security role link for the specified security role * reference name, if any; otherwise return null. * * @param name Security role reference used within this servlet */ @Override public String findSecurityReference(String name) { try { referencesLock.readLock().lock(); return references.get(name); } finally { referencesLock.readLock().unlock(); } } /** * Return the set of security role reference names associated with * this servlet, if any; otherwise return a zero-length array. */ @Override public String[] findSecurityReferences() { try { referencesLock.readLock().lock(); String results[] = new String[references.size()]; return references.keySet().toArray(results); } finally { referencesLock.readLock().unlock(); } } /** * FIXME: Fooling introspection ... */ @Deprecated public Wrapper findMappingObject() { return (Wrapper) getMappingObject(); } /** * Load and initialize an instance of this servlet, if there is not already * at least one initialized instance. This can be used, for example, to * load servlets that are marked in the deployment descriptor to be loaded * at server startup time. *

    * IMPLEMENTATION NOTE: Servlets whose classnames begin with * org.apache.catalina. (so-called "container" servlets) * are loaded by the same classloader that loaded this class, rather than * the classloader for the current web application. * This gives such classes access to Catalina internals, which are * prevented for classes loaded for web applications. * * @exception ServletException if the servlet init() method threw * an exception * @exception ServletException if some other loading problem occurs */ @Override public synchronized void load() throws ServletException { instance = loadServlet(); if (!instanceInitialized) { initServlet(instance); } if (isJspServlet) { StringBuilder oname = new StringBuilder(MBeanUtils.getDomain(getParent())); oname.append(":type=JspMonitor,name="); oname.append(getName()); oname.append(getWebModuleKeyProperties()); try { jspMonitorON = new ObjectName(oname.toString()); Registry.getRegistry(null, null) .registerComponent(instance, jspMonitorON, null); } catch( Exception ex ) { log.info("Error registering JSP monitoring with jmx " + instance); } } } /** * Load and initialize an instance of this servlet, if there is not already * at least one initialized instance. This can be used, for example, to * load servlets that are marked in the deployment descriptor to be loaded * at server startup time. */ public synchronized Servlet loadServlet() throws ServletException { // Nothing to do if we already have an instance or an instance pool if (!singleThreadModel && (instance != null)) return instance; PrintStream out = System.out; if (swallowOutput) { SystemLogHandler.startCapture(); } Servlet servlet; try { long t1=System.currentTimeMillis(); // Complain if no servlet class has been specified if (servletClass == null) { unavailable(null); throw new ServletException (sm.getString("standardWrapper.notClass", getName())); } InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager(); try { servlet = (Servlet) instanceManager.newInstance(servletClass); } catch (ClassCastException e) { unavailable(null); // Restore the context ClassLoader throw new ServletException (sm.getString("standardWrapper.notServlet", servletClass), e); } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); unavailable(null); // Added extra log statement for Bugzilla 36630: // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 if(log.isDebugEnabled()) { log.debug(sm.getString("standardWrapper.instantiate", servletClass), e); } // Restore the context ClassLoader throw new ServletException (sm.getString("standardWrapper.instantiate", servletClass), e); } if (multipartConfigElement == null) { MultipartConfig annotation = servlet.getClass().getAnnotation(MultipartConfig.class); if (annotation != null) { multipartConfigElement = new MultipartConfigElement(annotation); } } processServletSecurityAnnotation(servlet.getClass()); // Special handling for ContainerServlet instances if ((servlet instanceof ContainerServlet) && (isContainerProvidedServlet(servletClass) || ((Context) getParent()).getPrivileged() )) { ((ContainerServlet) servlet).setWrapper(this); } classLoadTime=(int) (System.currentTimeMillis() -t1); if (servlet instanceof SingleThreadModel) { if (instancePool == null) { instancePool = new Stack(); } singleThreadModel = true; } initServlet(servlet); fireContainerEvent("load", this); loadTime=System.currentTimeMillis() -t1; } finally { if (swallowOutput) { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { if (getServletContext() != null) { getServletContext().log(log); } else { out.println(log); } } } } return servlet; } /** * {@inheritDoc} */ @Override public void servletSecurityAnnotationScan() throws ServletException { if (getServlet() == null) { Class clazz = null; try { clazz = getParent().getLoader().getClassLoader().loadClass( getServletClass()); processServletSecurityAnnotation(clazz); } catch (ClassNotFoundException e) { // Safe to ignore. No class means no annotations to process } } else { if (servletSecurityAnnotationScanRequired) { processServletSecurityAnnotation(getServlet().getClass()); } } } private void processServletSecurityAnnotation(Class clazz) { // Calling this twice isn't harmful so no syncs servletSecurityAnnotationScanRequired = false; Context ctxt = (Context) getParent(); if (ctxt.getIgnoreAnnotations()) { return; } ServletSecurity secAnnotation = clazz.getAnnotation(ServletSecurity.class); if (secAnnotation != null) { ctxt.addServletSecurity( new ApplicationServletRegistration(this, ctxt), new ServletSecurityElement(secAnnotation)); } } private synchronized void initServlet(Servlet servlet) throws ServletException { if (instanceInitialized && !singleThreadModel) return; // Call the initialization method of this servlet try { instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, servlet); if( Globals.IS_SECURITY_ENABLED) { boolean success = false; try { Object[] args = new Object[] { facade }; SecurityUtil.doAsPrivilege("init", servlet, classType, args); success = true; } finally { if (!success) { // destroy() will not be called, thus clear the reference now SecurityUtil.remove(servlet); } } } else { servlet.init(facade); } instanceInitialized = true; instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet); } catch (UnavailableException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); unavailable(f); throw f; } catch (ServletException f) { instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw f; } catch (Throwable f) { ExceptionUtils.handleThrowable(f); getServletContext().log("StandardWrapper.Throwable", f ); instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, servlet, f); // If the servlet wanted to be unavailable it would have // said so, so do not call unavailable(null). throw new ServletException (sm.getString("standardWrapper.initException", getName()), f); } } /** * Remove the specified initialization parameter from this servlet. * * @param name Name of the initialization parameter to remove */ @Override public void removeInitParameter(String name) { try { parametersLock.writeLock().lock(); parameters.remove(name); } finally { parametersLock.writeLock().unlock(); } fireContainerEvent("removeInitParameter", name); } /** * Remove a listener no longer interested in InstanceEvents. * * @param listener The listener to remove */ @Override public void removeInstanceListener(InstanceListener listener) { instanceSupport.removeInstanceListener(listener); } /** * Remove a mapping associated with the wrapper. * * @param mapping The pattern to remove */ @Override public void removeMapping(String mapping) { try { mappingsLock.writeLock().lock(); mappings.remove(mapping); } finally { mappingsLock.writeLock().unlock(); } if(parent.getState().equals(LifecycleState.STARTED)) fireContainerEvent(REMOVE_MAPPING_EVENT, mapping); } /** * Remove any security role reference for the specified role name. * * @param name Security role used within this servlet to be removed */ @Override public void removeSecurityReference(String name) { try { referencesLock.writeLock().lock(); references.remove(name); } finally { referencesLock.writeLock().unlock(); } fireContainerEvent("removeSecurityReference", name); } /** * Return a String representation of this component. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); if (getParent() != null) { sb.append(getParent().toString()); sb.append("."); } sb.append("StandardWrapper["); sb.append(getName()); sb.append("]"); return (sb.toString()); } /** * Process an UnavailableException, marking this servlet as unavailable * for the specified amount of time. * * @param unavailable The exception that occurred, or null * to mark this servlet as permanently unavailable */ @Override public void unavailable(UnavailableException unavailable) { getServletContext().log(sm.getString("standardWrapper.unavailable", getName())); if (unavailable == null) setAvailable(Long.MAX_VALUE); else if (unavailable.isPermanent()) setAvailable(Long.MAX_VALUE); else { int unavailableSeconds = unavailable.getUnavailableSeconds(); if (unavailableSeconds <= 0) unavailableSeconds = 60; // Arbitrary default setAvailable(System.currentTimeMillis() + (unavailableSeconds * 1000L)); } } /** * Unload all initialized instances of this servlet, after calling the * destroy() method for each instance. This can be used, * for example, prior to shutting down the entire servlet engine, or * prior to reloading all of the classes from the Loader associated with * our Loader's repository. * * @exception ServletException if an exception is thrown by the * destroy() method */ @Override public synchronized void unload() throws ServletException { // Nothing to do if we have never loaded the instance if (!singleThreadModel && (instance == null)) return; unloading = true; // Loaf a while if the current instance is allocated // (possibly more than once if non-STM) if (countAllocated.get() > 0) { int nRetries = 0; long delay = unloadDelay / 20; while ((nRetries < 21) && (countAllocated.get() > 0)) { if ((nRetries % 10) == 0) { log.info(sm.getString("standardWrapper.waiting", countAllocated.toString(), getName())); } try { Thread.sleep(delay); } catch (InterruptedException e) { // Ignore } nRetries++; } } if (instanceInitialized) { PrintStream out = System.out; if (swallowOutput) { SystemLogHandler.startCapture(); } // Call the servlet destroy() method try { instanceSupport.fireInstanceEvent (InstanceEvent.BEFORE_DESTROY_EVENT, instance); if( Globals.IS_SECURITY_ENABLED) { try { SecurityUtil.doAsPrivilege("destroy", instance); } finally { SecurityUtil.remove(instance); } } else { instance.destroy(); } instanceSupport.fireInstanceEvent (InstanceEvent.AFTER_DESTROY_EVENT, instance); // Annotation processing if (!((Context) getParent()).getIgnoreAnnotations()) { ((StandardContext)getParent()).getInstanceManager().destroyInstance(instance); } } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); instanceSupport.fireInstanceEvent (InstanceEvent.AFTER_DESTROY_EVENT, instance, t); instance = null; instancePool = null; nInstances = 0; fireContainerEvent("unload", this); unloading = false; throw new ServletException (sm.getString("standardWrapper.destroyException", getName()), t); } finally { // Write captured output if (swallowOutput) { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { if (getServletContext() != null) { getServletContext().log(log); } else { out.println(log); } } } } } // Deregister the destroyed instance instance = null; if (isJspServlet && jspMonitorON != null ) { Registry.getRegistry(null, null).unregisterComponent(jspMonitorON); } if (singleThreadModel && (instancePool != null)) { try { while (!instancePool.isEmpty()) { Servlet s = instancePool.pop(); if (Globals.IS_SECURITY_ENABLED) { try { SecurityUtil.doAsPrivilege("destroy", s); } finally { SecurityUtil.remove(s); } } else { s.destroy(); } // Annotation processing if (!((Context) getParent()).getIgnoreAnnotations()) { ((StandardContext)getParent()).getInstanceManager().destroyInstance(s); } } } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); instancePool = null; nInstances = 0; unloading = false; fireContainerEvent("unload", this); throw new ServletException (sm.getString("standardWrapper.destroyException", getName()), t); } instancePool = null; nInstances = 0; } singleThreadModel = false; unloading = false; fireContainerEvent("unload", this); } // -------------------------------------------------- ServletConfig Methods /** * Return the initialization parameter value for the specified name, * if any; otherwise return null. * * @param name Name of the initialization parameter to retrieve */ @Override public String getInitParameter(String name) { return (findInitParameter(name)); } /** * Return the set of initialization parameter names defined for this * servlet. If none are defined, an empty Enumeration is returned. */ @Override public Enumeration getInitParameterNames() { try { parametersLock.readLock().lock(); return Collections.enumeration(parameters.keySet()); } finally { parametersLock.readLock().unlock(); } } /** * Return the servlet context with which this servlet is associated. */ @Override public ServletContext getServletContext() { if (parent == null) return (null); else if (!(parent instanceof Context)) return (null); else return (((Context) parent).getServletContext()); } /** * Return the name of this servlet. */ @Override public String getServletName() { return (getName()); } public long getProcessingTime() { return swValve.getProcessingTime(); } @Deprecated public void setProcessingTime(long processingTime) { swValve.setProcessingTime(processingTime); } public long getMaxTime() { return swValve.getMaxTime(); } @Deprecated public void setMaxTime(long maxTime) { swValve.setMaxTime(maxTime); } public long getMinTime() { return swValve.getMinTime(); } @Deprecated public void setMinTime(long minTime) { swValve.setMinTime(minTime); } public int getRequestCount() { return swValve.getRequestCount(); } @Deprecated public void setRequestCount(int requestCount) { swValve.setRequestCount(requestCount); } public int getErrorCount() { return swValve.getErrorCount(); } @Deprecated public void setErrorCount(int errorCount) { swValve.setErrorCount(errorCount); } /** * Increment the error count used for monitoring. */ @Override public void incrementErrorCount(){ swValve.incrementErrorCount(); } public long getLoadTime() { return loadTime; } @Deprecated public void setLoadTime(long loadTime) { this.loadTime = loadTime; } public int getClassLoadTime() { return classLoadTime; } @Override public MultipartConfigElement getMultipartConfigElement() { return multipartConfigElement; } @Override public void setMultipartConfigElement( MultipartConfigElement multipartConfigElement) { this.multipartConfigElement = multipartConfigElement; } @Override public boolean isAsyncSupported() { return asyncSupported; } @Override public void setAsyncSupported(boolean asyncSupported) { this.asyncSupported = asyncSupported; } @Override public boolean isEnabled() { return enabled; } @Override public void setEnabled(boolean enabled) { this.enabled = enabled; } // -------------------------------------------------------- Package Methods // -------------------------------------------------------- protected Methods /** * Return true if the specified class name represents a * container provided servlet class that should be loaded by the * server class loader. * * @param classname Name of the class to be checked */ protected boolean isContainerProvidedServlet(String classname) { if (classname.startsWith("org.apache.catalina.")) { return (true); } try { Class clazz = this.getClass().getClassLoader().loadClass(classname); return (ContainerServlet.class.isAssignableFrom(clazz)); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); return (false); } } protected Method[] getAllDeclaredMethods(Class c) { if (c.equals(javax.servlet.http.HttpServlet.class)) { return null; } Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); Method[] thisMethods = c.getDeclaredMethods(); if (thisMethods == null) { return parentMethods; } if ((parentMethods != null) && (parentMethods.length > 0)) { Method[] allMethods = new Method[parentMethods.length + thisMethods.length]; System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length); System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length); thisMethods = allMethods; } return thisMethods; } // ------------------------------------------------------ Lifecycle Methods /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Send j2ee.state.starting notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.starting", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } // Start up this component super.startInternal(); setAvailable(0L); // Send j2ee.state.running notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.running", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } } /** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setAvailable(Long.MAX_VALUE); // Send j2ee.state.stopping notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.stopping", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } // Shut down our servlet instance (if it has been initialized) try { unload(); } catch (ServletException e) { getServletContext().log(sm.getString ("standardWrapper.unloadException", getName()), e); } // Shut down this component super.stopInternal(); // Send j2ee.state.stoppped notification if (this.getObjectName() != null) { Notification notification = new Notification("j2ee.state.stopped", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } // Send j2ee.object.deleted notification Notification notification = new Notification("j2ee.object.deleted", this.getObjectName(), sequenceNumber++); broadcaster.sendNotification(notification); } @Override protected String getObjectNameKeyProperties() { StringBuilder keyProperties = new StringBuilder("j2eeType=Servlet,name="); String name = getName(); if (Util.objectNameValueNeedsQuote(name)) { name = ObjectName.quote(name); } keyProperties.append(name); keyProperties.append(getWebModuleKeyProperties()); return keyProperties.toString(); } private String getWebModuleKeyProperties() { StringBuilder keyProperties = new StringBuilder(",WebModule=//"); String hostName = getParent().getParent().getName(); if (hostName == null) { keyProperties.append("DEFAULT"); } else { keyProperties.append(hostName); } String contextName = ((Context) getParent()).getName(); if (!contextName.startsWith("/")) { keyProperties.append('/'); } keyProperties.append(contextName); StandardContext ctx = null; if (parent instanceof StandardContext) { ctx = (StandardContext) getParent(); } keyProperties.append(",J2EEApplication="); if (ctx == null) { keyProperties.append("none"); } else { keyProperties.append(ctx.getJ2EEApplication()); } keyProperties.append(",J2EEServer="); if (ctx == null) { keyProperties.append("none"); } else { keyProperties.append(ctx.getJ2EEServer()); } return keyProperties.toString(); } /** * JSR 77. Always return false. */ public boolean isStateManageable() { return false; } /* Remove a JMX notficationListener * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) */ @Override public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object object) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener,filter,object); } protected MBeanNotificationInfo[] notificationInfo; /* Get JMX Broadcaster Info * @TODO use StringManager for international support! * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! * @see javax.management.NotificationBroadcaster#getNotificationInfo() */ @Override public MBeanNotificationInfo[] getNotificationInfo() { if(notificationInfo == null) { notificationInfo = new MBeanNotificationInfo[]{ new MBeanNotificationInfo(new String[] { "j2ee.object.created"}, Notification.class.getName(), "servlet is created" ), new MBeanNotificationInfo(new String[] { "j2ee.state.starting"}, Notification.class.getName(), "servlet is starting" ), new MBeanNotificationInfo(new String[] { "j2ee.state.running"}, Notification.class.getName(), "servlet is running" ), new MBeanNotificationInfo(new String[] { "j2ee.state.stopped"}, Notification.class.getName(), "servlet start to stopped" ), new MBeanNotificationInfo(new String[] { "j2ee.object.stopped"}, Notification.class.getName(), "servlet is stopped" ), new MBeanNotificationInfo(new String[] { "j2ee.object.deleted"}, Notification.class.getName(), "servlet is deleted" ) }; } return notificationInfo; } /* Add a JMX-NotificationListener * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) */ @Override public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object object) throws IllegalArgumentException { broadcaster.addNotificationListener(listener,filter,object); } /** * Remove a JMX-NotificationListener * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) */ @Override public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { broadcaster.removeNotificationListener(listener); } // ------------------------------------------------------------- Attributes @Deprecated public boolean isEventProvider() { return false; } @Deprecated public boolean isStatisticsProvider() { return false; } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardEngine.java0000644000175100017510000003674212271471332024347 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Locale; import java.util.concurrent.atomic.AtomicReference; import org.apache.catalina.AccessLog; import org.apache.catalina.Container; import org.apache.catalina.ContainerEvent; import org.apache.catalina.ContainerListener; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Realm; import org.apache.catalina.Service; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.realm.NullRealm; import org.apache.catalina.util.ServerInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Standard implementation of the Engine interface. Each * child container must be a Host implementation to process the specific * fully qualified host name of that virtual host.
    * You can set the jvmRoute direct or with the System.property jvmRoute. * * @author Craig R. McClanahan */ public class StandardEngine extends ContainerBase implements Engine { private static final Log log = LogFactory.getLog(StandardEngine.class); // ----------------------------------------------------------- Constructors /** * Create a new StandardEngine component with the default basic Valve. */ public StandardEngine() { super(); pipeline.setBasic(new StandardEngineValve()); /* Set the jmvRoute using the system property jvmRoute */ try { setJvmRoute(System.getProperty("jvmRoute")); } catch(Exception ex) { log.warn(sm.getString("standardEngine.jvmRouteFail")); } // By default, the engine will hold the reloading thread backgroundProcessorDelay = 10; } // ----------------------------------------------------- Instance Variables /** * Host name to use when no server host, or an unknown host, * is specified in the request. */ private String defaultHost = null; /** * The descriptive information string for this implementation. */ private static final String info = "org.apache.catalina.core.StandardEngine/1.0"; /** * The Service that owns this Engine, if any. */ private Service service = null; /** Allow the base dir to be specified explicitly for * each engine. In time we should stop using catalina.base property - * otherwise we loose some flexibility. */ private String baseDir = null; /** * The JVM Route ID for this Tomcat instance. All Route ID's must be unique * across the cluster. */ private String jvmRouteId; /** * Default access log to use for request/response pairs where we can't ID * the intended host and context. */ private final AtomicReference defaultAccessLog = new AtomicReference(); // ------------------------------------------------------------- Properties /** * Obtain the configured Realm and provide a default Realm implementation * when no explicit configuration is set. * * @return configured realm, or a {@link NullRealm} by default */ @Override public Realm getRealm() { Realm configured = super.getRealm(); // If no set realm has been called - default to NullRealm // This can be overridden at engine, context and host level if (configured == null) { configured = new NullRealm(); this.setRealm(configured); } return configured; } /** * Return the default host. */ @Override public String getDefaultHost() { return (defaultHost); } /** * Set the default host. * * @param host The new default host */ @Override public void setDefaultHost(String host) { String oldDefaultHost = this.defaultHost; if (host == null) { this.defaultHost = null; } else { this.defaultHost = host.toLowerCase(Locale.ENGLISH); } support.firePropertyChange("defaultHost", oldDefaultHost, this.defaultHost); } /** * Set the cluster-wide unique identifier for this Engine. * This value is only useful in a load-balancing scenario. *

    * This property should not be changed once it is set. */ @Override public void setJvmRoute(String routeId) { jvmRouteId = routeId; } /** * Retrieve the cluster-wide unique identifier for this Engine. * This value is only useful in a load-balancing scenario. */ @Override public String getJvmRoute() { return jvmRouteId; } /** * Return the Service with which we are associated (if any). */ @Override public Service getService() { return (this.service); } /** * Set the Service with which we are associated (if any). * * @param service The service that owns this Engine */ @Override public void setService(Service service) { this.service = service; } public String getBaseDir() { if( baseDir==null ) { baseDir=System.getProperty(Globals.CATALINA_BASE_PROP); } if( baseDir==null ) { baseDir=System.getProperty(Globals.CATALINA_HOME_PROP); } return baseDir; } public void setBaseDir(String baseDir) { this.baseDir = baseDir; } // --------------------------------------------------------- Public Methods /** * Add a child Container, only if the proposed child is an implementation * of Host. * * @param child Child container to be added */ @Override public void addChild(Container child) { if (!(child instanceof Host)) throw new IllegalArgumentException (sm.getString("standardEngine.notHost")); super.addChild(child); } /** * Return descriptive information about this Container implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Disallow any attempt to set a parent for this Container, since an * Engine is supposed to be at the top of the Container hierarchy. * * @param container Proposed parent Container */ @Override public void setParent(Container container) { throw new IllegalArgumentException (sm.getString("standardEngine.notParent")); } @Override protected void initInternal() throws LifecycleException { // Ensure that a Realm is present before any attempt is made to start // one. This will create the default NullRealm if necessary. getRealm(); super.initInternal(); } /** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Log our server identification information if(log.isInfoEnabled()) log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo()); // Standard container startup super.startInternal(); } /** * Return a String representation of this component. */ @Override public String toString() { StringBuilder sb = new StringBuilder("StandardEngine["); sb.append(getName()); sb.append("]"); return (sb.toString()); } /** * Override the default implementation. If no access log is defined for the * Engine, look for one in the Engine's default host and then the default * host's ROOT context. If still none is found, return the default NoOp * access log. */ @Override public void logAccess(Request request, Response response, long time, boolean useDefault) { boolean logged = false; if (getAccessLog() != null) { accessLog.log(request, response, time); logged = true; } if (!logged && useDefault) { AccessLog newDefaultAccessLog = defaultAccessLog.get(); if (newDefaultAccessLog == null) { // If we reached this point, this Engine can't have an AccessLog // Look in the defaultHost Host host = (Host) findChild(getDefaultHost()); Context context = null; if (host != null && host.getState().isAvailable()) { newDefaultAccessLog = host.getAccessLog(); if (newDefaultAccessLog != null) { if (defaultAccessLog.compareAndSet(null, newDefaultAccessLog)) { AccessLogListener l = new AccessLogListener(this, host, null); l.install(); } } else { // Try the ROOT context of default host context = (Context) host.findChild(""); if (context != null && context.getState().isAvailable()) { newDefaultAccessLog = context.getAccessLog(); if (newDefaultAccessLog != null) { if (defaultAccessLog.compareAndSet(null, newDefaultAccessLog)) { AccessLogListener l = new AccessLogListener( this, null, context); l.install(); } } } } } if (newDefaultAccessLog == null) { newDefaultAccessLog = new NoopAccessLog(); if (defaultAccessLog.compareAndSet(null, newDefaultAccessLog)) { AccessLogListener l = new AccessLogListener(this, host, context); l.install(); } } } newDefaultAccessLog.log(request, response, time); } } /** * Return the parent class loader for this component. */ @Override public ClassLoader getParentClassLoader() { if (parentClassLoader != null) return (parentClassLoader); if (service != null) { return (service.getParentClassLoader()); } return (ClassLoader.getSystemClassLoader()); } // -------------------- JMX registration -------------------- @Override protected String getObjectNameKeyProperties() { return "type=Engine"; } // ----------------------------------------------------------- Inner classes protected static final class NoopAccessLog implements AccessLog { @Override public void log(Request request, Response response, long time) { // NOOP } @Override public void setRequestAttributesEnabled( boolean requestAttributesEnabled) { // NOOP } @Override public boolean getRequestAttributesEnabled() { // NOOP return false; } } protected static final class AccessLogListener implements PropertyChangeListener, LifecycleListener, ContainerListener { private StandardEngine engine; private Host host; private Context context; private volatile boolean disabled = false; public AccessLogListener(StandardEngine engine, Host host, Context context) { this.engine = engine; this.host = host; this.context = context; } public void install() { engine.addPropertyChangeListener(this); if (host != null) { host.addContainerListener(this); host.addLifecycleListener(this); } if (context != null) { context.addLifecycleListener(this); } } private void uninstall() { disabled = true; if (context != null) { context.removeLifecycleListener(this); } if (host != null) { host.removeLifecycleListener(this); host.removeContainerListener(this); } engine.removePropertyChangeListener(this); } @Override public void lifecycleEvent(LifecycleEvent event) { if (disabled) return; String type = event.getType(); if (Lifecycle.AFTER_START_EVENT.equals(type) || Lifecycle.BEFORE_STOP_EVENT.equals(type) || Lifecycle.BEFORE_DESTROY_EVENT.equals(type)) { // Container is being started/stopped/removed // Force re-calculation and disable listener since it won't // be re-used engine.defaultAccessLog.set(null); uninstall(); } } @Override public void propertyChange(PropertyChangeEvent evt) { if (disabled) return; if ("defaultHost".equals(evt.getPropertyName())) { // Force re-calculation and disable listener since it won't // be re-used engine.defaultAccessLog.set(null); uninstall(); } } @Override public void containerEvent(ContainerEvent event) { // Only useful for hosts if (disabled) return; if (Container.ADD_CHILD_EVENT.equals(event.getType())) { Context context = (Context) event.getData(); if ("".equals(context.getPath())) { // Force re-calculation and disable listener since it won't // be re-used engine.defaultAccessLog.set(null); uninstall(); } } } } } tomcat7-7.0.52/java/org/apache/catalina/core/AsyncListenerWrapper.java0000644000175100017510000000324611446460520025576 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; /** * TODO SERVLET3 - async * @author fhanik * */ public class AsyncListenerWrapper { private AsyncListener listener = null; public void fireOnStartAsync(AsyncEvent event) throws IOException { listener.onStartAsync(event); } public void fireOnComplete(AsyncEvent event) throws IOException { listener.onComplete(event); } public void fireOnTimeout(AsyncEvent event) throws IOException { listener.onTimeout(event); } public void fireOnError(AsyncEvent event) throws IOException { listener.onError(event); } public AsyncListener getListener() { return listener; } public void setListener(AsyncListener listener) { this.listener = listener; } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationJspPropertyGroupDescriptor.java0000644000175100017510000001025612271471332031212 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.Collection; import javax.servlet.descriptor.JspPropertyGroupDescriptor; import org.apache.catalina.deploy.JspPropertyGroup; public class ApplicationJspPropertyGroupDescriptor implements JspPropertyGroupDescriptor{ /** * @deprecated Will be made private in 8.0.x */ @Deprecated JspPropertyGroup jspPropertyGroup; public ApplicationJspPropertyGroupDescriptor( JspPropertyGroup jspPropertyGroup) { this.jspPropertyGroup = jspPropertyGroup; } @Override public String getBuffer() { String result = null; if (jspPropertyGroup.getBuffer() != null) { result = jspPropertyGroup.getBuffer().toString(); } return result; } @Override public String getDefaultContentType() { String result = null; if (jspPropertyGroup.getDefaultContentType() != null) { result = jspPropertyGroup.getDefaultContentType().toString(); } return result; } @Override public String getDeferredSyntaxAllowedAsLiteral() { String result = null; if (jspPropertyGroup.getDeferredSyntax() != null) { result = jspPropertyGroup.getDeferredSyntax().toString(); } return result; } @Override public String getElIgnored() { String result = null; if (jspPropertyGroup.getElIgnored() != null) { result = jspPropertyGroup.getElIgnored().toString(); } return result; } @Override public String getErrorOnUndeclaredNamespace() { String result = null; if (jspPropertyGroup.getErrorOnUndeclaredNamespace() != null) { result = jspPropertyGroup.getErrorOnUndeclaredNamespace().toString(); } return result; } @Override public Collection getIncludeCodas() { return jspPropertyGroup.getIncludeCodas(); } @Override public Collection getIncludePreludes() { return jspPropertyGroup.getIncludePreludes(); } @Override public String getIsXml() { String result = null; if (jspPropertyGroup.getIsXml() != null) { result = jspPropertyGroup.getIsXml().toString(); } return result; } @Override public String getPageEncoding() { String result = null; if (jspPropertyGroup.getPageEncoding() != null) { result = jspPropertyGroup.getPageEncoding().toString(); } return result; } @Override public String getScriptingInvalid() { String result = null; if (jspPropertyGroup.getScriptingInvalid() != null) { result = jspPropertyGroup.getScriptingInvalid().toString(); } return result; } @Override public String getTrimDirectiveWhitespaces() { String result = null; if (jspPropertyGroup.getTrimWhitespace() != null) { result = jspPropertyGroup.getTrimWhitespace().toString(); } return result; } @Override public Collection getUrlPatterns() { return jspPropertyGroup.getUrlPatterns(); } } tomcat7-7.0.52/java/org/apache/catalina/core/StandardEngineValve.java0000644000175100017510000001016212271471332025331 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Host; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.valves.ValveBase; import org.apache.tomcat.util.res.StringManager; /** * Valve that implements the default basic behavior for the * StandardEngine container implementation. *

    * USAGE CONSTRAINT: This implementation is likely to be useful only * when processing HTTP requests. * * @author Craig R. McClanahan */ final class StandardEngineValve extends ValveBase { //------------------------------------------------------ Constructor public StandardEngineValve() { super(true); } // ----------------------------------------------------- Instance Variables /** * The descriptive information related to this implementation. */ private static final String info = "org.apache.catalina.core.StandardEngineValve/1.0"; /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------------------------------------- Properties /** * Return descriptive information about this Valve implementation. */ @Override public String getInfo() { return (info); } // --------------------------------------------------------- Public Methods /** * Select the appropriate child Host to process this request, * based on the requested server name. If no matching Host can * be found, return an appropriate HTTP error. * * @param request Request to be processed * @param response Response to be produced * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public final void invoke(Request request, Response response) throws IOException, ServletException { // Select the Host to be used for this Request Host host = request.getHost(); if (host == null) { response.sendError (HttpServletResponse.SC_BAD_REQUEST, sm.getString("standardEngine.noHost", request.getServerName())); return; } if (request.isAsyncSupported()) { request.setAsyncSupported(host.getPipeline().isAsyncSupported()); } // Ask this Host to process this request host.getPipeline().getFirst().invoke(request, response); } /** * Process Comet event. * * @param request Request to be processed * @param response Response to be produced * @param event the event * * @exception IOException if an input/output error occurred * @exception ServletException if a servlet error occurred */ @Override public final void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Ask this Host to process this request request.getHost().getPipeline().getFirst().event(request, response, event); } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationHttpRequest.java0000644000175100017510000006247612271471332026140 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpSession; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Manager; import org.apache.catalina.Session; import org.apache.catalina.util.RequestUtil; /** * Wrapper around a javax.servlet.http.HttpServletRequest * that transforms an application request object (which might be the original * one passed to a servlet, or might be based on the 2.3 * javax.servlet.http.HttpServletRequestWrapper class) * back into an internal org.apache.catalina.HttpRequest. *

    * WARNING: Due to Java's lack of support for multiple * inheritance, all of the logic in ApplicationRequest is * duplicated in ApplicationHttpRequest. Make sure that you * keep these two classes in synchronization when making changes! * * @author Craig R. McClanahan * @author Remy Maucherat */ class ApplicationHttpRequest extends HttpServletRequestWrapper { // ------------------------------------------------------- Static Variables /** * The set of attribute names that are special for request dispatchers. */ protected static final String specials[] = { RequestDispatcher.INCLUDE_REQUEST_URI, RequestDispatcher.INCLUDE_CONTEXT_PATH, RequestDispatcher.INCLUDE_SERVLET_PATH, RequestDispatcher.INCLUDE_PATH_INFO, RequestDispatcher.INCLUDE_QUERY_STRING, RequestDispatcher.FORWARD_REQUEST_URI, RequestDispatcher.FORWARD_CONTEXT_PATH, RequestDispatcher.FORWARD_SERVLET_PATH, RequestDispatcher.FORWARD_PATH_INFO, RequestDispatcher.FORWARD_QUERY_STRING }; // ----------------------------------------------------------- Constructors /** * Construct a new wrapped request around the specified servlet request. * * @param request The servlet request being wrapped */ public ApplicationHttpRequest(HttpServletRequest request, Context context, boolean crossContext) { super(request); this.context = context; this.crossContext = crossContext; setRequest(request); } // ----------------------------------------------------- Instance Variables /** * The context for this request. */ protected Context context = null; /** * The context path for this request. */ protected String contextPath = null; /** * If this request is cross context, since this changes session access * behavior. */ protected boolean crossContext = false; /** * The current dispatcher type. */ protected DispatcherType dispatcherType = null; /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.core.ApplicationHttpRequest/1.0"; /** * The request parameters for this request. This is initialized from the * wrapped request, but updates are allowed. */ protected Map parameters = null; /** * Have the parameters for this request already been parsed? */ private boolean parsedParams = false; /** * The path information for this request. */ protected String pathInfo = null; /** * The query parameters for the current request. */ private String queryParamString = null; /** * The query string for this request. */ protected String queryString = null; /** * The current request dispatcher path. */ protected Object requestDispatcherPath = null; /** * The request URI for this request. */ protected String requestURI = null; /** * The servlet path for this request. */ protected String servletPath = null; /** * The currently active session for this request. */ protected Session session = null; /** * Special attributes. */ protected Object[] specialAttributes = new Object[specials.length]; // ------------------------------------------------- ServletRequest Methods /** * Override the getAttribute() method of the wrapped request. * * @param name Name of the attribute to retrieve */ @Override public Object getAttribute(String name) { if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { return dispatcherType; } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { if ( requestDispatcherPath != null ){ return requestDispatcherPath.toString(); } else { return null; } } int pos = getSpecial(name); if (pos == -1) { return getRequest().getAttribute(name); } else { if ((specialAttributes[pos] == null) && (specialAttributes[5] == null) && (pos >= 5)) { // If it's a forward special attribute, and null, it means this // is an include, so we check the wrapped request since // the request could have been forwarded before the include return getRequest().getAttribute(name); } else { return specialAttributes[pos]; } } } /** * Override the getAttributeNames() method of the wrapped * request. */ @Override public Enumeration getAttributeNames() { return (new AttributeNamesEnumerator()); } /** * Override the removeAttribute() method of the * wrapped request. * * @param name Name of the attribute to remove */ @Override public void removeAttribute(String name) { if (!removeSpecial(name)) getRequest().removeAttribute(name); } /** * Override the setAttribute() method of the * wrapped request. * * @param name Name of the attribute to set * @param value Value of the attribute to set */ @Override public void setAttribute(String name, Object value) { if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { dispatcherType = (DispatcherType)value; return; } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { requestDispatcherPath = value; return; } if (!setSpecial(name, value)) { getRequest().setAttribute(name, value); } } /** * Return a RequestDispatcher that wraps the resource at the specified * path, which may be interpreted as relative to the current request path. * * @param path Path of the resource to be wrapped */ @Override public RequestDispatcher getRequestDispatcher(String path) { if (context == null) return (null); // If the path is already context-relative, just pass it through if (path == null) return (null); else if (path.startsWith("/")) return (context.getServletContext().getRequestDispatcher(path)); // Convert a request-relative path to a context-relative one String servletPath = (String) getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); if (servletPath == null) servletPath = getServletPath(); // Add the path info, if there is any String pathInfo = getPathInfo(); String requestPath = null; if (pathInfo == null) { requestPath = servletPath; } else { requestPath = servletPath + pathInfo; } int pos = requestPath.lastIndexOf('/'); String relative = null; if (pos >= 0) { relative = requestPath.substring(0, pos + 1) + path; } else { relative = requestPath + path; } return (context.getServletContext().getRequestDispatcher(relative)); } /** * Override the getDispatcherType() method of the wrapped request. * */ @Override public DispatcherType getDispatcherType() { return dispatcherType; } // --------------------------------------------- HttpServletRequest Methods /** * Override the getContextPath() method of the wrapped * request. */ @Override public String getContextPath() { return (this.contextPath); } /** * Override the getParameter() method of the wrapped request. * * @param name Name of the requested parameter */ @Override public String getParameter(String name) { parseParameters(); Object value = parameters.get(name); if (value == null) return (null); else if (value instanceof String[]) return (((String[]) value)[0]); else if (value instanceof String) return ((String) value); else return (value.toString()); } /** * Override the getParameterMap() method of the * wrapped request. */ @Override public Map getParameterMap() { parseParameters(); return (parameters); } /** * Override the getParameterNames() method of the * wrapped request. */ @Override public Enumeration getParameterNames() { parseParameters(); return Collections.enumeration(parameters.keySet()); } /** * Override the getParameterValues() method of the * wrapped request. * * @param name Name of the requested parameter */ @Override public String[] getParameterValues(String name) { parseParameters(); Object value = parameters.get(name); if (value == null) return null; else if (value instanceof String[]) return ((String[]) value); else if (value instanceof String) { String values[] = new String[1]; values[0] = (String) value; return (values); } else { String values[] = new String[1]; values[0] = value.toString(); return (values); } } /** * Override the getPathInfo() method of the wrapped request. */ @Override public String getPathInfo() { return (this.pathInfo); } /** * Override the getQueryString() method of the wrapped * request. */ @Override public String getQueryString() { return (this.queryString); } /** * Override the getRequestURI() method of the wrapped * request. */ @Override public String getRequestURI() { return (this.requestURI); } /** * Override the getRequestURL() method of the wrapped * request. */ @Override public StringBuffer getRequestURL() { StringBuffer url = new StringBuffer(); String scheme = getScheme(); int port = getServerPort(); if (port < 0) port = 80; // Work around java.net.URL bug url.append(scheme); url.append("://"); url.append(getServerName()); if ((scheme.equals("http") && (port != 80)) || (scheme.equals("https") && (port != 443))) { url.append(':'); url.append(port); } url.append(getRequestURI()); return (url); } /** * Override the getServletPath() method of the wrapped * request. */ @Override public String getServletPath() { return (this.servletPath); } /** * Return the session associated with this Request, creating one * if necessary. */ @Override public HttpSession getSession() { return (getSession(true)); } /** * Return the session associated with this Request, creating one * if necessary and requested. * * @param create Create a new session if one does not exist */ @Override public HttpSession getSession(boolean create) { if (crossContext) { // There cannot be a session if no context has been assigned yet if (context == null) return (null); // Return the current session if it exists and is valid if (session != null && session.isValid()) { return (session.getSession()); } HttpSession other = super.getSession(false); if (create && (other == null)) { // First create a session in the first context: the problem is // that the top level request is the only one which can // create the cookie safely other = super.getSession(true); } if (other != null) { Session localSession = null; try { localSession = context.getManager().findSession(other.getId()); if (localSession != null && !localSession.isValid()) { localSession = null; } } catch (IOException e) { // Ignore } if (localSession == null && create) { localSession = context.getManager().createSession(other.getId()); } if (localSession != null) { localSession.access(); session = localSession; return session.getSession(); } } return null; } else { return super.getSession(create); } } /** * Returns true if the request specifies a JSESSIONID that is valid within * the context of this ApplicationHttpRequest, false otherwise. * * @return true if the request specifies a JSESSIONID that is valid within * the context of this ApplicationHttpRequest, false otherwise. */ @Override public boolean isRequestedSessionIdValid() { if (crossContext) { String requestedSessionId = getRequestedSessionId(); if (requestedSessionId == null) return (false); if (context == null) return (false); Manager manager = context.getManager(); if (manager == null) return (false); Session session = null; try { session = manager.findSession(requestedSessionId); } catch (IOException e) { // Ignore } if ((session != null) && session.isValid()) { return (true); } else { return (false); } } else { return super.isRequestedSessionIdValid(); } } // -------------------------------------------------------- Package Methods /** * Recycle this request */ public void recycle() { if (session != null) { session.endAccess(); } } /** * Return descriptive information about this implementation. */ public String getInfo() { return (info); } /** * Perform a shallow copy of the specified Map, and return the result. * * @param orig Origin Map to be copied */ Map copyMap(Map orig) { if (orig == null) return (new HashMap()); HashMap dest = new HashMap(); for (Map.Entry entry : orig.entrySet()) { dest.put(entry.getKey(), entry.getValue()); } return (dest); } /** * Set the context path for this request. * * @param contextPath The new context path */ void setContextPath(String contextPath) { this.contextPath = contextPath; } /** * Set the path information for this request. * * @param pathInfo The new path info */ void setPathInfo(String pathInfo) { this.pathInfo = pathInfo; } /** * Set the query string for this request. * * @param queryString The new query string */ void setQueryString(String queryString) { this.queryString = queryString; } /** * Set the request that we are wrapping. * * @param request The new wrapped request */ void setRequest(HttpServletRequest request) { super.setRequest(request); // Initialize the attributes for this request dispatcherType = (DispatcherType)request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); requestDispatcherPath = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); // Initialize the path elements for this request contextPath = request.getContextPath(); pathInfo = request.getPathInfo(); queryString = request.getQueryString(); requestURI = request.getRequestURI(); servletPath = request.getServletPath(); } /** * Set the request URI for this request. * * @param requestURI The new request URI */ void setRequestURI(String requestURI) { this.requestURI = requestURI; } /** * Set the servlet path for this request. * * @param servletPath The new servlet path */ void setServletPath(String servletPath) { this.servletPath = servletPath; } /** * Parses the parameters of this request. * * If parameters are present in both the query string and the request * content, they are merged. */ void parseParameters() { if (parsedParams) { return; } parameters = new HashMap(); parameters = copyMap(getRequest().getParameterMap()); mergeParameters(); parsedParams = true; } /** * Save query parameters for this request. * * @param queryString The query string containing parameters for this * request */ void setQueryParams(String queryString) { this.queryParamString = queryString; } // ------------------------------------------------------ Protected Methods /** * Is this attribute name one of the special ones that is added only for * included servlets? * * @param name Attribute name to be tested */ protected boolean isSpecial(String name) { for (int i = 0; i < specials.length; i++) { if (specials[i].equals(name)) return (true); } return (false); } /** * Get a special attribute. * * @return the special attribute pos, or -1 if it is not a special * attribute */ protected int getSpecial(String name) { for (int i = 0; i < specials.length; i++) { if (specials[i].equals(name)) { return (i); } } return (-1); } /** * Set a special attribute. * * @return true if the attribute was a special attribute, false otherwise */ protected boolean setSpecial(String name, Object value) { for (int i = 0; i < specials.length; i++) { if (specials[i].equals(name)) { specialAttributes[i] = value; return (true); } } return (false); } /** * Remove a special attribute. * * @return true if the attribute was a special attribute, false otherwise */ protected boolean removeSpecial(String name) { for (int i = 0; i < specials.length; i++) { if (specials[i].equals(name)) { specialAttributes[i] = null; return (true); } } return (false); } /** * Merge the two sets of parameter values into a single String array. * * @param values1 First set of values * @param values2 Second set of values */ protected String[] mergeValues(Object values1, Object values2) { ArrayList results = new ArrayList(); if (values1 == null) { // Skip - nothing to merge } else if (values1 instanceof String) results.add(values1); else if (values1 instanceof String[]) { String values[] = (String[]) values1; for (int i = 0; i < values.length; i++) results.add(values[i]); } else results.add(values1.toString()); if (values2 == null) { // Skip - nothing to merge } else if (values2 instanceof String) results.add(values2); else if (values2 instanceof String[]) { String values[] = (String[]) values2; for (int i = 0; i < values.length; i++) results.add(values[i]); } else results.add(values2.toString()); String values[] = new String[results.size()]; return results.toArray(values); } // ------------------------------------------------------ Private Methods /** * Merge the parameters from the saved query parameter string (if any), and * the parameters already present on this request (if any), such that the * parameter values from the query string show up first if there are * duplicate parameter names. */ private void mergeParameters() { if ((queryParamString == null) || (queryParamString.length() < 1)) return; HashMap queryParameters = new HashMap(); String encoding = getCharacterEncoding(); if (encoding == null) encoding = "ISO-8859-1"; RequestUtil.parseParameters(queryParameters, queryParamString, encoding); Iterator keys = parameters.keySet().iterator(); while (keys.hasNext()) { String key = keys.next(); Object value = queryParameters.get(key); if (value == null) { queryParameters.put(key, parameters.get(key)); continue; } queryParameters.put (key, mergeValues(value, parameters.get(key))); } parameters = queryParameters; } // ----------------------------------- AttributeNamesEnumerator Inner Class /** * Utility class used to expose the special attributes as being available * as request attributes. */ protected class AttributeNamesEnumerator implements Enumeration { protected int pos = -1; protected int last = -1; protected Enumeration parentEnumeration = null; protected String next = null; public AttributeNamesEnumerator() { parentEnumeration = getRequest().getAttributeNames(); for (int i = specialAttributes.length - 1; i >= 0; i--) { if (getAttribute(specials[i]) != null) { last = i; break; } } } @Override public boolean hasMoreElements() { return ((pos != last) || (next != null) || ((next = findNext()) != null)); } @Override public String nextElement() { if (pos != last) { for (int i = pos + 1; i <= last; i++) { if (getAttribute(specials[i]) != null) { pos = i; return (specials[i]); } } } String result = next; if (next != null) { next = findNext(); } else { throw new NoSuchElementException(); } return result; } protected String findNext() { String result = null; while ((result == null) && (parentEnumeration.hasMoreElements())) { String current = parentEnumeration.nextElement(); if (!isSpecial(current)) { result = current; } } return result; } } } tomcat7-7.0.52/java/org/apache/catalina/core/LocalStrings_ja.properties0000644000175100017510000006133212271471332026003 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationContext.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f applicationContext.mapping.error=\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 applicationContext.requestDispatcher.iae=\u30d1\u30b9 {0} \u304c"/"\u6587\u5b57\u3067\u59cb\u307e\u308a\u307e\u305b\u3093 applicationContext.setAttribute.namenull=name\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 applicationDispatcher.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059 applicationDispatcher.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059 applicationDispatcher.forward.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30d5\u30a9\u30ef\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 applicationDispatcher.forward.throw=\u30d5\u30a9\u30ef\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f applicationDispatcher.include.throw=\u30a4\u30f3\u30af\u30eb\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f applicationDispatcher.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 applicationDispatcher.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f applicationRequest.badParent=\u89aa\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 applicationRequest.badRequest=\u30ea\u30af\u30a8\u30b9\u30c8\u304cjavax.servlet.ServletRequestWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093 applicationResponse.badParent=\u89aa\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 applicationResponse.badResponse=\u30ec\u30b9\u30dd\u30f3\u30b9\u304cjavax.servlet.ServletResponseWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093 containerBase.alreadyStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 containerBase.notConfigured=\u57fa\u672c\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 containerBase.notStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 fastEngineMapper.alreadyStarted=FastEngineMapper {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 fastEngineMapper.notStarted=FastEngineMapper {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 filterChain.filter=\u30d5\u30a3\u30eb\u30bf\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f filterChain.servlet=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f httpContextMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardContext\u3067\u306f\u3042\u308a\u307e\u305b\u3093 httpEngineMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardEngine\u3067\u306f\u3042\u308a\u307e\u305b\u3093 httpHostMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardHost\u3067\u306f\u3042\u308a\u307e\u305b\u3093 interceptorValve.alreadyStarted=InterceptorValve\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 interceptorValve.notStarted=InterceptorValve\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 naming.bindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} naming.unbindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} naming.invalidEnvEntryType=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u578b\u3092\u6301\u3063\u3066\u3044\u307e\u3059 naming.invalidEnvEntryValue=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u5024\u3092\u6301\u3063\u3066\u3044\u307e\u3059 naming.namingContextCreationFailed=\u540d\u524d\u4ed8\u304d\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} standardContext.alreadyStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 standardContext.applicationListener=\u30af\u30e9\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f standardContext.applicationSkipped=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059 standardContext.badRequest=\u7121\u52b9\u306a\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9\u3067\u3059 ({0})\u3002 standardContext.errorPage.error=\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.errorPage.required=ErrorPage\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 standardContext.errorPage.warning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.filterMap.either=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u53c8\u306f\u306e\u3069\u3061\u3089\u304b\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.filterMap.name=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30d5\u30a3\u30eb\u30bf\u540d {0} \u3092\u6307\u5b9a\u3057\u307e\u3057\u305f standardContext.filterMap.pattern=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 standardContext.filterStart=\u30d5\u30a3\u30eb\u30bf {0} \u306e\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.filterStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d5\u30a3\u30eb\u30bf\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f standardContext.requestListenerStartFailed=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f standardContext.requestListenerConfig.added=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f standardContext.requestListenerConfig.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u8ffd\u52a0\u4e2d\u306e\u4f8b\u5916\u3067\u3059: {0} standardContext.isUnavailable=\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 standardContext.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.listenerStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f standardContext.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u7834\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.loginConfig.errorPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.loginConfig.errorWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.loginConfig.loginPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.loginConfig.loginWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.loginConfig.required=LoginConfig\u306fnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 standardContext.mappingError=\u76f8\u5bfeURI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 standardContext.notFound=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9 ({0}) \u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 standardContext.notReloadable=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u518d\u30ed\u30fc\u30c9\u306f\u7121\u52b9\u3067\u3059 standardContext.notStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 standardContext.notWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30e9\u30c3\u30d1\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.parameter.duplicate=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30d1\u30e9\u30e1\u30bf {0} \u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059 standardContext.parameter.required=\u30d1\u30e9\u30e1\u30bf\u540d\u3068\u30d1\u30e9\u30e1\u30bf\u5024\u306e\u4e21\u65b9\u304c\u5fc5\u8981\u3067\u3059 standardContext.reloadingCompleted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f standardContext.reloadingFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f standardContext.reloadingStarted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u3092\u958b\u59cb\u3057\u307e\u3057\u305f standardContext.requestListener.requestInit=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.requestListener.requestDestroy=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.resourcesStart=\u9759\u7684\u30ea\u30bd\u30fc\u30b9\u306e\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 standardContext.securityConstraint.pattern=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e\u5236\u7d04\u306e\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 standardContext.servletMap.name=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u540d {0} \u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059 standardContext.servletMap.pattern=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 standardContext.startCleanup=\u8d77\u52d5\u304c\u5931\u6557\u3057\u305f\u5f8c\u306e\u30af\u30ea\u30fc\u30f3\u30ca\u30c3\u30d7\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f standardContext.startFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u8d77\u52d5\u304c\u5931\u6557\u3057\u307e\u3057\u305f [{0}] standardContext.startingLoader=\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.startingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.startingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.stoppingContext=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.stoppingLoader=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.stoppingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.stoppingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 standardContext.urlDecode=\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u306eURL\u30c7\u30b3\u30fc\u30c9\u304c\u3067\u304d\u307e\u305b\u3093 standardContext.urlPattern.patternWarning=\u8b66\u544a: Servlet 2.4\u3067\u306fURL\u30d1\u30bf\u30fc\u30f3 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardContext.urlValidate=URL\u30c7\u30b3\u30fc\u30c9\u3055\u308c\u305f\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u3092\u691c\u8a3c\u3067\u304d\u307e\u305b\u3093 standardEngine.alreadyStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 standardEngine.mappingError=\u30b5\u30fc\u30d0\u540d {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 standardEngine.noHost=\u30b5\u30fc\u30d0\u540d {0} \u306b\u4e00\u81f4\u3059\u308b\u30db\u30b9\u30c8\u304c\u5b58\u5728\u3057\u307e\u305b\u3093 standardEngine.noHostHeader=Host:\u30d8\u30c3\u30c0\u3092\u6301\u305f\u306a\u3044 HTTP/1.1 \u30ea\u30af\u30a8\u30b9\u30c8\u3067\u3059 standardEngine.notHost=\u30a8\u30f3\u30b8\u30f3\u306e\u5b50\u4f9b\u306f\u30db\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardEngine.notParent=\u30a8\u30f3\u30b8\u30f3\u306f\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 standardEngine.notStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 standardEngine.unfoundHost=\u30d0\u30fc\u30c1\u30e3\u30eb\u30db\u30b9\u30c8 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 standardEngine.unknownHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u4e2d\u306b\u30b5\u30fc\u30d0\u30db\u30b9\u30c8\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 standardHost.accessBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093 standardHost.alreadyStarted=\u30db\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 standardHost.appBase=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093 standardHost.clientAbort=\u30ea\u30e2\u30fc\u30c8\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304c\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u4e2d\u6b62\u3057\u307e\u3057\u305f, IOException: {0} standardHost.configRequired=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3078\u306eURL\u304c\u5fc5\u8981\u3067\u3059 standardHost.configNotAllowed=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u304c\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 standardHost.installBase=\u30db\u30b9\u30c8Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u4e2d\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3060\u3051\u304c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u3059 standardHost.installing=URL {1} \u304b\u3089\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306bWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059 standardHost.installingWAR=URL {0} \u304b\u3089Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059 standardHost.installingXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eURL {0} \u3092\u51e6\u7406\u3057\u3066\u3044\u307e\u3059 standardHost.installError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 standardHost.invalidErrorReportValveClass=\u6307\u5b9a\u3055\u308c\u305f\u30a8\u30e9\u30fc\u30ea\u30dd\u30fc\u30c8\u30d0\u30eb\u30d6\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093: {0} standardHost.docBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059 standardHost.mappingError=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 standardHost.noContext=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 standardHost.noHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30db\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 standardHost.notContext=\u30db\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardHost.notStarted=\u30db\u30b9\u30c8\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 standardHost.nullName=\u30db\u30b9\u30c8\u540d\u304c\u5fc5\u8981\u3067\u3059 standardHost.pathFormat=\u7121\u52b9\u306a\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u3067\u3059: {0} standardHost.pathMatch=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u53c8\u306fWAR\u30d5\u30a1\u30a4\u30eb\u540d\u306b\u4e00\u81f4\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093: {1} standardHost.pathMissing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u73fe\u5728\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u305b\u3093 standardHost.pathRequired=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u304c\u5fc5\u8981\u3067\u3059 standardHost.pathUsed=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u65e2\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059 standardHost.removing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u3057\u307e\u3059 standardHost.removeError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f standardHost.start=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u307e\u3059 standardHost.stop=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u505c\u6b62\u3057\u307e\u3059 standardHost.unfoundContext=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 standardHost.warRequired=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306eURL\u304c\u5fc5\u8981\u3067\u3059 standardHost.warURL=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306aURL\u3067\u3059: {0} standardService.start.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u8d77\u52d5\u3057\u307e\u3059 standardService.stop.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u505c\u6b62\u3057\u307e\u3059 standardWrapper.allocate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 standardWrapper.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059 standardWrapper.containerServlet=\u30b3\u30f3\u30c6\u30ca\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 standardWrapper.createFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0}\u306b\u5bfe\u3059\u308b\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u4f5c\u6210\u3057\u307e\u3059 standardWrapper.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u5bfe\u3059\u308b\u4f8b\u5916\u306e\u5272\u308a\u5f53\u3066\u3092\u89e3\u9664\u3057\u307e\u3059 standardWrapper.destroyException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.destroy()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardWrapper.exception0=Tomcat\u306e\u4f8b\u5916\u306e\u5831\u544a standardWrapper.exception1=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f standardWrapper.exception2=\u4f8b\u5916\u306e\u5831\u544a: standardWrapper.exception3=\u6839\u672c\u306e\u539f\u56e0: standardWrapper.initException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.init()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardWrapper.instantiate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u3092\u521d\u671f\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f standardWrapper.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 standardWrapper.jasperLoader=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306bJasper\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u3092\u4f7f\u7528\u3057\u307e\u3059 standardWrapper.jspFile.format=JSP\u30d5\u30a1\u30a4\u30eb {0} \u304c''/''\u6587\u5b57\u3067\u59cb\u307e\u3063\u3066\u3044\u307e\u305b\u3093 standardWrapper.loadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardWrapper.missingClass=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u53c8\u306f\u305d\u308c\u304c\u4f9d\u5b58\u3059\u308b\u30af\u30e9\u30b9\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 standardWrapper.missingLoader=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30ed\u30fc\u30c0\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 standardWrapper.notChild=\u30e9\u30c3\u30d1\u30b3\u30f3\u30c6\u30ca\u306f\u5b50\u4f9b\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 standardWrapper.notClass=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u6307\u5b9a\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9\u304c\u3042\u308a\u307e\u305b\u3093 standardWrapper.notContext=\u30e9\u30c3\u30d1\u306e\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 standardWrapper.notFound=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093 standardWrapper.notServlet=\u30af\u30e9\u30b9 {0} \u306f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 standardWrapper.releaseFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059 standardWrapper.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardWrapper.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1} standardWrapper.statusTitle=Tomcat\u306e\u30a8\u30e9\u30fc\u306e\u5831\u544a standardWrapper.unavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u5229\u7528\u4e0d\u53ef\u80fd\u306b\u30de\u30fc\u30af\u3057\u307e\u3059 standardWrapper.unloadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cunload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f standardWrapper.unloading=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u30ed\u30fc\u30c9\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u5272\u308a\u5f53\u3066\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 standardWrapper.waiting={0} \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u5272\u308a\u5f53\u3066\u89e3\u9664\u3055\u308c\u308b\u306e\u3092\u5f85\u3063\u3066\u3044\u307e\u3059 tomcat7-7.0.52/java/org/apache/catalina/core/StandardServer.java0000644000175100017510000006244312271471332024405 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.security.AccessControlException; import java.util.Random; import javax.management.ObjectName; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.deploy.NamingResources; import org.apache.catalina.mbeans.MBeanFactory; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.startup.Catalina; import org.apache.catalina.util.ExtensionValidator; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.catalina.util.ServerInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.StringCache; import org.apache.tomcat.util.res.StringManager; /** * Standard implementation of the Server interface, available for use * (but not required) when deploying and starting Catalina. * * @author Craig R. McClanahan */ public final class StandardServer extends LifecycleMBeanBase implements Server { private static final Log log = LogFactory.getLog(StandardServer.class); // ------------------------------------------------------------ Constructor /** * Construct a default instance of this class. */ public StandardServer() { super(); globalNamingResources = new NamingResources(); globalNamingResources.setContainer(this); if (isUseNaming()) { if (namingContextListener == null) { namingContextListener = new NamingContextListener(); addLifecycleListener(namingContextListener); } } } // ----------------------------------------------------- Instance Variables /** * Global naming resources context. */ private javax.naming.Context globalNamingContext = null; /** * Global naming resources. */ private NamingResources globalNamingResources = null; /** * Descriptive information about this Server implementation. */ private static final String info = "org.apache.catalina.core.StandardServer/1.0"; /** * The naming context listener for this web application. */ private NamingContextListener namingContextListener = null; /** * The port number on which we wait for shutdown commands. */ private int port = 8005; /** * The address on which we wait for shutdown commands. */ private String address = "localhost"; /** * A random number generator that is only used if * the shutdown command string is longer than 1024 characters. */ private Random random = null; /** * The set of Services associated with this Server. */ private Service services[] = new Service[0]; /** * The shutdown command string we are looking for. */ private String shutdown = "SHUTDOWN"; /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); private volatile boolean stopAwait = false; private Catalina catalina = null; private ClassLoader parentClassLoader = null; /** * Thread that currently is inside our await() method. */ private volatile Thread awaitThread = null; /** * Server socket that is used to wait for the shutdown command. */ private volatile ServerSocket awaitSocket = null; // ------------------------------------------------------------- Properties /** * Return the global naming resources context. */ @Override public javax.naming.Context getGlobalNamingContext() { return (this.globalNamingContext); } /** * Set the global naming resources context. * * @param globalNamingContext The new global naming resource context */ public void setGlobalNamingContext (javax.naming.Context globalNamingContext) { this.globalNamingContext = globalNamingContext; } /** * Return the global naming resources. */ @Override public NamingResources getGlobalNamingResources() { return (this.globalNamingResources); } /** * Set the global naming resources. * * @param globalNamingResources The new global naming resources */ @Override public void setGlobalNamingResources (NamingResources globalNamingResources) { NamingResources oldGlobalNamingResources = this.globalNamingResources; this.globalNamingResources = globalNamingResources; this.globalNamingResources.setContainer(this); support.firePropertyChange("globalNamingResources", oldGlobalNamingResources, this.globalNamingResources); } /** * Return descriptive information about this Server implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Report the current Tomcat Server Release number * @return Tomcat release identifier */ public String getServerInfo() { return ServerInfo.getServerInfo(); } /** * Return the port number we listen to for shutdown commands. */ @Override public int getPort() { return (this.port); } /** * Set the port number we listen to for shutdown commands. * * @param port The new port number */ @Override public void setPort(int port) { this.port = port; } /** * Return the address on which we listen to for shutdown commands. */ @Override public String getAddress() { return (this.address); } /** * Set the address on which we listen to for shutdown commands. * * @param address The new address */ @Override public void setAddress(String address) { this.address = address; } /** * Return the shutdown command string we are waiting for. */ @Override public String getShutdown() { return (this.shutdown); } /** * Set the shutdown command we are waiting for. * * @param shutdown The new shutdown command */ @Override public void setShutdown(String shutdown) { this.shutdown = shutdown; } /** * Return the outer Catalina startup/shutdown component if present. */ @Override public Catalina getCatalina() { return catalina; } /** * Set the outer Catalina startup/shutdown component if present. */ @Override public void setCatalina(Catalina catalina) { this.catalina = catalina; } // --------------------------------------------------------- Server Methods /** * Add a new Service to the set of defined Services. * * @param service The Service to be added */ @Override public void addService(Service service) { service.setServer(this); synchronized (services) { Service results[] = new Service[services.length + 1]; System.arraycopy(services, 0, results, 0, services.length); results[services.length] = service; services = results; if (getState().isAvailable()) { try { service.start(); } catch (LifecycleException e) { // Ignore } } // Report this property change to interested listeners support.firePropertyChange("service", null, service); } } public void stopAwait() { stopAwait=true; Thread t = awaitThread; if (t != null) { ServerSocket s = awaitSocket; if (s != null) { awaitSocket = null; try { s.close(); } catch (IOException e) { // Ignored } } t.interrupt(); try { t.join(1000); } catch (InterruptedException e) { // Ignored } } } /** * Wait until a proper shutdown command is received, then return. * This keeps the main thread alive - the thread pool listening for http * connections is daemon threads. */ @Override public void await() { // Negative values - don't wait on port - tomcat is embedded or we just don't like ports if( port == -2 ) { // undocumented yet - for embedding apps that are around, alive. return; } if( port==-1 ) { try { awaitThread = Thread.currentThread(); while(!stopAwait) { try { Thread.sleep( 10000 ); } catch( InterruptedException ex ) { // continue and check the flag } } } finally { awaitThread = null; } return; } // Set up a server socket to wait on try { awaitSocket = new ServerSocket(port, 1, InetAddress.getByName(address)); } catch (IOException e) { log.error("StandardServer.await: create[" + address + ":" + port + "]: ", e); return; } try { awaitThread = Thread.currentThread(); // Loop waiting for a connection and a valid command while (!stopAwait) { ServerSocket serverSocket = awaitSocket; if (serverSocket == null) { break; } // Wait for the next connection Socket socket = null; StringBuilder command = new StringBuilder(); try { InputStream stream; try { socket = serverSocket.accept(); socket.setSoTimeout(10 * 1000); // Ten seconds stream = socket.getInputStream(); } catch (AccessControlException ace) { log.warn("StandardServer.accept security exception: " + ace.getMessage(), ace); continue; } catch (IOException e) { if (stopAwait) { // Wait was aborted with socket.close() break; } log.error("StandardServer.await: accept: ", e); break; } // Read a set of characters from the socket int expected = 1024; // Cut off to avoid DoS attack while (expected < shutdown.length()) { if (random == null) random = new Random(); expected += (random.nextInt() % 1024); } while (expected > 0) { int ch = -1; try { ch = stream.read(); } catch (IOException e) { log.warn("StandardServer.await: read: ", e); ch = -1; } if (ch < 32) // Control character or EOF terminates loop break; command.append((char) ch); expected--; } } finally { // Close the socket now that we are done with it try { if (socket != null) { socket.close(); } } catch (IOException e) { // Ignore } } // Match against our command string boolean match = command.toString().equals(shutdown); if (match) { log.info(sm.getString("standardServer.shutdownViaPort")); break; } else log.warn("StandardServer.await: Invalid command '" + command.toString() + "' received"); } } finally { ServerSocket serverSocket = awaitSocket; awaitThread = null; awaitSocket = null; // Close the server socket and return if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { // Ignore } } } } /** * Return the specified Service (if it exists); otherwise return * null. * * @param name Name of the Service to be returned */ @Override public Service findService(String name) { if (name == null) { return (null); } synchronized (services) { for (int i = 0; i < services.length; i++) { if (name.equals(services[i].getName())) { return (services[i]); } } } return (null); } /** * Return the set of Services defined within this Server. */ @Override public Service[] findServices() { return (services); } /** * Return the JMX service names. */ public ObjectName[] getServiceNames() { ObjectName onames[]=new ObjectName[ services.length ]; for( int i=0; iServer * out to the server.xml configuration file. * * @exception javax.management.InstanceNotFoundException * if the managed resource object cannot be found * @exception javax.management.MBeanException * if the initializer of the object throws an exception, or * persistence is not supported * @exception javax.management.RuntimeOperationsException * if an exception is reported by the persistence mechanism */ public synchronized void storeConfig() throws Exception { ObjectName sname = new ObjectName("Catalina:type=StoreConfig"); mserver.invoke(sname, "storeConfig", null, null); } /** * Write the configuration information for Context * out to the specified configuration file. * * @exception javax.management.InstanceNotFoundException if the managed resource object * cannot be found * @exception javax.management.MBeanException if the initializer of the object throws * an exception, or persistence is not supported * @exception javax.management.RuntimeOperationsException if an exception is reported * by the persistence mechanism */ public synchronized void storeContext(Context context) throws Exception { ObjectName sname = null; try { sname = new ObjectName("Catalina:type=StoreConfig"); if(mserver.isRegistered(sname)) { mserver.invoke(sname, "store", new Object[] {context}, new String [] { "java.lang.String"}); } else log.error("StoreConfig mbean not registered" + sname); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(t); } } /** * Return true if naming should be used. */ private boolean isUseNaming() { boolean useNaming = true; // Reading the "catalina.useNaming" environment variable String useNamingProperty = System.getProperty("catalina.useNaming"); if ((useNamingProperty != null) && (useNamingProperty.equals("false"))) { useNaming = false; } return useNaming; } /** * Start nested components ({@link Service}s) and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null); setState(LifecycleState.STARTING); globalNamingResources.start(); // Start our defined Services synchronized (services) { for (int i = 0; i < services.length; i++) { services[i].start(); } } } /** * Stop nested components ({@link Service}s) and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); fireLifecycleEvent(CONFIGURE_STOP_EVENT, null); // Stop our defined Services for (int i = 0; i < services.length; i++) { services[i].stop(); } globalNamingResources.stop(); stopAwait(); } /** * Invoke a pre-startup initialization. This is used to allow connectors * to bind to restricted ports under Unix operating environments. */ @Override protected void initInternal() throws LifecycleException { super.initInternal(); // Register global String cache // Note although the cache is global, if there are multiple Servers // present in the JVM (may happen when embedding) then the same cache // will be registered under multiple names onameStringCache = register(new StringCache(), "type=StringCache"); // Register the MBeanFactory MBeanFactory factory = new MBeanFactory(); factory.setContainer(this); onameMBeanFactory = register(factory, "type=MBeanFactory"); // Register the naming resources globalNamingResources.init(); // Populate the extension validator with JARs from common and shared // class loaders if (getCatalina() != null) { ClassLoader cl = getCatalina().getParentClassLoader(); // Walk the class loader hierarchy. Stop at the system class loader. // This will add the shared (if present) and common class loaders while (cl != null && cl != ClassLoader.getSystemClassLoader()) { if (cl instanceof URLClassLoader) { URL[] urls = ((URLClassLoader) cl).getURLs(); for (URL url : urls) { if (url.getProtocol().equals("file")) { try { File f = new File (url.toURI()); if (f.isFile() && f.getName().endsWith(".jar")) { ExtensionValidator.addSystemResource(f); } } catch (URISyntaxException e) { // Ignore } catch (IOException e) { // Ignore } } } } cl = cl.getParent(); } } // Initialize our defined Services for (int i = 0; i < services.length; i++) { services[i].init(); } } @Override protected void destroyInternal() throws LifecycleException { // Destroy our defined Services for (int i = 0; i < services.length; i++) { services[i].destroy(); } globalNamingResources.destroy(); unregister(onameMBeanFactory); unregister(onameStringCache); super.destroyInternal(); } /** * Return the parent class loader for this component. */ @Override public ClassLoader getParentClassLoader() { if (parentClassLoader != null) return (parentClassLoader); if (catalina != null) { return (catalina.getParentClassLoader()); } return (ClassLoader.getSystemClassLoader()); } /** * Set the parent class loader for this server. * * @param parent The new parent class loader */ @Override public void setParentClassLoader(ClassLoader parent) { ClassLoader oldParentClassLoader = this.parentClassLoader; this.parentClassLoader = parent; support.firePropertyChange("parentClassLoader", oldParentClassLoader, this.parentClassLoader); } private ObjectName onameStringCache; private ObjectName onameMBeanFactory; /** * Obtain the MBean domain for this server. The domain is obtained using * the following search order: *
      *
    1. Name of first {@link org.apache.catalina.Engine}.
    2. *
    3. Name of first {@link Service}.
    4. *
    */ @Override protected String getDomainInternal() { String domain = null; Service[] services = findServices(); if (services.length > 0) { Service service = services[0]; if (service != null) { domain = MBeanUtils.getDomain(service); } } return domain; } @Override protected final String getObjectNameKeyProperties() { return "type=Server"; } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationTaglibDescriptor.java0000644000175100017510000000443712271471332027102 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import javax.servlet.descriptor.TaglibDescriptor; public class ApplicationTaglibDescriptor implements TaglibDescriptor { private String location; private String uri; public ApplicationTaglibDescriptor(String location, String uri) { this.location = location; this.uri = uri; } @Override public String getTaglibLocation() { return location; } @Override public String getTaglibURI() { return uri; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((location == null) ? 0 : location.hashCode()); result = prime * result + ((uri == null) ? 0 : uri.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ApplicationTaglibDescriptor)) { return false; } ApplicationTaglibDescriptor other = (ApplicationTaglibDescriptor) obj; if (location == null) { if (other.location != null) { return false; } } else if (!location.equals(other.location)) { return false; } if (uri == null) { if (other.uri != null) { return false; } } else if (!uri.equals(other.uri)) { return false; } return true; } } tomcat7-7.0.52/java/org/apache/catalina/core/RestrictedFilters.properties0000644000175100017510000000147312271471332026366 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. org.apache.catalina.ssi.SSIFilter=restricted tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationServletRegistration.java0000644000175100017510000001536312271471332027660 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletRegistration; import javax.servlet.ServletSecurityElement; import org.apache.catalina.Context; import org.apache.catalina.LifecycleState; import org.apache.catalina.Wrapper; import org.apache.catalina.util.ParameterMap; import org.apache.tomcat.util.res.StringManager; public class ApplicationServletRegistration implements ServletRegistration.Dynamic { /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); private Wrapper wrapper; private Context context; public ApplicationServletRegistration(Wrapper wrapper, Context context) { this.wrapper = wrapper; this.context = context; } @Override public String getClassName() { return wrapper.getServletClass(); } @Override public String getInitParameter(String name) { return wrapper.findInitParameter(name); } @Override public Map getInitParameters() { ParameterMap result = new ParameterMap(); String[] parameterNames = wrapper.findInitParameters(); for (String parameterName : parameterNames) { result.put(parameterName, wrapper.findInitParameter(parameterName)); } result.setLocked(true); return result; } @Override public String getName() { return wrapper.getName(); } @Override public boolean setInitParameter(String name, String value) { if (name == null || value == null) { throw new IllegalArgumentException( sm.getString("applicationFilterRegistration.nullInitParam", name, value)); } if (getInitParameter(name) != null) { return false; } wrapper.addInitParameter(name, value); return true; } @Override public Set setInitParameters(Map initParameters) { Set conflicts = new HashSet(); for (Map.Entry entry : initParameters.entrySet()) { if (entry.getKey() == null || entry.getValue() == null) { throw new IllegalArgumentException(sm.getString( "applicationFilterRegistration.nullInitParams", entry.getKey(), entry.getValue())); } if (getInitParameter(entry.getKey()) != null) { conflicts.add(entry.getKey()); } } // Have to add in a separate loop since spec requires no updates at all // if there is an issue if (conflicts.isEmpty()) { for (Map.Entry entry : initParameters.entrySet()) { setInitParameter(entry.getKey(), entry.getValue()); } } return conflicts; } @Override public void setAsyncSupported(boolean asyncSupported) { wrapper.setAsyncSupported(asyncSupported); } @Override public void setLoadOnStartup(int loadOnStartup) { wrapper.setLoadOnStartup(loadOnStartup); } @Override public void setMultipartConfig(MultipartConfigElement multipartConfig) { wrapper.setMultipartConfigElement(multipartConfig); } @Override public void setRunAsRole(String roleName) { wrapper.setRunAs(roleName); } @Override public Set setServletSecurity(ServletSecurityElement constraint) { if (constraint == null) { throw new IllegalArgumentException(sm.getString( "applicationServletRegistration.setServletSecurity.iae", getName(), context.getName())); } if (!context.getState().equals(LifecycleState.STARTING_PREP)) { throw new IllegalStateException(sm.getString( "applicationServletRegistration.setServletSecurity.ise", getName(), context.getName())); } return context.addServletSecurity(this, constraint); } @Override public Set addMapping(String... urlPatterns) { if (urlPatterns == null) { return Collections.emptySet(); } Set conflicts = new HashSet(); for (String urlPattern : urlPatterns) { String wrapperName = context.findServletMapping(urlPattern); if (wrapperName != null) { Wrapper wrapper = (Wrapper) context.findChild(wrapperName); if (wrapper.isOverridable()) { // Some Wrappers (from global and host web.xml) may be // overridden rather than generating a conflict context.removeServletMapping(urlPattern); } else { conflicts.add(urlPattern); } } } if (!conflicts.isEmpty()) { return conflicts; } for (String urlPattern : urlPatterns) { context.addServletMapping(urlPattern, wrapper.getName()); } return Collections.emptySet(); } @Override public Collection getMappings() { Set result = new HashSet(); String servletName = wrapper.getName(); String[] urlPatterns = context.findServletMappings(); for (String urlPattern : urlPatterns) { String name = context.findServletMapping(urlPattern); if (name.equals(servletName)) { result.add(urlPattern); } } return result; } @Override public String getRunAsRole() { return wrapper.getRunAs(); } } tomcat7-7.0.52/java/org/apache/catalina/core/AccessLogAdapter.java0000644000175100017510000000406711616414623024622 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.Arrays; import org.apache.catalina.AccessLog; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; /** * A helper class that wraps several AccessLog instances. */ public class AccessLogAdapter implements AccessLog { private AccessLog[] logs; public AccessLogAdapter(AccessLog log) { if (log == null) { throw new NullPointerException(); } logs = new AccessLog[] { log }; } public void add(AccessLog log) { if (log == null) { throw new NullPointerException(); } AccessLog newArray[] = Arrays.copyOf(logs, logs.length + 1); newArray[newArray.length - 1] = log; logs = newArray; } @Override public void log(Request request, Response response, long time) { for (AccessLog log: logs) { log.log(request, response, time); } } @Override public void setRequestAttributesEnabled(boolean requestAttributesEnabled) { // NOOP } @Override public boolean getRequestAttributesEnabled() { // NOOP. Could return logs[0].getRequestAttributesEnabled(), but I do // not see a use case for that. return false; } } tomcat7-7.0.52/java/org/apache/catalina/core/LocalStrings_fr.properties0000644000175100017510000003615312271471332026023 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. applicationContext.attributeEvent=Exception lanc\u00e9e par l''\u00e9couteur (listener) d''\u00e9v\u00e8nement attributs applicationContext.requestDispatcher.iae=Le chemin {0} ne commence pas par le caract\u00e8re "/" applicationContext.setAttribute.namenull=le nom ne peut \u00eatre nul applicationDispatcher.allocateException=Exception d''allocation pour la servlet {0} applicationDispatcher.deallocateException=Exception de d\u00e9sallocation pour la servlet {0} applicationDispatcher.forward.ise=Impossible d''utiliser faire-suivre (forward) apr\u00e8s que la r\u00e9ponse ait \u00e9t\u00e9 envoy\u00e9e applicationDispatcher.forward.throw=La ressource faire-suivre (forwarded) a lanc\u00e9 une exception applicationDispatcher.include.throw=La ressource incluse (included) a lanc\u00e9 une exception applicationDispatcher.isUnavailable=La servlet {0} est actuellement indisponible applicationDispatcher.serviceException="Servlet.service()" pour la servlet {0} a lanc\u00e9 une exception applicationRequest.badParent=Impossible de trouver l''impl\u00e9mentation requ\u00eate parente (parent request) applicationRequest.badRequest=La requ\u00eate n''est pas une "javax.servlet.ServletRequestWrapper" applicationResponse.badParent=Impossible de trouver une impl\u00e9mentation r\u00e9ponse parente (parent response) applicationResponse.badResponse=La r\u00e9ponse n''est pas une "javax.servlet.ServletResponseWrapper" containerBase.alreadyStarted=Le conteneur {0} a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9 containerBase.notConfigured=Aucune Valve basique (basic valve) n''a \u00e9t\u00e9 configur\u00e9e containerBase.notStarted=Le conteneur {0} n''a pas \u00e9t\u00e9 d\u00e9marr\u00e9 fastEngineMapper.alreadyStarted=le "FastEngineMapper" {0} a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9 fastEngineMapper.notStarted=Le "FastEngineMapper" {0} n''a pas encore \u00e9t\u00e9 d\u00e9marr\u00e9 filterChain.filter=L''ex\u00e9cution du filtre (Filter) a lanc\u00e9 une exception filterChain.servlet=L''ex\u00e9cution de la servlet a lanc\u00e9 une exception httpContextMapper.container=Ce conteneur n''est pas un "StandardContext" httpEngineMapper.container=Ce conteneur n''est pas un "StandardEngine" httpHostMapper.container=Ce conteneur n''est pas un "StandardHost" interceptorValve.alreadyStarted=La valve d''interception (InterceptorValve) a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9e interceptorValve.notStarted=La valve d''interception (InterceptorValve) n''a pas encore \u00e9t\u00e9 d\u00e9marr\u00e9e naming.bindFailed=Echec lors du liage \u00e0 l''objet: {0} naming.unbindFailed=Echec lors du d\u00e9liage \u00e0 l''objet : {0} naming.invalidEnvEntryType=L''entr\u00e9e environnement {0} a un type invalide naming.invalidEnvEntryValue=L''entr\u00e9e environnement {0} a une valeur invalide naming.namingContextCreationFailed=La cr\u00e9ation du contexte de nommage (naming context) a \u00e9chou\u00e9 : {0} standardContext.alreadyStarted=Le contexte a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9 standardContext.applicationListener=Erreur lors de la configuration de la classe d''\u00e9coute de l''application (application listener) {0} standardContext.applicationSkipped=L''installation des \u00e9couteurs (listeners) de l''application a \u00e9t\u00e9 saut\u00e9e suite aux erreurs pr\u00e9c\u00e9dentes standardContext.badRequest=Chemin de requ\u00eate invalide ({0}). standardContext.errorPage.error=La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/' standardContext.errorPage.required=La page d''erreur (ErrorPage) ne peut \u00eatre nulle standardContext.errorPage.warning=ATTENTION: La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 standardContext.filterMap.either=L''association de filtre (filter mapping) doit indiquer soit une soit une standardContext.filterMap.name=L''association de filtre (filter mapping) indique un nom de filtre inconnu {0} standardContext.filterMap.pattern= {0} invalide dans l''association de filtre (filter mapping) standardContext.filterStart=Exception au d\u00e9marrage du filtre {0} standardContext.filterStartFailed=Echec du d\u00e9marrage des filtres d''application standardContext.requestListenerStartFailed=Echec d\u00e9marrage des Valves d''\u00e9coute standardContext.requestListenerConfig.added=Ajout de la valve d''\u00e9coute standardContext.requestListenerConfig.error=Exception lors de l''ajout de la valve d''\u00e9coute de requ\u00eate: {0} standardContext.isUnavailable=Cette application n''est pas disponible actuellement standardContext.listenerStart=Exception lors de l''envoi de l''\u00e9v\u00e8nement contexte initialis\u00e9 (context initialized) \u00e0 l''instance de classe d''\u00e9coute (listener) {0} standardContext.listenerStartFailed=Echec du d\u00e9marrage des \u00e9couteurs (listeners) d''application standardContext.listenerStop=Exception lors de l''envoi de l''\u00e9v\u00e8nement contexte d\u00e9truit (context destroyed) \u00e0 l''instance de classe d''\u00e9coute {0} standardContext.loginConfig.errorPage=La forme de page d''erreur (form error page) {0} doit commencer par un ''/'' standardContext.loginConfig.errorWarning=ATTENTION: La forme de page d''erreur (form error page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 standardContext.loginConfig.loginPage=La forme de page de connexion (form login page) {0} doit commencer par un ''/'' standardContext.loginConfig.loginWarning=ATTENTION: La forme de page de connexion (form login page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 standardContext.loginConfig.required="LoginConfig" ne peut \u00eatre nul standardContext.mappingError=Erreur dans la configuration d''association (mapping configuration) pour l''URI relative {0} standardContext.notFound=La ressource demand\u00e9e ({0}) n''est pas disponible. standardContext.notReloadable=Le rechargement est d\u00e9sactiv\u00e9 pour ce contexte standardContext.notStarted=Le contexte [{0}] n''a pas encore \u00e9t\u00e9 d\u00e9marr\u00e9 standardContext.notWrapper=Le fils du contexte (child of context) doit \u00eatre un enrobeur (wrapper) standardContext.parameter.duplicate=Param\u00e8tre d''initialisation de contexte dupliqu\u00e9 {0} standardContext.parameter.required=Le nom de param\u00e8tre ainsi que la valeur du param\u00e8tre sont requis standardContext.reloadingCompleted=Le rechargement de ce contexte est termin\u00e9 standardContext.reloadingFailed=Le rechargement de ce contexte a \u00e9chou\u00e9 suite \u00e0 une erreur pr\u00e9c\u00e9dente standardContext.reloadingStarted=Le rechargement du contexte [{0}] a d\u00e9marr\u00e9 standardContext.requestListener.requestInit=Une exception lors de l''envoi de requ\u00eate a initi\u00e9 un \u00e9v\u00e8nement cycle de vie (lifecycle event) pour l''instance de classe \u00e0 l''\u00e9coute (listener) {0} standardContext.requestListener.requestDestroy=Une exception lors de l''envoi de requ\u00eate a d\u00e9truit un \u00e9v\u00e8nement cycle de vie (lifecycle event) pour l''instance de classe \u00e0 l''\u00e9coute (listener) {0} standardContext.securityConstraint.pattern= {0} invalide d''apr\u00e8s les contraintes de s\u00e9curit\u00e9 (security constraint) standardContext.servletMap.name=L''association de servlet (servlet mapping) indique un nom de servlet inconnu {0} standardContext.servletMap.pattern= {0} invalide dans l''association de servlet (servlet mapping) standardContext.startCleanup=Exception lors du nettoyage apr\u00e8s que le d\u00e9marrage ait \u00e9chou\u00e9 standardContext.startFailed=Erreur de d\u00e9marrage du contexte [{0}] suite aux erreurs pr\u00e9c\u00e9dentes standardContext.startingContext=Exception lors du d\u00e9marrage du contexte [{0}] standardContext.startingLoader=Exception an d\u00e9marrage du "Loader" standardContext.startingManager=Exception an d\u00e9marrage du "Manager" standardContext.startingWrapper=Exception an d\u00e9marrage de l''enrobeur (wrapper) de la servlet {0} standardContext.stoppingContext=Exception \u00e0 l''arr\u00eat du Context [{0}] standardContext.stoppingLoader=Exception \u00e0 l''arr\u00eat du "Loader" standardContext.stoppingManager=Exception \u00e0 l''arr\u00eat du "Manager" standardContext.stoppingWrapper=Exception \u00e0 l''arr\u00eat de l''enrobeur (wrapper) de la servlet {0} standardContext.resourcesStart=Erreur lors du d\u00e9marrage des ressources statiques standardContext.urlDecode=Impossible de d\u00e9coder le chemin de requ\u00eate encod\u00e9 dans l''URL {0} standardContext.urlPattern.patternWarning=ATTENTION: Le mod\u00e8le (pattern) URL {0} doit commencer par un ''/'' dans l''API Servlet 2.4 standardContext.urlValidate=Impossible de valider le chemin de requ\u00eate encod\u00e9 dans l''URL {0} standardEngine.alreadyStarted=Le moteur a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9 standardEngine.mappingError=Erreur de configuration d''association (mapping configuration) pour le serveur {0} standardEngine.noHost=Aucune h\u00f4te (host) ne correspond au nom de serveur {0} standardEngine.noHostHeader=requ\u00eate HTTP/1.1 sans ent\u00eate Host: standardEngine.notHost=Le fils d''un moteur (child of an Engine) doit \u00eatre un h\u00f4te standardEngine.notParent=Un moteur (engine) ne peut avoir de conteneur parent (container) standardEngine.notStarted=Le moteur n''a pas encore \u00e9t\u00e9 d\u00e9marr\u00e9 standardEngine.unfoundHost=L''h\u00f4te virtuel (virtual host) {0} est introuvable standardEngine.unknownHost=Aucun serveur h\u00f4te n''est indiqu\u00e9 pour cette requ\u00eate standardHost.accessBase=Impossible d''acc\u00e9der le r\u00e9pertoire "document base" {0} standardHost.alreadyStarted=L''h\u00f4te a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9marr\u00e9 standardHost.appBase=Le r\u00e9pertoire de base de l''application {0} n''existe pas standardHost.configRequired=Une URL vers le fichier de configuration est obligatoire standardHost.configNotAllowed=L''utilisation d''un fichier de configuration n''est pas autoris\u00e9e standardHost.installing=Installation d''une application pour le chemin de contexte {0} depuis l''URL {1} standardHost.installingWAR=Installation d''une application depuis l''URL {0} standardHost.installError=Erreur lors du d\u00e9ploiement de l''application pour le chemin de contexte {0} standardHost.invalidErrorReportValveClass=Impossible de charger la classe valve de rapport d''erreur: {0} standardHost.docBase=Le r\u00e9pertoire "document base" {0} existe d\u00e9j\u00e0 standardHost.mappingError=Erreur d''association de configuration (mapping configuration) pour l''URI demand\u00e9e {0} standardHost.noContext=Aucun contexte n''est configur\u00e9 pour traiter cette requ\u00eate standardHost.noHost=Aucun h\u00f4te n''est configur\u00e9 pour traiter cette requ\u00eate standardHost.notContext=Le fils d''un h\u00f4te (child of a Host) doit \u00eatre un contexte standardHost.notStarted=l''h\u00f4te n''a pas encore \u00e9t\u00e9 d\u00e9marr\u00e9 standardHost.nullName=Le nom d''h\u00f4te est requis standardHost.pathFormat=Chemin de contexte invalide: {0} standardHost.pathMissing=Le chemin de contexte {0} n''est pas utilis\u00e9 actuellement standardHost.pathRequired=Le chemin de contexte est requis standardHost.pathUsed=Le chemin de contexte {0} est d\u00e9j\u00e0 utilis\u00e9 standardHost.removing=Retrait de l''application web pour le chemin de contexte {0} standardHost.removeError=Erreur lors du retrait de l''application web pour le chemin de contexte {0} standardHost.start=D\u00e9marrage de l''application web pour le chemin de contexte {0} standardHost.stop=Arr\u00eat de l''application web pour le chemin de contexte {0} standardHost.unfoundContext=Impossible de trouver un contexte pour l''URI {0} demand\u00e9e standardHost.warRequired=Une URL vers l''archive d''application web (war) est n\u00e9cessaire standardHost.warURL=URL vers l''archive d''application web (war) invalide: {0} standardService.start.name=D\u00e9marrage du service {0} standardService.stop.name=Arr\u00eat du service {0} standardWrapper.allocate=Erreur d''allocation \u00e0 une instance de servlet standardWrapper.allocateException=Exception lors de l''allocation pour la servlet {0} standardWrapper.containerServlet=Chargement du conteneur (container) de servlet {0} standardWrapper.createFilters=Exception \u00e0 la cr\u00e9ation de filtres pour la servlet {0} standardWrapper.deallocateException=Exception \u00e0 la d\u00e9sallocation pour la servlet {0} standardWrapper.destroyException="Servlet.destroy()" de la servlet {0} a g\u00e9n\u00e9r\u00e9 une exception standardWrapper.exception0=Rapport d''exception Tomcat standardWrapper.exception1=Une exception Servlet s''est produite standardWrapper.exception2=Rapport d''exception: standardWrapper.exception3=Cause m\u00e8re: standardWrapper.initException="Servlet.init()" pour la servlet {0} a g\u00e9n\u00e9r\u00e9 une exception standardWrapper.instantiate=Erreur \u00e0 l''instantiation de la classe servlet {0} standardWrapper.isUnavailable=La servlet {0} est actuellement indisponible standardWrapper.jasperLoader=Utilisation du chargeur de classe Jasper (classloader) pour la servlet {0} standardWrapper.jspFile.format=Le fichier JSP {0} ne commence par par un caract\u00e8re ''/'' standardWrapper.loadException=La servlet {0} a g\u00e9n\u00e9r\u00e9 une exception "load()" standardWrapper.missingClass=L''enrobeur (wrapper) ne peut trouver la classe servlet {0} ou une classe dont elle d\u00e9pend standardWrapper.missingLoader=L''enrobeur (wrapper) ne peut trouver de chargeur (loader) pour la servlet {0} standardWrapper.notChild=L''enrobeur de conteneur (wrapper container) peut ne pas avoir de conteneurs fils standardWrapper.notClass=Aucune classe servlet n''a \u00e9t\u00e9 sp\u00e9cifi\u00e9e pour la servlet {0} standardWrapper.notContext=Le conteneur parent d''un enrobeur (wrapper) doit \u00eatre un contexte standardWrapper.notFound=Servlet {0} n''est pas disponible. standardWrapper.notServlet=La classe {0} n''est pas une servlet standardWrapper.releaseFilters=Exception des filtres de sortie (release filters) pour la servlet {0} standardWrapper.serviceException="Servlet.service()" pour la servlet {0} a g\u00e9n\u00e9r\u00e9 une exception standardWrapper.statusHeader=Etat HTTP {0} - {1} standardWrapper.statusTitle=Rapport d''erreur Tomcat standardWrapper.unavailable=La servlet {0} est marqu\u00e9 comme indisponible standardWrapper.unloadException=La servlet {0} a g\u00e9n\u00e9r\u00e9 une exception "unload()" standardWrapper.unloading=Impossible d''allouer la servlet {0} car elle a \u00e9t\u00e9 d\u00e9charg\u00e9e tomcat7-7.0.52/java/org/apache/catalina/core/StandardPipeline.java0000644000175100017510000003320612271471332024677 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.util.ArrayList; import javax.management.ObjectName; import org.apache.catalina.Contained; import org.apache.catalina.Container; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Pipeline; import org.apache.catalina.Valve; import org.apache.catalina.util.LifecycleBase; import org.apache.catalina.valves.ValveBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; /** * Standard implementation of a processing Pipeline that will invoke * a series of Valves that have been configured to be called in order. This * implementation can be used for any type of Container. * * IMPLEMENTATION WARNING - This implementation assumes that no * calls to addValve() or removeValve are allowed * while a request is currently being processed. Otherwise, the mechanism * by which per-thread state is maintained will need to be modified. * * @author Craig R. McClanahan */ public class StandardPipeline extends LifecycleBase implements Pipeline, Contained { private static final Log log = LogFactory.getLog(StandardPipeline.class); // ----------------------------------------------------------- Constructors /** * Construct a new StandardPipeline instance with no associated Container. */ public StandardPipeline() { this(null); } /** * Construct a new StandardPipeline instance that is associated with the * specified Container. * * @param container The container we should be associated with */ public StandardPipeline(Container container) { super(); setContainer(container); } // ----------------------------------------------------- Instance Variables /** * The basic Valve (if any) associated with this Pipeline. */ protected Valve basic = null; /** * The Container with which this Pipeline is associated. */ protected Container container = null; /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.core.StandardPipeline/1.0"; /** * The first valve associated with this Pipeline. */ protected Valve first = null; // --------------------------------------------------------- Public Methods /** * Return descriptive information about this implementation class. */ public String getInfo() { return info; } @Override public boolean isAsyncSupported() { Valve valve = (first!=null)?first:basic; boolean supported = true; while (supported && valve!=null) { supported = supported & valve.isAsyncSupported(); valve = valve.getNext(); } return supported; } // ------------------------------------------------------ Contained Methods /** * Return the Container with which this Pipeline is associated. */ @Override public Container getContainer() { return (this.container); } /** * Set the Container with which this Pipeline is associated. * * @param container The new associated container */ @Override public void setContainer(Container container) { this.container = container; } @Override protected void initInternal() { // NOOP } /** * Start {@link Valve}s) in this pipeline and implement the requirements * of {@link LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Start the Valves in our pipeline (including the basic), if any Valve current = first; if (current == null) { current = basic; } while (current != null) { if (current instanceof Lifecycle) ((Lifecycle) current).start(); current = current.getNext(); } setState(LifecycleState.STARTING); } /** * Stop {@link Valve}s) in this pipeline and implement the requirements * of {@link LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); // Stop the Valves in our pipeline (including the basic), if any Valve current = first; if (current == null) { current = basic; } while (current != null) { if (current instanceof Lifecycle) ((Lifecycle) current).stop(); current = current.getNext(); } } @Override protected void destroyInternal() { Valve[] valves = getValves(); for (Valve valve : valves) { removeValve(valve); } } /** * Return a String representation of this component. */ @Override public String toString() { StringBuilder sb = new StringBuilder("Pipeline["); sb.append(container); sb.append(']'); return sb.toString(); } // ------------------------------------------------------- Pipeline Methods /** *

    Return the Valve instance that has been distinguished as the basic * Valve for this Pipeline (if any). */ @Override public Valve getBasic() { return (this.basic); } /** *

    Set the Valve instance that has been distinguished as the basic * Valve for this Pipeline (if any). Prior to setting the basic Valve, * the Valve's setContainer() will be called, if it * implements Contained, with the owning Container as an * argument. The method may throw an IllegalArgumentException * if this Valve chooses not to be associated with this Container, or * IllegalStateException if it is already associated with * a different Container.

    * * @param valve Valve to be distinguished as the basic Valve */ @Override public void setBasic(Valve valve) { // Change components if necessary Valve oldBasic = this.basic; if (oldBasic == valve) return; // Stop the old component if necessary if (oldBasic != null) { if (getState().isAvailable() && (oldBasic instanceof Lifecycle)) { try { ((Lifecycle) oldBasic).stop(); } catch (LifecycleException e) { log.error("StandardPipeline.setBasic: stop", e); } } if (oldBasic instanceof Contained) { try { ((Contained) oldBasic).setContainer(null); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } // Start the new component if necessary if (valve == null) return; if (valve instanceof Contained) { ((Contained) valve).setContainer(this.container); } if (getState().isAvailable() && valve instanceof Lifecycle) { try { ((Lifecycle) valve).start(); } catch (LifecycleException e) { log.error("StandardPipeline.setBasic: start", e); return; } } // Update the pipeline Valve current = first; while (current != null) { if (current.getNext() == oldBasic) { current.setNext(valve); break; } current = current.getNext(); } this.basic = valve; } /** *

    Add a new Valve to the end of the pipeline associated with this * Container. Prior to adding the Valve, the Valve's * setContainer() method will be called, if it implements * Contained, with the owning Container as an argument. * The method may throw an * IllegalArgumentException if this Valve chooses not to * be associated with this Container, or IllegalStateException * if it is already associated with a different Container.

    * * @param valve Valve to be added * * @exception IllegalArgumentException if this Container refused to * accept the specified Valve * @exception IllegalArgumentException if the specified Valve refuses to be * associated with this Container * @exception IllegalStateException if the specified Valve is already * associated with a different Container */ @Override public void addValve(Valve valve) { // Validate that we can add this Valve if (valve instanceof Contained) ((Contained) valve).setContainer(this.container); // Start the new component if necessary if (getState().isAvailable()) { if (valve instanceof Lifecycle) { try { ((Lifecycle) valve).start(); } catch (LifecycleException e) { log.error("StandardPipeline.addValve: start: ", e); } } } // Add this Valve to the set associated with this Pipeline if (first == null) { first = valve; valve.setNext(basic); } else { Valve current = first; while (current != null) { if (current.getNext() == basic) { current.setNext(valve); valve.setNext(basic); break; } current = current.getNext(); } } container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve); } /** * Return the set of Valves in the pipeline associated with this * Container, including the basic Valve (if any). If there are no * such Valves, a zero-length array is returned. */ @Override public Valve[] getValves() { ArrayList valveList = new ArrayList(); Valve current = first; if (current == null) { current = basic; } while (current != null) { valveList.add(current); current = current.getNext(); } return valveList.toArray(new Valve[0]); } public ObjectName[] getValveObjectNames() { ArrayList valveList = new ArrayList(); Valve current = first; if (current == null) { current = basic; } while (current != null) { if (current instanceof ValveBase) { valveList.add(((ValveBase) current).getObjectName()); } current = current.getNext(); } return valveList.toArray(new ObjectName[0]); } /** * Remove the specified Valve from the pipeline associated with this * Container, if it is found; otherwise, do nothing. If the Valve is * found and removed, the Valve's setContainer(null) method * will be called if it implements Contained. * * @param valve Valve to be removed */ @Override public void removeValve(Valve valve) { Valve current; if(first == valve) { first = first.getNext(); current = null; } else { current = first; } while (current != null) { if (current.getNext() == valve) { current.setNext(valve.getNext()); break; } current = current.getNext(); } if (first == basic) first = null; if (valve instanceof Contained) ((Contained) valve).setContainer(null); if (valve instanceof Lifecycle) { // Stop this valve if necessary if (getState().isAvailable()) { try { ((Lifecycle) valve).stop(); } catch (LifecycleException e) { log.error("StandardPipeline.removeValve: stop: ", e); } } try { ((Lifecycle) valve).destroy(); } catch (LifecycleException e) { log.error("StandardPipeline.removeValve: destroy: ", e); } } container.fireContainerEvent(Container.REMOVE_VALVE_EVENT, valve); } @Override public Valve getFirst() { if (first != null) { return first; } return basic; } } tomcat7-7.0.52/java/org/apache/catalina/core/ApplicationFilterChain.java0000644000175100017510000005154712271471332026035 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import java.security.Principal; import java.security.PrivilegedActionException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.InstanceEvent; import org.apache.catalina.comet.CometEvent; import org.apache.catalina.comet.CometFilter; import org.apache.catalina.comet.CometFilterChain; import org.apache.catalina.comet.CometProcessor; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.util.InstanceSupport; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Implementation of javax.servlet.FilterChain used to manage * the execution of a set of filters for a particular request. When the * set of defined filters has all been executed, the next call to * doFilter() will execute the servlet's service() * method itself. * * @author Craig R. McClanahan */ final class ApplicationFilterChain implements FilterChain, CometFilterChain { // Used to enforce requirements of SRV.8.2 / SRV.14.2.5.1 private static final ThreadLocal lastServicedRequest; private static final ThreadLocal lastServicedResponse; static { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest = new ThreadLocal(); lastServicedResponse = new ThreadLocal(); } else { lastServicedRequest = null; lastServicedResponse = null; } } // -------------------------------------------------------------- Constants public static final int INCREMENT = 10; // ----------------------------------------------------------- Constructors /** * Construct a new chain instance with no defined filters. */ public ApplicationFilterChain() { super(); } // ----------------------------------------------------- Instance Variables /** * Filters. */ private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; /** * The int which is used to maintain the current position * in the filter chain. */ private int pos = 0; /** * The int which gives the current number of filters in the chain. */ private int n = 0; /** * The servlet instance to be executed by this chain. */ private Servlet servlet = null; /** * The string manager for our package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The InstanceSupport instance associated with our Wrapper (used to * send "before filter" and "after filter" events. */ private InstanceSupport support = null; /** * Static class array used when the SecurityManager is turned on and * doFilter is invoked. */ private static Class[] classType = new Class[]{ServletRequest.class, ServletResponse.class, FilterChain.class}; /** * Static class array used when the SecurityManager is turned on and * service is invoked. */ private static Class[] classTypeUsedInService = new Class[]{ ServletRequest.class, ServletResponse.class}; /** * Static class array used when the SecurityManager is turned on and * doFilterEvent is invoked. */ private static Class[] cometClassType = new Class[]{ CometEvent.class, CometFilterChain.class}; /** * Static class array used when the SecurityManager is turned on and * event is invoked. */ private static Class[] classTypeUsedInEvent = new Class[] { CometEvent.class }; // ---------------------------------------------------- FilterChain Methods /** * Invoke the next filter in this chain, passing the specified request * and response. If there are no more filters in this chain, invoke * the service() method of the servlet itself. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ @Override public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; try { java.security.AccessController.doPrivileged( new java.security.PrivilegedExceptionAction() { @Override public Void run() throws ServletException, IOException { internalDoFilter(req,res); return null; } } ); } catch( PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; else if (e instanceof IOException) throw (IOException) e; else if (e instanceof RuntimeException) throw (RuntimeException) e; else throw new ServletException(e.getMessage(), e); } } else { internalDoFilter(request,response); } } private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = null; try { filter = filterConfig.getFilter(); support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, filter, request, response); if (request.isAsyncSupported() && "false".equalsIgnoreCase( filterConfig.getFilterDef().getAsyncSupported())) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res, this}; SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal); } else { filter.doFilter(request, response, this); } support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response); } catch (IOException e) { if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw e; } catch (ServletException e) { if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw e; } catch (RuntimeException e) { if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw e; } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response, e); throw new ServletException (sm.getString("filterChain.filter"), e); } return; } // We fell off the end of the chain -- call the servlet instance try { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(request); lastServicedResponse.set(response); } support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT, servlet, request, response); if (request.isAsyncSupported() && !support.getWrapper().isAsyncSupported()) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } // Use potentially wrapped request from this point if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) { if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res}; SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args, principal); } else { servlet.service(request, response); } } else { servlet.service(request, response); } support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response); } catch (IOException e) { support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw e; } catch (ServletException e) { support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw e; } catch (RuntimeException e) { support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw e; } catch (Throwable e) { ExceptionUtils.handleThrowable(e); support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); throw new ServletException (sm.getString("filterChain.servlet"), e); } finally { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(null); lastServicedResponse.set(null); } } } /** * Process the event, using the security manager if the option is enabled. * * @param event the event to process * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ @Override public void doFilterEvent(CometEvent event) throws IOException, ServletException { if( Globals.IS_SECURITY_ENABLED ) { final CometEvent ev = event; try { java.security.AccessController.doPrivileged( new java.security.PrivilegedExceptionAction() { @Override public Void run() throws ServletException, IOException { internalDoFilterEvent(ev); return null; } } ); } catch( PrivilegedActionException pe) { Exception e = pe.getException(); if (e instanceof ServletException) throw (ServletException) e; else if (e instanceof IOException) throw (IOException) e; else if (e instanceof RuntimeException) throw (RuntimeException) e; else throw new ServletException(e.getMessage(), e); } } else { internalDoFilterEvent(event); } } /** * The last request passed to a servlet for servicing from the current * thread. * * @return The last request to be serviced. */ public static ServletRequest getLastServicedRequest() { return lastServicedRequest.get(); } /** * The last response passed to a servlet for servicing from the current * thread. * * @return The last response to be serviced. */ public static ServletResponse getLastServicedResponse() { return lastServicedResponse.get(); } private void internalDoFilterEvent(CometEvent event) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; CometFilter filter = null; try { filter = (CometFilter) filterConfig.getFilter(); // FIXME: No instance listener processing for events for now /* support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, filter, event); */ if( Globals.IS_SECURITY_ENABLED ) { final CometEvent ev = event; Principal principal = ev.getHttpServletRequest().getUserPrincipal(); Object[] args = new Object[]{ev, this}; SecurityUtil.doAsPrivilege("doFilterEvent", filter, cometClassType, args, principal); } else { filter.doFilterEvent(event, this); } /*support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, event);*/ } catch (IOException e) { /* if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, event, e); */ throw e; } catch (ServletException e) { /* if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, event, e); */ throw e; } catch (RuntimeException e) { /* if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, event, e); */ throw e; } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); /*if (filter != null) support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, event, e);*/ throw new ServletException (sm.getString("filterChain.filter"), e); } return; } // We fell off the end of the chain -- call the servlet instance try { /* support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT, servlet, request, response); */ if( Globals.IS_SECURITY_ENABLED ) { final CometEvent ev = event; Principal principal = ev.getHttpServletRequest().getUserPrincipal(); Object[] args = new Object[]{ ev }; SecurityUtil.doAsPrivilege("event", servlet, classTypeUsedInEvent, args, principal); } else { ((CometProcessor) servlet).event(event); } /* support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response);*/ } catch (IOException e) { /* support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); */ throw e; } catch (ServletException e) { /* support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); */ throw e; } catch (RuntimeException e) { /* support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); */ throw e; } catch (Throwable e) { ExceptionUtils.handleThrowable(e); /* support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, servlet, request, response, e); */ throw new ServletException (sm.getString("filterChain.servlet"), e); } } // -------------------------------------------------------- Package Methods /** * Add a filter to the set of filters that will be executed in this chain. * * @param filterConfig The FilterConfig for the servlet to be executed */ void addFilter(ApplicationFilterConfig filterConfig) { // Prevent the same filter being added multiple times for(ApplicationFilterConfig filter:filters) if(filter==filterConfig) return; if (n == filters.length) { ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; System.arraycopy(filters, 0, newFilters, 0, n); filters = newFilters; } filters[n++] = filterConfig; } /** * Release references to the filters and wrapper executed by this chain. */ void release() { for (int i = 0; i < n; i++) { filters[i] = null; } n = 0; pos = 0; servlet = null; support = null; } /** * Prepare for reuse of the filters and wrapper executed by this chain. */ void reuse() { pos = 0; } /** * Set the servlet that will be executed at the end of this chain. * * @param servlet The Wrapper for the servlet to be executed */ void setServlet(Servlet servlet) { this.servlet = servlet; } /** * Set the InstanceSupport object used for event notifications * for this filter chain. * * @param support The InstanceSupport object for our Wrapper */ void setSupport(InstanceSupport support) { this.support = support; } } tomcat7-7.0.52/java/org/apache/catalina/core/AsyncContextImpl.java0000644000175100017510000005115012200762652024713 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import javax.naming.NamingException; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.AsyncDispatcher; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Valve; import org.apache.catalina.connector.Request; import org.apache.coyote.ActionCode; import org.apache.coyote.AsyncContextCallback; import org.apache.coyote.RequestInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * * @author fhanik * */ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback { private static final Log log = LogFactory.getLog(AsyncContextImpl.class); protected static final StringManager sm = StringManager.getManager(Constants.Package); private ServletRequest servletRequest = null; private ServletResponse servletResponse = null; private List listeners = new ArrayList(); private boolean hasOriginalRequestAndResponse = true; private volatile Runnable dispatch = null; private Context context = null; private long timeout = -1; private AsyncEvent event = null; private Request request; private volatile InstanceManager instanceManager; public AsyncContextImpl(Request request) { if (log.isDebugEnabled()) { logDebug("Constructor"); } this.request = request; } @Override public void complete() { if (log.isDebugEnabled()) { logDebug("complete "); } check(); request.getCoyoteRequest().action(ActionCode.COMMIT, null); request.getCoyoteRequest().action(ActionCode.ASYNC_COMPLETE, null); } @Override public void fireOnComplete() { List listenersCopy = new ArrayList(); listenersCopy.addAll(listeners); ClassLoader oldCL; if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedGetTccl(); oldCL = AccessController.doPrivileged(pa); } else { oldCL = Thread.currentThread().getContextClassLoader(); } ClassLoader newCL = context.getLoader().getClassLoader(); try { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl(newCL); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(newCL); } for (AsyncListenerWrapper listener : listenersCopy) { try { listener.fireOnComplete(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn("onComplete() failed for listener of type [" + listener.getClass().getName() + "]", t); } } } finally { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl(oldCL); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(oldCL); } } } public boolean timeout() { AtomicBoolean result = new AtomicBoolean(); request.getCoyoteRequest().action(ActionCode.ASYNC_TIMEOUT, result); if (result.get()) { ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); ClassLoader newCL = request.getContext().getLoader().getClassLoader(); try { Thread.currentThread().setContextClassLoader(newCL); List listenersCopy = new ArrayList(); listenersCopy.addAll(listeners); for (AsyncListenerWrapper listener : listenersCopy) { try { listener.fireOnTimeout(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn("onTimeout() failed for listener of type [" + listener.getClass().getName() + "]", t); } } request.getCoyoteRequest().action( ActionCode.ASYNC_IS_TIMINGOUT, result); return !result.get(); } finally { Thread.currentThread().setContextClassLoader(oldCL); } } return true; } @Override public void dispatch() { check(); String path; String pathInfo; ServletRequest servletRequest = getRequest(); if (servletRequest instanceof HttpServletRequest) { HttpServletRequest sr = (HttpServletRequest) servletRequest; path = sr.getServletPath(); pathInfo = sr.getPathInfo(); } else { path = request.getServletPath(); pathInfo = request.getPathInfo(); } if (pathInfo != null) { path += pathInfo; } dispatch(path); } @Override public void dispatch(String path) { check(); dispatch(request.getServletContext(),path); } @Override public void dispatch(ServletContext context, String path) { if (log.isDebugEnabled()) { logDebug("dispatch "); } check(); if (dispatch != null) { throw new IllegalStateException( sm.getString("asyncContextImpl.dispatchingStarted")); } if (request.getAttribute(ASYNC_REQUEST_URI)==null) { request.setAttribute(ASYNC_REQUEST_URI, request.getRequestURI()); request.setAttribute(ASYNC_CONTEXT_PATH, request.getContextPath()); request.setAttribute(ASYNC_SERVLET_PATH, request.getServletPath()); request.setAttribute(ASYNC_PATH_INFO, request.getPathInfo()); request.setAttribute(ASYNC_QUERY_STRING, request.getQueryString()); } final RequestDispatcher requestDispatcher = context.getRequestDispatcher(path); if (!(requestDispatcher instanceof AsyncDispatcher)) { throw new UnsupportedOperationException( sm.getString("asyncContextImpl.noAsyncDispatcher")); } final AsyncDispatcher applicationDispatcher = (AsyncDispatcher) requestDispatcher; final ServletRequest servletRequest = getRequest(); final ServletResponse servletResponse = getResponse(); Runnable run = new Runnable() { @Override public void run() { request.getCoyoteRequest().action(ActionCode.ASYNC_DISPATCHED, null); try { applicationDispatcher.dispatch(servletRequest, servletResponse); }catch (Exception x) { //log.error("Async.dispatch",x); throw new RuntimeException(x); } } }; this.dispatch = run; this.request.getCoyoteRequest().action(ActionCode.ASYNC_DISPATCH, null); } @Override public ServletRequest getRequest() { check(); return servletRequest; } @Override public ServletResponse getResponse() { check(); return servletResponse; } @Override public void start(final Runnable run) { if (log.isDebugEnabled()) { logDebug("start "); } check(); Runnable wrapper = new RunnableWrapper(run, context); this.request.getCoyoteRequest().action(ActionCode.ASYNC_RUN, wrapper); } @Override public void addListener(AsyncListener listener) { check(); AsyncListenerWrapper wrapper = new AsyncListenerWrapper(); wrapper.setListener(listener); listeners.add(wrapper); } @Override public void addListener(AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) { check(); AsyncListenerWrapper wrapper = new AsyncListenerWrapper(); wrapper.setListener(listener); listeners.add(wrapper); } @SuppressWarnings("unchecked") @Override public T createListener(Class clazz) throws ServletException { check(); T listener = null; try { listener = (T) getInstanceManager().newInstance(clazz.getName(), clazz.getClassLoader()); } catch (InstantiationException e) { ServletException se = new ServletException(e); throw se; } catch (IllegalAccessException e) { ServletException se = new ServletException(e); throw se; } catch (InvocationTargetException e) { ExceptionUtils.handleThrowable(e.getCause()); ServletException se = new ServletException(e); throw se; } catch (NamingException e) { ServletException se = new ServletException(e); throw se; } catch (ClassNotFoundException e) { ServletException se = new ServletException(e); throw se; } return listener; } public void recycle() { if (log.isDebugEnabled()) { logDebug("recycle "); } context = null; dispatch = null; event = null; hasOriginalRequestAndResponse = true; instanceManager = null; listeners.clear(); request = null; servletRequest = null; servletResponse = null; timeout = -1; } public boolean isStarted() { AtomicBoolean result = new AtomicBoolean(false); request.getCoyoteRequest().action( ActionCode.ASYNC_IS_STARTED, result); return result.get(); } public void setStarted(Context context, ServletRequest request, ServletResponse response, boolean originalRequestResponse) { this.request.getCoyoteRequest().action( ActionCode.ASYNC_START, this); this.context = context; this.servletRequest = request; this.servletResponse = response; this.hasOriginalRequestAndResponse = originalRequestResponse; this.event = new AsyncEvent(this, request, response); List listenersCopy = new ArrayList(); listenersCopy.addAll(listeners); for (AsyncListenerWrapper listener : listenersCopy) { try { listener.fireOnStartAsync(event); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn("onStartAsync() failed for listener of type [" + listener.getClass().getName() + "]", t); } } listeners.clear(); } @Override public boolean hasOriginalRequestAndResponse() { check(); return hasOriginalRequestAndResponse; } protected void doInternalDispatch() throws ServletException, IOException { if (log.isDebugEnabled()) { logDebug("intDispatch"); } try { Runnable runnable = dispatch; dispatch = null; runnable.run(); if (!request.isAsync()) { fireOnComplete(); } } catch (RuntimeException x) { // doInternalComplete(true); if (x.getCause() instanceof ServletException) { throw (ServletException)x.getCause(); } if (x.getCause() instanceof IOException) { throw (IOException)x.getCause(); } throw new ServletException(x); } } @Override public long getTimeout() { check(); return timeout; } @Override public void setTimeout(long timeout) { check(); this.timeout = timeout; request.getCoyoteRequest().action(ActionCode.ASYNC_SETTIMEOUT, Long.valueOf(timeout)); } public void setErrorState(Throwable t, boolean fireOnError) { if (t!=null) request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); request.getCoyoteRequest().action(ActionCode.ASYNC_ERROR, null); if (fireOnError) { AsyncEvent errorEvent = new AsyncEvent(event.getAsyncContext(), event.getSuppliedRequest(), event.getSuppliedResponse(), t); List listenersCopy = new ArrayList(); listenersCopy.addAll(listeners); for (AsyncListenerWrapper listener : listenersCopy) { try { listener.fireOnError(errorEvent); } catch (Throwable t2) { ExceptionUtils.handleThrowable(t); log.warn("onError() failed for listener of type [" + listener.getClass().getName() + "]", t2); } } } AtomicBoolean result = new AtomicBoolean(); request.getCoyoteRequest().action(ActionCode.ASYNC_IS_ERROR, result); if (result.get()) { // No listener called dispatch() or complete(). This is an error. // SRV.2.3.3.3 (search for "error dispatch") if (servletResponse instanceof HttpServletResponse) { ((HttpServletResponse) servletResponse).setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } Host host = (Host) context.getParent(); Valve stdHostValve = host.getPipeline().getBasic(); if (stdHostValve instanceof StandardHostValve) { ((StandardHostValve) stdHostValve).throwable(request, request.getResponse(), t); } request.getCoyoteRequest().action( ActionCode.ASYNC_IS_ERROR, result); if (result.get()) { // Still in the error state. The error page did not call // complete() or dispatch(). Complete the async processing. complete(); } } } private void logDebug(String method) { String rHashCode; String crHashCode; String rpHashCode; String stage; StringBuilder uri = new StringBuilder(); if (request == null) { rHashCode = "null"; crHashCode = "null"; rpHashCode = "null"; stage = "-"; uri.append("N/A"); } else { rHashCode = Integer.toHexString(request.hashCode()); org.apache.coyote.Request coyoteRequest = request.getCoyoteRequest(); if (coyoteRequest == null) { crHashCode = "null"; rpHashCode = "null"; stage = "-"; } else { crHashCode = Integer.toHexString(coyoteRequest.hashCode()); RequestInfo rp = coyoteRequest.getRequestProcessor(); if (rp == null) { rpHashCode = "null"; stage = "-"; } else { rpHashCode = Integer.toHexString(rp.hashCode()); stage = Integer.toString(rp.getStage()); } } uri.append(request.getRequestURI()); if (request.getQueryString() != null) { uri.append('?'); uri.append(request.getQueryString()); } } String threadName = Thread.currentThread().getName(); int len = threadName.length(); if (len > 20) { threadName = threadName.substring(len - 20, len); } String msg = String.format( "Req: %1$8s CReq: %2$8s RP: %3$8s Stage: %4$s " + "Thread: %5$20s State: %6$20s Method: %7$11s URI: %8$s", rHashCode, crHashCode, rpHashCode, stage, threadName, "N/A", method, uri); if (log.isTraceEnabled()) { log.trace(msg, new DebugException()); } else { log.debug(msg); } } private InstanceManager getInstanceManager() { if (instanceManager == null) { if (context instanceof StandardContext) { instanceManager = ((StandardContext)context).getInstanceManager(); } else { instanceManager = new DefaultInstanceManager(null, new HashMap>(), context, getClass().getClassLoader()); } } return instanceManager; } private void check() { if (request == null) { // AsyncContext has been recycled and should not be being used throw new IllegalStateException(sm.getString( "asyncContextImpl.requestEnded")); } } private static class DebugException extends Exception { private static final long serialVersionUID = 1L; } private static class RunnableWrapper implements Runnable { private Runnable wrapped = null; private Context context = null; public RunnableWrapper(Runnable wrapped, Context ctxt) { this.wrapped = wrapped; this.context = ctxt; } @Override public void run() { ClassLoader oldCL; if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedGetTccl(); oldCL = AccessController.doPrivileged(pa); } else { oldCL = Thread.currentThread().getContextClassLoader(); } try { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( context.getLoader().getClassLoader()); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader (context.getLoader().getClassLoader()); } wrapped.run(); } finally { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction pa = new PrivilegedSetTccl( oldCL); AccessController.doPrivileged(pa); } else { Thread.currentThread().setContextClassLoader(oldCL); } } } } private static class PrivilegedSetTccl implements PrivilegedAction { private ClassLoader cl; PrivilegedSetTccl(ClassLoader cl) { this.cl = cl; } @Override public Void run() { Thread.currentThread().setContextClassLoader(cl); return null; } } private static class PrivilegedGetTccl implements PrivilegedAction { @Override public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } } } tomcat7-7.0.52/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java0000644000175100017510000005315312267023542027743 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.core; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.sql.DriverManager; import java.util.StringTokenizer; import javax.imageio.ImageIO; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.catalina.Globals; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Provide a workaround for known places where the Java Runtime environment can * cause a memory leak or lock files. *

    * Memory leaks occur when JRE code uses * the context class loader to load a singleton as this will cause a memory leak * if a web application class loader happens to be the context class loader at * the time. The work-around is to initialise these singletons when Tomcat's * common class loader is the context class loader. *

    * Locked files usually occur when a resource inside a JAR is accessed without * first disabling Jar URL connection caching. The workaround is to disable this * caching by default. */ public class JreMemoryLeakPreventionListener implements LifecycleListener { private static final Log log = LogFactory.getLog(JreMemoryLeakPreventionListener.class); private static final StringManager sm = StringManager.getManager(Constants.Package); private static final boolean IS_JAVA_7_OR_LATER; static { boolean isJava7OrLater; try { Class.forName("java.util.Objects"); isJava7OrLater = true; } catch (ClassNotFoundException e) { isJava7OrLater = false; } IS_JAVA_7_OR_LATER = isJava7OrLater; } /** * Protect against the memory leak caused when the first call to * sun.awt.AppContext.getAppContext() is triggered by a web * application. Defaults to true for Java 6 and earlier (since * it is used by {@link java.beans.Introspector#flushCaches()}) but defaults * to false for Java 7 and later since * {@link java.beans.Introspector#flushCaches()} no longer uses AppContext * from 1.7.0_02 onwards. Also, from 1.7.0_25 onwards, calling this method * requires a graphical environment and starts an AWT thread. */ private boolean appContextProtection = !IS_JAVA_7_OR_LATER; public boolean isAppContextProtection() { return appContextProtection; } public void setAppContextProtection(boolean appContextProtection) { this.appContextProtection = appContextProtection; } /** * Protect against the memory leak caused when the first call to * java.awt.Toolkit.getDefaultToolkit() is triggered * by a web application. Defaults to false because a new * Thread is launched. */ private boolean awtThreadProtection = false; public boolean isAWTThreadProtection() { return awtThreadProtection; } public void setAWTThreadProtection(boolean awtThreadProtection) { this.awtThreadProtection = awtThreadProtection; } /** * Protect against the memory leak caused when the * sun.java2d.Disposer class is loaded by a web application. * Defaults to false because a new Thread is launched. */ private boolean java2dDisposerProtection = false; public boolean isJava2DDisposerProtection() { return java2dDisposerProtection; } public void setJava2DDisposerProtection(boolean java2dDisposerProtection) { this.java2dDisposerProtection = java2dDisposerProtection; } /** * Protect against the memory leak caused when the first call to * sun.misc.GC.requestLatency(long) is triggered by a web * application. This first call will start a GC Daemon thread with the * thread's context class loader configured to be the web application class * loader. Defaults to true. */ private boolean gcDaemonProtection = true; public boolean isGcDaemonProtection() { return gcDaemonProtection; } public void setGcDaemonProtection(boolean gcDaemonProtection) { this.gcDaemonProtection = gcDaemonProtection; } /** * Protect against the memory leak caused when the first call to * javax.security.auth.Policy is triggered by a web * application. This first call populate a static variable with a reference * to the context class loader. Defaults to true. */ private boolean securityPolicyProtection = true; public boolean isSecurityPolicyProtection() { return securityPolicyProtection; } public void setSecurityPolicyProtection(boolean securityPolicyProtection) { this.securityPolicyProtection = securityPolicyProtection; } /** * Protects against the memory leak caused when the first call to * javax.security.auth.login.Configuration is triggered by a * web application. This first call populate a static variable with a * reference to the context class loader. Defaults to true. */ private boolean securityLoginConfigurationProtection = true; public boolean isSecurityLoginConfigurationProtection() { return securityLoginConfigurationProtection; } public void setSecurityLoginConfigurationProtection( boolean securityLoginConfigurationProtection) { this.securityLoginConfigurationProtection = securityLoginConfigurationProtection; } /** * Protect against the memory leak, when the initialization of the * Java Cryptography Architecture is triggered by initializing * a MessageDigest during web application deployment. * This will occasionally start a Token Poller thread with the thread's * context class loader equal to the web application class loader. * Instead we initialize JCA early. * Defaults to true. */ private boolean tokenPollerProtection = true; public boolean isTokenPollerProtection() { return tokenPollerProtection; } public void setTokenPollerProtection(boolean tokenPollerProtection) { this.tokenPollerProtection = tokenPollerProtection; } /** * Protect against resources being read for JAR files and, as a side-effect, * the JAR file becoming locked. Note this disables caching for all * {@link URLConnection}s, regardless of type. Defaults to * true. */ private boolean urlCacheProtection = true; public boolean isUrlCacheProtection() { return urlCacheProtection; } public void setUrlCacheProtection(boolean urlCacheProtection) { this.urlCacheProtection = urlCacheProtection; } /** * XML parsing can pin a web application class loader in memory. This is * particularly nasty as profilers (at least YourKit and Eclipse MAT) don't * identify any GC roots related to this. * * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6916498 */ private boolean xmlParsingProtection = true; public boolean isXmlParsingProtection() { return xmlParsingProtection; } public void setXmlParsingProtection(boolean xmlParsingProtection) { this.xmlParsingProtection = xmlParsingProtection; } /** * com.sun.jndi.ldap.LdapPoolManager class spawns a thread when * it is initialized if the system property * com.sun.jndi.ldap.connect.pool.timeout is greater than 0. * That thread inherits the context class loader of the current thread, so * that there may be a web application class loader leak if the web app * is the first to use LdapPoolManager. */ private boolean ldapPoolProtection = true; public boolean isLdapPoolProtection() { return ldapPoolProtection; } public void setLdapPoolProtection(boolean ldapPoolProtection) { this.ldapPoolProtection = ldapPoolProtection; } /** * The first access to {@link DriverManager} will trigger the loading of * all {@link java.sql.Driver}s in the the current class loader. The web * application level memory leak protection can take care of this in most * cases but triggering the loading here has fewer side-effects. */ private boolean driverManagerProtection = true; public boolean isDriverManagerProtection() { return driverManagerProtection; } public void setDriverManagerProtection(boolean driverManagerProtection) { this.driverManagerProtection = driverManagerProtection; } /** * List of comma-separated fully qualified class names to load and initialize during * the startup of this Listener. This allows to pre-load classes that are known to * provoke classloader leaks if they are loaded during a request processing. */ private String classesToInitialize = null; public String getClassesToInitialize() { return classesToInitialize; } public void setClassesToInitialize(String classesToInitialize) { this.classesToInitialize = classesToInitialize; } @Override public void lifecycleEvent(LifecycleEvent event) { // Initialise these classes when Tomcat starts if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { // Use the system classloader as the victim for all this // ClassLoader pinning we're about to do. Thread.currentThread().setContextClassLoader( ClassLoader.getSystemClassLoader()); /* * First call to this loads all drivers in the current class * loader */ if (driverManagerProtection) { DriverManager.getDrivers(); } /* * Several components end up calling: * sun.awt.AppContext.getAppContext() * * Those libraries / components known to trigger memory leaks * due to eventual calls to getAppContext() are: * - Google Web Toolkit via its use of javax.imageio * - Tomcat via its use of java.beans.Introspector.flushCaches() * in 1.6.0_15 to 1.7.0_01. From 1.7.0_02 onwards use of * AppContext by Introspector.flushCaches() was replaced with * ThreadGroupContext * - others TBD * * From 1.7.0_25 onwards, a call to * sun.awt.AppContext.getAppContext() results in a thread being * started named AWT-AppKit that requires a graphic environment * to be available. */ // Trigger a call to sun.awt.AppContext.getAppContext(). This // will pin the system class loader in memory but that shouldn't // be an issue. if (appContextProtection) { ImageIO.getCacheDirectory(); } // Trigger the creation of the AWT (AWT-Windows, AWT-XAWT, // etc.) thread if (awtThreadProtection) { java.awt.Toolkit.getDefaultToolkit(); } // Trigger the creation of the "Java2D Disposer" thread. // See https://issues.apache.org/bugzilla/show_bug.cgi?id=51687 if(java2dDisposerProtection) { try { Class.forName("sun.java2d.Disposer"); } catch (ClassNotFoundException cnfe) { // Ignore this case: we must be running on a // non-Sun-based JRE. } } /* * Several components end up calling * sun.misc.GC.requestLatency(long) which creates a daemon * thread without setting the TCCL. * * Those libraries / components known to trigger memory leaks * due to eventual calls to requestLatency(long) are: * - javax.management.remote.rmi.RMIConnectorServer.start() * * Note: Long.MAX_VALUE is a special case that causes the thread * to terminate * */ if (gcDaemonProtection) { try { Class clazz = Class.forName("sun.misc.GC"); Method method = clazz.getDeclaredMethod( "requestLatency", new Class[] {long.class}); method.invoke(null, Long.valueOf(Long.MAX_VALUE - 1)); } catch (ClassNotFoundException e) { if (Globals.IS_ORACLE_JVM) { log.error(sm.getString( "jreLeakListener.gcDaemonFail"), e); } else { log.debug(sm.getString( "jreLeakListener.gcDaemonFail"), e); } } catch (SecurityException e) { log.error(sm.getString("jreLeakListener.gcDaemonFail"), e); } catch (NoSuchMethodException e) { log.error(sm.getString("jreLeakListener.gcDaemonFail"), e); } catch (IllegalArgumentException e) { log.error(sm.getString("jreLeakListener.gcDaemonFail"), e); } catch (IllegalAccessException e) { log.error(sm.getString("jreLeakListener.gcDaemonFail"), e); } catch (InvocationTargetException e) { ExceptionUtils.handleThrowable(e.getCause()); log.error(sm.getString("jreLeakListener.gcDaemonFail"), e); } } /* * Calling getPolicy retains a static reference to the context * class loader. */ if (securityPolicyProtection) { try { // Policy.getPolicy(); Class policyClass = Class .forName("javax.security.auth.Policy"); Method method = policyClass.getMethod("getPolicy"); method.invoke(null); } catch(ClassNotFoundException e) { // Ignore. The class is deprecated. } catch(SecurityException e) { // Ignore. Don't need call to getPolicy() to be // successful, just need to trigger static initializer. } catch (NoSuchMethodException e) { log.warn(sm.getString("jreLeakListener.authPolicyFail"), e); } catch (IllegalArgumentException e) { log.warn(sm.getString("jreLeakListener.authPolicyFail"), e); } catch (IllegalAccessException e) { log.warn(sm.getString("jreLeakListener.authPolicyFail"), e); } catch (InvocationTargetException e) { ExceptionUtils.handleThrowable(e.getCause()); log.warn(sm.getString("jreLeakListener.authPolicyFail"), e); } } /* * Initializing javax.security.auth.login.Configuration retains a static reference to the context * class loader. */ if (securityLoginConfigurationProtection) { try { Class.forName("javax.security.auth.login.Configuration", true, ClassLoader.getSystemClassLoader()); } catch(ClassNotFoundException e) { // Ignore } } /* * Creating a MessageDigest during web application startup * initializes the Java Cryptography Architecture. Under certain * conditions this starts a Token poller thread with TCCL equal * to the web application class loader. * * Instead we initialize JCA right now. */ if (tokenPollerProtection) { java.security.Security.getProviders(); } /* * Several components end up opening JarURLConnections without * first disabling caching. This effectively locks the file. * Whilst more noticeable and harder to ignore on Windows, it * affects all operating systems. * * Those libraries/components known to trigger this issue * include: * - log4j versions 1.2.15 and earlier * - javax.xml.bind.JAXBContext.newInstance() */ // Set the default URL caching policy to not to cache if (urlCacheProtection) { try { // Doesn't matter that this JAR doesn't exist - just as // long as the URL is well-formed URL url = new URL("jar:file://dummy.jar!/"); URLConnection uConn = url.openConnection(); uConn.setDefaultUseCaches(false); } catch (MalformedURLException e) { log.error(sm.getString( "jreLeakListener.jarUrlConnCacheFail"), e); } catch (IOException e) { log.error(sm.getString( "jreLeakListener.jarUrlConnCacheFail"), e); } } /* * Haven't got to the root of what is going on with this leak * but if a web app is the first to make the calls below the web * application class loader will be pinned in memory. */ if (xmlParsingProtection) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { log.error(sm.getString("jreLeakListener.xmlParseFail"), e); } } if (ldapPoolProtection) { try { Class.forName("com.sun.jndi.ldap.LdapPoolManager"); } catch (ClassNotFoundException e) { if (Globals.IS_ORACLE_JVM) { log.error(sm.getString( "jreLeakListener.ldapPoolManagerFail"), e); } else { log.debug(sm.getString( "jreLeakListener.ldapPoolManagerFail"), e); } } } if (classesToInitialize != null) { StringTokenizer strTok = new StringTokenizer(classesToInitialize, ", \r\n\t"); while (strTok.hasMoreTokens()) { String classNameToLoad = strTok.nextToken(); try { Class.forName(classNameToLoad); } catch (ClassNotFoundException e) { log.error( sm.getString("jreLeakListener.classToInitializeFail", classNameToLoad), e); // continue with next class to load } } } } finally { Thread.currentThread().setContextClassLoader(loader); } } } } tomcat7-7.0.52/java/org/apache/catalina/startup/0000755000175100017510000000000012301126370021345 5ustar locutuslocutustomcat7-7.0.52/java/org/apache/catalina/startup/LocalStrings_es.properties0000644000175100017510000002505312271471332026572 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. catalina.configFail = No pude cargar la configuraci\u00F3n del servidor desde [{0}] catalina.shutdownHookFail = El gancho de apagado ha experimentado un error al intentar para el servidor catalina.stopServer = No se ha configurado puerto de apagado. Apagando el servidor a trav\u00E9s de se\u00F1al de SO. Servidor no apagado. contextConfig.altDDNotFound = fichero alt-dd {0} no hallado contextConfig.applicationUrl = No pude determinar la URL para la aplicaci\u00F3n web.xml contextConfig.applicationMissing = Falta el archivo web.xml de la aplicaci\u00F3n. Utilizando los par\u00E1metros por defecto contextConfig.applicationParse = Error de evaluaci\u00F3n (parse) en el archivo web.xml de la aplicaci\u00F3n a {0} contextConfig.applicationPosition = Se ha producido en la l\u00EDnea {0} columna {1} contextConfig.applicationStart = Analizando fichero de aplicaci\u00F3n web.xml en {0} contextConfig.authenticatorConfigured = Configuraci\u00F3n de un autentificador (authenticator) para el m\u00E9todo {0} contextConfig.authenticatorInstantiate = Imposible de instanciar un autenticador (authenticator) para la clase {0} contextConfig.authenticatorMissing = Imposible de configurar un autentificador (authenticator) para el m\u00E9todo {0} contextConfig.authenticatorResources = Imposible de cargar la lista de correspondencia de autenticadores (authenticators) contextConfig.badUrl = No pude procesar descriptor de contextor [{0}] contectConfig.baseError = No pude determinar $CATALINA_BASE contextConfig.cce = El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un Contexto contextConfig.contextClose = Error cerrando context.xml\: {0} contextConfig.contextMissing = Falta context.xml\: {0} contextConfig.contextParse = Error de an\u00E1lisis en context.xml\: {0} contextConfig.defaultError = Error al procesar web.xml por defecto con nombre {0} en {1} contextConfig.defaultMissing = No se ha hallado web.xml global contextConfig.defaultPosition = Se ha producido en la l\u00EDnea {0} columna {1} contextConfig.destroy = ContextConfig\: Destruyendo contextConfig.fileUrl = No puedo crear un objeto Fichero desde la URL [{0}] contextConfig.fixDocBase = Excepci\u00F3n arreglando docBase\: {0} contextConfig.init = ContextConfig\: Inicializando contextConfig.inputStreamFile = No puedo procesar el fichero [{0}] para las anotaciones contextConfig.inputStreamJar = No puedo procesar la entrada de Jar [{0}] desde el Jar [{1}] para las anotaciones contextConfig.inputStreamJndi = No puedo procesar el elemento de recurso [{0}] para las anotaciones contextConfig.invalidSci = No se pudo crear el ServletContentInitializer [{0}] contextConfig.invalidSciHandlesTypes = No puedo cargar la clase [{0}] para revisar contra la anotaci\u00F3n @HandlesTypes de uno o m\u00E1s ServletContentInitializers. contextConfig.jarUrl = La conexi\u00F3n creada para la URL [{0}] no era una JarUrlConnection contextConfig.jar = No puedo crear el recurso [{0}] para las anotaciones contextConfig.jndiUrl = No puedo procesar la URL JNDI [{0}] para las anotaciones contextConfig.jndiUrlNotDirContextConn = La conexi\u00F3n creada para la URL [{0}] no era una DirContextURLConnection contextConfig.jspFile.error = El archivo JSP {0} debe de comenzar con ''/' contextConfig.jspFile.warning = AVISO\: El archivo JSP {0} debe de comenzar con ''/'' en Servlet 2.4 contextConfig.missingRealm = Alg\u00FAn reino (realm) no ha sido configurado para realizar la autenticaci\u00F3n contextConfig.resourceJarFail = Hallado JAR fallido a los procesos en URL [{0}] para recursos est\u00E1ticos a ser incluidos en contexto con nombre [{0}] contextConfig.role.auth = El nombre de papel de seguridad {0} es usado en un sin haber sido definido en contextConfig.role.link = El nombre de papel de seguridad {0} es usado en un sin haber sido definido en contextConfig.role.runas = El nombre de papel de seguridad {0} es usado en un sin haber sido definido en contextConfig.servletContainerInitializerFail = Hallado JAR fallido a proceso en URL [{0}] para ServletContainerInitializers para el contexto con nombre [{1}] contextConfig.start = "ContextConfig"\: Procesando "START" contextConfig.stop = "ContextConfig"\: Procesando "STOP" contextConfig.unavailable = Esta aplicaci\u00F3n est\u00E1 marcada como no disponible debido a los errores precedentes contextConfig.unknownUrlProtocol = El protocolo de URL [{0}] no fue reconocido durante el proceso de anotaciones. Se ignor\u00F3 la URL [{1}]. contextConfig.urlPatternValue = Ambis valores de UrlPattern y atributo fuerno puestos para anotaci\u00F3n de WebServlet de la clase [{0}] contextConfig.webinfClassesUrl = No pude determinar la URL para WEB-INF/classes contextConfig.xmlSettings = El contexto [{0}] analizar\u00E1 los ficheros web.xml y web-fragment.xml con validaci\u00F3n\:{1} y namespaceAware\:{2} embedded.noEngines = Alg\u00FAn motor (engine) no ha sido a\u00FAn definido embedded.notmp = No puedo hallar carpeta temporal especificada en {0} embedded.authenticatorNotInstanceOfValve = El Autenticado especificado no es un V\u00E1lvula engineConfig.cce = El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un motor (engine) engineConfig.start = "EngineConfig"\: Procesando "START" engineConfig.stop = "EngineConfig"\: Procesando "STOP" expandWar.copy = Error copiando {0} a {1} expandWar.deleteFailed = [{0}] no pudo ser completamente borrado. La presencia de los ficheros restantes puede causar problemas expandWar.illegalPath = The archive [{0}] is malformed and will be ignored\: an entry contains an illegal path [{1}] which was not expanded to [{2}] since that is outside of the defined docBase [{3}] hostConfig.canonicalizing = Error al borrar redespliegue de recursos desde contexto [{0}] hostConfig.cce = El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es una m\u00E1quina (host) hostConfig.context.remove = Error al quitar contexto [{0}] hostConfig.context.restart = Error durante el arranque del contexto {0} hostConfig.createDirs = No puedo crear directorio para despliegue\: {0} hostConfig.deploy = Desplieque del directorio {0} de la aplicaci\u00F3n web hostConfig.deployDescriptor = Desplieque del descriptor de configuraci\u00F3n {0} hostConfig.deployDescriptor.error = Error durante el despliegue del descriptor de configuraci\u00F3n {0} hostConfig.deployDescriptor.localDocBaseSpecified = Se ha especificado un docBase {0} dentro del appBase de la m\u00E1quina y ser\u00E1 ignorado hostConfig.deployDir = Despliegue del directorio {0} de la aplicaci\u00F3n web hostConfig.deployDir.error = Error durante el despliegue del directorio {0} de la aplicaci\u00F3n web hostConfig.deployWar = Despliegue del archivo {0} de la aplicaci\u00F3n web hostConfig.deployWar.error = Error durante el despliegue del archivo {0} de la aplicaci\u00F3n web hostConfig.deploy.error = Excepci\u00F3n en el directorio {0} de la aplicaci\u00F3n web hostConfig.deploying = Desplegando aplicaciones web descubiertas hostConfig.expand = Descompresi\u00F3n del archivo {0} de la aplicaci\u00F3n web hostConfig.expand.error = Excepci\u00F3n durante la descompresi\u00F3n del archivo {0} de la aplicaci\u00F3n web hostConfig.expanding = Descubierta descompresi\u00F3n de archivos de aplicaciones web hostConfig.ignorePath = Ignorando ruta [{0}] en appBase para despliegue autom\u00E1tico hostConfig.illegalWarName = El nombre de war [{0}] es inv\u00E1lido. El archivo ser\u00E1 ignorado. hostConfig.jmx.register = Fall\u00F3 el registro del contexto [{0}] hostConfig.jmx.unregister = Fall\u00F3 el desregistro del contexto [{0}] hostConfig.reload = Fall\u00F3 la recarga del contexto [{0}] hostConfig.removeXML = El context [{0}] est\u00E1 replegado hostConfig.removeDIR = El directorio [{0}] est\u00E1 replegado hostConfig.removeWAR = El War [{0}] est\u00E1 replegado hostConfig.start = "HostConfig"\: Procesando "START" hostConfig.stop = "HostConfig"\: Procesando "STOP" hostConfig.undeploy = Repliegue (undeploy) de la aplicaci\u00F3n web que tiene como trayectoria de contexto {0} hostConfig.undeploy.error = Error durante el repliegue (undeploy) de la aplicaci\u00F3n web que tiene como trayectoria de contexto {0} tldConfig.addListeners = A\u00F1adiendo {0} oyentes desde ficheros TLD tldConfig.cce = El objeto de datos de eventos de Ciclo de vida {0} no se encuentra en el Contexto tldConfig.dirFail = No pude procesar el directorio [{0}] para ficheros TLD tldConfig.dirScan = Explorando en busca de ficheros TLD en directorio [{0}] tldConfig.execute = Error al procesar ficheros TLD para el contexto con nombre [{0}] tldConfig.jarFail = No pude procesar el JAR [{0}] para ficheros TLD tldConfig.webinfFail = No pude procesar TLD hallado en [{0}] tldConfig.webinfScan = Esplorando WEB-INF en busca de ficheros TLD en [{0}] tldConfig.webxmlAdd = A\u00F1adiendo ruta [{0}] para URI [{1}] tldConfig.webxmlFail = No pude procesar TLD con ruta [{0}] y URI [{1}] tldConfig.webxmlSkip = La ruta [{1}] saltada desde URI [{0}] es un duplicado tldConfig.webxmlStart = Explorando elementos en web.xml userConfig.database = Excepci\u00F3n durante la carga de base de datos de usuario userConfig.deploy = Despliegue de la aplicaci\u00F3n web para el usuario {0} userConfig.deploying = Desplegando aplicaciones web para el usuario userConfig.error = Error durante el despliegue de la aplicaci\u00F3n web para el usario {0} userConfig.start = "UserConfig"\: Tratamiento del "START" userConfig.stop = "UserConfig"\: Tratamiento del "STOP" webRuleSet.absoluteOrdering = Elemento no v\u00E1lido en web-fragment.xml y ser\u00E1 ignorado webRuleSet.relativeOrdering = elemento no v\u00E1lido en web.xml y ser\u00E1 ignorado xmlErrorHandler.error = Error no fatal [{0}] reportado por el proceso [{1}]. xmlErrorHandler.warning = Aviso [{0}] reportado por el proceso [{1}]. tomcat7-7.0.52/java/org/apache/catalina/startup/Tool.java0000644000175100017510000002064012271471332023136 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; import org.apache.catalina.Globals; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; /** *

    General purpose wrapper for command line tools that should execute in an * environment with the common class loader environment set up by Catalina. * This should be executed from a command line script that conforms to * the following requirements:

    *
      *
    • Passes the catalina.home system property configured with * the pathname of the Tomcat installation directory.
    • *
    • Sets the system classpath to include bootstrap.jar and * $JAVA_HOME/lib/tools.jar.
    • *
    * *

    The command line to execute the tool looks like:

    *
     *   java -classpath $CLASSPATH org.apache.catalina.startup.Tool \
     *     ${options} ${classname} ${arguments}
     * 
    * *

    with the following replacement contents: *

      *
    • ${options} - Command line options for this Tool wrapper. * The following options are supported: *
        *
      • -ant : Set the ant.home system property * to corresponding to the value of catalina.home * (useful when your command line tool runs Ant).
      • *
      • -common : Add common/classes and * common/lib *
      • -server : Add server/classes and * server/lib to the class loader repositories.
      • *
      • -shared : Add shared/classes and * shared/lib to the class loader repositories.
      • *
      *
    • ${classname} - Fully qualified Java class name of the * application's main class.
    • *
    • ${arguments} - Command line arguments to be passed to * the application's main() method.
    • *
    * * @author Craig R. McClanahan */ public final class Tool { private static final Log log = LogFactory.getLog(Tool.class); // ------------------------------------------------------- Static Variables /** * Set ant.home system property? */ private static boolean ant = false; /** * The pathname of our installation base directory. */ private static String catalinaHome = System.getProperty(Globals.CATALINA_HOME_PROP); /** * Include common classes in the repositories? */ private static boolean common = false; /** * Include server classes in the repositories? */ private static boolean server = false; /** * Include shared classes in the repositories? */ private static boolean shared = false; // ----------------------------------------------------------- Main Program /** * The main program for the bootstrap. * * @param args Command line arguments to be processed */ @SuppressWarnings("null") public static void main(String args[]) { // Verify that "catalina.home" was passed. if (catalinaHome == null) { log.error("Must set '" + Globals.CATALINA_HOME_PROP + "' system property"); System.exit(1); } // Process command line options int index = 0; while (true) { if (index == args.length) { usage(); System.exit(1); } if ("-ant".equals(args[index])) ant = true; else if ("-common".equals(args[index])) common = true; else if ("-server".equals(args[index])) server = true; else if ("-shared".equals(args[index])) shared = true; else break; index++; } if (index > args.length) { usage(); System.exit(1); } // Set "ant.home" if requested if (ant) System.setProperty("ant.home", catalinaHome); // Construct the class loader we will be using ClassLoader classLoader = null; try { ArrayList packed = new ArrayList(); ArrayList unpacked = new ArrayList(); unpacked.add(new File(catalinaHome, "classes")); packed.add(new File(catalinaHome, "lib")); if (common) { unpacked.add(new File(catalinaHome, "common" + File.separator + "classes")); packed.add(new File(catalinaHome, "common" + File.separator + "lib")); } if (server) { unpacked.add(new File(catalinaHome, "server" + File.separator + "classes")); packed.add(new File(catalinaHome, "server" + File.separator + "lib")); } if (shared) { unpacked.add(new File(catalinaHome, "shared" + File.separator + "classes")); packed.add(new File(catalinaHome, "shared" + File.separator + "lib")); } classLoader = ClassLoaderFactory.createClassLoader (unpacked.toArray(new File[0]), packed.toArray(new File[0]), null); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); } Thread.currentThread().setContextClassLoader(classLoader); // Load our application class Class clazz = null; String className = args[index++]; try { if (log.isDebugEnabled()) log.debug("Loading application class " + className); clazz = classLoader.loadClass(className); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("Exception creating instance of " + className, t); System.exit(1); } Method method = null; String params[] = new String[args.length - index]; System.arraycopy(args, index, params, 0, params.length); try { if (log.isDebugEnabled()) log.debug("Identifying main() method"); String methodName = "main"; Class paramTypes[] = new Class[1]; paramTypes[0] = params.getClass(); method = clazz.getMethod(methodName, paramTypes); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error("Exception locating main() method", t); System.exit(1); } // Invoke the main method of the application class try { if (log.isDebugEnabled()) log.debug("Calling main() method"); Object paramValues[] = new Object[1]; paramValues[0] = params; method.invoke(null, paramValues); } catch (Throwable t) { t = ExceptionUtils.unwrapInvocationTargetException(t); ExceptionUtils.handleThrowable(t); log.error("Exception calling main() method", t); System.exit(1); } } /** * Display usage information about this tool. */ private static void usage() { log.info("Usage: java org.apache.catalina.startup.Tool [] []"); } } tomcat7-7.0.52/java/org/apache/catalina/startup/SetContextPropertiesRule.java0000644000175100017510000000501012271471332027220 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.digester.Rule; import org.xml.sax.Attributes; /** * Rule that uses the introspection utils to set properties of a context * (everything except "path"). * * @author Remy Maucherat */ public class SetContextPropertiesRule extends Rule { // ----------------------------------------------------------- Constructors // ----------------------------------------------------- Instance Variables // --------------------------------------------------------- Public Methods /** * Handle the beginning of an XML element. * * @param attributes The attributes of this element * * @exception Exception if a processing error occurs */ @Override public void begin(String namespace, String nameX, Attributes attributes) throws Exception { for (int i = 0; i < attributes.getLength(); i++) { String name = attributes.getLocalName(i); if ("".equals(name)) { name = attributes.getQName(i); } if ("path".equals(name) || "docBase".equals(name)) { continue; } String value = attributes.getValue(i); if (!digester.isFakeAttribute(digester.peek(), name) && !IntrospectionUtils.setProperty(digester.peek(), name, value) && digester.getRulesValidation()) { digester.getLogger().warn("[SetContextPropertiesRule]{" + digester.getMatch() + "} Setting property '" + name + "' to '" + value + "' did not find a matching property."); } } } } tomcat7-7.0.52/java/org/apache/catalina/startup/CatalinaProperties.java0000644000175100017510000001202712271471332026012 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.Properties; import org.apache.catalina.Globals; /** * Utility class to read the bootstrap Catalina configuration. * * @author Remy Maucherat */ public class CatalinaProperties { // ------------------------------------------------------- Static Variables private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( CatalinaProperties.class ); private static Properties properties = null; static { loadProperties(); } // --------------------------------------------------------- Public Methods /** * Return specified property value. */ public static String getProperty(String name) { return properties.getProperty(name); } /** * Return specified property value. * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static String getProperty(String name, String defaultValue) { return properties.getProperty(name, defaultValue); } // --------------------------------------------------------- Public Methods /** * Load properties. */ private static void loadProperties() { InputStream is = null; Throwable error = null; try { String configUrl = getConfigUrl(); if (configUrl != null) { is = (new URL(configUrl)).openStream(); } } catch (Throwable t) { handleThrowable(t); } if (is == null) { try { File home = new File(getCatalinaBase()); File conf = new File(home, "conf"); File propsFile = new File(conf, "catalina.properties"); is = new FileInputStream(propsFile); } catch (Throwable t) { handleThrowable(t); } } if (is == null) { try { is = CatalinaProperties.class.getResourceAsStream ("/org/apache/catalina/startup/catalina.properties"); } catch (Throwable t) { handleThrowable(t); } } if (is != null) { try { properties = new Properties(); properties.load(is); is.close(); } catch (Throwable t) { handleThrowable(t); error = t; } } if ((is == null) || (error != null)) { // Do something log.warn("Failed to load catalina.properties", error); // That's fine - we have reasonable defaults. properties=new Properties(); } // Register the properties as system properties Enumeration enumeration = properties.propertyNames(); while (enumeration.hasMoreElements()) { String name = (String) enumeration.nextElement(); String value = properties.getProperty(name); if (value != null) { System.setProperty(name, value); } } } /** * Get the value of the catalina.home environment variable. */ private static String getCatalinaHome() { return System.getProperty(Globals.CATALINA_HOME_PROP, System.getProperty("user.dir")); } /** * Get the value of the catalina.base environment variable. */ private static String getCatalinaBase() { return System.getProperty(Globals.CATALINA_BASE_PROP, getCatalinaHome()); } /** * Get the value of the configuration URL. */ private static String getConfigUrl() { return System.getProperty("catalina.config"); } // Copied from ExceptionUtils since that class is not visible during start private static void handleThrowable(Throwable t) { if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } // All other instances of Throwable will be silently swallowed } } tomcat7-7.0.52/java/org/apache/catalina/startup/ContextRuleSet.java0000644000175100017510000001754712271471332025165 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSetBase; /** *

    RuleSet for processing the contents of a * Context definition element.

    * * @author Craig R. McClanahan */ public class ContextRuleSet extends RuleSetBase { // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; /** * Should the context be created. */ protected boolean create = true; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public ContextRuleSet() { this(""); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public ContextRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public ContextRuleSet(String prefix, boolean create) { super(); this.namespaceURI = null; this.prefix = prefix; this.create = create; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { if (create) { digester.addObjectCreate(prefix + "Context", "org.apache.catalina.core.StandardContext", "className"); digester.addSetProperties(prefix + "Context"); } else { digester.addRule(prefix + "Context", new SetContextPropertiesRule()); } if (create) { digester.addRule(prefix + "Context", new LifecycleListenerRule ("org.apache.catalina.startup.ContextConfig", "configClass")); digester.addSetNext(prefix + "Context", "addChild", "org.apache.catalina.Container"); } digester.addCallMethod(prefix + "Context/InstanceListener", "addInstanceListener", 0); digester.addObjectCreate(prefix + "Context/Listener", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Context/Listener"); digester.addSetNext(prefix + "Context/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener"); digester.addObjectCreate(prefix + "Context/Loader", "org.apache.catalina.loader.WebappLoader", "className"); digester.addSetProperties(prefix + "Context/Loader"); digester.addSetNext(prefix + "Context/Loader", "setLoader", "org.apache.catalina.Loader"); digester.addObjectCreate(prefix + "Context/Manager", "org.apache.catalina.session.StandardManager", "className"); digester.addSetProperties(prefix + "Context/Manager"); digester.addSetNext(prefix + "Context/Manager", "setManager", "org.apache.catalina.Manager"); digester.addObjectCreate(prefix + "Context/Manager/Store", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Context/Manager/Store"); digester.addSetNext(prefix + "Context/Manager/Store", "setStore", "org.apache.catalina.Store"); digester.addObjectCreate(prefix + "Context/Parameter", "org.apache.catalina.deploy.ApplicationParameter"); digester.addSetProperties(prefix + "Context/Parameter"); digester.addSetNext(prefix + "Context/Parameter", "addApplicationParameter", "org.apache.catalina.deploy.ApplicationParameter"); digester.addRuleSet(new RealmRuleSet(prefix + "Context/")); digester.addObjectCreate(prefix + "Context/Resources", "org.apache.naming.resources.FileDirContext", "className"); digester.addSetProperties(prefix + "Context/Resources"); digester.addSetNext(prefix + "Context/Resources", "setResources", "javax.naming.directory.DirContext"); digester.addObjectCreate(prefix + "Context/ResourceLink", "org.apache.catalina.deploy.ContextResourceLink"); digester.addSetProperties(prefix + "Context/ResourceLink"); digester.addRule(prefix + "Context/ResourceLink", new SetNextNamingRule("addResourceLink", "org.apache.catalina.deploy.ContextResourceLink")); digester.addObjectCreate(prefix + "Context/Valve", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Context/Valve"); digester.addSetNext(prefix + "Context/Valve", "addValve", "org.apache.catalina.Valve"); digester.addCallMethod(prefix + "Context/WatchedResource", "addWatchedResource", 0); digester.addCallMethod(prefix + "Context/WrapperLifecycle", "addWrapperLifecycle", 0); digester.addCallMethod(prefix + "Context/WrapperListener", "addWrapperListener", 0); digester.addObjectCreate(prefix + "Context/JarScanner", "org.apache.tomcat.util.scan.StandardJarScanner", "className"); digester.addSetProperties(prefix + "Context/JarScanner"); digester.addSetNext(prefix + "Context/JarScanner", "setJarScanner", "org.apache.tomcat.JarScanner"); } } tomcat7-7.0.52/java/org/apache/catalina/startup/SetAllPropertiesRule.java0000644000175100017510000000543112271471332026313 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.util.HashMap; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.digester.Rule; import org.xml.sax.Attributes; /** * Rule that uses the introspection utils to set properties. * * @author Remy Maucherat * @author Filip Hanik */ public class SetAllPropertiesRule extends Rule { // ----------------------------------------------------------- Constructors public SetAllPropertiesRule() {} public SetAllPropertiesRule(String[] exclude) { for (int i=0; i excludes = new HashMap(); // --------------------------------------------------------- Public Methods /** * Handle the beginning of an XML element. * * @param attributes The attributes of this element * * @exception Exception if a processing error occurs */ @Override public void begin(String namespace, String nameX, Attributes attributes) throws Exception { for (int i = 0; i < attributes.getLength(); i++) { String name = attributes.getLocalName(i); if ("".equals(name)) { name = attributes.getQName(i); } String value = attributes.getValue(i); if ( !excludes.containsKey(name)) { if (!digester.isFakeAttribute(digester.peek(), name) && !IntrospectionUtils.setProperty(digester.peek(), name, value) && digester.getRulesValidation()) { digester.getLogger().warn("[SetAllPropertiesRule]{" + digester.getMatch() + "} Setting property '" + name + "' to '" + value + "' did not find a matching property."); } } } } } tomcat7-7.0.52/java/org/apache/catalina/startup/NamingRuleSet.java0000644000175100017510000001215112271471332024734 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSetBase; /** *

    RuleSet for processing the JNDI Enterprise Naming * Context resource declaration elements.

    * * @author Craig R. McClanahan * @author Remy Maucherat */ public class NamingRuleSet extends RuleSetBase { // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public NamingRuleSet() { this(""); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public NamingRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { digester.addObjectCreate(prefix + "Ejb", "org.apache.catalina.deploy.ContextEjb"); digester.addRule(prefix + "Ejb", new SetAllPropertiesRule()); digester.addRule(prefix + "Ejb", new SetNextNamingRule("addEjb", "org.apache.catalina.deploy.ContextEjb")); digester.addObjectCreate(prefix + "Environment", "org.apache.catalina.deploy.ContextEnvironment"); digester.addSetProperties(prefix + "Environment"); digester.addRule(prefix + "Environment", new SetNextNamingRule("addEnvironment", "org.apache.catalina.deploy.ContextEnvironment")); digester.addObjectCreate(prefix + "LocalEjb", "org.apache.catalina.deploy.ContextLocalEjb"); digester.addRule(prefix + "LocalEjb", new SetAllPropertiesRule()); digester.addRule(prefix + "LocalEjb", new SetNextNamingRule("addLocalEjb", "org.apache.catalina.deploy.ContextLocalEjb")); digester.addObjectCreate(prefix + "Resource", "org.apache.catalina.deploy.ContextResource"); digester.addRule(prefix + "Resource", new SetAllPropertiesRule()); digester.addRule(prefix + "Resource", new SetNextNamingRule("addResource", "org.apache.catalina.deploy.ContextResource")); digester.addObjectCreate(prefix + "ResourceEnvRef", "org.apache.catalina.deploy.ContextResourceEnvRef"); digester.addRule(prefix + "ResourceEnvRef", new SetAllPropertiesRule()); digester.addRule(prefix + "ResourceEnvRef", new SetNextNamingRule("addResourceEnvRef", "org.apache.catalina.deploy.ContextResourceEnvRef")); digester.addObjectCreate(prefix + "ServiceRef", "org.apache.catalina.deploy.ContextService"); digester.addRule(prefix + "ServiceRef", new SetAllPropertiesRule()); digester.addRule(prefix + "ServiceRef", new SetNextNamingRule("addService", "org.apache.catalina.deploy.ContextService")); digester.addObjectCreate(prefix + "Transaction", "org.apache.catalina.deploy.ContextTransaction"); digester.addRule(prefix + "Transaction", new SetAllPropertiesRule()); digester.addRule(prefix + "Transaction", new SetNextNamingRule("setTransaction", "org.apache.catalina.deploy.ContextTransaction")); } } tomcat7-7.0.52/java/org/apache/catalina/startup/FailedContext.java0000644000175100017510000005427012265507335024766 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.beans.PropertyChangeListener; import java.io.IOException; import java.net.URL; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.naming.directory.DirContext; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletSecurityElement; import javax.servlet.descriptor.JspConfigDescriptor; import org.apache.catalina.AccessLog; import org.apache.catalina.Authenticator; import org.apache.catalina.Cluster; import org.apache.catalina.Container; import org.apache.catalina.ContainerListener; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.Loader; import org.apache.catalina.Manager; import org.apache.catalina.Pipeline; import org.apache.catalina.Realm; import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.core.ApplicationServletRegistration; import org.apache.catalina.deploy.ApplicationListener; import org.apache.catalina.deploy.ApplicationParameter; import org.apache.catalina.deploy.ErrorPage; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.deploy.NamingResources; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.CharsetMapper; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.tomcat.InstanceManager; import org.apache.tomcat.JarScanner; import org.apache.tomcat.util.http.mapper.Mapper; import org.apache.tomcat.util.res.StringManager; /** * An implementation of {@link Context} that is used as a place-holder for * deployed applications when their deployment fails and a Context instance * (usually {@link org.apache.catalina.core.StandardContext} but may be any * Context implementation) cannot be created. */ public class FailedContext extends LifecycleMBeanBase implements Context { protected static final StringManager sm = StringManager.getManager(Constants.Package); // --------------------- Methods that need to work even for a failed context private URL configFile; @Override public URL getConfigFile() { return configFile; } @Override public void setConfigFile(URL configFile) { this.configFile = configFile; } private String docBase; @Override public String getDocBase() { return docBase; } @Override public void setDocBase(String docBase) { this.docBase = docBase; } private String name = null; @Override public String getName() { return name; } @Override public void setName(String name) { this.name = name; } private Container parent; @Override public Container getParent() { return parent; } @Override public void setParent(Container parent) { this.parent = parent; } private String path = null; @Override public String getPath() { return path; } @Override public void setPath(String path) { this.path = path; } private String webappVersion = null; @Override public String getWebappVersion() { return webappVersion; } @Override public void setWebappVersion(String webappVersion) { this.webappVersion = webappVersion; } @Override @Deprecated protected String getDomainInternal() { return MBeanUtils.getDomain(this); } @Override protected String getObjectNameKeyProperties() { StringBuilder keyProperties = new StringBuilder("j2eeType=WebModule,name=//"); String hostname = getParent().getName(); if (hostname == null) { keyProperties.append("DEFAULT"); } else { keyProperties.append(hostname); } String contextName = getName(); if (!contextName.startsWith("/")) { keyProperties.append('/'); } keyProperties.append(contextName); keyProperties.append(",J2EEApplication=none,J2EEServer=none"); return keyProperties.toString(); } @Override protected void startInternal() throws LifecycleException { throw new LifecycleException( sm.getString("failedContext.start", getName())); } @Override protected void stopInternal() throws LifecycleException { // NO-OP // Allow stop to complete since it is used for clean-up } // Only need to read these @Override public void addWatchedResource(String name) { /* NO-OP */ } @Override public String[] findWatchedResources() { return new String[0]; } @Override public void removeWatchedResource(String name) { /* NO-OP */ } @Override public void addChild(Container child) { /* NO-OP */ } @Override public Container findChild(String name) { return null; } @Override public Container[] findChildren() { return new Container[0]; } @Override public void removeChild(Container child) { /* NO-OP */ } @Override public String toString() { return getName(); } // -------------------------------------------- All NO-OPs beyond this point @Override public Loader getLoader() { return null; } @Override public void setLoader(Loader loader) { /* NO-OP */ } @Override public Log getLogger() { return null; } @Override public Manager getManager() { return null; } @Override public void setManager(Manager manager) { /* NO-OP */ } @Override public Pipeline getPipeline() { return null; } @Override public Cluster getCluster() { return null; } @Override public void setCluster(Cluster cluster) { /* NO-OP */ } @Override public int getBackgroundProcessorDelay() { return -1; } @Override public void setBackgroundProcessorDelay(int delay) { /* NO-OP */ } @Override public ClassLoader getParentClassLoader() { return null; } @Override public void setParentClassLoader(ClassLoader parent) { /* NO-OP */ } @Override public Realm getRealm() { return null; } @Override public void setRealm(Realm realm) { /* NO-OP */ } @Override public DirContext getResources() { return null; } @Override public void setResources(DirContext resources) { /* NO-OP */ } @Override public void backgroundProcess() { /* NO-OP */ } @Override public void addContainerListener(ContainerListener listener) { /* NO-OP */ } @Override public ContainerListener[] findContainerListeners() { return null; } @Override public void removeContainerListener(ContainerListener listener) { /* NO-OP */ } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { /* NO-OP */ } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { /* NO-OP */ } @Override public void invoke(Request request, Response response) throws IOException, ServletException { /* NO-OP */ } @Override public void fireContainerEvent(String type, Object data) { /* NO-OP */ } @Override public void logAccess(Request request, Response response, long time, boolean useDefault) { /* NO-OP */ } @Override public AccessLog getAccessLog() { return null; } @Override public int getStartStopThreads() { return 0; } @Override public void setStartStopThreads(int startStopThreads) { /* NO-OP */ } @Override public boolean getAllowCasualMultipartParsing() { return false; } @Override public void setAllowCasualMultipartParsing( boolean allowCasualMultipartParsing) { /* NO-OP */ } @Override public Object[] getApplicationEventListeners() { return null; } @Override public void setApplicationEventListeners(Object[] listeners) { /* NO-OP */ } @Override public Object[] getApplicationLifecycleListeners() { return null; } @Override public void setApplicationLifecycleListeners(Object[] listeners) { /* NO-OP */ } @Override public boolean getAvailable() { return false; } @Deprecated @Override public CharsetMapper getCharsetMapper() { return null; } @Deprecated @Override public void setCharsetMapper(CharsetMapper mapper) { /* NO-OP */ } @Override public String getCharset(Locale locale) { return null; } @Override public boolean getConfigured() { return false; } @Override public void setConfigured(boolean configured) { /* NO-OP */ } @Override public boolean getCookies() { return false; } @Override public void setCookies(boolean cookies) { /* NO-OP */ } @Override public String getSessionCookieName() { return null; } @Override public void setSessionCookieName(String sessionCookieName) { /* NO-OP */ } @Override public boolean getUseHttpOnly() { return false; } @Override public void setUseHttpOnly(boolean useHttpOnly) { /* NO-OP */ } @Override public String getSessionCookieDomain() { return null; } @Override public void setSessionCookieDomain(String sessionCookieDomain) { /* NO-OP */ } @Override public String getSessionCookiePath() { return null; } @Override public void setSessionCookiePath(String sessionCookiePath) { /* NO-OP */ } @Override public boolean getSessionCookiePathUsesTrailingSlash() { return false; } @Override public void setSessionCookiePathUsesTrailingSlash( boolean sessionCookiePathUsesTrailingSlash) { /* NO-OP */ } @Override public boolean getCrossContext() { return false; } @Override public void setCrossContext(boolean crossContext) { /* NO-OP */ } @Override public String getAltDDName() { return null; } @Override public void setAltDDName(String altDDName) { /* NO-OP */ } @Override public String getDisplayName() { return null; } @Override public void setDisplayName(String displayName) { /* NO-OP */ } @Override public boolean getDistributable() { return false; } @Override public void setDistributable(boolean distributable) { /* NO-OP */ } @Override public String getEncodedPath() { return null; } @Override public boolean getIgnoreAnnotations() { return false; } @Override public void setIgnoreAnnotations(boolean ignoreAnnotations) { /* NO-OP */ } @Override public LoginConfig getLoginConfig() { return null; } @Override public void setLoginConfig(LoginConfig config) { /* NO-OP */ } @Override public Mapper getMapper() { return null; } @Override public NamingResources getNamingResources() { return null; } @Override public void setNamingResources(NamingResources namingResources) { /* NO-OP */ } @Override public String getPublicId() { return null; } @Override public void setPublicId(String publicId) { /* NO-OP */ } @Override public boolean getReloadable() { return false; } @Override public void setReloadable(boolean reloadable) { /* NO-OP */ } @Override public boolean getOverride() { return false; } @Override public void setOverride(boolean override) { /* NO-OP */ } @Override public boolean getPrivileged() { return false; } @Override public void setPrivileged(boolean privileged) { /* NO-OP */ } @Override public ServletContext getServletContext() { return null; } @Override public int getSessionTimeout() { return 0; } @Override public void setSessionTimeout(int timeout) { /* NO-OP */ } @Override public boolean getSwallowAbortedUploads() { return false; } @Override public void setSwallowAbortedUploads(boolean swallowAbortedUploads) { /* NO-OP */ } @Override public boolean getSwallowOutput() { return false; } @Override public void setSwallowOutput(boolean swallowOutput) { /* NO-OP */ } @Override public String getWrapperClass() { return null; } @Override public void setWrapperClass(String wrapperClass) { /* NO-OP */ } @Override public boolean getXmlNamespaceAware() { return false; } @Override public void setXmlNamespaceAware(boolean xmlNamespaceAware) { /* NO-OP */ } @Override public boolean getXmlValidation() { return false; } @Override public void setXmlValidation(boolean xmlValidation) { /* NO-OP */ } @Override public void setTldValidation(boolean tldValidation) { /* NO-OP */ } @Override public boolean getXmlBlockExternal() { return true; } @Override public void setXmlBlockExternal(boolean xmlBlockExternal) { /* NO-OP */ } @Override public boolean getTldValidation() { return false; } @Override public boolean getTldNamespaceAware() { return true; } @Override public void setTldNamespaceAware(boolean tldNamespaceAware) { /* NO-OP */ } @Override public JarScanner getJarScanner() { return null; } @Override public void setJarScanner(JarScanner jarScanner) { /* NO-OP */ } @Override public Authenticator getAuthenticator() { return null; } @Override public void setLogEffectiveWebXml(boolean logEffectiveWebXml) { /* NO-OP */ } @Override public boolean getLogEffectiveWebXml() { return false; } @Override public void addApplicationListener(ApplicationListener listener) { /* NO-OP */ } @Override public void addApplicationListener(String listener) { /* NO-OP */ } @Override public String[] findApplicationListeners() { return null; } @Override public void removeApplicationListener(String listener) { /* NO-OP */ } @Override public void addApplicationParameter(ApplicationParameter parameter) { /* NO-OP */ } @Override public ApplicationParameter[] findApplicationParameters() { return null; } @Override public void removeApplicationParameter(String name) { /* NO-OP */ } @Override public void addConstraint(SecurityConstraint constraint) { /* NO-OP */ } @Override public SecurityConstraint[] findConstraints() { return null; } @Override public void removeConstraint(SecurityConstraint constraint) { /* NO-OP */ } @Override public void addErrorPage(ErrorPage errorPage) { /* NO-OP */ } @Override public ErrorPage findErrorPage(int errorCode) { return null; } @Override public ErrorPage findErrorPage(String exceptionType) { return null; } @Override public ErrorPage[] findErrorPages() { return null; } @Override public void removeErrorPage(ErrorPage errorPage) { /* NO-OP */ } @Override public void addFilterDef(FilterDef filterDef) { /* NO-OP */ } @Override public FilterDef findFilterDef(String filterName) { return null; } @Override public FilterDef[] findFilterDefs() { return null; } @Override public void removeFilterDef(FilterDef filterDef) { /* NO-OP */ } @Override public void addFilterMap(FilterMap filterMap) { /* NO-OP */ } @Override public void addFilterMapBefore(FilterMap filterMap) { /* NO-OP */ } @Override public FilterMap[] findFilterMaps() { return null; } @Override public void removeFilterMap(FilterMap filterMap) { /* NO-OP */ } @Override public void addInstanceListener(String listener) { /* NO-OP */ } @Override public String[] findInstanceListeners() { return null; } @Override public void removeInstanceListener(String listener) { /* NO-OP */ } @Override public void addLocaleEncodingMappingParameter(String locale, String encoding) { /* NO-OP */ } @Override public void addMimeMapping(String extension, String mimeType) { /* NO-OP */ } @Override public String findMimeMapping(String extension) { return null; } @Override public String[] findMimeMappings() { return null; } @Override public void removeMimeMapping(String extension) { /* NO-OP */ } @Override public void addParameter(String name, String value) { /* NO-OP */ } @Override public String findParameter(String name) { return null; } @Override public String[] findParameters() { return null; } @Override public void removeParameter(String name) { /* NO-OP */ } @Override public void addRoleMapping(String role, String link) { /* NO-OP */ } @Override public String findRoleMapping(String role) { return null; } @Override public void removeRoleMapping(String role) { /* NO-OP */ } @Override public void addSecurityRole(String role) { /* NO-OP */ } @Override public boolean findSecurityRole(String role) { return false; } @Override public String[] findSecurityRoles() { return null; } @Override public void removeSecurityRole(String role) { /* NO-OP */ } @Override public void addServletMapping(String pattern, String name) { /* NO-OP */ } @Override public void addServletMapping(String pattern, String name, boolean jspWildcard) { /* NO-OP */ } @Override public String findServletMapping(String pattern) { return null; } @Override public String[] findServletMappings() { return null; } @Override public void removeServletMapping(String pattern) { /* NO-OP */ } @Override public void addWelcomeFile(String name) { /* NO-OP */ } @Override public boolean findWelcomeFile(String name) { return false; } @Override public String[] findWelcomeFiles() { return null; } @Override public void removeWelcomeFile(String name) { /* NO-OP */ } @Override public void addWrapperLifecycle(String listener) { /* NO-OP */ } @Override public String[] findWrapperLifecycles() { return null; } @Override public void removeWrapperLifecycle(String listener) { /* NO-OP */ } @Override public void addWrapperListener(String listener) { /* NO-OP */ } @Override public String[] findWrapperListeners() { return null; } @Override public void removeWrapperListener(String listener) { /* NO-OP */ } @Override public Wrapper createWrapper() { return null; } @Override public String findStatusPage(int status) { return null; } @Override public int[] findStatusPages() { return null; } @Override public boolean fireRequestInitEvent(ServletRequest request) { return false; } @Override public boolean fireRequestDestroyEvent(ServletRequest request) { return false; } @Override public void reload() { /* NO-OP */ } @Override public String getRealPath(String path) { return null; } @Override public int getEffectiveMajorVersion() { return 0; } @Override public void setEffectiveMajorVersion(int major) { /* NO-OP */ } @Override public int getEffectiveMinorVersion() { return 0; } @Override public void setEffectiveMinorVersion(int minor) { /* NO-OP */ } @Override public JspConfigDescriptor getJspConfigDescriptor() { return null; } @Override public void addResourceJarUrl(URL url) { /* NO-OP */ } @Override public void addServletContainerInitializer(ServletContainerInitializer sci, Set> classes) { /* NO-OP */ } @Override public boolean getPaused() { return false; } @Override public boolean isServlet22() { return false; } @Override public Set addServletSecurity( ApplicationServletRegistration registration, ServletSecurityElement servletSecurityElement) { return null; } @Override public void setResourceOnlyServlets(String resourceOnlyServlets) { /* NO-OP */ } @Override public String getResourceOnlyServlets() { return null; } @Override public boolean isResourceOnlyServlet(String servletName) { return false; } @Override public String getBaseName() { return null; } @Override public void setFireRequestListenersOnForwards(boolean enable) { /* NO-OP */ } @Override public boolean getFireRequestListenersOnForwards() { return false; } @Override public void setPreemptiveAuthentication(boolean enable) { /* NO-OP */ } @Override public boolean getPreemptiveAuthentication() { return false; } @Override public void setSendRedirectBody(boolean enable) { /* NO-OP */ } @Override public boolean getSendRedirectBody() { return false; } @SuppressWarnings("unused") public synchronized void addValve(Valve valve) { /* NO-OP */ } @Override public String getInfo() { return null; } @Override public Object getMappingObject() { return null; } @Override public void addPostConstructMethod(String clazz, String method) { /* NO-OP */ } @Override public void addPreDestroyMethod(String clazz, String method) { /* NO-OP */ } @Override public void removePostConstructMethod(String clazz) { /* NO-OP */ } @Override public void removePreDestroyMethod(String clazz) { /* NO-OP */ } @Override public String findPostConstructMethod(String clazz) { return null; } @Override public String findPreDestroyMethod(String clazz) { return null; } @Override public Map findPostConstructMethods() { return null; } @Override public Map findPreDestroyMethods() { return null; } @Override public InstanceManager getInstanceManager() { return null; } @Override public void setInstanceManager(InstanceManager instanceManager) { /* NO-OP */ } @Override public void setContainerSciFilter(String containerSciFilter) { /* NO-OP */ } @Override public String getContainerSciFilter() { return null; } }tomcat7-7.0.52/java/org/apache/catalina/startup/Bootstrap.java0000644000175100017510000004207712271471332024206 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.lang.management.ManagementFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import org.apache.catalina.Globals; import org.apache.catalina.security.SecurityClassLoad; import org.apache.catalina.startup.ClassLoaderFactory.Repository; import org.apache.catalina.startup.ClassLoaderFactory.RepositoryType; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; /** * Bootstrap loader for Catalina. This application constructs a class loader * for use in loading the Catalina internal classes (by accumulating all of the * JAR files found in the "server" directory under "catalina.home"), and * starts the regular execution of the container. The purpose of this * roundabout approach is to keep the Catalina internal classes (and any * other classes they depend on, such as an XML parser) out of the system * class path and therefore not visible to application level classes. * * @author Craig R. McClanahan * @author Remy Maucherat */ public final class Bootstrap { private static final Log log = LogFactory.getLog(Bootstrap.class); // ------------------------------------------------------- Static Variables /** * Daemon object used by main. */ private static Bootstrap daemon = null; // -------------------------------------------------------------- Variables /** * Daemon reference. */ private Object catalinaDaemon = null; protected ClassLoader commonLoader = null; protected ClassLoader catalinaLoader = null; protected ClassLoader sharedLoader = null; // -------------------------------------------------------- Private Methods private void initClassLoaders() { try { commonLoader = createClassLoader("common", null); if( commonLoader == null ) { // no config file, default to this loader - we might be in a 'single' env. commonLoader=this.getClass().getClassLoader(); } catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { handleThrowable(t); log.error("Class loader creation threw exception", t); System.exit(1); } } private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception { String value = CatalinaProperties.getProperty(name + ".loader"); if ((value == null) || (value.equals(""))) return parent; value = replace(value); List repositories = new ArrayList(); StringTokenizer tokenizer = new StringTokenizer(value, ","); while (tokenizer.hasMoreElements()) { String repository = tokenizer.nextToken().trim(); if (repository.length() == 0) { continue; } // Check for a JAR URL repository try { @SuppressWarnings("unused") URL url = new URL(repository); repositories.add( new Repository(repository, RepositoryType.URL)); continue; } catch (MalformedURLException e) { // Ignore } // Local repository if (repository.endsWith("*.jar")) { repository = repository.substring (0, repository.length() - "*.jar".length()); repositories.add( new Repository(repository, RepositoryType.GLOB)); } else if (repository.endsWith(".jar")) { repositories.add( new Repository(repository, RepositoryType.JAR)); } else { repositories.add( new Repository(repository, RepositoryType.DIR)); } } ClassLoader classLoader = ClassLoaderFactory.createClassLoader (repositories, parent); // Retrieving MBean server MBeanServer mBeanServer = null; if (MBeanServerFactory.findMBeanServer(null).size() > 0) { mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0); } else { mBeanServer = ManagementFactory.getPlatformMBeanServer(); } // Register the server classloader ObjectName objectName = new ObjectName("Catalina:type=ServerClassLoader,name=" + name); mBeanServer.registerMBean(classLoader, objectName); return classLoader; } /** * System property replacement in the given string. * * @param str The original string * @return the modified string */ protected String replace(String str) { // Implementation is copied from ClassLoaderLogManager.replace(), // but added special processing for catalina.home and catalina.base. String result = str; int pos_start = str.indexOf("${"); if (pos_start >= 0) { StringBuilder builder = new StringBuilder(); int pos_end = -1; while (pos_start >= 0) { builder.append(str, pos_end + 1, pos_start); pos_end = str.indexOf('}', pos_start + 2); if (pos_end < 0) { pos_end = pos_start - 1; break; } String propName = str.substring(pos_start + 2, pos_end); String replacement; if (propName.length() == 0) { replacement = null; } else if (Globals.CATALINA_HOME_PROP.equals(propName)) { replacement = getCatalinaHome(); } else if (Globals.CATALINA_BASE_PROP.equals(propName)) { replacement = getCatalinaBase(); } else { replacement = System.getProperty(propName); } if (replacement != null) { builder.append(replacement); } else { builder.append(str, pos_start, pos_end + 1); } pos_start = str.indexOf("${", pos_end + 1); } builder.append(str, pos_end + 1, str.length()); result = builder.toString(); } return result; } /** * Initialize daemon. */ public void init() throws Exception { // Set Catalina path setCatalinaHome(); setCatalinaBase(); initClassLoaders(); Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method if (log.isDebugEnabled()) log.debug("Loading startup class"); Class startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); // Set the shared extensions class loader if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); catalinaDaemon = startupInstance; } /** * Load daemon. */ private void load(String[] arguments) throws Exception { // Call the load() method String methodName = "load"; Object param[]; Class paramTypes[]; if (arguments==null || arguments.length==0) { paramTypes = null; param = null; } else { paramTypes = new Class[1]; paramTypes[0] = arguments.getClass(); param = new Object[1]; param[0] = arguments; } Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes); if (log.isDebugEnabled()) log.debug("Calling startup class " + method); method.invoke(catalinaDaemon, param); } /** * getServer() for configtest */ private Object getServer() throws Exception { String methodName = "getServer"; Method method = catalinaDaemon.getClass().getMethod(methodName); return method.invoke(catalinaDaemon); } // ----------------------------------------------------------- Main Program /** * Load the Catalina daemon. */ public void init(String[] arguments) throws Exception { init(); load(arguments); } /** * Start the Catalina daemon. */ public void start() throws Exception { if( catalinaDaemon==null ) init(); Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null); method.invoke(catalinaDaemon, (Object [])null); } /** * Stop the Catalina Daemon. */ public void stop() throws Exception { Method method = catalinaDaemon.getClass().getMethod("stop", (Class [] ) null); method.invoke(catalinaDaemon, (Object [] ) null); } /** * Stop the standalone server. */ public void stopServer() throws Exception { Method method = catalinaDaemon.getClass().getMethod("stopServer", (Class []) null); method.invoke(catalinaDaemon, (Object []) null); } /** * Stop the standalone server. */ public void stopServer(String[] arguments) throws Exception { Object param[]; Class paramTypes[]; if (arguments==null || arguments.length==0) { paramTypes = null; param = null; } else { paramTypes = new Class[1]; paramTypes[0] = arguments.getClass(); param = new Object[1]; param[0] = arguments; } Method method = catalinaDaemon.getClass().getMethod("stopServer", paramTypes); method.invoke(catalinaDaemon, param); } /** * Set flag. */ public void setAwait(boolean await) throws Exception { Class paramTypes[] = new Class[1]; paramTypes[0] = Boolean.TYPE; Object paramValues[] = new Object[1]; paramValues[0] = Boolean.valueOf(await); Method method = catalinaDaemon.getClass().getMethod("setAwait", paramTypes); method.invoke(catalinaDaemon, paramValues); } public boolean getAwait() throws Exception { Class paramTypes[] = new Class[0]; Object paramValues[] = new Object[0]; Method method = catalinaDaemon.getClass().getMethod("getAwait", paramTypes); Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues); return b.booleanValue(); } /** * Destroy the Catalina Daemon. */ public void destroy() { // FIXME } /** * Main method and entry point when starting Tomcat via the provided * scripts. * * @param args Command line arguments to be processed */ public static void main(String args[]) { if (daemon == null) { // Don't set daemon until init() has completed Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to prevent // a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null==daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } } public void setCatalinaHome(String s) { System.setProperty(Globals.CATALINA_HOME_PROP, s); } public void setCatalinaBase(String s) { System.setProperty(Globals.CATALINA_BASE_PROP, s); } /** * Set the catalina.base System property to the current * working directory if it has not been set. */ private void setCatalinaBase() { if (System.getProperty(Globals.CATALINA_BASE_PROP) != null) return; if (System.getProperty(Globals.CATALINA_HOME_PROP) != null) System.setProperty(Globals.CATALINA_BASE_PROP, System.getProperty(Globals.CATALINA_HOME_PROP)); else System.setProperty(Globals.CATALINA_BASE_PROP, System.getProperty("user.dir")); } /** * Set the catalina.home System property to the current * working directory if it has not been set. */ private void setCatalinaHome() { if (System.getProperty(Globals.CATALINA_HOME_PROP) != null) return; File bootstrapJar = new File(System.getProperty("user.dir"), "bootstrap.jar"); if (bootstrapJar.exists()) { try { System.setProperty (Globals.CATALINA_HOME_PROP, (new File(System.getProperty("user.dir"), "..")) .getCanonicalPath()); } catch (Exception e) { // Ignore System.setProperty(Globals.CATALINA_HOME_PROP, System.getProperty("user.dir")); } } else { System.setProperty(Globals.CATALINA_HOME_PROP, System.getProperty("user.dir")); } } /** * Get the value of the catalina.home environment variable. */ public static String getCatalinaHome() { return System.getProperty(Globals.CATALINA_HOME_PROP, System.getProperty("user.dir")); } /** * Get the value of the catalina.base environment variable. */ public static String getCatalinaBase() { return System.getProperty(Globals.CATALINA_BASE_PROP, getCatalinaHome()); } // Copied from ExceptionUtils since that class is not visible during start private static void handleThrowable(Throwable t) { if (t instanceof ThreadDeath) { throw (ThreadDeath) t; } if (t instanceof VirtualMachineError) { throw (VirtualMachineError) t; } // All other instances of Throwable will be silently swallowed } } tomcat7-7.0.52/java/org/apache/catalina/startup/Tomcat.java0000644000175100017510000011266012271471332023454 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.Servlet; import javax.servlet.ServletException; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Realm; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.Wrapper; import org.apache.catalina.authenticator.NonLoginAuthenticator; import org.apache.catalina.connector.Connector; import org.apache.catalina.core.NamingContextListener; import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardEngine; import org.apache.catalina.core.StandardHost; import org.apache.catalina.core.StandardServer; import org.apache.catalina.core.StandardService; import org.apache.catalina.core.StandardWrapper; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.realm.RealmBase; // TODO: lazy init for the temp dir - only when a JSP is compiled or // get temp dir is called we need to create it. This will avoid the // need for the baseDir // TODO: allow contexts without a base dir - i.e. // only programmatic. This would disable the default servlet. /** * Minimal tomcat starter for embedding/unit tests. * * Tomcat supports multiple styles of configuration and * startup - the most common and stable is server.xml-based, * implemented in org.apache.catalina.startup.Bootstrap. * * This class is for use in apps that embed tomcat. * Requirements: * * - all tomcat classes and possibly servlets are in the classpath. * ( for example all is in one big jar, or in eclipse CP, or in any other * combination ) * * - we need one temporary directory for work files * * - no config file is required. This class provides methods to * use if you have a webapp with a web.xml file, but it is * optional - you can use your own servlets. * * There are a variety of 'add' methods to configure servlets and webapps. These * methods, by default, create a simple in-memory security realm and apply it. * If you need more complex security processing, you can define a subclass of * this class. * * This class provides a set of convenience methods for configuring webapp * contexts, all overloads of the method
    addWebapp
    . These methods * create a webapp context, configure it, and then add it to a {@link Host}. * They do not use a global default web.xml; rather, they add a lifecycle * listener that adds the standard DefaultServlet, JSP processing, and welcome * files. * * In complex cases, you may prefer to use the ordinary Tomcat API to create * webapp contexts; for example, you might need to install a custom Loader * before the call to {@link Host#addChild(Container)}. To replicate the basic * behavior of the
    addWebapp
    methods, you may want to call two * methods of this class: {@link #noDefaultWebXmlPath()} and * {@link #getDefaultWebXmlListener()}. * * {@link #getDefaultRealm()} returns the simple security realm. * * {@link #getDefaultWebXmlListener()} returns a {@link LifecycleListener} that * adds the standard DefaultServlet, JSP processing, and welcome files. If you * add this listener, you must prevent Tomcat from applying any standard global * web.xml with ... * * {@link #noDefaultWebXmlPath()} returns a dummy pathname to configure to * prevent {@link ContextConfig} from trying to apply a global web.xml file. * * This class provides a main() and few simple CLI arguments, * see setters for doc. It can be used for simple tests and * demo. * * @see TestTomcat * @author Costin Manolache */ public class Tomcat { // Single engine, service, server, connector - few cases need more, // they can use server.xml protected Server server; protected Service service; protected Engine engine; protected Connector connector; // for more - customize the classes // To make it a bit easier to config for the common case // ( one host, one context ). protected Host host; // TODO: it's easy to add support for more hosts - but is it // really needed ? // TODO: allow use of in-memory connector protected int port = 8080; protected String hostname = "localhost"; protected String basedir; // Default in-memory realm, will be set by default on the Engine. Can be // replaced at engine level or over-ridden at Host or Context level @Deprecated // Will be removed in Tomcat 8.0.x. protected Realm defaultRealm; private final Map userPass = new HashMap(); private final Map> userRoles = new HashMap>(); private final Map userPrincipals = new HashMap(); public Tomcat() { // NOOP } /** * Tomcat needs a directory for temp files. This should be the * first method called. * * By default, if this method is not called, we use: * - system properties - catalina.base, catalina.home * - $HOME/tomcat.$PORT * ( /tmp doesn't seem a good choice for security ). * * * TODO: better default ? Maybe current dir ? * TODO: disable work dir if not needed ( no jsp, etc ). */ public void setBaseDir(String basedir) { this.basedir = basedir; } /** * Set the port for the default connector. Must * be called before start(). */ public void setPort(int port) { this.port = port; } /** * The the hostname of the default host, default is * 'localhost'. */ public void setHostname(String s) { hostname = s; } /** * This is equivalent to adding a web application to Tomcat's webapps * directory. The equivalent of the default web.xml will be applied to the * web application and any WEB-INF/web.xml and META-INF/context.xml packaged * with the application will be processed normally. Normal web fragment and * {@link javax.servlet.ServletContainerInitializer} processing will be * applied. * * @throws ServletException */ public Context addWebapp(String contextPath, String baseDir) throws ServletException { return addWebapp(getHost(), contextPath, baseDir); } /** * Add a context - programmatic mode, no web.xml used. * * API calls equivalent with web.xml: * * context-param * ctx.addParameter("name", "value"); * * * error-page * ErrorPage ep = new ErrorPage(); * ep.setErrorCode(500); * ep.setLocation("/error.html"); * ctx.addErrorPage(ep); * * ctx.addMimeMapping("ext", "type"); * * Note: If you reload the Context, all your configuration will be lost. If * you need reload support, consider using a LifecycleListener to provide * your configuration. * * TODO: add the rest * * @param contextPath "" for root context. * @param baseDir base dir for the context, for static files. Must exist, * relative to the server home */ public Context addContext(String contextPath, String baseDir) { return addContext(getHost(), contextPath, baseDir); } /** * Equivalent with * . * * In general it is better/faster to use the method that takes a * Servlet as param - this one can be used if the servlet is not * commonly used, and want to avoid loading all deps. * ( for example: jsp servlet ) * * You can customize the returned servlet, ex: * * wrapper.addInitParameter("name", "value"); * * @param contextPath Context to add Servlet to * @param servletName Servlet name (used in mappings) * @param servletClass The class to be used for the Servlet * @return The wrapper for the servlet */ public Wrapper addServlet(String contextPath, String servletName, String servletClass) { Container ctx = getHost().findChild(contextPath); return addServlet((Context) ctx, servletName, servletClass); } /** * Static version of {@link #addServlet(String, String, String)} * @param ctx Context to add Servlet to * @param servletName Servlet name (used in mappings) * @param servletClass The class to be used for the Servlet * @return The wrapper for the servlet */ public static Wrapper addServlet(Context ctx, String servletName, String servletClass) { // will do class for name and set init params Wrapper sw = ctx.createWrapper(); sw.setServletClass(servletClass); sw.setName(servletName); ctx.addChild(sw); return sw; } /** * Add an existing Servlet to the context with no class.forName or * initialisation. * @param contextPath Context to add Servlet to * @param servletName Servlet name (used in mappings) * @param servlet The Servlet to add * @return The wrapper for the servlet */ public Wrapper addServlet(String contextPath, String servletName, Servlet servlet) { Container ctx = getHost().findChild(contextPath); return addServlet((Context) ctx, servletName, servlet); } /** * Static version of {@link #addServlet(String, String, Servlet)}. * @param ctx Context to add Servlet to * @param servletName Servlet name (used in mappings) * @param servlet The Servlet to add * @return The wrapper for the servlet */ public static Wrapper addServlet(Context ctx, String servletName, Servlet servlet) { // will do class for name and set init params Wrapper sw = new ExistingStandardWrapper(servlet); sw.setName(servletName); ctx.addChild(sw); return sw; } /** * Initialise the server. * * @throws LifecycleException */ public void init() throws LifecycleException { getServer(); getConnector(); server.init(); } /** * Start the server. * * @throws LifecycleException */ public void start() throws LifecycleException { getServer(); getConnector(); server.start(); } /** * Stop the server. * * @throws LifecycleException */ public void stop() throws LifecycleException { getServer(); server.stop(); } /** * Destroy the server. This object cannot be used once this method has been * called. */ public void destroy() throws LifecycleException { getServer(); server.destroy(); // Could null out objects here } /** * Add a user for the in-memory realm. All created apps use this * by default, can be replaced using setRealm(). * */ public void addUser(String user, String pass) { userPass.put(user, pass); } /** * @see #addUser(String, String) */ public void addRole(String user, String role) { List roles = userRoles.get(user); if (roles == null) { roles = new ArrayList(); userRoles.put(user, roles); } roles.add(role); } // ------- Extra customization ------- // You can tune individual tomcat objects, using internal APIs /** * Get the default http connector. You can set more * parameters - the port is already initialized. * * Alternatively, you can construct a Connector and set any params, * then call addConnector(Connector) * * @return A connector object that can be customized */ public Connector getConnector() { getServer(); if (connector != null) { return connector; } // This will load Apr connector if available, // default to nio. I'm having strange problems with apr // XXX: jfclere weird... Don't add the AprLifecycleListener then. // and for the use case the speed benefit wouldn't matter. connector = new Connector("HTTP/1.1"); // connector = new Connector("org.apache.coyote.http11.Http11Protocol"); connector.setPort(port); service.addConnector( connector ); return connector; } public void setConnector(Connector connector) { this.connector = connector; } /** * Get the service object. Can be used to add more * connectors and few other global settings. */ public Service getService() { getServer(); return service; } /** * Sets the current host - all future webapps will * be added to this host. When tomcat starts, the * host will be the default host. * * @param host */ public void setHost(Host host) { this.host = host; } public Host getHost() { if (host == null) { host = new StandardHost(); host.setName(hostname); getEngine().addChild( host ); } return host; } /** * Set a custom realm for auth. If not called, a simple * default will be used, using an internal map. * * Must be called before adding a context. * * @deprecated Will be removed in Tomcat 8.0.x. */ @Deprecated public void setDefaultRealm(Realm realm) { defaultRealm = realm; } /** * Access to the engine, for further customization. */ public Engine getEngine() { if(engine == null ) { getServer(); engine = new StandardEngine(); engine.setName( "Tomcat" ); engine.setDefaultHost(hostname); if (defaultRealm == null) { initSimpleAuth(); } engine.setRealm(defaultRealm); service.setContainer(engine); } return engine; } /** * Get the server object. You can add listeners and few more * customizations. JNDI is disabled by default. */ public Server getServer() { if (server != null) { return server; } initBaseDir(); System.setProperty("catalina.useNaming", "false"); server = new StandardServer(); server.setPort( -1 ); service = new StandardService(); service.setName("Tomcat"); server.addService( service ); return server; } public Context addContext(Host host, String contextPath, String dir) { return addContext(host, contextPath, contextPath, dir); } public Context addContext(Host host, String contextPath, String contextName, String dir) { silence(host, contextPath); Context ctx = new StandardContext(); ctx.setName(contextName); ctx.setPath(contextPath); ctx.setDocBase(dir); ctx.addLifecycleListener(new FixContextListener()); if (host == null) { getHost().addChild(ctx); } else { host.addChild(ctx); } return ctx; } public Context addWebapp(Host host, String url, String path) { return addWebapp(host, url, url, path); } public Context addWebapp(Host host, String url, String name, String path) { silence(host, url); Context ctx = new StandardContext(); ctx.setName(name); ctx.setPath(url); ctx.setDocBase(path); ctx.addLifecycleListener(new DefaultWebXmlListener()); ctx.setConfigFile(getWebappConfigFile(path, url)); ContextConfig ctxCfg = new ContextConfig(); ctx.addLifecycleListener(ctxCfg); // prevent it from looking ( if it finds one - it'll have dup error ) ctxCfg.setDefaultWebXml(noDefaultWebXmlPath()); if (host == null) { getHost().addChild(ctx); } else { host.addChild(ctx); } return ctx; } /** * Return a listener that provides the required configuration items for JSP * processing. From the standard Tomcat global web.xml. Pass this to * {@link Context#addLifecycleListener(LifecycleListener)} and then pass the * result of {@link #noDefaultWebXmlPath()} to * {@link ContextConfig#setDefaultWebXml(String)}. * @return a listener object that configures default JSP processing. */ public LifecycleListener getDefaultWebXmlListener() { return new DefaultWebXmlListener(); } /** * @return a pathname to pass to * {@link ContextConfig#setDefaultWebXml(String)} when using * {@link #getDefaultWebXmlListener()}. */ public String noDefaultWebXmlPath() { return Constants.NoDefaultWebXml; } /** * For complex configurations, this accessor allows callers of this class * to obtain the simple realm created by default. * @return the simple in-memory realm created by default. * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated public Realm getDefaultRealm() { if (defaultRealm == null) { initSimpleAuth(); } return defaultRealm; } // ---------- Helper methods and classes ------------------- /** * Create an in-memory realm. You can replace it for contexts with a real * one. The Realm created here will be added to the Engine by default and * may be replaced at the Engine level or over-ridden (as per normal Tomcat * behaviour) at the Host or Context level. * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated protected void initSimpleAuth() { defaultRealm = new RealmBase() { @Override protected String getName() { return "Simple"; } @Override protected String getPassword(String username) { return userPass.get(username); } @Override protected Principal getPrincipal(String username) { Principal p = userPrincipals.get(username); if (p == null) { String pass = userPass.get(username); if (pass != null) { p = new GenericPrincipal(username, pass, userRoles.get(username)); userPrincipals.put(username, p); } } return p; } }; } protected void initBaseDir() { String catalinaHome = System.getProperty(Globals.CATALINA_HOME_PROP); if (basedir == null) { basedir = System.getProperty(Globals.CATALINA_BASE_PROP); } if (basedir == null) { basedir = catalinaHome; } if (basedir == null) { // Create a temp dir. basedir = System.getProperty("user.dir") + "/tomcat." + port; File home = new File(basedir); home.mkdir(); if (!home.isAbsolute()) { try { basedir = home.getCanonicalPath(); } catch (IOException e) { basedir = home.getAbsolutePath(); } } } if (catalinaHome == null) { System.setProperty(Globals.CATALINA_HOME_PROP, basedir); } System.setProperty(Globals.CATALINA_BASE_PROP, basedir); } static final String[] silences = new String[] { "org.apache.coyote.http11.Http11Protocol", "org.apache.catalina.core.StandardService", "org.apache.catalina.core.StandardEngine", "org.apache.catalina.startup.ContextConfig", "org.apache.catalina.core.ApplicationContext", "org.apache.catalina.core.AprLifecycleListener" }; /** * Controls if the loggers will be silenced or not. * @param silent true sets the log level to WARN for the * loggers that log information on Tomcat start up. This * prevents the usual startup information being logged. * false sets the log level to the default * level of INFO. */ public void setSilent(boolean silent) { for (String s : silences) { if (silent) { Logger.getLogger(s).setLevel(Level.WARNING); } else { Logger.getLogger(s).setLevel(Level.INFO); } } } private void silence(Host host, String ctx) { Logger.getLogger(getLoggerName(host, ctx)).setLevel(Level.WARNING); } private String getLoggerName(Host host, String ctx) { String loggerName = "org.apache.catalina.core.ContainerBase.[default].["; if (host == null) { loggerName += getHost().getName(); } else { loggerName += host.getName(); } loggerName += "].["; loggerName += ctx; loggerName += "]"; return loggerName; } /** * Enables JNDI naming which is disabled by default. Server must implement * {@link Lifecycle} in order for the {@link NamingContextListener} to be * used. * */ public void enableNaming() { // Make sure getServer() has been called as that is where naming is // disabled getServer(); server.addLifecycleListener(new NamingContextListener()); System.setProperty("catalina.useNaming", "true"); String value = "org.apache.naming"; String oldValue = System.getProperty(javax.naming.Context.URL_PKG_PREFIXES); if (oldValue != null) { if (oldValue.contains(value)) { value = oldValue; } else { value = value + ":" + oldValue; } } System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value); value = System.getProperty (javax.naming.Context.INITIAL_CONTEXT_FACTORY); if (value == null) { System.setProperty (javax.naming.Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory"); } } /** * Provide default configuration for a context. This is the programmatic * equivalent of the default web.xml. * * TODO: in normal Tomcat, if default-web.xml is not found, use this * method * * @param contextPath The context to set the defaults for */ public void initWebappDefaults(String contextPath) { Container ctx = getHost().findChild(contextPath); initWebappDefaults((Context) ctx); } /** * Static version of {@link #initWebappDefaults(String)} * @param ctx The context to set the defaults for */ public static void initWebappDefaults(Context ctx) { // Default servlet Wrapper servlet = addServlet( ctx, "default", "org.apache.catalina.servlets.DefaultServlet"); servlet.setLoadOnStartup(1); servlet.setOverridable(true); // JSP servlet (by class name - to avoid loading all deps) servlet = addServlet( ctx, "jsp", "org.apache.jasper.servlet.JspServlet"); servlet.addInitParameter("fork", "false"); servlet.setLoadOnStartup(3); servlet.setOverridable(true); // Servlet mappings ctx.addServletMapping("/", "default"); ctx.addServletMapping("*.jsp", "jsp"); ctx.addServletMapping("*.jspx", "jsp"); // Sessions ctx.setSessionTimeout(30); // MIME mappings for (int i = 0; i < DEFAULT_MIME_MAPPINGS.length;) { ctx.addMimeMapping(DEFAULT_MIME_MAPPINGS[i++], DEFAULT_MIME_MAPPINGS[i++]); } // Welcome files ctx.addWelcomeFile("index.html"); ctx.addWelcomeFile("index.htm"); ctx.addWelcomeFile("index.jsp"); } /** * Fix startup sequence - required if you don't use web.xml. * * The start() method in context will set 'configured' to false - and * expects a listener to set it back to true. */ public static class FixContextListener implements LifecycleListener { @Override public void lifecycleEvent(LifecycleEvent event) { try { Context context = (Context) event.getLifecycle(); if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { context.setConfigured(true); } // LoginConfig is required to process @ServletSecurity // annotations if (context.getLoginConfig() == null) { context.setLoginConfig( new LoginConfig("NONE", null, null, null)); context.getPipeline().addValve(new NonLoginAuthenticator()); } } catch (ClassCastException e) { return; } } } /** * Fix reload - required if reloading and using programmatic configuration. * When a context is reloaded, any programmatic configuration is lost. This * listener sets the equivalent of conf/web.xml when the context starts. */ public static class DefaultWebXmlListener implements LifecycleListener { @Override public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_START_EVENT.equals(event.getType())) { initWebappDefaults((Context) event.getLifecycle()); } } } /** * Helper class for wrapping existing servlets. This disables servlet * lifecycle and normal reloading, but also reduces overhead and provide * more direct control over the servlet. */ public static class ExistingStandardWrapper extends StandardWrapper { private final Servlet existing; @SuppressWarnings("deprecation") public ExistingStandardWrapper( Servlet existing ) { this.existing = existing; if (existing instanceof javax.servlet.SingleThreadModel) { singleThreadModel = true; instancePool = new Stack(); } } @Override public synchronized Servlet loadServlet() throws ServletException { if (singleThreadModel) { Servlet instance; try { instance = existing.getClass().newInstance(); } catch (InstantiationException e) { throw new ServletException(e); } catch (IllegalAccessException e) { throw new ServletException(e); } instance.init(facade); return instance; } else { if (!instanceInitialized) { existing.init(facade); instanceInitialized = true; } return existing; } } @Override public long getAvailable() { return 0; } @Override public boolean isUnavailable() { return false; } @Override public Servlet getServlet() { return existing; } @Override public String getServletClass() { return existing.getClass().getName(); } } /** * TODO: would a properties resource be better ? Or just parsing * /etc/mime.types ? * This is needed because we don't use the default web.xml, where this * is encoded. */ private static final String[] DEFAULT_MIME_MAPPINGS = { "abs", "audio/x-mpeg", "ai", "application/postscript", "aif", "audio/x-aiff", "aifc", "audio/x-aiff", "aiff", "audio/x-aiff", "aim", "application/x-aim", "art", "image/x-jg", "asf", "video/x-ms-asf", "asx", "video/x-ms-asf", "au", "audio/basic", "avi", "video/x-msvideo", "avx", "video/x-rad-screenplay", "bcpio", "application/x-bcpio", "bin", "application/octet-stream", "bmp", "image/bmp", "body", "text/html", "cdf", "application/x-cdf", "cer", "application/pkix-cert", "class", "application/java", "cpio", "application/x-cpio", "csh", "application/x-csh", "css", "text/css", "dib", "image/bmp", "doc", "application/msword", "dtd", "application/xml-dtd", "dv", "video/x-dv", "dvi", "application/x-dvi", "eps", "application/postscript", "etx", "text/x-setext", "exe", "application/octet-stream", "gif", "image/gif", "gtar", "application/x-gtar", "gz", "application/x-gzip", "hdf", "application/x-hdf", "hqx", "application/mac-binhex40", "htc", "text/x-component", "htm", "text/html", "html", "text/html", "ief", "image/ief", "jad", "text/vnd.sun.j2me.app-descriptor", "jar", "application/java-archive", "java", "text/x-java-source", "jnlp", "application/x-java-jnlp-file", "jpe", "image/jpeg", "jpeg", "image/jpeg", "jpg", "image/jpeg", "js", "application/javascript", "jsf", "text/plain", "jspf", "text/plain", "kar", "audio/midi", "latex", "application/x-latex", "m3u", "audio/x-mpegurl", "mac", "image/x-macpaint", "man", "text/troff", "mathml", "application/mathml+xml", "me", "text/troff", "mid", "audio/midi", "midi", "audio/midi", "mif", "application/x-mif", "mov", "video/quicktime", "movie", "video/x-sgi-movie", "mp1", "audio/mpeg", "mp2", "audio/mpeg", "mp3", "audio/mpeg", "mp4", "video/mp4", "mpa", "audio/mpeg", "mpe", "video/mpeg", "mpeg", "video/mpeg", "mpega", "audio/x-mpeg", "mpg", "video/mpeg", "mpv2", "video/mpeg2", "nc", "application/x-netcdf", "oda", "application/oda", "odb", "application/vnd.oasis.opendocument.database", "odc", "application/vnd.oasis.opendocument.chart", "odf", "application/vnd.oasis.opendocument.formula", "odg", "application/vnd.oasis.opendocument.graphics", "odi", "application/vnd.oasis.opendocument.image", "odm", "application/vnd.oasis.opendocument.text-master", "odp", "application/vnd.oasis.opendocument.presentation", "ods", "application/vnd.oasis.opendocument.spreadsheet", "odt", "application/vnd.oasis.opendocument.text", "otg", "application/vnd.oasis.opendocument.graphics-template", "oth", "application/vnd.oasis.opendocument.text-web", "otp", "application/vnd.oasis.opendocument.presentation-template", "ots", "application/vnd.oasis.opendocument.spreadsheet-template ", "ott", "application/vnd.oasis.opendocument.text-template", "ogx", "application/ogg", "ogv", "video/ogg", "oga", "audio/ogg", "ogg", "audio/ogg", "spx", "audio/ogg", "flac", "audio/flac", "anx", "application/annodex", "axa", "audio/annodex", "axv", "video/annodex", "xspf", "application/xspf+xml", "pbm", "image/x-portable-bitmap", "pct", "image/pict", "pdf", "application/pdf", "pgm", "image/x-portable-graymap", "pic", "image/pict", "pict", "image/pict", "pls", "audio/x-scpls", "png", "image/png", "pnm", "image/x-portable-anymap", "pnt", "image/x-macpaint", "ppm", "image/x-portable-pixmap", "ppt", "application/vnd.ms-powerpoint", "pps", "application/vnd.ms-powerpoint", "ps", "application/postscript", "psd", "image/vnd.adobe.photoshop", "qt", "video/quicktime", "qti", "image/x-quicktime", "qtif", "image/x-quicktime", "ras", "image/x-cmu-raster", "rdf", "application/rdf+xml", "rgb", "image/x-rgb", "rm", "application/vnd.rn-realmedia", "roff", "text/troff", "rtf", "application/rtf", "rtx", "text/richtext", "sh", "application/x-sh", "shar", "application/x-shar", /*"shtml", "text/x-server-parsed-html",*/ "sit", "application/x-stuffit", "snd", "audio/basic", "src", "application/x-wais-source", "sv4cpio", "application/x-sv4cpio", "sv4crc", "application/x-sv4crc", "svg", "image/svg+xml", "svgz", "image/svg+xml", "swf", "application/x-shockwave-flash", "t", "text/troff", "tar", "application/x-tar", "tcl", "application/x-tcl", "tex", "application/x-tex", "texi", "application/x-texinfo", "texinfo", "application/x-texinfo", "tif", "image/tiff", "tiff", "image/tiff", "tr", "text/troff", "tsv", "text/tab-separated-values", "txt", "text/plain", "ulw", "audio/basic", "ustar", "application/x-ustar", "vxml", "application/voicexml+xml", "xbm", "image/x-xbitmap", "xht", "application/xhtml+xml", "xhtml", "application/xhtml+xml", "xls", "application/vnd.ms-excel", "xml", "application/xml", "xpm", "image/x-xpixmap", "xsl", "application/xml", "xslt", "application/xslt+xml", "xul", "application/vnd.mozilla.xul+xml", "xwd", "image/x-xwindowdump", "vsd", "application/vnd.visio", "wav", "audio/x-wav", "wbmp", "image/vnd.wap.wbmp", "wml", "text/vnd.wap.wml", "wmlc", "application/vnd.wap.wmlc", "wmls", "text/vnd.wap.wmlsc", "wmlscriptc", "application/vnd.wap.wmlscriptc", "wmv", "video/x-ms-wmv", "wrl", "model/vrml", "wspolicy", "application/wspolicy+xml", "Z", "application/x-compress", "z", "application/x-compress", "zip", "application/zip" }; protected URL getWebappConfigFile(String path, String url) { File docBase = new File(path); if (docBase.isDirectory()) { return getWebappConfigFileFromDirectory(docBase, url); } else { return getWebappConfigFileFromJar(docBase, url); } } private URL getWebappConfigFileFromDirectory(File docBase, String url) { URL result = null; File webAppContextXml = new File(docBase, Constants.ApplicationContextXml); if (webAppContextXml.exists()) { try { result = webAppContextXml.toURI().toURL(); } catch (MalformedURLException e) { Logger.getLogger(getLoggerName(getHost(), url)).log(Level.WARNING, "Unable to determine web application context.xml " + docBase, e); } } return result; } private URL getWebappConfigFileFromJar(File docBase, String url) { URL result = null; JarFile jar = null; try { jar = new JarFile(docBase); JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml); if (entry != null) { result = new URL("jar:" + docBase.toURI().toString() + "!/" + Constants.ApplicationContextXml); } } catch (IOException e) { Logger.getLogger(getLoggerName(getHost(), url)).log(Level.WARNING, "Unable to determine web application context.xml " + docBase, e); } finally { if (jar != null) { try { jar.close(); } catch (IOException e) { // ignore } } } return result; } } tomcat7-7.0.52/java/org/apache/catalina/startup/Authenticators.properties0000644000175100017510000000216712271471332026475 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. BASIC=org.apache.catalina.authenticator.BasicAuthenticator CLIENT-CERT=org.apache.catalina.authenticator.SSLAuthenticator DIGEST=org.apache.catalina.authenticator.DigestAuthenticator FORM=org.apache.catalina.authenticator.FormAuthenticator NONE=org.apache.catalina.authenticator.NonLoginAuthenticator SPNEGO=org.apache.catalina.authenticator.SpnegoAuthenticatortomcat7-7.0.52/java/org/apache/catalina/startup/RealmRuleSet.java0000644000175100017510000000676612271471332024602 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSetBase; /** *

    RuleSet for processing the contents of a Realm definition * element. This RuleSet supports Realms such as the * CombinedRealm that used nested Realms.

    */ public class RealmRuleSet extends RuleSetBase { private static final int MAX_NESTED_REALM_LEVELS = Integer.getInteger( "org.apache.catalina.startup.RealmRuleSet.MAX_NESTED_REALM_LEVELS", 3).intValue(); // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public RealmRuleSet() { this(""); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public RealmRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { String pattern = prefix; for (int i = 0; i < MAX_NESTED_REALM_LEVELS; i++) { if (i > 0) { pattern += "/"; } pattern += "Realm"; digester.addObjectCreate(pattern, null, // MUST be specified in the element, "className"); digester.addSetProperties(pattern); if (i == 0) { digester.addSetNext(pattern, "setRealm", "org.apache.catalina.Realm"); } else { digester.addSetNext(pattern, "addRealm", "org.apache.catalina.Realm"); } } } } tomcat7-7.0.52/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java0000644000175100017510000000453212271471332027254 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.lang.reflect.Method; import org.apache.catalina.Container; import org.apache.tomcat.util.digester.Rule; import org.xml.sax.Attributes; /** *

    Rule that copies the parentClassLoader property from the * next-to-top item on the stack (which must be a Container) * to the top item on the stack (which must also be a * Container).

    * * @author Craig R. McClanahan */ public class CopyParentClassLoaderRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a new instance of this Rule. */ public CopyParentClassLoaderRule() { } // --------------------------------------------------------- Public Methods /** * Handle the beginning of an XML element. * * @param attributes The attributes of this element * * @exception Exception if a processing error occurs */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (digester.getLogger().isDebugEnabled()) digester.getLogger().debug("Copying parent class loader"); Container child = (Container) digester.peek(0); Object parent = digester.peek(1); Method method = parent.getClass().getMethod("getParentClassLoader", new Class[0]); ClassLoader classLoader = (ClassLoader) method.invoke(parent, new Object[0]); child.setParentClassLoader(classLoader); } } tomcat7-7.0.52/java/org/apache/catalina/startup/TldRuleSet.java0000644000175100017510000001237512271471332024256 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.Rule; import org.apache.tomcat.util.digester.RuleSetBase; /** *

    RuleSet for processing the contents of a tag library * descriptor resource.

    * * @author Craig R. McClanahan */ public class TldRuleSet extends RuleSetBase { // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public TldRuleSet() { this(""); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public TldRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { // Note the sharing of state between rules TaglibUriRule taglibUriRule = new TaglibUriRule(); digester.addRule(prefix + "taglib", new TaglibRule(taglibUriRule)); digester.addRule(prefix + "taglib/uri", taglibUriRule); digester.addRule(prefix + "taglib/listener/listener-class", new TaglibListenerRule(taglibUriRule)); } } /* * This rule only exists to reset the duplicateUri flag on the TaglibUriRule. */ final class TaglibRule extends Rule { private final TaglibUriRule taglibUriRule; public TaglibRule(TaglibUriRule taglibUriRule) { this.taglibUriRule = taglibUriRule; } @Override public void body(String namespace, String name, String text) throws Exception { taglibUriRule.setDuplicateUri(false); } } final class TaglibUriRule extends Rule { // This is set to false for each file processed by the TaglibRule private boolean duplicateUri; public TaglibUriRule() { } @Override public void body(String namespace, String name, String text) throws Exception { TldConfig tldConfig = (TldConfig) digester.peek(digester.getCount() - 1); if (tldConfig.isKnownTaglibUri(text)) { // Already seen this URI duplicateUri = true; // This is expected if the URI was defined in web.xml // Log message at debug in this case if (tldConfig.isKnownWebxmlTaglibUri(text)) { if (digester.getLogger().isDebugEnabled()) { digester.getLogger().debug( "TLD skipped. URI: " + text + " is already defined"); } } else { digester.getLogger().info( "TLD skipped. URI: " + text + " is already defined"); } } else { // New URI. Add it to known list and carry on tldConfig.addTaglibUri(text); } } public boolean isDuplicateUri() { return duplicateUri; } public void setDuplicateUri(boolean duplciateUri) { this.duplicateUri = duplciateUri; } } final class TaglibListenerRule extends Rule { private final TaglibUriRule taglibUriRule; public TaglibListenerRule(TaglibUriRule taglibUriRule) { this.taglibUriRule = taglibUriRule; } @Override public void body(String namespace, String name, String text) throws Exception { TldConfig tldConfig = (TldConfig) digester.peek(digester.getCount() - 1); // Only process the listener if the URI is not a duplicate if (!taglibUriRule.isDuplicateUri()) { tldConfig.addApplicationListener(text.trim()); } } }tomcat7-7.0.52/java/org/apache/catalina/startup/DigesterFactory.java0000644000175100017510000001672512271471332025330 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.net.URL; import org.apache.catalina.util.SchemaResolver; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSet; /** * Wrapper class around the Digester that hide Digester's initialization details * * @author Jean-Francois Arcand * * @deprecated Use {@link org.apache.tomcat.util.descriptor.DigesterFactory} */ @Deprecated public class DigesterFactory { /** * The log. */ private static final Log log = LogFactory.getLog(DigesterFactory.class); /** * Create a Digester parser with no Rule * associated and XML validation turned off. * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static Digester newDigester(){ return newDigester(false, false, null); } /** * Create a Digester parser with XML validation turned off. * @param rule an instance of RuleSet used for parsing the xml. * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public static Digester newDigester(RuleSet rule){ return newDigester(false,false,rule); } /** * Create a Digester parser. * @param xmlValidation turn on/off xml validation * @param xmlNamespaceAware turn on/off namespace validation * @param rule an instance of RuleSet used for parsing the xml. */ public static Digester newDigester(boolean xmlValidation, boolean xmlNamespaceAware, RuleSet rule) { Digester digester = new Digester(); digester.setNamespaceAware(xmlNamespaceAware); digester.setValidating(xmlValidation); digester.setUseContextClassLoader(true); SchemaResolver schemaResolver = new SchemaResolver(digester); registerLocalSchema(schemaResolver); digester.setEntityResolver(schemaResolver); if ( rule != null ) { digester.addRuleSet(rule); } return (digester); } /** * Utilities used to force the parser to use local schema, when available, * instead of the schemaLocation XML element. */ protected static void registerLocalSchema(SchemaResolver schemaResolver){ // J2EE register(Constants.J2eeSchemaResourcePath_14, Constants.J2eeSchemaPublicId_14, schemaResolver); register(Constants.JavaeeSchemaResourcePath_5, Constants.JavaeeSchemaPublicId_5, schemaResolver); register(Constants.JavaeeSchemaResourcePath_6, Constants.JavaeeSchemaPublicId_6, schemaResolver); // W3C register(Constants.W3cSchemaResourcePath_10, Constants.W3cSchemaPublicId_10, schemaResolver); register(Constants.W3cSchemaDTDResourcePath_10, Constants.W3cSchemaDTDPublicId_10, schemaResolver); register(Constants.W3cDatatypesDTDResourcePath_10, Constants.W3cDatatypesDTDPublicId_10, schemaResolver); // JSP register(Constants.JspSchemaResourcePath_20, Constants.JspSchemaPublicId_20, schemaResolver); register(Constants.JspSchemaResourcePath_21, Constants.JspSchemaPublicId_21, schemaResolver); register(Constants.JspSchemaResourcePath_22, Constants.JspSchemaPublicId_22, schemaResolver); // TLD register(Constants.TldDtdResourcePath_11, Constants.TldDtdPublicId_11, schemaResolver); register(Constants.TldDtdResourcePath_12, Constants.TldDtdPublicId_12, schemaResolver); register(Constants.TldSchemaResourcePath_20, Constants.TldSchemaPublicId_20, schemaResolver); register(Constants.TldSchemaResourcePath_21, Constants.TldSchemaPublicId_21, schemaResolver); // web.xml register(Constants.WebDtdResourcePath_22, Constants.WebDtdPublicId_22, schemaResolver); register(Constants.WebDtdResourcePath_23, Constants.WebDtdPublicId_23, schemaResolver); register(Constants.WebSchemaResourcePath_24, Constants.WebSchemaPublicId_24, schemaResolver); register(Constants.WebSchemaResourcePath_25, Constants.WebSchemaPublicId_25, schemaResolver); register(Constants.WebSchemaResourcePath_30, Constants.WebSchemaPublicId_30, schemaResolver); register(Constants.WebCommonSchemaResourcePath_30, Constants.WebCommonSchemaPublicId_30, schemaResolver); register(Constants.WebFragmentSchemaResourcePath_30, Constants.WebFragmentSchemaPublicId_30, schemaResolver); // Web Service register(Constants.J2eeWebServiceSchemaResourcePath_11, Constants.J2eeWebServiceSchemaPublicId_11, schemaResolver); register(Constants.J2eeWebServiceClientSchemaResourcePath_11, Constants.J2eeWebServiceClientSchemaPublicId_11, schemaResolver); register(Constants.JavaeeWebServiceSchemaResourcePath_12, Constants.JavaeeWebServiceSchemaPublicId_12, schemaResolver); register(Constants.JavaeeWebServiceClientSchemaResourcePath_12, Constants.JavaeeWebServiceClientSchemaPublicId_12, schemaResolver); register(Constants.JavaeeWebServiceSchemaResourcePath_13, Constants.JavaeeWebServiceSchemaPublicId_13, schemaResolver); register(Constants.JavaeeWebServiceClientSchemaResourcePath_13, Constants.JavaeeWebServiceClientSchemaPublicId_13, schemaResolver); } /** * Load the resource and add it to the resolver. */ protected static void register(String resourceURL, String resourcePublicId, SchemaResolver schemaResolver){ URL url = DigesterFactory.class.getResource(resourceURL); if(url == null) { log.warn("Could not get url for " + resourceURL); } else { schemaResolver.register(resourcePublicId , url.toString() ); } } } tomcat7-7.0.52/java/org/apache/catalina/startup/PasswdUserDatabase.java0000644000175100017510000001167312271471332025754 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; /** * Concrete implementation of the UserDatabase
    interface * that processes the /etc/passwd file on a Unix system. * * @author Craig R. McClanahan */ public final class PasswdUserDatabase implements UserDatabase { // --------------------------------------------------------- Constructors /** * Initialize a new instance of this user database component. */ public PasswdUserDatabase() { super(); } // --------------------------------------------------- Instance Variables /** * The pathname of the Unix password file. */ private static final String PASSWORD_FILE = "/etc/passwd"; /** * The set of home directories for all defined users, keyed by username. */ private Hashtable homes = new Hashtable(); /** * The UserConfig listener with which we are associated. */ private UserConfig userConfig = null; // ----------------------------------------------------------- Properties /** * Return the UserConfig listener with which we are associated. */ @Override public UserConfig getUserConfig() { return (this.userConfig); } /** * Set the UserConfig listener with which we are associated. * * @param userConfig The new UserConfig listener */ @Override public void setUserConfig(UserConfig userConfig) { this.userConfig = userConfig; init(); } // ------------------------------------------------------- Public Methods /** * Return an absolute pathname to the home directory for the specified user. * * @param user User for which a home directory should be retrieved */ @Override public String getHome(String user) { return homes.get(user); } /** * Return an enumeration of the usernames defined on this server. */ @Override public Enumeration getUsers() { return (homes.keys()); } // ------------------------------------------------------ Private Methods /** * Initialize our set of users and home directories. */ private void init() { BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(PASSWORD_FILE)); while (true) { // Accumulate the next line StringBuilder buffer = new StringBuilder(); while (true) { int ch = reader.read(); if ((ch < 0) || (ch == '\n')) break; buffer.append((char) ch); } String line = buffer.toString(); if (line.length() < 1) break; // Parse the line into constituent elements int n = 0; String tokens[] = new String[7]; for (int i = 0; i < tokens.length; i++) tokens[i] = null; while (n < tokens.length) { String token = null; int colon = line.indexOf(':'); if (colon >= 0) { token = line.substring(0, colon); line = line.substring(colon + 1); } else { token = line; line = ""; } tokens[n++] = token; } // Add this user and corresponding directory if ((tokens[0] != null) && (tokens[5] != null)) homes.put(tokens[0], tokens[5]); } reader.close(); reader = null; } catch (Exception e) { if (reader != null) { try { reader.close(); } catch (IOException f) { // Ignore } reader = null; } } } } tomcat7-7.0.52/java/org/apache/catalina/startup/EngineConfig.java0000644000175100017510000000605012271471332024553 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.catalina.Engine; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * Startup event listener for a Engine that configures the properties * of that Engine, and the associated defined contexts. * * @author Craig R. McClanahan */ public class EngineConfig implements LifecycleListener { private static final Log log = LogFactory.getLog( EngineConfig.class ); // ----------------------------------------------------- Instance Variables /** * The Engine we are associated with. */ protected Engine engine = null; /** * The string resources for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // --------------------------------------------------------- Public Methods /** * Process the START event for an associated Engine. * * @param event The lifecycle event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { // Identify the engine we are associated with try { engine = (Engine) event.getLifecycle(); } catch (ClassCastException e) { log.error(sm.getString("engineConfig.cce", event.getLifecycle()), e); return; } // Process the event that has occurred if (event.getType().equals(Lifecycle.START_EVENT)) start(); else if (event.getType().equals(Lifecycle.STOP_EVENT)) stop(); } // -------------------------------------------------------- Protected Methods /** * Process a "start" event for this Engine. */ protected void start() { if (engine.getLogger().isDebugEnabled()) engine.getLogger().debug(sm.getString("engineConfig.start")); } /** * Process a "stop" event for this Engine. */ protected void stop() { if (engine.getLogger().isDebugEnabled()) engine.getLogger().debug(sm.getString("engineConfig.stop")); } } tomcat7-7.0.52/java/org/apache/catalina/startup/UserConfig.java0000644000175100017510000002671412271471332024275 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.regex.Pattern; import org.apache.catalina.Context; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.tomcat.util.res.StringManager; /** * Startup event listener for a Host that configures Contexts (web * applications) for all defined "users" who have a web application in a * directory with the specified name in their home directories. The context * path of each deployed application will be set to ~xxxxx, where * xxxxx is the username of the owning user for that web application * * @author Craig R. McClanahan */ public final class UserConfig implements LifecycleListener { private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( UserConfig.class ); // ----------------------------------------------------- Instance Variables /** * The Java class name of the Context configuration class we should use. */ private String configClass = "org.apache.catalina.startup.ContextConfig"; /** * The Java class name of the Context implementation we should use. */ private String contextClass = "org.apache.catalina.core.StandardContext"; /** * The directory name to be searched for within each user home directory. */ private String directoryName = "public_html"; /** * The base directory containing user home directories. */ private String homeBase = null; /** * The Host we are associated with. */ private Host host = null; /** * The string resources for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The Java class name of the user database class we should use. */ private String userClass = "org.apache.catalina.startup.PasswdUserDatabase"; /** * A regular expression defining user who deployment is allowed. */ protected Pattern allow = null; /** * A regular expression defining user who deployment is denied. */ protected Pattern deny = null; // ------------------------------------------------------------- Properties /** * Return the Context configuration class name. */ public String getConfigClass() { return (this.configClass); } /** * Set the Context configuration class name. * * @param configClass The new Context configuration class name. */ public void setConfigClass(String configClass) { this.configClass = configClass; } /** * Return the Context implementation class name. */ public String getContextClass() { return (this.contextClass); } /** * Set the Context implementation class name. * * @param contextClass The new Context implementation class name. */ public void setContextClass(String contextClass) { this.contextClass = contextClass; } /** * Return the directory name for user web applications. */ public String getDirectoryName() { return (this.directoryName); } /** * Set the directory name for user web applications. * * @param directoryName The new directory name */ public void setDirectoryName(String directoryName) { this.directoryName = directoryName; } /** * Return the base directory containing user home directories. */ public String getHomeBase() { return (this.homeBase); } /** * Set the base directory containing user home directories. * * @param homeBase The new base directory */ public void setHomeBase(String homeBase) { this.homeBase = homeBase; } /** * Return the user database class name for this component. */ public String getUserClass() { return (this.userClass); } /** * Set the user database class name for this component. */ public void setUserClass(String userClass) { this.userClass = userClass; } /** * Return the regular expression used to test for user who deployment is allowed. */ public String getAllow() { if (allow == null) return null; return allow.toString(); } /** * Set the regular expression used to test for user who deployment is allowed. * * @param allow The new allow expression */ public void setAllow(String allow) { if (allow == null || allow.length() == 0) { this.allow = null; } else { this.allow = Pattern.compile(allow); } } /** * Return the regular expression used to test for user who deployment is denied. */ public String getDeny() { if (deny == null) return null; return deny.toString(); } /** * Set the regular expression used to test for user who deployment is denied. * * @param deny The new deny expression */ public void setDeny(String deny) { if (deny == null || deny.length() == 0) { this.deny = null; } else { this.deny = Pattern.compile(deny); } } // --------------------------------------------------------- Public Methods /** * Process the START event for an associated Host. * * @param event The lifecycle event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { // Identify the host we are associated with try { host = (Host) event.getLifecycle(); } catch (ClassCastException e) { log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); return; } // Process the event that has occurred if (event.getType().equals(Lifecycle.START_EVENT)) start(); else if (event.getType().equals(Lifecycle.STOP_EVENT)) stop(); } // -------------------------------------------------------- Private Methods /** * Deploy a web application for any user who has a web application present * in a directory with a specified name within their home directory. */ private void deploy() { if (host.getLogger().isDebugEnabled()) host.getLogger().debug(sm.getString("userConfig.deploying")); // Load the user database object for this host UserDatabase database = null; try { Class clazz = Class.forName(userClass); database = (UserDatabase) clazz.newInstance(); database.setUserConfig(this); } catch (Exception e) { host.getLogger().error(sm.getString("userConfig.database"), e); return; } ExecutorService executor = host.getStartStopExecutor(); List> results = new ArrayList>(); // Deploy the web application (if any) for each defined user Enumeration users = database.getUsers(); while (users.hasMoreElements()) { String user = users.nextElement(); if (!isDeployAllowed(user)) continue; String home = database.getHome(user); results.add(executor.submit(new DeployUserDirectory(this, user, home))); } for (Future result : results) { try { result.get(); } catch (Exception e) { host.getLogger().error(sm.getString("userConfig.deploy.threaded.error"), e); } } } /** * Deploy a web application for the specified user if they have such an * application in the defined directory within their home directory. * * @param user Username owning the application to be deployed * @param home Home directory of this user */ private void deploy(String user, String home) { // Does this user have a web application to be deployed? String contextPath = "/~" + user; if (host.findChild(contextPath) != null) return; File app = new File(home, directoryName); if (!app.exists() || !app.isDirectory()) return; /* File dd = new File(app, "/WEB-INF/web.xml"); if (!dd.exists() || !dd.isFile() || !dd.canRead()) return; */ host.getLogger().info(sm.getString("userConfig.deploy", user)); // Deploy the web application for this user try { Class clazz = Class.forName(contextClass); Context context = (Context) clazz.newInstance(); context.setPath(contextPath); context.setDocBase(app.toString()); clazz = Class.forName(configClass); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); context.addLifecycleListener(listener); host.addChild(context); } catch (Exception e) { host.getLogger().error(sm.getString("userConfig.error", user), e); } } /** * Process a "start" event for this Host. */ private void start() { if (host.getLogger().isDebugEnabled()) host.getLogger().debug(sm.getString("userConfig.start")); deploy(); } /** * Process a "stop" event for this Host. */ private void stop() { if (host.getLogger().isDebugEnabled()) host.getLogger().debug(sm.getString("userConfig.stop")); } /** * Test allow and deny rules for the provided user. * * @return true if this user is allowed to deploy, * false otherwise */ private boolean isDeployAllowed(String user) { if (deny != null && deny.matcher(user).matches()) { return false; } if (allow != null) { if (allow.matcher(user).matches()) { return true; } else { return false; } } return true; } private static class DeployUserDirectory implements Runnable { private UserConfig config; private String user; private String home; public DeployUserDirectory(UserConfig config, String user, String home) { this.config = config; this.user = user; this.home= home; } @Override public void run() { config.deploy(user, home); } } } tomcat7-7.0.52/java/org/apache/catalina/startup/TldConfig.java0000644000175100017510000004741012271471332024076 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.StringTokenizer; import javax.servlet.ServletContext; import javax.servlet.descriptor.TaglibDescriptor; import org.apache.catalina.Context; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.core.StandardContext; import org.apache.catalina.deploy.ApplicationListener; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.descriptor.DigesterFactory; import org.apache.tomcat.util.descriptor.XmlErrorHandler; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.scan.Jar; import org.apache.tomcat.util.scan.JarFactory; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Startup event listener for a Context that configures application * listeners configured in any TLD files. * * @author Craig R. McClanahan * @author Jean-Francois Arcand * @author Costin Manolache */ public final class TldConfig implements LifecycleListener { private static final String TLD_EXT = ".tld"; private static final String WEB_INF = "/WEB-INF/"; private static final String WEB_INF_LIB = "/WEB-INF/lib/"; // Names of JARs that are known not to contain any TLDs private static volatile Set noTldJars = null; private static final org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( TldConfig.class ); /** * The string resources for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The Digesters available to process tld files. */ private static Digester[] tldDigesters = new Digester[2]; /** * Create (if necessary) and return a Digester configured to process the * tld. */ private static Digester createTldDigester(boolean validation, boolean blockExternal) { Digester digester = null; if (!validation) { if (tldDigesters[0] == null) { tldDigesters[0] = DigesterFactory.newDigester(validation, true, new TldRuleSet(), blockExternal); tldDigesters[0].getParser(); } digester = tldDigesters[0]; } else { if (tldDigesters[1] == null) { tldDigesters[1] = DigesterFactory.newDigester(validation, true, new TldRuleSet(), blockExternal); tldDigesters[1].getParser(); } digester = tldDigesters[1]; } return digester; } static { // Set the default list of JARs to skip for TLDs StringBuilder jarList = new StringBuilder(System.getProperty( Constants.DEFAULT_JARS_TO_SKIP, "")); String tldJars = System.getProperty(Constants.TLD_JARS_TO_SKIP, ""); if (tldJars.length() > 0) { if (jarList.length() > 0) { jarList.append(','); } jarList.append(tldJars); } if (jarList.length() > 0) { setNoTldJars(jarList.toString()); } } /** * Sets the list of JARs that are known not to contain any TLDs. * * @param jarNames List of comma-separated names of JAR files that are * known not to contain any TLDs. */ public static synchronized void setNoTldJars(String jarNames) { if (jarNames == null) { noTldJars = null; } else { if (noTldJars == null) { noTldJars = new HashSet(); } else { noTldJars.clear(); } StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); while (tokenizer.hasMoreElements()) { noTldJars.add(tokenizer.nextToken()); } } } // ----------------------------------------------------- Instance Variables /** * The Context we are associated with. */ private Context context = null; /** * The Digester we will use to process tag library * descriptor files. */ private Digester tldDigester = null; /** * Set of URIs discovered for the associated context. Used to enforce the * correct processing priority. Only the TLD associated with the first * instance of any URI will be processed. */ private Set taglibUris = new HashSet(); private Set webxmlTaglibUris = new HashSet(); private ArrayList listeners = new ArrayList(); // --------------------------------------------------------- Public Methods /** * Adds a taglib URI to the list of known URIs. */ public void addTaglibUri(String uri) { taglibUris.add(uri); } /** * Determines if the provided URI is a known taglib URI. */ public boolean isKnownTaglibUri(String uri) { return taglibUris.contains(uri); } /** * Determines if the provided URI is a known taglib URI. */ public boolean isKnownWebxmlTaglibUri(String uri) { return webxmlTaglibUris.contains(uri); } /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public Context getContext() { return context; } /** * @deprecated Unused - will be removed in 8.0.x */ @Deprecated public void setContext(Context context) { this.context = context; } public void addApplicationListener( String s ) { if(log.isDebugEnabled()) log.debug( "Add tld listener " + s); listeners.add(s); } public String[] getTldListeners() { String result[]=new String[listeners.size()]; listeners.toArray(result); return result; } /** * Scan for and configure all tag library descriptors found in this * web application. * * This supports a Tomcat-specific extension to the TLD search * order defined in the JSP spec. It allows tag libraries packaged as JAR * files to be shared by web applications by simply dropping them in a * location that all web applications have access to (e.g., * /lib). It also supports some of the weird and * wonderful arrangements present when Tomcat gets embedded. * * The set of shared JARs to be scanned for TLDs is narrowed down by * the noTldJars class variable, which contains the names of JARs * that are known not to contain any TLDs. */ public void execute() { long t1=System.currentTimeMillis(); /* * Priority order of URIs required by spec is: * 1. J2EE platform taglibs - Tomcat doesn't provide these * 2. web.xml entries * 3. JARS in WEB-INF/lib & TLDs under WEB-INF (equal priority) * 4. Additional entries from the container * * Keep processing order in sync with o.a.j.compiler.TldLocationsCache */ // Stage 2 - web.xml entries tldScanWebXml(); // Stage 3a - TLDs under WEB-INF (not lib or classes) tldScanResourcePaths(WEB_INF); // Stages 3b & 4 JarScanner jarScanner = context.getJarScanner(); jarScanner.scan(context.getServletContext(), context.getLoader().getClassLoader(), new TldJarScannerCallback(), noTldJars); // Now add all the listeners we found to the listeners for this context String list[] = getTldListeners(); if( log.isDebugEnabled() ) log.debug(sm.getString("tldConfig.addListeners", Integer.valueOf(list.length))); for( int i=0; list!=null && i descriptors = context.getJspConfigDescriptor().getTaglibs(); for (TaglibDescriptor descriptor : descriptors) { String resourcePath = descriptor.getTaglibLocation(); // Note: Whilst the Servlet 2.4 DTD implies that the location must // be a context-relative path starting with '/', JSP.7.3.6.1 states // explicitly how paths that do not start with '/' should be // handled. if (!resourcePath.startsWith("/")) { resourcePath = WEB_INF + resourcePath; } if (taglibUris.contains(descriptor.getTaglibURI())) { log.warn(sm.getString("tldConfig.webxmlSkip", resourcePath, descriptor.getTaglibURI())); } else { if (log.isTraceEnabled()) { log.trace(sm.getString("tldConfig.webxmlAdd", resourcePath, descriptor.getTaglibURI())); } InputStream stream = null; try { stream = context.getServletContext().getResourceAsStream( resourcePath); if (stream != null) { XmlErrorHandler handler = tldScanStream(stream); handler.logFindings(log, resourcePath); taglibUris.add(descriptor.getTaglibURI()); webxmlTaglibUris.add(descriptor.getTaglibURI()); } else { log.warn(sm.getString("tldConfig.webxmlFailPathDoesNotExist", resourcePath, descriptor.getTaglibURI())); } } catch (IOException ioe) { log.warn(sm.getString("tldConfig.webxmlFail", resourcePath, descriptor.getTaglibURI()), ioe); } finally { if (stream != null) { try { stream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } } } } /* * Scans the web application's sub-directory identified by startPath, * along with its sub-directories, for TLDs. * * Initially, rootPath equals /WEB-INF/. The /WEB-INF/classes and * /WEB-INF/lib sub-directories are excluded from the search, as per the * JSP 2.0 spec. * * Keep in sync with o.a.j.comiler.TldLocationsCache */ private void tldScanResourcePaths(String startPath) { if (log.isTraceEnabled()) { log.trace(sm.getString("tldConfig.webinfScan", startPath)); } ServletContext ctxt = context.getServletContext(); Set dirList = ctxt.getResourcePaths(startPath); if (dirList != null) { Iterator it = dirList.iterator(); while (it.hasNext()) { String path = it.next(); if (!path.endsWith(TLD_EXT) && (path.startsWith(WEB_INF_LIB) || path.startsWith("/WEB-INF/classes/"))) { continue; } if (path.endsWith(TLD_EXT)) { if (path.startsWith("/WEB-INF/tags/") && !path.endsWith("implicit.tld")) { continue; } InputStream stream = ctxt.getResourceAsStream(path); try { XmlErrorHandler handler = tldScanStream(stream); handler.logFindings(log, path); } catch (IOException ioe) { log.warn(sm.getString("tldConfig.webinfFail", path), ioe); } finally { if (stream != null) { try { stream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } } else { tldScanResourcePaths(path); } } } } /* * Scans the directory identified by startPath, along with its * sub-directories, for TLDs. * * Keep in sync with o.a.j.comiler.TldLocationsCache */ private void tldScanDir(File start) { if (log.isTraceEnabled()) { log.trace(sm.getString("tldConfig.dirScan", start.getAbsolutePath())); } File[] fileList = start.listFiles(); if (fileList != null) { for (int i = 0; i < fileList.length; i++) { // Scan recursively if (fileList[i].isDirectory()) { tldScanDir(fileList[i]); } else if (fileList[i].getAbsolutePath().endsWith(TLD_EXT)) { InputStream stream = null; try { stream = new FileInputStream(fileList[i]); XmlErrorHandler handler = tldScanStream(stream); handler.logFindings(log, fileList[i].getAbsolutePath()); } catch (IOException ioe) { log.warn(sm.getString("tldConfig.dirFail", fileList[i].getAbsolutePath()), ioe); } finally { if (stream != null) { try { stream.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } } } } } /* * Scans the given JarURLConnection for TLD files located in META-INF * (or a sub-directory of it). * * @param jarConn The JarURLConnection to the JAR file to scan * * Keep in sync with o.a.j.comiler.TldLocationsCache */ private void tldScanJar(JarURLConnection jarConn) { Jar jar = null; InputStream is; try { jar = JarFactory.newInstance(jarConn.getURL()); jar.nextEntry(); String entryName = jar.getEntryName(); while (entryName != null) { if (entryName.startsWith("META-INF/") && entryName.endsWith(".tld")) { is = null; try { is = jar.getEntryInputStream(); XmlErrorHandler handler = tldScanStream(is); handler.logFindings(log, jarConn.getURL() + entryName); } finally { if (is != null) { try { is.close(); } catch (IOException ioe) { // Ignore } } } } jar.nextEntry(); entryName = jar.getEntryName(); } } catch (IOException ioe) { log.warn(sm.getString("tldConfig.jarFail", jarConn.getURL()), ioe); } finally { if (jar != null) { jar.close(); } } } /* * Scan the TLD contents in the specified input stream, and register * any application event listeners found there. NOTE - This * method ensure that the InputStream is correctly closed. * * @param resourceStream InputStream containing a tag library descriptor * * @throws IOException If the file cannot be read */ private XmlErrorHandler tldScanStream(InputStream resourceStream) throws IOException { InputSource source = new InputSource(resourceStream); XmlErrorHandler result = new XmlErrorHandler(); synchronized (tldDigester) { try { tldDigester.setErrorHandler(result); tldDigester.push(this); tldDigester.parse(source); } catch (SAXException s) { // Hack - makes exception handling simpler throw new IOException(s); } finally { tldDigester.reset(); } return result; } } @Override public void lifecycleEvent(LifecycleEvent event) { // Identify the context we are associated with try { context = (Context) event.getLifecycle(); } catch (ClassCastException e) { log.error(sm.getString("tldConfig.cce", event.getLifecycle()), e); return; } if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) { init(); } else if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { try { execute(); } catch (Exception e) { log.error(sm.getString( "tldConfig.execute", context.getName()), e); } } else if (event.getType().equals(Lifecycle.STOP_EVENT)) { taglibUris.clear(); webxmlTaglibUris.clear(); listeners.clear(); } } private void init() { if (tldDigester == null){ tldDigester = createTldDigester(context.getTldValidation(), context.getXmlBlockExternal()); } } } tomcat7-7.0.52/java/org/apache/catalina/startup/HostRuleSet.java0000644000175100017510000001124212271471332024440 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSetBase; /** *

    RuleSet for processing the contents of a * Host definition element. This RuleSet does NOT include * any rules for nested Context which should be added via instances of * ContextRuleSet.

    * * @author Craig R. McClanahan */ public class HostRuleSet extends RuleSetBase { // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public HostRuleSet() { this(""); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public HostRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { digester.addObjectCreate(prefix + "Host", "org.apache.catalina.core.StandardHost", "className"); digester.addSetProperties(prefix + "Host"); digester.addRule(prefix + "Host", new CopyParentClassLoaderRule()); digester.addRule(prefix + "Host", new LifecycleListenerRule ("org.apache.catalina.startup.HostConfig", "hostConfigClass")); digester.addSetNext(prefix + "Host", "addChild", "org.apache.catalina.Container"); digester.addCallMethod(prefix + "Host/Alias", "addAlias", 0); //Cluster configuration start digester.addObjectCreate(prefix + "Host/Cluster", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Host/Cluster"); digester.addSetNext(prefix + "Host/Cluster", "setCluster", "org.apache.catalina.Cluster"); //Cluster configuration end digester.addObjectCreate(prefix + "Host/Listener", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Host/Listener"); digester.addSetNext(prefix + "Host/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener"); digester.addRuleSet(new RealmRuleSet(prefix + "Host/")); digester.addObjectCreate(prefix + "Host/Valve", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Host/Valve"); digester.addSetNext(prefix + "Host/Valve", "addValve", "org.apache.catalina.Valve"); } } tomcat7-7.0.52/java/org/apache/catalina/startup/Embedded.java0000644000175100017510000007326312271471332023723 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.util.HashMap; import org.apache.catalina.Authenticator; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Loader; import org.apache.catalina.Realm; import org.apache.catalina.Valve; import org.apache.catalina.connector.Connector; import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardEngine; import org.apache.catalina.core.StandardHost; import org.apache.catalina.core.StandardService; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.security.SecurityConfig; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.log.SystemLogHandler; import org.apache.tomcat.util.res.StringManager; /** * Convenience class to embed a Catalina servlet container environment * inside another application. You must call the methods of this class in the * following order to ensure correct operation. * *
      *
    • Instantiate a new instance of this class.
    • *
    • Set the relevant properties of this object itself. In particular, * you will want to establish the default Logger to be used, as well * as the default Realm if you are using container-managed security.
    • *
    • Call createEngine() to create an Engine object, and then * call its property setters as desired.
    • *
    • Call createHost() to create at least one virtual Host * associated with the newly created Engine, and then call its property * setters as desired. After you customize this Host, add it to the * corresponding Engine with engine.addChild(host).
    • *
    • Call createContext() to create at least one Context * associated with each newly created Host, and then call its property * setters as desired. You SHOULD create a Context with * a pathname equal to a zero-length string, which will be used to process * all requests not mapped to some other Context. After you customize * this Context, add it to the corresponding Host with * host.addChild(context).
    • *
    • Call addEngine() to attach this Engine to the set of * defined Engines for this object.
    • *
    • Call createConnector() to create at least one TCP/IP * connector, and then call its property setters as desired.
    • *
    • Call addConnector() to attach this Connector to the set * of defined Connectors for this object. The added Connector will use * the most recently added Engine to process its received requests.
    • *
    • Repeat the above series of steps as often as required (although there * will typically be only one Engine instance created).
    • *
    • Call start() to initiate normal operations of all the * attached components.
    • *
    * * After normal operations have begun, you can add and remove Connectors, * Engines, Hosts, and Contexts on the fly. However, once you have removed * a particular component, it must be thrown away -- you can create a new one * with the same characteristics if you merely want to do a restart. *

    * To initiate a normal shutdown, call the stop() method of * this object. *

    * @see org.apache.catalina.startup.Bootstrap#main For a complete example * of how Tomcat is set up and launched as an Embedded application. * * @author Craig R. McClanahan * * @deprecated Use {@link Tomcat} instead. */ @Deprecated public class Embedded extends StandardService { private static final Log log = LogFactory.getLog(Embedded.class); // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class with default properties. */ public Embedded() { this(null); } /** * Construct a new instance of this class with specified properties. * * @param realm Realm implementation to be inherited by all components * (unless overridden further down the container hierarchy) */ public Embedded(Realm realm) { super(); setRealm(realm); setSecurityProtection(); } // ----------------------------------------------------- Instance Variables /** * Is naming enabled ? */ protected boolean useNaming = true; /** * Is standard streams redirection enabled ? */ protected boolean redirectStreams = true; /** * The set of Engines that have been deployed in this server. Normally * there will only be one. */ protected Engine engines[] = new Engine[0]; /** * Custom mappings of login methods to authenticators */ protected volatile HashMap authenticators; /** * Descriptive information about this server implementation. */ protected static final String info = "org.apache.catalina.startup.Embedded/1.0"; /** * The default realm to be used by all containers associated with * this component. */ protected Realm realm = null; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Use await. */ protected boolean await = false; // ------------------------------------------------------------- Properties /** * Return true if naming is enabled. */ public boolean isUseNaming() { return (this.useNaming); } /** * Enables or disables naming support. * * @param useNaming The new use naming value */ public void setUseNaming(boolean useNaming) { boolean oldUseNaming = this.useNaming; this.useNaming = useNaming; support.firePropertyChange("useNaming", Boolean.valueOf(oldUseNaming), Boolean.valueOf(this.useNaming)); } /** * Return true if redirection of standard streams is enabled. */ public boolean isRedirectStreams() { return (this.redirectStreams); } /** * Enables or disables redirection. * * @param redirectStreams The new redirection value */ public void setRedirectStreams(boolean redirectStreams) { boolean oldRedirectStreams = this.redirectStreams; this.redirectStreams = redirectStreams; support.firePropertyChange("redirectStreams", Boolean.valueOf(oldRedirectStreams), Boolean.valueOf(this.redirectStreams)); } /** * Return the default Realm for our Containers. */ public Realm getRealm() { return (this.realm); } /** * Set the default Realm for our Containers. * * @param realm The new default realm */ public void setRealm(Realm realm) { Realm oldRealm = this.realm; this.realm = realm; support.firePropertyChange("realm", oldRealm, this.realm); } public void setAwait(boolean b) { await = b; } public boolean isAwait() { return await; } public void setCatalinaHome(String s) { System.setProperty(Globals.CATALINA_HOME_PROP, s); } public void setCatalinaBase(String s) { System.setProperty(Globals.CATALINA_BASE_PROP, s); } public String getCatalinaHome() { return System.getProperty(Globals.CATALINA_HOME_PROP); } public String getCatalinaBase() { return System.getProperty(Globals.CATALINA_BASE_PROP); } // --------------------------------------------------------- Public Methods /** * Add a new Connector to the set of defined Connectors. The newly * added Connector will be associated with the most recently added Engine. * * @param connector The connector to be added * * @exception IllegalStateException if no engines have been added yet */ @Override public synchronized void addConnector(Connector connector) { if( log.isDebugEnabled() ) { log.debug("Adding connector (" + connector.getInfo() + ")"); } // Make sure we have a Container to send requests to if (engines.length < 1) throw new IllegalStateException (sm.getString("embedded.noEngines")); /* * Add the connector. This will set the connector's container to the * most recently added Engine */ super.addConnector(connector); } /** * Add a new Engine to the set of defined Engines. * * @param engine The engine to be added */ public synchronized void addEngine(Engine engine) { if( log.isDebugEnabled() ) log.debug("Adding engine (" + engine.getInfo() + ")"); // Add this Engine to our set of defined Engines Engine results[] = new Engine[engines.length + 1]; for (int i = 0; i < engines.length; i++) results[i] = engines[i]; results[engines.length] = engine; engines = results; // Start this Engine if necessary if (getState().isAvailable()) { try { engine.start(); } catch (LifecycleException e) { log.error("Engine.start", e); } } this.container = engine; } /** * Create, configure, and return a new TCP/IP socket connector * based on the specified properties. * * @param address InetAddress to bind to, or null if the * connector is supposed to bind to all addresses on this server * @param port Port number to listen to * @param secure true if the generated connector is supposed to be * SSL-enabled, and false otherwise */ public Connector createConnector(InetAddress address, int port, boolean secure) { return createConnector(address != null? address.toString() : null, port, secure); } public Connector createConnector(String address, int port, boolean secure) { String protocol = "http"; if (secure) { protocol = "https"; } return createConnector(address, port, protocol); } public Connector createConnector(InetAddress address, int port, String protocol) { return createConnector(address != null? address.toString() : null, port, protocol); } public Connector createConnector(String address, int port, String protocol) { Connector connector = null; if (address != null) { /* * InetAddress.toString() returns a string of the form * "/". Get the latter part, so that the * address can be parsed (back) into an InetAddress using * InetAddress.getByName(). */ int index = address.indexOf('/'); if (index != -1) { address = address.substring(index + 1); } } if (log.isDebugEnabled()) { log.debug("Creating connector for address='" + ((address == null) ? "ALL" : address) + "' port='" + port + "' protocol='" + protocol + "'"); } try { if (protocol.equals("ajp")) { connector = new Connector("org.apache.coyote.ajp.AjpProtocol"); } else if (protocol.equals("memory")) { connector = new Connector("org.apache.coyote.memory.MemoryProtocolHandler"); } else if (protocol.equals("http")) { connector = new Connector(); } else if (protocol.equals("https")) { connector = new Connector(); connector.setScheme("https"); connector.setSecure(true); connector.setProperty("SSLEnabled","true"); // FIXME !!!! SET SSL PROPERTIES } else { connector = new Connector(protocol); } if (address != null) { IntrospectionUtils.setProperty(connector, "address", "" + address); } IntrospectionUtils.setProperty(connector, "port", "" + port); } catch (Exception e) { log.error("Couldn't create connector."); } return (connector); } /** * Create, configure, and return a Context that will process all * HTTP requests received from one of the associated Connectors, * and directed to the specified context path on the virtual host * to which this Context is connected. *

    * After you have customized the properties, listeners, and Valves * for this Context, you must attach it to the corresponding Host * by calling: *

         *   host.addChild(context);
         * 
    * which will also cause the Context to be started if the Host has * already been started. * * @param path Context path of this application ("" for the default * application for this host, must start with a slash otherwise) * @param docBase Absolute pathname to the document base directory * for this web application * * @exception IllegalArgumentException if an invalid parameter * is specified */ public Context createContext(String path, String docBase) { if( log.isDebugEnabled() ) log.debug("Creating context '" + path + "' with docBase '" + docBase + "'"); StandardContext context = new StandardContext(); context.setDocBase(docBase); context.setPath(path); ContextConfig config = new ContextConfig(); config.setCustomAuthenticators(authenticators); context.addLifecycleListener(config); return (context); } /** * Create, configure, and return an Engine that will process all * HTTP requests received from one of the associated Connectors, * based on the specified properties. */ public Engine createEngine() { if( log.isDebugEnabled() ) log.debug("Creating engine"); StandardEngine engine = new StandardEngine(); // Default host will be set to the first host added engine.setRealm(realm); // Inherited by all children return (engine); } /** * Create, configure, and return a Host that will process all * HTTP requests received from one of the associated Connectors, * and directed to the specified virtual host. *

    * After you have customized the properties, listeners, and Valves * for this Host, you must attach it to the corresponding Engine * by calling: *

         *   engine.addChild(host);
         * 
    * which will also cause the Host to be started if the Engine has * already been started. If this is the default (or only) Host you * will be defining, you may also tell the Engine to pass all requests * not assigned to another virtual host to this one: *
         *   engine.setDefaultHost(host.getName());
         * 
    * * @param name Canonical name of this virtual host * @param appBase Absolute pathname to the application base directory * for this virtual host * * @exception IllegalArgumentException if an invalid parameter * is specified */ public Host createHost(String name, String appBase) { if( log.isDebugEnabled() ) log.debug("Creating host '" + name + "' with appBase '" + appBase + "'"); StandardHost host = new StandardHost(); host.setAppBase(appBase); host.setName(name); return (host); } /** * Create and return a class loader manager that can be customized, and * then attached to a Context, before it is started. * * @param parent ClassLoader that will be the parent of the one * created by this Loader */ public Loader createLoader(ClassLoader parent) { if( log.isDebugEnabled() ) log.debug("Creating Loader with parent class loader '" + parent + "'"); WebappLoader loader = new WebappLoader(parent); return (loader); } /** * Return descriptive information about this Server implementation and * the corresponding version number, in the format * <description>/<version>. */ @Override public String getInfo() { return (info); } /** * Remove the specified Context from the set of defined Contexts for its * associated Host. If this is the last Context for this Host, the Host * will also be removed. * * @param context The Context to be removed */ public synchronized void removeContext(Context context) { if( log.isDebugEnabled() ) log.debug("Removing context[" + context.getName() + "]"); // Is this Context actually among those that are defined? boolean found = false; for (int i = 0; i < engines.length; i++) { Container hosts[] = engines[i].findChildren(); for (int j = 0; j < hosts.length; j++) { Container contexts[] = hosts[j].findChildren(); for (int k = 0; k < contexts.length; k++) { if (context == (Context) contexts[k]) { found = true; break; } } if (found) break; } if (found) break; } if (!found) return; // Remove this Context from the associated Host if( log.isDebugEnabled() ) log.debug(" Removing this Context"); context.getParent().removeChild(context); } /** * Remove the specified Engine from the set of defined Engines, along with * all of its related Hosts and Contexts. All associated Connectors are * also removed. * * @param engine The Engine to be removed */ public synchronized void removeEngine(Engine engine) { if( log.isDebugEnabled() ) log.debug("Removing engine (" + engine.getInfo() + ")"); // Is the specified Engine actually defined? int j = -1; for (int i = 0; i < engines.length; i++) { if (engine == engines[i]) { j = i; break; } } if (j < 0) return; // Remove any Connector that is using this Engine if( log.isDebugEnabled() ) log.debug(" Removing related Containers"); while (true) { int n = -1; for (int i = 0; i < connectors.length; i++) { if (connectors[i].getService().getContainer() == engine) { n = i; break; } } if (n < 0) break; removeConnector(connectors[n]); } // Stop this Engine if necessary if( log.isDebugEnabled() ) log.debug(" Stopping this Engine"); try { engine.stop(); } catch (LifecycleException e) { log.error("Engine.stop", e); } // Remove this Engine from our set of defined Engines if( log.isDebugEnabled() ) log.debug(" Removing this Engine"); int k = 0; Engine results[] = new Engine[engines.length - 1]; for (int i = 0; i < engines.length; i++) { if (i != j) results[k++] = engines[i]; } engines = results; } /** * Remove the specified Host, along with all of its related Contexts, * from the set of defined Hosts for its associated Engine. If this is * the last Host for this Engine, the Engine will also be removed. * * @param host The Host to be removed */ public synchronized void removeHost(Host host) { if( log.isDebugEnabled() ) log.debug("Removing host[" + host.getName() + "]"); // Is this Host actually among those that are defined? boolean found = false; for (int i = 0; i < engines.length; i++) { Container hosts[] = engines[i].findChildren(); for (int j = 0; j < hosts.length; j++) { if (host == (Host) hosts[j]) { found = true; break; } } if (found) break; } if (!found) return; // Remove this Host from the associated Engine if( log.isDebugEnabled() ) log.debug(" Removing this Host"); host.getParent().removeChild(host); } /* * Maps the specified login method to the specified authenticator, allowing * the mappings in org/apache/catalina/startup/Authenticators.properties * to be overridden. * * @param authenticator Authenticator to handle authentication for the * specified login method * @param loginMethod Login method that maps to the specified authenticator * * @throws IllegalArgumentException if the specified authenticator does not * implement the org.apache.catalina.Valve interface */ public void addAuthenticator(Authenticator authenticator, String loginMethod) { if (!(authenticator instanceof Valve)) { throw new IllegalArgumentException( sm.getString("embedded.authenticatorNotInstanceOfValve")); } if (authenticators == null) { synchronized (this) { if (authenticators == null) { authenticators = new HashMap(); } } } authenticators.put(loginMethod, authenticator); } // ------------------------------------------------------ Lifecycle Methods /** * Start nested components ({@link Connector}s and {@link Engine}s) and * implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { if( log.isInfoEnabled() ) log.info("Starting tomcat server"); // Validate the setup of our required system properties initDirs(); // Initialize some naming specific properties initNaming(); setState(LifecycleState.STARTING); // Start our defined Engines first for (int i = 0; i < engines.length; i++) { engines[i].start(); } // Start our defined Connectors second for (int i = 0; i < connectors.length; i++) { ((Lifecycle) connectors[i]).start(); } } /** * Stop nested components ({@link Connector}s and {@link Engine}s) and * implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { if( log.isDebugEnabled() ) log.debug("Stopping embedded server"); setState(LifecycleState.STOPPING); // Stop our defined Connectors first for (int i = 0; i < connectors.length; i++) { ((Lifecycle) connectors[i]).stop(); } // Stop our defined Engines second for (int i = 0; i < engines.length; i++) { engines[i].stop(); } } // ------------------------------------------------------ Protected Methods /** Initialize naming - this should only enable java:env and root naming. * If tomcat is embedded in an application that already defines those - * it shouldn't do it. * * XXX The 2 should be separated, you may want to enable java: but not * the initial context and the reverse * XXX Can we "guess" - i.e. lookup java: and if something is returned assume * false ? * XXX We have a major problem with the current setting for java: url */ protected void initNaming() { // Setting additional variables if (!useNaming) { log.info( "Catalina naming disabled"); System.setProperty("catalina.useNaming", "false"); } else { System.setProperty("catalina.useNaming", "true"); String value = "org.apache.naming"; String oldValue = System.getProperty(javax.naming.Context.URL_PKG_PREFIXES); if (oldValue != null) { value = value + ":" + oldValue; } System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value); if( log.isDebugEnabled() ) log.debug("Setting naming prefix=" + value); value = System.getProperty (javax.naming.Context.INITIAL_CONTEXT_FACTORY); if (value == null) { System.setProperty (javax.naming.Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory"); } else { log.debug( "INITIAL_CONTEXT_FACTORY already set " + value ); } } } protected void initDirs() { String catalinaHome = System.getProperty(Globals.CATALINA_HOME_PROP); if (catalinaHome == null) { // Backwards compatibility patch for J2EE RI 1.3 String j2eeHome = System.getProperty("com.sun.enterprise.home"); if (j2eeHome != null) { catalinaHome=System.getProperty("com.sun.enterprise.home"); } else if (System.getProperty(Globals.CATALINA_BASE_PROP) != null) { catalinaHome = System.getProperty(Globals.CATALINA_BASE_PROP); } else { // Use IntrospectionUtils and guess the dir catalinaHome = IntrospectionUtils.guessInstall (Globals.CATALINA_HOME_PROP, Globals.CATALINA_BASE_PROP, "catalina.jar"); if (catalinaHome == null) { catalinaHome = IntrospectionUtils.guessInstall ("tomcat.install", Globals.CATALINA_HOME_PROP, "tomcat.jar"); } } } // last resort - for minimal/embedded cases. if(catalinaHome==null) { catalinaHome=System.getProperty("user.dir"); } if (catalinaHome != null) { File home = new File(catalinaHome); if (!home.isAbsolute()) { try { catalinaHome = home.getCanonicalPath(); } catch (IOException e) { catalinaHome = home.getAbsolutePath(); } } System.setProperty(Globals.CATALINA_HOME_PROP, catalinaHome); } if (System.getProperty(Globals.CATALINA_BASE_PROP) == null) { System.setProperty(Globals.CATALINA_BASE_PROP, catalinaHome); } else { String catalinaBase = System.getProperty(Globals.CATALINA_BASE_PROP); File base = new File(catalinaBase); if (!base.isAbsolute()) { try { catalinaBase = base.getCanonicalPath(); } catch (IOException e) { catalinaBase = base.getAbsolutePath(); } } System.setProperty(Globals.CATALINA_BASE_PROP, catalinaBase); } String temp = System.getProperty("java.io.tmpdir"); if (temp == null || (!(new File(temp)).exists()) || (!(new File(temp)).isDirectory())) { log.error(sm.getString("embedded.notmp", temp)); } } protected void initStreams() { if (redirectStreams) { // Replace System.out and System.err with a custom PrintStream System.setOut(new SystemLogHandler(System.out)); System.setErr(new SystemLogHandler(System.err)); } } // -------------------------------------------------------- Private Methods /** * Set the security package access/protection. */ protected void setSecurityProtection(){ SecurityConfig securityConfig = SecurityConfig.newInstance(); securityConfig.setPackageDefinition(); securityConfig.setPackageAccess(); } } tomcat7-7.0.52/java/org/apache/catalina/startup/XmlErrorHandler.java0000644000175100017510000000516612251316545025301 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.util.HashSet; import java.util.Set; import org.apache.juli.logging.Log; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * @deprecated Use {@link org.apache.tomcat.util.descriptor.XmlErrorHandler} */ @Deprecated public class XmlErrorHandler implements ErrorHandler { private static final StringManager sm = StringManager.getManager(Constants.Package); private Set errors = new HashSet(); private Set warnings = new HashSet(); @Override public void error(SAXParseException exception) throws SAXException { // Collect non-fatal errors errors.add(exception); } @Override public void fatalError(SAXParseException exception) throws SAXException { // Re-throw fatal errors throw exception; } @Override public void warning(SAXParseException exception) throws SAXException { // Collect warnings warnings.add(exception); } public Set getErrors() { // Internal use only - don't worry about immutability return errors; } public Set getWarnings() { // Internal use only - don't worry about immutability return warnings; } public void logFindings(Log log, String source) { for (SAXParseException e : getWarnings()) { log.warn(sm.getString( "xmlErrorHandler.warning", e.getMessage(), source)); } for (SAXParseException e : getErrors()) { log.warn(sm.getString( "xmlErrorHandler.error", e.getMessage(), source)); } } } tomcat7-7.0.52/java/org/apache/catalina/startup/ContextConfig.java0000644000175100017510000030476012271471332025003 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; import javax.naming.Binding; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.annotation.HandlesTypes; import org.apache.catalina.Authenticator; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Pipeline; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.catalina.core.ContainerBase; import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardEngine; import org.apache.catalina.core.StandardHost; import org.apache.catalina.deploy.ErrorPage; import org.apache.catalina.deploy.FilterDef; import org.apache.catalina.deploy.FilterMap; import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.catalina.deploy.ServletDef; import org.apache.catalina.deploy.WebXml; import org.apache.catalina.util.ContextName; import org.apache.catalina.util.Introspection; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.naming.resources.DirContextURLConnection; import org.apache.naming.resources.FileDirContext; import org.apache.naming.resources.ResourceAttributes; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.bcel.classfile.AnnotationElementValue; import org.apache.tomcat.util.bcel.classfile.AnnotationEntry; import org.apache.tomcat.util.bcel.classfile.ArrayElementValue; import org.apache.tomcat.util.bcel.classfile.ClassFormatException; import org.apache.tomcat.util.bcel.classfile.ClassParser; import org.apache.tomcat.util.bcel.classfile.ElementValue; import org.apache.tomcat.util.bcel.classfile.ElementValuePair; import org.apache.tomcat.util.bcel.classfile.JavaClass; import org.apache.tomcat.util.descriptor.DigesterFactory; import org.apache.tomcat.util.descriptor.XmlErrorHandler; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSet; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.scan.Jar; import org.apache.tomcat.util.scan.JarFactory; import org.xml.sax.InputSource; import org.xml.sax.SAXParseException; /** * Startup event listener for a Context that configures the properties * of that Context, and the associated defined servlets. * * @author Craig R. McClanahan * @author Jean-Francois Arcand */ public class ContextConfig implements LifecycleListener { private static final Log log = LogFactory.getLog( ContextConfig.class ); /** * The string resources for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); protected static final LoginConfig DUMMY_LOGIN_CONFIG = new LoginConfig("NONE", null, null, null); /** * The set of Authenticators that we know how to configure. The key is * the name of the implemented authentication method, and the value is * the fully qualified Java class name of the corresponding Valve. */ protected static final Properties authenticators; /** * The list of JARs that will be skipped when scanning a web application * for JARs. This means the JAR will not be scanned for web fragments, SCIs, * annotations or classes that match @HandlesTypes. */ private static final Set pluggabilityJarsToSkip = new HashSet(); static { // Load our mapping properties for the standard authenticators InputStream is = ContextConfig.class.getClassLoader().getResourceAsStream( "org/apache/catalina/startup/Authenticators.properties"); Properties props = null; props = new Properties(); if (is != null) { try { props.load(is); } catch (IOException e) { props = null; } } authenticators = props; // Load the list of JARS to skip addJarsToSkip(Constants.DEFAULT_JARS_TO_SKIP); addJarsToSkip(Constants.PLUGGABILITY_JARS_TO_SKIP); } private static void addJarsToSkip(String systemPropertyName) { String jarList = System.getProperty(systemPropertyName); if (jarList != null) { StringTokenizer tokenizer = new StringTokenizer(jarList, ","); while (tokenizer.hasMoreElements()) { pluggabilityJarsToSkip.add(tokenizer.nextToken()); } } } /** * Deployment count. */ protected static long deploymentCount = 0L; /** * Cache of default web.xml fragments per Host */ protected static final Map hostWebXmlCache = new ConcurrentHashMap(); // ----------------------------------------------------- Instance Variables /** * Custom mappings of login methods to authenticators */ protected Map customAuthenticators; /** * The Context we are associated with. */ protected Context context = null; /** * The default web application's context file location. * @deprecated Unnecessary */ @Deprecated protected String defaultContextXml = null; /** * The default web application's deployment descriptor location. */ protected String defaultWebXml = null; /** * Track any fatal errors during startup configuration processing. */ protected boolean ok = false; /** * Original docBase. */ protected String originalDocBase = null; /** * Anti-locking docBase. It is a path to a copy of the web application * in the java.io.tmpdir directory. This path is always an absolute one. */ private File antiLockingDocBase = null; /** * Map of ServletContainerInitializer to classes they expressed interest in. */ protected final Map>> initializerClassMap = new LinkedHashMap>>(); /** * Map of Types to ServletContainerInitializer that are interested in those * types. */ protected final Map, Set> typeInitializerMap = new HashMap, Set>(); /** * Cache of JavaClass objects (byte code) by fully qualified class name. * Only populated if it is necessary to scan the super types and interfaces * as part of the processing for {@link HandlesTypes}. */ protected final Map javaClassCache = new HashMap(); /** * Flag that indicates if at least one {@link HandlesTypes} entry is present * that represents an annotation. */ protected boolean handlesTypesAnnotations = false; /** * Flag that indicates if at least one {@link HandlesTypes} entry is present * that represents a non-annotation. */ protected boolean handlesTypesNonAnnotations = false; /** * The Digester we will use to process web application * deployment descriptor files. */ protected Digester webDigester = null; protected WebRuleSet webRuleSet = null; /** * The Digester we will use to process web fragment * deployment descriptor files. */ protected Digester webFragmentDigester = null; protected WebRuleSet webFragmentRuleSet = null; // ------------------------------------------------------------- Properties /** * Return the location of the default deployment descriptor */ public String getDefaultWebXml() { if( defaultWebXml == null ) { defaultWebXml=Constants.DefaultWebXml; } return (this.defaultWebXml); } /** * Set the location of the default deployment descriptor * * @param path Absolute/relative path to the default web.xml */ public void setDefaultWebXml(String path) { this.defaultWebXml = path; } /** * Return the location of the default context file * @deprecated Never changed from default */ @Deprecated public String getDefaultContextXml() { if( defaultContextXml == null ) { defaultContextXml=Constants.DefaultContextXml; } return (this.defaultContextXml); } /** * Set the location of the default context file * * @param path Absolute/relative path to the default context.xml * @deprecated Unused */ @Deprecated public void setDefaultContextXml(String path) { this.defaultContextXml = path; } /** * Sets custom mappings of login methods to authenticators. * * @param customAuthenticators Custom mappings of login methods to * authenticators */ public void setCustomAuthenticators( Map customAuthenticators) { this.customAuthenticators = customAuthenticators; } // --------------------------------------------------------- Public Methods /** * Process events for an associated Context. * * @param event The lifecycle event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { // Identify the context we are associated with try { context = (Context) event.getLifecycle(); } catch (ClassCastException e) { log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e); return; } // Process the event that has occurred if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { configureStart(); } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) { beforeStart(); } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) { // Restore docBase for management tools if (originalDocBase != null) { context.setDocBase(originalDocBase); } } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) { configureStop(); } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) { init(); } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) { destroy(); } } // -------------------------------------------------------- protected Methods /** * Process the application classes annotations, if it exists. */ protected void applicationAnnotationsConfig() { long t1=System.currentTimeMillis(); WebAnnotationSet.loadApplicationAnnotations(context); long t2=System.currentTimeMillis(); if (context instanceof StandardContext) { ((StandardContext) context).setStartupTime(t2-t1+ ((StandardContext) context).getStartupTime()); } } /** * Set up an Authenticator automatically if required, and one has not * already been configured. */ protected void authenticatorConfig() { LoginConfig loginConfig = context.getLoginConfig(); SecurityConstraint constraints[] = context.findConstraints(); if (context.getIgnoreAnnotations() && (constraints == null || constraints.length ==0) && !context.getPreemptiveAuthentication()) { return; } else { if (loginConfig == null) { // Not metadata-complete or security constraints present, need // an authenticator to support @ServletSecurity annotations // and/or constraints loginConfig = DUMMY_LOGIN_CONFIG; context.setLoginConfig(loginConfig); } } // Has an authenticator been configured already? if (context.getAuthenticator() != null) return; if (!(context instanceof ContainerBase)) { return; // Cannot install a Valve even if it would be needed } // Has a Realm been configured for us to authenticate against? if (context.getRealm() == null) { log.error(sm.getString("contextConfig.missingRealm")); ok = false; return; } /* * First check to see if there is a custom mapping for the login * method. If so, use it. Otherwise, check if there is a mapping in * org/apache/catalina/startup/Authenticators.properties. */ Valve authenticator = null; if (customAuthenticators != null) { authenticator = (Valve) customAuthenticators.get(loginConfig.getAuthMethod()); } if (authenticator == null) { if (authenticators == null) { log.error(sm.getString("contextConfig.authenticatorResources")); ok = false; return; } // Identify the class name of the Valve we should configure String authenticatorName = null; authenticatorName = authenticators.getProperty(loginConfig.getAuthMethod()); if (authenticatorName == null) { log.error(sm.getString("contextConfig.authenticatorMissing", loginConfig.getAuthMethod())); ok = false; return; } // Instantiate and install an Authenticator of the requested class try { Class authenticatorClass = Class.forName(authenticatorName); authenticator = (Valve) authenticatorClass.newInstance(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString( "contextConfig.authenticatorInstantiate", authenticatorName), t); ok = false; } } if (authenticator != null && context instanceof ContainerBase) { Pipeline pipeline = ((ContainerBase) context).getPipeline(); if (pipeline != null) { ((ContainerBase) context).getPipeline().addValve(authenticator); if (log.isDebugEnabled()) { log.debug(sm.getString( "contextConfig.authenticatorConfigured", loginConfig.getAuthMethod())); } } } } /** * Create and return a Digester configured to process the * web application deployment descriptor (web.xml). */ public void createWebXmlDigester(boolean namespaceAware, boolean validation) { boolean blockExternal = context.getXmlBlockExternal(); webRuleSet = new WebRuleSet(false); webDigester = DigesterFactory.newDigester(validation, namespaceAware, webRuleSet, blockExternal); webDigester.getParser(); webFragmentRuleSet = new WebRuleSet(true); webFragmentDigester = DigesterFactory.newDigester(validation, namespaceAware, webFragmentRuleSet, blockExternal); webFragmentDigester.getParser(); } /** * Create (if necessary) and return a Digester configured to process the * context configuration descriptor for an application. */ protected Digester createContextDigester() { Digester digester = new Digester(); digester.setValidating(false); digester.setRulesValidation(true); HashMap, List> fakeAttributes = new HashMap, List>(); ArrayList attrs = new ArrayList(); attrs.add("className"); fakeAttributes.put(Object.class, attrs); digester.setFakeAttributes(fakeAttributes); RuleSet contextRuleSet = new ContextRuleSet("", false); digester.addRuleSet(contextRuleSet); RuleSet namingRuleSet = new NamingRuleSet("Context/"); digester.addRuleSet(namingRuleSet); return digester; } protected String getBaseDir() { Container engineC=context.getParent().getParent(); if( engineC instanceof StandardEngine ) { return ((StandardEngine)engineC).getBaseDir(); } return System.getProperty(Globals.CATALINA_BASE_PROP); } /** * Process the default configuration file, if it exists. */ protected void contextConfig(Digester digester) { // Open the default context.xml file, if it exists if( defaultContextXml==null && context instanceof StandardContext ) { defaultContextXml = ((StandardContext)context).getDefaultContextXml(); } // set the default if we don't have any overrides if( defaultContextXml==null ) getDefaultContextXml(); if (!context.getOverride()) { File defaultContextFile = new File(defaultContextXml); if (!defaultContextFile.isAbsolute()) { defaultContextFile =new File(getBaseDir(), defaultContextXml); } if (defaultContextFile.exists()) { try { URL defaultContextUrl = defaultContextFile.toURI().toURL(); processContextConfig(digester, defaultContextUrl); } catch (MalformedURLException e) { log.error(sm.getString( "contextConfig.badUrl", defaultContextFile), e); } } File hostContextFile = new File(getHostConfigBase(), Constants.HostContextXml); if (hostContextFile.exists()) { try { URL hostContextUrl = hostContextFile.toURI().toURL(); processContextConfig(digester, hostContextUrl); } catch (MalformedURLException e) { log.error(sm.getString( "contextConfig.badUrl", hostContextFile), e); } } } if (context.getConfigFile() != null) processContextConfig(digester, context.getConfigFile()); } /** * Process a context.xml. */ protected void processContextConfig(Digester digester, URL contextXml) { if (log.isDebugEnabled()) log.debug("Processing context [" + context.getName() + "] configuration file [" + contextXml + "]"); InputSource source = null; InputStream stream = null; try { source = new InputSource(contextXml.toString()); URLConnection xmlConn = contextXml.openConnection(); xmlConn.setUseCaches(false); stream = xmlConn.getInputStream(); } catch (Exception e) { log.error(sm.getString("contextConfig.contextMissing", contextXml) , e); } if (source == null) return; try { source.setByteStream(stream); digester.setClassLoader(this.getClass().getClassLoader()); digester.setUseContextClassLoader(false); digester.push(context.getParent()); digester.push(context); XmlErrorHandler errorHandler = new XmlErrorHandler(); digester.setErrorHandler(errorHandler); digester.parse(source); if (errorHandler.getWarnings().size() > 0 || errorHandler.getErrors().size() > 0) { errorHandler.logFindings(log, contextXml.toString()); ok = false; } if (log.isDebugEnabled()) { log.debug("Successfully processed context [" + context.getName() + "] configuration file [" + contextXml + "]"); } } catch (SAXParseException e) { log.error(sm.getString("contextConfig.contextParse", context.getName()), e); log.error(sm.getString("contextConfig.defaultPosition", "" + e.getLineNumber(), "" + e.getColumnNumber())); ok = false; } catch (Exception e) { log.error(sm.getString("contextConfig.contextParse", context.getName()), e); ok = false; } finally { try { if (stream != null) { stream.close(); } } catch (IOException e) { log.error(sm.getString("contextConfig.contextClose"), e); } } } /** * Adjust docBase. */ protected void fixDocBase() throws IOException { Host host = (Host) context.getParent(); String appBase = host.getAppBase(); File canonicalAppBase = new File(appBase); if (canonicalAppBase.isAbsolute()) { canonicalAppBase = canonicalAppBase.getCanonicalFile(); } else { canonicalAppBase = new File(getBaseDir(), appBase) .getCanonicalFile(); } String docBase = context.getDocBase(); if (docBase == null) { // Trying to guess the docBase according to the path String path = context.getPath(); if (path == null) { return; } ContextName cn = new ContextName(path, context.getWebappVersion()); docBase = cn.getBaseName(); } File file = new File(docBase); if (!file.isAbsolute()) { docBase = (new File(canonicalAppBase, docBase)).getPath(); } else { docBase = file.getCanonicalPath(); } file = new File(docBase); String origDocBase = docBase; ContextName cn = new ContextName(context.getPath(), context.getWebappVersion()); String pathName = cn.getBaseName(); boolean unpackWARs = true; if (host instanceof StandardHost) { unpackWARs = ((StandardHost) host).isUnpackWARs(); if (unpackWARs && context instanceof StandardContext) { unpackWARs = ((StandardContext) context).getUnpackWAR(); } } if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory() && unpackWARs) { URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/"); docBase = ExpandWar.expand(host, war, pathName); file = new File(docBase); docBase = file.getCanonicalPath(); if (context instanceof StandardContext) { ((StandardContext) context).setOriginalDocBase(origDocBase); } } else if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory() && !unpackWARs) { URL war = new URL("jar:" + (new File (docBase)).toURI().toURL() + "!/"); ExpandWar.validate(host, war, pathName); } else { File docDir = new File(docBase); if (!docDir.exists()) { File warFile = new File(docBase + ".war"); if (warFile.exists()) { URL war = new URL("jar:" + warFile.toURI().toURL() + "!/"); if (unpackWARs) { docBase = ExpandWar.expand(host, war, pathName); file = new File(docBase); docBase = file.getCanonicalPath(); } else { docBase = warFile.getCanonicalPath(); ExpandWar.validate(host, war, pathName); } } if (context instanceof StandardContext) { ((StandardContext) context).setOriginalDocBase(origDocBase); } } } if (docBase.startsWith(canonicalAppBase.getPath() + File.separatorChar)) { docBase = docBase.substring(canonicalAppBase.getPath().length()); docBase = docBase.replace(File.separatorChar, '/'); if (docBase.startsWith("/")) { docBase = docBase.substring(1); } } else { docBase = docBase.replace(File.separatorChar, '/'); } context.setDocBase(docBase); } protected void antiLocking() { if ((context instanceof StandardContext) && ((StandardContext) context).getAntiResourceLocking()) { Host host = (Host) context.getParent(); String appBase = host.getAppBase(); String docBase = context.getDocBase(); if (docBase == null) return; originalDocBase = docBase; File docBaseFile = new File(docBase); if (!docBaseFile.isAbsolute()) { File file = new File(appBase); if (!file.isAbsolute()) { file = new File(getBaseDir(), appBase); } docBaseFile = new File(file, docBase); } String path = context.getPath(); if (path == null) { return; } ContextName cn = new ContextName(path, context.getWebappVersion()); docBase = cn.getBaseName(); if (originalDocBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) { antiLockingDocBase = new File( System.getProperty("java.io.tmpdir"), deploymentCount++ + "-" + docBase + ".war"); } else { antiLockingDocBase = new File( System.getProperty("java.io.tmpdir"), deploymentCount++ + "-" + docBase); } antiLockingDocBase = antiLockingDocBase.getAbsoluteFile(); if (log.isDebugEnabled()) log.debug("Anti locking context[" + context.getName() + "] setting docBase to " + antiLockingDocBase.getPath()); // Cleanup just in case an old deployment is lying around ExpandWar.delete(antiLockingDocBase); if (ExpandWar.copy(docBaseFile, antiLockingDocBase)) { context.setDocBase(antiLockingDocBase.getPath()); } } } /** * Process a "init" event for this Context. */ protected void init() { // Called from StandardContext.init() Digester contextDigester = createContextDigester(); contextDigester.getParser(); if (log.isDebugEnabled()) log.debug(sm.getString("contextConfig.init")); context.setConfigured(false); ok = true; contextConfig(contextDigester); createWebXmlDigester(context.getXmlNamespaceAware(), context.getXmlValidation()); } /** * Process a "before start" event for this Context. */ protected synchronized void beforeStart() { try { fixDocBase(); } catch (IOException e) { log.error(sm.getString( "contextConfig.fixDocBase", context.getName()), e); } antiLocking(); } /** * Process a "contextConfig" event for this Context. */ protected synchronized void configureStart() { // Called from StandardContext.start() if (log.isDebugEnabled()) log.debug(sm.getString("contextConfig.start")); if (log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.xmlSettings", context.getName(), Boolean.valueOf(context.getXmlValidation()), Boolean.valueOf(context.getXmlNamespaceAware()))); } webConfig(); if (!context.getIgnoreAnnotations()) { applicationAnnotationsConfig(); } if (ok) { validateSecurityRoles(); } // Configure an authenticator if we need one if (ok) authenticatorConfig(); // Dump the contents of this pipeline if requested if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) { log.debug("Pipeline Configuration:"); Pipeline pipeline = ((ContainerBase) context).getPipeline(); Valve valves[] = null; if (pipeline != null) valves = pipeline.getValves(); if (valves != null) { for (int i = 0; i < valves.length; i++) { log.debug(" " + valves[i].getInfo()); } } log.debug("======================"); } // Make our application available if no problems were encountered if (ok) context.setConfigured(true); else { log.error(sm.getString("contextConfig.unavailable")); context.setConfigured(false); } } /** * Process a "stop" event for this Context. */ protected synchronized void configureStop() { if (log.isDebugEnabled()) log.debug(sm.getString("contextConfig.stop")); int i; // Removing children Container[] children = context.findChildren(); for (i = 0; i < children.length; i++) { context.removeChild(children[i]); } // Removing application parameters /* ApplicationParameter[] applicationParameters = context.findApplicationParameters(); for (i = 0; i < applicationParameters.length; i++) { context.removeApplicationParameter (applicationParameters[i].getName()); } */ // Removing security constraints SecurityConstraint[] securityConstraints = context.findConstraints(); for (i = 0; i < securityConstraints.length; i++) { context.removeConstraint(securityConstraints[i]); } // Removing Ejbs /* ContextEjb[] contextEjbs = context.findEjbs(); for (i = 0; i < contextEjbs.length; i++) { context.removeEjb(contextEjbs[i].getName()); } */ // Removing environments /* ContextEnvironment[] contextEnvironments = context.findEnvironments(); for (i = 0; i < contextEnvironments.length; i++) { context.removeEnvironment(contextEnvironments[i].getName()); } */ // Removing errors pages ErrorPage[] errorPages = context.findErrorPages(); for (i = 0; i < errorPages.length; i++) { context.removeErrorPage(errorPages[i]); } // Removing filter defs FilterDef[] filterDefs = context.findFilterDefs(); for (i = 0; i < filterDefs.length; i++) { context.removeFilterDef(filterDefs[i]); } // Removing filter maps FilterMap[] filterMaps = context.findFilterMaps(); for (i = 0; i < filterMaps.length; i++) { context.removeFilterMap(filterMaps[i]); } // Removing local ejbs /* ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs(); for (i = 0; i < contextLocalEjbs.length; i++) { context.removeLocalEjb(contextLocalEjbs[i].getName()); } */ // Removing Mime mappings String[] mimeMappings = context.findMimeMappings(); for (i = 0; i < mimeMappings.length; i++) { context.removeMimeMapping(mimeMappings[i]); } // Removing parameters String[] parameters = context.findParameters(); for (i = 0; i < parameters.length; i++) { context.removeParameter(parameters[i]); } // Removing resource env refs /* String[] resourceEnvRefs = context.findResourceEnvRefs(); for (i = 0; i < resourceEnvRefs.length; i++) { context.removeResourceEnvRef(resourceEnvRefs[i]); } */ // Removing resource links /* ContextResourceLink[] contextResourceLinks = context.findResourceLinks(); for (i = 0; i < contextResourceLinks.length; i++) { context.removeResourceLink(contextResourceLinks[i].getName()); } */ // Removing resources /* ContextResource[] contextResources = context.findResources(); for (i = 0; i < contextResources.length; i++) { context.removeResource(contextResources[i].getName()); } */ // Removing security role String[] securityRoles = context.findSecurityRoles(); for (i = 0; i < securityRoles.length; i++) { context.removeSecurityRole(securityRoles[i]); } // Removing servlet mappings String[] servletMappings = context.findServletMappings(); for (i = 0; i < servletMappings.length; i++) { context.removeServletMapping(servletMappings[i]); } // FIXME : Removing status pages // Removing welcome files String[] welcomeFiles = context.findWelcomeFiles(); for (i = 0; i < welcomeFiles.length; i++) { context.removeWelcomeFile(welcomeFiles[i]); } // Removing wrapper lifecycles String[] wrapperLifecycles = context.findWrapperLifecycles(); for (i = 0; i < wrapperLifecycles.length; i++) { context.removeWrapperLifecycle(wrapperLifecycles[i]); } // Removing wrapper listeners String[] wrapperListeners = context.findWrapperListeners(); for (i = 0; i < wrapperListeners.length; i++) { context.removeWrapperListener(wrapperListeners[i]); } // Remove (partially) folders and files created by antiLocking if (antiLockingDocBase != null) { // No need to log failure - it is expected in this case ExpandWar.delete(antiLockingDocBase, false); } // Reset ServletContextInitializer scanning initializerClassMap.clear(); typeInitializerMap.clear(); ok = true; } /** * Process a "destroy" event for this Context. */ protected synchronized void destroy() { // Called from StandardContext.destroy() if (log.isDebugEnabled()) log.debug(sm.getString("contextConfig.destroy")); // Skip clearing the work directory if Tomcat is being shutdown Server s = getServer(); if (s != null && !s.getState().isAvailable()) { return; } // Changed to getWorkPath per Bugzilla 35819. if (context instanceof StandardContext) { String workDir = ((StandardContext) context).getWorkPath(); if (workDir != null) { ExpandWar.delete(new File(workDir)); } } } private Server getServer() { Container c = context; while (c != null && !(c instanceof Engine)) { c = c.getParent(); } if (c == null) { return null; } Service s = ((Engine)c).getService(); if (s == null) { return null; } return s.getServer(); } /** * Validate the usage of security role names in the web application * deployment descriptor. If any problems are found, issue warning * messages (for backwards compatibility) and add the missing roles. * (To make these problems fatal instead, simply set the ok * instance variable to false as well). */ protected void validateSecurityRoles() { // Check role names used in elements SecurityConstraint constraints[] = context.findConstraints(); for (int i = 0; i < constraints.length; i++) { String roles[] = constraints[i].findAuthRoles(); for (int j = 0; j < roles.length; j++) { if (!"*".equals(roles[j]) && !context.findSecurityRole(roles[j])) { log.warn(sm.getString("contextConfig.role.auth", roles[j])); context.addSecurityRole(roles[j]); } } } // Check role names used in elements Container wrappers[] = context.findChildren(); for (int i = 0; i < wrappers.length; i++) { Wrapper wrapper = (Wrapper) wrappers[i]; String runAs = wrapper.getRunAs(); if ((runAs != null) && !context.findSecurityRole(runAs)) { log.warn(sm.getString("contextConfig.role.runas", runAs)); context.addSecurityRole(runAs); } String names[] = wrapper.findSecurityReferences(); for (int j = 0; j < names.length; j++) { String link = wrapper.findSecurityReference(names[j]); if ((link != null) && !context.findSecurityRole(link)) { log.warn(sm.getString("contextConfig.role.link", link)); context.addSecurityRole(link); } } } } /** * Get config base. * * @deprecated Unused - will be removed in 8.0.x */ @Deprecated protected File getConfigBase() { File configBase = new File(getBaseDir(), "conf"); if (!configBase.exists()) { return null; } return configBase; } protected File getHostConfigBase() { File file = null; Container container = context; Host host = null; Engine engine = null; while (container != null) { if (container instanceof Host) { host = (Host)container; } if (container instanceof Engine) { engine = (Engine)container; } container = container.getParent(); } if (host != null && host.getXmlBase()!=null) { String xmlBase = host.getXmlBase(); file = new File(xmlBase); if (!file.isAbsolute()) file = new File(getBaseDir(), xmlBase); } else { StringBuilder result = new StringBuilder(); if (engine != null) { result.append(engine.getName()).append('/'); } if (host != null) { result.append(host.getName()).append('/'); } file = new File (getConfigBase(), result.toString()); } try { return file.getCanonicalFile(); } catch (IOException e) { return file; } } /** * Scan the web.xml files that apply to the web application and merge them * using the rules defined in the spec. For the global web.xml files, * where there is duplicate configuration, the most specific level wins. ie * an application's web.xml takes precedence over the host level or global * web.xml file. */ protected void webConfig() { /* * Anything and everything can override the global and host defaults. * This is implemented in two parts * - Handle as a web fragment that gets added after everything else so * everything else takes priority * - Mark Servlets as overridable so SCI configuration can replace * configuration from the defaults */ /* * The rules for annotation scanning are not as clear-cut as one might * think. Tomcat implements the following process: * - As per SRV.1.6.2, Tomcat will scan for annotations regardless of * which Servlet spec version is declared in web.xml. The EG has * confirmed this is the expected behaviour. * - As per http://java.net/jira/browse/SERVLET_SPEC-36, if the main * web.xml is marked as metadata-complete, JARs are still processed * for SCIs. * - If metadata-complete=true and an absolute ordering is specified, * JARs excluded from the ordering are also excluded from the SCI * processing. * - If an SCI has a @HandlesType annotation then all classes (except * those in JARs excluded from an absolute ordering) need to be * scanned to check if they match. */ Set defaults = new HashSet(); defaults.add(getDefaultWebXmlFragment()); WebXml webXml = createWebXml(); // Parse context level web.xml InputSource contextWebXml = getContextWebXmlSource(); parseWebXml(contextWebXml, webXml, false); ServletContext sContext = context.getServletContext(); // Ordering is important here // Step 1. Identify all the JARs packaged with the application // If the JARs have a web-fragment.xml it will be parsed at this // point. Map fragments = processJarsForWebFragments(webXml); // Step 2. Order the fragments. Set orderedFragments = null; orderedFragments = WebXml.orderWebFragments(webXml, fragments, sContext); // Step 3. Look for ServletContainerInitializer implementations if (ok) { processServletContainerInitializers(context.getServletContext()); } if (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) { // Step 4. Process /WEB-INF/classes for annotations if (ok) { // Hack required by Eclipse's "serve modules without // publishing" feature since this backs WEB-INF/classes by // multiple locations rather than one. NamingEnumeration listBindings = null; try { try { listBindings = context.getResources().listBindings( "/WEB-INF/classes"); } catch (NameNotFoundException ignore) { // Safe to ignore } while (listBindings != null && listBindings.hasMoreElements()) { Binding binding = listBindings.nextElement(); if (binding.getObject() instanceof FileDirContext) { File webInfClassDir = new File( ((FileDirContext) binding.getObject()).getDocBase()); processAnnotationsFile(webInfClassDir, webXml, webXml.isMetadataComplete()); } else { String resource = "/WEB-INF/classes/" + binding.getName(); try { URL url = sContext.getResource(resource); processAnnotationsUrl(url, webXml, webXml.isMetadataComplete()); } catch (MalformedURLException e) { log.error(sm.getString( "contextConfig.webinfClassesUrl", resource), e); } } } } catch (NamingException e) { log.error(sm.getString( "contextConfig.webinfClassesUrl", "/WEB-INF/classes"), e); } } // Step 5. Process JARs for annotations - only need to process // those fragments we are going to use if (ok) { processAnnotations( orderedFragments, webXml.isMetadataComplete()); } // Cache, if used, is no longer required so clear it javaClassCache.clear(); } if (!webXml.isMetadataComplete()) { // Step 6. Merge web-fragment.xml files into the main web.xml // file. if (ok) { ok = webXml.merge(orderedFragments); } // Step 7. Apply global defaults // Have to merge defaults before JSP conversion since defaults // provide JSP servlet definition. webXml.merge(defaults); // Step 8. Convert explicitly mentioned jsps to servlets if (ok) { convertJsps(webXml); } // Step 9. Apply merged web.xml to Context if (ok) { webXml.configureContext(context); } } else { webXml.merge(defaults); convertJsps(webXml); webXml.configureContext(context); } // Step 9a. Make the merged web.xml available to other // components, specifically Jasper, to save those components // from having to re-generate it. // TODO Use a ServletContainerInitializer for Jasper String mergedWebXml = webXml.toXml(); sContext.setAttribute( org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML, mergedWebXml); if (context.getLogEffectiveWebXml()) { log.info("web.xml:\n" + mergedWebXml); } // Always need to look for static resources // Step 10. Look for static resources packaged in JARs if (ok) { // Spec does not define an order. // Use ordered JARs followed by remaining JARs Set resourceJars = new LinkedHashSet(); if (orderedFragments != null) { for (WebXml fragment : orderedFragments) { resourceJars.add(fragment); } } for (WebXml fragment : fragments.values()) { if (!resourceJars.contains(fragment)) { resourceJars.add(fragment); } } processResourceJARs(resourceJars); // See also StandardContext.resourcesStart() for // WEB-INF/classes/META-INF/resources configuration } // Step 11. Apply the ServletContainerInitializer config to the // context if (ok) { for (Map.Entry>> entry : initializerClassMap.entrySet()) { if (entry.getValue().isEmpty()) { context.addServletContainerInitializer( entry.getKey(), null); } else { context.addServletContainerInitializer( entry.getKey(), entry.getValue()); } } } } private WebXml getDefaultWebXmlFragment() { // Host should never be null Host host = (Host) context.getParent(); DefaultWebXmlCacheEntry entry = hostWebXmlCache.get(host); InputSource globalWebXml = getGlobalWebXmlSource(); InputSource hostWebXml = getHostWebXmlSource(); long globalTimeStamp = 0; long hostTimeStamp = 0; if (globalWebXml != null) { try { URL url = new URL(globalWebXml.getSystemId()); globalTimeStamp = url.openConnection().getLastModified(); } catch (MalformedURLException e) { globalTimeStamp = -1; } catch (IOException e) { globalTimeStamp = -1; } } if (hostWebXml != null) { try { URL url = new URL(hostWebXml.getSystemId()); hostTimeStamp = url.openConnection().getLastModified(); } catch (MalformedURLException e) { hostTimeStamp = -1; } catch (IOException e) { hostTimeStamp = -1; } } if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp && entry.getHostTimeStamp() == hostTimeStamp) { return entry.getWebXml(); } // Parsing global web.xml is relatively expensive. Use a sync block to // make sure it only happens once. Use the pipeline since a lock will // already be held on the host by another thread synchronized (host.getPipeline()) { entry = hostWebXmlCache.get(host); if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp && entry.getHostTimeStamp() == hostTimeStamp) { return entry.getWebXml(); } WebXml webXmlDefaultFragment = createWebXml(); webXmlDefaultFragment.setOverridable(true); // Set to distributable else every app will be prevented from being // distributable when the default fragment is merged with the main // web.xml webXmlDefaultFragment.setDistributable(true); // When merging, the default welcome files are only used if the app has // not defined any welcomes files. webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false); // Parse global web.xml if present if (globalWebXml == null) { // This is unusual enough to log log.info(sm.getString("contextConfig.defaultMissing")); } else { parseWebXml(globalWebXml, webXmlDefaultFragment, false); } // Parse host level web.xml if present // Additive apart from welcome pages webXmlDefaultFragment.setReplaceWelcomeFiles(true); parseWebXml(hostWebXml, webXmlDefaultFragment, false); // Don't update the cache if an error occurs if (globalTimeStamp != -1 && hostTimeStamp != -1) { entry = new DefaultWebXmlCacheEntry(webXmlDefaultFragment, globalTimeStamp, hostTimeStamp); hostWebXmlCache.put(host, entry); } return webXmlDefaultFragment; } } private void convertJsps(WebXml webXml) { Map jspInitParams; ServletDef jspServlet = webXml.getServlets().get("jsp"); if (jspServlet == null) { jspInitParams = new HashMap(); Wrapper w = (Wrapper) context.findChild("jsp"); if (w != null) { String[] params = w.findInitParameters(); for (String param : params) { jspInitParams.put(param, w.findInitParameter(param)); } } } else { jspInitParams = jspServlet.getParameterMap(); } for (ServletDef servletDef: webXml.getServlets().values()) { if (servletDef.getJspFile() != null) { convertJsp(servletDef, jspInitParams); } } } private void convertJsp(ServletDef servletDef, Map jspInitParams) { servletDef.setServletClass(org.apache.catalina.core.Constants.JSP_SERVLET_CLASS); String jspFile = servletDef.getJspFile(); if ((jspFile != null) && !jspFile.startsWith("/")) { if (context.isServlet22()) { if(log.isDebugEnabled()) log.debug(sm.getString("contextConfig.jspFile.warning", jspFile)); jspFile = "/" + jspFile; } else { throw new IllegalArgumentException (sm.getString("contextConfig.jspFile.error", jspFile)); } } servletDef.getParameterMap().put("jspFile", jspFile); servletDef.setJspFile(null); for (Map.Entry initParam: jspInitParams.entrySet()) { servletDef.addInitParameter(initParam.getKey(), initParam.getValue()); } } protected WebXml createWebXml() { return new WebXml(); } /** * Scan JARs for ServletContainerInitializer implementations. */ protected void processServletContainerInitializers(ServletContext servletContext) { List detectedScis; try { WebappServiceLoader loader = new WebappServiceLoader( servletContext, context.getContainerSciFilter()); detectedScis = loader.load(ServletContainerInitializer.class); } catch (IOException e) { log.error(sm.getString( "contextConfig.servletContainerInitializerFail", context.getName()), e); ok = false; return; } for (ServletContainerInitializer sci : detectedScis) { initializerClassMap.put(sci, new HashSet>()); HandlesTypes ht; try { ht = sci.getClass().getAnnotation(HandlesTypes.class); } catch (Exception e) { if (log.isDebugEnabled()) { log.info(sm.getString("contextConfig.sci.debug", sci.getClass().getName()), e); } else { log.info(sm.getString("contextConfig.sci.info", sci.getClass().getName())); } continue; } if (ht == null) { continue; } Class[] types = ht.value(); if (types == null) { continue; } for (Class type : types) { if (type.isAnnotation()) { handlesTypesAnnotations = true; } else { handlesTypesNonAnnotations = true; } Set scis = typeInitializerMap.get(type); if (scis == null) { scis = new HashSet(); typeInitializerMap.put(type, scis); } scis.add(sci); } } } /** * Scan JARs that contain web-fragment.xml files that will be used to * configure this application to see if they also contain static resources. * If static resources are found, add them to the context. Resources are * added in web-fragment.xml priority order. */ protected void processResourceJARs(Set fragments) { for (WebXml fragment : fragments) { URL url = fragment.getURL(); Jar jar = null; try { // Note: Ignore file URLs for now since only jar URLs will be accepted if ("jar".equals(url.getProtocol())) { jar = JarFactory.newInstance(url); jar.nextEntry(); String entryName = jar.getEntryName(); while (entryName != null) { if (entryName.startsWith("META-INF/resources/")) { context.addResourceJarUrl(url); break; } jar.nextEntry(); entryName = jar.getEntryName(); } } else if ("file".equals(url.getProtocol())) { FileDirContext fileDirContext = new FileDirContext(); fileDirContext.setDocBase(new File(url.toURI()).getAbsolutePath()); try { fileDirContext.lookup("META-INF/resources/"); //lookup succeeded if(context instanceof StandardContext){ ((StandardContext)context).addResourcesDirContext(fileDirContext); } } catch (NamingException e) { //not found, ignore } } } catch (IOException ioe) { log.error(sm.getString("contextConfig.resourceJarFail", url, context.getName())); } catch (URISyntaxException e) { log.error(sm.getString("contextConfig.resourceJarFail", url, context.getName())); } finally { if (jar != null) { jar.close(); } } } } /** * Identify the default web.xml to be used and obtain an input source for * it. */ protected InputSource getGlobalWebXmlSource() { // Is a default web.xml specified for the Context? if (defaultWebXml == null && context instanceof StandardContext) { defaultWebXml = ((StandardContext) context).getDefaultWebXml(); } // Set the default if we don't have any overrides if (defaultWebXml == null) getDefaultWebXml(); // Is it explicitly suppressed, e.g. in embedded environment? if (Constants.NoDefaultWebXml.equals(defaultWebXml)) { return null; } return getWebXmlSource(defaultWebXml, getBaseDir()); } /** * Identify the host web.xml to be used and obtain an input source for * it. */ protected InputSource getHostWebXmlSource() { File hostConfigBase = getHostConfigBase(); if (!hostConfigBase.exists()) return null; return getWebXmlSource(Constants.HostWebXml, hostConfigBase.getPath()); } /** * Identify the application web.xml to be used and obtain an input source * for it. */ protected InputSource getContextWebXmlSource() { InputStream stream = null; InputSource source = null; URL url = null; String altDDName = null; // Open the application web.xml file, if it exists ServletContext servletContext = context.getServletContext(); if (servletContext != null) { altDDName = (String)servletContext.getAttribute( Globals.ALT_DD_ATTR); if (altDDName != null) { try { stream = new FileInputStream(altDDName); url = new File(altDDName).toURI().toURL(); } catch (FileNotFoundException e) { log.error(sm.getString("contextConfig.altDDNotFound", altDDName)); } catch (MalformedURLException e) { log.error(sm.getString("contextConfig.applicationUrl")); } } else { stream = servletContext.getResourceAsStream (Constants.ApplicationWebXml); try { url = servletContext.getResource( Constants.ApplicationWebXml); } catch (MalformedURLException e) { log.error(sm.getString("contextConfig.applicationUrl")); } } } if (stream == null || url == null) { if (log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.applicationMissing") + " " + context); } } else { source = new InputSource(url.toExternalForm()); source.setByteStream(stream); } return source; } /** * * @param filename Name of the file (possibly with one or more leading path * segments) to read * @param path Location that filename is relative to */ protected InputSource getWebXmlSource(String filename, String path) { File file = new File(filename); if (!file.isAbsolute()) { file = new File(path, filename); } InputStream stream = null; InputSource source = null; try { if (!file.exists()) { // Use getResource and getResourceAsStream stream = getClass().getClassLoader().getResourceAsStream(filename); if(stream != null) { source = new InputSource(getClass().getClassLoader().getResource( filename).toURI().toString()); } } else { source = new InputSource(file.getAbsoluteFile().toURI().toString()); stream = new FileInputStream(file); } if (stream != null && source != null) { source.setByteStream(stream); } } catch (Exception e) { log.error(sm.getString( "contextConfig.defaultError", filename, file), e); } return source; } /** * Parses the given source and stores the parsed data in the given web.xml * representation. The byte stream will be closed at the end of the parse * operation. * * @param source Input source containing the XML data to be parsed * @param dest The object representation of common elements of web.xml and * web-fragment.xml * @param fragment Specifies whether the source is web-fragment.xml or * web.xml */ protected void parseWebXml(InputSource source, WebXml dest, boolean fragment) { if (source == null) return; XmlErrorHandler handler = new XmlErrorHandler(); Digester digester; WebRuleSet ruleSet; if (fragment) { digester = webFragmentDigester; ruleSet = webFragmentRuleSet; } else { digester = webDigester; ruleSet = webRuleSet; } digester.push(dest); digester.setErrorHandler(handler); if(log.isDebugEnabled()) { log.debug(sm.getString("contextConfig.applicationStart", source.getSystemId())); } try { digester.parse(source); if (handler.getWarnings().size() > 0 || handler.getErrors().size() > 0) { ok = false; handler.logFindings(log, source.getSystemId()); } } catch (SAXParseException e) { log.error(sm.getString("contextConfig.applicationParse", source.getSystemId()), e); log.error(sm.getString("contextConfig.applicationPosition", "" + e.getLineNumber(), "" + e.getColumnNumber())); ok = false; } catch (Exception e) { log.error(sm.getString("contextConfig.applicationParse", source.getSystemId()), e); ok = false; } finally { digester.reset(); ruleSet.recycle(); InputStream is = source.getByteStream(); if (is != null) { try { is.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } } /** * Scan /WEB-INF/lib for JARs and for each one found add it and any * /META-INF/web-fragment.xml to the resulting Map. web-fragment.xml files * will be parsed before being added to the map. Every JAR will be added and * null will be used if no web-fragment.xml was found. Any JARs * known not contain fragments will be skipped. * * @return A map of JAR name to processed web fragment (if any) */ protected Map processJarsForWebFragments(WebXml application) { JarScanner jarScanner = context.getJarScanner(); boolean parseRequired = true; Set absoluteOrder = application.getAbsoluteOrdering(); if (absoluteOrder != null && absoluteOrder.isEmpty() && !context.getXmlValidation()) { // Skip parsing when there is an empty absolute ordering and // validation is not enabled parseRequired = false; } FragmentJarScannerCallback callback = new FragmentJarScannerCallback(parseRequired); jarScanner.scan(context.getServletContext(), context.getLoader().getClassLoader(), callback, pluggabilityJarsToSkip); return callback.getFragments(); } protected void processAnnotations(Set fragments, boolean handlesTypesOnly) { for(WebXml fragment : fragments) { WebXml annotations = new WebXml(); // no impact on distributable annotations.setDistributable(true); URL url = fragment.getURL(); processAnnotationsUrl(url, annotations, (handlesTypesOnly || fragment.isMetadataComplete())); Set set = new HashSet(); set.add(annotations); // Merge annotations into fragment - fragment takes priority fragment.merge(set); } } protected void processAnnotationsUrl(URL url, WebXml fragment, boolean handlesTypesOnly) { if (url == null) { // Nothing to do. return; } else if ("jar".equals(url.getProtocol())) { processAnnotationsJar(url, fragment, handlesTypesOnly); } else if ("jndi".equals(url.getProtocol())) { processAnnotationsJndi(url, fragment, handlesTypesOnly); } else if ("file".equals(url.getProtocol())) { try { processAnnotationsFile( new File(url.toURI()), fragment, handlesTypesOnly); } catch (URISyntaxException e) { log.error(sm.getString("contextConfig.fileUrl", url), e); } } else { log.error(sm.getString("contextConfig.unknownUrlProtocol", url.getProtocol(), url)); } } protected void processAnnotationsJar(URL url, WebXml fragment, boolean handlesTypesOnly) { Jar jar = null; InputStream is; try { jar = JarFactory.newInstance(url); jar.nextEntry(); String entryName = jar.getEntryName(); while (entryName != null) { if (entryName.endsWith(".class")) { is = null; try { is = jar.getEntryInputStream(); processAnnotationsStream( is, fragment, handlesTypesOnly); } catch (IOException e) { log.error(sm.getString("contextConfig.inputStreamJar", entryName, url),e); } catch (ClassFormatException e) { log.error(sm.getString("contextConfig.inputStreamJar", entryName, url),e); } finally { if (is != null) { try { is.close(); } catch (IOException ioe) { // Ignore } } } } jar.nextEntry(); entryName = jar.getEntryName(); } } catch (IOException e) { log.error(sm.getString("contextConfig.jarFile", url), e); } finally { if (jar != null) { jar.close(); } } } protected void processAnnotationsJndi(URL url, WebXml fragment, boolean handlesTypesOnly) { try { URLConnection urlConn = url.openConnection(); DirContextURLConnection dcUrlConn; if (!(urlConn instanceof DirContextURLConnection)) { // This should never happen sm.getString("contextConfig.jndiUrlNotDirContextConn", url); return; } dcUrlConn = (DirContextURLConnection) urlConn; dcUrlConn.setUseCaches(false); String type = dcUrlConn.getHeaderField(ResourceAttributes.TYPE); if (ResourceAttributes.COLLECTION_TYPE.equals(type)) { // Collection Enumeration dirs = dcUrlConn.list(); while (dirs.hasMoreElements()) { String dir = dirs.nextElement(); URL dirUrl = new URL(url.toString() + '/' + dir); processAnnotationsJndi(dirUrl, fragment, handlesTypesOnly); } } else { // Single file if (url.getPath().endsWith(".class")) { InputStream is = null; try { is = dcUrlConn.getInputStream(); processAnnotationsStream( is, fragment, handlesTypesOnly); } catch (IOException e) { log.error(sm.getString("contextConfig.inputStreamJndi", url),e); } catch (ClassFormatException e) { log.error(sm.getString("contextConfig.inputStreamJndi", url),e); } finally { if (is != null) { try { is.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } } } } catch (IOException e) { log.error(sm.getString("contextConfig.jndiUrl", url), e); } } protected void processAnnotationsFile(File file, WebXml fragment, boolean handlesTypesOnly) { if (file.isDirectory()) { String[] dirs = file.list(); for (String dir : dirs) { processAnnotationsFile( new File(file,dir), fragment, handlesTypesOnly); } } else if (file.canRead() && file.getName().endsWith(".class")) { FileInputStream fis = null; try { fis = new FileInputStream(file); processAnnotationsStream(fis, fragment, handlesTypesOnly); } catch (IOException e) { log.error(sm.getString("contextConfig.inputStreamFile", file.getAbsolutePath()),e); } catch (ClassFormatException e) { log.error(sm.getString("contextConfig.inputStreamFile", file.getAbsolutePath()),e); } finally { if (fis != null) { try { fis.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } } } } } protected void processAnnotationsStream(InputStream is, WebXml fragment, boolean handlesTypesOnly) throws ClassFormatException, IOException { ClassParser parser = new ClassParser(is, null); JavaClass clazz = parser.parse(); checkHandlesTypes(clazz); if (handlesTypesOnly) { return; } String className = clazz.getClassName(); AnnotationEntry[] annotationsEntries = clazz.getAnnotationEntries(); for (AnnotationEntry ae : annotationsEntries) { String type = ae.getAnnotationType(); if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) { processAnnotationWebServlet(className, ae, fragment); }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) { processAnnotationWebFilter(className, ae, fragment); }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) { fragment.addListener(className); } else { // Unknown annotation - ignore } } } /** * For classes packaged with the web application, the class and each * super class needs to be checked for a match with {@link HandlesTypes} or * for an annotation that matches {@link HandlesTypes}. * @param javaClass */ protected void checkHandlesTypes(JavaClass javaClass) { // Skip this if we can if (typeInitializerMap.size() == 0) return; if ((javaClass.getAccessFlags() & org.apache.tomcat.util.bcel.Constants.ACC_ANNOTATION) > 0) { // Skip annotations. return; } String className = javaClass.getClassName(); Class clazz = null; if (handlesTypesNonAnnotations) { // This *might* be match for a HandlesType. populateJavaClassCache(className, javaClass); JavaClassCacheEntry entry = javaClassCache.get(className); if (entry.getSciSet() == null) { try { populateSCIsForCacheEntry(entry); } catch (StackOverflowError soe) { throw new IllegalStateException(sm.getString( "contextConfig.annotationsStackOverflow", context.getName(), classHierarchyToString(className, entry))); } } if (entry.getSciSet().size() > 0) { // Need to try and load the class clazz = Introspection.loadClass(context, className); if (clazz == null) { // Can't load the class so no point continuing return; } for (ServletContainerInitializer sci : entry.getSciSet()) { Set> classes = initializerClassMap.get(sci); if (classes == null) { classes = new HashSet>(); initializerClassMap.put(sci, classes); } classes.add(clazz); } } } if (handlesTypesAnnotations) { for (Map.Entry, Set> entry : typeInitializerMap.entrySet()) { if (entry.getKey().isAnnotation()) { AnnotationEntry[] annotationEntries = javaClass.getAnnotationEntries(); for (AnnotationEntry annotationEntry : annotationEntries) { if (entry.getKey().getName().equals( getClassName(annotationEntry.getAnnotationType()))) { if (clazz == null) { clazz = Introspection.loadClass( context, className); if (clazz == null) { // Can't load the class so no point // continuing return; } } for (ServletContainerInitializer sci : entry.getValue()) { initializerClassMap.get(sci).add(clazz); } break; } } } } } } private String classHierarchyToString(String className, JavaClassCacheEntry entry) { JavaClassCacheEntry start = entry; StringBuilder msg = new StringBuilder(className); msg.append("->"); String parentName = entry.getSuperclassName(); JavaClassCacheEntry parent = javaClassCache.get(parentName); int count = 0; while (count < 100 && parent != null && parent != start) { msg.append(parentName); msg.append("->"); count ++; parentName = parent.getSuperclassName(); parent = javaClassCache.get(parentName); } msg.append(parentName); return msg.toString(); } private void populateJavaClassCache(String className, JavaClass javaClass) { if (javaClassCache.containsKey(className)) { return; } // Add this class to the cache javaClassCache.put(className, new JavaClassCacheEntry(javaClass)); populateJavaClassCache(javaClass.getSuperclassName()); for (String iterface : javaClass.getInterfaceNames()) { populateJavaClassCache(iterface); } } private void populateJavaClassCache(String className) { if (!javaClassCache.containsKey(className)) { String name = className.replace('.', '/') + ".class"; InputStream is = context.getLoader().getClassLoader().getResourceAsStream(name); if (is == null) { return; } ClassParser parser = new ClassParser(is, null); try { JavaClass clazz = parser.parse(); populateJavaClassCache(clazz.getClassName(), clazz); } catch (ClassFormatException e) { log.debug(sm.getString("contextConfig.invalidSciHandlesTypes", className), e); } catch (IOException e) { log.debug(sm.getString("contextConfig.invalidSciHandlesTypes", className), e); } finally { try { is.close(); } catch (IOException e) { // ignore } } } } private void populateSCIsForCacheEntry(JavaClassCacheEntry cacheEntry) { Set result = new HashSet(); // Super class String superClassName = cacheEntry.getSuperclassName(); JavaClassCacheEntry superClassCacheEntry = javaClassCache.get(superClassName); // Avoid an infinite loop with java.lang.Object if (cacheEntry.equals(superClassCacheEntry)) { cacheEntry.setSciSet(new HashSet()); return; } // May be null of the class is not present or could not be loaded. if (superClassCacheEntry != null) { if (superClassCacheEntry.getSciSet() == null) { populateSCIsForCacheEntry(superClassCacheEntry); } result.addAll(superClassCacheEntry.getSciSet()); } result.addAll(getSCIsForClass(superClassName)); // Interfaces for (String interfaceName : cacheEntry.getInterfaceNames()) { JavaClassCacheEntry interfaceEntry = javaClassCache.get(interfaceName); // A null could mean that the class not present in application or // that there is nothing of interest. Either way, nothing to do here // so move along if (interfaceEntry != null) { if (interfaceEntry.getSciSet() == null) { populateSCIsForCacheEntry(interfaceEntry); } result.addAll(interfaceEntry.getSciSet()); } result.addAll(getSCIsForClass(interfaceName)); } cacheEntry.setSciSet(result); } private Set getSCIsForClass(String className) { for (Map.Entry, Set> entry : typeInitializerMap.entrySet()) { Class clazz = entry.getKey(); if (!clazz.isAnnotation()) { if (clazz.getName().equals(className)) { return entry.getValue(); } } } return Collections.emptySet(); } private static final String getClassName(String internalForm) { if (!internalForm.startsWith("L")) { return internalForm; } // Assume starts with L, ends with ; and uses / rather than . return internalForm.substring(1, internalForm.length() - 1).replace('/', '.'); } protected void processAnnotationWebServlet(String className, AnnotationEntry ae, WebXml fragment) { String servletName = null; // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81 ElementValuePair[] evps = ae.getElementValuePairs(); for (ElementValuePair evp : evps) { String name = evp.getNameString(); if ("name".equals(name)) { servletName = evp.getValue().stringifyValue(); break; } } if (servletName == null) { // classname is default servletName as annotation has no name! servletName = className; } ServletDef servletDef = fragment.getServlets().get(servletName); boolean isWebXMLservletDef; if (servletDef == null) { servletDef = new ServletDef(); servletDef.setServletName(servletName); servletDef.setServletClass(className); isWebXMLservletDef = false; } else { isWebXMLservletDef = true; } boolean urlPatternsSet = false; String[] urlPatterns = null; // ElementValuePair[] evps = ae.getElementValuePairs(); for (ElementValuePair evp : evps) { String name = evp.getNameString(); if ("value".equals(name) || "urlPatterns".equals(name)) { if (urlPatternsSet) { throw new IllegalArgumentException(sm.getString( "contextConfig.urlPatternValue", className)); } urlPatternsSet = true; urlPatterns = processAnnotationsStringArray(evp.getValue()); } else if ("description".equals(name)) { if (servletDef.getDescription() == null) { servletDef.setDescription(evp.getValue().stringifyValue()); } } else if ("displayName".equals(name)) { if (servletDef.getDisplayName() == null) { servletDef.setDisplayName(evp.getValue().stringifyValue()); } } else if ("largeIcon".equals(name)) { if (servletDef.getLargeIcon() == null) { servletDef.setLargeIcon(evp.getValue().stringifyValue()); } } else if ("smallIcon".equals(name)) { if (servletDef.getSmallIcon() == null) { servletDef.setSmallIcon(evp.getValue().stringifyValue()); } } else if ("asyncSupported".equals(name)) { if (servletDef.getAsyncSupported() == null) { servletDef.setAsyncSupported(evp.getValue() .stringifyValue()); } } else if ("loadOnStartup".equals(name)) { if (servletDef.getLoadOnStartup() == null) { servletDef .setLoadOnStartup(evp.getValue().stringifyValue()); } } else if ("initParams".equals(name)) { Map initParams = processAnnotationWebInitParams(evp .getValue()); if (isWebXMLservletDef) { Map webXMLInitParams = servletDef .getParameterMap(); for (Map.Entry entry : initParams .entrySet()) { if (webXMLInitParams.get(entry.getKey()) == null) { servletDef.addInitParameter(entry.getKey(), entry .getValue()); } } } else { for (Map.Entry entry : initParams .entrySet()) { servletDef.addInitParameter(entry.getKey(), entry .getValue()); } } } } if (!isWebXMLservletDef && urlPatterns != null) { fragment.addServlet(servletDef); } if (urlPatterns != null) { if (!fragment.getServletMappings().containsValue(servletName)) { for (String urlPattern : urlPatterns) { fragment.addServletMapping(urlPattern, servletName); } } } } /** * process filter annotation and merge with existing one! * FIXME: refactoring method too long and has redundant subroutines with * processAnnotationWebServlet! * @param className * @param ae * @param fragment */ protected void processAnnotationWebFilter(String className, AnnotationEntry ae, WebXml fragment) { String filterName = null; // must search for name s. Spec Servlet API 3.0 - 8.2.3.3.n.ii page 81 ElementValuePair[] evps = ae.getElementValuePairs(); for (ElementValuePair evp : evps) { String name = evp.getNameString(); if ("filterName".equals(name)) { filterName = evp.getValue().stringifyValue(); break; } } if (filterName == null) { // classname is default filterName as annotation has no name! filterName = className; } FilterDef filterDef = fragment.getFilters().get(filterName); FilterMap filterMap = new FilterMap(); boolean isWebXMLfilterDef; if (filterDef == null) { filterDef = new FilterDef(); filterDef.setFilterName(filterName); filterDef.setFilterClass(className); isWebXMLfilterDef = false; } else { isWebXMLfilterDef = true; } boolean urlPatternsSet = false; boolean servletNamesSet = false; boolean dispatchTypesSet = false; String[] urlPatterns = null; for (ElementValuePair evp : evps) { String name = evp.getNameString(); if ("value".equals(name) || "urlPatterns".equals(name)) { if (urlPatternsSet) { throw new IllegalArgumentException(sm.getString( "contextConfig.urlPatternValue", className)); } urlPatterns = processAnnotationsStringArray(evp.getValue()); urlPatternsSet = urlPatterns.length > 0; for (String urlPattern : urlPatterns) { filterMap.addURLPattern(urlPattern); } } else if ("servletNames".equals(name)) { String[] servletNames = processAnnotationsStringArray(evp .getValue()); servletNamesSet = servletNames.length > 0; for (String servletName : servletNames) { filterMap.addServletName(servletName); } } else if ("dispatcherTypes".equals(name)) { String[] dispatcherTypes = processAnnotationsStringArray(evp .getValue()); dispatchTypesSet = dispatcherTypes.length > 0; for (String dispatcherType : dispatcherTypes) { filterMap.setDispatcher(dispatcherType); } } else if ("description".equals(name)) { if (filterDef.getDescription() == null) { filterDef.setDescription(evp.getValue().stringifyValue()); } } else if ("displayName".equals(name)) { if (filterDef.getDisplayName() == null) { filterDef.setDisplayName(evp.getValue().stringifyValue()); } } else if ("largeIcon".equals(name)) { if (filterDef.getLargeIcon() == null) { filterDef.setLargeIcon(evp.getValue().stringifyValue()); } } else if ("smallIcon".equals(name)) { if (filterDef.getSmallIcon() == null) { filterDef.setSmallIcon(evp.getValue().stringifyValue()); } } else if ("asyncSupported".equals(name)) { if (filterDef.getAsyncSupported() == null) { filterDef .setAsyncSupported(evp.getValue().stringifyValue()); } } else if ("initParams".equals(name)) { Map initParams = processAnnotationWebInitParams(evp .getValue()); if (isWebXMLfilterDef) { Map webXMLInitParams = filterDef .getParameterMap(); for (Map.Entry entry : initParams .entrySet()) { if (webXMLInitParams.get(entry.getKey()) == null) { filterDef.addInitParameter(entry.getKey(), entry .getValue()); } } } else { for (Map.Entry entry : initParams .entrySet()) { filterDef.addInitParameter(entry.getKey(), entry .getValue()); } } } } if (!isWebXMLfilterDef) { fragment.addFilter(filterDef); if (urlPatternsSet || servletNamesSet) { filterMap.setFilterName(filterName); fragment.addFilterMapping(filterMap); } } if (urlPatternsSet || dispatchTypesSet) { Set fmap = fragment.getFilterMappings(); FilterMap descMap = null; for (FilterMap map : fmap) { if (filterName.equals(map.getFilterName())) { descMap = map; break; } } if (descMap != null) { String[] urlsPatterns = descMap.getURLPatterns(); if (urlPatternsSet && (urlsPatterns == null || urlsPatterns.length == 0)) { for (String urlPattern : filterMap.getURLPatterns()) { descMap.addURLPattern(urlPattern); } } String[] dispatcherNames = descMap.getDispatcherNames(); if (dispatchTypesSet && (dispatcherNames == null || dispatcherNames.length == 0)) { for (String dis : filterMap.getDispatcherNames()) { descMap.setDispatcher(dis); } } } } } protected String[] processAnnotationsStringArray(ElementValue ev) { ArrayList values = new ArrayList(); if (ev instanceof ArrayElementValue) { ElementValue[] arrayValues = ((ArrayElementValue) ev).getElementValuesArray(); for (ElementValue value : arrayValues) { values.add(value.stringifyValue()); } } else { values.add(ev.stringifyValue()); } String[] result = new String[values.size()]; return values.toArray(result); } protected Map processAnnotationWebInitParams( ElementValue ev) { Map result = new HashMap(); if (ev instanceof ArrayElementValue) { ElementValue[] arrayValues = ((ArrayElementValue) ev).getElementValuesArray(); for (ElementValue value : arrayValues) { if (value instanceof AnnotationElementValue) { ElementValuePair[] evps = ((AnnotationElementValue) value).getAnnotationEntry().getElementValuePairs(); String initParamName = null; String initParamValue = null; for (ElementValuePair evp : evps) { if ("name".equals(evp.getNameString())) { initParamName = evp.getValue().stringifyValue(); } else if ("value".equals(evp.getNameString())) { initParamValue = evp.getValue().stringifyValue(); } else { // Ignore } } result.put(initParamName, initParamValue); } } } return result; } private class FragmentJarScannerCallback implements JarScannerCallback { private static final String FRAGMENT_LOCATION = "META-INF/web-fragment.xml"; private Map fragments = new HashMap(); private final boolean parseRequired; public FragmentJarScannerCallback(boolean parseRequired) { this.parseRequired = parseRequired; } @Override public void scan(JarURLConnection jarConn) throws IOException { URL url = jarConn.getURL(); URL resourceURL = jarConn.getJarFileURL(); Jar jar = null; InputStream is = null; WebXml fragment = new WebXml(); try { jar = JarFactory.newInstance(url); if (parseRequired || context.getXmlValidation()) { is = jar.getInputStream(FRAGMENT_LOCATION); } if (is == null) { // If there is no web-fragment.xml to process there is no // impact on distributable fragment.setDistributable(true); } else { InputSource source = new InputSource( "jar:" + resourceURL.toString() + "!/" + FRAGMENT_LOCATION); source.setByteStream(is); parseWebXml(source, fragment, true); } } finally { if (jar != null) { jar.close(); } fragment.setURL(url); if (fragment.getName() == null) { fragment.setName(fragment.getURL().toString()); } fragment.setJarName(extractJarFileName(url)); fragments.put(fragment.getName(), fragment); } } private String extractJarFileName(URL input) { String url = input.toString(); if (url.endsWith("!/")) { // Remove it url = url.substring(0, url.length() - 2); } // File name will now be whatever is after the final / return url.substring(url.lastIndexOf('/') + 1); } @Override public void scan(File file) throws IOException { InputStream stream = null; WebXml fragment = new WebXml(); try { File fragmentFile = new File(file, FRAGMENT_LOCATION); if (fragmentFile.isFile()) { stream = new FileInputStream(fragmentFile); InputSource source = new InputSource(fragmentFile.toURI().toURL().toString()); source.setByteStream(stream); parseWebXml(source, fragment, true); } else { // If there is no web.xml, normal folder no impact on // distributable fragment.setDistributable(true); } } finally { fragment.setURL(file.toURI().toURL()); if (fragment.getName() == null) { fragment.setName(fragment.getURL().toString()); } fragment.setJarName(file.getName()); fragments.put(fragment.getName(), fragment); } } public Map getFragments() { return fragments; } } private static class DefaultWebXmlCacheEntry { private final WebXml webXml; private final long globalTimeStamp; private final long hostTimeStamp; public DefaultWebXmlCacheEntry(WebXml webXml, long globalTimeStamp, long hostTimeStamp) { this.webXml = webXml; this.globalTimeStamp = globalTimeStamp; this.hostTimeStamp = hostTimeStamp; } public WebXml getWebXml() { return webXml; } public long getGlobalTimeStamp() { return globalTimeStamp; } public long getHostTimeStamp() { return hostTimeStamp; } } private static class JavaClassCacheEntry { public final String superclassName; public final String[] interfaceNames; private Set sciSet = null; public JavaClassCacheEntry(JavaClass javaClass) { superclassName = javaClass.getSuperclassName(); interfaceNames = javaClass.getInterfaceNames(); } public String getSuperclassName() { return superclassName; } public String[] getInterfaceNames() { return interfaceNames; } public Set getSciSet() { return sciSet; } public void setSciSet(Set sciSet) { this.sciSet = sciSet; } } } tomcat7-7.0.52/java/org/apache/catalina/startup/SetNextNamingRule.java0000644000175100017510000000750112271471332025576 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.catalina.Context; import org.apache.catalina.deploy.NamingResources; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.digester.Rule; /** *

    Rule implementation that calls a method on the (top-1) (parent) * object, passing the top object (child) as an argument. It is * commonly used to establish parent-child relationships.

    * *

    This rule now supports more flexible method matching by default. * It is possible that this may break (some) code * written against release 1.1.1 or earlier. *

    */ public class SetNextNamingRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a "set next" rule with the specified method name. * * @param methodName Method name of the parent method to call * @param paramType Java class of the parent method's argument * (if you wish to use a primitive type, specify the corresponding * Java wrapper class instead, such as java.lang.Boolean * for a boolean parameter) */ public SetNextNamingRule(String methodName, String paramType) { this.methodName = methodName; this.paramType = paramType; } // ----------------------------------------------------- Instance Variables /** * The method name to call on the parent object. */ protected String methodName = null; /** * The Java class name of the parameter type expected by the method. */ protected String paramType = null; // --------------------------------------------------------- Public Methods /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { // Identify the objects to be used Object child = digester.peek(0); Object parent = digester.peek(1); NamingResources namingResources = null; if (parent instanceof Context) { namingResources = ((Context) parent).getNamingResources(); } else { namingResources = (NamingResources) parent; } // Call the specified method IntrospectionUtils.callMethod1(namingResources, methodName, child, paramType, digester.getClassLoader()); } /** * Render a printable version of this Rule. */ @Override public String toString() { StringBuilder sb = new StringBuilder("SetNextRule["); sb.append("methodName="); sb.append(methodName); sb.append(", paramType="); sb.append(paramType); sb.append("]"); return (sb.toString()); } } tomcat7-7.0.52/java/org/apache/catalina/startup/WebRuleSet.java0000644000175100017510000015331312274367456024264 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.lang.reflect.Method; import java.util.ArrayList; import org.apache.catalina.deploy.ContextEnvironment; import org.apache.catalina.deploy.ContextHandler; import org.apache.catalina.deploy.ContextService; import org.apache.catalina.deploy.ResourceBase; import org.apache.catalina.deploy.SecurityConstraint; import org.apache.catalina.deploy.ServletDef; import org.apache.catalina.deploy.WebXml; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.digester.CallMethodRule; import org.apache.tomcat.util.digester.CallParamRule; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.Rule; import org.apache.tomcat.util.digester.RuleSetBase; import org.apache.tomcat.util.digester.SetNextRule; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.Attributes; /** *

    RuleSet for processing the contents of a web application * deployment descriptor (/WEB-INF/web.xml) resource.

    * * @author Craig R. McClanahan */ public class WebRuleSet extends RuleSetBase { /** * The string resources for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; /** * The full pattern matching prefix, including the webapp or web-fragment * component, to use for matching elements */ protected String fullPrefix = null; /** * Flag that indicates if this ruleset is for a web-fragment.xml file or for * a web.xml file. */ protected boolean fragment = false; /** * The SetSessionConfig rule used to parse the web.xml */ protected SetSessionConfig sessionConfig = new SetSessionConfig(); /** * The SetLoginConfig rule used to parse the web.xml */ protected SetLoginConfig loginConfig = new SetLoginConfig(); /** * The SetJspConfig rule used to parse the web.xml */ protected SetJspConfig jspConfig = new SetJspConfig(); /** * The NameRule rule used to parse the web.xml */ protected NameRule name = new NameRule(); /** * The AbsoluteOrderingRule rule used to parse the web.xml */ protected AbsoluteOrderingRule absoluteOrdering; /** * The RelativeOrderingRule rule used to parse the web.xml */ protected RelativeOrderingRule relativeOrdering; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix and default fragment setting. */ public WebRuleSet() { this("", false); } /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public WebRuleSet(boolean fragment) { this("", fragment); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public WebRuleSet(String prefix, boolean fragment) { super(); this.namespaceURI = null; this.prefix = prefix; this.fragment = fragment; if(fragment) { fullPrefix = prefix + "web-fragment"; } else { fullPrefix = prefix + "web-app"; } absoluteOrdering = new AbsoluteOrderingRule(fragment); relativeOrdering = new RelativeOrderingRule(fragment); } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { digester.addRule(fullPrefix, new SetPublicIdRule("setPublicId")); digester.addRule(fullPrefix, new IgnoreAnnotationsRule()); digester.addRule(fullPrefix, new VersionRule()); // Required for both fragments and non-fragments digester.addRule(fullPrefix + "/absolute-ordering", absoluteOrdering); digester.addRule(fullPrefix + "/ordering", relativeOrdering); if (fragment) { // web-fragment.xml digester.addRule(fullPrefix + "/name", name); digester.addCallMethod(fullPrefix + "/ordering/after/name", "addAfterOrdering", 0); digester.addCallMethod(fullPrefix + "/ordering/after/others", "addAfterOrderingOthers"); digester.addCallMethod(fullPrefix + "/ordering/before/name", "addBeforeOrdering", 0); digester.addCallMethod(fullPrefix + "/ordering/before/others", "addBeforeOrderingOthers"); } else { // web.xml digester.addCallMethod(fullPrefix + "/absolute-ordering/name", "addAbsoluteOrdering", 0); digester.addCallMethod(fullPrefix + "/absolute-ordering/others", "addAbsoluteOrderingOthers"); } digester.addCallMethod(fullPrefix + "/context-param", "addContextParam", 2); digester.addCallParam(fullPrefix + "/context-param/param-name", 0); digester.addCallParam(fullPrefix + "/context-param/param-value", 1); digester.addCallMethod(fullPrefix + "/display-name", "setDisplayName", 0); digester.addRule(fullPrefix + "/distributable", new SetDistributableRule()); configureNamingRules(digester); digester.addObjectCreate(fullPrefix + "/error-page", "org.apache.catalina.deploy.ErrorPage"); digester.addSetNext(fullPrefix + "/error-page", "addErrorPage", "org.apache.catalina.deploy.ErrorPage"); digester.addCallMethod(fullPrefix + "/error-page/error-code", "setErrorCode", 0); digester.addCallMethod(fullPrefix + "/error-page/exception-type", "setExceptionType", 0); digester.addCallMethod(fullPrefix + "/error-page/location", "setLocation", 0); digester.addObjectCreate(fullPrefix + "/filter", "org.apache.catalina.deploy.FilterDef"); digester.addSetNext(fullPrefix + "/filter", "addFilter", "org.apache.catalina.deploy.FilterDef"); digester.addCallMethod(fullPrefix + "/filter/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/filter/display-name", "setDisplayName", 0); digester.addCallMethod(fullPrefix + "/filter/filter-class", "setFilterClass", 0); digester.addCallMethod(fullPrefix + "/filter/filter-name", "setFilterName", 0); digester.addCallMethod(fullPrefix + "/filter/icon/large-icon", "setLargeIcon", 0); digester.addCallMethod(fullPrefix + "/filter/icon/small-icon", "setSmallIcon", 0); digester.addCallMethod(fullPrefix + "/filter/async-supported", "setAsyncSupported", 0); digester.addCallMethod(fullPrefix + "/filter/init-param", "addInitParameter", 2); digester.addCallParam(fullPrefix + "/filter/init-param/param-name", 0); digester.addCallParam(fullPrefix + "/filter/init-param/param-value", 1); digester.addObjectCreate(fullPrefix + "/filter-mapping", "org.apache.catalina.deploy.FilterMap"); digester.addSetNext(fullPrefix + "/filter-mapping", "addFilterMapping", "org.apache.catalina.deploy.FilterMap"); digester.addCallMethod(fullPrefix + "/filter-mapping/filter-name", "setFilterName", 0); digester.addCallMethod(fullPrefix + "/filter-mapping/servlet-name", "addServletName", 0); digester.addCallMethod(fullPrefix + "/filter-mapping/url-pattern", "addURLPattern", 0); digester.addCallMethod(fullPrefix + "/filter-mapping/dispatcher", "setDispatcher", 0); digester.addCallMethod(fullPrefix + "/listener/listener-class", "addListener", 0); digester.addRule(fullPrefix + "/jsp-config", jspConfig); digester.addObjectCreate(fullPrefix + "/jsp-config/jsp-property-group", "org.apache.catalina.deploy.JspPropertyGroup"); digester.addSetNext(fullPrefix + "/jsp-config/jsp-property-group", "addJspPropertyGroup", "org.apache.catalina.deploy.JspPropertyGroup"); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/deferred-syntax-allowed-as-literal", "setDeferredSyntax", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/el-ignored", "setElIgnored", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/include-coda", "addIncludeCoda", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/include-prelude", "addIncludePrelude", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/is-xml", "setIsXml", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/page-encoding", "setPageEncoding", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/scripting-invalid", "setScriptingInvalid", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/trim-directive-whitespaces", "setTrimWhitespace", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/url-pattern", "addUrlPattern", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/default-content-type", "setDefaultContentType", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/buffer", "setBuffer", 0); digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/error-on-undeclared-namespace", "setErrorOnUndeclaredNamespace", 0); digester.addRule(fullPrefix + "/login-config", loginConfig); digester.addObjectCreate(fullPrefix + "/login-config", "org.apache.catalina.deploy.LoginConfig"); digester.addSetNext(fullPrefix + "/login-config", "setLoginConfig", "org.apache.catalina.deploy.LoginConfig"); digester.addCallMethod(fullPrefix + "/login-config/auth-method", "setAuthMethod", 0); digester.addCallMethod(fullPrefix + "/login-config/realm-name", "setRealmName", 0); digester.addCallMethod(fullPrefix + "/login-config/form-login-config/form-error-page", "setErrorPage", 0); digester.addCallMethod(fullPrefix + "/login-config/form-login-config/form-login-page", "setLoginPage", 0); digester.addCallMethod(fullPrefix + "/mime-mapping", "addMimeMapping", 2); digester.addCallParam(fullPrefix + "/mime-mapping/extension", 0); digester.addCallParam(fullPrefix + "/mime-mapping/mime-type", 1); digester.addObjectCreate(fullPrefix + "/security-constraint", "org.apache.catalina.deploy.SecurityConstraint"); digester.addSetNext(fullPrefix + "/security-constraint", "addSecurityConstraint", "org.apache.catalina.deploy.SecurityConstraint"); digester.addRule(fullPrefix + "/security-constraint/auth-constraint", new SetAuthConstraintRule()); digester.addCallMethod(fullPrefix + "/security-constraint/auth-constraint/role-name", "addAuthRole", 0); digester.addCallMethod(fullPrefix + "/security-constraint/display-name", "setDisplayName", 0); digester.addCallMethod(fullPrefix + "/security-constraint/user-data-constraint/transport-guarantee", "setUserConstraint", 0); digester.addObjectCreate(fullPrefix + "/security-constraint/web-resource-collection", "org.apache.catalina.deploy.SecurityCollection"); digester.addSetNext(fullPrefix + "/security-constraint/web-resource-collection", "addCollection", "org.apache.catalina.deploy.SecurityCollection"); digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/http-method", "addMethod", 0); digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/http-method-omission", "addOmittedMethod", 0); digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/url-pattern", "addPattern", 0); digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/web-resource-name", "setName", 0); digester.addCallMethod(fullPrefix + "/security-role/role-name", "addSecurityRole", 0); digester.addRule(fullPrefix + "/servlet", new ServletDefCreateRule()); digester.addSetNext(fullPrefix + "/servlet", "addServlet", "org.apache.catalina.deploy.ServletDef"); digester.addCallMethod(fullPrefix + "/servlet/init-param", "addInitParameter", 2); digester.addCallParam(fullPrefix + "/servlet/init-param/param-name", 0); digester.addCallParam(fullPrefix + "/servlet/init-param/param-value", 1); digester.addCallMethod(fullPrefix + "/servlet/jsp-file", "setJspFile", 0); digester.addCallMethod(fullPrefix + "/servlet/load-on-startup", "setLoadOnStartup", 0); digester.addCallMethod(fullPrefix + "/servlet/run-as/role-name", "setRunAs", 0); digester.addObjectCreate(fullPrefix + "/servlet/security-role-ref", "org.apache.catalina.deploy.SecurityRoleRef"); digester.addSetNext(fullPrefix + "/servlet/security-role-ref", "addSecurityRoleRef", "org.apache.catalina.deploy.SecurityRoleRef"); digester.addCallMethod(fullPrefix + "/servlet/security-role-ref/role-link", "setLink", 0); digester.addCallMethod(fullPrefix + "/servlet/security-role-ref/role-name", "setName", 0); digester.addCallMethod(fullPrefix + "/servlet/servlet-class", "setServletClass", 0); digester.addCallMethod(fullPrefix + "/servlet/servlet-name", "setServletName", 0); digester.addObjectCreate(fullPrefix + "/servlet/multipart-config", "org.apache.catalina.deploy.MultipartDef"); digester.addSetNext(fullPrefix + "/servlet/multipart-config", "setMultipartDef", "org.apache.catalina.deploy.MultipartDef"); digester.addCallMethod(fullPrefix + "/servlet/multipart-config/location", "setLocation", 0); digester.addCallMethod(fullPrefix + "/servlet/multipart-config/max-file-size", "setMaxFileSize", 0); digester.addCallMethod(fullPrefix + "/servlet/multipart-config/max-request-size", "setMaxRequestSize", 0); digester.addCallMethod(fullPrefix + "/servlet/multipart-config/file-size-threshold", "setFileSizeThreshold", 0); digester.addCallMethod(fullPrefix + "/servlet/async-supported", "setAsyncSupported", 0); digester.addCallMethod(fullPrefix + "/servlet/enabled", "setEnabled", 0); digester.addRule(fullPrefix + "/servlet-mapping", new CallMethodMultiRule("addServletMapping", 2, 0)); digester.addCallParam(fullPrefix + "/servlet-mapping/servlet-name", 1); digester.addRule(fullPrefix + "/servlet-mapping/url-pattern", new CallParamMultiRule(0)); digester.addRule(fullPrefix + "/session-config", sessionConfig); digester.addObjectCreate(fullPrefix + "/session-config", "org.apache.catalina.deploy.SessionConfig"); digester.addSetNext(fullPrefix + "/session-config", "setSessionConfig", "org.apache.catalina.deploy.SessionConfig"); digester.addCallMethod(fullPrefix + "/session-config/session-timeout", "setSessionTimeout", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/name", "setCookieName", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/domain", "setCookieDomain", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/path", "setCookiePath", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/comment", "setCookieComment", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/http-only", "setCookieHttpOnly", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/secure", "setCookieSecure", 0); digester.addCallMethod(fullPrefix + "/session-config/cookie-config/max-age", "setCookieMaxAge", 0); digester.addCallMethod(fullPrefix + "/session-config/tracking-mode", "addSessionTrackingMode", 0); // Taglibs pre Servlet 2.4 digester.addRule(fullPrefix + "/taglib", new TaglibLocationRule(false)); digester.addCallMethod(fullPrefix + "/taglib", "addTaglib", 2); digester.addCallParam(fullPrefix + "/taglib/taglib-location", 1); digester.addCallParam(fullPrefix + "/taglib/taglib-uri", 0); // Taglibs Servlet 2.4 onwards digester.addRule(fullPrefix + "/jsp-config/taglib", new TaglibLocationRule(true)); digester.addCallMethod(fullPrefix + "/jsp-config/taglib", "addTaglib", 2); digester.addCallParam(fullPrefix + "/jsp-config/taglib/taglib-location", 1); digester.addCallParam(fullPrefix + "/jsp-config/taglib/taglib-uri", 0); digester.addCallMethod(fullPrefix + "/welcome-file-list/welcome-file", "addWelcomeFile", 0); digester.addCallMethod(fullPrefix + "/locale-encoding-mapping-list/locale-encoding-mapping", "addLocaleEncodingMapping", 2); digester.addCallParam(fullPrefix + "/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0); digester.addCallParam(fullPrefix + "/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1); digester.addRule(fullPrefix + "/post-construct", new LifecycleCallbackRule("addPostConstructMethods", 2, true)); digester.addCallParam(fullPrefix + "/post-construct/lifecycle-callback-class", 0); digester.addCallParam(fullPrefix + "/post-construct/lifecycle-callback-method", 1); digester.addRule(fullPrefix + "/pre-destroy", new LifecycleCallbackRule("addPreDestroyMethods", 2, false)); digester.addCallParam(fullPrefix + "/pre-destroy/lifecycle-callback-class", 0); digester.addCallParam(fullPrefix + "/pre-destroy/lifecycle-callback-method", 1); } protected void configureNamingRules(Digester digester) { //ejb-local-ref digester.addObjectCreate(fullPrefix + "/ejb-local-ref", "org.apache.catalina.deploy.ContextLocalEjb"); digester.addSetNext(fullPrefix + "/ejb-local-ref", "addEjbLocalRef", "org.apache.catalina.deploy.ContextLocalEjb"); digester.addCallMethod(fullPrefix + "/ejb-local-ref/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/ejb-local-ref/ejb-link", "setLink", 0); digester.addCallMethod(fullPrefix + "/ejb-local-ref/ejb-ref-name", "setName", 0); digester.addCallMethod(fullPrefix + "/ejb-local-ref/ejb-ref-type", "setType", 0); digester.addCallMethod(fullPrefix + "/ejb-local-ref/local", "setLocal", 0); digester.addCallMethod(fullPrefix + "/ejb-local-ref/local-home", "setHome", 0); digester.addRule(fullPrefix + "/ejb-local-ref/mapped-name", new MappedNameRule()); configureInjectionRules(digester, "web-app/ejb-local-ref/"); //ejb-ref digester.addObjectCreate(fullPrefix + "/ejb-ref", "org.apache.catalina.deploy.ContextEjb"); digester.addSetNext(fullPrefix + "/ejb-ref", "addEjbRef", "org.apache.catalina.deploy.ContextEjb"); digester.addCallMethod(fullPrefix + "/ejb-ref/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/ejb-ref/ejb-link", "setLink", 0); digester.addCallMethod(fullPrefix + "/ejb-ref/ejb-ref-name", "setName", 0); digester.addCallMethod(fullPrefix + "/ejb-ref/ejb-ref-type", "setType", 0); digester.addCallMethod(fullPrefix + "/ejb-ref/home", "setHome", 0); digester.addCallMethod(fullPrefix + "/ejb-ref/remote", "setRemote", 0); digester.addRule(fullPrefix + "/ejb-ref/mapped-name", new MappedNameRule()); configureInjectionRules(digester, "web-app/ejb-ref/"); //env-entry digester.addObjectCreate(fullPrefix + "/env-entry", "org.apache.catalina.deploy.ContextEnvironment"); digester.addSetNext(fullPrefix + "/env-entry", "addEnvEntry", "org.apache.catalina.deploy.ContextEnvironment"); digester.addRule(fullPrefix + "/env-entry", new SetOverrideRule()); digester.addCallMethod(fullPrefix + "/env-entry/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/env-entry/env-entry-name", "setName", 0); digester.addCallMethod(fullPrefix + "/env-entry/env-entry-type", "setType", 0); digester.addCallMethod(fullPrefix + "/env-entry/env-entry-value", "setValue", 0); digester.addRule(fullPrefix + "/env-entry/mapped-name", new MappedNameRule()); configureInjectionRules(digester, "web-app/env-entry/"); //resource-env-ref digester.addObjectCreate(fullPrefix + "/resource-env-ref", "org.apache.catalina.deploy.ContextResourceEnvRef"); digester.addSetNext(fullPrefix + "/resource-env-ref", "addResourceEnvRef", "org.apache.catalina.deploy.ContextResourceEnvRef"); digester.addCallMethod(fullPrefix + "/resource-env-ref/resource-env-ref-name", "setName", 0); digester.addCallMethod(fullPrefix + "/resource-env-ref/resource-env-ref-type", "setType", 0); digester.addRule(fullPrefix + "/resource-env-ref/mapped-name", new MappedNameRule()); configureInjectionRules(digester, "web-app/resource-env-ref/"); //message-destination digester.addObjectCreate(fullPrefix + "/message-destination", "org.apache.catalina.deploy.MessageDestination"); digester.addSetNext(fullPrefix + "/message-destination", "addMessageDestination", "org.apache.catalina.deploy.MessageDestination"); digester.addCallMethod(fullPrefix + "/message-destination/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/message-destination/display-name", "setDisplayName", 0); digester.addCallMethod(fullPrefix + "/message-destination/icon/large-icon", "setLargeIcon", 0); digester.addCallMethod(fullPrefix + "/message-destination/icon/small-icon", "setSmallIcon", 0); digester.addCallMethod(fullPrefix + "/message-destination/message-destination-name", "setName", 0); digester.addRule(fullPrefix + "/message-destination/mapped-name", new MappedNameRule()); //message-destination-ref digester.addObjectCreate(fullPrefix + "/message-destination-ref", "org.apache.catalina.deploy.MessageDestinationRef"); digester.addSetNext(fullPrefix + "/message-destination-ref", "addMessageDestinationRef", "org.apache.catalina.deploy.MessageDestinationRef"); digester.addCallMethod(fullPrefix + "/message-destination-ref/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/message-destination-ref/message-destination-link", "setLink", 0); digester.addCallMethod(fullPrefix + "/message-destination-ref/message-destination-ref-name", "setName", 0); digester.addCallMethod(fullPrefix + "/message-destination-ref/message-destination-type", "setType", 0); digester.addCallMethod(fullPrefix + "/message-destination-ref/message-destination-usage", "setUsage", 0); digester.addRule(fullPrefix + "/message-destination-ref/mapped-name", new MappedNameRule()); configureInjectionRules(digester, "web-app/message-destination-ref/"); //resource-ref digester.addObjectCreate(fullPrefix + "/resource-ref", "org.apache.catalina.deploy.ContextResource"); digester.addSetNext(fullPrefix + "/resource-ref", "addResourceRef", "org.apache.catalina.deploy.ContextResource"); digester.addCallMethod(fullPrefix + "/resource-ref/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/resource-ref/res-auth", "setAuth", 0); digester.addCallMethod(fullPrefix + "/resource-ref/res-ref-name", "setName", 0); digester.addCallMethod(fullPrefix + "/resource-ref/res-sharing-scope", "setScope", 0); digester.addCallMethod(fullPrefix + "/resource-ref/res-type", "setType", 0); digester.addRule(fullPrefix + "/resource-ref/mapped-name", new MappedNameRule()); configureInjectionRules(digester, "web-app/resource-ref/"); //service-ref digester.addObjectCreate(fullPrefix + "/service-ref", "org.apache.catalina.deploy.ContextService"); digester.addSetNext(fullPrefix + "/service-ref", "addServiceRef", "org.apache.catalina.deploy.ContextService"); digester.addCallMethod(fullPrefix + "/service-ref/description", "setDescription", 0); digester.addCallMethod(fullPrefix + "/service-ref/display-name", "setDisplayname", 0); digester.addCallMethod(fullPrefix + "/service-ref/icon/large-icon", "setLargeIcon", 0); digester.addCallMethod(fullPrefix + "/service-ref/icon/small-icon", "setSmallIcon", 0); digester.addCallMethod(fullPrefix + "/service-ref/service-ref-name", "setName", 0); digester.addCallMethod(fullPrefix + "/service-ref/service-interface", "setInterface", 0); digester.addCallMethod(fullPrefix + "/service-ref/service-ref-type", "setType", 0); digester.addCallMethod(fullPrefix + "/service-ref/wsdl-file", "setWsdlfile", 0); digester.addCallMethod(fullPrefix + "/service-ref/jaxrpc-mapping-file", "setJaxrpcmappingfile", 0); digester.addRule(fullPrefix + "/service-ref/service-qname", new ServiceQnameRule()); digester.addRule(fullPrefix + "/service-ref/port-component-ref", new CallMethodMultiRule("addPortcomponent", 2, 1)); digester.addCallParam(fullPrefix + "/service-ref/port-component-ref/service-endpoint-interface", 0); digester.addRule(fullPrefix + "/service-ref/port-component-ref/port-component-link", new CallParamMultiRule(1)); digester.addObjectCreate(fullPrefix + "/service-ref/handler", "org.apache.catalina.deploy.ContextHandler"); digester.addRule(fullPrefix + "/service-ref/handler", new SetNextRule("addHandler", "org.apache.catalina.deploy.ContextHandler")); digester.addCallMethod(fullPrefix + "/service-ref/handler/handler-name", "setName", 0); digester.addCallMethod(fullPrefix + "/service-ref/handler/handler-class", "setHandlerclass", 0); digester.addCallMethod(fullPrefix + "/service-ref/handler/init-param", "setProperty", 2); digester.addCallParam(fullPrefix + "/service-ref/handler/init-param/param-name", 0); digester.addCallParam(fullPrefix + "/service-ref/handler/init-param/param-value", 1); digester.addRule(fullPrefix + "/service-ref/handler/soap-header", new SoapHeaderRule()); digester.addCallMethod(fullPrefix + "/service-ref/handler/soap-role", "addSoapRole", 0); digester.addCallMethod(fullPrefix + "/service-ref/handler/port-name", "addPortName", 0); digester.addRule(fullPrefix + "/service-ref/mapped-name", new MappedNameRule()); configureInjectionRules(digester, "web-app/service-ref/"); } protected void configureInjectionRules(Digester digester, String base) { digester.addCallMethod(prefix + base + "injection-target", "addInjectionTarget", 2); digester.addCallParam(prefix + base + "injection-target/injection-target-class", 0); digester.addCallParam(prefix + base + "injection-target/injection-target-name", 1); } /** * Reset counter used for validating the web.xml file. */ public void recycle(){ jspConfig.isJspConfigSet = false; sessionConfig.isSessionConfigSet = false; loginConfig.isLoginConfigSet = false; name.isNameSet = false; absoluteOrdering.isAbsoluteOrderingSet = false; relativeOrdering.isRelativeOrderingSet = false; } } // ----------------------------------------------------------- Private Classes /** * Rule to check that the login-config is occurring * only 1 time within the web.xml */ final class SetLoginConfig extends Rule { protected boolean isLoginConfigSet = false; public SetLoginConfig() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (isLoginConfigSet){ throw new IllegalArgumentException( " element is limited to 1 occurrence"); } isLoginConfigSet = true; } } /** * Rule to check that the jsp-config is occurring * only 1 time within the web.xml */ final class SetJspConfig extends Rule { protected boolean isJspConfigSet = false; public SetJspConfig() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (isJspConfigSet){ throw new IllegalArgumentException( " element is limited to 1 occurrence"); } isJspConfigSet = true; } } /** * Rule to check that the session-config is occurring * only 1 time within the web.xml */ final class SetSessionConfig extends Rule { protected boolean isSessionConfigSet = false; public SetSessionConfig() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (isSessionConfigSet){ throw new IllegalArgumentException( " element is limited to 1 occurrence"); } isSessionConfigSet = true; } } /** * A Rule that calls the setAuthConstraint(true) method of * the top item on the stack, which must be of type * org.apache.catalina.deploy.SecurityConstraint. */ final class SetAuthConstraintRule extends Rule { public SetAuthConstraintRule() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { SecurityConstraint securityConstraint = (SecurityConstraint) digester.peek(); securityConstraint.setAuthConstraint(true); if (digester.getLogger().isDebugEnabled()) { digester.getLogger() .debug("Calling SecurityConstraint.setAuthConstraint(true)"); } } } /** * Class that calls setDistributable(true) for the top object * on the stack, which must be a org.apache.catalina.Context. */ final class SetDistributableRule extends Rule { public SetDistributableRule() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { WebXml webXml = (WebXml) digester.peek(); webXml.setDistributable(true); if (digester.getLogger().isDebugEnabled()) { digester.getLogger().debug (webXml.getClass().getName() + ".setDistributable(true)"); } } } /** * Class that calls a property setter for the top object on the stack, * passing the public ID of the entity we are currently processing. */ final class SetPublicIdRule extends Rule { public SetPublicIdRule(String method) { this.method = method; } private String method = null; @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { Object top = digester.peek(); Class paramClasses[] = new Class[1]; paramClasses[0] = "String".getClass(); String paramValues[] = new String[1]; paramValues[0] = digester.getPublicId(); Method m = null; try { m = top.getClass().getMethod(method, paramClasses); } catch (NoSuchMethodException e) { digester.getLogger().error("Can't find method " + method + " in " + top + " CLASS " + top.getClass()); return; } m.invoke(top, (Object [])paramValues); if (digester.getLogger().isDebugEnabled()) digester.getLogger().debug("" + top.getClass().getName() + "." + method + "(" + paramValues[0] + ")"); } } /** * A Rule that calls the factory method on the specified Context to * create the object that is to be added to the stack. */ final class ServletDefCreateRule extends Rule { public ServletDefCreateRule() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { ServletDef servletDef = new ServletDef(); digester.push(servletDef); if (digester.getLogger().isDebugEnabled()) digester.getLogger().debug("new " + servletDef.getClass().getName()); } @Override public void end(String namespace, String name) throws Exception { ServletDef servletDef = (ServletDef) digester.pop(); if (digester.getLogger().isDebugEnabled()) digester.getLogger().debug("pop " + servletDef.getClass().getName()); } } /** * A Rule that can be used to call multiple times a method as many times as needed * (used for addServletMapping). */ final class CallParamMultiRule extends CallParamRule { public CallParamMultiRule(int paramIndex) { super(paramIndex); } @Override public void end(String namespace, String name) { if (bodyTextStack != null && !bodyTextStack.empty()) { // what we do now is push one parameter onto the top set of parameters Object parameters[] = (Object[]) digester.peekParams(); @SuppressWarnings("unchecked") ArrayList params = (ArrayList) parameters[paramIndex]; if (params == null) { params = new ArrayList(); parameters[paramIndex] = params; } params.add(bodyTextStack.pop()); } } } /** * A Rule that can be used to call multiple times a method as many times as needed * (used for addServletMapping). */ final class CallMethodMultiRule extends CallMethodRule { protected int multiParamIndex = 0; public CallMethodMultiRule(String methodName, int paramCount, int multiParamIndex) { super(methodName, paramCount); this.multiParamIndex = multiParamIndex; } /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { // Retrieve or construct the parameter values array Object parameters[] = null; if (paramCount > 0) { parameters = (Object[]) digester.popParams(); } else { parameters = new Object[0]; super.end(namespace, name); } ArrayList multiParams = (ArrayList) parameters[multiParamIndex]; // Construct the parameter values array we will need // We only do the conversion if the param value is a String and // the specified paramType is not String. Object paramValues[] = new Object[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) { if (i != multiParamIndex) { // convert nulls and convert stringy parameters // for non-stringy param types if(parameters[i] == null || (parameters[i] instanceof String && !String.class.isAssignableFrom(paramTypes[i]))) { paramValues[i] = IntrospectionUtils.convert((String) parameters[i], paramTypes[i]); } else { paramValues[i] = parameters[i]; } } } // Determine the target object for the method call Object target; if (targetOffset >= 0) { target = digester.peek(targetOffset); } else { target = digester.peek(digester.getCount() + targetOffset); } if (target == null) { StringBuilder sb = new StringBuilder(); sb.append("[CallMethodRule]{"); sb.append(""); sb.append("} Call target is null ("); sb.append("targetOffset="); sb.append(targetOffset); sb.append(",stackdepth="); sb.append(digester.getCount()); sb.append(")"); throw new org.xml.sax.SAXException(sb.toString()); } if (multiParams == null) { paramValues[multiParamIndex] = null; IntrospectionUtils.callMethodN(target, methodName, paramValues, paramTypes); return; } for (int j = 0; j < multiParams.size(); j++) { Object param = multiParams.get(j); if(param == null || (param instanceof String && !String.class.isAssignableFrom(paramTypes[multiParamIndex]))) { paramValues[multiParamIndex] = IntrospectionUtils.convert((String) param, paramTypes[multiParamIndex]); } else { paramValues[multiParamIndex] = param; } IntrospectionUtils.callMethodN(target, methodName, paramValues, paramTypes); } } } /** * A Rule that check if the annotations have to be loaded. * */ final class IgnoreAnnotationsRule extends Rule { public IgnoreAnnotationsRule() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { WebXml webxml = (WebXml) digester.peek(digester.getCount() - 1); String value = attributes.getValue("metadata-complete"); if ("true".equals(value)) { webxml.setMetadataComplete(true); } else if ("false".equals(value)) { webxml.setMetadataComplete(false); } if (digester.getLogger().isDebugEnabled()) { digester.getLogger().debug (webxml.getClass().getName() + ".setMetadataComplete( " + webxml.isMetadataComplete() + ")"); } } } /** * A Rule that records the spec version of the web.xml being parsed * */ final class VersionRule extends Rule { public VersionRule() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { WebXml webxml = (WebXml) digester.peek(digester.getCount() - 1); webxml.setVersion(attributes.getValue("version")); if (digester.getLogger().isDebugEnabled()) { digester.getLogger().debug (webxml.getClass().getName() + ".setVersion( " + webxml.getVersion() + ")"); } } } /** * A rule that ensures only a single name element is present. */ final class NameRule extends Rule { protected boolean isNameSet = false; public NameRule() { // NO-OP } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (isNameSet){ throw new IllegalArgumentException(WebRuleSet.sm.getString( "webRuleSet.nameCount")); } isNameSet = true; } @Override public void body(String namespace, String name, String text) throws Exception { super.body(namespace, name, text); ((WebXml) digester.peek()).setName(text); } } /** * A rule that logs a warning if absolute ordering is configured for a fragment * and fails if multiple absolute orders are configured. */ final class AbsoluteOrderingRule extends Rule { protected boolean isAbsoluteOrderingSet = false; private final boolean fragment; public AbsoluteOrderingRule(boolean fragment) { this.fragment = fragment; } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (fragment) { digester.getLogger().warn( WebRuleSet.sm.getString("webRuleSet.absoluteOrdering")); } if (isAbsoluteOrderingSet) { throw new IllegalArgumentException(WebRuleSet.sm.getString( "webRuleSet.absoluteOrderingCount")); } else { isAbsoluteOrderingSet = true; WebXml webXml = (WebXml) digester.peek(); webXml.createAbsoluteOrdering(); if (digester.getLogger().isDebugEnabled()) { digester.getLogger().debug( webXml.getClass().getName() + ".setAbsoluteOrdering()"); } } } } /** * A rule that logs a warning if relative ordering is configured. */ final class RelativeOrderingRule extends Rule { protected boolean isRelativeOrderingSet = false; private final boolean fragment; public RelativeOrderingRule(boolean fragment) { this.fragment = fragment; } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { if (!fragment) { digester.getLogger().warn( WebRuleSet.sm.getString("webRuleSet.relativeOrdering")); } if (isRelativeOrderingSet) { throw new IllegalArgumentException(WebRuleSet.sm.getString( "webRuleSet.relativeOrderingCount")); } else { isRelativeOrderingSet = true; } } } /** * A Rule that sets soap headers on the ContextHandler. * */ final class SoapHeaderRule extends Rule { public SoapHeaderRule() { // NO-OP } /** * Process the body text of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param text The body text of this element */ @Override public void body(String namespace, String name, String text) throws Exception { String namespaceuri = null; String localpart = text; int colon = text.indexOf(':'); if (colon >= 0) { String prefix = text.substring(0,colon); namespaceuri = digester.findNamespaceURI(prefix); localpart = text.substring(colon+1); } ContextHandler contextHandler = (ContextHandler)digester.peek(); contextHandler.addSoapHeaders(localpart,namespaceuri); } } /** * A Rule that sets service qname on the ContextService. * */ final class ServiceQnameRule extends Rule { public ServiceQnameRule() { // NO-OP } /** * Process the body text of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param text The body text of this element */ @Override public void body(String namespace, String name, String text) throws Exception { String namespaceuri = null; String localpart = text; int colon = text.indexOf(':'); if (colon >= 0) { String prefix = text.substring(0,colon); namespaceuri = digester.findNamespaceURI(prefix); localpart = text.substring(colon+1); } ContextService contextService = (ContextService)digester.peek(); contextService.setServiceqnameLocalpart(localpart); contextService.setServiceqnameNamespaceURI(namespaceuri); } } /** * A rule that checks if the taglib element is in the right place. */ final class TaglibLocationRule extends Rule { final boolean isServlet24OrLater; public TaglibLocationRule(boolean isServlet24OrLater) { this.isServlet24OrLater = isServlet24OrLater; } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { WebXml webXml = (WebXml) digester.peek(digester.getCount() - 1); // If we have a public ID, this is not a 2.4 or later webapp boolean havePublicId = (webXml.getPublicId() != null); // havePublicId and isServlet24OrLater should be mutually exclusive if (havePublicId == isServlet24OrLater) { throw new IllegalArgumentException( "taglib definition not consistent with specification version"); } } } /** * A Rule that sets mapped name on the ResourceBase. */ final class MappedNameRule extends Rule { public MappedNameRule() { // NO-OP } /** * Process the body text of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param text The body text of this element */ @Override public void body(String namespace, String name, String text) throws Exception { ResourceBase resourceBase = (ResourceBase) digester.peek(); resourceBase.setProperty("mappedName", text.trim()); } } /** * A rule that fails if more than one post construct or pre destroy methods * are configured per class. */ final class LifecycleCallbackRule extends CallMethodRule { private final boolean postConstruct; public LifecycleCallbackRule(String methodName, int paramCount, boolean postConstruct) { super(methodName, paramCount); this.postConstruct = postConstruct; } @Override public void end(String namespace, String name) throws Exception { Object[] params = (Object[]) digester.peekParams(); if (params != null && params.length == 2) { WebXml webXml = (WebXml) digester.peek(); if (postConstruct) { if (webXml.getPostConstructMethods().containsKey(params[0])) { throw new IllegalArgumentException(WebRuleSet.sm.getString( "webRuleSet.postconstruct.duplicate", params[0])); } } else { if (webXml.getPreDestroyMethods().containsKey(params[0])) { throw new IllegalArgumentException(WebRuleSet.sm.getString( "webRuleSet.predestroy.duplicate", params[0])); } } } super.end(namespace, name); } } final class SetOverrideRule extends Rule { public SetOverrideRule() { // no-op } @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { ContextEnvironment envEntry = (ContextEnvironment) digester.peek(); envEntry.setOverride(false); if (digester.getLogger().isDebugEnabled()) { digester.getLogger().debug( envEntry.getClass().getName() + ".setOverride(false)"); } } } tomcat7-7.0.52/java/org/apache/catalina/startup/WebappServiceLoader.java0000644000175100017510000001707312265507335026123 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.regex.Pattern; import javax.servlet.ServletContext; /** * A variation of Java's JAR ServiceLoader that respects exclusion rules for * web applications. *

    * Primarily intended for use loading ServletContainerInitializers as defined * by Servlet 8.2.4. This implementation does not attempt lazy loading as the * container is required to introspect all implementations discovered. *

    * If the ServletContext defines ORDERED_LIBS, then only JARs in WEB-INF/lib * that are named in that set will be included in the search for * provider configuration files; if ORDERED_LIBS is not defined then * all JARs will be searched for provider configuration files. Providers * defined by resources in the parent ClassLoader will always be returned. *

    * Provider classes will be loaded using the context's ClassLoader. * * @see javax.servlet.ServletContainerInitializer * @see java.util.ServiceLoader */ public class WebappServiceLoader { private static final String LIB = "/WEB-INF/lib/"; private static final String SERVICES = "META-INF/services/"; private static final Charset UTF8 = Charset.forName("UTF-8"); private final ServletContext context; private final Pattern containerSciFilterPattern; /** * Construct a loader to load services from a ServletContext. * * @param context the context to use */ public WebappServiceLoader(ServletContext context, String containerSciFilter) { this.context = context; if (containerSciFilter != null && containerSciFilter.length() > 0) { containerSciFilterPattern = Pattern.compile(containerSciFilter); } else { containerSciFilterPattern = null; } } /** * Load the providers for a service type. * * @param serviceType the type of service to load * @return an unmodifiable collection of service providers * @throws IOException if there was a problem loading any service */ public List load(Class serviceType) throws IOException { String configFile = SERVICES + serviceType.getName(); LinkedHashSet applicationServicesFound = new LinkedHashSet(); LinkedHashSet containerServicesFound = new LinkedHashSet(); ClassLoader loader = context.getClassLoader(); // if the ServletContext has ORDERED_LIBS, then use that to specify the // set of JARs from WEB-INF/lib that should be used for loading services @SuppressWarnings("unchecked") List orderedLibs = (List) context.getAttribute(ServletContext.ORDERED_LIBS); if (orderedLibs != null) { // handle ordered libs directly, ... for (String lib : orderedLibs) { URL jarUrl = context.getResource(LIB + lib); if (jarUrl == null) { // should not happen, just ignore continue; } String base = jarUrl.toExternalForm(); URL url; if (base.endsWith("/")) { url = new URL(base + configFile); } else { url = new URL("jar:" + base + "!/" + configFile); } try { parseConfigFile(applicationServicesFound, url); } catch (FileNotFoundException e) { // no provider file found, this is OK } } // and the parent ClassLoader for all others loader = loader.getParent(); } Enumeration resources; if (loader == null) { resources = ClassLoader.getSystemResources(configFile); } else { resources = loader.getResources(configFile); } while (resources.hasMoreElements()) { parseConfigFile(containerServicesFound, resources.nextElement()); } // Filter the discovered container SCIs if required if (containerSciFilterPattern != null) { Iterator iter = containerServicesFound.iterator(); while (iter.hasNext()) { if (containerSciFilterPattern.matcher(iter.next()).find()) { iter.remove(); } } } // Add the application services after the container services to ensure // that the container services are loaded first containerServicesFound.addAll(applicationServicesFound); // load the discovered services if (containerServicesFound.isEmpty()) { return Collections.emptyList(); } return loadServices(serviceType, containerServicesFound); } private void parseConfigFile(LinkedHashSet servicesFound, URL url) throws IOException { InputStream is = null; try { is = url.openStream(); InputStreamReader in = new InputStreamReader(is, UTF8); BufferedReader reader = new BufferedReader(in); String line; while ((line = reader.readLine()) != null) { int i = line.indexOf('#'); if (i >= 0) { line = line.substring(0, i); } line = line.trim(); if (line.length() == 0) { continue; } servicesFound.add(line); } } finally { if (is != null) { is.close(); } } } private List loadServices(Class serviceType, LinkedHashSet servicesFound) throws IOException { ClassLoader loader = context.getClassLoader(); List services = new ArrayList(servicesFound.size()); for (String serviceClass : servicesFound) { try { Class clazz = Class.forName(serviceClass, true, loader); services.add(serviceType.cast(clazz.newInstance())); } catch (ClassNotFoundException e) { throw new IOException(e); } catch (InstantiationException e) { throw new IOException(e); } catch (IllegalAccessException e) { throw new IOException(e); } catch (ClassCastException e) { throw new IOException(e); } } return Collections.unmodifiableList(services); } } tomcat7-7.0.52/java/org/apache/catalina/startup/LifecycleListenerRule.java0000644000175100017510000001043612271471332026460 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.catalina.Container; import org.apache.catalina.LifecycleListener; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.digester.Rule; import org.xml.sax.Attributes; /** * Rule that creates a new {@link LifecycleListener} and associates it with the * top object on the stack which must implement {@link Container}. The * implementation class to be used is determined by: *

      *
    1. Does the top element on the stack specify an implementation class using * the attribute specified when this rule was created?
    2. *
    3. Does the parent {@link Container} of the {@link Container} on the top of * the stack specify an implementation class using the attribute specified * when this rule was created?
    4. *
    5. Use the default implementation class specified when this rule was * created.
    6. *
    */ public class LifecycleListenerRule extends Rule { // ----------------------------------------------------------- Constructors /** * Construct a new instance of this Rule. * * @param listenerClass Default name of the LifecycleListener * implementation class to be created * @param attributeName Name of the attribute that optionally * includes an override name of the LifecycleListener class */ public LifecycleListenerRule(String listenerClass, String attributeName) { this.listenerClass = listenerClass; this.attributeName = attributeName; } // ----------------------------------------------------- Instance Variables /** * The attribute name of an attribute that can override the * implementation class name. */ private String attributeName; /** * The name of the LifecycleListener implementation class. */ private String listenerClass; // --------------------------------------------------------- Public Methods /** * Handle the beginning of an XML element. * * @param attributes The attributes of this element * * @exception Exception if a processing error occurs */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { Container c = (Container) digester.peek(); Container p = null; Object obj = digester.peek(1); if (obj instanceof Container) { p = (Container) obj; } String className = null; // Check the container for the specified attribute if (attributeName != null) { String value = attributes.getValue(attributeName); if (value != null) className = value; } // Check the container's parent for the specified attribute if (p != null && className == null) { String configClass = (String) IntrospectionUtils.getProperty(p, attributeName); if (configClass != null && configClass.length() > 0) { className = configClass; } } // Use the default if (className == null) { className = listenerClass; } // Instantiate a new LifecyleListener implementation object Class clazz = Class.forName(className); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); // Add this LifecycleListener to our associated component c.addLifecycleListener(listener); } } tomcat7-7.0.52/java/org/apache/catalina/startup/EngineRuleSet.java0000644000175100017510000001102012271471332024722 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.RuleSetBase; /** *

    RuleSet for processing the contents of a * Engine definition element. This RuleSet does NOT include * any rules for nested Host elements, which should be added via instances of * HostRuleSet.

    * * @author Craig R. McClanahan */ public class EngineRuleSet extends RuleSetBase { // ----------------------------------------------------- Instance Variables /** * The matching pattern prefix to use for recognizing our elements. */ protected String prefix = null; // ------------------------------------------------------------ Constructor /** * Construct an instance of this RuleSet with the default * matching pattern prefix. */ public EngineRuleSet() { this(""); } /** * Construct an instance of this RuleSet with the specified * matching pattern prefix. * * @param prefix Prefix for matching pattern rules (including the * trailing slash character) */ public EngineRuleSet(String prefix) { super(); this.namespaceURI = null; this.prefix = prefix; } // --------------------------------------------------------- Public Methods /** *

    Add the set of Rule instances defined in this RuleSet to the * specified Digester instance, associating them with * our namespace URI (if any). This method should only be called * by a Digester instance.

    * * @param digester Digester instance to which the new Rule instances * should be added. */ @Override public void addRuleInstances(Digester digester) { digester.addObjectCreate(prefix + "Engine", "org.apache.catalina.core.StandardEngine", "className"); digester.addSetProperties(prefix + "Engine"); digester.addRule(prefix + "Engine", new LifecycleListenerRule ("org.apache.catalina.startup.EngineConfig", "engineConfigClass")); digester.addSetNext(prefix + "Engine", "setContainer", "org.apache.catalina.Container"); //Cluster configuration start digester.addObjectCreate(prefix + "Engine/Cluster", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Engine/Cluster"); digester.addSetNext(prefix + "Engine/Cluster", "setCluster", "org.apache.catalina.Cluster"); //Cluster configuration end digester.addObjectCreate(prefix + "Engine/Listener", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Engine/Listener"); digester.addSetNext(prefix + "Engine/Listener", "addLifecycleListener", "org.apache.catalina.LifecycleListener"); digester.addRuleSet(new RealmRuleSet(prefix + "Engine/")); digester.addObjectCreate(prefix + "Engine/Valve", null, // MUST be specified in the element "className"); digester.addSetProperties(prefix + "Engine/Valve"); digester.addSetNext(prefix + "Engine/Valve", "addValve", "org.apache.catalina.Valve"); } } tomcat7-7.0.52/java/org/apache/catalina/startup/mbeans-descriptors.xml0000644000175100017510000001470312271471332025707 0ustar locutuslocutus tomcat7-7.0.52/java/org/apache/catalina/startup/HostConfig.java0000644000175100017510000020202212271471332024260 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.management.ObjectName; import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.DistributedManager; import org.apache.catalina.Engine; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Manager; import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardHost; import org.apache.catalina.util.ContextName; import org.apache.catalina.util.IOTools; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; /** * Startup event listener for a Host that configures the properties * of that Host, and the associated defined contexts. * * @author Craig R. McClanahan * @author Remy Maucherat */ public class HostConfig implements LifecycleListener { private static final Log log = LogFactory.getLog( HostConfig.class ); // ----------------------------------------------------- Instance Variables /** * App base. */ protected File appBase = null; /** * Config base. */ protected File configBase = null; /** * The Java class name of the Context configuration class we should use. * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated protected String configClass = "org.apache.catalina.startup.ContextConfig"; /** * The Java class name of the Context implementation we should use. */ protected String contextClass = "org.apache.catalina.core.StandardContext"; /** * The Host we are associated with. */ protected Host host = null; /** * The JMX ObjectName of this component. */ protected ObjectName oname = null; /** * The string resources for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Should we deploy XML Context config files packaged with WAR files and * directories? */ protected boolean deployXML = false; /** * Should XML files be copied to * $CATALINA_BASE/conf/<engine>/<host> by default when * a web application is deployed? */ protected boolean copyXML = false; /** * Should we unpack WAR files when auto-deploying applications in the * appBase directory? */ protected boolean unpackWARs = false; /** * Map of deployed applications. */ protected Map deployed = new ConcurrentHashMap(); /** * List of applications which are being serviced, and shouldn't be * deployed/undeployed/redeployed at the moment. */ protected ArrayList serviced = new ArrayList(); /** * The Digester instance used to parse context descriptors. */ protected Digester digester = createDigester(contextClass); private final Object digesterLock = new Object(); /** * The list of Wars in the appBase to be ignored because they are invalid * (e.g. contain /../ sequences). */ protected Set invalidWars = new HashSet(); // ------------------------------------------------------------- Properties /** * Return the Context configuration class name. * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated public String getConfigClass() { return (this.configClass); } /** * Set the Context configuration class name. * * @param configClass The new Context configuration class name. * @deprecated Will be removed in Tomcat 8.0.x */ @Deprecated public void setConfigClass(String configClass) { this.configClass = configClass; } /** * Return the Context implementation class name. */ public String getContextClass() { return (this.contextClass); } /** * Set the Context implementation class name. * * @param contextClass The new Context implementation class name. */ public void setContextClass(String contextClass) { String oldContextClass = this.contextClass; this.contextClass = contextClass; if (!oldContextClass.equals(contextClass)) { synchronized (digesterLock) { digester = createDigester(getContextClass()); } } } /** * Return the deploy XML config file flag for this component. */ public boolean isDeployXML() { return (this.deployXML); } /** * Set the deploy XML config file flag for this component. * * @param deployXML The new deploy XML flag */ public void setDeployXML(boolean deployXML) { this.deployXML= deployXML; } /** * Return the copy XML config file flag for this component. */ public boolean isCopyXML() { return (this.copyXML); } /** * Set the copy XML config file flag for this component. * * @param copyXML The new copy XML flag */ public void setCopyXML(boolean copyXML) { this.copyXML= copyXML; } /** * Return the unpack WARs flag. */ public boolean isUnpackWARs() { return (this.unpackWARs); } /** * Set the unpack WARs flag. * * @param unpackWARs The new unpack WARs flag */ public void setUnpackWARs(boolean unpackWARs) { this.unpackWARs = unpackWARs; } // --------------------------------------------------------- Public Methods /** * Process the START event for an associated Host. * * @param event The lifecycle event that has occurred */ @Override public void lifecycleEvent(LifecycleEvent event) { // Identify the host we are associated with try { host = (Host) event.getLifecycle(); if (host instanceof StandardHost) { setCopyXML(((StandardHost) host).isCopyXML()); setDeployXML(((StandardHost) host).isDeployXML()); setUnpackWARs(((StandardHost) host).isUnpackWARs()); setContextClass(((StandardHost) host).getContextClass()); } } catch (ClassCastException e) { log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); return; } // Process the event that has occurred if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) { check(); } else if (event.getType().equals(Lifecycle.START_EVENT)) { start(); } else if (event.getType().equals(Lifecycle.STOP_EVENT)) { stop(); } } /** * Add a serviced application to the list. */ public synchronized void addServiced(String name) { serviced.add(name); } /** * Is application serviced ? * @return state of the application */ public synchronized boolean isServiced(String name) { return (serviced.contains(name)); } /** * Removed a serviced application from the list. */ public synchronized void removeServiced(String name) { serviced.remove(name); } /** * Get the instant where an application was deployed. * @return 0L if no application with that name is deployed, or the instant * on which the application was deployed */ public long getDeploymentTime(String name) { DeployedApplication app = deployed.get(name); if (app == null) { return 0L; } return app.timestamp; } /** * Has the specified application been deployed? Note applications defined * in server.xml will not have been deployed. * @return true if the application has been deployed and * false if the application has not been deployed or does not * exist */ public boolean isDeployed(String name) { DeployedApplication app = deployed.get(name); if (app == null) { return false; } return true; } // ------------------------------------------------------ Protected Methods /** * Create the digester which will be used to parse context config files. */ protected static Digester createDigester(String contextClassName) { Digester digester = new Digester(); digester.setValidating(false); // Add object creation rule digester.addObjectCreate("Context", contextClassName, "className"); // Set the properties on that object (it doesn't matter if extra // properties are set) digester.addSetProperties("Context"); return (digester); } protected File returnCanonicalPath(String path) { File file = new File(path); File base = new File(System.getProperty(Globals.CATALINA_BASE_PROP)); if (!file.isAbsolute()) file = new File(base,path); try { return file.getCanonicalFile(); } catch (IOException e) { return file; } } /** * Return a File object representing the "application root" directory * for our associated Host. */ protected File appBase() { if (appBase != null) { return appBase; } appBase = returnCanonicalPath(host.getAppBase()); return appBase; } /** * Return a File object representing the "configuration root" directory * for our associated Host. */ protected File configBase() { if (configBase != null) { return configBase; } if (host.getXmlBase()!=null) { configBase = returnCanonicalPath(host.getXmlBase()); } else { StringBuilder xmlDir = new StringBuilder("conf"); Container parent = host.getParent(); if (parent instanceof Engine) { xmlDir.append('/'); xmlDir.append(parent.getName()); } xmlDir.append('/'); xmlDir.append(host.getName()); configBase = returnCanonicalPath(xmlDir.toString()); } return (configBase); } /** * Get the name of the configBase. * For use with JMX management. */ public String getConfigBaseName() { return configBase().getAbsolutePath(); } /** * Deploy applications for any directories or WAR files that are found * in our "application root" directory. */ protected void deployApps() { File appBase = appBase(); File configBase = configBase(); String[] filteredAppPaths = filterAppPaths(appBase.list()); // Deploy XML descriptors from configBase deployDescriptors(configBase, configBase.list()); // Deploy WARs deployWARs(appBase, filteredAppPaths); // Deploy expanded folders deployDirectories(appBase, filteredAppPaths); } /** * Filter the list of application file paths to remove those that match * the regular expression defined by {@link Host#getDeployIgnore()}. * * @param unfilteredAppPaths The list of application paths to filtert * * @return The filtered list of application paths */ protected String[] filterAppPaths(String[] unfilteredAppPaths) { Pattern filter = host.getDeployIgnorePattern(); if (filter == null) { return unfilteredAppPaths; } List filteredList = new ArrayList(); Matcher matcher = null; for (String appPath : unfilteredAppPaths) { if (matcher == null) { matcher = filter.matcher(appPath); } else { matcher.reset(appPath); } if (matcher.matches()) { if (log.isDebugEnabled()) { log.debug(sm.getString("hostConfig.ignorePath", appPath)); } } else { filteredList.add(appPath); } } return filteredList.toArray(new String[filteredList.size()]); } /** * Deploy applications for any directories or WAR files that are found * in our "application root" directory. */ protected void deployApps(String name) { File appBase = appBase(); File configBase = configBase(); ContextName cn = new ContextName(name, false); String baseName = cn.getBaseName(); if (deploymentExists(baseName)) { return; } // Deploy XML descriptor from configBase File xml = new File(configBase, baseName + ".xml"); if (xml.exists()) { deployDescriptor(cn, xml); return; } // Deploy WAR File war = new File(appBase, baseName + ".war"); if (war.exists()) { deployWAR(cn, war); return; } // Deploy expanded folder File dir = new File(appBase, baseName); if (dir.exists()) deployDirectory(cn, dir); } /** * Deploy XML context descriptors. */ protected void deployDescriptors(File configBase, String[] files) { if (files == null) return; ExecutorService es = host.getStartStopExecutor(); List> results = new ArrayList>(); for (int i = 0; i < files.length; i++) { File contextXml = new File(configBase, files[i]); if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) { ContextName cn = new ContextName(files[i], true); if (isServiced(cn.getName()) || deploymentExists(cn.getName())) continue; results.add( es.submit(new DeployDescriptor(this, cn, contextXml))); } } for (Future result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDescriptor.threaded.error"), e); } } } /** * @param cn * @param contextXml */ @SuppressWarnings("null") // context is not null protected void deployDescriptor(ContextName cn, File contextXml) { DeployedApplication deployedApp = new DeployedApplication(cn.getName(), true); // Assume this is a configuration descriptor and deploy it if(log.isInfoEnabled()) { log.info(sm.getString("hostConfig.deployDescriptor", contextXml.getAbsolutePath())); } Context context = null; boolean isExternalWar = false; boolean isExternal = false; File expandedDocBase = null; FileInputStream fis = null; try { fis = new FileInputStream(contextXml); synchronized (digesterLock) { try { context = (Context) digester.parse(fis); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDescriptor.error", contextXml.getAbsolutePath()), e); context = new FailedContext(); } finally { digester.reset(); } } Class clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); context.addLifecycleListener(listener); context.setConfigFile(contextXml.toURI().toURL()); context.setName(cn.getName()); context.setPath(cn.getPath()); context.setWebappVersion(cn.getVersion()); // Add the associated docBase to the redeployed list if it's a WAR if (context.getDocBase() != null) { File docBase = new File(context.getDocBase()); if (!docBase.isAbsolute()) { docBase = new File(appBase(), context.getDocBase()); } // If external docBase, register .xml as redeploy first if (!docBase.getCanonicalPath().startsWith( appBase().getAbsolutePath() + File.separator)) { isExternal = true; deployedApp.redeployResources.put( contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified())); deployedApp.redeployResources.put(docBase.getAbsolutePath(), Long.valueOf(docBase.lastModified())); if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) { isExternalWar = true; } } else { log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified", docBase)); // Ignore specified docBase context.setDocBase(null); } } host.addChild(context); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("hostConfig.deployDescriptor.error", contextXml.getAbsolutePath()), t); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // Ignore } } // Get paths for WAR and expanded WAR in appBase // default to appBase dir + name expandedDocBase = new File(appBase(), cn.getBaseName()); if (context.getDocBase() != null) { // first assume docBase is absolute expandedDocBase = new File(context.getDocBase()); if (!expandedDocBase.isAbsolute()) { // if docBase specified and relative, it must be relative to appBase expandedDocBase = new File(appBase(), context.getDocBase()); } } // Add the eventual unpacked WAR and all the resources which will be // watched inside it if (isExternalWar && unpackWARs) { deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified())); deployedApp.redeployResources.put(contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified())); addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context); } else { // Find an existing matching war and expanded folder if (!isExternal) { File warDocBase = new File(expandedDocBase.getAbsolutePath() + ".war"); if (warDocBase.exists()) { deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), Long.valueOf(warDocBase.lastModified())); } else { // Trigger a redeploy if a WAR is added deployedApp.redeployResources.put( warDocBase.getAbsolutePath(), Long.valueOf(0)); } } if (expandedDocBase.exists()) { deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), Long.valueOf(expandedDocBase.lastModified())); addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context); } else { if (!isExternal && !unpackWARs) { // Trigger a reload if a DIR is added deployedApp.reloadResources.put( expandedDocBase.getAbsolutePath(), Long.valueOf(0)); } addWatchedResources(deployedApp, null, context); } // Add the context XML to the list of files which should trigger a redeployment if (!isExternal) { deployedApp.redeployResources.put( contextXml.getAbsolutePath(), Long.valueOf(contextXml.lastModified())); } } // Add the global redeploy resources (which are never deleted) at // the end so they don't interfere with the deletion process addGlobalRedeployResources(deployedApp); } if (host.findChild(context.getName()) != null) { deployed.put(context.getName(), deployedApp); } } /** * Deploy WAR files. */ protected void deployWARs(File appBase, String[] files) { if (files == null) return; ExecutorService es = host.getStartStopExecutor(); List> results = new ArrayList>(); for (int i = 0; i < files.length; i++) { if (files[i].equalsIgnoreCase("META-INF")) continue; if (files[i].equalsIgnoreCase("WEB-INF")) continue; File war = new File(appBase, files[i]); if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() && !invalidWars.contains(files[i]) ) { ContextName cn = new ContextName(files[i], true); if (isServiced(cn.getName())) { continue; } if (deploymentExists(cn.getName())) { DeployedApplication app = deployed.get(cn.getName()); if (!unpackWARs && app != null) { // Need to check for a directory that should not be // there File dir = new File(appBase, cn.getBaseName()); if (dir.exists()) { if (!app.loggedDirWarning) { log.warn(sm.getString( "hostConfig.deployWar.hiddenDir", dir.getAbsoluteFile(), war.getAbsoluteFile())); app.loggedDirWarning = true; } } else { app.loggedDirWarning = false; } } continue; } // Check for WARs with /../ /./ or similar sequences in the name if (!validateContextPath(appBase, cn.getBaseName())) { log.error(sm.getString( "hostConfig.illegalWarName", files[i])); invalidWars.add(files[i]); continue; } results.add(es.submit(new DeployWar(this, cn, war))); } } for (Future result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployWar.threaded.error"), e); } } } private boolean validateContextPath(File appBase, String contextPath) { // More complicated than the ideal as the canonical path may or may // not end with File.separator for a directory StringBuilder docBase; String canonicalDocBase = null; try { String canonicalAppBase = appBase.getCanonicalPath(); docBase = new StringBuilder(canonicalAppBase); if (canonicalAppBase.endsWith(File.separator)) { docBase.append(contextPath.substring(1).replace( '/', File.separatorChar)); } else { docBase.append(contextPath.replace('/', File.separatorChar)); } // At this point docBase should be canonical but will not end // with File.separator canonicalDocBase = (new File(docBase.toString())).getCanonicalPath(); // If the canonicalDocBase ends with File.separator, add one to // docBase before they are compared if (canonicalDocBase.endsWith(File.separator)) { docBase.append(File.separator); } } catch (IOException ioe) { return false; } // Compare the two. If they are not the same, the contextPath must // have /../ like sequences in it return canonicalDocBase.equals(docBase.toString()); } /** * @param cn * @param war */ protected void deployWAR(ContextName cn, File war) { // Checking for a nested /META-INF/context.xml JarFile jar = null; InputStream istream = null; FileOutputStream fos = null; BufferedOutputStream ostream = null; File xml = new File(appBase(), cn.getBaseName() + "/META-INF/context.xml"); boolean xmlInWar = false; JarEntry entry = null; try { jar = new JarFile(war); entry = jar.getJarEntry(Constants.ApplicationContextXml); if (entry != null) { xmlInWar = true; } } catch (IOException e) { /* Ignore */ } finally { entry = null; if (jar != null) { try { jar.close(); } catch (IOException ioe) { // Ignore; } jar = null; } } Context context = null; try { if (deployXML && xml.exists() && !copyXML) { synchronized (digesterLock) { try { context = (Context) digester.parse(xml); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDescriptor.error", war.getAbsolutePath()), e); } finally { if (context == null) { context = new FailedContext(); } digester.reset(); } } context.setConfigFile(xml.toURI().toURL()); } else if (deployXML && xmlInWar) { synchronized (digesterLock) { try { jar = new JarFile(war); entry = jar.getJarEntry(Constants.ApplicationContextXml); istream = jar.getInputStream(entry); context = (Context) digester.parse(istream); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDescriptor.error", war.getAbsolutePath()), e); } finally { if (context == null) { context = new FailedContext(); } context.setConfigFile(new URL("jar:" + war.toURI().toString() + "!/" + Constants.ApplicationContextXml)); if (istream != null) { try { istream.close(); } catch (IOException e) { /* Ignore */ } istream = null; } entry = null; if (jar != null) { try { jar.close(); } catch (IOException e) { /* Ignore */ } jar = null; } digester.reset(); } } } else if (!deployXML && xmlInWar) { // Block deployment as META-INF/context.xml may contain security // configuration necessary for a secure deployment. log.error(sm.getString("hostConfig.deployDescriptor.blocked", cn.getPath(), Constants.ApplicationContextXml, new File(configBase(), cn.getBaseName() + ".xml"))); } else { context = (Context) Class.forName(contextClass).newInstance(); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("hostConfig.deployWar.error", war.getAbsolutePath()), t); } finally { if (context == null) { context = new FailedContext(); } } boolean copyThisXml = false; if (deployXML) { if (host instanceof StandardHost) { copyThisXml = ((StandardHost) host).isCopyXML(); } // If Host is using default value Context can override it. if (!copyThisXml && context instanceof StandardContext) { copyThisXml = ((StandardContext) context).getCopyXML(); } if (xmlInWar && copyThisXml) { // Change location of XML file to config base xml = new File(configBase(), cn.getBaseName() + ".xml"); entry = null; try { jar = new JarFile(war); entry = jar.getJarEntry(Constants.ApplicationContextXml); istream = jar.getInputStream(entry); fos = new FileOutputStream(xml); ostream = new BufferedOutputStream(fos, 1024); byte buffer[] = new byte[1024]; while (true) { int n = istream.read(buffer); if (n < 0) { break; } ostream.write(buffer, 0, n); } ostream.flush(); } catch (IOException e) { /* Ignore */ } finally { if (ostream != null) { try { ostream.close(); } catch (IOException ioe) { // Ignore } ostream = null; } if (fos != null) { try { fos.close(); } catch (IOException ioe) { // Ignore } fos = null; } if (istream != null) { try { istream.close(); } catch (IOException ioe) { // Ignore } istream = null; } if (jar != null) { try { jar.close(); } catch (IOException ioe) { // Ignore; } jar = null; } } } } DeployedApplication deployedApp = new DeployedApplication(cn.getName(), xml.exists() && deployXML && copyThisXml); // Deploy the application in this WAR file if(log.isInfoEnabled()) log.info(sm.getString("hostConfig.deployWar", war.getAbsolutePath())); try { // Populate redeploy resources with the WAR file deployedApp.redeployResources.put (war.getAbsolutePath(), Long.valueOf(war.lastModified())); if (deployXML && xml.exists() && copyThisXml) { deployedApp.redeployResources.put(xml.getAbsolutePath(), Long.valueOf(xml.lastModified())); } else if (!copyThisXml ) { // In case an XML file is added to the config base later deployedApp.redeployResources.put( (new File(configBase(), cn.getBaseName() + ".xml")).getAbsolutePath(), Long.valueOf(0)); } Class clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); context.addLifecycleListener(listener); context.setName(cn.getName()); context.setPath(cn.getPath()); context.setWebappVersion(cn.getVersion()); context.setDocBase(cn.getBaseName() + ".war"); host.addChild(context); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("hostConfig.deployWar.error", war.getAbsolutePath()), t); } finally { // If we're unpacking WARs, the docBase will be mutated after // starting the context if (unpackWARs && context != null && context.getDocBase() != null) { File docBase = new File(appBase(), cn.getBaseName()); deployedApp.redeployResources.put(docBase.getAbsolutePath(), Long.valueOf(docBase.lastModified())); addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); if (deployXML && !copyThisXml && (xmlInWar || xml.exists())) { deployedApp.redeployResources.put(xml.getAbsolutePath(), Long.valueOf(xml.lastModified())); } } else { // Passing null for docBase means that no resources will be // watched. This will be logged at debug level. addWatchedResources(deployedApp, null, context); } // Add the global redeploy resources (which are never deleted) at // the end so they don't interfere with the deletion process addGlobalRedeployResources(deployedApp); } deployed.put(cn.getName(), deployedApp); } /** * Deploy directories. */ protected void deployDirectories(File appBase, String[] files) { if (files == null) return; ExecutorService es = host.getStartStopExecutor(); List> results = new ArrayList>(); for (int i = 0; i < files.length; i++) { if (files[i].equalsIgnoreCase("META-INF")) continue; if (files[i].equalsIgnoreCase("WEB-INF")) continue; File dir = new File(appBase, files[i]); if (dir.isDirectory()) { ContextName cn = new ContextName(files[i], false); if (isServiced(cn.getName()) || deploymentExists(cn.getName())) continue; results.add(es.submit(new DeployDirectory(this, cn, dir))); } } for (Future result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDir.threaded.error"), e); } } } /** * @param cn * @param dir */ protected void deployDirectory(ContextName cn, File dir) { // Deploy the application in this directory if( log.isInfoEnabled() ) log.info(sm.getString("hostConfig.deployDir", dir.getAbsolutePath())); Context context = null; File xml = new File(dir, Constants.ApplicationContextXml); File xmlCopy = new File(configBase(), cn.getBaseName() + ".xml"); DeployedApplication deployedApp; boolean copyThisXml = copyXML; try { if (deployXML && xml.exists()) { synchronized (digesterLock) { try { context = (Context) digester.parse(xml); } catch (Exception e) { log.error(sm.getString( "hostConfig.deployDescriptor.error", xml), e); context = new FailedContext(); } finally { if (context == null) { context = new FailedContext(); } digester.reset(); } } if (copyThisXml == false && context instanceof StandardContext) { // Host is using default value. Context may override it. copyThisXml = ((StandardContext) context).getCopyXML(); } if (copyThisXml) { InputStream is = null; OutputStream os = null; try { is = new FileInputStream(xml); os = new FileOutputStream(xmlCopy); IOTools.flow(is, os); // Don't catch IOE - let the outer try/catch handle it } finally { try { if (is != null) is.close(); } catch (IOException e){ // Ignore } try { if (os != null) os.close(); } catch (IOException e){ // Ignore } } context.setConfigFile(xmlCopy.toURI().toURL()); } else { context.setConfigFile(xml.toURI().toURL()); } } else if (!deployXML && xml.exists()) { // Block deployment as META-INF/context.xml may contain security // configuration necessary for a secure deployment. log.error(sm.getString("hostConfig.deployDescriptor.blocked", cn.getPath(), xml, xmlCopy)); context = new FailedContext(); } else { context = (Context) Class.forName(contextClass).newInstance(); } Class clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); context.addLifecycleListener(listener); context.setName(cn.getName()); context.setPath(cn.getPath()); context.setWebappVersion(cn.getVersion()); context.setDocBase(cn.getBaseName()); host.addChild(context); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("hostConfig.deployDir.error", dir.getAbsolutePath()), t); } finally { deployedApp = new DeployedApplication(cn.getName(), xml.exists() && deployXML && copyThisXml); // Fake re-deploy resource to detect if a WAR is added at a later // point deployedApp.redeployResources.put(dir.getAbsolutePath() + ".war", Long.valueOf(0)); deployedApp.redeployResources.put(dir.getAbsolutePath(), Long.valueOf(dir.lastModified())); if (deployXML && xml.exists()) { if (copyThisXml) { deployedApp.redeployResources.put( xmlCopy.getAbsolutePath(), Long.valueOf(xmlCopy.lastModified())); } else { deployedApp.redeployResources.put( xml.getAbsolutePath(), Long.valueOf(xml.lastModified())); // Fake re-deploy resource to detect if a context.xml file is // added at a later point deployedApp.redeployResources.put( xmlCopy.getAbsolutePath(), Long.valueOf(0)); } } else { // Fake re-deploy resource to detect if a context.xml file is // added at a later point deployedApp.redeployResources.put( xmlCopy.getAbsolutePath(), Long.valueOf(0)); if (!xml.exists()) { deployedApp.redeployResources.put( xml.getAbsolutePath(), Long.valueOf(0)); } } addWatchedResources(deployedApp, dir.getAbsolutePath(), context); // Add the global redeploy resources (which are never deleted) at // the end so they don't interfere with the deletion process addGlobalRedeployResources(deployedApp); } deployed.put(cn.getName(), deployedApp); } /** * Check if a webapp is already deployed in this host. * * @param contextName of the context which will be checked */ protected boolean deploymentExists(String contextName) { return (deployed.containsKey(contextName) || (host.findChild(contextName) != null)); } /** * Add watched resources to the specified Context. * @param app HostConfig deployed app * @param docBase web app docBase * @param context web application context */ protected void addWatchedResources(DeployedApplication app, String docBase, Context context) { // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, // WEB-INF/*.xml), where we would only check if at least one // resource is newer than app.timestamp File docBaseFile = null; if (docBase != null) { docBaseFile = new File(docBase); if (!docBaseFile.isAbsolute()) { docBaseFile = new File(appBase(), docBase); } } String[] watchedResources = context.findWatchedResources(); for (int i = 0; i < watchedResources.length; i++) { File resource = new File(watchedResources[i]); if (!resource.isAbsolute()) { if (docBase != null) { resource = new File(docBaseFile, watchedResources[i]); } else { if(log.isDebugEnabled()) log.debug("Ignoring non-existent WatchedResource '" + resource.getAbsolutePath() + "'"); continue; } } if(log.isDebugEnabled()) log.debug("Watching WatchedResource '" + resource.getAbsolutePath() + "'"); app.reloadResources.put(resource.getAbsolutePath(), Long.valueOf(resource.lastModified())); } } protected void addGlobalRedeployResources(DeployedApplication app) { // Redeploy resources processing is hard-coded to never delete this file File hostContextXml = new File(getConfigBaseName(), Constants.HostContextXml); if (hostContextXml.isFile()) { app.redeployResources.put(hostContextXml.getAbsolutePath(), Long.valueOf(hostContextXml.lastModified())); } // Redeploy resources in CATALINA_BASE/conf are never deleted File globalContextXml = returnCanonicalPath(Constants.DefaultContextXml); if (globalContextXml.isFile()) { app.redeployResources.put(globalContextXml.getAbsolutePath(), Long.valueOf(globalContextXml.lastModified())); } } /** * Check resources for redeployment and reloading. */ protected synchronized void checkResources(DeployedApplication app) { String[] resources = app.redeployResources.keySet().toArray(new String[0]); for (int i = 0; i < resources.length; i++) { File resource = new File(resources[i]); if (log.isDebugEnabled()) log.debug("Checking context[" + app.name + "] redeploy resource " + resource); long lastModified = app.redeployResources.get(resources[i]).longValue(); if (resource.exists() || lastModified == 0) { if (resource.lastModified() > lastModified) { if (resource.isDirectory()) { // No action required for modified directory app.redeployResources.put(resources[i], Long.valueOf(resource.lastModified())); } else if (app.hasDescriptor && resource.getName().toLowerCase( Locale.ENGLISH).endsWith(".war")) { // Modified WAR triggers a reload if there is an XML // file present // The only resource that should be deleted is the // expanded WAR (if any) Context context = (Context) host.findChild(app.name); String docBase = context.getDocBase(); docBase = docBase.toLowerCase(Locale.ENGLISH); if (!docBase.endsWith(".war")) { // This is an expanded directory File docBaseFile = new File(docBase); if (!docBaseFile.isAbsolute()) { docBaseFile = new File(appBase(), docBase); } ExpandWar.delete(docBaseFile); // Reset the docBase to trigger re-expansion of the // WAR context.setDocBase(resource.getAbsolutePath()); } reload(app); // Update times app.redeployResources.put(resources[i], Long.valueOf(resource.lastModified())); app.timestamp = System.currentTimeMillis(); if (unpackWARs) { addWatchedResources(app, context.getDocBase(), context); } else { addWatchedResources(app, null, context); } return; } else { // Everything else triggers a redeploy // (just need to undeploy here, deploy will follow) deleteRedeployResources(app, resources, i, false); undeploy(app); return; } } } else { // There is a chance the the resource was only missing // temporarily eg renamed during a text editor save try { Thread.sleep(500); } catch (InterruptedException e1) { // Ignore } // Recheck the resource to see if it was really deleted if (resource.exists()) { continue; } if (lastModified == 0L) { continue; } // Undeploy application undeploy(app); deleteRedeployResources(app, resources, i, true); return; } } resources = app.reloadResources.keySet().toArray(new String[0]); for (int i = 0; i < resources.length; i++) { File resource = new File(resources[i]); if (log.isDebugEnabled()) log.debug("Checking context[" + app.name + "] reload resource " + resource); long lastModified = app.reloadResources.get(resources[i]).longValue(); if ((!resource.exists() && lastModified != 0L) || (resource.lastModified() != lastModified)) { // Reload application reload(app); // Update times app.reloadResources.put(resources[i], Long.valueOf(resource.lastModified())); app.timestamp = System.currentTimeMillis(); return; } } } private void reload(DeployedApplication app) { if(log.isInfoEnabled()) log.info(sm.getString("hostConfig.reload", app.name)); Context context = (Context) host.findChild(app.name); if (context.getState().isAvailable()) { // Reload catches and logs exceptions context.reload(); } else { // If the context was not started (for example an error // in web.xml) we'll still get to try to start try { context.start(); } catch (Exception e) { log.warn(sm.getString ("hostConfig.context.restart", app.name), e); } } } private void undeploy(DeployedApplication app) { if (log.isInfoEnabled()) log.info(sm.getString("hostConfig.undeploy", app.name)); Container context = host.findChild(app.name); try { host.removeChild(context); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn(sm.getString ("hostConfig.context.remove", app.name), t); } deployed.remove(app.name); } private void deleteRedeployResources(DeployedApplication app, String[] resources, int i, boolean deleteReloadResources) { // Delete other redeploy resources for (int j = i + 1; j < resources.length; j++) { try { File current = new File(resources[j]); current = current.getCanonicalFile(); // Never delete per host context.xml defaults if (Constants.HostContextXml.equals( current.getName())) { continue; } // Only delete resources in the appBase or the // host's configBase if (isDeletableResource(current)) { if (log.isDebugEnabled()) log.debug("Delete " + current); ExpandWar.delete(current); } } catch (IOException e) { log.warn(sm.getString ("hostConfig.canonicalizing", app.name), e); } } // Delete reload resources (to remove any remaining .xml descriptor) if (deleteReloadResources) { String[] resources2 = app.reloadResources.keySet().toArray(new String[0]); for (int j = 0; j < resources2.length; j++) { try { File current = new File(resources2[j]); current = current.getCanonicalFile(); // Never delete per host context.xml defaults if (Constants.HostContextXml.equals( current.getName())) { continue; } // Only delete resources in the appBase or the host's // configBase if (isDeletableResource(current)) { if (log.isDebugEnabled()) log.debug("Delete " + current); ExpandWar.delete(current); } } catch (IOException e) { log.warn(sm.getString ("hostConfig.canonicalizing", app.name), e); } } } } private boolean isDeletableResource(File resource) { if ((resource.getAbsolutePath().startsWith( appBase().getAbsolutePath() + File.separator)) || ((resource.getAbsolutePath().startsWith( configBase().getAbsolutePath()) && (resource.getAbsolutePath().endsWith(".xml"))))) { return true; } return false; } /** * Process a "start" event for this Host. */ public void start() { if (log.isDebugEnabled()) log.debug(sm.getString("hostConfig.start")); try { ObjectName hostON = host.getObjectName(); oname = new ObjectName (hostON.getDomain() + ":type=Deployer,host=" + host.getName()); Registry.getRegistry(null, null).registerComponent (this, oname, this.getClass().getName()); } catch (Exception e) { log.error(sm.getString("hostConfig.jmx.register", oname), e); } if (host.getCreateDirs()) { File[] dirs = new File[] {appBase(),configBase()}; for (int i=0; i sortedAppNames = new TreeSet(); sortedAppNames.addAll(deployed.keySet()); if (sortedAppNames.size() < 2) { return; } Iterator iter = sortedAppNames.iterator(); ContextName previous = new ContextName(iter.next(), false); do { ContextName current = new ContextName(iter.next(), false); if (current.getPath().equals(previous.getPath())) { // Current and previous are same path - current will always // be a later version Context previousContext = (Context) host.findChild(previous.getName()); Context currentContext = (Context) host.findChild(previous.getName()); if (previousContext != null && currentContext != null && currentContext.getState().isAvailable() && !isServiced(previous.getName())) { Manager manager = previousContext.getManager(); if (manager != null) { int sessionCount; if (manager instanceof DistributedManager) { sessionCount = ((DistributedManager) manager).getActiveSessionsFull(); } else { sessionCount = manager.getActiveSessions(); } if (sessionCount == 0) { if (log.isInfoEnabled()) { log.info(sm.getString( "hostConfig.undeployVersion", previous.getName())); } DeployedApplication app = deployed.get(previous.getName()); String[] resources = app.redeployResources.keySet().toArray( new String[0]); // Version is unused - undeploy it completely // The -1 is a 'trick' to ensure all redeploy // resources are removed undeploy(app); deleteRedeployResources(app, resources, -1, true); } } } } previous = current; } while (iter.hasNext()); } /** * Add a new Context to be managed by us. * Entry point for the admin webapp, and other JMX Context controllers. */ public void manageApp(Context context) { String contextName = context.getName(); if (deployed.containsKey(contextName)) return; DeployedApplication deployedApp = new DeployedApplication(contextName, false); // Add the associated docBase to the redeployed list if it's a WAR boolean isWar = false; if (context.getDocBase() != null) { File docBase = new File(context.getDocBase()); if (!docBase.isAbsolute()) { docBase = new File(appBase(), context.getDocBase()); } deployedApp.redeployResources.put(docBase.getAbsolutePath(), Long.valueOf(docBase.lastModified())); if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) { isWar = true; } } host.addChild(context); // Add the eventual unpacked WAR and all the resources which will be // watched inside it if (isWar && unpackWARs) { File docBase = new File(appBase(), context.getBaseName()); deployedApp.redeployResources.put(docBase.getAbsolutePath(), Long.valueOf(docBase.lastModified())); addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); } else { addWatchedResources(deployedApp, null, context); } deployed.put(contextName, deployedApp); } /** * Remove a webapp from our control. * Entry point for the admin webapp, and other JMX Context controllers. */ public void unmanageApp(String contextName) { if(isServiced(contextName)) { deployed.remove(contextName); host.removeChild(host.findChild(contextName)); } } // ----------------------------------------------------- Instance Variables /** * This class represents the state of a deployed application, as well as * the monitored resources. */ protected static class DeployedApplication { public DeployedApplication(String name, boolean hasDescriptor) { this.name = name; this.hasDescriptor = hasDescriptor; } /** * Application context path. The assertion is that * (host.getChild(name) != null). */ public String name; /** * Does this application have a context.xml descriptor file on the * host's configBase? */ public final boolean hasDescriptor; /** * Any modification of the specified (static) resources will cause a * redeployment of the application. If any of the specified resources is * removed, the application will be undeployed. Typically, this will * contain resources like the context.xml file, a compressed WAR path. * The value is the last modification time. */ public LinkedHashMap redeployResources = new LinkedHashMap(); /** * Any modification of the specified (static) resources will cause a * reload of the application. This will typically contain resources * such as the web.xml of a webapp, but can be configured to contain * additional descriptors. * The value is the last modification time. */ public HashMap reloadResources = new HashMap(); /** * Instant where the application was last put in service. */ public long timestamp = System.currentTimeMillis(); /** * In some circumstances, such as when unpackWARs is true, a directory * may be added to the appBase that is ignored. This flag indicates that * the user has been warned so that the warning is not logged on every * run of the auto deployer. */ public boolean loggedDirWarning = false; } private static class DeployDescriptor implements Runnable { private HostConfig config; private ContextName cn; private File descriptor; public DeployDescriptor(HostConfig config, ContextName cn, File descriptor) { this.config = config; this.cn = cn; this.descriptor= descriptor; } @Override public void run() { config.deployDescriptor(cn, descriptor); } } private static class DeployWar implements Runnable { private HostConfig config; private ContextName cn; private File war; public DeployWar(HostConfig config, ContextName cn, File war) { this.config = config; this.cn = cn; this.war = war; } @Override public void run() { config.deployWAR(cn, war); } } private static class DeployDirectory implements Runnable { private HostConfig config; private ContextName cn; private File dir; public DeployDirectory(HostConfig config, ContextName cn, File dir) { this.config = config; this.cn = cn; this.dir = dir; } @Override public void run() { config.deployDirectory(cn, dir); } } } tomcat7-7.0.52/java/org/apache/catalina/startup/Constants.java0000644000175100017510000001742612271471332024205 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; /** * String constants for the startup package. * * @author Craig R. McClanahan * @author Jean-Francois Arcand */ public final class Constants { public static final String Package = "org.apache.catalina.startup"; public static final String ApplicationContextXml = "META-INF/context.xml"; public static final String ApplicationWebXml = "/WEB-INF/web.xml"; public static final String DefaultContextXml = "conf/context.xml"; public static final String DefaultWebXml = "conf/web.xml"; public static final String HostContextXml = "context.xml.default"; public static final String HostWebXml = "web.xml.default"; public static final String DEFAULT_JARS_TO_SKIP = "tomcat.util.scan.DefaultJarScanner.jarsToSkip"; public static final String PLUGGABILITY_JARS_TO_SKIP = "org.apache.catalina.startup.ContextConfig.jarsToSkip"; public static final String TLD_JARS_TO_SKIP = "org.apache.catalina.startup.TldConfig.jarsToSkip"; /** * A dummy value used to suppress loading the default web.xml file. * *

    * It is useful when embedding Tomcat, when the default configuration is * done programmatically, e.g. by calling * Tomcat.initWebappDefaults(context). * * @see Tomcat */ public static final String NoDefaultWebXml = "org/apache/catalina/startup/NO_DEFAULT_XML"; // J2EE public static final String J2eeSchemaPublicId_14 = "j2ee_1_4.xsd"; public static final String J2eeSchemaResourcePath_14 = "/javax/servlet/resources/j2ee_1_4.xsd"; public static final String JavaeeSchemaPublicId_5 = "javaee_5.xsd"; public static final String JavaeeSchemaResourcePath_5 = "/javax/servlet/resources/javaee_5.xsd"; public static final String JavaeeSchemaPublicId_6 = "javaee_6.xsd"; public static final String JavaeeSchemaResourcePath_6 = "/javax/servlet/resources/javaee_6.xsd"; // W3C public static final String W3cSchemaPublicId_10 = "xml.xsd"; public static final String W3cSchemaResourcePath_10 = "/javax/servlet/resources/xml.xsd"; public static final String W3cSchemaDTDPublicId_10 = "XMLSchema.dtd"; public static final String W3cSchemaDTDResourcePath_10 = "/javax/servlet/resources/XMLSchema.dtd"; public static final String W3cDatatypesDTDPublicId_10 = "datatypes.dtd"; public static final String W3cDatatypesDTDResourcePath_10 = "/javax/servlet/resources/datatypes.dtd"; // JSP public static final String JspSchemaPublicId_20 = "jsp_2_0.xsd"; public static final String JspSchemaResourcePath_20 = "/javax/servlet/jsp/resources/jsp_2_0.xsd"; public static final String JspSchemaPublicId_21 = "jsp_2_1.xsd"; public static final String JspSchemaResourcePath_21 = "/javax/servlet/jsp/resources/jsp_2_1.xsd"; public static final String JspSchemaPublicId_22 = "jsp_2_2.xsd"; public static final String JspSchemaResourcePath_22 = "/javax/servlet/jsp/resources/jsp_2_2.xsd"; // TLD public static final String TldDtdPublicId_11 = "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"; public static final String TldDtdResourcePath_11 = "/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd"; public static final String TldDtdPublicId_12 = "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"; public static final String TldDtdResourcePath_12 = "/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd"; public static final String TldSchemaPublicId_20 = "web-jsptaglibrary_2_0.xsd"; public static final String TldSchemaResourcePath_20 = "/javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd"; public static final String TldSchemaPublicId_21 = "web-jsptaglibrary_2_1.xsd"; public static final String TldSchemaResourcePath_21 = "/javax/servlet/jsp/resources/web-jsptaglibrary_2_1.xsd"; // web.xml public static final String WebDtdPublicId_22 = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"; public static final String WebDtdResourcePath_22 = "/javax/servlet/resources/web-app_2_2.dtd"; public static final String WebDtdPublicId_23 = "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"; public static final String WebDtdResourcePath_23 = "/javax/servlet/resources/web-app_2_3.dtd"; public static final String WebSchemaPublicId_24 = "web-app_2_4.xsd"; public static final String WebSchemaResourcePath_24 = "/javax/servlet/resources/web-app_2_4.xsd"; public static final String WebSchemaPublicId_25 = "web-app_2_5.xsd"; public static final String WebSchemaResourcePath_25 = "/javax/servlet/resources/web-app_2_5.xsd"; public static final String WebSchemaPublicId_30 = "web-app_3_0.xsd"; public static final String WebSchemaResourcePath_30 = "/javax/servlet/resources/web-app_3_0.xsd"; public static final String WebCommonSchemaPublicId_30 = "web-common_3_0.xsd"; public static final String WebCommonSchemaResourcePath_30 = "/javax/servlet/resources/web-common_3_0.xsd"; public static final String WebFragmentSchemaPublicId_30 = "web-fragment_3_0.xsd"; public static final String WebFragmentSchemaResourcePath_30 = "/javax/servlet/resources/web-fragment_3_0.xsd"; // Web service public static final String J2eeWebServiceSchemaPublicId_11 = "j2ee_web_services_1_1.xsd"; public static final String J2eeWebServiceSchemaResourcePath_11 = "/javax/servlet/resources/j2ee_web_services_1_1.xsd"; public static final String J2eeWebServiceClientSchemaPublicId_11 = "j2ee_web_services_client_1_1.xsd"; public static final String J2eeWebServiceClientSchemaResourcePath_11 = "/javax/servlet/resources/j2ee_web_services_client_1_1.xsd"; public static final String JavaeeWebServiceSchemaPublicId_12 = "javaee_web_services_1_2.xsd"; public static final String JavaeeWebServiceSchemaResourcePath_12 = "/javax/servlet/resources/javaee_web_services_1_2.xsd"; public static final String JavaeeWebServiceClientSchemaPublicId_12 = "javaee_web_services_client_1_2.xsd"; public static final String JavaeeWebServiceClientSchemaResourcePath_12 = "/javax/servlet/resources/javaee_web_services_client_1_2.xsd"; public static final String JavaeeWebServiceSchemaPublicId_13 = "javaee_web_services_1_3.xsd"; public static final String JavaeeWebServiceSchemaResourcePath_13 = "/javax/servlet/resources/javaee_web_services_1_3.xsd"; public static final String JavaeeWebServiceClientSchemaPublicId_13 = "javaee_web_services_client_1_3.xsd"; public static final String JavaeeWebServiceClientSchemaResourcePath_13 = "/javax/servlet/resources/javaee_web_services_client_1_3.xsd"; } tomcat7-7.0.52/java/org/apache/catalina/startup/LocalStrings.properties0000644000175100017510000002735412271471332026111 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. catalina.configFail=Unable to load server configuration from [{0}] catalina.noCluster=Cluster RuleSet not found due to [{0}]. Cluster configuration disabled. catalina.serverStartFail=The required Server component failed to start so Tomcat is unable to start. catalina.shutdownHookFail=The shutdown hook experienced an error while trying to stop the server catalina.stopServer=No shutdown port configured. Shut down server through OS signal. Server not shut down. catalina.stopServer.connectException=Could not contact {0}:{1}. Tomcat may not be running. contextConfig.altDDNotFound=alt-dd file {0} not found contextConfig.annotationsStackOverflow=Unable to complete the scan for annotations for web application [{0}] due to a StackOverflowError. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies. The class hierarchy being processed was [{1}] contextConfig.applicationUrl=Unable to determine URL for application web.xml contextConfig.applicationMissing=Missing application web.xml, using defaults only contextConfig.applicationParse=Parse error in application web.xml file at {0} contextConfig.applicationPosition=Occurred at line {0} column {1} contextConfig.applicationStart=Parsing application web.xml file at {0} contextConfig.authenticatorConfigured=Configured an authenticator for method {0} contextConfig.authenticatorInstantiate=Cannot instantiate an authenticator of class {0} contextConfig.authenticatorMissing=Cannot configure an authenticator for method {0} contextConfig.authenticatorResources=Cannot load authenticators mapping list contextConfig.badUrl=Unable to process context descriptor [{0}] contextConfig.baseError=Unable to determine location of global configuration (usually $CATALINA_BASE/conf) contextConfig.cce=Lifecycle event data object {0} is not a Context contextConfig.contextClose=Error closing context.xml contextConfig.contextMissing=Missing context.xml: {0} contextConfig.contextParse=Parse error in context.xml for {0} contextConfig.defaultError=Error processed default web.xml named {0} at {1} contextConfig.defaultMissing=No global web.xml found contextConfig.defaultPosition=Occurred at line {0} column {1} contextConfig.destroy=ContextConfig: Destroying contextConfig.fileUrl=Unable to create a File object from the URL [{0}] contextConfig.fixDocBase=Exception fixing docBase for context [{0}] contextConfig.init=ContextConfig: Initializing contextConfig.inputStreamFile=Unable to process file [{0}] for annotations contextConfig.inputStreamJar=Unable to process Jar entry [{0}] from Jar [{1}] for annotations contextConfig.inputStreamJndi=Unable to process resource element [{0}] for annotations contextConfig.invalidSci=The ServletContentInitializer [{0}] could not be created contextConfig.jarUrl=The connection created for URL [{0}] was not a JarUrlConnection contextConfig.jar=Unable to process resource [{0}] for annotations contextConfig.jndiUrl=Unable to process JNDI URL [{0}] for annotations contextConfig.jndiUrlNotDirContextConn=The connection created for URL [{0}] was not a DirContextURLConnection contextConfig.jspFile.error=JSP file {0} must start with a ''/' contextConfig.jspFile.warning=WARNING: JSP file {0} must start with a ''/'' in Servlet 2.4 contextConfig.missingRealm=No Realm has been configured to authenticate against contextConfig.resourceJarFail=Failed to processes JAR found at URL [{0}] for static resources to be included in context with name [{0}] contextConfig.role.auth=Security role name {0} used in an without being defined in a contextConfig.role.link=Security role name {0} used in a without being defined in a contextConfig.role.runas=Security role name {0} used in a without being defined in a contextConfig.sci.debug=Unable to process ServletContainerInitializer for [{0}]. This is most likely due to a class defined in the @HandlesTypes annotation being missing contextConfig.sci.info=Unable to process ServletContainerInitializer for [{0}]. This is most likely due to a class defined in the @HandlesTypes annotation being missing. Enable DEBUG level logging for the full stack trace. contextConfig.servletContainerInitializerFail=Failed to process JAR found at URL [{0}] for ServletContainerInitializers for context with name [{1}] contextConfig.start=ContextConfig: Processing START contextConfig.stop=ContextConfig: Processing STOP contextConfig.unavailable=Marking this application unavailable due to previous error(s) contextConfig.unknownUrlProtocol=The URL protocol [{0}] was not recognised during annotation processing. URL [{1}] was ignored. contextConfig.urlPatternValue=Both the UrlPattern and value attribute were set for the WebServlet annotation on class [{0}] contextConfig.webinfClassesUrl=Unable to determine URL for [{0}] contextConfig.xmlSettings=Context [{0}] will parse web.xml and web-fragment.xml files with validation:{1} and namespaceAware:{2} embedded.noEngines=No engines have been defined yet embedded.notmp=Cannot find specified temporary folder at {0} embedded.authenticatorNotInstanceOfValve=Specified Authenticator is not a Valve engineConfig.cce=Lifecycle event data object {0} is not an Engine engineConfig.start=EngineConfig: Processing START engineConfig.stop=EngineConfig: Processing STOP expandWar.copy=Error copying {0} to {1} expandWar.createFailed=Unable to create the directory [{0}] expandWar.deleteFailed=[{0}] could not be completely deleted. The presence of the remaining files may cause problems expandWar.illegalPath=The archive [{0}] is malformed and will be ignored: an entry contains an illegal path [{1}] which was not expanded to [{2}] since that is outside of the defined docBase [{3}] expandWar.missingJarEntry=Cannot get input stream for JarEntry "{0}" - broken WAR file? failedContext.start=Failed to process either the global, per-host or context-specific context.xml file therefore the [{0}] Context cannot be started. hostConfig.appBase=Application base [{1}] for host [{0}] does not exist or is not a directory. deployOnStartUp and autoDeploy have been set to false to prevent deployment errors. Other errors may still occur. hostConfig.canonicalizing=Error delete redeploy resources from context [{0}] hostConfig.cce=Lifecycle event data object {0} is not a Host hostConfig.context.remove=Error while removing context [{0}] hostConfig.context.restart=Error during context [{0}] restart hostConfig.createDirs=Unable to create directory for deployment: {0} hostConfig.deploy=Deploying web application directory {0} hostConfig.deployDescriptor=Deploying configuration descriptor {0} hostConfig.deployDescriptor.blocked=The web application with context path [{0}] was not deployed because it contained a deployment descriptor [{1}] which may include configuration necessary for the secure deployment of the application but processing of deployment descriptors is prevented by the deployXML setting of this host. An appropriate descriptor should be created at [{2}] to deploy this application. hostConfig.deployDescriptor.error=Error deploying configuration descriptor {0} hostConfig.deployDescriptor.threaded.error=Error waiting for multi-thread deployment of context descriptors to complete hostConfig.deployDescriptor.localDocBaseSpecified=A docBase {0} inside the host appBase has been specified, and will be ignored hostConfig.deployDir=Deploying web application directory {0} hostConfig.deployDir.error=Error deploying web application directory {0} hostConfig.deployDir.threaded.error=Error waiting for multi-thread deployment of directories to complete hostConfig.deployWar=Deploying web application archive {0} hostConfig.deployWar.error=Error deploying web application archive {0} hostConfig.deployWar.hiddenDir=The directory [{0}] will be ignored because the WAR [{1}] takes priority and unpackWARs is false hostConfig.deployWar.threaded.error=Error waiting for multi-thread deployment of WAR files to complete hostConfig.deploy.error=Exception while deploying web application directory {0} hostConfig.deploying=Deploying discovered web applications hostConfig.expand=Expanding web application archive {0} hostConfig.expand.error=Exception while expanding web application archive {0} hostConfig.expanding=Expanding discovered web application archives hostConfig.ignorePath=Ignoring path [{0}] in appBase for automatic deployment hostConfig.illegalWarName=The war name [{0}] is invalid. The archive will be ignored. hostConfig.jmx.register=Register context [{0}] failed hostConfig.jmx.unregister=Unregister context [{0}] failed hostConfig.reload=Reloading context [{0}] hostConfig.removeXML=Context [{0}] is undeployed hostConfig.removeDIR=Directory {0} is undeployed hostConfig.removeWAR=War {0} is undeployed hostConfig.start=HostConfig: Processing START hostConfig.stop=HostConfig: Processing STOP hostConfig.undeploy=Undeploying context [{0}] hostConfig.undeploy.error=Error undeploying web application at context path {0} hostConfig.undeployVersion=Undeploying old version of context [{0}] which has no active session tldConfig.addListeners=Adding {0} listeners from TLD files tldConfig.cce=Lifecycle event data object {0} is not a Context tldConfig.dirFail=Failed to process directory [{0}] for TLD files tldConfig.dirScan=Scanning for TLD files in directory [{0}] tldConfig.execute=Error processing TLD files for context with name [{0}] tldConfig.jarFail=Failed to process JAR [{0}] for TLD files tldConfig.webinfFail=Failed to process TLD found at [{0}] tldConfig.webinfScan=Scanning WEB-INF for TLD files in [{0}] tldConfig.webxmlAdd=Adding path [{0}] for URI [{1}] tldConfig.webxmlFail=Failed to process TLD with path [{0}] and URI [{1}] tldConfig.webxmlFailPathDoesNotExist=Failed to process TLD with path [{0}] and URI [{1}]. The specified path does not exist. tldConfig.webxmlSkip=Path [{1}] skipped since URI [{0}] is a duplicate tldConfig.webxmlStart=Scanning elements in web.xml userConfig.database=Exception loading user database userConfig.deploy=Deploying web application for user {0} userConfig.deploying=Deploying user web applications userConfig.error=Error deploying web application for user {0} userConfig.start=UserConfig: Processing START userConfig.stop=UserConfig: Processing STOP userConfig.deploy.threaded.error=Error waiting for multi-thread deployment of user directories to complete webAnnotationSet.invalidInjection=Invalid method resource injection annotation. webRuleSet.absoluteOrdering= element not valid in web-fragment.xml and will be ignored webRuleSet.absoluteOrderingCount= element is limited to 1 occurrence webRuleSet.nameCount= element is limited to 1 occurrence webRuleSet.postconstruct.duplicate=Duplicate post construct method definition for class {0} webRuleSet.predestroy.duplicate=Duplicate pre destroy method definition for class {0} webRuleSet.relativeOrdering= element not valid in web.xml and will be ignored webRuleSet.relativeOrderingCount= element is limited to 1 occurrence xmlErrorHandler.error=Non-fatal error [{0}] reported processing [{1}]. xmlErrorHandler.warning=Warning [{0}] reported processing [{1}]. tomcat7-7.0.52/java/org/apache/catalina/startup/LocalStrings_ja.properties0000644000175100017510000002031212271471332026546 0ustar locutuslocutus# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. contextConfig.applicationMissing=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u3060\u3051\u3092\u4f7f\u7528\u3057\u307e\u3059 contextConfig.applicationParse=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u30d5\u30a1\u30a4\u30eb {0} \u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059 contextConfig.applicationPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f contextConfig.authenticatorConfigured=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3057\u307e\u3059 contextConfig.authenticatorInstantiate=\u30af\u30e9\u30b9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u3067\u304d\u307e\u305b\u3093 contextConfig.authenticatorMissing=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 contextConfig.authenticatorResources=\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u306e\u30de\u30c3\u30d7\u30ea\u30b9\u30c8\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 contextConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 contextConfig.defaultPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f contextConfig.jspFile.error=JSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 contextConfig.jspFile.warning=\u8b66\u544a: Servlet 2.4\u3067\u306fJSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 contextConfig.missingRealm=\u8a8d\u8a3c\u3059\u308b\u305f\u3081\u306b\u30ec\u30eb\u30e0\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 contextConfig.role.auth=\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f contextConfig.role.link=\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f contextConfig.role.runas=\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f contextConfig.start=ContextConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 contextConfig.stop=ContextConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 contextConfig.unavailable=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u5229\u7528\u3067\u304d\u306a\u3044\u3088\u3046\u306b\u30de\u30fc\u30af\u3057\u307e\u3059 embedded.noEngines=\u307e\u3060\u30a8\u30f3\u30b8\u30f3\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 engineConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30a8\u30f3\u30b8\u30f3\u3067\u306f\u3042\u308a\u307e\u305b\u3093 engineConfig.start=EngineConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 engineConfig.stop=EngineConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 hostConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30db\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 hostConfig.deploy=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059 hostConfig.deployDescriptor=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u3057\u307e\u3059 hostConfig.deployDescriptor.error=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 hostConfig.deployDir=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059 hostConfig.deployDir.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 hostConfig.deployWar=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u3057\u307e\u3059 hostConfig.deployWar.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 hostConfig.deploy.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u4f8b\u5916\u3067\u3059 hostConfig.deploying=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 hostConfig.expand=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u3057\u307e\u3059 hostConfig.expand.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u4e2d\u306e\u4f8b\u5916\u3067\u3059 hostConfig.expanding=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u3092\u5c55\u958b\u3057\u307e\u3059 hostConfig.context.restart=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u3092\u518d\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 hostConfig.removeXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f hostConfig.removeDIR=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f hostConfig.removeWAR=WAR\u30d5\u30a1\u30a4\u30eb {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f hostConfig.start=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 hostConfig.stop=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 hostConfig.undeploy=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3059 hostConfig.undeploy.error=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 hostConfig.undeploying=\u914d\u5099\u3055\u308c\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u3066\u3044\u307e\u3059 userConfig.database=\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 userConfig.deploy=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 userConfig.deploying=\u30e6\u30fc\u30b6\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 userConfig.error=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 userConfig.start=UserConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 userConfig.stop=UserConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 tomcat7-7.0.52/java/org/apache/catalina/startup/ConnectorCreateRule.java0000644000175100017510000000643512271471332026135 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.lang.reflect.Method; import org.apache.catalina.Executor; import org.apache.catalina.Service; import org.apache.catalina.connector.Connector; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.digester.Rule; import org.xml.sax.Attributes; /** * Rule implementation that creates a connector. */ public class ConnectorCreateRule extends Rule { private static final Log log = LogFactory.getLog(ConnectorCreateRule.class); // --------------------------------------------------------- Public Methods /** * Process the beginning of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise * @param attributes The attribute list for this element */ @Override public void begin(String namespace, String name, Attributes attributes) throws Exception { Service svc = (Service)digester.peek(); Executor ex = null; if ( attributes.getValue("executor")!=null ) { ex = svc.getExecutor(attributes.getValue("executor")); } Connector con = new Connector(attributes.getValue("protocol")); if ( ex != null ) _setExecutor(con,ex); digester.push(con); } public void _setExecutor(Connector con, Executor ex) throws Exception { Method m = IntrospectionUtils.findMethod(con.getProtocolHandler().getClass(),"setExecutor",new Class[] {java.util.concurrent.Executor.class}); if (m!=null) { m.invoke(con.getProtocolHandler(), new Object[] {ex}); }else { log.warn("Connector ["+con+"] does not support external executors. Method setExecutor(java.util.concurrent.Executor) not found."); } } /** * Process the end of this element. * * @param namespace the namespace URI of the matching element, or an * empty string if the parser is not namespace aware or the element has * no namespace * @param name the local name if the parser is namespace aware, or just * the element name otherwise */ @Override public void end(String namespace, String name) throws Exception { digester.pop(); } } tomcat7-7.0.52/java/org/apache/catalina/startup/ExpandWar.java0000644000175100017510000003504212271471332024114 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.URL; import java.nio.channels.FileChannel; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipException; import org.apache.catalina.Globals; import org.apache.catalina.Host; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; /** * Expand out a WAR in a Host's appBase. * * @author Craig R. McClanahan * @author Remy Maucherat * @author Glenn L. Nielsen */ public class ExpandWar { private static final Log log = LogFactory.getLog(ExpandWar.class); /** * The string resources for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); /** * Expand the WAR file found at the specified URL into an unpacked * directory structure, and return the absolute pathname to the expanded * directory. * * @param host Host war is being installed for * @param war URL of the web application archive to be expanded * (must start with "jar:") * @param pathname Context path name for web application * * @exception IllegalArgumentException if this is not a "jar:" URL or if the * WAR file is invalid * @exception IOException if an input/output error was encountered * during expansion */ public static String expand(Host host, URL war, String pathname) throws IOException { // Make sure that there is no such directory already existing File appBase = new File(host.getAppBase()); if (!appBase.isAbsolute()) { appBase = new File(System.getProperty(Globals.CATALINA_BASE_PROP), host.getAppBase()); } if (!appBase.exists() || !appBase.isDirectory()) { throw new IOException (sm.getString("hostConfig.appBase", appBase.getAbsolutePath())); } File docBase = new File(appBase, pathname); if (docBase.exists()) { // War file is already installed return (docBase.getAbsolutePath()); } // Create the new document base directory if(!docBase.mkdir() && !docBase.isDirectory()) throw new IOException(sm.getString("expandWar.createFailed", docBase)); // Expand the WAR into the new document base directory String canonicalDocBasePrefix = docBase.getCanonicalPath(); if (!canonicalDocBasePrefix.endsWith(File.separator)) { canonicalDocBasePrefix += File.separator; } JarURLConnection juc = (JarURLConnection) war.openConnection(); juc.setUseCaches(false); JarFile jarFile = null; InputStream input = null; boolean success = false; try { jarFile = juc.getJarFile(); Enumeration jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); String name = jarEntry.getName(); File expandedFile = new File(docBase, name); if (!expandedFile.getCanonicalPath().startsWith( canonicalDocBasePrefix)) { // Trying to expand outside the docBase // Throw an exception to stop the deployment throw new IllegalArgumentException( sm.getString("expandWar.illegalPath",war, name, expandedFile.getCanonicalPath(), canonicalDocBasePrefix)); } int last = name.lastIndexOf('/'); if (last >= 0) { File parent = new File(docBase, name.substring(0, last)); if (!parent.mkdirs() && !parent.isDirectory()) { throw new IOException( sm.getString("expandWar.createFailed", parent)); } } if (name.endsWith("/")) { continue; } input = jarFile.getInputStream(jarEntry); if(null == input) throw new ZipException(sm.getString("expandWar.missingJarEntry", jarEntry.getName())); // Bugzilla 33636 expand(input, expandedFile); long lastModified = jarEntry.getTime(); if ((lastModified != -1) && (lastModified != 0)) { expandedFile.setLastModified(lastModified); } input.close(); input = null; } success = true; } catch (IOException e) { throw e; } finally { if (!success) { // If something went wrong, delete expanded dir to keep things // clean deleteDir(docBase); } if (input != null) { try { input.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } input = null; } if (jarFile != null) { try { jarFile.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } jarFile = null; } } // Return the absolute path to our new document base directory return (docBase.getAbsolutePath()); } /** * Validate the WAR file found at the specified URL. * * @param host Host war is being installed for * @param war URL of the web application archive to be validated * (must start with "jar:") * @param pathname Context path name for web application * * @exception IllegalArgumentException if this is not a "jar:" URL or if the * WAR file is invalid * @exception IOException if an input/output error was encountered * during validation */ public static void validate(Host host, URL war, String pathname) throws IOException { // Make the appBase absolute File appBase = new File(host.getAppBase()); if (!appBase.isAbsolute()) { appBase = new File(System.getProperty(Globals.CATALINA_BASE_PROP), host.getAppBase()); } File docBase = new File(appBase, pathname); // Calculate the document base directory String canonicalDocBasePrefix = docBase.getCanonicalPath(); if (!canonicalDocBasePrefix.endsWith(File.separator)) { canonicalDocBasePrefix += File.separator; } JarURLConnection juc = (JarURLConnection) war.openConnection(); juc.setUseCaches(false); JarFile jarFile = null; try { jarFile = juc.getJarFile(); Enumeration jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); String name = jarEntry.getName(); File expandedFile = new File(docBase, name); if (!expandedFile.getCanonicalPath().startsWith( canonicalDocBasePrefix)) { // Entry located outside the docBase // Throw an exception to stop the deployment throw new IllegalArgumentException( sm.getString("expandWar.illegalPath",war, name, expandedFile.getCanonicalPath(), canonicalDocBasePrefix)); } } } catch (IOException e) { throw e; } finally { if (jarFile != null) { try { jarFile.close(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } jarFile = null; } } } /** * Copy the specified file or directory to the destination. * * @param src File object representing the source * @param dest File object representing the destination */ public static boolean copy(File src, File dest) { boolean result = true; String files[] = null; if (src.isDirectory()) { files = src.list(); result = dest.mkdir(); } else { files = new String[1]; files[0] = ""; } if (files == null) { files = new String[0]; } for (int i = 0; (i < files.length) && result; i++) { File fileSrc = new File(src, files[i]); File fileDest = new File(dest, files[i]); if (fileSrc.isDirectory()) { result = copy(fileSrc, fileDest); } else { FileChannel ic = null; FileChannel oc = null; try { ic = (new FileInputStream(fileSrc)).getChannel(); oc = (new FileOutputStream(fileDest)).getChannel(); ic.transferTo(0, ic.size(), oc); } catch (IOException e) { log.error(sm.getString ("expandWar.copy", fileSrc, fileDest), e); result = false; } finally { if (ic != null) { try { ic.close(); } catch (IOException e) { } } if (oc != null) { try { oc.close(); } catch (IOException e) { } } } } } return result; } /** * Delete the specified directory, including all of its contents and * sub-directories recursively. Any failure will be logged. * * @param dir File object representing the directory to be deleted */ public static boolean delete(File dir) { // Log failure by default return delete(dir, true); } /** * Delete the specified directory, including all of its contents and * sub-directories recursively. * * @param dir File object representing the directory to be deleted * @param logFailure true if failure to delete the resource * should be logged */ public static boolean delete(File dir, boolean logFailure) { boolean result; if (dir.isDirectory()) { result = deleteDir(dir, logFailure); } else { if (dir.exists()) { result = dir.delete(); } else { result = true; } } if (logFailure && !result) { log.error(sm.getString( "expandWar.deleteFailed", dir.getAbsolutePath())); } return result; } /** * Delete the specified directory, including all of its contents and * sub-directories recursively. Any failure will be logged. * * @param dir File object representing the directory to be deleted */ public static boolean deleteDir(File dir) { return deleteDir(dir, true); } /** * Delete the specified directory, including all of its contents and * sub-directories recursively. * * @param dir File object representing the directory to be deleted * @param logFailure true if failure to delete the resource * should be logged */ public static boolean deleteDir(File dir, boolean logFailure) { String files[] = dir.list(); if (files == null) { files = new String[0]; } for (int i = 0; i < files.length; i++) { File file = new File(dir, files[i]); if (file.isDirectory()) { deleteDir(file, logFailure); } else { file.delete(); } } boolean result; if (dir.exists()) { result = dir.delete(); } else { result = true; } if (logFailure && !result) { log.error(sm.getString( "expandWar.deleteFailed", dir.getAbsolutePath())); } return result; } /** * Expand the specified input stream into the specified file. * * @param input InputStream to be copied * @param file The file to be created * * @exception IOException if an input/output error occurs */ private static void expand(InputStream input, File file) throws IOException { BufferedOutputStream output = null; try { output = new BufferedOutputStream(new FileOutputStream(file)); byte buffer[] = new byte[2048]; while (true) { int n = input.read(buffer); if (n <= 0) break; output.write(buffer, 0, n); } } finally { if (output != null) { try { output.close(); } catch (IOException e) { // Ignore } } } } } tomcat7-7.0.52/java/org/apache/catalina/startup/Catalina.java0000644000175100017510000007347212271471332023750 0ustar locutuslocutus/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.catalina.startup; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.net.ConnectException; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.logging.LogManager; import org.apache.catalina.Container; import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Server; import org.apache.catalina.security.SecurityConfig; import org.apache.juli.ClassLoaderLogManager; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.Rule; import org.apache.tomcat.util.digester.RuleSet; import org.apache.tomcat.util.log.SystemLogHandler; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXParseException; /** * Startup/Shutdown shell program for Catalina. The following command line * options are recognized: *